Skip to content

feat(web): collapsible squad rail (toggle + breakpoint + ⌘\)#70

Merged
SymbolStar merged 2 commits into
mainfrom
feat/squad-rail-collapsible
Jun 11, 2026
Merged

feat(web): collapsible squad rail (toggle + breakpoint + ⌘\)#70
SymbolStar merged 2 commits into
mainfrom
feat/squad-rail-collapsible

Conversation

@SymbolStar

Copy link
Copy Markdown
Owner

What

让左侧 squad rail 可折叠:48px 图标态 ↔ 默认 260px 展开态。

How

  • Toggle: brand header 左侧加 «/» 按钮(aria-expanded + aria-label,hover 区扩到整条 header)。
  • 过渡: #home-viewgrid-template-columns 加 200ms ease-out;内部 label 用 opacity + translateX(-8px) 150ms 先完成淡出,避免文字穿帮(按 dora 的细节确认)。
  • 优先级合并(bobby 在 thread 里给出的方案):
    userPreference (localStorage openforge.sidebar.squad.collapsed) ?? autoCollapsed (matchMedia(max-width: 1099px))。用户手动切过一次后,断点变化不会再覆盖。
  • 快捷键: Cmd/Ctrl + \ 切换(已 grep 确认 Backslash 未被其他 hotkey 占用)。
  • 折叠态视觉: 圆形 28px icon,active 用 #262626 底 + #4F8CFF ring(不拉满宽);.has-unread → 右上 6px #FF4757 红点带 #0A0A0A halo。
  • Tooltip: 浮层固定颜色 #1a1d24 / #FFFFFF、阴影 0 4px 12px rgba(0,0,0,.4);hover 400ms 后弹出,触屏长按 300ms 弹出,rail 滚动/窗口 resize/blur/折叠瞬间立刻关掉。
  • A11y: MutationObserverrenderSquadRail 重建列表后给每个 .squad-itemaria-label=<squad name>,VoiceOver 可读;toggle 按钮 aria-expanded 跟随状态。
  • Reduced motion: @media (prefers-reduced-motion: reduce) 关掉所有过渡。
  • Dark mode 纪律: rail 是 always-dark token island,颜色全部用字面值(不用 var(--text-on-accent) 也不用 color: inherit,避开 MEMORY 里记的那次翻车)。

Files

  • web/index.html — brand header 新增 toggle 按钮 (+3 lines)
  • web/style.css — collapsed 态 + tooltip + 过渡 (+141 lines)
  • web/app.js — IIFE squadRailCollapsible() (+165 lines)

Mock 对照

按 designer 三档 mock 实现:

  • mock-1920: 默认展开 + 红点未读
  • mock-1280: 上半展开、下半折叠 + tooltip
  • mock-1100: 自动折叠

Manual tests

  • 1920 / 1280 / 1100 三档刷新行为对得上 mock
  • toggle 按钮 / ⌘\ 切换、状态写入 localStorage 持久
  • 在 1000px 手动展开 → 拖宽到 1920 → 拖窄回 1000:保持展开(不自动折)
  • 折叠态 hover 400ms 弹 tooltip,离开消失,滚动关掉
  • 折叠瞬间正在 hover tooltip 立即关闭
  • dark / light 主题下 rail 始终是字面值色(无白底白字翻车)
  • VoiceOver 念出 squad 名

Refs

Thread: th_19eb051b00c_908369 (OpenForge designer/bobby 协作)

- Add « / » toggle button in brand header (aria-expanded, aria-label).
- Body class .squad-collapsed switches #home-view grid to 48px fixed
  width with 200ms ease-out transition; gutter hidden in collapsed mode.
- Labels (brand-title / section-label / squad-name / count / badge /
  new-squad-btn / archive toggle) fade out in 150ms (opacity +
  translateX(-8px)) so text clears before the width shrinks (per dora's
  ack on translation-only label motion).
