feat(admin): migrate admin surfaces onto role tokens - #373
Conversation
Scopes the admin layout root with EditionViewRoot and migrates the non-portal hardcoded color sites (text-white, bg-white/10, border-white/20, bg-purple-600) onto the role tokens from #363, with no visual change since each token carries today's exact value. Colors inside Radix Dialog/AlertDialog portals are left as-is since those portals render outside the edition-view CSS variable scope.
…active Code review flagged reusing the surface-active fill token as a border color as crossing the vocabulary doc's role taxonomy, even though the value matched. No border token covers this exact value yet, so leave it literal, matching the untouched border-white/10 in the same file.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
🟡 Changes recommended
Moderate token-migration gaps remain in hover and border colors, accent foregrounds, and an in-scope LinkWizard color.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
Migrates admin surfaces to edition role tokens under EditionViewRoot while preserving current styling.
Changes:
- Scopes admin content with
EditionViewRoot. - Replaces selected hardcoded colors with semantic tokens.
- Updates analytics, navigation, CTA, and archive styling.
File summaries
| File | Summary |
|---|---|
src/routes/admin/festivals/$festivalSlug/editions/$editionSlug/sets.tsx |
Tokenizes the Add Set CTA; hardcoded hover color remains. |
src/routes/admin/festivals/$festivalSlug/editions/$editionSlug.tsx |
Tokenizes the edition sub-navigation surface. |
src/routes/admin/analytics.tsx |
Tokenizes analytics surfaces and text; hardcoded borders remain. |
src/routes/admin.tsx |
Adds edition scope and tokenized tabs; active foreground and LinkWizard colors need updates. |
src/pages/admin/festivals/StageManagement/CreateStageDialog.tsx |
Tokenizes the CTA; hardcoded hover color remains. |
src/pages/admin/festivals/FestivalManagementSection.tsx |
Tokenizes the festival CTA; hardcoded hover color remains. |
src/pages/admin/festivals/FestivalEditionManagement.tsx |
Tokenizes the edition CTA; hardcoded hover color remains. |
src/pages/admin/festivals/EditionNavLink.tsx |
Tokenizes navigation states; active accent foreground needs correction. |
src/pages/admin/ArtistsManagement/components/BulkEditorHeader.tsx |
Tokenizes the artist CTA; hardcoded hover color remains. |
src/pages/admin/ArtistsManagement/ArchiveArtistDialog.tsx |
Updates archive hover text styling. |
Review details
Suppressed comments (6)
src/pages/admin/ArtistsManagement/ArchiveArtistDialog.tsx:52
- This replacement uses the page
foregroundrole for text rendered over the destructive red hover fill. That is only correct while both happen to be white; when the edition theme changesforeground, the destructive action can get the wrong contrast. Use the destructive foreground role for text on this fill (and keep the fill on its semantic destructive token).
className="border-red-400 text-red-400 hover:bg-red-400 hover:text-foreground"
src/pages/admin/festivals/FestivalManagementSection.tsx:38
- This CTA now gets
bg-accent, butButton's default variant still suppliestext-primary-foreground; notext-accent-foregroundis applied. That is near-white today, but the identity flip changes the dark-theme accent to lime with darkaccent-foregroundwhile the global primary foreground remains light, making the label fail the intended contrast. Add the paired accent foreground role to this CTA.
className="bg-accent hover:bg-purple-700"
src/pages/admin/festivals/StageManagement/CreateStageDialog.tsx:42
- Only the resting background is tokenized here. This
Buttonstill inheritstext-primary-foreground, andhover:bg-purple-700remains a literal; the palette flip changes the scopedaccent/accent-foregroundbut notprimary-foreground, so this CTA can have the wrong text contrast and revert to purple on hover. Usetext-accent-foregroundand a role token for the hover state, consistently with the other converted CTAs.
<Button className="bg-accent hover:bg-purple-700">
src/pages/admin/festivals/StageManagement/CreateStageDialog.tsx:42
- This CTA now gets
bg-accent, butButton's default variant still suppliestext-primary-foreground; notext-accent-foregroundis applied. That is near-white today, but the identity flip changes the dark-theme accent to lime with darkaccent-foregroundwhile the global primary foreground remains light, making the label fail the intended contrast. Add the paired accent foreground role to this CTA.
<Button className="bg-accent hover:bg-purple-700">
src/routes/admin.tsx:89
- Applying the
.edition-viewscope to the entire admin tree also overrides shared variables such as--muted-foreground(purple-200),--border(purple-400/30), and--ringfor existing shadcn components. Most admin cards still use the default whitebg-card, while many labels and empty states still usetext-muted-foreground(for exampleBulkEditorFooter), so they now become light purple on white and card borders/focus rings change. This contradicts the claimed zero visual change; scope only fully migrated surfaces or update the remaining admin components/variables before applying this wrapper.
<EditionViewRoot>
src/routes/admin/festivals/$festivalSlug/editions/$editionSlug/sets.tsx:95
- This CTA now gets
bg-accent, butButton's default variant still suppliestext-primary-foreground; notext-accent-foregroundis applied. That is near-white today, but the identity flip changes the dark-theme accent to lime with darkaccent-foregroundwhile the global primary foreground remains light, making the label fail the intended contrast. Add the paired accent foreground role to this CTA.
className="bg-accent hover:bg-purple-700"
- Files reviewed: 10/10 changed files
- Comments generated: 9
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Playwright test resultsDetails
|
…t states Per review feedback: moves the edition-view role tokens from the .edition-view scope class onto :root so the whole app shares one set of values instead of admin (or any other unmigrated surface) keeping stale shadcn defaults for the same variable names — this also fixes Radix portal content never seeing the override, since :root is the ultimate ancestor of a portal too. Adds a real accent-hover token (purple-700) so CTAs stop mixing a token fill with a literal hover color, pairs every bg-accent use with text-accent-foreground, and migrates the remaining non-portal literals flagged in review (analytics.tsx borders via border-foreground/NN, LinkWizardTable via bg-accent/20) instead of leaving them hardcoded.
There was a problem hiding this comment.
🟡 Changes recommended
Three moderate findings remain regarding token scope, theme selector alignment, and archive hover color.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
Suppressed comments (2)
docs/design/edition-color-vocabulary.md:12
- This new global-token contract conflicts with the canonical identity spec:
docs/design/edition-identity-spec.md:5still limits the identity to voter-facing edition views and explicitly keeps admin, groups/settings, landing, and auth on the old skin, while this line makes the same roles app-global. Update the canonical spec and the zero-change scope together with the implementation, or retain the scoped model.
- **The tokens live on `:root`, not a scope class (#367).** They used to sit under a `.edition-view` class so only voter-facing pages picked them up, but that meant every other surface (admin included) kept the old shadcn light-theme defaults for the same variable names — so a partial migration elsewhere (like admin's) recolored whatever hadn't been touched yet, and Radix portal content (which renders under `document.body`, outside any wrapper's scope) never picked up the override at all. The whole app renders on the same dark identity today, so there's one set of values for the whole app and no scope class to remember. `EditionViewRoot` still supplies the `bg-app-gradient` ground and is where the flip (#359) will attach `data-edition-theme="light"`.
src/index.css:32
- Changing
--accentat:rootalso recolors generic shadcn controls outside the migrated surfaces:Buttonoutline/ghost variants and/terms's ghost back button usehover:bg-accent, which was neutral under the old global value but is now purple. The identity spec still says landing/auth/groups/settings keep the old skin, so this violates the zero-visual-change claim and mixes the edition role with the old global meaning. Keep a separate scope/token or update those consumers and the contract before globalizing it.
--accent: 271.5 81.3% 55.9%; /* purple-600 */
- Files reviewed: 15/15 changed files
- Comments generated: 3
- Review effort level: Lite
EditionViewRoot's only remaining job was bg-app-gradient — the role tokens live on :root now, so admin doesn't need the wrapper. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01546kmFCrpafJ2ykLQKjYvb
There was a problem hiding this comment.
🟡 Changes recommended
Two unresolved moderate issues in src/index.css affect dialog contrast and future theme selection.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
Suppressed comments (6)
Previously missed (2) — in code that hasn't changed since the last review.
src/index.css:10
- Moving
--foregroundto:rootmakes it white for every portal, butDialogContentandAlertDialogContentstill renderbg-background, whose root value remains white (src/components/ui/dialog.tsx:39). Their inherited titles/body text can therefore become white on white, so this is not a zero-visual-change migration for dialogs. Keep these overrides scoped or give the shared portal primitives an explicitly compatible foreground/background before globalizing the tokens.
--foreground: 0 0% 100%; /* text-white */
src/index.css:118
EditionViewRootrenders the futuredata-edition-themeattribute on its wrapper<div>, but:root[...]matches only the document root (<html>). When #359 adds the attribute toEditionViewRootas documented inEditionViewRoot.tsx:7, this block will never match and the light palette will not apply. Keep the selector on.edition-viewor move the attribute todocument.documentElementconsistently.
:root[data-edition-theme="light"] {
src/index.css:33
--accent-foregroundis pure white, but these five migrated Add/Create buttons did not previously usetext-white;Button's default variant suppliedtext-primary-foreground(210 40% 98%). Addingtext-accent-foregroundtherefore changes their label color instead of preserving it, contrary to the zero-visual-change claim. Keeptext-primary-foregroundat these call sites or choose a token with the former value.
--accent-foreground: 0 0% 100%;
src/index.css:16
- These
popovervalues now apply to every Radix popover/dropdown portal because those contents render underdocument.bodyand consumebg-popover text-popover-foreground(for examplesrc/components/ui/popover.tsx:14-20). Before this change the global values were white/dark; they are now gray-800/purple-100, so portal content changes visually despite the PR's stated portal exception and zero-visual-change goal. Keep the edition values scoped or explicitly opt only the intended portals into them.
--popover: 215 27.9% 16.9%; /* gray-800 */
--popover-foreground: 268.7 100% 95.5%; /* purple-100 */
src/pages/admin/ArtistsManagement/ArchiveArtistDialog.tsx:52
text-destructive-foregroundis not equivalent to the replacedtext-white:--destructive-foregroundis210 40% 98%(#f1f5f9), while the old class is pure white. This changes the hover text color and breaks the stated zero-visual-change guarantee; use a token whose current value is white or deliberately update the destructive foreground token.
className="border-red-400 text-red-400 hover:bg-red-400 hover:text-destructive-foreground"
src/routes/admin.tsx:80
- The PR description says the admin layout is scoped with
EditionViewRoot, but both the loading branch and the main branch in this file still return plaindivroots (the main one is at lines 88-89). That means admin will not receive theedition-viewroot where the planneddata-edition-thememarker is attached, so the future theme flip will skip this surface. Wrap both branches withEditionViewRootor apply the same scope/data-theme contract directly.
<div className="text-foreground text-xl">Loading...</div>
- Files reviewed: 15/15 changed files
- Comments generated: 1
- Review effort level: Lite
…:root token migration The AuthDialog, toast notifications, and admin Artists table (Bulk Editor and generic Table primitives) render on white backgrounds but were picking up the dark edition-view identity's now-global muted-foreground/ foreground values, washing out text, placeholders, and the input focus ring. Add explicit gray/black overrides at these light-surface call sites and shared table defaults, without reverting the :root migration. Also removes the now-vestigial EditionViewRoot wrapper (it had shrunk to a single div once its token-scoping job moved to :root) and the stale CSS comment block in index.css.
There was a problem hiding this comment.
🟡 Changes recommended
Global token changes cause critical light-surface styling regressions, with additional tokenization and documentation issues unresolved.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
Suppressed comments (8)
Previously missed (1) — in code that hasn't changed since the last review.
src/index.css:32
- The root token migration still leaves
src/pages/admin/festivals/FestivalLogoDialog.tsx:178onbg-purple-600 hover:bg-purple-700, so the admin Upload Logo CTA is not tokenized and will diverge when--accent/--accent-hoverchanges. Migrate this remaining admin CTA as well to satisfy the stated admin color-site scope.
--accent: 271.5 81.3% 55.9%; /* purple-600 */
src/components/ui/table.tsx:76
- These shared table primitives are being changed from the semantic
text-muted-foreground(and inherited cell text) to fixedtext-gray-*colors. That bypasses the role tokens introduced here, so table headers/captions/cells will ignore the planned theme flip; the admin-specific neutral override should be applied at the call site instead of changing the shared primitive.
"h-12 px-4 text-left align-middle font-medium text-gray-500 [&:has([role=checkbox])]:pr-0",
src/components/ui/toaster.tsx:18
- This only changes the toast root's inherited text color, but
ToastClosestill explicitly usestext-foreground/50andhover:text-foreground(src/components/ui/toast.tsx:78). With the new global foreground set to white and the default toast background stillbg-background(white), the close control remains white on white and is effectively invisible. Make the close control use the toast's default text color while preserving destructive-toast styling.
<Toast key={id} className="text-gray-900" {...props}>
src/components/ui/toaster.tsx:24
- These overrides are unconditional, so they replace the variant colors on destructive toasts. For example,
useAddAdminMutationemitsvariant: "destructive";text-gray-900then overridestext-destructive-foreground, and the description'stext-gray-500overrides the inherited destructive color, producing dark text on the red toast. Apply the gray overrides only for the default variant and leave destructive toasts on their variant colors.
<Toast key={id} className="text-gray-900" {...props}>
<div className="grid gap-1">
{title && <ToastTitle>{title}</ToastTitle>}
{description && (
<ToastDescription className="text-gray-500">
{description}
</ToastDescription>
src/index.css:25
- Making
--muted-foregroundpurple-200 global also recolors unchanged admin helper and empty-state text on white cards. For example,FestivalManagementTableandStagesTablestill usetext-muted-foreground, so their messages become low-contrast purple on white instead of the previous neutral value. Keep the edition value scoped or provide a light-surface/admin override before globalizing it.
--muted-foreground: 268.6 100% 91.8%; /* purple-200 */
src/index.css:40
- Moving
--borderfrom the old light value to:rootrecolors every genericborder-borderconsumer, not only the migrated admin literals.Cardalways renders a border, and admin cards such asFestivalManagementSectionuse<Card>without a border override, so their outlines change from the previous gray to purple-400/30, contradicting the claimed zero visual change. Keep the role override scoped or preserve the default border outside the intended surfaces.
--border: 270 95.2% 75.3% / 0.3; /* border-purple-400/30 */
src/index.css:32
--accentis also moved to:rootwith purple-600, but the sharedButtonprimitive's outline and ghost variants usehover:bg-accent/hover:text-accent-foreground(src/components/ui/button.tsx:16-19). Every unconverted admin action button therefore changes from the old neutral hover to purple—for example the table's ghost edit/delete buttons—so this is not zero visual change. Keep this token scoped or update those variants/surfaces as part of the migration.
--accent: 271.5 81.3% 55.9%; /* purple-600 */
src/pages/admin/ArtistsManagement/ArchiveArtistDialog.tsx:52
- This replacement is not value-equivalent to the old
hover:text-white:--destructive-foregroundstill resolves to210 40% 98%(slate-50, approximately#f8fafc), not0 0% 100%. Either set the role's foreground value to white for this palette or retain the original class if zero visual change is required.
className="border-red-400 text-red-400 hover:bg-red-400 hover:text-destructive-foreground"
- Files reviewed: 24/24 changed files
- Comments generated: 2
- Review effort level: Lite
…l grays Introduces surface-foreground/surface-muted-foreground/surface-border tokens for white-background surfaces (dialogs, toasts, admin tables), replacing the hardcoded gray-900/gray-500/gray-300 classes.
There was a problem hiding this comment.
🔵 Needs a closer look
Two moderate findings remain involving table borders and low-contrast muted text on white surfaces.
Review details
Suppressed comments (5)
Previously missed (2) — in code that hasn't changed since the last review.
src/components/ui/table.tsx:76
- This updates table text but leaves the table border path on the generic global
--bordertoken:TableRowstill supplies onlyborder-b, and the base layer appliesborder-border. With the new root value this makes the white admin tables use the purple identity border instead of the newly introducedpaper-border; the other admin tables do not have the analytics-specific border overrides. Apply the paper border to the shared admin table styling (or to each white table surface).
"h-12 px-4 text-left align-middle font-medium text-paper-muted-foreground [&:has([role=checkbox])]:pr-0",
src/index.css:25
- Making
--muted-foregroundthe edition purple-200 value globally leaves unchanged descriptions and placeholders on white paper surfaces with very low contrast. For example, admin dialog helper text andTextareaplaceholders still usetext-muted-foreground(FestivalDialog.tsx:196,SetFormDialog.tsx:299), whileCardDescriptionretains the same default. Migrate those light-surface consumers topaper-muted-foregroundor keep the edition value scoped.
--muted-foreground: 268.6 100% 91.8%; /* purple-200 */
src/components/ui/dialog.tsx:39
- Although
DialogContentnow establishes a paper foreground, the sharedTextareastill setsplaceholder:text-muted-foreground(src/components/ui/textarea.tsx:12). Multiline fields in the admin/group dialogs therefore show pale purple placeholder text on the white dialog;Inputwas updated butTextareawas not. Give the textarea a paper placeholder token for these white surfaces.
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border border-paper-border bg-paper-background p-6 text-paper-foreground shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
src/components/ui/toast.tsx:30
- The root renders both the Radix
Toasterand the Sonner toaster, anduseToastuses this Radix variant. Its default still uses the genericborder bg-background, so it does not receive the new neutralpaper-border/paper-backgroundroles (and currently keeps the global purple border). Use the paper roles here as well.
default: "border bg-background text-paper-foreground",
src/index.css:10
- Moving
--foregroundto:rootmakes every remainingbg-backgroundsurface inherit white text while--backgroundis still white. This leaves existing light UI such as the defaultAlert(bg-background text-foreground),AlertDialogContent/outline cancel, outline badges in admin tables, and the Radix toast close control (text-foreground/50) effectively white-on-white; the legal routes also inherit this body color overfrom-background. Migrate these consumers to the paper roles or retain a light-surface override before applying the edition foreground globally.
--foreground: 0 0% 100%; /* text-white */
- Files reviewed: 29/29 changed files
- Comments generated: 0 new
- Review effort level: Lite
DialogTitle/DialogDescription in AuthDialog and the Input override in EmailStep duplicated styling the Dialog/Input primitives already apply. Also drops the stale "(new)" marker from the accent-hover doc row. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01546kmFCrpafJ2ykLQKjYvb
There was a problem hiding this comment.
🟡 Changes recommended
Four moderate styling issues remain in input focus, table borders, muted text contrast, and Link Wizard badges.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
Suppressed comments (6)
Previously missed (2) — in code that hasn't changed since the last review.
src/components/ui/table.tsx:76
- The new
paper-bordertoken is not used by this shared table.TableHeader/TableRowstill derive their borders from globalborder-border, andBulkEditorTablewraps the table withborder, so white admin tables retain the translucent purple--borderrather than the neutral paper border introduced for admin tables. Apply the paper border to the white-table wrapper/rows while preserving the explicit identity borders in analytics.
"h-12 px-4 text-left align-middle font-medium text-paper-muted-foreground [&:has([role=checkbox])]:pr-0",
src/pages/admin/festivals/LinkWizard/LinkWizardTable.tsx:60
- The selected-row token change does not account for the outline badges rendered in this same white admin table.
Badge's outline variant still setstext-foreground, which is now globally white, so the Spotify and SoundCloud labels below render white-on-white and disappear. Give these badges the paper foreground (or provide a white-table-specific outline variant).
className={cn(artist.id === currentArtistId && "bg-accent/20")}
src/components/ui/toast.tsx:30
- The Radix toast is one of the white chrome surfaces described by this PR, but its default variant still uses
bg-backgroundand the globalborder. Under the new identity those roles are not the paper background/border, so the toast only happens to be white today and retains the purple identity border. Use the paper background and border here, as the Sonner wrapper already does.
default: "border bg-background text-paper-foreground",
src/components/ui/toast.tsx:30
- Changing the default toast text to paper colors leaves
ToastClosebelow ontext-foreground/50andhover:text-foreground. With the root foreground white and the default white toast, the close icon is white-on-white when hover or focus reveals it, so the dismiss control is not perceivable. Switch the default close colors to paper foreground while preserving the destructive overrides.
default: "border bg-background text-paper-foreground",
src/index.css:10
--foregroundis now white globally while--backgroundremains white, but several light-surface primitives still consume these global roles. For example, the defaultAlert/AlertDialogContentusebg-backgroundwithtext-foregroundor inherited title text, and the default activeTabsTriggeruses the same pair; admin schedule-import alerts/confirmations andImageEditDialogtabs therefore become white-on-white. The root-level legal pages andAppFooterhave the same base mismatch. Migrate the remaining light surfaces to the paper roles before making this identity global.
--foreground: 0 0% 100%; /* text-white */
src/index.css:45
- The new global accent roles are used by the other admin primary actions in this PR, but
FestivalLogoDialogstill usesbg-purple-600 hover:bg-purple-700for Upload Logo. Once the accent role changes (the purpose of this migration/theme flip), that admin CTA will be the remaining hardcoded color and diverge from the rest; migrate it tobg-accent text-accent-foreground hover:bg-accent-hover.
--accent: 271.5 81.3% 55.9%; /* purple-600 */
- Files reviewed: 27/27 changed files
- Comments generated: 2
- Review effort level: Lite
Badge outline variant and the Link Wizard's stage/time/co-performer text used text-foreground/muted-foreground, which are now white/pale-purple globally and invisible against the white/slate-50 admin chrome. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01546kmFCrpafJ2ykLQKjYvb
…text Login email input inherited the purple edition ring; CardDescription and Textarea inherited the light-purple muted-foreground on white surfaces. Add a paper-ring token and use paper-muted-foreground for both. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01546kmFCrpafJ2ykLQKjYvb
Consistent with the paper-* token pairing already used for the toast/dialog foreground and border on light chrome. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01546kmFCrpafJ2ykLQKjYvb
There was a problem hiding this comment.
🟡 Changes recommended
Unresolved findings include a critical white-on-white alert/dialog regression and moderate input ring, toast close-button, and badge test issues.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
Suppressed comments (4)
src/components/ui/table.tsx:76
- The paper migration only changes table text;
TableRowstill has a bareborder-b, which resolves through the global purple--border. Since the default table consumers are admin tables and several sit on white cards, their separators remain purple-alpha instead of using the new neutral--paper-borderrole. Apply a paper border for white tables (or expose a light-table variant), while retaining the explicit dark row colors used by analytics.
"h-12 px-4 text-left align-middle font-medium text-paper-muted-foreground [&:has([role=checkbox])]:pr-0",
src/index.css:25
- This makes the light purple
muted-foregroundvalue global, but several white-surface consumers still use it directly:CardDescriptioninsrc/routes/admin/admins.tsx, remaining admin descriptions,Textareaplaceholders, andMultiSelectplaceholders (the cookie banner is another global example). Those now render near-white text on white surfaces because only a subset of primitives was migrated topaper-muted-foreground. Migrate all white-surface consumers to the paper role, or keep the identity value scoped.
--muted-foreground: 268.6 100% 91.8%; /* purple-200 */
src/index.css:47
- The new
accent/accent-hoverroles are used by the other migrated admin CTAs, but the upload action inFestivalLogoDialogstill hardcodesbg-purple-600 hover:bg-purple-700(src/pages/admin/festivals/FestivalLogoDialog.tsx:175-179). That admin action will diverge from the role-token palette as soon as the accent changes; migrate it tobg-accent text-accent-foreground hover:bg-accent-hover.
--accent: 271.5 81.3% 55.9%; /* purple-600 */
--accent-foreground: 0 0% 100%;
tailwind.config.ts:84
- The new
accent-hoverrole is used for the other migrated admin CTAs, butsrc/pages/admin/festivals/FestivalLogoDialog.tsx:178still usesbg-purple-600 hover:bg-purple-700. That button will bypass the shared accent token and will not follow the same palette/theme behavior as the surrounding admin actions. Migrate this remaining admin CTA to the accent roles as well.
- Files reviewed: 34/34 changed files
- Comments generated: 4
- Review effort level: Lite
There was a problem hiding this comment.
🟡 Changes recommended
Four unresolved light-surface readability and focus-state issues remain.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
Suppressed comments (6)
src/components/ui/table.tsx:76
- The table migration changes cell text but leaves
TableRowbelow with onlyborder-b. Since the global* { @apply border-border; }now resolves to the purple translucent identity border, ordinary admin table separators remain purple on the white table instead of using the newpaper-borderrole. Add the paper border to the row base (and handle the white table wrapper borders consistently).
"h-12 px-4 text-left align-middle font-medium text-paper-muted-foreground [&:has([role=checkbox])]:pr-0",
src/components/ui/textarea.tsx:12
- Unlike
Input, this change only recolors the placeholder; the textarea value still inherits globaltext-foreground(white). A standalone admin editor such asFestivalInfoFieldrenders this control inEditContainerwith a lightbg-muted/50, so entered descriptions are white on a light background. Give the shared textarea an explicit paper foreground for its value.
"flex min-h-[80px] w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-paper-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
src/components/ui/toast.tsx:30
- The default Radix toast now uses a paper background but still has only a bare
border. Becausesrc/index.cssappliesborder-borderglobally and--borderis now the translucent purple identity border, these white toasts retain a purple border instead of the new neutralpaper-borderrole. Addborder-paper-borderto this variant.
default: "border bg-paper-background text-paper-foreground",
src/index.css:10
- Making
--foregroundwhite at:rootalso affects the unchanged defaultAlertandAlertDialogprimitives.Alertstill rendersbg-background text-foreground(white on white), while portalledAlertDialogContenthas a whitebg-background, titles that inherit the white body color, and descriptions using the pale global--muted-foreground; the admin import warnings and confirmation dialogs are therefore unreadable. Update those primitives to thepaper-*roles before making this palette global.
--foreground: 0 0% 100%; /* text-white */
src/index.css:25
- Changing
--muted-foregroundto the purple-200 identity value globally leaves explicit admin uses on white surfaces with very low contrast. For example,BulkEditorTableRowstill renders its created-at cell withtext-muted-foreground(src/pages/admin/ArtistsManagement/components/BulkEditorTableRow.tsx:89), which overrides the new paper color on the white artists table; the table empty states have the same problem. Replace these white-surface admin overrides withtext-paper-muted-foregroundrather than relying on the global muted role.
--muted-foreground: 268.6 100% 91.8%; /* purple-200 */
src/index.css:54
- Although
--paper-borderis introduced above, the admin table shells andTableHeader/TableRowstill use genericborder/border-b. After this global change those resolve to--border(purple-400/30), so white admin tables continue to use the dark-identity border instead of the neutral paper border intended by this migration. Update the shared table and white-surface border classes toborder-paper-border.
--border: 270 95.2% 75.3% / 0.3; /* border-purple-400/30 */
- Files reviewed: 36/36 changed files
- Comments generated: 4
- Review effort level: Lite
| <textarea | ||
| className={cn( | ||
| "flex min-h-[80px] w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50", | ||
| "flex min-h-[80px] w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-paper-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50", |
| variants: { | ||
| variant: { | ||
| default: "border bg-background text-foreground", | ||
| default: "border bg-paper-background text-paper-foreground", |
| :root { | ||
| --background: 0 0% 100%; | ||
| --foreground: 222.2 84% 4.9%; | ||
| --foreground: 0 0% 100%; /* text-white */ |
| <MarkdownText content={value} className="prose-sm" /> | ||
| ) : ( | ||
| <span className="text-muted-foreground italic"> | ||
| <span className="text-paper-muted-foreground italic"> |
There was a problem hiding this comment.
🟡 Changes recommended
Four unresolved moderate border-token issues remain in paper-surface components.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
Suppressed comments (7)
Previously missed (1) — in code that hasn't changed since the last review.
src/components/ui/table.tsx:76
- The new
paper-bordertoken is not applied to the table's own borders.TableRowstill emits bareborder-b, and the admin table wrappers still emit bareborder, so white tables continue to use the global translucent purple--borderinstead of the neutral paper border. Apply the paper border to the shared row/outer-table styles while preserving analytics' explicit white hairlines.
"h-12 px-4 text-left align-middle font-medium text-paper-muted-foreground [&:has([role=checkbox])]:pr-0",
docs/design/edition-identity-spec.md:15
- The scope/token contract now says the document root is the integration point, and this PR deletes the only
EditionViewRoot/.edition-viewwrapper, but the implementation notes below still require font families to be wired at anedition-viewroot. There is no such source element left, so that instruction is stale and will misdirect the typography follow-up; update it to the actual route/document-root hook or retain a wrapper.
- Token values are CSS variables on `:root` (#367). Dark values are the default; light values apply under an explicit `data-edition-theme="light"` attribute on the document root.
src/components/ui/sonner.tsx:17
- The default Sonner toast is now white, but its cancel button still uses
text-muted-foreground. With the new global value, a cancel action is rendered in purple-200 on the lightbg-mutedfill, leaving it low-contrast even though the toast title and description were migrated to paper roles. Keep the fill if desired, but switch the cancel text totext-paper-foreground(or another paper-compatible foreground).
"group toast group-[.toaster]:bg-paper-background group-[.toaster]:text-paper-foreground group-[.toaster]:border-paper-border group-[.toaster]:shadow-lg",
description: "group-[.toast]:text-paper-muted-foreground",
src/components/ui/textarea.tsx:12
- Although
Inputnow usesring-paper,Textareastill uses the globalring-ring. Focusing a textarea in an admin white card/dialog therefore shows the purple identity ring instead of the neutral paper treatment this PR introduces for white inputs. Usefocus-visible:ring-paper-ringhere.
"flex min-h-[80px] w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-paper-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
src/index.css:10
- Making
--foregroundwhite globally also changesbody(which appliesbg-background text-foreground) and existingtext-foregroundconsumers outside the dark-gradient surfaces. For example,/privacy,/terms, and/cookiesstill use a whitebg-background, whileDeleteGroupDialogexplicitly usestext-foregroundon its white dialog, so these become white-on-white. Migrate those white-surface consumers to thepaper-*roles before globalizing this token, or keep the identity scope until they are migrated.
--foreground: 0 0% 100%; /* text-white */
src/index.css:25
- Globalizing
--muted-foregroundto the purple-200 identity value leaves ordinarytext-muted-foregroundcontent on white surfaces with very low contrast. For example,LinkWizardStep/CandidateCardrender inside the default whiteCard, andCookiePreferencesDialoghas whiteDialogContent, but those consumers still use this role. Migrate all white-surface muted text totext-paper-muted-foreground(or provide a scoped paper role) rather than leaving these admin/auth surfaces on the purple value.
--muted-foreground: 268.6 100% 91.8%; /* purple-200 */
src/pages/admin/ArtistsManagement/BulkEditor/TextareaCell.tsx:77
- When
valueis present this branch rendersMarkdownText, whose prose paragraphs/headings usetext-foreground; after the root foreground was changed to white, populated descriptions in the white Artists table render white-on-white. The placeholder change only fixes empty cells; give this admin rendering paper-foreground prose styles without changing the dark EditionView MarkdownText defaults.
<span className="text-paper-muted-foreground italic">
- Files reviewed: 36/36 changed files
- Comments generated: 3
- Review effort level: Lite
| ref={ref} | ||
| className={cn( | ||
| "fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg", | ||
| "fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-paper-background text-paper-foreground p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg", |
| variants: { | ||
| variant: { | ||
| default: "bg-background text-foreground", | ||
| default: "bg-paper-background text-paper-foreground", |
| variants: { | ||
| variant: { | ||
| default: "border bg-background text-foreground", | ||
| default: "border bg-paper-background text-paper-foreground", |
Moves role-token CSS variables from
.edition-viewscope onto global:rootso the whole app shares one token set, instead of admin/portal surfaces silently keeping old shadcn light-theme defaults for the same variable names.Introduces
paper-background/paper-foreground/paper-muted-foreground/paper-bordertokens for white-background surfaces (dialogs, toasts, admin tables, inputs, OTP) so they no longer inherit the dark-identitybackground/foreground/muted-foreground/ringvalues. Namedpaper-*rather thansurface-*to avoid colliding with the existingsurface/surface-raised/surface-activetranslucent overlay tokens.Verification
EditionViewpages still render the dark purple identity unchanged.