docs(android): summarize website frontend theme for Android client #17
98
android/theme-plan.md
Normal file
98
android/theme-plan.md
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
# Android theme plan — mirroring the website frontend
|
||||||
|
|
||||||
|
This is a summary of the **website frontend theme** (source of truth:
|
||||||
|
`website/client/src/styles/theme.css`, applied at runtime by
|
||||||
|
`website/client/src/contexts/SiteContext.jsx`) so the native Android client can
|
||||||
|
present a visually consistent brand. Where the web uses CSS custom properties,
|
||||||
|
the Android equivalent is a Compose `MaterialTheme` `ColorScheme` + `Typography`.
|
||||||
|
|
||||||
|
## Overall character
|
||||||
|
|
||||||
|
A **dark, moody, "arcane fantasy" theme** — deep blue-black backgrounds, muted
|
||||||
|
slate-blue accent, parchment-white text, and an engraved serif display face. It
|
||||||
|
reads like a leather-and-moonlight fantasy ledger, not a bright consumer app.
|
||||||
|
There is **no light mode** on the web; the app should ship dark-only to match.
|
||||||
|
|
||||||
|
## Color tokens
|
||||||
|
|
||||||
|
The web theme is a flat set of CSS variables under `:root`. Map them to Compose
|
||||||
|
as follows (hex is authoritative):
|
||||||
|
|
||||||
|
| Web token | Hex | Role | Compose slot (suggested) |
|
||||||
|
|-------------------|------------|----------------------------------------|-------------------------------|
|
||||||
|
| `--bg` | `#0e1318` | App background | `background` |
|
||||||
|
| `--bg-deep` | `#0b0f14` | Deepest surface / on-accent text | `surfaceDim` / `onPrimary` |
|
||||||
|
| `--panel-a` | `#192231` | Card gradient top | `surface` |
|
||||||
|
| `--panel-b` | `#141a21` | Card gradient bottom | `surfaceContainer` |
|
||||||
|
| `--panel-flat` | `#11161d` | Flat panels, toolbars | `surfaceContainerLow` |
|
||||||
|
| `--line` | `#2a3544` | Borders / dividers | `outline` |
|
||||||
|
| `--line-soft` | `#1d2733` | Subtle row dividers | `outlineVariant` |
|
||||||
|
| `--accent` | `#7f99bd` | **Primary accent** (brand-overridable) | `primary` |
|
||||||
|
| `--accent-bright` | `#cdd9e8` | Primary button fill, active states | `primaryContainer` / bright |
|
||||||
|
| `--ink` | `#eef3f8` | Highest-contrast text | `onBackground` |
|
||||||
|
| `--head` | `#e6edf6` | Headings | heading color |
|
||||||
|
| `--text` | `#c4cdd8` | Body prose | `onSurface` |
|
||||||
|
| `--muted` | `#aeb8c4` | Secondary text | `onSurfaceVariant` |
|
||||||
|
| `--dim` | `#6f7d8e` | Meta / captions / placeholders | dim / disabled text |
|
||||||
|
| `--blue` | `#13243c` | Accent hover/active background | `secondaryContainer` |
|
||||||
|
| `--mode-live` | `#5fb98a` | "Shard live" status (green) | success |
|
||||||
|
| `--mode-maint` | `#e6c26a` | "Maintenance" status (amber) | warning |
|
||||||
|
|
||||||
|
### Semantic / status colors (used in badges, diffs, moderation)
|
||||||
|
|
||||||
|
- **Success / published / live:** green `#5fb98a` (fills at ~16–22% alpha, text `#7fd0a4`).
|
||||||
|
- **Warning / maintenance / moderation (kick/mute/warn):** amber `#e0b070` / `#e6c26a`.
|
||||||
|
- **Danger / ban / red-link / errors:** desaturated red `#d98b84` (borders `#6e3b38`).
|
||||||
|
- **Admin badge:** near-white `#d8e2ef` on `#3a4a5e`.
|
||||||
|
|
||||||
|
## Branding is data, not code
|
||||||
|
|
||||||
|
The `--accent` value is **overridden at runtime** per shard instance. On the web,
|
||||||
|
`SiteContext` reads `brand.accent` from the site settings API and sets the CSS
|
||||||
|
variable, so one build reskins for any shard. **The Android app should do the
|
||||||
|
same:** fetch the brand payload (name, `accent`, colors, logo/hero/favicon) from
|
||||||
|
the website API and derive the `primary` color at runtime rather than hardcoding
|
||||||
|
`#7f99bd`. Default to `#7f99bd` when the brand payload is absent/offline.
|
||||||
|
|
||||||
|
## Typography
|
||||||
|
|
||||||
|
Three font families, by role:
|
||||||
|
|
||||||
|
- **Display** (`--display`): **Cinzel**, falling back to Georgia serif — an
|
||||||
|
engraved Roman capitals face used for the logo, `h1`/`.h1`, and prose
|
||||||
|
`h2`/`h3`. Bundle Cinzel as an app font; this face carries the brand.
|
||||||
|
- **Serif body** (`--serif`): **Georgia / Times New Roman** — default body and
|
||||||
|
prose text; `line-height ≈ 1.6`.
|
||||||
|
- **Sans** (`--sans`): **Helvetica Neue / Arial** — UI chrome: buttons, pills,
|
||||||
|
form labels, table headers, badges, meta. Labels/eyebrows/kickers are
|
||||||
|
UPPERCASE with wide letter-spacing (`0.1–0.18em`) and small (0.68–0.86rem).
|
||||||
|
|
||||||
|
Heading scale is fluid on web (`h1` clamps ~2.4–3.6rem); pick fixed Material type
|
||||||
|
scale equivalents (e.g. display for `h1`, headline for `h2`, title for `h3`).
|
||||||
|
|
||||||
|
## Shape, elevation & motion
|
||||||
|
|
||||||
|
- **Corners:** cards/panels `10–12px` radius; inputs/small elements `8px`;
|
||||||
|
pills and buttons are **fully rounded** (`999px` / capsule).
|
||||||
|
- **Cards:** vertical gradient `--panel-a → --panel-b`, 1px `--line` border, soft
|
||||||
|
drop shadow (`0 14px 34px rgba(0,0,0,0.3)`). On hover the web lifts `-3px` and
|
||||||
|
brightens the border to `--accent` — translate to a pressed/focused accent
|
||||||
|
border on Android.
|
||||||
|
- **Buttons:** primary = bright fill (`--accent-bright`) with dark text;
|
||||||
|
ghost/secondary = translucent dark fill with accent-on-hover border.
|
||||||
|
- **Motion:** short, subtle transitions (0.12–0.18s). Keep animations understated.
|
||||||
|
|
||||||
|
## Signature accents (nice-to-have)
|
||||||
|
|
||||||
|
- The **"moon"** motif: a radial-gradient sphere (`#eef3f8 → #9fb0c6 → #5d6e88`) —
|
||||||
|
a small brand flourish worth reproducing.
|
||||||
|
- Accent-tinted focus rings and left-border "note" callouts
|
||||||
|
(`border-left: 3px solid --accent` over a translucent `--blue` background).
|
||||||
|
|
||||||
|
## Implementation note for Compose
|
||||||
|
|
||||||
|
Define one `darkColorScheme(...)` from the table above, a `Typography` binding the
|
||||||
|
three families, and a `Shapes` set (`small = 8.dp`, `medium = 10.dp`, capsule for
|
||||||
|
buttons). Load `accent` from the brand API into a state holder and rebuild the
|
||||||
|
`primary` (and derived `primaryContainer`) at runtime so a shard's custom accent
|
||||||
|
flows through the whole UI — exactly as `SiteContext` does on the web.
|
||||||
Reference in New Issue
Block a user