fix: sidebar collapse, CSS cascade conflicts, download progress, dark-mode marks - #41
Merged
Merged
Conversation
The 900px breakpoint narrows the sidebar to a 72px icon rail and hides the brand, nav and language labels, but the appearance and task centre labels were left visible. At 12px of usable column CJK wraps to one glyph per line, so "外观" rendered 12x33px vertically and "任务中心" folded onto two lines at 45x66px. Both labels now hide with the others. The appearance icon hides too: unlike the language row it had no such rule, so icon + gap + select overflowed the rail and squeezed the select to 30px instead of the 47px its neighbour gets. Neither control loses its accessible name, because the selects carry aria-label and the task centre button keeps the hidden span as its text content. MinWidth/MinHeight on the window are a floor, not a second breakpoint: the rail is meant to collapse under 900px, and the layout is verified down to 560px. They stop the window being dragged narrower than any breakpoint accounts for.
A min-height meant as a 28px floor was applied to a selector list holding .button, .disclosure-trigger, .provider-link and .agent-manage-row. Only .provider-link declares no height of its own; the others declare 38px, 46px and 84px, and .button-compact inherits 32px through .button. Equal specificity plus later source order (app.css loads after base.css) made the floor a ceiling, so every button in the app rendered 10px shorter than designed and the Agent card never applied its 84px. Measured live, all five resolved to 28px. The rule now covers only .provider-link. Three more duplicates went the same way. .agent-manage-pill set colour and background that .agent-manage-state immediately overrode, so shape is now shared and colour is set once per variant. app.css carried a second prefers-reduced-motion block overriding two of the four properties base.css sets, while base.css remained the only one covering ::before/::after. body declared min-height twice nine lines apart. Computed values for all three are unchanged. cascade.test.ts is the first gate that reads CSS. It reports only a genuine conflict -- same context, same selector, same property, different value -- because re-declaring a selector to add different properties is normal authoring, and so is overriding inside a media query. Verified by reinjecting the .agent-manage-row regression, which it reports with both line numbers and the winning value. Also drops .desktop-app-path, which no markup used.
Starting a download and leaving the page hid the bar for the rest of the run, and it never came back. The install itself was unaffected: it runs in Go, independent of the component that asked for it. TaskCenterProvider already sits above the router, so the progress map survived the route change. What did not was the condition around the bar -- each caller gated it on a local useState flag that reset to empty when its page unmounted, while the entry it was hiding stayed in the provider the whole time. The unmount also stranded the outcome. setNotice and setFailure ran on an unmounted component, so an install that finished after the user navigated away reported neither "安装完成" nor its error, and the finally block's resetProgress never took effect. Silence read the same as success. In-flight state and outcome now live in the provider as running and outcomes, with startTask/finishTask around the call. Callers read the shared flag, so remounting mid-download restores the bar and keeps the buttons disabled instead of allowing a second install. Verified by unmounting a row mid-download in a test and asserting the bar returns, the install is not started twice, and the verdict still arrives. RuntimeSection and RuntimePrompt carried the identical pattern and are fixed the same way. ActivationPage already rendered unconditionally and keeps its explicit pending, which is now an override rather than the only way to show a bar.
On the dark theme the five licensed marks rendered as black glyphs on #2c2c2e panels. Painted to a canvas, all 420 opaque pixels of a mark measured rgb(0, 0, 0): roughly 1.2:1 against the panel, effectively invisible. Each asset is distributed as a single-colour glyph that paints with fill="currentColor", and the container already sets the right colour -- var(--icon-fg), which the Lucide marks beside them inherit correctly. The marks could not: loaded through <img src>, an SVG is an isolated document, so currentColor has no page colour to resolve against and falls back to black. The container's colour never reached them. They are now inlined, so currentColor resolves the same way it does for every other icon in the row. Nothing about the artwork changes: the viewBox is untouched and a test asserts it, so the published geometry is preserved. This is inheriting a colour the assets were authored to inherit, not recolouring vendor artwork -- these marks carry no brand colour of their own. The markup is bundled at build time from files in this repository, so dangerouslySetInnerHTML is not receiving runtime input. Also corrects the file header, which said three assets when five ship.
Three conflicts in DesktopAppSection, all on lines both sides edited for unrelated reasons. main threaded a desktop agent id through the API calls and the onSetup callback so several desktop Agents can coexist; this branch moved the in-flight flag and the outcome into TaskCenterProvider. Each conflict keeps both: the id argument from main, the shared busy flag and provider-recorded message from here. The two changes reinforce each other. Progress is keyed by desktopApp.id, so with more than one desktop Agent on the overview each row tracks its own download -- verified by starting one install with two rows mounted and asserting only one bar appears.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Four UI fixes found while investigating two layout reports. Each is a separate commit with its own regression test.
Closes #37, closes #38, closes #39.
侧栏收窄后文字竖排 (#37)
900px 断点把侧栏压到 72px 并隐藏了一批标签,但漏掉两个。在运行的应用里量到「外观」是 12×33px 竖排,「任务中心」45×66px 折两行。
主题选择器的图标也一起隐藏了 —— 语言选择器本来就隐藏自己的图标,不隐藏的话「图标 + gap + select」在 72px 里放不下,select 被压到 30px。现在两者一致(47px,x=12)。两个 select 各自带
aria-label,任务中心按钮保留隐藏 span 作为可访问名称,无障碍不受影响。MinWidth: 560/MinHeight: 480是下限而非第二个断点:折叠栏本来就该在 900px 以下生效,布局验证到 560px 无横向溢出。重复 CSS 规则静默覆盖 (#38)
一条本意是 28px 下限的规则被写进了包含
.button、.disclosure-trigger、.provider-link、.agent-manage-row的选择器列表。只有.provider-link自己没声明高度;其余声明的是 38px、46px、84px,.button-compact通过.button继承 32px。同特异性 + 靠后的源码顺序(app.css在base.css之后)让下限变成了上限:.button.button-compact.disclosure-trigger.agent-manage-row也就是全应用每个按钮都比设计矮 10px,不只是 Agent 卡片。另外清掉三处同类重复(
.agent-manage-pill颜色被.agent-manage-state立刻覆盖、app.css里多余的一份prefers-reduced-motion、body的min-height声明两次),三者计算值均不变,已逐一实测确认。新增
cascade.test.ts—— 这是第一个读 CSS 的门禁。判定收窄到「同上下文、同选择器、同属性、不同值」,因为重复声明本身是正常写法,media query 里覆盖也是。用重新注入.agent-manage-row回归的方式验证过它会失败,并且报出两个行号和胜出值。切页后下载进度与结果丢失 (#39)
TaskCenterProvider在 router 之上,所以progressmap 本来就存活,底层下载也从未中断。丢的是渲染条件 —— 每个调用方都用本地useState标志控制进度条,切页卸载后归零。更严重的是
finally落在已卸载组件上:setNotice/setFailure都不生效,所以切页期间完成的安装既不报「安装完成」也不报错误,静默与成功无法区分。改为把 in-flight 标志与结果放进 provider(
running/outcomes+startTask/finishTask)。重新挂载后进度条恢复,按钮保持 disabled 而不是允许重复安装。RuntimeSection和RuntimePrompt是同一个模式,一并修掉;ActivationPage本来就无条件渲染,不受影响。深色模式下 Agent 图标不可见
五个授权图标在深色主题下是
#2c2c2e面板上的黑色字形。绘到 canvas 上量,420 个不透明像素全是rgb(0,0,0),约 1.2:1 对比度。原因:资产用
fill="currentColor",容器颜色也正确(--icon-fg,旁边的 Lucide 图标继承得没问题),但通过<img src>加载的 SVG 是独立文档,currentColor看不到页面颜色,回落成黑色。改为内联,
currentColor就能像其他图标一样解析。美术资产没有任何改动:viewBox不变并有测试断言,几何形状原样保留。这些字形本身不含品牌色,是被设计成继承文字颜色的,所以这是让它按设计继承,而不是改写厂商美术。dangerouslySetInnerHTML接收的是构建期从本仓库文件打包的内容,不是运行时输入。同时修正了文件头注释 —— 它写「三个资产」,实际发行五个。
验证
go vet ./...干净,go test -race ./...14 个包通过pnpm run build含tsc --noEmit-tags wails桌面构建通过,已在真实桌面应用中重启验证check-docs.py49 文件,licence 6 测试 +--check通过深色模式与折叠侧栏的数值均在运行的应用里实测,不是仅凭代码推断。窗口边框拖拽这一路径只在视口 resize 上验证过。
🤖 Generated with Claude Code