| 1 |
# MNW Frontend |
| 2 |
|
| 3 |
Server-rendered HTML via Askama templates, HTMX for interactivity, hand-authored CSS. No build step, no JS framework. |
| 4 |
|
| 5 |
## Design System |
| 6 |
|
| 7 |
Typography and brand colors come from the cross-project brand system (three-tier type system, base palette, diamond mark rule). The server extends the base palette with CSS custom properties: |
| 8 |
|
| 9 |
### Extended Colors (CSS Variables) |
| 10 |
|
| 11 |
|
| 12 |
|
| 13 |
| `--background` | `#ede8e1` | Page background (brand beige) | |
| 14 |
| `--detail` | `#3d3530` | Body text (brand charcoal-brown) | |
| 15 |
| `--highlight` | `#6c5ce7` | Diamond mark only (brand violet) | |
| 16 |
| `--light-background` | `#f4f0eb` | Cards, elevated surfaces | |
| 17 |
| `--surface-muted` | `#ddd7c5` | Secondary buttons, status boxes | |
| 18 |
| `--border` | `#d0cbb8` | Borders, dividers | |
| 19 |
| `--text-muted` | `#8a8480` | Tertiary text | |
| 20 |
| `--success` | `#2d5016` | Positive states | |
| 21 |
| `--warning` | `#8b7355` | Caution states | |
| 22 |
| `--danger` | `#d62828` | Destructive actions, errors | |
| 23 |
| `--focus-ring` | `#6c5ce7` | Keyboard focus indicator | |
| 24 |
|
| 25 |
### Rules |
| 26 |
|
| 27 |
- **No pure white/black.** Use `--background` and `--detail` instead. |
| 28 |
- **Accent color is for the dot only.** Do not use `--highlight` for buttons, links, or borders. |
| 29 |
|
| 30 |
## Template Structure |
| 31 |
|
| 32 |
``` |
| 33 |
templates/ |
| 34 |
base.html Base layout (head, nav, footer, HTMX/CSRF) |
| 35 |
index.html Landing page |
| 36 |
pages/ Full page templates (extend base.html) |
| 37 |
login.html, join.html, discover.html, item.html, project.html, ... |
| 38 |
dashboards/ Dashboard pages (extend base.html, tabbed) |
| 39 |
dashboard-user.html User dashboard (Account, Payments, Projects, Analytics, Creator, SyncKit) |
| 40 |
dashboard-project.html Project dashboard (Overview, Content, Analytics, Blog, Promotions, Subscriptions, Settings) |
| 41 |
dashboard-item.html Item dashboard (versions, license keys, promo codes) |
| 42 |
admin-*.html Admin panels (waitlist, users, uploads, appeals) |
| 43 |
partials/ HTMX fragments (no base.html, returned directly) |
| 44 |
tabs/ Dashboard tab content (loaded via hx-get) |
| 45 |
user_details.html Account settings, links, SSH keys, sessions |
| 46 |
user_payments.html Stripe status, transactions, contacts |
| 47 |
user_projects.html Project list |
| 48 |
user_analytics.html Aggregated analytics |
| 49 |
user_creator.html Waitlist/invite system |
| 50 |
user_synckit.html SyncKit app management |
| 51 |
project_overview.html Project stats |
| 52 |
project_content.html Item list with bulk actions |
| 53 |
project_blog.html Blog post management |
| 54 |
project_analytics.html Per-project analytics |
| 55 |
project_settings.html Project config, git repos |
| 56 |
project_subscriptions.html Subscription tiers |
| 57 |
project_promotions.html Promo codes |
| 58 |
admin_*.html Admin table rows (HTMX swap targets) |
| 59 |
alert.html, form_status.html, save_status.html Status feedback fragments |
| 60 |
``` |
| 61 |
|
| 62 |
### Conventions |
| 63 |
|
| 64 |
- Full pages extend `base.html` and define `{% block content %}`. |
| 65 |
- Tab content is loaded via HTMX (`hx-get="/dashboard/tabs/details"` etc). |
| 66 |
- Partials are standalone HTML fragments — no `{% extends %}`. |
| 67 |
- Template structs live in `src/templates/dashboard.rs` (pages) and `src/templates/partials.rs` (fragments). |
| 68 |
|
| 69 |
## CSS Architecture |
| 70 |
|
| 71 |
Single file: `static/style.css` (~3100 lines). No preprocessor, no minification pipeline. |
| 72 |
|
| 73 |
### Section Order |
| 74 |
|
| 75 |
1. **Fonts** (`@font-face` declarations) |
| 76 |
2. **Variables** (`:root` custom properties) |
| 77 |
3. **Reset + Base** (global element styles) |
| 78 |
4. **Layout** (`.padded-page`, `.centered-page`, `.container`) |
| 79 |
5. **Buttons** (`.btn-primary`, `.btn-secondary`, `.btn-danger`, `.small` modifier) |
| 80 |
6. **Forms** (`.form-group`, `.form-section`, `.checkbox-group`) |
| 81 |
7. **Tables** (`.data-table`, `.compact-table`) |
| 82 |
8. **Utilities** (`.text-sm`, `.muted`, `.scroll-x`, etc.) |
| 83 |
9. **Badges** (`.badge`, `.badge-success`, `.badge-danger`) |
| 84 |
10. **Cards** (`.card`, `.stat-card`, `.project-card`) |
| 85 |
11. **Navigation** (`.tabs`, `.tab`, header/footer) |
| 86 |
12. **Components** (modals, toasts, progress bars, onboarding) |
| 87 |
13. **Page-specific** (discover, pricing, git browser, docs, splash) |
| 88 |
14. **Responsive** (`@media` queries at the end) |
| 89 |
|
| 90 |
### Utility Classes |
| 91 |
|
| 92 |
|
| 93 |
|
| 94 |
| `.text-sm` | `font-size: 0.85rem` | Secondary text (emails, dates) | |
| 95 |
| `.text-xs` | `font-size: 0.8rem` | Tertiary text (IDs, annotations) | |
| 96 |
| `.muted` | `opacity: 0.7` | De-emphasized content | |
| 97 |
| `.dimmed` | `opacity: 0.6` | Further de-emphasized | |
| 98 |
| `.meta` | `font-size: 0.85rem; opacity: 0.7` | Labels, captions | |
| 99 |
| `.nowrap` | `white-space: nowrap` | Dates, status badges | |
| 100 |
| `.scroll-x` | `overflow-x: auto; -webkit-overflow-scrolling: touch` | Horizontal scroll wrappers | |
| 101 |
| `.text-center` | `text-align: center` | Centered blocks | |
| 102 |
| `.small` | `padding: 0.25rem 0.6rem; font-size: 0.8rem` | Compact buttons in tables | |
| 103 |
| `.empty-state` | `text-align: center; padding: 2rem; opacity: 0.6` | Empty list messages | |
| 104 |
|
| 105 |
### Table Classes |
| 106 |
|
| 107 |
**`.data-table`** — Full-featured tables with alternating row backgrounds, hover states, and sortable headers. Used for transactions, blog posts, content items. |
| 108 |
|
| 109 |
**`.compact-table`** — Lighter admin/dashboard tables. Provides `width: 100%`, `border-collapse`, cell padding, header styling (`0.85rem`, muted), and row borders. Used for admin user/waitlist/upload tables, invite codes, wave history. |
| 110 |
|
| 111 |
### Button Variants |
| 112 |
|
| 113 |
Buttons use the `.btn-*` family. See `design-system.md` § Buttons for the current class names, colors, and modifiers. The bare `.primary` / `.secondary` / `.danger` classes were retired; use `.btn-primary`, `.btn-secondary`, `.btn-danger` instead. |
| 114 |
|
| 115 |
## HTMX Patterns |
| 116 |
|
| 117 |
### Tab Navigation |
| 118 |
|
| 119 |
Dashboard pages use HTMX tabs. Each tab button triggers `hx-get` to load content into `#tab-content`: |
| 120 |
|
| 121 |
```html |
| 122 |
<button class="tab active" |
| 123 |
hx-get="/dashboard/tabs/details" |
| 124 |
hx-target="#tab-content" |
| 125 |
hx-swap="innerHTML" |
| 126 |
hx-indicator="#tab-spinner" |
| 127 |
onclick="setActiveTab(this)">Account</button> |
| 128 |
``` |
| 129 |
|
| 130 |
Tab content is a partial template — the handler returns raw HTML, not a full page. |
| 131 |
|
| 132 |
### Admin Table Updates |
| 133 |
|
| 134 |
Admin actions (suspend, approve, trust) return the full table partial to replace the table body: |
| 135 |
|
| 136 |
```html |
| 137 |
<button class="primary small" |
| 138 |
hx-post="/api/admin/users/{{ user.id }}/trust" |
| 139 |
hx-target="#users-table" |
| 140 |
hx-swap="innerHTML">Trust</button> |
| 141 |
``` |
| 142 |
|
| 143 |
### Form Feedback |
| 144 |
|
| 145 |
Form submissions target a status element for inline feedback: |
| 146 |
|
| 147 |
```html |
| 148 |
<form hx-put="/api/users/me" |
| 149 |
hx-target="#profile-save-status" |
| 150 |
hx-swap="innerHTML"> |
| 151 |
``` |
| 152 |
|
| 153 |
The handler returns an `AlertTemplate` or `FormStatusTemplate` partial. |
| 154 |
|
| 155 |
### CSRF |
| 156 |
|
| 157 |
All mutating requests include CSRF tokens. The `base.html` template exposes `csrfHeaders()` for JS `fetch()` calls. HTMX requests get CSRF headers via `hx-headers` on the body element. |
| 158 |
|
| 159 |
## JavaScript |
| 160 |
|
| 161 |
Minimal JS — only where HTMX cannot handle the interaction. |
| 162 |
|
| 163 |
|
| 164 |
|
| 165 |
| `htmx.min.js` | HTMX library (vendored) | |
| 166 |
| `passkey.js` | WebAuthn passkey registration/authentication | |
| 167 |
| `upload.js` | File upload with progress bars | |
| 168 |
| `insertions.js` | Content insertion clip management | |
| 169 |
|
| 170 |
Inline `<script>` blocks in templates handle tab-specific interactions (blog editor, promo code toggling, SyncKit app management, link reordering). These are scoped to their tab and loaded when the tab content arrives via HTMX. |
| 171 |
|
| 172 |
### Conventions |
| 173 |
|
| 174 |
- Use `csrfHeaders()` for all `fetch()` calls. |
| 175 |
- Use `showToast(message)` for user notifications. |
| 176 |
- Use `hx-confirm` for destructive actions. |
| 177 |
- No external JS dependencies beyond HTMX. |
| 178 |
- No JS framework — vanilla DOM manipulation only. |
| 179 |
|
| 180 |
## Static Assets |
| 181 |
|
| 182 |
``` |
| 183 |
static/ |
| 184 |
style.css Main stylesheet (3100+ lines) |
| 185 |
htmx.min.js HTMX library |
| 186 |
passkey.js WebAuthn integration |
| 187 |
upload.js File upload with progress |
| 188 |
insertions.js Content insertion management |
| 189 |
fonts/ Young Serif, IBM Plex Mono, Lato (TTF) |
| 190 |
images/ Logo, favicons |
| 191 |
``` |
| 192 |
|
| 193 |
## Progressive Disclosure |
| 194 |
|
| 195 |
The dashboard conditionally shows features based on user state: |
| 196 |
|
| 197 |
- **Projects/Analytics tabs**: Only visible when `can_create_projects` is true. |
| 198 |
- **SyncKit tab**: Only visible when user is a creator AND has projects. |
| 199 |
- **SSH keys section**: Only visible when git hosting is enabled on the server. |
| 200 |
- **Subscriptions tab** (project dashboard): Only visible when Stripe is connected. |
| 201 |
- **Creator notification prefs**: Only visible when `can_create_projects` is true. |
| 202 |
- **Onboarding checklist**: Auto-dismissed when all steps complete (or manually skipped). |
| 203 |
|
| 204 |
## Key Paths |
| 205 |
|
| 206 |
|
| 207 |
|
| 208 |
| CSS | `static/style.css` | |
| 209 |
| Base template | `templates/base.html` | |
| 210 |
| Dashboard pages | `templates/dashboards/` | |
| 211 |
| Tab partials | `templates/partials/tabs/` | |
| 212 |
| Admin partials | `templates/partials/admin_*.html` | |
| 213 |
| Template structs | `src/templates/dashboard.rs`, `src/templates/partials.rs` | |
| 214 |
| Dashboard handlers | `src/routes/pages/dashboard/` | |
| 215 |
| JS (passkeys) | `static/passkey.js` | |
| 216 |
| JS (uploads) | `static/upload.js` | |
| 217 |
|