stack/.github
BilalG1 401191615f
feat(dashboard): one-time Stack Auth → Hexclave rebrand modal (#1493)
## Summary

Adds a one-time informational modal that announces the **Stack Auth →
Hexclave** rebrand to existing logged-in dashboard users. Brand-new
users signing up after the cutoff already land on a fully
Hexclave-branded experience and don't see the modal — they have no
"Stack Auth" mental model to update.

Stacked on top of **PR #1481** (the visible-rebrand flip).

![Hexclave rebrand
modal](https://github.com/hexclave/stack-auth/raw/cl/hexclave-rebrand-modal/.github/assets/hexclave-rebrand-modal.png)

## What's in here

- **Component**:
[`apps/dashboard/src/components/hexclave-rebrand-modal.tsx`](https://github.com/hexclave/stack-auth/blob/cl/hexclave-rebrand-modal/apps/dashboard/src/components/hexclave-rebrand-modal.tsx)
— the modal itself plus the static `RebrandIllustration` (Stack Auth
mark → arrow → Hexclave benzene mark).
- **Mount**:
[`apps/dashboard/src/app/(main)/(protected)/layout-client.tsx`](https://github.com/hexclave/stack-auth/blob/cl/hexclave-rebrand-modal/apps/dashboard/src/app/(main)/(protected)/layout-client.tsx)
— single `<HexclaveRebrandModal />` inside `ConfigUpdateDialogProvider`
so it covers every authenticated dashboard route.
- **Asset**: `apps/dashboard/public/hexclave-icon.svg` — the
benzene-ring mark pulled from `https://hexclave.com/icon.svg` (the
canonical Hexclave brand mark). Stack Auth side uses the existing
`/logo.svg` + `/logo-bright.svg` (dark mode variant).

## Targeting

Three independent conditions must all hold for the modal to render:

1. **Logged-in user** — `useUser({ or: "return-null" })` opts out of the
sign-in redirect so guests are silently skipped.
2. **`user.signedUpAt < REBRAND_CUTOFF`** where `REBRAND_CUTOFF =
2026-05-27T00:00:00Z`. This is the cleanest "pre-rebrand user" signal —
more accurate than cookie inspection (the existing `stack-is-https` hint
cookie gets dual-written for new and returning users alike since
[`packages/template/src/lib/cookie.ts:201`](https://github.com/hexclave/stack-auth/blob/cl/hexclave-rebrand-modal/packages/template/src/lib/cookie.ts#L201),
so it can't distinguish), and it follows the same user across
browsers/devices.
3. **No `hexclave-rebrand-modal-dismissed=true` in localStorage**. Any
dismissal path (Got it button, X, overlay click, Escape) routes through
`onOpenChange` and writes this flag, so the modal never re-opens for
that browser.

## Behavior verification

End-to-end checked against a live dev dashboard:

-  Modal opens once on first authenticated dashboard view for a
pre-cutoff user.
-  `localStorage["hexclave-rebrand-modal-dismissed"]` flips to `"true"`
on any dismissal path.
-  Reload after dismissal: zero `[role=dialog]` elements rendered,
localStorage flag persists.
-  Not rendered for guests (no useUser → early `return null`, no
auth-redirect).
-  Not rendered for users with `signedUpAt >= REBRAND_CUTOFF`.
-  SSR-safe: hooks into `useEffect` to read storage post-hydration;
`try/catch` around storage access so private-mode / sandboxed iframes
degrade silently.
-  `pnpm --filter @stackframe/dashboard lint` clean.

## Notes

- **`pnpm typecheck`** was not run as part of this change because the
dashboard typecheck depends on `codegen-prisma` against a live DB
(pre-existing infra debt noted in PR #1481). Lint covers the type-shape
of the touched files via the project's strict TS-aware ESLint rules.
- **Migration link** points to
[`docs.hexclave.com/migration`](https://docs.hexclave.com/migration),
the same URL referenced from
[`packages/template/src/internal/deprecation-warning.ts:36`](https://github.com/hexclave/stack-auth/blob/cl/hexclave-rebrand-modal/packages/template/src/internal/deprecation-warning.ts#L36)
— single source of truth for the migration story.
- **No animation** by design — the modal is static; entry/exit uses the
existing Radix Dialog fade.

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Adds a one-time modal in the dashboard to announce the Stack Auth →
Hexclave rebrand for pre-rebrand users. It shows once per account per
browser, inlines the import-rename step, links the migration guide, and
doesn’t show for new signups or in dev/preview environments.

- **New Features**
- Shows only for logged-in users with `signedUpAt <
'2026-05-27T00:00:00Z'`; guests, post-cutoff signups, and local
emulator/remote dev/preview never see it.
- Dismissal persists via
`localStorage["hexclave-rebrand-modal-dismissed:<user.id>"]="true"`; all
close paths set the flag.
- Mounted in the protected dashboard layout so it covers all
authenticated routes once per account per browser.
- Includes illustration (`/logo.svg` → arrow → `/hexclave-icon.svg`) and
links to app.hexclave.com and the migration guide; copy tells users to
rename `@stackframe/*` to `@hexclave/*` (`@stackframe/stack` →
`@hexclave/next`).

<sup>Written for commit 92c07f2bd8.
Summary will update on new commits. <a
href="https://cubic.dev/pr/hexclave/stack-auth/pull/1493?utm_source=github">Review
in cubic</a></sup>

<!-- End of auto-generated description by cubic. -->
2026-05-26 18:16:25 -07:00
..
assets feat(dashboard): one-time Stack Auth → Hexclave rebrand modal (#1493) 2026-05-26 18:16:25 -07:00
recurseml-rules Clarifying Recurse ML Naming Rules (#872) 2025-09-02 09:31:14 -07:00
workflows ci(hexclave): scope mirror publish to @hexclave/* packages 2026-05-26 10:25:58 -07:00
.recurseml.yaml Add Recurse ML rules for naming and code patterns (#780) 2025-07-18 09:58:23 -07:00
auto_assign.yml Run auto-assign on draft PRs 2025-04-10 10:18:47 -07:00
pull_request_template.md feat(hexclave): PR 2 — visible rebrand to Hexclave 2026-05-23 17:35:08 -07:00
SECURITY.md feat(hexclave): PR 2 — visible rebrand to Hexclave 2026-05-23 17:35:08 -07:00