feat(docs): add opt-in sticky table header, enable on Progress Board - #1992
feat(docs): add opt-in sticky table header, enable on Progress Board#1992te6-in wants to merge 3 commits into
Conversation
`TableRoot` gains a `stickyHeader` prop, off by default. When on, the wrapper becomes a bounded-height scroll box and `thead th` pins to its top — the only arrangement that works without JS, since `overflow-x-auto` already makes the wrapper a scroll container in both axes and so captures any sticky descendant. The height is capped to the viewport (`100dvh` minus the fumadocs header row) because a box taller than the screen would carry its pinned header off-screen with it. Two rules had to move to the cells, which are what actually stick: - the row separator lives on `tr` (`[&_tr]:border-b`), so it detached from the pinned header and scrolled away; it now sits on `thead th` - the Progress Board's sticky corner cell needs `z-20!` and its existing `bg-…!`, since `[&_thead_th]:` (0,1,2) outranks a plain utility class Markdown tables are untouched: they never pass the prop, so their wrapper, `max-height`, and `th` positioning are unchanged. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018XHskjCS2GuqyqjenH1VJn
|
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthrough
ChangesSticky 헤더 테이블
Estimated code review effort: 2 (Simple) | ~10 minutes 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Alpha Preview (Stackflow SPA)
|
Alpha Preview (Storybook)
|
Alpha Preview (Docs)
|
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/components/table.tsx`:
- Line 46: 공유 TableRoot 레시피의 seedStickyHeaderChrome에서 고정된 bg-bg-layer-default
표면색을 제거하고 CSS 변수 참조만 유지하세요. stickyHeader 헤더의 불투명 배경은 보존하되, 실제 변수 값은
wrapperClassName 또는 docs wrapper의 스타일에서 정의해 각 문서 래퍼가 색상을 제어하도록 변경하세요.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 91dc60cc-d684-40de-9a18-474f7b6f5ef9
📒 Files selected for processing (2)
docs/components/progress-board-table.tsxdocs/components/table.tsx
| const seedStickyHeaderChrome = clsx( | ||
| "[&_thead_th]:sticky [&_thead_th]:top-0 [&_thead_th]:z-10", | ||
| // seedTableChrome의 `[&_th]:bg-transparent`를 이겨, 지나가는 본문 행이 헤더 뒤로 비치지 않게 한다 | ||
| "[&_thead_th]:bg-bg-layer-default", |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win
공유 TableRoot 레시피에서 표면색을 고정하지 마세요.
Line 46의 bg-bg-layer-default는 stickyHeader를 사용하는 모든 TableRoot에 표면색을 강제합니다. 헤더의 불투명 배경은 필요하지만, 색상은 docs wrapper의 CSS 변수로 공급해야 합니다. seedStickyHeaderChrome에는 변수 참조만 남기고, wrapperClassName 또는 docs wrapper에서 값을 정의하세요.
As per coding guidelines: "공유 recipe의 표면 색상은 recipe 자체가 아니라 docs wrapper에서 CSS 변수로 중립화한다."
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/components/table.tsx` at line 46, 공유 TableRoot 레시피의
seedStickyHeaderChrome에서 고정된 bg-bg-layer-default 표면색을 제거하고 CSS 변수 참조만 유지하세요.
stickyHeader 헤더의 불투명 배경은 보존하되, 실제 변수 값은 wrapperClassName 또는 docs wrapper의 스타일에서
정의해 각 문서 래퍼가 색상을 제어하도록 변경하세요.
Source: Coding guidelines
The first attempt turned the wrapper into a bounded-height scroll box, so the table scrolled inside itself. The page should stay the scroll subject and only the header row should pin under the site header. That requires the wrapper to stop being a scroll container, which also gives up horizontal scrolling — so the swap only happens at `md` and up, where the table fits. Below `md` the wrapper keeps `overflow-x-auto`, the header does not stick, and the sticky first column still works. `md` is safe because the table's min-content width is 584px against 720px of article column there; between 584px and its 678px max-content it only wraps rather than overflowing. Overflowing would be silent data loss: the docs layout root is `overflow-x: clip`, so clipped columns get no scrollbar to reveal them. The offset comes from fumadocs' `--fd-docs-row-2`, which already tracks the responsive header height (64/72/76px). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018XHskjCS2GuqyqjenH1VJn
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
docs/components/progress-board-table.tsx (1)
94-95: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win좌상단 sticky 헤더 셀의
z-index를 높이세요.모바일에서 표를 수평 스크롤할 때 뒤의 헤더 셀이 좌상단 셀을 덮을 수 있습니다.
TableRoot의z-10은md이상에서만 적용되며, 좌상단 셀에는 별도z-index가 없습니다. 해당 셀에z-20!을 추가하세요.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/components/progress-board-table.tsx` around lines 94 - 95, Update the sticky top-left header cell in the table markup to add the `z-20!` utility to its existing className, ensuring it remains above other header cells during horizontal scrolling on all viewport sizes.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/components/table.tsx`:
- Around line 50-51: In the table styles, update the sticky header border
utility in the thead/th selector to use the exposed
border-palette-static-*-alpha-* token instead of border-stroke-neutral-muted,
choosing a static-alpha value with sufficient contrast in both light and dark
themes. Preserve the existing responsive border placement.
---
Outside diff comments:
In `@docs/components/progress-board-table.tsx`:
- Around line 94-95: Update the sticky top-left header cell in the table markup
to add the `z-20!` utility to its existing className, ensuring it remains above
other header cells during horizontal scrolling on all viewport sizes.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 64c1316b-9652-44ba-8a84-e09190a813fa
📒 Files selected for processing (2)
docs/components/progress-board-table.tsxdocs/components/table.tsx
| // 구분선은 `[&_tr]:border-b`로 tr에 그려지는데 고정되는 건 th뿐이라 선만 떨어져 스크롤된다. 셀로 옮겨야 헤더를 따라 남는다 | ||
| "md:[&_thead_th]:border-b md:[&_thead_th]:border-stroke-neutral-muted", |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -eu
printf '%s\n' '--- target file ---'
sed -n '1,120p' docs/components/table.tsx
printf '%s\n' '--- token references ---'
rg -n --glob '**/*.{tsx,ts,css,md,json}' \
'border-stroke-neutral-muted|palette-static-[^"'\''[:space:]]*-alpha-[^"'\''[:space:]]*|static-alpha|stroke-neutral-muted' .
printf '%s\n' '--- candidate style/token files ---'
git ls-files | rg '(^|/)(global\.css|.*tailwind.*|.*theme.*|.*token.*|.*seed.*|.*css)$' | head -80Repository: daangn/seed-design
Length of output: 50375
🏁 Script executed:
#!/bin/bash
set -eu
printf '%s\n' '--- target excerpt from prior output ---'
sed -n '1,100p' /tmp/coderabbit-shell-logs/shell-output-gWA59W
printf '%s\n' '--- tracked source files containing target token ---'
rg -n --glob '!**/dist/**' --glob '!**/build/**' --glob '!**/.next/**' \
--glob '!**/node_modules/**' --glob '*.{tsx,ts,css,md,json}' \
'border-stroke-neutral-muted' . | head -80
printf '%s\n' '--- tracked source files containing static-alpha token names ---'
rg -n --glob '!**/dist/**' --glob '!**/build/**' --glob '!**/.next/**' \
--glob '!**/node_modules/**' --glob '*.{tsx,ts,css,md,json}' \
'palette-static-[A-Za-z0-9_-]*-alpha-[A-Za-z0-9_]+' . | head -120
printf '%s\n' '--- token/config file candidates ---'
git ls-files | rg '(^|/)(global\.css|.*tailwind.*|.*theme.*|.*token.*|.*seed.*|.*css)$' | head -120Repository: daangn/seed-design
Length of output: 31226
🏁 Script executed:
#!/bin/bash
set -eu
printf '%s\n' '--- docs global CSS relevant imports and overrides ---'
rg -n -C 4 'tailwind4-theme|seed-design|color-stroke|palette-static|important|thead|table' docs/app/global.css
printf '%s\n' '--- direct static-alpha border utilities in docs source ---'
rg -n --glob 'docs/**/*.{tsx,ts,css,md,mdx}' \
'border-(palette-static|color-palette-static)|border-(?:[xytrbl]-)?palette-static|palette-static-.*alpha' . | head -120
printf '%s\n' '--- semantic and static token definitions ---'
sed -n '260,290p' packages/lynx-qvism-preset/src/token.css
sed -n '475,500p' packages/lynx-qvism-preset/src/token.css
sed -n '1,115p' packages/tailwind4-theme/index.css
printf '%s\n' '--- theme declarations around token blocks ---'
sed -n '160,225p' packages/lynx-qvism-preset/src/token.css
sed -n '380,435p' packages/lynx-qvism-preset/src/token.css
printf '%s\n' '--- git diff summary ---'
git diff --stat -- docs/components/table.tsxRepository: daangn/seed-design
Length of output: 22215
🏁 Script executed:
#!/bin/bash
set -eu
printf '%s\n' '--- docs global CSS relevant imports and overrides ---'
rg -n -C 4 'tailwind4-theme|seed-design|color-stroke|palette-static|important|thead|table' docs/app/global.css
printf '%s\n' '--- direct static-alpha border utilities in docs source ---'
rg -n --glob 'docs/**/*.{tsx,ts,css,md,mdx}' \
'border-(palette-static|color-palette-static)|border-(xytrbl-)?palette-static|palette-static-.*alpha' . | head -120
printf '%s\n' '--- semantic and static token definitions ---'
sed -n '260,290p' packages/lynx-qvism-preset/src/token.css
sed -n '475,500p' packages/lynx-qvism-preset/src/token.css
sed -n '1,115p' packages/tailwind4-theme/index.css
printf '%s\n' '--- theme declarations around token blocks ---'
sed -n '160,225p' packages/lynx-qvism-preset/src/token.css
sed -n '380,435p' packages/lynx-qvism-preset/src/token.css
printf '%s\n' '--- git diff summary ---'
git diff --stat -- docs/components/table.tsxRepository: daangn/seed-design
Length of output: 22215
🏁 Script executed:
#!/bin/bash
set -eu
python3 - <<'PY'
from pathlib import Path
import re
token_css = Path("packages/lynx-qvism-preset/src/token.css").read_text()
theme_css = Path("packages/tailwind4-theme/index.css").read_text()
def block_after(marker):
start = token_css.index(marker)
end = token_css.find("\n}", start)
return token_css[start:end if end != -1 else len(token_css)]
light = block_after(":root {")
dark_start = token_css.index('`@media` (prefers-color-scheme: dark)')
dark = token_css[dark_start:token_css.find("\n}", dark_start)]
for label, block in [("light", light), ("dark", dark)]:
match = re.search(
r"--seed-color-stroke-neutral-muted:\s*var\((--seed-color-palette-static-[^)]+)\)",
block,
)
print(f"{label}: {match.group(1) if match else 'not found'}")
for name in [
"--color-palette-static-black-alpha-300",
"--color-palette-static-white-alpha-100",
]:
print(f"tailwind exposure {name}: {name in theme_css}")
PYRepository: daangn/seed-design
Length of output: 262
🏁 Script executed:
#!/bin/bash
set -eu
printf '%s\n' '--- token CSS selectors and target declarations ---'
sed -n '1,35p' packages/lynx-qvism-preset/src/token.css
rg -n -C 3 \
'prefers-color-scheme|data-theme|color-scheme|--seed-color-stroke-neutral-muted' \
packages/lynx-qvism-preset/src/token.css | head -100
printf '%s\n' '--- focused declaration verifier ---'
python3 - <<'PY'
from pathlib import Path
import re
token_css = Path("packages/lynx-qvism-preset/src/token.css").read_text()
theme_css = Path("packages/tailwind4-theme/index.css").read_text()
matches = re.findall(
r"--seed-color-stroke-neutral-muted:\s*var\((--seed-color-palette-static-[^)]+)\)",
token_css,
)
print("stroke-neutral-muted mappings:", matches)
for name in [
"--color-palette-static-black-alpha-300",
"--color-palette-static-white-alpha-100",
]:
print(f"tailwind exposure {name}:", name in theme_css)
PYRepository: daangn/seed-design
Length of output: 3373
Sticky 헤더 보더를 static-alpha 토큰으로 교체하세요.
md:[&_thead_th]:border-stroke-neutral-muted는 semantic stroke token입니다. Tailwind theme에 노출된 border-palette-static-*-alpha-* 토큰을 사용하고 라이트·다크 테마의 대비를 확인하세요.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/components/table.tsx` around lines 50 - 51, In the table styles, update
the sticky header border utility in the thead/th selector to use the exposed
border-palette-static-*-alpha-* token instead of border-stroke-neutral-muted,
choosing a static-alpha value with sufficient contrast in both light and dark
themes. Preserve the existing responsive border placement.
Source: Coding guidelines
`--fd-docs-row-2` sums the banner and the header on the assumption that they stack vertically. On this site both are `sticky top-0`, so the header paints over the banner and the pinned chrome ends at the header's own height. Using row-2 left a banner-height gap below the site header that body rows scrolled through. Only deployments that render the banner show it — locally the banner is absent, so row-1 is 0 and the two values coincide. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018XHskjCS2GuqyqjenH1VJn
Summary by CodeRabbit