fix(onboarding) [BRNS-DESK-026]: make terms and privacy reachable from sign-in and about - #82
fix(onboarding) [BRNS-DESK-026]: make terms and privacy reachable from sign-in and about#82sebastian-ssvlabs wants to merge 1 commit into
Conversation
…m sign-in and about The sign-in screen asserted "By continuing you agree to the Terms & Privacy Policy." as plain text: no anchor, no URL, and no other route to either document anywhere in the app. The only way to read what was being agreed to was to guess the URL in a browser. - New LegalConsent component renders the sentence with real anchors to https://mybrains.ai/terms and https://mybrains.ai/privacy, so the line is keyboard-reachable and surfaces as links to assistive tech. - The sentence and the two link labels move into en/zh-CN as a template with {terms}/{privacy} slots, so each locale keeps its own word order. - The same two links are added to the About modal footer for post-onboarding reachability. - URLs live once in src/lib/legal-links.ts, which also routes the click to the default browser via plugin-shell.
| > | ||
| <span>Apache License 2.0</span> | ||
| <span>Copyright 2025-2026 OpenCovibe Contributors</span> | ||
| <span class="flex items-center gap-3"> |
There was a problem hiding this comment.
🟡 BRNS-DESK-026: acceptance requires the Terms/Privacy links to be reachable from About, but AboutModal is only mounted from src/routes/_opencovibe_layout.svelte.txt (an inert reference copy), so no post-onboarding surface in the live app can reach these links. Mount AboutModal from a live surface (e.g. a Settings/menu entry) or add the two links to an actually reachable surface.
nir-ssvlabs
left a comment
There was a problem hiding this comment.
Verified the part that would quietly reproduce the bug: both URLs serve. https://mybrains.ai/terms and /privacy return 200, and https://app.mybrains.ai/terms really does 404 — so the host choice is right and a consent link that leads nowhere isn't shipping in place of one that didn't exist.
The e.defaultPrevented bail is the detail I'd have expected to be missing: +page.svelte already installs a document-level capture handler that routes every http(s) anchor externally, so without that guard these two links would open twice. Splitting the sentence on {terms} / {privacy} slots rather than concatenating is also the right call for a localized legal string — a locale that needs different word order can have it.
Checked: both URLs and the 404 claim by request, the double-open guard against the existing capture handler, and that the new keys are present in both locales. Not read: the About-modal surface beyond its use of the shared constants.
Merge: ✅ into main.
Summary
grep -rniE "terms|privacy|tos|eula" src/ messages/ src-tauri/src/found that sentence as the only legal string in the codebase: no anchor, no URL, no Settings entry, no About link, no menu or tray item. The only way to review what was being agreed to was to guess a URL in a browser.https://mybrains.ai/terms,https://mybrains.ai/privacy— theapp.mybrains.aivariants 404), the sentence is localized, and the same two links are reachable from the About modal after onboarding.Mechanism
src/lib/legal-links.tsholds the two URLs once (now referenced from two surfaces) plusopenLegalLink(e, url), which sends the click to the default browser via the existingplugin-shellidiom with awindow.openfallback. It bails one.defaultPreventedbecause+page.sveltealready installs a document-level capture handler that opens everyhttp(s)anchor externally — without that guard a link inside that tree would open twice.src/lib/components/LegalConsent.svelterenders the sentence from a single template key with{terms}/{privacy}slots and splits on those slots, so a locale can reorder the links rather than being locked to English word order; the labels are separate keys. Real<a href>elements keep the muted palette but add underline + pointer, so they are keyboard-reachable and expose as links (previouslyAXLinkcount on that screen was 0). The sign-in screen's paragraph becomes<LegalConsent marginTop={loginErr ? 14 : 26} />, which keeps the visual spacing behaviour and keeps this out of the 15k-line+page.svelte.New keys
legal_consent/legal_terms/legal_privacyare added to bothmessages/en.jsonandmessages/zh-CN.jsonwith a real Chinese translation.Overlap with sibling DESK PRs: the AboutModal edit is deliberately additive — one import line and one new
<span>appended after the existing copyright line in the footer — so BRNS-DESK-017's rebrand of the version/copyright lines rebases cleanly. The locale additions sit in their ownlegal_*block between thesetup_*andchat_*groups (same line position in both files) rather than at either end, to stay clear of 017/027/028/030. The sign-in screen change is a 7-line deletion replaced by one component tag, so PRs touching the connect/sign-in screen have minimal surface to conflict with.Worth flagging separately:
AboutModal.svelteis currently only mounted fromsrc/routes/_opencovibe_layout.svelte.txt(the inert fork-reference copy), so nothing in the live app opens it today. The links now live in the right surface, but re-wiring that surface is out of scope here — if 017 does not restore it, post-onboarding reachability needs a follow-up (e.g. a Settings entry).Verification
npx prettier --checkon all six changed files — cleannpx eslinton the changed files — 0 errors; the 35 warnings are pre-existingno-unused-varsin+page.svelte/chat/+page.svelte, none in the new filesnode scripts/i18n-check.mjs— 0 errors, 18 warnings (all pre-existing); the three new keys align across locales and their{terms}/{privacy}placeholder sets matchsvelte-check— 0 errors, 129 pre-existing warnings; none inLegalConsent.svelteorlegal-links.ts(the one hit inAboutModal.svelteis the pre-existingdialog-role tabindex warning on an untouched line). Needednpx svelte-kit syncfirst, since a fresh clone has no.svelte-kit— the blocker BRNS-DESK-016 documents--no-verifygrep -rn "By continuing you agree" --include='*.svelte' src/→ 0AXLinkcount ≥ 2), the actual browser hand-off on click, and the zh-CN rendering were not observed in a running app.cargowas not run at all (no local Rust target);shell:allow-openwas already granted insrc-tauri/capabilities/default.json, so no capability change was needed.