Skip to content

feat(cards): left share card design, every-post cards and page-name og:title - #4

Merged
arjunpredev merged 2 commits into
mainfrom
share-cards-predev-design
Oct 26, 2026
Merged

arjunpredev merged 2 commits into
mainfrom
share-cards-predev-design

Conversation

@arjunpredev

Copy link
Copy Markdown
Contributor

What

A second share card design, picked per site, plus cards for every post and page-name og:title tags.

appearance.shareCards

shareCards?: {
    design?: 'centered' | 'left';   // default 'centered' (today's design, unchanged)
    everyPost?: boolean;            // default false
    home?: { title?: string | null; dim?: string | null; text?: string | null } | null;
} | null;

Typed in packages/core/src/types.ts (ShareCardSettings), stored with the other appearance settings, and edited in the admin under Settings, Appearance, Share cards: a design picker, the every-post switch and the front page card's three lines. Documented in docs/configuration.md.

The left design (packages/server/src/card-left.ts)

  • On top: the site's logo, then a trail of mono capitals. The site part comes from site data: the masthead title read the way the front page sets it, so a title of "Acme blog" gives ACME · BLOG. With no masthead title the trail is the site title and "Blog". Each card adds its own part: a post's primary topic, TOPIC or AUTHOR.
  • Then the headline (with an optional dimmer second line on the front page) and one support line.
  • A footer band under a hairline. On the left: the byline and date for a post, or a post count for the front page, topics and authors. On the right: the page's address (example.com/blog, example.com/blog/tag/news).
  • Author cards show the portrait (or the first letter of the name) in a 132px circle, top right.
  • Text is fitted with satori's own measurements (fitCard). A long title steps down from 64px to 48px (two lines, three at 48px). Support copy keeps as many whole sentences as fit (three lines, two under a three-line title). Nothing is drawn under 28px. The centered design's clip() is not used.
  • Sky: one SVG of fixed-seed stars (no backdrop pipeline).
  • Fonts: Inter 500/600/800 in the subsets the text needs, and JetBrains Mono 500/700. Both come from fontsource on jsdelivr and are kept in R2, the way Inter is today.
  • Beyond the spec, for any site's data: a trail too wide for the card drops its middle parts and then shortens its last one. A title still over three lines at 48px ends at a word. A support line with no room for even a line is left out. A post whose only text is a summary ending in a cut-off sentence keeps only its whole sentences.

everyPost

When on, every post and page is shared with a drawn card as og:image and twitter:image, including pages with a cover image. The cover stays on the page and in its BlogPosting structured data. An ogImage set by hand on the post still wins. The editor's "When shared" preview follows the setting (/me now says everyPostCard).

Tags around the cards

  • og:image:alt on drawn cards is shareCardAlt(card): the headline, then the support line, capped at 420 characters.

  • og:title is the page's own name:

    • a post: ogTitle, else its title (metaTitle stays in <title>)
    • a topic: ogTitle, else its name
    • an author: their name
    • the front page: ogTitle, else the masthead title, else the site title

    Before, topics and authors were shared as "Name - Site" by default. <title> keeps its suffix.

  • CARD_DESIGN goes to 2, so every card (both designs) is drawn again under a new address.

satori stays at 0.32

The design was drawn on satori 0.33.4. 0.33 imports HarfBuzz WebAssembly at module load, through fs or a script-relative fetch, which a Worker without nodejs_compat can't do. On 0.32 the only layout difference is that 0.32 spaces a run's last letter from what follows. The trail's word margins take that back, and a pixel comparison with the 0.33 reference renders shows the same line breaks, sizes and positions (left differences are glyph kerning, which 0.33 gets from HarfBuzz).

Checks

  • bun run typecheck: clean
  • bun run --cwd packages/admin build: clean
  • bun scripts/leak-guard.ts (with the private denylist) and gitleaks: clean
  • The repo has no unit test suite, so no tests were added.
  • A staging deploy of this branch passes the smoke test (38/38). With the left design and everyPost on there, every page lists a drawn card, twitter:image matches og:image, and topic and author pages are shared by name alone. The Worker draws each card in 1.4 to 3.5 s on first request; after that it is served from R2.
  • With shareCards unset, renderSite lists the same card objects as before, under new keys only.

🤖 Generated with Claude Code

Pre.dev Agent and others added 2 commits October 26, 2026 14:11
…name og:title

A site can now pick its share card design with appearance.shareCards:

- design: 'centered' (the default, unchanged) or 'left'. The left design
  sets the site's logo and a trail of mono capitals on top (site, section,
  then the post's topic, "Topic" or "Author"), the headline and one support
  line, and a footer band with the byline and date or a post count on the
  left and the page's address on the right, on a sky of still stars. An
  author card shows the portrait, or an initial, in a circle. Text is fitted
  with satori's own measurements: a long title steps down from 64px to 48px,
  and support copy keeps whole sentences.
  It loads Inter 500/600/800 and JetBrains Mono 500/700 from fontsource,
  kept in R2 like Inter is today.
- everyPost: posts and pages with a cover are shared with a drawn card too.
  The cover stays on the page and in its structured data; an ogImage set by
  hand still wins. The editor's share preview follows the setting.
- home: the front page card's headline, a dimmer second line and its text.

Shared pages now go by their own name: og:title is a post's ogTitle or
title (its metaTitle stays in <title>), a topic's ogTitle or name, an
author's name, and the front page's ogTitle, masthead title or site title.
Before, topics and authors were shared as "Name - Site" by default.

og:image:alt on drawn cards is the headline, then the support line, at
most 420 characters. CARD_DESIGN goes to 2, so every card is drawn again
under a new address.

The Worker stays on satori 0.32: 0.33 loads HarfBuzz WebAssembly at import
through fs or a script-relative fetch, which a Worker without nodejs_compat
cannot do. 0.32 spaces a run's last letter from what follows, so the trail's
word margins take that back.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A post with no whole excerpt or description of its own gets its support
line from the page's summary, which can end in an ellipsis where an import
or the summary itself cut a sentence short. The card now keeps only the
whole sentences before it, or shows no support line.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@arjunpredev
arjunpredev merged commit fc91c10 into main Oct 26, 2026
1 check passed
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