mirror of
https://github.com/Ryder-Sun/Meldwork.git
synced 2026-11-07 06:56:03 -10:00
fix: show one compact theme-aware discovery loader
Remove the duplicate progress bar and pulsing status dot. Reduce wave geometry to 190 by 72 and inherit existing light/dark accent colors. Record the provider-agnostic native CLI boundary in AGENTS.md. Checks: frontend 375 tests; web and desktop builds; desktop pack; Electron first-run and returning-user checks with animated loader, light/dark colors and a 560px window.
This commit is contained in:
1 parent
05ec2bfbf0
commit
d2f6171ddd
5 files changed
+21
-83
No files matched your search
@@ -11,6 +11,7 @@
|
||||
|
||||
- Meldwork is a local-first desktop application. Do not introduce a required server, container, or cluster dependency unless the task explicitly calls for it.
|
||||
- Keep Agent execution in the Electron main process. Renderer access must go through narrow, validated preload APIs.
|
||||
- Respect native Agent configuration and keep CLI integration provider-agnostic. Do not add gateway-specific adapters, provider overrides, or bundled patches for external tools such as Magpie.
|
||||
- Never expose executable paths, tokens, credentials, or unrestricted shell execution to renderer code.
|
||||
- Store secrets only through operating-system-backed secure storage. Do not add plaintext fallbacks.
|
||||
- Keep workspace write access opt-in. Conversations and groups stay local; do not add remote participants, cloud channels, or remote conversation storage.
|
||||
|
||||
@@ -41,9 +41,6 @@
|
||||
<p class="agent-discovery-kicker">{{ t('agentDiscovery.kicker') }}</p>
|
||||
<h1>{{ t('agentDiscovery.title') }}</h1>
|
||||
<p>{{ t('agentDiscovery.body') }}</p>
|
||||
<div class="agent-discovery-progress" aria-hidden="true">
|
||||
<span />
|
||||
</div>
|
||||
<div class="agent-discovery-status">
|
||||
<span class="agent-discovery-status-dot" aria-hidden="true" />
|
||||
<span>{{ t('agentDiscovery.status') }}</span>
|
||||
|
||||
@@ -59,6 +59,8 @@ describe('Meldwork workbench', () => {
|
||||
expect(wrapper.get('.agent-discovery-overlay').text()).toContain('Agent CLI')
|
||||
expect(wrapper.find('.pixel-blast-container').exists()).toBe(true)
|
||||
expect(wrapper.get('.agent-discovery-overlay').find('.wave-physics-loader').exists()).toBe(true)
|
||||
expect(wrapper.get('.agent-discovery-overlay').findAll('.wave-physics-loader')).toHaveLength(1)
|
||||
expect(wrapper.find('.agent-discovery-progress').exists()).toBe(false)
|
||||
expect(wrapper.get('.workspace-pane').attributes()).toHaveProperty('inert')
|
||||
expect(wrapper.get('.sidebar').attributes()).toHaveProperty('inert')
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="wave-physics-loader" aria-hidden="true">
|
||||
<div class="wave-physics-loader" :data-theme="theme" aria-hidden="true">
|
||||
<div class="wave-physics-track">
|
||||
<span
|
||||
v-for="bar in bars"
|
||||
@@ -21,34 +21,23 @@
|
||||
<script setup>
|
||||
import { computed, onBeforeUnmount, onMounted, ref } from 'vue'
|
||||
|
||||
const props = defineProps({
|
||||
defineProps({
|
||||
theme: { type: String, default: 'light' },
|
||||
})
|
||||
|
||||
const numBars = 15
|
||||
const barWidth = 12
|
||||
const barGap = 8
|
||||
const barWidth = 8
|
||||
const barGap = 5
|
||||
const barTotalWidth = barWidth + barGap
|
||||
const B = 4
|
||||
const maxBounce = 60
|
||||
const baseBarH = 16
|
||||
const wavePeakH = 48
|
||||
const maxBounce = 24
|
||||
const baseBarH = 8
|
||||
const wavePeakH = 24
|
||||
const duration = 4000
|
||||
|
||||
const progress = ref(0.5)
|
||||
let animationFrame = 0
|
||||
|
||||
function interpolate(start, end, value) {
|
||||
return Math.round(start + (end - start) * value)
|
||||
}
|
||||
|
||||
function barColor(theme, waveValue) {
|
||||
if (theme === 'dark') {
|
||||
return `rgb(${interpolate(39, 228, waveValue)} ${interpolate(39, 228, waveValue)} ${interpolate(42, 231, waveValue)})`
|
||||
}
|
||||
return `rgb(${interpolate(228, 39, waveValue)} ${interpolate(228, 39, waveValue)} ${interpolate(231, 42, waveValue)})`
|
||||
}
|
||||
|
||||
function frameAt(t) {
|
||||
const xFrac = t < 0.5 ? t / 0.5 : (1 - t) / 0.5
|
||||
const ballIndex = xFrac * (numBars - 1)
|
||||
@@ -57,7 +46,7 @@ function frameAt(t) {
|
||||
|
||||
const bounceH = 4 * bounceF * (1 - bounceF)
|
||||
const heightFactor = Math.max(0, 1 - bounceH * 2)
|
||||
const ballIndent = heightFactor * 20
|
||||
const ballIndent = heightFactor * 10
|
||||
const ballY = (baseBarH + wavePeakH - ballIndent) + bounceH * maxBounce
|
||||
|
||||
const bars = Array.from({ length: numBars }, (_unused, index) => {
|
||||
@@ -68,13 +57,13 @@ function frameAt(t) {
|
||||
let indent = 0
|
||||
if (dist < 1.5) {
|
||||
const indentDist = Math.cos((dist / 1.5) * (Math.PI / 2))
|
||||
indent = indentDist * heightFactor * 20
|
||||
indent = indentDist * heightFactor * 10
|
||||
}
|
||||
|
||||
const barHeight = Math.max(4, baseBarH + waveValue * wavePeakH - indent)
|
||||
const barHeight = Math.max(3, baseBarH + waveValue * wavePeakH - indent)
|
||||
|
||||
return {
|
||||
color: barColor(props.theme, waveValue),
|
||||
color: `color-mix(in srgb, var(--accent) ${Math.round(waveValue * 100)}%, var(--accent-soft))`,
|
||||
height: `${barHeight}px`,
|
||||
index,
|
||||
}
|
||||
@@ -83,7 +72,7 @@ function frameAt(t) {
|
||||
return {
|
||||
bars,
|
||||
ball: {
|
||||
color: props.theme === 'dark' ? 'rgb(244, 244, 245)' : 'rgb(24, 24, 27)',
|
||||
color: 'var(--accent)',
|
||||
scaleX: 1 + heightFactor * 0.25,
|
||||
scaleY: 1 - heightFactor * 0.3,
|
||||
x: `${ballIndex * barTotalWidth}px`,
|
||||
@@ -126,16 +115,16 @@ onBeforeUnmount(() => {
|
||||
|
||||
.wave-physics-track {
|
||||
position: relative;
|
||||
width: 292px;
|
||||
height: 192px;
|
||||
width: 190px;
|
||||
height: 72px;
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
justify-content: flex-start;
|
||||
gap: 8px;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
.wave-physics-bar {
|
||||
width: 12px;
|
||||
width: 8px;
|
||||
border-radius: 999px;
|
||||
transform-origin: bottom center;
|
||||
will-change: height, background-color;
|
||||
@@ -145,22 +134,14 @@ onBeforeUnmount(() => {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 999px;
|
||||
transform-origin: bottom center;
|
||||
box-shadow: 0 1px 3px color-mix(in srgb, currentColor 24%, transparent);
|
||||
will-change: transform, background-color;
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.wave-physics-track {
|
||||
width: 260px;
|
||||
transform: scale(0.9);
|
||||
transform-origin: center;
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.wave-physics-bar,
|
||||
.wave-physics-ball {
|
||||
|
||||
@@ -67,25 +67,6 @@
|
||||
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;
|
||||
@@ -101,7 +82,6 @@
|
||||
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,
|
||||
@@ -125,29 +105,6 @@
|
||||
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; }
|
||||
|
||||
Reference in new issue
Block a user