Skip to content

fix: sidebar collapse, CSS cascade conflicts, download progress, dark-mode marks - #41

Merged
yujiezhang-ops merged 5 commits into
mainfrom
fix/sidebar-collapse-and-css-cascade
Aug 5, 2026
Merged

fix: sidebar collapse, CSS cascade conflicts, download progress, dark-mode marks#41
yujiezhang-ops merged 5 commits into
mainfrom
fix/sidebar-collapse-and-css-cascade

Conversation

@yujiezhang-ops

Copy link
Copy Markdown
Collaborator

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.cssbase.css 之后)让下限变成了上限:

选择器 声明值 修前生效
.button 38px 28px
.button-compact 32px 28px
.disclosure-trigger 46px 28px
.agent-manage-row 84px 28px

也就是全应用每个按钮都比设计矮 10px,不只是 Agent 卡片。另外清掉三处同类重复(.agent-manage-pill 颜色被 .agent-manage-state 立刻覆盖、app.css 里多余的一份 prefers-reduced-motionbodymin-height 声明两次),三者计算值均不变,已逐一实测确认。

新增 cascade.test.ts —— 这是第一个读 CSS 的门禁。判定收窄到「同上下文、同选择器、同属性、不同值」,因为重复声明本身是正常写法,media query 里覆盖也是。用重新注入 .agent-manage-row 回归的方式验证过它会失败,并且报出两个行号和胜出值。

切页后下载进度与结果丢失 (#39)

TaskCenterProvider 在 router 之上,所以 progress map 本来就存活,底层下载也从未中断。丢的是渲染条件 —— 每个调用方都用本地 useState 标志控制进度条,切页卸载后归零。

更严重的是 finally 落在已卸载组件上:setNotice / setFailure 都不生效,所以切页期间完成的安装既不报「安装完成」也不报错误,静默与成功无法区分

改为把 in-flight 标志与结果放进 provider(running / outcomes + startTask / finishTask)。重新挂载后进度条恢复,按钮保持 disabled 而不是允许重复安装。RuntimeSectionRuntimePrompt 是同一个模式,一并修掉;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 个包通过
  • 前端 156 个测试通过(原 148),pnpm run buildtsc --noEmit
  • -tags wails 桌面构建通过,已在真实桌面应用中重启验证
  • check-docs.py 49 文件,licence 6 测试 + --check 通过
  • 第一个提交单独验证过可独立通过,便于 bisect

深色模式与折叠侧栏的数值均在运行的应用里实测,不是仅凭代码推断。窗口边框拖拽这一路径只在视口 resize 上验证过。

🤖 Generated with Claude Code

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.
@yujiezhang-ops
yujiezhang-ops merged commit dee448f into main Aug 5, 2026
4 checks passed
@Paulkm2006
Paulkm2006 deleted the fix/sidebar-collapse-and-css-cascade branch August 5, 2026 10:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant