docs: minimalist UI redesign proposal
Per-screen audit + 6 design principles + per-screen mockups + commit-by-commit implementation plan + 7 open questions. Boldest moves: collapse the 5-button-per-row admin list into a hover-revealed ⋯ menu with clickable status pill; fold the standalone Share section into the detail-page header as an inline link strip; drop the JSON-questions textarea from /new behind a <details> disclosure so the common path reads as four inputs and a button. No code touched — design only. Awaiting m's go before coder shift.
This commit is contained in:
706
docs/plans/ui-redesign.md
Normal file
706
docs/plans/ui-redesign.md
Normal file
@@ -0,0 +1,706 @@
|
||||
# fdbck — minimalist UI redesign
|
||||
|
||||
**Status:** design proposal, not yet approved.
|
||||
**Branch:** `mai/cronus/fdbck-minimalist-ui`.
|
||||
**Author:** cronus, 2026-05-06.
|
||||
|
||||
m's brief: *"While our app is quite simple, the layout of it seems overly complex
|
||||
and crowded. I want clearer separation (by negative space) between the different
|
||||
elements and smarter control buttons for a smooth UX."*
|
||||
|
||||
The app is already small (1 stylesheet, 2 reusable components, 5 routes). The
|
||||
problem isn't features — it's that the existing screens fight minimalism with
|
||||
*always-visible action rows*, *redundant copy*, *inline `style="..."` patches*,
|
||||
and *tight vertical rhythm*. This doc proposes per-screen edits that hold
|
||||
features constant but trade visible buttons for whitespace and progressive
|
||||
disclosure.
|
||||
|
||||
---
|
||||
|
||||
## 1. Audit
|
||||
|
||||
### 1.1 `/` (landing)
|
||||
|
||||
```
|
||||
┌────────────────────────────────────────┐
|
||||
│ fdbck │ ← 1.75rem h1
|
||||
│ Private feedback forms and live chat… │
|
||||
│ │
|
||||
│ This page is only reachable through… │
|
||||
│ [ Admin sign-in ] │ ← ghost button
|
||||
└────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
- Already close to minimalist — 20 lines of markup, two paragraphs, one ghost
|
||||
button. Mostly fine.
|
||||
- The wordmark `fdbck` is the brand moment but renders at the same size as
|
||||
every other page h1 (`1.75rem`). It should *feel* like a logo on the landing
|
||||
page, not a generic heading.
|
||||
- Two paragraphs ("Private feedback forms…" / "This page is only reachable…")
|
||||
partly say the same thing. The second one is a near-tautology — the user is
|
||||
already on the page, so "you got here through a private link" is implicit.
|
||||
- Vertical rhythm is tight: `1.5rem` between subtitle and section, then the
|
||||
button sits right under one short sentence.
|
||||
- Tiny: a marketing-blank landing for a tool whose CTA is "sign in" feels
|
||||
hollow. Either lean further into emptiness (just the wordmark + sign-in) or
|
||||
add one line of confidence-building text. We'll lean into emptiness.
|
||||
|
||||
### 1.2 `/login`
|
||||
|
||||
```
|
||||
┌────────────────────────────────────────┐
|
||||
│ Sign in │
|
||||
│ Admin access only. │
|
||||
│ │
|
||||
│ Email [______________] │
|
||||
│ Password [______________] │
|
||||
│ [ Sign in → ] │
|
||||
└────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
- "Sign in" + "Admin access only" is mild redundancy — the page is the form.
|
||||
- Error banner sits *between* the password field and the submit button, which
|
||||
pushes the button down on error and feels like a layout glitch. Better
|
||||
position: above the form (page-level error) or beneath the button as an
|
||||
inline string.
|
||||
- Two fields, one button, no dark patterns — already minimalist. Just needs
|
||||
more vertical breathing room and a quieter subtitle (or none).
|
||||
|
||||
### 1.3 `/admin/feedback` (list)
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────────────────────────────┐
|
||||
│ Feedback forms [ + New form ] │
|
||||
│ Collect feedback through forms or live chat. Share a private… │
|
||||
│ │
|
||||
│ Your forms (4) │
|
||||
│ ┌──────────────────────────────────────────────────────────┐ │
|
||||
│ │ Title (link) [Form+chat] [open] │ │
|
||||
│ │ 12 responses · 7 messages · created 2026-05-01 │ │
|
||||
│ │ /f/long-slug-shown-raw │ │
|
||||
│ │ [Edit] [Copy link] [Open] [Close] [Delete] ← 5 buttons │ │
|
||||
│ └──────────────────────────────────────────────────────────┘ │
|
||||
│ … │
|
||||
└──────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
- **The biggest offender.** Five always-visible buttons per row (Edit, Copy
|
||||
link, Open, Close/Reopen, Delete) wrap onto multiple lines on narrow widths.
|
||||
Even on desktop they read as a noisy strip.
|
||||
- Each row has *border + shadow + bg + padding + status pill + mode pill +
|
||||
raw slug + meta line + button strip*. Nine visual objects per row.
|
||||
- Inline `style="…"` everywhere (`+page.svelte:108-156`). Should be classes in
|
||||
`feedback.css` so dark-mode and rhythm tokens stay consistent.
|
||||
- The raw `/f/<slug>` line is shown but has no purpose for the admin — they
|
||||
use Copy link or Open. It's just text noise.
|
||||
- Header repeats the page title in the body (`<h1>Feedback forms</h1>`) and
|
||||
then the section heading (`<h2>Your forms (N)</h2>`). The H2 mostly
|
||||
duplicates the H1, just with a count.
|
||||
|
||||
### 1.4 `/admin/feedback/new`
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────────────────────────────┐
|
||||
│ [← All forms] │
|
||||
│ Create a new form │
|
||||
│ Set up a feedback form, a live chat session, or both. You'll… │
|
||||
│ │
|
||||
│ Title [______________________________] │
|
||||
│ Description [______________________________] │
|
||||
│ ☑ Enable live chat │
|
||||
│ Questions (JSON, optional) [ + Insert sample ] │
|
||||
│ ┌──────────────────────────────────────────────────────────┐ │
|
||||
│ │ { … 14-row JSON textarea, monospace … } │ │
|
||||
│ └──────────────────────────────────────────────────────────┘ │
|
||||
│ Leave empty for chat-only feedback. You can edit questions… │
|
||||
│ │
|
||||
│ [ ✓ Create form ] │
|
||||
└──────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
- The JSON textarea is a *power-user escape hatch* dropped into the same
|
||||
surface as a beginner-friendly title/description form. It dominates the
|
||||
page (14 rows, monospace font), even though the visual builder on the
|
||||
detail page is the recommended path.
|
||||
- "Insert sample" sits *to the right* of the label, inside the field's
|
||||
header — visually clever but also noise.
|
||||
- The chat checkbox is a single inline item floating in its own block. It
|
||||
looks afterthought-y. (It also reuses `.fb-option-row` styling, which is
|
||||
meant for question options.)
|
||||
- Helper text under the JSON is good, but it's the *third* descriptive
|
||||
paragraph on the page (`<p>Set up a feedback form…</p>`,
|
||||
`placeholder="…"`, `<div class="fb-question__help">`).
|
||||
|
||||
### 1.5 `/admin/feedback/[id]` (detail)
|
||||
|
||||
```
|
||||
┌────────────────────────────────────────────────────────────────────────┐
|
||||
│ [← All forms] │
|
||||
│ My session feedback │
|
||||
│ Some optional description text shown if present. │
|
||||
│ [open] /f/long-slug [Copy link] [Preview] [Close] [CSV] [JSON] [Delete] ← 8 chips/buttons in one row
|
||||
│ │
|
||||
│ ┌── Share ─────────────────────────────────────────────────────────┐ │
|
||||
│ │ Memorable short link — resolves to /f/long-slug. │ │
|
||||
│ │ https://msbls.de/vote [ Copy ] [ Open ↗ ] │ │
|
||||
│ │ ▸ Replace with a different short link │ │
|
||||
│ └──────────────────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ [ Chat (3) ] [ Results (12) ] [ Responses (12) ] [ Edit ] │
|
||||
│ …active tab body… │
|
||||
└────────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
- **Header is the densest surface in the app.** Eight clickable controls in a
|
||||
flex-wrap row: status pill, raw slug, Copy link, Preview, Close/Reopen,
|
||||
CSV, JSON, Delete. On a 1024px viewport this wraps onto two lines.
|
||||
- "Copy link / Preview" in the header *and* a separate Share section *and*
|
||||
the slug shown raw — three different ways to access the same URL.
|
||||
- CSV / JSON download buttons sit between Close and Delete — they're not
|
||||
in the same gravitational tier (export is benign, Delete is nuclear), but
|
||||
they look identical (both `fb-btn--ghost fb-btn--sm`).
|
||||
- The Share section (recently added) was bolted onto the layout rather than
|
||||
designed into it. It sits between header and tabs, breaking the "header →
|
||||
tab → tab body" mental model.
|
||||
- The Edit tab's form has its own internal mini-toolbar (Visual / JSON
|
||||
toggle), which is correct but visually clashes with the parent tab strip
|
||||
one screen up.
|
||||
- Polling `setInterval(refresh, 5000)` is right; no UX change needed there.
|
||||
|
||||
### 1.6 `/f/[slug]` (participant)
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────┐
|
||||
│ Title │
|
||||
│ Optional description │
|
||||
│ [⚠ closed banner if closed] │
|
||||
│ │
|
||||
│ Dein Name (optional): [Anonym______] ← inline label + full-width input collide
|
||||
│ │
|
||||
│ ┌── Live-Feedback ──────────────────┐ │
|
||||
│ │ scroll list of posts │ │
|
||||
│ │ [textarea] │ │
|
||||
│ │ [ Senden ] │ │
|
||||
│ └───────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌── Fragebogen ─────────────────────┐ │
|
||||
│ │ q1 [...] │ │
|
||||
│ │ q2 [...] │ │
|
||||
│ │ [ Absenden ] │ │
|
||||
│ └───────────────────────────────────┘ │
|
||||
│ │
|
||||
│ fdbck.msbls.de │
|
||||
└──────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
- Already simple. Needs *more* breathing room between Chat and Form sections
|
||||
— they read as two equally-weighted siblings, but in practice one of them
|
||||
is what the user came for.
|
||||
- The `Dein Name (optional):` label sits inline left of a full-width input
|
||||
(`fb-name-row`), while every other label in the participant form is on
|
||||
its own line above the input. The inline-label pattern is the only one
|
||||
of its kind on this page — kill it.
|
||||
- Footer `fdbck.msbls.de` is fine as a quiet trust signal.
|
||||
- Closed banner uses `--color-warning` palette which reads as alert; for a
|
||||
closed-form *neutral* state, a quieter visual is better.
|
||||
- Locale mix: admin pages use English (`Sign in`, `Edit`, `Delete`), but the
|
||||
participant page is German (`Senden`, `Absenden`, `Fragebogen`). Probably
|
||||
intentional (admins are us, participants are German-speaking) — flagging
|
||||
it so we don't accidentally homogenise during the redesign. **Not in
|
||||
scope to change.**
|
||||
|
||||
---
|
||||
|
||||
## 2. Principles
|
||||
|
||||
The following six rules apply to every screen. They are the lens for §3.
|
||||
|
||||
1. **Whitespace over dividers.** Replace borders/shadows/dividers with
|
||||
generous vertical space. The rule of thumb: if a card is bordered on a
|
||||
page that's already on a coloured `--gradient-bg`, the card competes with
|
||||
the page background — drop the border, keep the radius+padding, lean on
|
||||
negative space. Spacing scale: `0.5rem` (within a row), `1.25rem` (between
|
||||
form fields), `2.5rem` (between sections), `4rem` (above page footer).
|
||||
2. **One primary action per page.** Per screen, exactly one button uses the
|
||||
solid `.fb-btn` (filled green). Everything else is `--secondary` or
|
||||
`--ghost` or icon-only. Today most screens have 2–8 solid-or-near-solid
|
||||
actions competing for attention.
|
||||
3. **Smarter controls — collapse rows.** Anywhere we currently render 3+
|
||||
buttons in a strip, the redesign keeps **one** primary inline (or zero —
|
||||
"the row itself is the button") and tucks the rest behind a `⋯` menu
|
||||
(`<details>` summary or a small popover). Status flips become pill
|
||||
toggles instead of buttons. Destructive actions live *only* inside the
|
||||
`⋯` menu, never as a top-level visible button.
|
||||
4. **Visual hierarchy via type weight, not borders.** Inter is loaded — use
|
||||
weight `700` for page-h1, `600` for section-h2, `500` for form labels,
|
||||
`400` for body. Tracking `-0.02em` on headings (already in the CSS for
|
||||
h1) extended to h2. This lets us drop a lot of decorative chrome.
|
||||
5. **Optimistic UX.** Delete a row → row disappears immediately, with an
|
||||
undo toast for ~6s. Toggle status → pill switches instantly, network
|
||||
call in background. Errors revert the optimistic change and show a small
|
||||
inline message. We already have Svelte 5 `$state` everywhere, so this
|
||||
is plumbing, not architecture.
|
||||
6. **No inline `style="..."` for layout.** Every inline style currently in
|
||||
the .svelte files moves to a class in `feedback.css`. Two reasons: dark
|
||||
mode lives in `@media (prefers-color-scheme: dark)` rules and inline
|
||||
styles bypass it; and inline styles defeat the spacing-scale rule (1).
|
||||
|
||||
Optional principle 7 (suggest, but waiting for m): **list, not cards.** A
|
||||
naked padded list with hover-revealed actions beats card-grids for a small N
|
||||
(≈ <50 forms). Keeps the page feeling like *content*, not a dashboard.
|
||||
|
||||
---
|
||||
|
||||
## 3. Per-screen redesigns
|
||||
|
||||
### 3.1 `/` (landing)
|
||||
|
||||
```
|
||||
┌────────────────────────────────────────┐
|
||||
│ │
|
||||
│ │
|
||||
│ fdbck │ ← 2.5rem, weight 700, tracked -0.03em
|
||||
│ feedback by link │ ← muted, 1rem, weight 400
|
||||
│ │
|
||||
│ │
|
||||
│ [ Admin sign-in → ] │ ← single ghost button, sized fb-btn--lg
|
||||
│ │
|
||||
└────────────────────────────────────────┘
|
||||
↑ massive vertical centering
|
||||
```
|
||||
|
||||
- Centre the page vertically (max-width 480px, `min-height: 100vh`,
|
||||
`display: grid; place-items: center;`).
|
||||
- Drop the "This page is only reachable through a private link…" sentence —
|
||||
if a participant lands here they're not lost; the wordmark + sign-in is
|
||||
enough.
|
||||
- Wordmark grows to `2.5rem`, weight `700`, tracking `-0.03em`. Subtitle
|
||||
shrinks to `1rem` muted.
|
||||
- Single CTA, `fb-btn--lg fb-btn--ghost` with the existing `arrow-right`
|
||||
icon (already used on login submit).
|
||||
|
||||
### 3.2 `/login`
|
||||
|
||||
```
|
||||
┌────────────────────────────────────────┐
|
||||
│ │
|
||||
│ Sign in │ ← drop "Admin access only"
|
||||
│ │
|
||||
│ Email │
|
||||
│ [______________________] │
|
||||
│ │
|
||||
│ Password │
|
||||
│ [______________________] │
|
||||
│ │
|
||||
│ ⓘ inline error appears here, muted │
|
||||
│ │
|
||||
│ [ Sign in → ] │
|
||||
└────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
- Drop the "Admin access only." subtitle (the URL says it).
|
||||
- Vertical-centre the form (same grid trick as landing).
|
||||
- Inline error: render as a small muted line *below* the submit button
|
||||
rather than an `fb-banner--error` block above it. Less alarming, no
|
||||
layout shift.
|
||||
- Keep the existing primary `fb-btn` with arrow-right icon.
|
||||
|
||||
### 3.3 `/admin/feedback` (list) — **the biggest change**
|
||||
|
||||
```
|
||||
┌────────────────────────────────────────────────────────────────────┐
|
||||
│ Forms [ + New ] │ ← terse h1, primary CTA
|
||||
│ ───────── │
|
||||
│ │
|
||||
│ My session feedback ●open ⋯ │ ← row hover-reveals ⋯
|
||||
│ Form + chat · 12 responses · 7 messages │
|
||||
│ │
|
||||
│ ┌── 2.5rem of pure whitespace ──┐ │
|
||||
│ │
|
||||
│ Sprint 4 retro ○closed ⋯ │
|
||||
│ Form · 0 responses │
|
||||
│ │
|
||||
│ ┌── 2.5rem of pure whitespace ──┐ │
|
||||
│ │
|
||||
│ Quick chat ●open ⋯ │
|
||||
│ Chat · 21 messages │
|
||||
└────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**Row anatomy:**
|
||||
|
||||
- The whole row title is a link → goes to detail (today's "Edit" button
|
||||
becomes implicit).
|
||||
- Subtitle: mode + counts only. **Drop** the raw `/f/<slug>` line, the
|
||||
`created DATE` ("created" word), and the mode pill — fold mode into the
|
||||
subtitle text ("Form + chat · 12 responses").
|
||||
- Right side: a status dot+label (●open / ○closed) that *is the toggle* —
|
||||
click flips it (optimistic). One control replaces today's
|
||||
pill-+-Close-button pair.
|
||||
- Trailing `⋯` menu (`<details>` summary or popover) opens:
|
||||
- Copy link
|
||||
- Open ↗
|
||||
- Edit (explicit jump, even though row is also a link)
|
||||
- ──────
|
||||
- Delete (red)
|
||||
- Drop `border + shadow + bg` on the row container. Rely on row-padding
|
||||
+ `2.5rem` gap between rows. Hover state: faint `--color-bg-tertiary`
|
||||
background, no border.
|
||||
- Mobile (`< 640px`): keep the `⋯` always visible; on desktop reveal on
|
||||
hover for a calmer default state.
|
||||
|
||||
**Header:**
|
||||
|
||||
- Drop the descriptive paragraph ("Collect feedback through forms…"). The
|
||||
user already knows what fdbck is.
|
||||
- H1 reads "Forms" (terser than "Feedback forms", since we're already at
|
||||
`/admin/feedback`).
|
||||
- Drop the H2 "Your forms (N)" — the count moves into the H1 area as a
|
||||
small muted number, or drops entirely (the rows themselves are the
|
||||
count).
|
||||
- Keep one solid `+ New` button on the right.
|
||||
|
||||
**Empty state:** generous whitespace + "No forms yet — create your first
|
||||
one." + the same `+ New` button as primary CTA.
|
||||
|
||||
**Optimistic delete:** after confirming, row disappears immediately;
|
||||
toast at the bottom: "Form deleted. [Undo]" for 6s.
|
||||
|
||||
### 3.4 `/admin/feedback/new`
|
||||
|
||||
```
|
||||
┌────────────────────────────────────────────────────────────────────┐
|
||||
│ ← Forms │ ← terse back-link, no chip
|
||||
│ │
|
||||
│ New form │
|
||||
│ │
|
||||
│ Title │
|
||||
│ [______________________________________________] │
|
||||
│ │
|
||||
│ Description (optional) │
|
||||
│ [______________________________________________] │
|
||||
│ │
|
||||
│ ☐ Enable live chat │
|
||||
│ │
|
||||
│ ▸ Add questions now (advanced) │ ← collapsed by default
|
||||
│ │
|
||||
│ [ ✓ Create form ] │
|
||||
└────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
- Title + Description + chat checkbox are the *common path*. They occupy
|
||||
the full page width without any JSON noise.
|
||||
- The JSON textarea moves behind a `<details>` disclosure labelled "Add
|
||||
questions now (advanced)". Inside the disclosure we keep:
|
||||
- the `Insert sample` button (now sits *inside* the disclosure, where it
|
||||
belongs)
|
||||
- the textarea
|
||||
- the helper paragraph
|
||||
- Rationale: the visual builder on the detail page is the canonical path
|
||||
for adding questions; offering JSON paste at *creation* is power-user
|
||||
speed-up, not the default. By collapsing it, the new-form page reads
|
||||
like 4 inputs and a button.
|
||||
- Replace the back-link button with a plain `← Forms` text-link in muted
|
||||
weight 500, no chip styling.
|
||||
- Drop the page subtitle ("Set up a feedback form…"). The label "New form"
|
||||
+ the form below carry the meaning.
|
||||
- Move the chat toggle from a faux-`fb-option-row` checkbox to a proper
|
||||
`.fb-toggle` with a clean label-on-the-left layout (new class — small
|
||||
CSS addition).
|
||||
|
||||
### 3.5 `/admin/feedback/[id]` (detail) — **the second-biggest change**
|
||||
|
||||
```
|
||||
┌────────────────────────────────────────────────────────────────────────┐
|
||||
│ ← Forms │
|
||||
│ │
|
||||
│ My session feedback ●open ⋯ │ ← title + clickable status pill + ⋯
|
||||
│ Some optional description shown if present. │
|
||||
│ │
|
||||
│ msbls.de/vote [ Copy ] [ Open ↗ ] [ Replace ] │ ← share-link strip, INLINE in header
|
||||
│ │
|
||||
│ ───────────────────────────────────────────────────────────────── │ ← whitespace, no border
|
||||
│ │
|
||||
│ [ Chat (3) ] [ Results (12) ] [ Responses (12) ] [ Edit ] │
|
||||
│ │
|
||||
│ …active tab body, with 2.5rem top-padding… │
|
||||
└────────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**Header collapse — 8 controls → 3 visible:**
|
||||
|
||||
| today's control | redesign |
|
||||
| ------------------------------------ | ---------------------- |
|
||||
| status pill (display only) | status pill, clickable to toggle (optimistic) |
|
||||
| `/f/slug` raw text | dropped (the share strip below has the link) |
|
||||
| Copy link button | inside share strip |
|
||||
| Preview button | inside share strip ("Open ↗") |
|
||||
| Close / Reopen button | merged into status pill |
|
||||
| CSV button | inside `⋯` menu |
|
||||
| JSON button | inside `⋯` menu |
|
||||
| Delete button | inside `⋯` menu (red, last) |
|
||||
|
||||
`⋯` menu contents (in order, with separators):
|
||||
|
||||
1. Copy link (when the share strip is hidden on mobile)
|
||||
2. Export CSV
|
||||
3. Export JSON
|
||||
4. ──────
|
||||
5. Delete (red)
|
||||
|
||||
**Share section disappears as a separate block.** The short URL is shown
|
||||
inline in the header as one strip:
|
||||
|
||||
- If `inst.short_url` exists: show it + Copy + Open ↗ + Replace (Replace
|
||||
opens a small inline form *under* the strip — same `<details>` pattern
|
||||
as today, but compact).
|
||||
- If it doesn't: show "No short link · [ Create one ]" → click reveals
|
||||
the slug input + create button.
|
||||
|
||||
This kills today's awkward "section between header and tabs" structure
|
||||
and folds share into the place where the user expects "where do I share
|
||||
this".
|
||||
|
||||
**Tabs unchanged in count and labels.** They stay: Chat / Results /
|
||||
Responses / Edit. Selection style stays the segmented-pill (`fb-tabs` /
|
||||
`fb-tab--active`). Whitespace between tab strip and tab body grows from
|
||||
`1.25rem` to `2.5rem` so the tab body breathes.
|
||||
|
||||
**Edit tab inline polish:**
|
||||
|
||||
- Drop the duplicate `<h2>Edit · v3</h2>` heading inside the tab — the
|
||||
active tab pill already says "Edit". Save the version pill for a quiet
|
||||
spot next to the Save button.
|
||||
- The `Visual` / `JSON` toggle becomes a small segmented control in the
|
||||
same shape as the tab pills (consistency).
|
||||
- Save button is the page's primary action *while* this tab is active.
|
||||
No other solid button on the page in that state.
|
||||
|
||||
**Banner about responses-already-received** (`{submissions.length}
|
||||
responses already received…`) becomes a single muted line above the form,
|
||||
not a banner box.
|
||||
|
||||
### 3.6 `/f/[slug]` (participant)
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────┐
|
||||
│ │
|
||||
│ Title │ ← h1, room above
|
||||
│ Optional description │
|
||||
│ │
|
||||
│ ⓘ closed (only if closed, neutral) │ ← muted not yellow when closed
|
||||
│ │
|
||||
│ ───────────────────────────────────── │ ← 3rem gap
|
||||
│ │
|
||||
│ Live-Feedback │
|
||||
│ ┌── chat list ──────────────────────┐ │
|
||||
│ │ … │ │
|
||||
│ └───────────────────────────────────┘ │
|
||||
│ [ textarea (full width) ] │
|
||||
│ [Senden]│
|
||||
│ │
|
||||
│ ───────────────────────────────────── │ ← 3rem gap (same as above)
|
||||
│ │
|
||||
│ Fragebogen │
|
||||
│ q1 │
|
||||
│ q2 │
|
||||
│ │
|
||||
│ [ Absenden ] │
|
||||
│ │
|
||||
│ │
|
||||
│ fdbck.msbls.de │
|
||||
└──────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
- **Drop the inline-label name row.** Replace with a normal labelled field
|
||||
matching the rest of the form:
|
||||
|
||||
```
|
||||
Dein Name (optional)
|
||||
[Anonym__________________________]
|
||||
```
|
||||
|
||||
Or move it *below* the chat/form sections as a footer-style "Du
|
||||
schreibst als: Anonym ✎" with click-to-edit. (Suggested — see open
|
||||
question #5.) For v1 keep it at top but normalise its layout.
|
||||
- Increase section gap from `1.75rem` to `3rem` between the chat block
|
||||
and the form block, so they read as two distinct activities.
|
||||
- Closed banner: switch from amber `--color-warning` palette to a quiet
|
||||
neutral muted style (1px top border + small italic line) — closed is a
|
||||
state, not an alert.
|
||||
- Drop the `border-color: var(--color-primary)` on `.fb-chat__post--mine`
|
||||
in favour of a subtle left-border-only accent (3px, `--color-primary`).
|
||||
The current full pill-with-coloured-border treatment is loud.
|
||||
- Footer `fdbck.msbls.de` → wrap as a permalink to `/`, very muted.
|
||||
|
||||
---
|
||||
|
||||
## 4. Implementation plan
|
||||
|
||||
The redesign is *only* CSS + small `.svelte` markup edits. No new
|
||||
components, no new dependencies, no schema changes. Suggested commit order
|
||||
(each commit is independently mergeable and testable):
|
||||
|
||||
### Commit 1 — CSS foundation: spacing scale + typography rhythm
|
||||
|
||||
- `src/lib/styles/feedback.css`:
|
||||
- Add a spacing scale as CSS custom properties (`--space-1` through
|
||||
`--space-7`, or named `--gap-row / --gap-field / --gap-section /
|
||||
--gap-foot`).
|
||||
- Bump `.fb-section` margin-bottom from `1.75rem` → `--gap-section`
|
||||
(≈ `2.5rem`).
|
||||
- `.fb-header h1` weight stays 700; `.fb-section h2` weight bumps from
|
||||
`600` → `600` (no change) but tracking `-0.01em` already there.
|
||||
- Add `.fb-page-narrow` (max-width `480px`) and `.fb-page-center`
|
||||
(vertical grid centre) modifiers for landing/login.
|
||||
- Add `.fb-toggle` for label-left+switch-right boolean fields.
|
||||
- Add `.fb-row` for spacious list rows (no border, no shadow, hover
|
||||
bg) plus `.fb-row__title`, `.fb-row__meta`, `.fb-row__actions`.
|
||||
- Add `.fb-status-pill` (clickable open/closed pill).
|
||||
- Add `.fb-menu` (the `⋯` dropdown — implemented as `<details>` +
|
||||
`<summary>` + a positioned panel).
|
||||
- Add `.fb-share-strip` (the inline header share row in 3.5).
|
||||
- No structural Svelte changes in this commit — verify in the browser
|
||||
that the existing pages still render fine since added classes are
|
||||
unused additions.
|
||||
|
||||
### Commit 2 — landing + login (cheap wins)
|
||||
|
||||
- `src/routes/+page.svelte`: drop the second paragraph; wrap shell in
|
||||
`fb-page-center fb-page-narrow`; bump wordmark size.
|
||||
- `src/routes/login/+page.svelte`: drop the "Admin access only."
|
||||
subtitle; wrap in `fb-page-center fb-page-narrow`; move error from
|
||||
`fb-banner--error` block to a small inline muted line.
|
||||
- Verify both routes in the browser at 375px / 1024px / 1440px.
|
||||
|
||||
### Commit 3 — `/admin/feedback/new`
|
||||
|
||||
- `src/routes/admin/feedback/new/+page.svelte`:
|
||||
- Drop the page subtitle.
|
||||
- Replace the chat-checkbox block with `.fb-toggle`.
|
||||
- Wrap "Questions (JSON, optional)" + sample button + textarea +
|
||||
helper inside a `<details>` with summary "Add questions now
|
||||
(advanced)".
|
||||
- Remove inline `style="..."` on the back-link block; replace with a
|
||||
`.fb-back-link` class (text-only, muted).
|
||||
|
||||
### Commit 4 — `/admin/feedback` (list) — biggest change, isolated commit
|
||||
|
||||
- `src/routes/admin/feedback/+page.svelte`:
|
||||
- Drop the H1 paragraph.
|
||||
- Drop the H2 "Your forms (N)".
|
||||
- Replace each row (today's bordered card with 5 buttons) with the
|
||||
`.fb-row` pattern from commit 1: title is a link to detail,
|
||||
subtitle merges mode + counts, right side is `.fb-status-pill`
|
||||
(toggle) + `.fb-menu` trigger.
|
||||
- Move all inline `style="..."` to classes (no new feature).
|
||||
- Add the `⋯` menu component inline using `<details>` — no JS
|
||||
framework needed; click-outside-to-close via a small `addEventListener`
|
||||
in `onMount`.
|
||||
- Add optimistic delete with undo toast (small `<aside>` element fixed
|
||||
to bottom-centre, `setTimeout` 6s, calls `DELETE` only after timeout
|
||||
expires).
|
||||
- Verify the live deployed list still looks right after deploy.
|
||||
|
||||
### Commit 5 — `/admin/feedback/[id]` (detail) — second-biggest change
|
||||
|
||||
- `src/routes/admin/feedback/[id]/+page.svelte`:
|
||||
- Header collapse per 3.5: status becomes `.fb-status-pill`, drop
|
||||
raw `/f/slug` text, drop inline Copy/Preview/Close/Reopen/CSV/
|
||||
JSON/Delete buttons.
|
||||
- Add `.fb-share-strip` directly under the title/description in the
|
||||
header (replaces the standalone Share section below).
|
||||
- Add `.fb-menu` with Copy link / Export CSV / Export JSON /
|
||||
────── / Delete.
|
||||
- Delete the standalone `<section data-fb-share>` block — its
|
||||
contents are now in the header strip + a "Replace" inline form.
|
||||
- Inside Edit tab: drop the `<h2>Edit · v3</h2>`, move version pill
|
||||
next to Save; turn Visual/JSON into a segmented pill control
|
||||
matching `.fb-tabs`.
|
||||
- Move `submissions.length` warning from `.fb-banner` to muted line.
|
||||
- Replace inline `style="..."` with classes throughout.
|
||||
|
||||
### Commit 6 — `/f/[slug]` participant polish
|
||||
|
||||
- `src/routes/f/[slug]/+page.svelte`:
|
||||
- Replace the inline-label name row with a stacked-label field.
|
||||
- Increase gap between Chat and Form sections (use `--gap-section`).
|
||||
- Switch "(closed)" banner to neutral muted style (a new
|
||||
`.fb-status-line--muted` modifier on `.fb-banner` or a dedicated
|
||||
`.fb-closed-line` class).
|
||||
- Adjust `.fb-chat__post--mine` styling: drop full coloured border,
|
||||
add `border-left: 3px solid var(--color-primary)` only.
|
||||
- Wrap footer text in an `<a href="/">` with `aria-label="fdbck home"`.
|
||||
|
||||
### Commit 7 — sweep: optimistic toggles, hover-reveal actions
|
||||
|
||||
- Add the optimistic-update + undo-toast pattern to `setStatus` on the
|
||||
detail page (status pill instant flip, server call after).
|
||||
- Apply the same to per-row `toggleStatus` on the list page.
|
||||
- Verify dark-mode pass: walk all five routes in dark mode (browser
|
||||
emulator) since multiple inline `style="..."` strings were converted
|
||||
to classes that inherit from `:root` / `prefers-color-scheme`.
|
||||
|
||||
---
|
||||
|
||||
## 5. Open questions for m
|
||||
|
||||
These are decisions m should weigh in on before implementation. Each has
|
||||
my recommendation, but they're all reversible.
|
||||
|
||||
1. **Cards vs spacious list for `/admin/feedback`.** I'm proposing a
|
||||
spacious list (no border, lots of whitespace, hover-revealed `⋯`).
|
||||
The brief mentions cards as an option. **My recommendation: list.**
|
||||
Cards add visual chrome (border + shadow) which is the opposite of
|
||||
"negative space". Cards earn their keep when each item has rich
|
||||
content (image, multi-line preview); fdbck rows have title + 2
|
||||
meta lines.
|
||||
2. **Optimistic delete with 6s undo, or keep the `confirm()` modal?**
|
||||
Today both list and detail use `confirm("…cannot be undone")`. The
|
||||
undo toast is smoother but trades safety for fluency. **My
|
||||
recommendation: undo toast** — the row reappears identically if
|
||||
undone, the destructive call only fires after timeout, no data is
|
||||
actually at risk during the 6s window. Keep `confirm()` only on
|
||||
detail-page Delete (deleting from the detail page is a more
|
||||
deliberate action and merits an extra step).
|
||||
3. **Share-link strip in the detail header — does it belong there?**
|
||||
I'm folding the standalone Share section *into* the header (3.5).
|
||||
Alternative: keep Share as a section but move it *below* the tabs,
|
||||
so the header stays minimal. **My recommendation: in the header.**
|
||||
Sharing the link is the second-most-common action after viewing
|
||||
results; it belongs near the title.
|
||||
4. **Drop the Edit tab body's inner H2?** Today every tab body has an
|
||||
`<h2>` echoing the tab name (`<h2>Live chat</h2>`,
|
||||
`<h2>Results</h2>`, etc.). I want to drop these — the tab strip
|
||||
already labels the active section. But this is a stylistic call.
|
||||
**My recommendation: drop the inner H2s,** add `2rem` of top
|
||||
padding to the tab body so the active tab pill alone titles the
|
||||
section.
|
||||
5. **Participant name field — top, bottom-as-footer, or bottom-as-
|
||||
"edit"?** Today it's at the top with an inline label. I'm proposing
|
||||
stacking it the same as other fields. A bolder alternative: move
|
||||
it to a footer-style "Du schreibst als: Anonym ✎" below all
|
||||
sections. **My recommendation for v1: stacked label, top.** Bolder
|
||||
move waits for v2.
|
||||
6. **Locale homogenisation.** Admin pages are English, participant
|
||||
page is German. Out of scope for this redesign — flagging only so
|
||||
we don't accidentally translate one of them while doing the markup
|
||||
pass. Confirm this stays as-is.
|
||||
7. **Accent on `--color-primary`.** Same green stays per brief. But
|
||||
today some screens have `box-shadow: 0 0 0 3px rgb(22 163 74 /
|
||||
0.15)` on focus and others have `0.25` opacity — minor inconsistency.
|
||||
Worth normalising during commit 1? **My recommendation: yes,
|
||||
normalise to one focus-ring rule (0.2 opacity, 3px).**
|
||||
|
||||
---
|
||||
|
||||
## 6. Anti-scope (explicitly NOT in this redesign)
|
||||
|
||||
- Palette: no new colours, no new accent.
|
||||
- Stack: still SvelteKit + vanilla CSS + Inter. No new deps.
|
||||
- Routes: unchanged URL structure.
|
||||
- Data model: unchanged.
|
||||
- Locale: no homogenisation (see Q6).
|
||||
- Polling intervals (5s admin, 3s chat): unchanged.
|
||||
- Auth flow / share-link backend: unchanged (only the *display* of the
|
||||
share link in the detail header changes).
|
||||
Reference in New Issue
Block a user