Skip to content

Repository files navigation

siwe.xyz

The site for Sign in with Ethereum. One site, five things: the landing page, the documentation, the libraries, the blog, and the tools.

Built with VitePress 2. The docs use the default theme, because for reference material it is already the best thing available; everything else is hand-built on top of it.

pnpm install
pnpm dev        # http://localhost:4321
pnpm build      # → .vitepress/dist
pnpm preview
pnpm typecheck

Node 22.12 or newer. VitePress 2 dropped Node 20 but ships no engines field, so nothing will warn you.

What lives where

.vitepress/
  config.ts              site config, nav, sidebar
  rss.ts                 feed.rss, generated in buildEnd
  og.ts                  per-page Open Graph images, generated in buildEnd
  theme/
    index.ts             registers every global component
    Layout.vue           default theme + our slots
    style/               tokens.css, base.css, vp.css, fonts.css
    components/          the landing sections, the tools, the mark
    data/                ecosystem, libraries, stories, categories, posts loader
    lib/siwe/            the ERC-4361 parser, linter and fixer
    lib/example.ts       the one example message the whole site shares
    mark/                the brand engine, vendored — see below
src/
  index.md               the landing page
  contact.md             the contact form, posting to the API below
  docs/                  the documentation
  blog/                  posts, one directory per category
  ecosystem/  tools/  brand.md
  public/                fonts, favicon, the three case-study marks
api/                     the contact/newsletter service — see api/README.md

pnpm build generates a 1200 × 630 PNG for every Markdown page under the build output's og/ directory and writes matching Open Graph and Twitter metadata into every rendered page. pnpm og is a convenient alias for that build.

Two things that are copied on purpose

The mark engine. .vitepress/theme/mark/scanlines.js and icon.js are byte-for-byte copies from signinwithethereum/brand-experiments. Do not edit them here — change them there and copy again, so the site and the brand repository cannot drift. mark/index.ts is the only local file: it types the engine and loads it on the client.

The validator. .vitepress/theme/lib/siwe/ is the linter that shipped on docs.siwe.xyz, moved across unchanged. It was written as framework-free TypeScript, so all of it ported; only the interface is new. Its Jest suites (~1,500 lines) were left behind in the old repository and are worth bringing over.

Adding things

An ecosystem entry — one object in .vitepress/theme/data/ecosystem.ts. No logo: third-party marks arrive in mixed polarity and a wall of 90 of them says less than 90 legible names. Add a note if there is something specific to say.

A blog post — a markdown file in src/blog/<category>/. The category comes from the directory, so the URL and the category cannot disagree. Frontmatter needs title, date and description; the byline is rendered by the layout.

A blog category — a directory, an index.md holding <BlogIndex category="the-slug" />, and an entry in data/categories.ts. A category with no posts is hidden rather than shown with a zero.

A docs page — a markdown file under src/docs/, plus a sidebar entry in .vitepress/config.ts. Internal links are absolute and extensionless (/docs/quickstart/), and ignoreDeadLinks is off, so a wrong one fails the build rather than shipping.

Design

Everything comes off the mark. It is a 31 × 9 grid with ink on rows 0, 2, 4, 6 and 8 — so the cell is the unit, section dividers are two hairlines a cell apart (an ink row and its gap, at page scale), and there are exactly four colour roles.

The tokens are named --canvas, --field, --ink and --accent on purpose: those are the four names the mark engine reads, so a mark inherits whatever palette it sits in with no mapping layer. A .screen panel rebinds them to the screen palette and a mark inside one follows automatically.

--accent is #7f00f6 in both themes and is for fills. --accent-ui is the readable sibling per theme — 7.4:1 on white, 7.6:1 on black — and is what carries text and links.

Geist Sans for prose, Geist Mono for labels, values, code and anything a machine wrote. Both variable, both self-hosted. See /brand.

Deploying

Static build → nginx → Kamal, the same shape as the two sites this replaces.

cp .env.production.example .env.production   # fill it in; it is gitignored
cp .kamal/secrets.example .kamal/secrets

pnpm kamal:setup     # first time
pnpm kamal:deploy
pnpm kamal:logs

config/deploy.yml claims APP_HOSTsiwe.xyz — plus three retired names the same container answers on only to redirect them: www.siwe.xyz, next.siwe.xyz (the pre-release hostname for this rewrite) and docs.siwe.xyz (the Docusaurus site this replaces). docs.siwe.xyz forwards the path unchanged to siwe.xyz, where the path rules in nginx.conf move the old documentation URLs under /docs/; the mapping therefore lives in one place.

The contact form and the newsletter signup post to a small companion service — plain Node plus PostgreSQL, forwarding contact mail via Resend — that lives in api/ and deploys as its own Kamal app (config/deploy.api.yml, the kamal:api:* scripts) on the same server under API_HOST. The site build bakes https://API_HOST in as the endpoint, so point DNS for it at DEPLOY_HOST before the cutover. See api/README.md.

Do not commit .env.production. The repository this replaces committed its deploy host and registry username.

Licence

MIT. The mark and the wordmark are covered by the brand guidance at /brand.

About

The website and docs for SIWE.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages