Skip to content

feat(desktop): onboarding polish — docked CTAs, backup key card, dot grid#2008

Merged
wesbillman merged 6 commits into
mainfrom
cynthiac/onboarding-polish
Jul 17, 2026
Merged

feat(desktop): onboarding polish — docked CTAs, backup key card, dot grid#2008
wesbillman merged 6 commits into
mainfrom
cynthiac/onboarding-polish

Conversation

@cynfria

@cynfria cynfria commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Summary

Polish pass over the desktop onboarding flow.

  • Docked CTAs. Every step's primary/secondary CTAs dock to the bottom of the viewport via a portal (OnboardingFooter), clearing the transform-containment that traps position: fixed, with a scrim so scrolled content fades under them. Applies across the machine, relay, and community flows.
  • Shared chrome. New OnboardingChrome (top-left Buzz mark + step-dots pagination), replacing OnboardingStepDots.
  • Backup key card. The private key sits in a translucent white card (bg-white/50, 12px radius) with olive ink (--buzz-onboarding-backup-ink) on the key and the "never share" caption; 36px mono key via a nsec-key token; no layout shift on reveal (same-length mask). Copy now works whether or not the key is revealed.
  • Dot grid on all onboarding pages.
  • CTA label colors: chartreuse on the landing screen, light blue inside the steps.

The non-obvious bug (worth a look)

The masked key overflowed its container only in WKWebView — WebKit will not line-break a run of (U+2022) even with word-break: break-all / overflow-wrap: anywhere, while Chromium breaks it fine. Our Playwright suite runs Chromium, so it never caught this. Fix: the mask joins its bullets with a zero-width space (a break opportunity WebKit honors), and the wrapping text is a plain block inside the flex item. Verified in the WebKit engine that both masked and revealed states wrap and stay inside the card. See NsecMaskedDisplay.tsx.

Testing

  • desktop-check, desktop-test, desktop-tauri-test pass; pnpm check:px-text and pnpm run build clean.
  • New onboarding-docked-cta-screenshots.spec.ts; identity-lost.spec.ts updated for the dot-grid background.
  • Onboarding + identity-lost E2E suites pass.

🤖 Generated with Claude Code

cynfria and others added 2 commits July 16, 2026 17:22
Dock the primary/secondary CTAs of every onboarding step to the bottom of
the viewport via a portal (OnboardingFooter) so they clear the transform
containment that traps position:fixed, with a scrim so scrolled content
fades under them. Add shared OnboardingChrome (top-left mark + step-dots
pagination), replacing OnboardingStepDots. Applies across the machine,
relay, and community flows and all steps.

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

Backup step: frame the private key in a translucent white card (bg-white/50,
12px radius) with olive ink (--buzz-onboarding-backup-ink) on the key and the
"never share" caption; large 36px mono key via a nsec-key token; no layout
shift on reveal (same-length mask). Copy now works whether or not the key is
revealed.

Fix key overflow in WKWebView: WebKit will not line-break a run of U+2022
bullets even with break-all/overflow-wrap, so the masked key ran off its
container (Chromium-based Playwright never caught it). Join the mask bullets
with a zero-width space; the wrapping text is a block inside the flex item.

Also: dot-grid pattern on all onboarding pages, and split the primary-CTA
label color — chartreuse on the landing screen, light blue inside the steps.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@cynfria
cynfria requested a review from a team as a code owner July 17, 2026 00:30
cynfria and others added 2 commits July 16, 2026 17:49
- Guard NostrKeyImportForm handleSubmit against re-entry: the portaled
  submit button is now type=button, so the single-field form still
  submits on Enter — without the guard a second Enter during an in-flight
  import fired a duplicate onImport (double keyring write).
- Restore variant-aware submit styling so KeyringLockedScreen (default
  variant, rendered outside the onboarding footer provider) keeps its
  full-width button instead of a mismatched docked pill.
- Restore bottom padding on the avatar step so its tall emoji/color grid
  scrolls clear of the always-docked footer + scrim on short windows.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- CommunityOnboardingFlow: derive the step-dot position from the same
  condition that picks the rendered page, so the dots no longer regress
  6->5 while the starter-team page shows 'Preparing Welcome...' during
  the finalizing transient.
