feat(ui): add Alert, DropdownMenu, Tooltip primitives and ThemeProvider with dark mode toggle - #141
Merged
Conversation
…oggle Adds the shared UI primitives that table row actions, topbar menus, and truncated-address displays need, plus the user-facing theme switch. Alert (ShadeProtocol#90) - src/components/ui/alert.tsx with Alert, AlertTitle, AlertDescription - default and destructive variants via cva, matching button.tsx conventions - destructive variant reproduces the hand-written error box classes exactly, so refactoring both auth screens carries no visual change - AlertDescription adds no line-height of its own to preserve text-sm leading - register-client.tsx and sign-in-client.tsx now use Alert, keeping their mt-5 / mb-4 spacing via className DropdownMenu (ShadeProtocol#92) - src/components/ui/dropdown-menu.tsx on @radix-ui/react-dropdown-menu - DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuLabel - portalled content with popover tokens and tw-animate-css transitions Tooltip (ShadeProtocol#96) - src/components/ui/tooltip.tsx on @radix-ui/react-tooltip (new dependency) - TooltipProvider defaults to a 200ms delay and is mounted once in the root layout so any subtree can use tooltips Theme toggle (ShadeProtocol#104) - src/components/theme-provider.tsx re-exports the existing ThemeProvider at the path the issue specifies; a second provider would fork theme state - src/components/ui/theme-toggle.tsx toggles via useTheme with Sun/Moon icons and an aria-label that tracks the current mode Tests: 16 new cases covering the acceptance criteria - menu anchoring, Escape and outside-click dismissal, onSelect firing, tooltip on hover and keyboard focus, dark class toggling, and localStorage persistence across remount.
|
@0xDeon Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds the three missing shared UI primitives (
Alert,DropdownMenu,Tooltip) and the user-facing dark mode toggle.Issues
Closes #90
Closes #92
Closes #96
Closes #104
Alert— #90src/components/ui/alert.tsxexportsAlert,AlertTitle, andAlertDescription, withdefaultanddestructivevariants viacva, following the existingbutton.tsxconventions (forwardRef,data-slot,cn).No visual regression. The
destructivevariant reproduces the hand-written classes exactly:Two details worth flagging for review:
AlertDescriptiondeliberately sets no line-height. An earlier draft appliedleading-6, which would have silently changed the error text from 20px to 24px leading attext-sm— a real regression on multi-line errors.mt-5in register,mb-4in sign-in) are passed throughclassNamerather than baked into the variant, so both screens keep their original layout.Refactored:
src/app/register/register-client.tsxsrc/app/sign-in/sign-in-client.tsxDropdownMenu— #92src/components/ui/dropdown-menu.tsxbuilt on@radix-ui/react-dropdown-menu(already a dependency, no install needed).Exports
DropdownMenu,DropdownMenuTrigger,DropdownMenuContent,DropdownMenuItem,DropdownMenuSeparator, andDropdownMenuLabel. Content is portalled, themed with thepopovertokens, and animated with thetw-animate-cssclasses already imported inglobals.css.Tooltip— #96src/components/ui/tooltip.tsxbuilt on@radix-ui/react-tooltip— the one new dependency in this PR.TooltipProviderwraps a 200ms default delay and is mounted once insrc/app/layout.tsx, insideThemeProvider, so any subtree can use tooltips without its own provider.Theme toggle — #104
The repo already had a working
ThemeProvideratsrc/components/ThemeProvider.tsx, mounted in the root layout — it toggles.darkand persists tolocalStorageundershade:theme. What was missing was the toggle button.src/components/theme-provider.tsx— re-exports the existing provider at the path the issue specifies. Defining a second provider here would fork theme state into two independent copies, so this re-exports instead. The root layout now imports from this path.src/components/ui/theme-toggle.tsx—ThemeTogglebutton usinglucide-react'sSun/Moon, with anaria-labelthat tracks the current mode.Note:
lucide-reactis path-mapped intsconfig.jsonto the local shim atsrc/lib/lucide-react.tsx; bothSunandMoonalready exist there, so no shim additions were needed.Tests
16 new cases across 4 files, written against the acceptance criteria:
alert.test.tsxalertrole, variant classes match the original error box, callerclassNamepreserveddropdown-menu.test.tsxaria-controls/aria-expanded), closes on Escape, closes on outside click,onSelectfirestooltip.test.tsxtheme-toggle.test.tsx.darkinstantly, persists tolocalStorage, restores across remount (reload), a11y labelsThe outside-click test dispatches
pointerDown/mouseDowndirectly rather than usinguser.click. Radix setspointer-events: noneon the body while an open menu traps interaction, whichuser-eventrefuses to click through; the dispatched sequence is what Radix actually listens for. This is commented inline.Verification
tsc --noEmitnext build✓ Compiled successfullyTwo pre-existing failures, confirmed not from this PR
Both were reproduced on a clean
upstream/mainwith this branch's changes stashed:next buildfails at its lint gate on 4 errors in files this PR does not touch —src/app/payment/[id]/page.tsx,src/components/invoices/InvoiceRowActions.test.tsx,src/components/profile/ProfileDetailsForm.test.tsx,src/components/ui/api-key-reveal.tsx. Compilation itself succeeds. Baseline produces the identical 4 errors.billing-plan-form.test.tsxtimes out at 5000ms under full-suite parallel load. It passes when run alone, both with and without this branch's changes, and fails on baseline under the full suite. Looks like a timeout that needs raising, unrelated to this work.Left both alone as out of scope — happy to fix in a follow-up if you'd like them bundled.