diff --git a/web/src/components/FoxelLoadingIndicator.tsx b/web/src/components/FoxelLoadingIndicator.tsx
new file mode 100644
index 0000000..63346f1
--- /dev/null
+++ b/web/src/components/FoxelLoadingIndicator.tsx
@@ -0,0 +1,18 @@
+import type { CSSProperties } from 'react';
+
+interface FoxelLoadingIndicatorProps {
+ className?: string;
+ style?: CSSProperties;
+}
+
+export default function FoxelLoadingIndicator({ className, style }: FoxelLoadingIndicatorProps) {
+ return (
+
+
+
+ );
+}
diff --git a/web/src/global.css b/web/src/global.css
index f7ab3ee..1c9af63 100644
--- a/web/src/global.css
+++ b/web/src/global.css
@@ -1,6 +1,45 @@
html,body,#root { min-height: 100%; height: 100%; }
body { margin: 0; font-family: system-ui,-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,'Helvetica Neue',Arial,'Noto Sans',sans-serif; background: var(--ant-color-bg-layout, #f9f9f9); }
+.ant-spin .fx-loading-indicator.ant-spin-dot {
+ width: 1.5em;
+ height: 1.5em;
+ vertical-align: middle;
+ color: var(--ant-color-text, #111);
+}
+
+[data-theme="dark"] .ant-spin .fx-loading-indicator.ant-spin-dot {
+ color: var(--ant-color-text, #f5f5f5);
+}
+
+.fx-loading-indicator-mark {
+ display: block;
+ width: 100%;
+ height: 100%;
+ background: currentColor;
+ -webkit-mask: url('/logo.svg') center / contain no-repeat;
+ mask: url('/logo.svg') center / contain no-repeat;
+ transform-origin: center;
+ animation: fx-logo-breathe 2.4s ease-in-out infinite;
+}
+
+@keyframes fx-logo-breathe {
+ 0%, 100% {
+ opacity: 0.45;
+ transform: scale(0.9);
+ }
+ 50% {
+ opacity: 1;
+ transform: scale(1);
+ }
+}
+
+@media (prefers-reduced-motion: reduce) {
+ .fx-loading-indicator-mark {
+ animation: none;
+ }
+}
+
::-webkit-scrollbar { width: 8px; height: 8px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: var(--ant-color-fill-tertiary, #d9d9d9); border-radius: 4px; }
diff --git a/web/src/main.tsx b/web/src/main.tsx
index 5fa32c7..dd63178 100644
--- a/web/src/main.tsx
+++ b/web/src/main.tsx
@@ -3,13 +3,17 @@ import App from './App.tsx';
import 'antd/dist/reset.css';
import './global.css';
import { BrowserRouter } from 'react-router';
+import { ConfigProvider } from 'antd';
+import FoxelLoadingIndicator from './components/FoxelLoadingIndicator';
// 初始化插件依赖注入
import { initExternals } from './plugins/externals';
initExternals();
createRoot(document.getElementById('root')!).render(
-
-
-
+ }}>
+
+
+
+
);