- Collapsed-mode active squad shows only a 28px circular icon-cell
  highlight (#262626 bg + #4F8CFF ring), not full-width.
- has-unread → 6px #FF4757 dot on top-right of icon with #0A0A0A halo.
- Floating tooltip (#1a1d24 / #FFFFFF, 4/12 rgba(0,0,0,.4) shadow)
  shows full squad name after 400ms hover (300ms long-press on touch).
- localStorage key 'openforge.sidebar.squad.collapsed' persists user
  preference; matchMedia (max-width:1099px) auto-collapses; user choice
  always wins (no re-auto after manual expand, per bobby's plan).
- Cmd/Ctrl+\ toggles (Backslash unused elsewhere — checked).
- MutationObserver sets aria-label=<squad name> on each item for VO.
- prefers-reduced-motion disables transitions.
- All colors literal — rail is always-dark token island (MEMORY
  --text-on-accent flip landmine avoided).
@github-actions

github-actions Bot commented Jun 10, 2026

Copy link
Copy Markdown

🤖 bot-review (comment-only · phase 1)

Diff: 3 files changed, 343 insertions(+) @ 2ccc4c6

Red-line checks:

  • ✅ A-7.5: no new 'forbidden' code in xiaof

Phase 1: this bot leaves comments only. Auto-approve will be enabled per-path after 1–2 weeks of clean runs. Promotion plan: judy PR #42 follow-up.

designer flagged: collapsing the brand row hides .brand-settings-btn,
so users have no way to reach Settings when the rail is collapsed.
Per dora's option 2 (footer is the utility lane / IA-correct):

- index.html: add #btn-settings-collapsed in .footer-help.
- style.css: in body.squad-collapsed mode, hide status dot/text and
  show a single 40\u00d740 \u2699 button that fills the centered footer.
- app.js: click delegates to the existing #btn-settings (no duplicated
  modal wiring).

Literal colors only \u2014 same dark-island discipline as the rest of the
rail (no --text-on-accent / inherit).
@SymbolStar SymbolStar merged commit 3378742 into main Jun 11, 2026
6 of 7 checks passed
SymbolStar added a commit that referenced this pull request Jun 11, 2026
…el (#73)

PR #72 fixed the toggle hit-box but designer's regression flagged a
320px gray ghost panel hugging the squad rail in collapsed mode at
1100/1280/1920. Root cause: source-order grid mis-mapping.

#home-view has 5 grid items: squad-rail, squad-gutter, thread-rail,
thread-gutter, thread-pane. PR #70 set
  body.squad-collapsed .col-gutter[data-gutter="squad"] { display:none; }
which removes the squad-gutter from grid layout, but the collapsed
template was still 5-track (48px / 0 / w-thread / 5px / 1fr). With only
4 items left, source order packed them into tracks 1\u20134:
  squad-rail \u2192 48px
  thread-rail \u2192 0px  (squashed)
  thread-gutter \u2192 320px (renders as a fat empty gutter \u2014 the "ghost")
  thread-pane \u2192 5px (squashed)
  track 5 (1fr) \u2192 empty
That left, mid-empty, mid-empty layout is exactly the screenshots.

Fix: collapsed template becomes a 4-track grid that matches the 4
visible items (48px / w-thread / 5px / 1fr). Also pin
#squad-rail { width:48px } in collapsed mode so any stale inline
--w-squad from earlier user drags can't bleed through.

Verified DOM mentally against designer's three crops; no JS change
needed.
SymbolStar added a commit that referenced this pull request Jun 11, 2026
…el (#74)

PR #72 fixed the toggle hit-box but designer's regression flagged a
320px gray ghost panel hugging the squad rail in collapsed mode at
1100/1280/1920. Root cause: source-order grid mis-mapping.

#home-view has 5 grid items: squad-rail, squad-gutter, thread-rail,
thread-gutter, thread-pane. PR #70 set
  body.squad-collapsed .col-gutter[data-gutter="squad"] { display:none; }
which removes the squad-gutter from grid layout, but the collapsed
template was still 5-track (48px / 0 / w-thread / 5px / 1fr). With only
4 items left, source order packed them into tracks 1\u20134:
  squad-rail \u2192 48px
  thread-rail \u2192 0px  (squashed)
  thread-gutter \u2192 320px (renders as a fat empty gutter \u2014 the "ghost")
  thread-pane \u2192 5px (squashed)
  track 5 (1fr) \u2192 empty
That left, mid-empty, mid-empty layout is exactly the screenshots.

Fix: collapsed template becomes a 4-track grid that matches the 4
visible items (48px / w-thread / 5px / 1fr). Also pin
#squad-rail { width:48px } in collapsed mode so any stale inline
--w-squad from earlier user drags can't bleed through.

Verified DOM mentally against designer's three crops; no JS change
needed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant