Skip to content
This repository was archived by the owner on Aug 7, 2026. It is now read-only.

feat(fileshare): recipient-field clarity, draft persistence & compose/nav polish - #306

Merged
rubenhensen merged 11 commits into
mainfrom
fix/issue-289-recipient-field-clarity
Jul 13, 2026
Merged

feat(fileshare): recipient-field clarity, draft persistence & compose/nav polish#306
rubenhensen merged 11 commits into
mainfrom
fix/issue-289-recipient-field-clarity

Conversation

@dobby-coder

@dobby-coder dobby-coder Bot commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

Closes #289 (part of encryption4all/postguard-js#188).

This began as the recipient-field clarity fix for #289 and picked up several
related compose, navigation, and marketing polish items requested alongside it.
Latest main is merged in.

Recipient field clarity (#289)

In the July 2026 user test a participant typed the recipient's email address
into the optional message box
instead of the recipient field — the recipient
input read generically as "Email address" and didn't signal "who you're sending
to".

  • Clearer label — the recipient input is now "Recipient email address"
    (EN) / "E-mailadres ontvanger" (NL) instead of the generic "Email
    address".
  • Reads as an address fieldtype=email with autocomplete="email",
    inputmode="email", autocapitalize="none", spellcheck="false", plus
    inline invalidity (shown only after the field is left) and a typo suggestion
    (e.g. gmial.comgmail.com) so what turns red matches the send-time
    check.
  • An envelope icon was trialled and removed — the label + placeholder
    (recipient@example.com) + field semantics carry the distinction without it.
  • Field order is confirmed as Recipient → optional Message → Send.

Compose step

  • Draft survives a refresh — recipient email(s), requested attributes,
    message, and attached files are persisted so refreshing /fileshare no
    longer wipes a half-written message. Files + metadata live in IndexedDB;
    restored files are re-injected into the dropzone so their previews reappear.
    Scope is bounded to the tab session via a sessionStorage marker (survives a
    refresh, dropped on tab close) and cleared on a successful send.
    • Privacy note: while a session is live the attached files sit
      unencrypted in the browser's IndexedDB. That's the deliberate trade-off for
      surviving a refresh; it's dropped on tab close (next-load cleanup) and on
      send.
  • Dropzone illustration no longer zooms on hover.
  • QR popup title ("Sign & send" / "Onderteken & verzend") bumped to
    font-size: md.

Help toggle

  • The expandable help sections used to pop open/closed instantly (native
    <details>). They now slide vertically open/closed (Svelte-controlled,
    reduced-motion aware, keeps the aria-expanded/aria-controls disclosure
    semantics).

Navigation & marketing

  • Navbar reflow on refresh fixedFF_BUSINESS was read from the
    runtime-injected APP_CONFIG, so prerendered marketing pages omitted the
    "PostGuard for Business" nav/footer item (flag false at build) while the
    client re-added it at runtime. That mismatch reflowed the navbar on every
    refresh. The feature is fully rolled out, so business is now a build-time
    constant that's always present — prerendered HTML and client render agree.
  • External-link arrows — off-site links (docs, business, GitHub, Yivi,
    Caesar) in the header, hamburger menu, and footers now carry the
    docs.postguard.eu (VitePress) external-link marker — reproduced 1:1: the
    Material north-east glyph, 11px, muted, opening in a new tab with
    rel=noopener and a screen-reader "opens in a new tab" hint.

Manual verification — draft persistence

Worth checking on the preview since it's hard to cover end-to-end automatically:

  1. On /fileshare, attach a file and type a recipient email + message, then
    reload — the file preview, email, and message should all return.
  2. Close the tab and reopen /fileshare — the draft should be gone (empty
    form), with no leftover data in IndexedDB (postguard-fileshare).

Checks

svelte-check (0 errors/0 warnings), eslint, and prettier --check clean on
changed files; Svelte MCP autofixer reports no issues. The external-link arrow
was screenshot-compared against docs.postguard.eu, and draft persistence was
verified in a real browser (add → refresh → restore; new session → cleared).

Users in the July 2026 user test typed the recipient's email address into
the optional message box because the recipient field did not clearly read
as "who you're sending to" (#289).

- Relabel the recipient input "Recipient email address" (EN) /
  "E-mailadres ontvanger" (NL) instead of the generic "Email address".
- Style it distinctly as an address field: leading envelope icon plus
  email autocomplete / inputmode / autocapitalize / spellcheck hints.
- Field order is already Recipient -> optional Message -> Send; confirmed
  and locked in with a regression test.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@dobby-coder dobby-coder Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: REQUEST_CHANGES — posted as a COMMENT only because GitHub blocks self-request-changes on a bot-authored PR. Treat as blocking.

Rules Dobby 2 — gatekeeper review (1 blocking finding).

The UI change itself is sound: the recipient input now carries an explicit "Recipient email address" label (en/nl), reads as an address field (type=email + autocomplete/inputmode/autocapitalize/spellcheck), gains a decorative leading envelope icon, and sits before the optional message box — cleanly addressing #289. Design, a11y (the icon is correctly aria-hidden/pointer-events:none), and the regression test's intent all check out.

Blocking: the new regression test fails CI's Svelte Check job with a type error (elementHandle() may be null passed to a Node param). See the inline comment for the exact reproduction and fix. Build, ESLint, Prettier, Stylelint and the Playwright run (13/13) all pass — this is the only issue.

Non-blocking note: PRs #303#308 from the July-2026 user-test batch each touch the shared en.json/nl.json bundle. They edit distinct keys (no overlapping lines) and are independent per-component fixes, so separate PRs are acceptable here — just flagging per consolidate-overlapping-prs in case a conflict surfaces at merge time.

Comment thread tests/recipient-field-clarity.test.ts
…nt ordering test

message.elementHandle() can resolve to null; narrow it with a guard
before passing to recipient.evaluate so `Svelte Check` (CI) type-checks.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@dobby-coder dobby-coder Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: APPROVE (sign-off) — posted as event=COMMENT because GitHub blocks self-APPROVE on a bot-authored PR (this PR is authored by dobby-coder[bot]). Treat as approved.

Rules Dobby 2 — gatekeeper review (cycle 2): no findings, clean.

The cycle-1 blocking finding (regression test failed Svelte Check — nullable elementHandle() passed to a Node param) is resolved at HEAD by commit 0423f89. Re-verified on a fresh checkout: npm run check → svelte-check reports 0 errors / 0 warnings across 819 files.

Rule-compliance and code-correctness checks both came back clean:

  • Conventional-commit title ✓, closing keyword (Closes #289) ✓, regression test present ✓ (tests-required-on-fixes).
  • WCAG: decorative envelope icon is aria-hidden="true" / focusable="false" / pointer-events:none; input keeps type=email + autocomplete/inputmode/autocapitalize/spellcheck and its accessible name ("Recipient email address"); label/input association intact.
  • No layout/type regressions — .pg-input stays full-width inside the new flex wrapper.

Review Dobby 2 handed forward 0 findings (Playwright 13/13, build clean). Flipping the PR to ready-for-review.

@dobby-coder
dobby-coder Bot marked this pull request as ready for review July 11, 2026 17:27
…nt-field-clarity

# Conflicts:
#	src/lib/components/filesharing/RecipientSelectionFields.svelte
Native <details>/<summary> shows and hides its content instantly with no
transition. Drive the disclosure from Svelte state instead so the content
can slide vertically in and out with a transition, honoring the disclosure
a11y pattern (aria-expanded/aria-controls) and prefers-reduced-motion.
FF_BUSINESS was read from the runtime-injected APP_CONFIG at module load.
On prerendered marketing pages the flag is false at build time (no
APP_CONFIG), so the static HTML omitted the business nav/footer item; at
runtime the flag is true, so hydration re-added it. That prerender-vs-client
mismatch made the navbar visibly reflow on every refresh (#297-adjacent).

The feature is fully rolled out, so make business a build-time constant that
is always present. Prerendered HTML and client render now agree — no reflow.
Add an ExternalLinkIcon that reproduces the docs.postguard.eu (VitePress)
external-link marker 1:1 — the Material north-east arrow glyph, 11px, muted
tertiary colour, nudged 4px right / 1px up. Apply it to off-site links in the
desktop header, hamburger menu, and both footers (docs, business, GitHub,
Yivi, Caesar), and open those links in a new tab with rel=noopener. The arrow
is decorative; a visually-hidden "opens in a new tab" hint (en/nl) keeps the
link's accessible name intact.
Refreshing /fileshare previously cleared everything the user had entered.
Persist the recipient email(s), requested attributes, message and attached
files so a refresh restores the compose step.

- Files + metadata are stored in IndexedDB (files can be large). FileInput
  re-injects restored files via Dropzone.addFile so their previews render and
  they flow into state like a normal add.
- A sessionStorage marker scopes the draft to the tab session: it survives a
  refresh but a new session drops any stale draft, so file contents don't
  linger. The draft is also cleared on a successful send.
- Saves are gated until the initial load runs, so an early empty save can't
  clobber the draft being restored.
@rubenhensen
rubenhensen merged commit 1e7bf1a into main Jul 13, 2026
8 checks passed
@rubenhensen
rubenhensen deleted the fix/issue-289-recipient-field-clarity branch July 13, 2026 15:02
@rubenhensen rubenhensen changed the title fix(filesharing): make recipient field read clearly as the address field feat(fileshare): recipient-field clarity, draft persistence & compose/nav polish Jul 13, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

UX: recipient email address is typed into the message field

1 participant