Skip to content

Add a Shiki code block, and Card options for no accent and a traced hover - #44

Draft
thebuilder wants to merge 1 commit into
mainfrom
feat/code-block-component-a2504d
Draft

thebuilder wants to merge 1 commit into
mainfrom
feat/code-block-component-a2504d

Conversation

@thebuilder

Copy link
Copy Markdown
Owner

What this adds

Three things.

code-block

A new registry item wrapping Shiki. CodeBlock takes a string of code and highlights it on the server, so Shiki never reaches the browser and only the copy button ships as client code.

<CodeBlock code={source} lang="tsx" title="app/page.tsx" />

Colors come from the theme's CSS variables rather than a Shiki theme of its own, so a block follows whichever phosphor the page is set to. Parts are CodeBlock, CodeBlockTitle, CodeBlockBody and CodeBlockCopy.

The item is three files, and the split is forced rather than chosen. lib/shiki.ts holds the theme and the highlighter and is React-free, because next.config.ts imports it for the MDX rehype plugin. code-block-copy.tsx is its own module because it is the only client half, and importing it from the server file would otherwise drag Shiki into the bundle.

This is the first item with a registry:lib file, so scripts/check-docs.mjs now skips those when it compares an item's exports to its documented parts. A part is something the caller renders, and a helper module the components import is not one.

use-copied

A registry hook, pulled out because the code block and the site's copy-page button both need it and the payload cannot import site code. It takes the string to copy or a function returning it, which may be async, and swallows a clipboard the browser denies instead of rejecting where nothing can catch it.

Card options

accent={false} drops the colored left edge and leaves the title in the card's own color, for a grid where no panel is the one to read first.

trace sends the accent around the card on hover or on focus within it, across the top, down the right and back along the bottom. Leaving runs the same three in reverse. It needs three registered custom properties to animate, so @property and the card-trace utility live in theme.mjs. Under prefers-reduced-motion the outline still appears, it just arrives at once.

The three left-edge modes are a keyed map plus one lookup, matching how led, sheet, terminal-window and chart already handle their variants.

Fixed along the way

CardAccent's rule past the accent was pinned to --line, so hovering a card with a stripe lifted the right and bottom edges while the top stayed dim. It now reads --card-rule, which the card raises on hover. The rule is also the background under the gradient rather than its last stop, because a gradient built from a variable jumps where a background color eases on the card's own 260ms curve.

The site now installs from the registry

It had its own copy of all of this. Consuming the registry instead deleted lib/code.ts, lib/shiki-theme.ts, components/docs/code-block.tsx, highlighted.tsx, copy-button.tsx, use-copied.ts, and components/copy-command.tsx, which had become a second panel doing the code block's job.

Highlighting also moved out of lib/source.ts and into the component that renders it. lib/source.ts now only reads files, and /c/<name>.md and llms-full.txt stop paying Shiki for every example and discarding the result.

For a reviewer

  • registry/terminal/ui/card.tsx and registry/terminal/theme.mjs are the two files worth reading closely. app/globals.css and the generated blocks in registry.json and public/r/ are build output.
  • The traced hover is a port of the .project hover on thebuilder.dk. I read the live CSS rather than reimplementing by eye, including the asymmetric enter and leave timings.
  • Verified by installing @afterglow/code-block and @afterglow/card into a scratch Next.js project over a local server, which confirmed the @/registry/terminal/lib/shiki to @/lib/shiki rewrite, the nested use-copied dependency, and the merged theme CSS.
  • Hover behavior checked in a browser by sampling computed styles through the transition, since a screenshot cannot show whether the trace steps or eases.
  • pnpm check passes and fallow audit is pass.

…over

Three things, all asked for together.

`code-block` is a new registry item. `CodeBlock` takes a string of code and
highlights it on the server, so Shiki never reaches the browser and only the
copy button ships as client code. The theme hands Shiki the palette's CSS
variables rather than hex, so a block follows whichever phosphor the page is
set to. Its three files split along the boundaries that force them: the
highlighter is React-free because `next.config.ts` imports it for the MDX
rehype plugin, and the copy button is its own module because it is the only
client half.

The site had its own copy of all of this. It now installs from the registry
instead, which deleted `lib/code.ts`, `lib/shiki-theme.ts`, and the three docs
components that drew code blocks, along with `CopyCommand`, which had become a
second panel doing the same job. Highlighting moved out of `lib/source.ts` and
into the component that renders it, so `/c/<name>.md` and `llms-full.txt` stop
paying Shiki for every example and throwing the result away.

`use-copied` is a registry hook, pulled out because the code block and the
site's copy-page button both need it and the payload cannot import site code.
It takes the string to copy or a function returning it, and swallows a
clipboard the browser denies instead of rejecting where nothing can catch it.

Card gets two options. `accent={false}` drops the colored left edge and leaves
the title in the card's own color, for a grid where no panel is the one to
read first. `trace` sends the accent around the card on hover, across the top,
down the right and back along the bottom, reversing on leaving. The trace needs
three registered custom properties to animate, so `@property` and the utility
live in `theme.mjs`. Under `prefers-reduced-motion` the outline still appears,
it just arrives at once.

`CardAccent`'s rule past the accent was pinned to `--line`, so the top edge
stayed dim while hover lifted the other three. It now reads `--card-rule`,
which the card raises on hover, and the rule is the background under the
gradient rather than its last stop, because a gradient built from a variable
jumps where a background color eases.

`scripts/check-docs.mjs` skips `registry:lib` files when it compares an item's
exports to its documented parts. A part is something the caller renders, and a
helper module the components import is not one.

Verified by installing `@afterglow/code-block` and `@afterglow/card` into a
scratch Next.js project over a local server, confirming the import rewrites,
the nested hook dependency and the merged CSS.
@vercel

vercel Bot commented Sep 17, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
afterglow Ready Ready Preview Sep 17, 2026 4:49pm UTC

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