- onboarding-avatar-skip / onboarding-backup specs: capture the full
  viewport instead of the step subtree, so the portaled docked CTAs
  actually appear in the QA screenshots again.
- NsecMaskedDisplay: memoize the masked-bullet string on nsec instead of
  reallocating it every render.

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

brow commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

🤖 Review summary (approved — no blockers). Cross-posting from the Buzz review thread for the record.

What I checked (full diff, all 19 files, base 2494926, head 307263d):

  • Docked CTA portal (OnboardingFooter) — sound design. Portal target is a sibling of the transformed step subtree, which correctly escapes the position: fixed containing-block trap. The animation-fill-mode: both → backwards change on the mask-reveal transition is the right companion fix (end state is identity transform, so no visual change). Inline fallback when no provider exists covers KeyringLockedScreen, and its full-width button styling is preserved via the variant branch.
  • Enter-key double-submit guard in NostrKeyImportForm — good catch, real bug: the submit button became type="button" in the portal, but the single-field form still submits on Enter; the in-flight guard in handleSubmit prevents a concurrent double keyring write.
  • WebKit mask wrap (NsecMaskedDisplay) — ZWSP-joined bullets is a legit fix for WebKit refusing to break U+2022 runs; mask is non-selectable and copy uses the raw nsec, so the ZWSP never leaks. Masking every char (vs the old 6-char plaintext prefix) is a strict improvement. Copy-while-masked is fine — clipboard gets the real key by explicit user action.
  • Security invariants intact — nsec still not in DOM until reveal, select-none + blur while masked, variant="boxed" settings usage unaffected.
  • Step-dots correctness — community flow correctly mirrors the render condition so the "finalizing" transient stays on page 6 (regression the branch itself caught and fixed); old OnboardingStepDots deleted with zero stale references.
  • Tests — new docked-CTA screenshot spec wired into the smoke project; identity-lost spec updated to match the dot-grid background-image. All CI green (Desktop Core, Build, 4 smoke E2E shards, 2 integration shards).

One nit posted inline (non-blocking): desktop/src/shared/ui/step-progress.tsx is now dead code.

import { useSystemColorScheme } from "@/shared/theme/useSystemColorScheme";
import { Button } from "@/shared/ui/button";
import { StartupWindowDragRegion } from "@/shared/ui/StartupWindowDragRegion";
import { StepProgress } from "@/shared/ui/step-progress";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🤖 Non-blocking nit: with this last import gone (the AvatarStep usage is also removed in this PR), desktop/src/shared/ui/step-progress.tsx is now dead code — nothing references StepProgress anymore. Fine to drop in a follow-up polish PR.

cynfria and others added 2 commits July 16, 2026 20:12
Reconcile the onboarding polish PR (#2008) with main's onboarding reskin
(#2003), which both redesigned the same screens.

Resolution (per design sign-off):
- Step chrome: keep our OnboardingChrome (static bee + centered progress
  bar); drop the OnboardingStepDots component. Bump the shared page count
  to 7 to include main's new Default-config step. WelcomeSetup now uses
  OnboardingChrome.
- CTA placement: keep our bottom-docked OnboardingFooter across every
  step, including main's new/reskinned Setup, Default-config, and
  Community pages.
- Keep main's newly shipped functionality: the Default-config step and
  the community inline avatar editor.
- Keep our non-conflicting backup/key work (WebKit wrap fix, translucent
  key card, olive key color, copy-while-masked, double-import guard).
- Align happy-path page titles to the text-title token (40px) for a
  consistent flow.
Remove machine-local Claude permissions, restart logs, and the stale
process ID accidentally included while resolving onboarding conflicts.

Co-authored-by: Pinky <44b8e82baa6e0e254e0208d68f335c283c94e7b78dd1fa10d5a49d3f13dd0435@sprout-oss.stage.blox.sqprod.co>
Signed-off-by: Wes <wesbillman@users.noreply.github.com>
@wesbillman
wesbillman enabled auto-merge (squash) July 17, 2026 03:27
@wesbillman
wesbillman merged commit 43bd104 into main Jul 17, 2026
25 checks passed
@wesbillman
wesbillman deleted the cynthiac/onboarding-polish branch July 17, 2026 03:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants