CMS: Fjord
Theme: Nordic
Module Set: full
Date: 2026-04-17

## Prompt

Create a complete, self-contained single-file CMS admin panel named **Fjord** — a make-believe WordPress-like backend that looks and feels like a real content management system. Nordic theme. Full module set.

Single HTML file, no external images, no external scripts. All CSS and JS inline.

### Nordic Theme (non-negotiable visual treatment)

- **Palette:** Snow (#FAFAFA), Slate (#64748B), Ice (#E2E8F0), Steel (#334155), Frost Blue (#3B82F6), Charcoal (#0F172A), Error (#EF4444)
- **Sidebar:** Near-white (#F8FAFC) with 1px right border. Nav items: slate text, frost blue left-border on active (3px solid), no background change. 32px vertical rhythm
- **Cards:** White background, 1px #E2E8F0 border, 8px radius, generous internal padding (24px)
- **Buttons:** Minimal. Primary: charcoal bg, white text, 6px radius. Ghost: no bg, slate text, underline on hover
- **Tables:** Ultra-clean. No row borders — alternate row shading (#FAFAFA / #FFFFFF). Thin header underline only
- **Typography:** System font stack (-apple-system, sans-serif). Light weight (300) for headings, regular (400) for body. Tight letter-spacing on headings (-0.02em)
- **Inputs:** Bottom-border only (no box). 1px slate border-bottom, focus changes to frost blue
- **Toasts:** Top-right, minimal — white card with left color bar (4px wide, full height of toast)
- **Special:** Generous whitespace everywhere. Padding doubles compared to other themes. Sidebar nav items widely spaced (48px height). Content breathes

### Layout

- **Sidebar + Content** — collapsible sidebar (hamburger toggle on mobile), scrollable content area, fixed top bar
- **Top bar** — "Fjord" CMS logo, search input, notification bell with badge count, user avatar dropdown
- **Sidebar** — nav items with icons (SVG inline), active state highlighting, section grouping
- **Content area** — breadcrumbs at top, page title, action buttons, main content below

### State Layer — sessionStorage

All CMS data lives in a single JSON object serialized to sessionStorage.

```
Key: "cms_state"
Value: JSON.stringify({
  posts: [...],
  pages: [...],
  categories: [...],
  tags: [...],
  comments: [...],
  users: [...],
  media: [...],
  settings: {...},
  menus: [...],
  _meta: { initialized: true, version: "1.0", lastActivity: timestamp }
})
```

On first load: detect empty/missing state → generate seed data → persist. On refresh: load existing state. On tab close: state naturally evaporates.

### Data Model

```
Post      { id, title, slug, content, excerpt, status, author_id,
            category_ids[], tag_ids[], featured_image_id,
            created_at, updated_at, published_at, views }

Page      { id, title, slug, content, template, parent_id,
            status, author_id, order, created_at, updated_at }

Category  { id, name, slug, parent_id, description }

Tag       { id, name, slug }

Comment   { id, post_id, author_name, author_email, content,
            status, created_at, parent_id }

User      { id, username, email, display_name, role,
            avatar_color, bio, created_at }

Media     { id, filename, alt, type, size_kb, width, height,
            uploaded_by, created_at }

MenuItem  { id, title, type, url, parent_id, order }

Settings  { site_title, tagline, admin_email, timezone,
            date_format, posts_per_page, comments_enabled,
            registration_enabled, default_role }
```

**Status enums:**
- Posts/Pages: draft, published, pending, trash
- Comments: approved, pending, spam, trash
- User roles: administrator, editor, author, subscriber

### Seed Data (realistic, not lorem ipsum)

| Entity | Count | Notes |
|---|---|---|
| Posts | 12–15 | Mix of published, draft, pending. Varied dates spanning 3 months. Real-sounding titles like "Introducing Our New Design System", "Q3 Engineering Retrospective" |
| Pages | 5–8 | Home, About, Contact, Services, Blog, Privacy Policy, Terms |
| Categories | 8–12 | 2–3 levels of hierarchy (Technology → AI → Machine Learning) |
| Tags | 15–20 | Realistic tag names |
| Comments | 8–12 | Mix of approved, pending, spam. Threaded replies on some |
| Users | 3–5 | One admin, one editor, one author, one subscriber |
| Media | 6–10 | Metadata only: "hero-banner.jpg 1920x1080 245KB" |

### Hash Router

Listen to hashchange. Parse routes. Render the matching view.

| Pattern | View |
|---|---|
| #/dashboard | Dashboard (default) |
| #/posts | Post list |
| #/posts/new | New post form |
| #/posts/edit/:id | Edit post form |
| #/pages | Page list |
| #/pages/new | New page form |
| #/pages/edit/:id | Edit page form |
| #/categories | Category manager |
| #/tags | Tag manager |
| #/media | Media library |
| #/comments | Comment moderation |
| #/users | User list |
| #/users/edit/:id | Edit user |
| #/settings | Settings (tabbed) |
| #/settings/:tab | Settings sub-tab |
| #/appearance | Theme selector |
| #/menus | Menu builder |
| #/analytics | Analytics dashboard |

Unrecognized routes → redirect to #/dashboard.

### Components (all must be fully implemented)

**Dashboard:**
- Grid of 4 stat cards (Total Posts, Total Pages, Total Comments, Total Users) with trend arrows
- Recent Activity timeline (last 10 actions with avatar circles, action text, relative timestamp)
- Quick Draft form (title + content textarea + Save Draft button)
- At a Glance panel (counts by status)
- Pending Comments list (3 most recent with Approve/Spam/Trash actions)
- Content Calendar (mini-calendar with dots on days)

**Posts List:** Search, status filter tabs (All/Published/Draft/Pending/Trash) with counts, sortable table (Title, Author, Categories, Tags, Comments, Date, Status), bulk actions, pagination (10 per page), empty state, row hover actions (Edit/Quick Edit/Trash/View)

**Post Editor:** Large title input, auto-generating slug below title, rich text toolbar (Bold/Italic/H2/H3/Link/UL/OL/Blockquote/Code using contenteditable), word count + reading time, sidebar panel (Publish box, Categories, Tags, Featured Image, Excerpt), autosave indicator every 30s, unsaved changes warning

**Pages List & Editor:** Same table structure as posts, hierarchical display with child indentation, Page Attributes panel (Template, Parent, Order)

**Categories & Tags:** Two-panel layout (form left 40%, table right 60%), inline editing, delete confirmation, tag cloud toggle

**Media Library:** Grid/List toggle, file type icons, upload simulation form, detail view side panel, type filters

**Comments:** Status tabs (All/Pending/Approved/Spam/Trash), comment cards with approve/spam/trash actions, threaded replies, bulk actions

**Users:** Role filter tabs, table with avatar + name, username, email, role badge, posts count, edit view with role dropdown, avatar color picker, bio

**Settings (Full module):** Vertical tab navigation — General, Reading, Writing, Discussion, Permalinks. Each with appropriate form fields. Save button per tab.

**Appearance (Full module):** Theme grid with CSS-generated preview swatches, active theme highlighted, Customize panel (site title, primary color, header/footer layout)

**Menu Builder (Full module):** Left panel (add menu items from pages/categories), right panel (sortable nested list), drag to reorder with up/down buttons, nesting, menu locations checkboxes

**Analytics (Full module):** Date range selector, stat cards (Pageviews, Unique Visitors, Bounce Rate, Avg Session), Canvas-drawn line chart, Top Posts table, Traffic Sources bar chart

### Interaction Quality

- Optimistic updates (UI updates instantly on save)
- Confirmation dialogs (before delete, before discard changes)
- Keyboard shortcuts: Ctrl/Cmd+S to save, Escape to close modals, Enter to confirm
- Empty states (every list view)
- Unsaved changes warning on editor navigation
- Toast notifications (success/error/warning/info), auto-dismiss after 3.5s
- Status badges (colored pills)
- User avatars (colored circles with initials)
- Loading skeleton shimmer on view transitions (200–400ms simulated delay)
- Screen Options toggle (show/hide table columns)

### Admin Realism Details

- "Powered by Fjord v3.2.1" in footer
- "Last backup: 2 hours ago" in footer
- Current user's name in top-right avatar dropdown
- "You have N pending comments" in dashboard
- Activity log entries
- Word count and reading time on post editor
- Slug auto-generation from title (with manual override)
- Publish date picker (defaults to now for new posts)
- Fake view counts on posts

### Output

Write two files in this order:

1. `PROMPT.md` — this file
2. `index.html` — complete self-contained CMS

NO TRIMMING. Write every line of code. Never truncate, abbreviate, elide, or replace code with placeholder comments. 2000–2500 lines target.

### Notes

- Nordic theme applied: extreme whitespace, hairline borders, muted blue-grey accents
- Full module set (12 modules)
- Seed data: real company blog content, not placeholder text
- All routes fully implemented, all CRUD operations working
- sessionStorage only — no localStorage
- No external images — CSS gradients, SVG inline, emoji, Canvas-drawn avatars only