From 156c392cc2bb9beb10b5320ab8629ecb35443aa0 Mon Sep 17 00:00:00 2001 From: Hong Minhee Date: Wed, 29 Apr 2026 02:08:25 +0900 Subject: [PATCH 01/42] Document the front-end design system DESIGN.md introduces the design language for Hollo's server-rendered web pages: simplicity and modernness on an achromatic neutral base, tinted by each account's chosen theme color through CSS custom properties on the html element. It covers brand identity, design principles, the color system (neutral palette, twenty theme hues, and CSS variable injection), typography (Inter + Noto Sans CJK + JetBrains Mono via presetWebFonts), spacing, iconography (Lucide via presetIcons), component recipes, motion, and accessibility expectations. AGENTS.md is updated to point future contributors at DESIGN.md as the source of truth for front-end decisions. Assisted-by: Claude Code:claude-opus-4-7 --- AGENTS.md | 19 ++++ DESIGN.md | 334 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 353 insertions(+) create mode 100644 DESIGN.md diff --git a/AGENTS.md b/AGENTS.md index 4f7d28ae..f4225826 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -126,6 +126,7 @@ Key architectural components | *src/federation/index.ts* | Federation setup with inbox listeners | | *src/oauth/middleware.ts* | Authentication middleware | | *src/entities/status.ts* | Status entity serialization | +| *DESIGN.md* | Design system and front-end conventions | Technology stack @@ -187,6 +188,24 @@ export function MyComponent({ name }: { name: string }) { import React from 'react'; // Don't do this ~~~~ +### Design system and front-end conventions + +When working on any user-facing page (admin dashboard, profile, post, +auth, OAuth screens, etc.), read *DESIGN.md* first. It defines: + + - the visual design principles (simplicity, modernness, content first, + lightweight SSR, accessibility), + - the color system (achromatic neutrals plus per-account theme color + via CSS custom properties on ``), + - typography, spacing, iconography, and component recipes, + - the UnoCSS toolchain conventions (preset choices, prose application + areas, theme token injection, variant groups). + +Treat *DESIGN.md* as the single source of truth for front-end decisions +that aren't directly answered by the source code. Never introduce ad-hoc +CSS or inline styling that contradicts it; if the document is missing +guidance on a real case, update *DESIGN.md* in the same change. + ### Database guidelines - *Migrations*: Always generate migrations for schema changes diff --git a/DESIGN.md b/DESIGN.md new file mode 100644 index 00000000..07bd1367 --- /dev/null +++ b/DESIGN.md @@ -0,0 +1,334 @@ +Hollo design system +=================== + +This document defines the visual design language and front-end conventions +of Hollo's web pages. Hollo is primarily a headless ActivityPub server, but +it ships a small surface of server-rendered HTML pages — the admin +dashboard, account profiles, individual posts, the OAuth consent screen, +and a handful of utility screens. This document specifies how those pages +should look, feel, and be implemented. + +The design language values *simplicity* and *modernness* over decoration. +Surfaces are achromatic by default; color only enters the page through +the account owner's chosen *theme color*, which tints the profile and +post pages of that account. The visual center of every page is the +content the user came for, not the chrome around it. + + +Brand identity +-------------- + +The name *Hollo* is always written with a capital “H” and lowercase +“ollo”. The mark is a circular badge with the wordmark “Hollo” inside, +distributed as two SVGs at the project root: + + - *logo-black.svg* — for use on light backgrounds. + - *logo-white.svg* — for use on dark backgrounds. + +Both files are served from */public/* and embedded inline only when an +icon-sized rendering is needed. Don't recolor the mark; switch between +black and white based on the surrounding surface. + +The voice of the UI is short and matter-of-fact. Prefer plain English +sentences over imperative shouts; trust the reader. + + +Design principles +----------------- + + - *Simplicity*: prefer fewer controls, fewer borders, fewer surfaces. + Visual hierarchy comes from typography and spacing, not from boxes. + - *Modernness*: use modern CSS features (logical properties, OKLCH + color, container queries when needed) but never at the cost of + progressive degradation. + - *Content first*: text columns stay at a comfortable measure. Media + expands only when it earns the room. + - *Lightweight SSR*: pages are server-rendered with Hono JSX and ship + zero client-side JavaScript by default. Never reach for a runtime + framework to solve a styling problem that CSS can answer. + - *Accessibility*: every interactive element is keyboard-reachable, has + a visible focus state, and meets WCAG AA contrast in both light and + dark color schemes. + + +Color system +------------ + +### Neutral palette + +The default surface is achromatic. Hollo uses UnoCSS's *Wind4* neutral +scale (*neutral-50* through *neutral-950*) for backgrounds, borders, +surfaces, and text. No saturation enters a page until a theme color is +applied. + +| Role | Light scheme | Dark scheme | +| --------------- | ------------- | ------------- | +| Page background | *neutral-50* | *neutral-950* | +| Surface | *white* | *neutral-900* | +| Subtle border | *neutral-200* | *neutral-800* | +| Body text | *neutral-900* | *neutral-100* | +| Muted text | *neutral-500* | *neutral-400* | + +### Account theme colors + +Each account owner picks a theme color from a fixed set of twenty named +hues, defined as the *theme\_color* PostgreSQL enum in *src/schema.ts*: + +~~~~ +amber azure blue cyan fuchsia green grey indigo +jade lime orange pink pumpkin purple red sand +slate violet yellow zinc +~~~~ + +The palette comes from Pico CSS's named color palette. Each hue is +expressed at nine tonal stops (*50, 100, 200, 300, 400, 500, 600, 700, +800, 900*), stored as RGB triples in *src/theme/colors.ts*. + +### CSS variable injection + +The theme color is applied through CSS custom properties on the +`` element. *Layout.tsx* reads the account's *themeColor* and +emits inline declarations: + +~~~~ html + +~~~~ + +The UnoCSS configuration exposes these variables as a generic *brand* +color token: + +~~~~ ts +theme: { + colors: { + brand: { + 50: "rgb(var(--theme-50) / )", + // ... 100 through 900 + DEFAULT: "rgb(var(--theme-500) / )", + }, + }, +} +~~~~ + +This means components write `bg-brand`, `text-brand-700`, +`border-brand-200`, and so on, without ever knowing which of the twenty +hues is currently active. No safelist is needed because no class name +varies with the theme color. + +### Dark mode + +Dark mode follows the operating system via `prefers-color-scheme: dark`. +There is no manual toggle in the first pass; that may be added later +without changing the underlying tokens. All component recipes specify +both light and dark variants up front. + + +Typography +---------- + +### Type families + +| Role | Family | Source | +| -------- | ---------------------------------------------- | ------------------------- | +| Sans | *Inter* | bunny.net (Google mirror) | +| Sans CJK | *Noto Sans KR*, *Noto Sans JP*, *Noto Sans SC* | bunny.net | +| Mono | *JetBrains Mono* | bunny.net | + +Fonts are loaded through UnoCSS's *presetWebFonts* with the *bunny* +provider, which is a privacy-respecting mirror of Google Fonts. The CSS +font stack lists Inter first, then the three Noto Sans CJK families, and +falls back to the system stack so initial paint never blocks on a +network request. + +### Type scale + +Use the Wind4 default scale unchanged (*text-xs* through *text-5xl*). +Body copy is *text-base* with *leading-relaxed*. Headings step down by +one level per nesting depth. + +### Long-form content + +Rendered Markdown — post bodies, account bio fields, reply chains — is +wrapped in the *prose* class from *presetTypography*, with +*prose-neutral* and *dark:prose-invert* variants. Inline code uses the +mono family; block code is rendered through Shiki and keeps its own +colors. + + +Spacing and layout +------------------ + +The spacing scale is Wind4's default 4 px grid. Use multiples of *2* +(*0.5rem*), *3*, *4*, *6*, *8*, *12*, and *16* for almost all gaps. + +Page widths: + + - Reading column (post body, profile bio, settings forms): *max-w-2xl* + (~42 rem). + - Dashboard column (timelines, account list): *max-w-3xl* (~48 rem). + - Wide chrome (top nav, footer): full width with internal *max-w-5xl*. + +Breakpoints follow the Wind4 defaults (*sm* 640 px, *md* 768 px, *lg* +1024 px, *xl* 1280 px). Mobile is the design start point; widen by +adding `md:` and `lg:` variants. + + +Iconography +----------- + +Hollo uses a single icon collection: *Lucide*, surfaced through +UnoCSS's *presetIcons* with the *@iconify-json/lucide* package. Icons +are written as CSS classes: + +~~~~ tsx +