Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
311 commits
Select commit Hold shift + click to select a range
16c01cc
Add NodeFlare to nodes-as-a-service providers list
BabyScope May 20, 2026
7ce492c
fix(seo): normalize locale codes to BCP 47 for lang and hreflang attr…
nloureiro May 21, 2026
531f884
refactor(IssuesList): self-fetch GFIs, remove MDX scope plumbing
pettinarip May 21, 2026
0f5ba5e
Merge branch 'dev' into ui-card
myelinated-wackerow May 21, 2026
491b838
build(deps): bump uuid from 13.0.0 to 13.0.2
dependabot[bot] May 21, 2026
3f5d98f
refactor: ui/card update, clean-up and implementation
myelinated-wackerow May 21, 2026
ab42812
Merge branch 'dev' into ui-card
myelinated-wackerow May 21, 2026
0e496f7
patch: tds header spacing
myelinated-wackerow May 21, 2026
38b3ee2
Merge branch 'dev' into ui-card
wackerow May 21, 2026
6d7409e
feat: add /reports page under Research menu
konopkja May 22, 2026
af80536
refactor: apply border to `header-bar` variant
myelinated-wackerow May 22, 2026
533fffb
Leaderboard: Update for aarnavrotten post 1380
bshastry May 22, 2026
0ecf73c
perf(reports): convert cover images to WebP
konopkja May 22, 2026
596990f
docs(reports): rewrite intro copy in educational voice
konopkja May 22, 2026
026da2c
refactor(ui): use text-body-medium as CardContent default
myelinated-wackerow May 22, 2026
b217d5a
feat(reports): show PDF file size on cards linking direct PDFs
konopkja May 22, 2026
58e0256
docs(skill): standardize Card usage guidance
myelinated-wackerow May 22, 2026
b7decbf
fix: add missing docs-nav-data-availability-description translation key
andreivladbrg May 22, 2026
b0ca60b
feat(reports): link 4 more reports directly to their PDFs
konopkja May 22, 2026
b7b2f4a
fix(codeblock): switch shiki theme to vitesse
pettinarip May 22, 2026
f7b6c34
fix: banner image blurred background styling
myelinated-wackerow May 22, 2026
c1fc143
docs(stories): Card matrix + MarkdownCard title
myelinated-wackerow May 22, 2026
9b9c1f4
i18n(zh): align quantum-resistance with zh-tw
myelinated-wackerow May 22, 2026
2bec07a
Update chains data
actions-user May 22, 2026
5a10381
Merge pull request #18241 from ethereum/intl/pending-qr-breadcrumb
wackerow May 22, 2026
0ef3de2
Merge pull request #18255 from bshastry/aarnav-1380-geth-info
wackerow May 22, 2026
4d44869
Merge pull request #18253 from ethereum/dependabot/npm_and_yarn/uuid-…
wackerow May 23, 2026
647106d
Merge pull request #18265 from ethereum/automated-update-20260522170224
wackerow May 23, 2026
c9c2849
Merge branch 'dev' into md-alert-spacing
myelinated-wackerow May 23, 2026
6373803
fix(ui): external link color styling
myelinated-wackerow May 23, 2026
2ba76fc
fix(ui): first element alignment in markdown MainArticle
myelinated-wackerow May 23, 2026
7bde5a7
Merge branch 'ui-card' of github.com:ethereum/ethereum-org-website in…
myelinated-wackerow May 23, 2026
18fd314
feat(ui): enable ctaLabel/href props for MarkdownCard
myelinated-wackerow May 23, 2026
e21db78
refactor(ui): ui/callout unification
myelinated-wackerow May 24, 2026
5221699
fix(10years): remove unwanted shadow from tabs list
nloureiro May 25, 2026
7c30e86
fix(leaderboard): remove hover border-radius from list items
nloureiro May 25, 2026
4c2573a
i18n(ar): LLM translation
wackerow May 25, 2026
b908cf9
i18n(bn): LLM translation
wackerow May 25, 2026
a48ac9d
i18n(cs): LLM translation
wackerow May 25, 2026
f3fb483
i18n(de): LLM translation
wackerow May 25, 2026
7ad004d
i18n(es): LLM translation
wackerow May 25, 2026
12c228f
i18n(fr): LLM translation
wackerow May 25, 2026
c9e4822
i18n(hi): LLM translation
wackerow May 25, 2026
72310d7
i18n(id): LLM translation
wackerow May 25, 2026
a9e496f
i18n(it): LLM translation
wackerow May 25, 2026
a4d370f
i18n(ja): LLM translation
wackerow May 25, 2026
95a4f79
i18n(ko): LLM translation
wackerow May 25, 2026
11b3baf
i18n(mr): LLM translation
wackerow May 25, 2026
f480d36
i18n(pl): LLM translation
wackerow May 25, 2026
69384f2
i18n(pt-br): LLM translation
wackerow May 25, 2026
35397b6
i18n(ru): LLM translation
wackerow May 25, 2026
c10410a
i18n(sw): LLM translation
wackerow May 25, 2026
2038bd7
i18n(ta): LLM translation
wackerow May 25, 2026
85ebeac
i18n(te): LLM translation
wackerow May 25, 2026
cc8ce95
i18n(tr): LLM translation
wackerow May 25, 2026
b136a20
i18n(uk): LLM translation
wackerow May 25, 2026
2d6461f
i18n(ur): LLM translation
wackerow May 25, 2026
acffd1c
i18n(vi): LLM translation
wackerow May 25, 2026
9be4eb1
i18n(zh): LLM translation
wackerow May 25, 2026
8dea2ec
i18n(zh-tw): LLM translation
wackerow May 25, 2026
bca78df
i18n: merge tmp-intl/run-0525-1037 into intl/pending-dev
wackerow May 25, 2026
8d58c8e
fix(10years): fully override TabsList default shadow and border
nloureiro May 25, 2026
b7df5b9
fix(10years): restore default TabsList style, keep only layout overrides
nloureiro May 25, 2026
214187d
fix(10years): let TabsList use default max-w-fit width
nloureiro May 25, 2026
77f78f7
refactor(intl): migrate strings from json to markdown
myelinated-wackerow May 25, 2026
3e0b6ad
Merge branch 'staging' into dev
pettinarip May 25, 2026
e7309c5
refactor(ui): ui/callout unification and implementation
myelinated-wackerow May 25, 2026
08df5b2
feat(reports): refresh cover artwork + add Ethereum Basics card
konopkja May 25, 2026
bf33bc5
perf(reports): re-encode hero from higher-resolution source
konopkja May 25, 2026
e6c6bc9
docs(skill): document unified ui/callout
myelinated-wackerow May 25, 2026
f40802c
refactor(storybook): ui/callout stories
myelinated-wackerow May 25, 2026
9a96285
fix: /review-translations filter API field
myelinated-wackerow May 25, 2026
2b6a038
Merge pull request #18273 from ethereum/intl/pending-dev
wackerow May 25, 2026
78e4c4e
Merge branch 'dev' into ui-card
myelinated-wackerow May 26, 2026
754fa17
chore: remove stray intl namespace files
myelinated-wackerow May 26, 2026
092036f
i18n(ar): LLM translation
wackerow May 26, 2026
f077455
i18n(bn): LLM translation
wackerow May 26, 2026
1e7df3b
i18n(cs): LLM translation
wackerow May 26, 2026
814c786
i18n(de): LLM translation
wackerow May 26, 2026
9ecf8d9
i18n(es): LLM translation
wackerow May 26, 2026
40b9bb6
i18n(fr): LLM translation
wackerow May 26, 2026
024c28c
i18n(hi): LLM translation
wackerow May 26, 2026
a467ef5
i18n(id): LLM translation
wackerow May 26, 2026
8dd9573
i18n(it): LLM translation
wackerow May 26, 2026
4e585bf
i18n(ja): LLM translation
wackerow May 26, 2026
cb48f7e
i18n(ko): LLM translation
wackerow May 26, 2026
636c48e
i18n(mr): LLM translation
wackerow May 26, 2026
c18c5a3
i18n(pl): LLM translation
wackerow May 26, 2026
4f6f7fd
i18n(pt-br): LLM translation
wackerow May 26, 2026
5e3c44e
i18n(ru): LLM translation
wackerow May 26, 2026
fd88d4d
i18n(sw): LLM translation
wackerow May 26, 2026
8f6cb9b
i18n(ta): LLM translation
wackerow May 26, 2026
5ce0456
i18n(te): LLM translation
wackerow May 26, 2026
5ab1336
i18n(tr): LLM translation
wackerow May 26, 2026
4d85b06
i18n(uk): LLM translation
wackerow May 26, 2026
4cd8c81
i18n(ur): LLM translation
wackerow May 26, 2026
be79aa9
i18n(vi): LLM translation
wackerow May 26, 2026
3085e8d
i18n(zh): LLM translation
wackerow May 26, 2026
c7e65ce
i18n(zh-tw): LLM translation
wackerow May 26, 2026
0a48d00
i18n: sanitize translation output
wackerow May 26, 2026
5340bd1
i18n: merge tmp-intl/run-0526-0659 into intl/pending-dev
wackerow May 26, 2026
65e32ee
Merge pull request #18275 from ethereum/fix/intl-review-filter-conten…
wackerow May 26, 2026
af95dd9
i18n: fix 4 review issues (es/sw/zh/tr)
myelinated-wackerow May 26, 2026
57b9a4e
Leaderboard: Update for Jie Ma
bshastry May 26, 2026
1658afa
feat(reports): expand JSON-LD with CollectionPage + per-report ItemList
konopkja May 26, 2026
b63c00c
feat(reports): swap hero to existing what-is-ethereum-network illustr…
konopkja May 26, 2026
3ec7d2c
Merge pull request #18278 from ethereum/intl/pending-dev
wackerow May 26, 2026
7509e40
seo(reports): set H1 to "Reports on Ethereum from institutions"
konopkja May 26, 2026
8b2dca3
Merge branch 'dev' into ui-card
myelinated-wackerow May 26, 2026
e1bb83f
i18n(ar): LLM translation
wackerow May 26, 2026
07eadea
i18n(bn): LLM translation
wackerow May 26, 2026
634bd94
i18n(cs): LLM translation
wackerow May 26, 2026
575226b
i18n(de): LLM translation
wackerow May 26, 2026
97e0be2
i18n(es): LLM translation
wackerow May 26, 2026
a53ef44
i18n(fr): LLM translation
wackerow May 26, 2026
e85a4c9
i18n(hi): LLM translation
wackerow May 26, 2026
59a8eb9
i18n(id): LLM translation
wackerow May 26, 2026
001ff31
i18n(it): LLM translation
wackerow May 26, 2026
b137489
i18n(ja): LLM translation
wackerow May 26, 2026
874060e
i18n(ko): LLM translation
wackerow May 26, 2026
f76be9d
i18n(mr): LLM translation
wackerow May 26, 2026
344a2bd
i18n(pl): LLM translation
wackerow May 26, 2026
d302d52
i18n(pt-br): LLM translation
wackerow May 26, 2026
5a618b4
i18n(ru): LLM translation
wackerow May 26, 2026
f2078cd
i18n(sw): LLM translation
wackerow May 26, 2026
76c58c2
i18n(ta): LLM translation
wackerow May 26, 2026
2babc25
i18n(te): LLM translation
wackerow May 26, 2026
2a97589
i18n(tr): LLM translation
wackerow May 26, 2026
e459761
i18n(uk): LLM translation
wackerow May 26, 2026
6592f5d
i18n(ur): LLM translation
wackerow May 26, 2026
56bedbe
i18n(vi): LLM translation
wackerow May 26, 2026
d7d9fb7
i18n(zh): LLM translation
wackerow May 26, 2026
d5f5679
i18n(zh-tw): LLM translation
wackerow May 26, 2026
ffa93b3
i18n: sanitize translation output
wackerow May 26, 2026
9a137a2
i18n: merge tmp-intl/run-0526-0949 into intl/pending-dev
wackerow May 26, 2026
9fbb389
fix: use SITE_URL for llms.txt cross-references instead of hardcoded …
pettinarip May 26, 2026
ac76b61
feat(reports): swap hero to books illustration
konopkja May 26, 2026
83e287e
refactor(ui): ui/callout CalloutMain, size variants
myelinated-wackerow May 26, 2026
604c82b
deprecate: CalloutEmoji usaage
myelinated-wackerow May 26, 2026
bb32cf5
chore(reports): refresh hero illustration
konopkja May 26, 2026
4ac1ee7
docs(skill): design-system ui/callout updates
myelinated-wackerow May 26, 2026
25aac03
perf(reports): tighten hero asset to 104 KB
konopkja May 26, 2026
de09c33
fix(ui): unbreak callout stories type-check
myelinated-wackerow May 26, 2026
b6b1fff
i18n: fix 5 review issues (ar/hi/ko/ur/vi)
myelinated-wackerow May 26, 2026
7cd0fd8
patch(ui): apply adjustments per design review
myelinated-wackerow May 26, 2026
9f2dcc8
refactor: use `size` variant naming
myelinated-wackerow May 26, 2026
37b14c7
chore: remove unused orientation variants
myelinated-wackerow May 26, 2026
dfc8f80
refactor: ui/card api suggestions from code review
myelinated-wackerow May 26, 2026
ba803b8
Merge pull request #18215 from ethereum/intl-knowledge-base
pettinarip May 26, 2026
f04badb
Merge pull request #18279 from bshastry/jie-1577-grandine-low
wackerow May 26, 2026
1b6054e
docs(stories): sync card stories to current API
myelinated-wackerow May 26, 2026
e7b20e2
docs(skill): sync ui/card guidance to latest API
myelinated-wackerow May 26, 2026
8f62d07
fix(tds): drop removed CardHeader spacing prop
myelinated-wackerow May 26, 2026
a8478a1
Merge pull request #18281 from ethereum/intl/pending-dev
wackerow May 26, 2026
9397f03
patch: bottom row spacing, rm mb-1
wackerow May 26, 2026
93e3340
Merge pull request #18272 from ethereum/fix/leaderboard-hover-border-…
wackerow May 26, 2026
5d85ccf
chore: run prettier
wackerow May 26, 2026
fc5b6ec
Merge pull request #18270 from ethereum/fix/10years-tab-shadow
wackerow May 26, 2026
7d42af5
Merge pull request #18210 from ethereum/ui-card
wackerow May 26, 2026
bdbb56f
i18n(ar): LLM translation
wackerow May 26, 2026
ef5c651
i18n(bn): LLM translation
wackerow May 26, 2026
467677c
i18n(cs): LLM translation
wackerow May 26, 2026
064c423
i18n(de): LLM translation
wackerow May 26, 2026
3e8afec
i18n(es): LLM translation
wackerow May 26, 2026
e55923b
i18n(fr): LLM translation
wackerow May 26, 2026
8bc5f5b
i18n(hi): LLM translation
wackerow May 26, 2026
6a9cb5c
i18n(id): LLM translation
wackerow May 26, 2026
eec825c
i18n(it): LLM translation
wackerow May 26, 2026
49f7353
i18n(ja): LLM translation
wackerow May 26, 2026
0a8118f
i18n(ko): LLM translation
wackerow May 26, 2026
756c717
i18n(mr): LLM translation
wackerow May 26, 2026
9608848
i18n(pl): LLM translation
wackerow May 26, 2026
661ec22
i18n(pt-br): LLM translation
wackerow May 26, 2026
cd48330
i18n(ru): LLM translation
wackerow May 26, 2026
db09a25
i18n(sw): LLM translation
wackerow May 26, 2026
4d69d08
i18n(ta): LLM translation
wackerow May 26, 2026
9ca8275
i18n(te): LLM translation
wackerow May 26, 2026
1ed213b
i18n(tr): LLM translation
wackerow May 26, 2026
4dcedfb
i18n(uk): LLM translation
wackerow May 26, 2026
42653fe
i18n(ur): LLM translation
wackerow May 26, 2026
2f8a83f
i18n(vi): LLM translation
wackerow May 26, 2026
2135a28
i18n(zh): LLM translation
wackerow May 26, 2026
d4a4d85
i18n(zh-tw): LLM translation
wackerow May 26, 2026
c8532d4
i18n: sanitize translation output
wackerow May 26, 2026
d43a9aa
i18n: merge tmp-intl/run-0526-1634 into intl/pending-dev
wackerow May 26, 2026
b0fbb67
Merge pull request #18240 from ethereum/qr-breadcrumb
pettinarip May 26, 2026
ed83c4c
Merge pull request #18235 from ethereum/md-alert-spacing
pettinarip May 26, 2026
8d6b7ab
Merge pull request #18222 from ethereum/patch-layer-2-hero
pettinarip May 26, 2026
90f63a3
Merge pull request #18243 from ethereum/banner-as-screenshot
pettinarip May 26, 2026
df7a5f9
i18n: fix 7 review issues (ar/fr/ja/pl/ru/zh/zh-tw)
myelinated-wackerow May 26, 2026
0c833f4
Merge pull request #18285 from ethereum/intl/pending-dev
wackerow May 27, 2026
300340d
i18n(bn): LLM translation
wackerow May 27, 2026
273081a
i18n: sanitize translation output
wackerow May 27, 2026
1513336
i18n: merge tmp-intl/run-0527-0655 into intl/pending-dev
wackerow May 27, 2026
79aa288
Merge branch 'dev' into ui-callout
myelinated-wackerow May 27, 2026
06abc92
chore: migrate ui stories to __stories__
myelinated-wackerow May 27, 2026
3582e7e
Merge pull request #18274 from ethereum/ui-callout
wackerow May 27, 2026
62067ae
Merge pull request #18266 from ethereum/layout-top-padding
pettinarip May 27, 2026
49f693d
Merge pull request #18277 from ethereum/intl-stray-cleanup
pettinarip May 27, 2026
134d910
Merge branch 'dev' into feat/reports-page
myelinated-wackerow May 27, 2026
12b48b2
refactor: reports page cards and layout
myelinated-wackerow May 27, 2026
969e94a
patch(ui): add text-pretty to ui/card
myelinated-wackerow May 27, 2026
9fa828d
refactor: use formatDate
myelinated-wackerow May 27, 2026
07ce1e2
refactor(intl): use number formatting for PDF byte size
myelinated-wackerow May 27, 2026
aa041ed
temp: hide report pending PDF
myelinated-wackerow May 27, 2026
f6dcdfc
refactor: use url helper utils
myelinated-wackerow May 27, 2026
b723b45
chore: remove unnecessary wraper div
myelinated-wackerow May 27, 2026
1dc89c2
Merge pull request #18254 from konopkja/feat/reports-page
wackerow May 27, 2026
f5f566b
Merge pull request #18286 from ethereum/intl/pending-dev
wackerow May 27, 2026
b2bddf3
Merge remote-tracking branch 'origin/dev' into feat/llms-txt-automation
pettinarip May 27, 2026
b0ce19e
Merge pull request #18234 from ethereum/feat/llms-txt-automation
pettinarip May 27, 2026
faf9ef5
Merge remote-tracking branch 'origin/dev' into builder-hub-blog
mnelsonBT May 27, 2026
9ba1454
Apply /latest/ URL changes and resolve branch conflicts
mnelsonBT May 27, 2026
f1eb815
Remove old placeholder blog posts
mnelsonBT May 27, 2026
b7c4577
fixing breadcrumb
mnelsonBT May 27, 2026
3d97e8c
changing hero image
mnelsonBT May 27, 2026
2b0eab6
updating hero images
mnelsonBT May 27, 2026
27f28e3
refactor: align /latest with /tutorials styling
myelinated-wackerow May 27, 2026
276d775
update(ui): developer blog cards
myelinated-wackerow May 27, 2026
f67ab2e
revert: MdxHero usage
myelinated-wackerow May 27, 2026
ef09385
refactor: use existing tutorial layout
myelinated-wackerow May 28, 2026
b6e34a8
feat(ui): add blog image to page conditionally
myelinated-wackerow May 28, 2026
1325c4a
patch: hide edit button for blog entries
myelinated-wackerow May 28, 2026
6c30651
patch(ui): apply text-body-medium to CardParagraph
myelinated-wackerow May 28, 2026
232c6ab
fix: nested p tags, scroll container spacing
myelinated-wackerow May 28, 2026
6bcfd1a
patch: full width CTA on mobile
myelinated-wackerow May 28, 2026
c69589b
patch(ui): use ghost variant, rm preview card bg
myelinated-wackerow May 28, 2026
2e388ec
fix(seo): update /en/staking/ links to /staking/ in restaking transla…
nloureiro May 28, 2026
91010f9
fix(docs): correct smart-contracts example URL in style guide
nloureiro May 28, 2026
60b7f31
fix(ui): ui/callout overflow
myelinated-wackerow May 28, 2026
efd0c7f
Merge pull request #18293 from ethereum/fix-callout
wackerow May 28, 2026
671cd94
feat: add RSS feed for /latest/ posts
myelinated-wackerow May 28, 2026
a4ca50c
patch: rm redundant intl string
myelinated-wackerow May 28, 2026
931d891
chore: prettify
myelinated-wackerow May 28, 2026
ee43cba
patch: adjustments from code review
myelinated-wackerow May 28, 2026
077b22d
rename: IBlogPost to BlogPost
myelinated-wackerow May 28, 2026
fed5762
refactor(intl): page-latest namespace
myelinated-wackerow May 28, 2026
cf7af4c
chore: limit to ethereum + l2s
wackerow May 28, 2026
b844f75
Merge pull request #18244 from BabyScope/add-nodeflare-rpc
wackerow May 28, 2026
a69a91a
Merge pull request #18259 from andreivladbrg/fix/docs-nav-data-availa…
wackerow May 28, 2026
79c5790
Merge pull request #18263 from ethereum/fix/codeblock-vitesse-theme
wackerow May 28, 2026
4393e9f
Merge pull request #18250 from ethereum/issueslist-self-fetch
wackerow May 28, 2026
55b457a
Merge pull request #18146 from ethereum/builder-hub-blog
wackerow May 28, 2026
1488a12
fix: use relative path for internal link
myelinated-wackerow May 28, 2026
666b199
Merge pull request #18294 from ethereum/fix/seo-restaking-en-staking-…
wackerow May 28, 2026
fb9e27d
Merge pull request #18295 from ethereum/fix/seo-style-guide-example-link
wackerow May 28, 2026
608bb05
patch: rm noir from post tags
myelinated-wackerow May 28, 2026
962bbb9
Merge pull request #18298 from ethereum/post-tag-patch
wackerow May 28, 2026
bfe5cb9
Merge pull request #18246 from ethereum/fix/qa-weekly-issues-may-2026
wackerow May 28, 2026
4633e3c
11.8.0
pettinarip May 28, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 1 addition & 1 deletion .claude/commands/review-translations.md
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ curl -sf "$GLOSSARY_HOST/llms.txt" \
ENGLISH_SOURCE=$(cat "$WORKTREE_PATH/public/content/{path}.md")
curl -sf -X POST "$GLOSSARY_API_URL/filter" \
-H "Content-Type: application/json" \
-d "$(jq -n --arg text "$ENGLISH_SOURCE" --arg lang "{LANGUAGE_CODE}" '{text: $text, language: $lang}')"
-d "$(jq -n --arg content "$ENGLISH_SOURCE" --arg lang "{LANGUAGE_CODE}" '{content: $content, language: $lang}')"
```

**Fallback — full language** when filtering per file is impractical or the endpoint is unreachable:
Expand Down
87 changes: 0 additions & 87 deletions .claude/commands/update-llms-txt.md

This file was deleted.

6 changes: 4 additions & 2 deletions .claude/skills/design-system/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ When the existing primitive doesn't quite fit, the answer is usually "add a vari
6. **Logical CSS for direction.** Use `ms-`/`me-`/`ps-`/`pe-`/`inset-s-`/`inset-e-`/`border-s`/`border-e`/`text-start`/`text-end`. The site supports Arabic and Urdu (RTL). Hard-coded `left-`/`right-`/`ml-`/`mr-`/`pl-`/`pr-` breaks RTL.
7. **Locale-aware formatters.** `numberFormat()` from `@/lib/utils/numbers`, `dateTimeFormat()` from `@/lib/utils/date`. Never `toLocaleString` / `Intl.NumberFormat` directly.
8. **`useRtlFlip()` for directional icons** (right-pointing arrows/chevrons). Or use `ChevronNext`/`ChevronPrev` from `@/components/Chevron`.
9. **Markdown content goes through `MdComponents`.** The legacy `@/components/Card` (default export) is reserved for markdown shortcodes -- never import it from app code; use `@/components/ui/card`.
9. **Markdown content goes through `MdComponents`.** The `<Card>` markdown shortcode is backed by `@/components/MarkdownCard` (a thin wrapper around the `ui/card` primitives with an MDX-friendly prop shape). For app code, compose the primitives directly from `@/components/ui/card`.
10. **Storybook stories ship with new UI components.** No automated unit tests; Storybook + Chromatic + types are the verification layer.
11. **Don't add new layouts.** There are six canonical layouts (`TopicLayout`, `StaticLayout`, `DocsLayout`, `TutorialLayout`, `ContentLayout`, `BaseLayout`). New sectioned content goes in `src/data/topics/<key>.ts` as a `TopicLayout` config -- not a new layout component. See `references/layouts.md`.

Expand All @@ -40,7 +40,7 @@ These are landmines where the code looks reasonable but the pattern is wrong. Th

### Imports that look right but aren't

- **Cards**: `import { Card } from "@/components/ui/card"` is canonical. **Not** `import Card from "@/components/Card"` (default export of that file is reserved for markdown shortcodes).
- **Cards**: `import { Card } from "@/components/ui/card"` is canonical for app code. The `<Card>` markdown shortcode is backed by `@/components/MarkdownCard` — that wrapper is rarely imported from app code, since composing the `ui/card` parts directly is more flexible.
- **Tooltips**: `import Tooltip from "@/components/Tooltip"` (mobile-aware, Matomo-tracked, scroll-close). **Not** `import { Tooltip } from "@/components/ui/tooltip"` (that's the bare Radix primitive used internally).
- **Modals**: `import Modal from "@/components/ui/dialog-modal"` (default export, the high-level convenience) for typical modal needs. `@/components/ui/dialog` is the vanilla shadcn-style primitive for fine-grained Radix control. Same names exported from both files; **do not mix sources within a feature**.
- **Heroes**: import from `@/components/Hero` (`ContentHero`, `SimpleHero`, `HubHero`, `MdxHero`, `HomeHero`). **Not** `@/components/PageHero` (deprecation track).
Expand All @@ -56,6 +56,7 @@ Used in 5 places. Don't introduce new uses. Use Tailwind `dark:` variant + seman
### Subtle component behaviors

- `<Button isSecondary>` only takes effect on `outline` and `ghost` variants. Silent no-op on `solid`/`link`.
- **`Card` is variant-driven, not `className`-driven.** Padding, spacing, background, border-radius, and text color are owned by the `variant` / `size` variants and the CSS vars they set (`--card-pad`, `--content-space`, `--banner-radius`). Adjusting any of those via `className` on `Card`/`CardContent`/`CardHeader`/`CardFooter` is the wrong escape hatch — add a variant case in `card.tsx` instead. See `references/card-walkthrough.md`.
- `<CardBanner fit="contain">` with a single `<Image>` child auto-clones it as a blurred backdrop. Pass two children and you lose this magic.
- `LinkBox` requires a `LinkOverlay` somewhere inside; without it, the whole-card-clickable pattern doesn't work.
- `commonControlClasses` in `ui/checkbox.tsx` is shared by `Switch`. Editing it changes both.
Expand Down Expand Up @@ -105,6 +106,7 @@ Pull these in only when the trigger applies. Don't read them all upfront.
- **`references/server-vs-client.md`** -- Load when deciding whether to mark a component `"use client"`, structuring a page that mixes static and interactive parts, or refactoring across the SSR boundary.
- **`references/a11y.md`** -- Load when adding interactive elements (modals, dropdowns, custom click targets), building forms, or working with images and headings.
- **`references/card-walkthrough.md`** -- Load when starting any card-shaped UI work; an end-to-end worked example.
- **`references/callout-walkthrough.md`** -- Load when adding or modifying an in-content `Callout` (image/emoji + title + description + CTA); covers banner shape, side-by-side equalization, variants, and the CSS variable hooks.
- **`references/page-hero-walkthrough.md`** -- Load when starting a new page that needs a hero; an end-to-end worked example.
- **`references/layouts.md`** -- Load when you're tempted to create a new layout, when adding a new topic-hub section, or when refactoring a one-off `src/layouts/md/<Section>Layout` file. The canonical inventory plus the rule that new layouts are very rare.
- **`references/new-component-checklist.md`** -- Load before opening a PR for a new component. The pre-merge checklist.
Expand Down
2 changes: 1 addition & 1 deletion .claude/skills/design-system/references/a11y.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ Without it, screen readers announce nothing meaningful for the button.

### `<aside>` is for tangentially-related content

`<aside>` is the right element for content that sits beside the main flow -- top-of-page ribbons, side callouts, supplementary explainers. In this codebase that includes `UpgradeStatus`, `CalloutBanner`/`CalloutSSR`, `CallToContribute`, `StakingHierarchy`, `TranslationBanner`, and `<Alert variant="banner">`. None of these should be `<section>` or `<article>`.
`<aside>` is the right element for content that sits beside the main flow -- top-of-page ribbons, side callouts, supplementary explainers. In this codebase that includes `UpgradeStatus`, the unified `Callout` (at `@/components/ui/callout`), `CallToContribute`, `StakingHierarchy`, `TranslationBanner`, and `<Alert variant="banner">`. None of these should be `<section>` or `<article>`.

What `<aside>` does NOT imply is a live-region role. If the content is announced dynamically (form result, async status change), pair the `<aside>` with `role="status"` (polite) or `role="alert"` (assertive). Static editorial banners can stay role-less and shouldn't announce on page load.

Expand Down
137 changes: 137 additions & 0 deletions .claude/skills/design-system/references/callout-walkthrough.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
# Walkthrough: "I Need a Callout"

A worked example of using the design system correctly when adding an in-content callout — a card-shaped block with an optional image banner, title, description, and optional CTA buttons.

## Step 1: Confirm it's a `Callout`

`Callout` is one of several similar-looking primitives. Pick by what you're actually building:

- **Card-shaped promotional/educational block, with an optional image banner, title, description, and 0–2 CTA buttons** → `Callout`
- **Linkable summary card in a grid (list of things)** → `Card`
- **In-prose notice or warning** → `<Alert variant="info|warning|error|success|update">`
- **Top-of-page full-bleed ribbon** → `<Alert variant="banner">`
- **Whole-card-clickable wrapper around arbitrary content** → `LinkBox` + `LinkOverlay`

If you're tempted to inline `flex flex-col rounded-2xl bg-card-gradient-secondary ... p-8` with an `<img>` overhang, you're reinventing `Callout`.

## Step 2: Compose `Callout`

The default export covers the common shape:

```tsx
import Callout from "@/components/ui/callout"
import { ButtonLink } from "@/components/ui/buttons/Button"

<Callout
image={someImage}
alt="Stylized illustration"
title={t("page-x-callout-title")}
description={t("page-x-callout-description")}
>
<ButtonLink href="/...">{t("page-x-callout-cta")}</ButtonLink>
</Callout>
```

### What's happening

- `Callout` wraps `CalloutRoot` (the `<aside>`) → optional `CalloutBanner` → `CalloutMain` → (`CalloutContent` → `CalloutTitle` + `CalloutDescription`) + optional `CalloutButtons`. `CalloutMain` is the internal flex parent that gives the title/description block and the buttons block their asymmetric spacing (title↔description tight, content↔buttons loose); `CalloutContent` holds only the heading + description.
- `image` is the optical anchor at the top. It overflows the gradient card via paired `mt-24` (reservation) / `-mt-24` (banner offset) so the image floats above. The reservation is gated to `@max-3xl/callout` and only applies when a banner is present (so banner-less callouts don't reserve space).
- `title` and `description` are literal strings — the call site resolves intl. Do **not** reintroduce `titleKey` / `descriptionKey` props; those were removed during unification.
- Children render inside `CalloutButtons`. The buttons slot uses `mt-auto` so it pins to the bottom of the main area.

## Step 3: Banner shape — image or none

The only optical anchor is `image`:

- `image` renders a `<CalloutBanner>` with the image. Banner area reserves 96px above the gradient card for the overlap effect.
- Omit `image` for a content-only callout. The aside skips the 96px reservation entirely (via the `has-[[data-label=callout-banner]]:` gate), so the gradient card sits flush at the top.

The legacy `emoji` prop / `CalloutEmoji` slot was removed in May 2026 — the single in-tree consumer was migrated to a banner-less callout, and the pattern was retired. Do not reintroduce.

## Step 4: Side-by-side equalization (automatic)

When two or more `<Callout>`s share a parent at `md+` viewport, banners pin to a 16rem min-height (256px) and buttons bottom-align across cards via `mt-auto`. Single callouts and stacked callouts (below `md`) retain natural banner height.

```tsx
<div className="grid grid-cols-1 md:grid-cols-2 gap-8">
<Callout image={...} title={...} description="Short copy.">
<ButtonLink href="#">A</ButtonLink>
</Callout>
<Callout image={...} title={...} description="A much longer description that wraps to multiple lines.">
<ButtonLink href="#">B</ButtonLink>
</Callout>
</div>
```

The equalization rule lives on `CalloutBanner` as:

```
@max-3xl/callout:md:[aside:not(:only-child)_&]:min-h-64
```

— "inside a small-container layout, at `md+` viewport, when the wrapping aside has a sibling aside, pin banner to 16rem." The `md:` gate is hardcoded to Tailwind's default 768px breakpoint, which matches the `md:grid-cols-2` pattern used across `gas`, `learn`, `layer-2`, and `stablecoins`. If you use a different parent breakpoint, equalization may misalign — flag it.

## Step 5: Variants

Two size variants, both fully responsive across the `@3xl/callout` container breakpoint:

| Variant | Title @ `@max-3xl/callout` → `@3xl/callout` | Description @ `@max-3xl/callout` → `@3xl/callout` | Notes |
|---|---|---|---|
| `base` (default) | `text-2xl` (24px) → `text-3xl` (30px) | `text-lg` (18px) → `text-xl` (20px) | Default scale; use for prominent CTAs |
| `sm` | `text-xl` (20px) → `text-2xl` (24px) | `text-base` (16px) → `text-lg` (18px) | Tighter; use when the callout is secondary to surrounding content or stacked at narrower widths |

Variant naming reflects visual prominence (text scale only). Gap and padding are unchanged across variants. The previous `large` / `medium` / `small` triad was consolidated into `base` / `sm` in May 2026 — descriptions are now responsive in both variants (they were fixed-size before).

## Step 6: Heading level (`as` prop)

`CalloutTitle` renders `<h2>` by default. When the callout sits inside an h2-introduced section, pass `as="h3"` (or `as="h4"` for deeper nesting) to keep the heading hierarchy clean:

```tsx
<Callout as="h3" image={...} title={...} description={...} />
```

## Step 7: CSS variable hooks

Layout values are driven by CSS variables on the aside. Variants override these; pages can override per-instance via `className`.

| Variable | Default | Set by | Notes |
|---|---|---|---|
| `--callout-padding` | `--spacing(8)` (32px), `--spacing(12)` at `@3xl/callout` | Root | Banner horizontal padding and `CalloutMain` padding both read this |
| `--spacing-unit` | `0.25lh` | Root | Line-height-relative rhythm unit. `CalloutContent` uses `gap-(--spacing-unit)` (title↔description tight); `CalloutMain` uses `gap-[calc(var(--spacing-unit)*4)]` (content↔buttons loose) |
| `--title-font-size` | Variant-driven, responsive at `@3xl/callout` | Variants | See Step 5 table |
| `--content-font-size` | Variant-driven, responsive at `@3xl/callout` | Variants | See Step 5 table |

Adding a variant follows the existing pattern — set the variable on the aside in the variant's `cn()` block, mirroring the responsive shape used by `base` / `sm`:

```tsx
// In ui/callout.tsx, inside variants:
xl: cn(
"[--callout-padding:--spacing(16)]",
"[--title-font-size:var(--text-3xl)] *:@3xl/callout:[--title-font-size:var(--text-4xl)]",
"[--content-font-size:var(--text-xl)] *:@3xl/callout:[--content-font-size:var(--text-2xl)]",
),
```

The `*:@3xl/callout:[--var:...]` shape is required (not `@3xl/callout:[--var:...]`) because the `@container/callout` lives on the aside itself — the override has to descend through a child before the container query resolves.

Avoid the `**:data-[label=callout-content]:...` descendant-selector pattern for new variants — push the rule onto `CalloutContent` directly, or use a CSS variable hook so the slot owns its own behavior. The one remaining instance of that pattern (on `base`, for `w-[inherit]`) is preserved from the pre-consolidation default and should not be propagated.

## Step 8: When the shape doesn't quite match

Almost always the answer is "add a variant" or "expose a CSS variable hook" rather than "create a new component."

- **Different image overflow amount** — currently the `-mt-24` is hardcoded on `CalloutBanner`. The clean evolution is a `--callout-banner-overflow` CSS variable that both the aside's reservation and the banner's negative margin read. Worth doing before the second consumer requests it.
- **Different banner alignment** (top-anchor vs centered) — `grid place-items-center` is the current default; the alignment could become a variant if a use case demands it.
- **Image with hard-coded sizing** — don't override the image's `sizes` attribute per-call without a strong reason. The component-level `sizes="(min-width: 768px) 400px, calc(100vw - 64px)"` is tuned to the layout's actual breakpoints and the `max-h-64` cap.

## Step 9: Storybook story

`src/components/ui/callout.stories.tsx` is the single source. Add a story only when you're introducing a new variant or shape that the existing stories don't cover. Variant-axis stories opt out of Chromatic at the meta level; the `Composites` story stays in Chromatic and uses real intl keys so the Storybook locale toolbar exercises RTL and verbose-language layouts.

## Pre-merge checklist

- [ ] `title` / `description` are translated at the call site (no `titleKey` / `descriptionKey`).
- [ ] `variant` is `base` (default) or `sm` — the old `large` / `medium` / `small` names were removed.
- [ ] If using `as`, the resulting heading level matches the section's hierarchy.
- [ ] If introducing a new visual treatment, it lives as a variant or CSS variable hook on `ui/callout`, not a sibling component.
- [ ] Storybook coverage updated if the new variant/shape isn't already represented.
Loading
Loading