diff --git a/frontend/package-lock.json b/frontend/package-lock.json index dd1c0a6..d718e89 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -12,6 +12,7 @@ "@vicons/ionicons5": "^0.12.0", "dompurify": "^3.4.13", "marked": "^9.0.0", + "three": "^0.185.1", "vue": "^3.4.0" }, "devDependencies": { @@ -2240,6 +2241,12 @@ "dev": true, "license": "MIT" }, + "node_modules/three": { + "version": "0.185.1", + "resolved": "https://registry.npmjs.org/three/-/three-0.185.1.tgz", + "integrity": "sha512-5aojFCXKwnjBRZvUnt3WFfEcvUJgkN5LlijRFN95hMy8WVkG4I0QNcJE+OuWvuJ0bOdStrbfXn0pkd6/QyiAlg==", + "license": "MIT" + }, "node_modules/tinybench": { "version": "2.9.0", "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", diff --git a/frontend/package.json b/frontend/package.json index d932325..ace4d05 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -20,6 +20,7 @@ "@vicons/ionicons5": "^0.12.0", "dompurify": "^3.4.13", "marked": "^9.0.0", + "three": "^0.185.1", "vue": "^3.4.0" }, "overrides": { diff --git a/frontend/src/App.vue b/frontend/src/App.vue index 9d4af5d..c9dc9f5 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -12,7 +12,7 @@

{{ t('app.loading') }}

-
@@ -26,6 +26,33 @@ :t="t" :theme="theme" :active-view="activeView" :blocked="contentInteractionBlocked" :open-system-settings="openSystemSettings" :toggle-locale="toggleLocale" :toggle-theme="toggleTheme" :shortcut-definitions="shortcutDefinitions" /> + +
+ +
+ +
+

{{ t('agentDiscovery.kicker') }}

+

{{ t('agentDiscovery.title') }}

+

{{ t('agentDiscovery.body') }}

+ +
+
+
+
+
+
+
+ + diff --git a/frontend/src/components/WavePhysicsLoader.vue b/frontend/src/components/WavePhysicsLoader.vue new file mode 100644 index 0000000..e2a7c78 --- /dev/null +++ b/frontend/src/components/WavePhysicsLoader.vue @@ -0,0 +1,170 @@ + + + + + diff --git a/frontend/src/locales/en.js b/frontend/src/locales/en.js index 062b6c8..f7a97ea 100644 --- a/frontend/src/locales/en.js +++ b/frontend/src/locales/en.js @@ -6,6 +6,10 @@ export default { 'delivery.run.budget-exhausted': 'Budget exhausted', 'delivery.run.circuit-breaker': 'Stopped by run protection', 'delivery.viewing': 'Viewing delivery; next message is regular chat', + 'agentDiscovery.kicker': 'Local workspace startup', + 'agentDiscovery.title': 'Finding your local Agents', + 'agentDiscovery.body': 'Meldwork is checking the Agent CLIs available on this computer.', + 'agentDiscovery.status': 'Preparing your workspace', "delivery.title": "Tasks & delivery", "delivery.bound": "Next message runs this task", "delivery.select": "Select task", diff --git a/frontend/src/locales/zh.js b/frontend/src/locales/zh.js index b5faa29..2f346c4 100644 --- a/frontend/src/locales/zh.js +++ b/frontend/src/locales/zh.js @@ -6,6 +6,10 @@ export default { 'delivery.run.budget-exhausted': '预算已用尽', 'delivery.run.circuit-breaker': '运行保护已停止执行', 'delivery.viewing': '查看交付中;下一次发送为普通聊天', + 'agentDiscovery.kicker': '本地工作台启动中', + 'agentDiscovery.title': '正在寻找本地 Agent', + 'agentDiscovery.body': 'Meldwork 正在检查这台电脑上可用的 Agent CLI。', + 'agentDiscovery.status': '正在准备工作台', "delivery.title": "任务与交付", "delivery.bound": "下一次发送用于此任务", "delivery.select": "选择任务", diff --git a/frontend/src/styles/agent-discovery.css b/frontend/src/styles/agent-discovery.css index 369ba43..acc8827 100644 --- a/frontend/src/styles/agent-discovery.css +++ b/frontend/src/styles/agent-discovery.css @@ -1,4 +1,155 @@ -/* Agent discovery runs in the background: the sidebar shows skeleton rows +.agent-discovery-overlay { + position: fixed; + inset: 0; + z-index: 90; + display: grid; + place-items: center; + overflow: hidden; + isolation: isolate; + padding: 32px; + background: var(--bg); + color: var(--text); + cursor: progress; +} + +.agent-discovery-content { + position: relative; + z-index: 1; + width: min(430px, 100%); + display: grid; + justify-items: center; + gap: 0; + padding: 12px 20px; + text-align: center; +} + +.agent-discovery-mark { + position: relative; + display: block; + width: 52px; + height: 52px; + margin-bottom: 28px; + object-fit: contain; + filter: drop-shadow(0 9px 20px color-mix(in srgb, var(--accent) 18%, transparent)); +} + +.agent-discovery-copy { + position: relative; + z-index: 1; + display: grid; + justify-items: center; + text-shadow: 0 1px 14px color-mix(in srgb, var(--bg) 72%, transparent); +} + +.agent-discovery-kicker { + margin: 0 0 9px; + color: var(--accent); + font-size: 11px; + font-weight: 700; + letter-spacing: 0.08em; + text-transform: uppercase; +} + +.agent-discovery-copy h1 { + margin: 0; + font-size: 30px; + line-height: 1.2; +} + +.agent-discovery-copy > p:not(.agent-discovery-kicker) { + max-width: 360px; + margin: 10px 0 0; + color: var(--muted); + line-height: 1.55; +} + +.agent-discovery-progress { + width: min(260px, 100%); + height: 3px; + margin-top: 26px; + overflow: hidden; + border-radius: 999px; + background: color-mix(in srgb, var(--border) 68%, transparent); +} + +.agent-discovery-progress span { + display: block; + width: 46%; + height: 100%; + border-radius: inherit; + background: var(--onboarding-frame-gradient); + box-shadow: 0 0 14px color-mix(in srgb, var(--accent) 34%, transparent); + animation: agent-discovery-progress 1.35s ease-in-out infinite; +} + +.agent-discovery-status { + display: inline-flex; + align-items: center; + gap: 7px; + margin-top: 13px; + color: var(--muted); + font-size: 11px; +} + +.agent-discovery-status-dot { + width: 6px; + height: 6px; + border-radius: 50%; + background: var(--accent); + box-shadow: 0 0 0 4px color-mix(in srgb, var(--accent) 12%, transparent); + animation: agent-discovery-dot 1.25s ease-in-out infinite; +} + +.agent-discovery-enter-active, +.agent-discovery-leave-active { + transition: opacity 0.28s ease; +} + +.agent-discovery-enter-active .agent-discovery-content, +.agent-discovery-leave-active .agent-discovery-content { + transition: opacity 0.28s ease, transform 0.28s cubic-bezier(0.16, 1, 0.3, 1); +} + +.agent-discovery-enter-from, +.agent-discovery-leave-to { + opacity: 0; +} + +.agent-discovery-enter-from .agent-discovery-content, +.agent-discovery-leave-to .agent-discovery-content { + opacity: 0; + transform: translateY(8px) scale(0.985); +} + +@keyframes agent-discovery-progress { + 0% { transform: translateX(-125%); opacity: 0.4; } + 55% { opacity: 1; } + 100% { transform: translateX(300%); opacity: 0.4; } +} + +@keyframes agent-discovery-dot { + 0%, 100% { opacity: 0.42; transform: scale(0.86); } + 50% { opacity: 1; transform: scale(1); } +} + +@media (prefers-reduced-motion: reduce) { + .agent-discovery-progress span, + .agent-discovery-status-dot { + animation: none; + } + + .agent-discovery-progress span { + width: 58%; + transform: translateX(36%); + } +} + +@media (max-width: 480px) { + .agent-discovery-overlay { padding: 24px; } + .agent-discovery-copy h1 { font-size: 26px; } + .agent-discovery-mark { margin-bottom: 20px; } +} +/* The sidebar also shows skeleton rows during Agent discovery until the first detection returns. Only transform and opacity animate. */ .sidebar-discovery { display: grid; @@ -53,37 +204,9 @@ color: var(--muted); } -.boot-progress { - width: 140px; - height: 3px; - overflow: hidden; - border-radius: 999px; - background: color-mix(in srgb, var(--border) 70%, transparent); -} - -.boot-progress span { - display: block; - width: 40%; - height: 100%; - border-radius: inherit; - background: var(--accent); - animation: boot-progress 1.2s var(--ease-standard) infinite; -} - -@keyframes boot-progress { - from { transform: translateX(-110%); } - to { transform: translateX(260%); } -} - @media (prefers-reduced-motion: reduce) { .sidebar-discovery-row i, - .sidebar-discovery-row b, - .boot-progress span { + .sidebar-discovery-row b { animation: none; } - - .boot-progress span { - width: 100%; - opacity: 0.5; - } } diff --git a/frontend/src/styles/base-foundation.css b/frontend/src/styles/base-foundation.css index 1b9cb4b..2e140dc 100644 --- a/frontend/src/styles/base-foundation.css +++ b/frontend/src/styles/base-foundation.css @@ -1,4 +1,7 @@ :root { + --pixel-blast-primary: #d92f24; + --pixel-blast-secondary: #007d91; + --pixel-blast-tertiary: #ed512f; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Microsoft YaHei", "Noto Sans CJK SC", sans-serif; font-synthesis: none; text-rendering: optimizeLegibility; @@ -90,6 +93,9 @@ } :root[data-theme="dark"] { + --pixel-blast-primary: #ff836d; + --pixel-blast-secondary: #54f5ff; + --pixel-blast-tertiary: #ffa36f; color-scheme: dark; --bg: #111618; --sidebar: #161c1e;