-
Notifications
You must be signed in to change notification settings - Fork 3
Feature : add dark mode #105
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
WalkthroughThis update standardizes the application's visual styling to use semantic, theme-based color tokens instead of hardcoded color values. It introduces a global theme provider for dark/light mode support, adds a theme toggle component, and updates numerous UI components to use design system tokens for colors, backgrounds, and borders. No logic or control flow is altered. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant App
participant ThemeProvider
participant ModeToggle
User->>App: Loads application
App->>ThemeProvider: Wraps UI in ThemeProvider
ThemeProvider-->>App: Provides theme context (dark/light)
App->>ModeToggle: Renders theme toggle button
User->>ModeToggle: Clicks toggle
ModeToggle->>ThemeProvider: Updates theme (dark/light)
ThemeProvider-->>App: Updates theme context
App-->>User: Rerenders UI with new theme tokens
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Suggested reviewers
Note 🔌 MCP (Model Context Protocol) integration is now available in Early Access!Pro users can now connect to remote MCP servers under the Integrations page to get reviews and chat conversations that understand additional development context. 📜 Recent review detailsConfiguration used: CodeRabbit UI ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (36)
✅ Files skipped from review due to trivial changes (12)
🚧 Files skipped from review as they are similar to previous changes (24)
✨ Finishing Touches
🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
Hello @mayur1377, thank you for submitting your first pull request to the easy-invoice repository. We value your contribution and encourage you to review our contribution guidelines to ensure your submission meets our standards. Please note that every merged PR is automatically enrolled in our Best PR Initiative, offering a chance to win $500 each quarter. Our team is available via GitHub Discussions or Discord if you have any questions. Welcome aboard! |
Thank you for your submission! As you prepare for the review process, please ensure that your PR title, description, and any linked issues fully comply with our contribution guidelines. A clear explanation of your changes and their context will help expedite the review process. Every merged PR is automatically entered into our Best PR Initiative, offering a chance to win $500 every quarter. We appreciate your attention to detail and look forward to reviewing your contribution! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (7)
src/components/short-address.tsx (1)
25-30
: Improve accessibility with an explicit labelScreen-reader users cannot rely on the visual tooltip; add an
aria-label
so the button’s purpose is announced even without hover/focus.- <button - type="button" - onClick={handleCopy} - className={`text-muted-foreground hover:text-foreground transition-colors flex items-center gap-2 ${className}`} + <button + type="button" + aria-label="Copy address to clipboard" + onClick={handleCopy} + className={`text-muted-foreground hover:text-foreground transition-colors flex items-center gap-2 ${className}`}src/components/subscription-plans/blocks/create-subscription-plan.tsx (1)
281-289
: Minor UX nit – keep disabled state truly muted
WhenisLoading
is true the button is disabled, yet thehover:text-foreground
class still applies and can visually “brighten” the label on hover (HTML disables click events, but the hover style still triggers).
Consider guarding the hover style so it does not activate while disabled:-className="flex items-center text-sm text-muted-foreground hover:text-foreground transition-colors" +className="flex items-center text-sm text-muted-foreground transition-colors + hover:text-foreground disabled:hover:text-muted-foreground"src/components/view-recurring-payments/blocks/status-badge.tsx (1)
7-11
: Inconsistent background opacity for “paused” badge
All other statuses use thecolor/10
translucent background pattern, butpaused
falls back tobg-muted
(opaque). For visual consistency you might want:- paused: "bg-muted text-muted-foreground border-border", + paused: "bg-muted/10 text-muted-foreground border-border",(if your tailwind config exposes a muted/10 token).
src/components/view-recurring-payments/view-recurring-payments.tsx (1)
82-85
: Prefer token without embedded opacity for destructive borders
border-destructive/30
mixes semantic token + hard-coded opacity. Consider a pure token (e.g.border-destructive
) and control transparency through CSS variables or the design-system’s.opacity-*
utilities to stay fully theme-driven.src/components/dashboard/invoices-sent.tsx (1)
95-98
: Use the Button’svariant
API instead of hard-coding colorsManually setting
bg-primary
,hover:bg-primary/80
, andtext-primary-foreground
bypasses the button component’s variant system and may diverge if the theme palette changes.-<Button className="bg-primary hover:bg-primary/80 text-primary-foreground"> +<Button variant="default">Keeps styling consistent and centralised.
src/components/payment-route.tsx (1)
129-133
: Replace hard-codedtext-purple-600
with a theme tokenThis is the last hard-coded colour in the component. Using something like
text-primary-foreground
(or a dedicated “brand” token) keeps dark-mode contrast predictable.-<span className="text-purple-600"> +<span className="text-primary-foreground">src/components/background-wrapper.tsx (1)
67-87
: Consider dark mode decorative elements.The decorative gradient elements are completely hidden in dark mode, which might make the dark theme feel visually empty compared to the light theme.
Consider adding subtle dark mode decoratives:
- {/* Decorative elements - only show in light mode */} - {!isDark && ( + {/* Decorative elements */} + {isDark ? ( + <> + <div className="absolute top-0 right-0 w-[600px] h-[600px] -translate-y-1/2 translate-x-1/2"> + <div + className="w-full h-full rounded-full opacity-10 blur-3xl" + style={{ + background: `linear-gradient(to bottom right, ${getTailwindColor("slate-800")}, ${getTailwindColor("slate-900")})`, + }} + /> + </div> + <div className="absolute bottom-0 left-0 w-[600px] h-[600px] translate-y-1/2 -translate-x-1/2"> + <div + className="w-full h-full rounded-full opacity-10 blur-3xl" + style={{ + background: `linear-gradient(to top right, ${getTailwindColor("zinc-800")}, ${getTailwindColor("zinc-900")})`, + }} + /> + </div> + </> + ) : ( <> <div className="absolute top-0 right-0 w-[600px] h-[600px] -translate-y-1/2 translate-x-1/2"> <div className="w-full h-full rounded-full opacity-30 blur-3xl" style={{ background: `linear-gradient(to bottom right, ${getTailwindColor(topGradient.from)}, ${getTailwindColor(topGradient.to)})`, }} /> </div> <div className="absolute bottom-0 left-0 w-[600px] h-[600px] translate-y-1/2 -translate-x-1/2"> <div className="w-full h-full rounded-full opacity-30 blur-3xl" style={{ background: `linear-gradient(to top right, ${getTailwindColor(bottomGradient.from)}, ${getTailwindColor(bottomGradient.to)})`, }} /> </div> </> - )} + )}
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
package-lock.json
is excluded by!**/package-lock.json
📒 Files selected for processing (38)
src/app/dashboard/layout.tsx
(2 hunks)src/app/i/[id]/page.tsx
(1 hunks)src/app/invoices/create/page.tsx
(1 hunks)src/app/layout.tsx
(2 hunks)src/components/background-wrapper.tsx
(3 hunks)src/components/batch-payout.tsx
(17 hunks)src/components/compliance-status.tsx
(1 hunks)src/components/create-recurring-payment/blocks/create-recurring-payment-form.tsx
(2 hunks)src/components/create-recurring-payment/create-recurring-payment.tsx
(5 hunks)src/components/dashboard/blocks/empty-state.tsx
(1 hunks)src/components/dashboard/blocks/invoice-row.tsx
(5 hunks)src/components/dashboard/blocks/pagination.tsx
(2 hunks)src/components/dashboard/blocks/stat-card.tsx
(1 hunks)src/components/dashboard/blocks/table-head-cell.tsx
(1 hunks)src/components/dashboard/invoices-received.tsx
(6 hunks)src/components/dashboard/invoices-sent.tsx
(2 hunks)src/components/dashboard/subscriptions.tsx
(4 hunks)src/components/direct-payout.tsx
(10 hunks)src/components/footer.tsx
(1 hunks)src/components/header.tsx
(4 hunks)src/components/invoice-form.tsx
(2 hunks)src/components/invoice-me-link.tsx
(1 hunks)src/components/invoice-me-links.tsx
(3 hunks)src/components/invoice-preview.tsx
(7 hunks)src/components/mode-toggle.tsx
(1 hunks)src/components/payment-route.tsx
(4 hunks)src/components/payment-section.tsx
(10 hunks)src/components/payment-secured-using-request.tsx
(1 hunks)src/components/short-address.tsx
(1 hunks)src/components/subscription-plan-preview.tsx
(5 hunks)src/components/subscription-plans/blocks/create-subscription-plan.tsx
(1 hunks)src/components/subscription-plans/blocks/subscription-plan-link.tsx
(3 hunks)src/components/subscription-plans/subscription-plans.tsx
(2 hunks)src/components/ui/tooltip.tsx
(1 hunks)src/components/view-recurring-payments/blocks/completed-payments.tsx
(1 hunks)src/components/view-recurring-payments/blocks/frequency-badge.tsx
(1 hunks)src/components/view-recurring-payments/blocks/status-badge.tsx
(1 hunks)src/components/view-recurring-payments/view-recurring-payments.tsx
(8 hunks)
🧰 Additional context used
🧠 Learnings (15)
📓 Common learnings
Learnt from: aimensahnoun
PR: RequestNetwork/easy-invoice#21
File: src/components/background-wrapper.tsx:31-31
Timestamp: 2025-02-20T10:26:33.809Z
Learning: Dynamic Tailwind class interpolation for gradient classes (from-${color} and to-${color}) in the BackgroundWrapper component is intentionally implemented this way and doesn't require a mapping object solution.
📚 Learning: dynamic tailwind class interpolation for gradient classes (from-${color} and to-${color}) in the bac...
Learnt from: aimensahnoun
PR: RequestNetwork/easy-invoice#21
File: src/components/background-wrapper.tsx:31-31
Timestamp: 2025-02-20T10:26:33.809Z
Learning: Dynamic Tailwind class interpolation for gradient classes (from-${color} and to-${color}) in the BackgroundWrapper component is intentionally implemented this way and doesn't require a mapping object solution.
Applied to files:
src/app/i/[id]/page.tsx
src/components/view-recurring-payments/blocks/status-badge.tsx
src/components/background-wrapper.tsx
📚 Learning: the `payrequest` function in the invoice router retrieves payment transactions calldata from the req...
Learnt from: aimensahnoun
PR: RequestNetwork/easy-invoice#2
File: src/server/routers/invoice.ts:0-0
Timestamp: 2025-02-12T13:04:46.135Z
Learning: The `payRequest` function in the invoice router retrieves payment transactions calldata from the Request API and does not process the payment itself. The actual payment status update happens through the webhook handler.
Applied to files:
src/components/payment-secured-using-request.tsx
📚 Learning: the handleformsubmit function in src/components/invoice-form.tsx correctly uses data.clientemail fro...
Learnt from: rodrigopavezi
PR: RequestNetwork/easy-invoice#45
File: src/components/invoice-form.tsx:316-319
Timestamp: 2025-05-19T13:00:48.790Z
Learning: The handleFormSubmit function in src/components/invoice-form.tsx correctly uses data.clientEmail from the form submission data to find matching payers, which is the proper implementation.
Applied to files:
src/app/dashboard/layout.tsx
src/components/create-recurring-payment/blocks/create-recurring-payment-form.tsx
src/components/payment-section.tsx
src/components/direct-payout.tsx
src/components/dashboard/invoices-sent.tsx
src/components/invoice-form.tsx
src/components/invoice-preview.tsx
src/components/dashboard/invoices-received.tsx
src/components/dashboard/blocks/invoice-row.tsx
📚 Learning: the appkit wallet module requires initialization time before it's ready for use. a 2-second delay is...
Learnt from: aimensahnoun
PR: RequestNetwork/easy-invoice#23
File: src/components/direct-payment.tsx:63-89
Timestamp: 2025-02-27T13:58:33.590Z
Learning: The AppKit wallet module requires initialization time before it's ready for use. A 2-second delay is intentionally used in the DirectPayment component to ensure the wallet is fully initialized before allowing interactions.
Applied to files:
src/components/subscription-plan-preview.tsx
src/components/create-recurring-payment/create-recurring-payment.tsx
src/components/direct-payout.tsx
src/components/batch-payout.tsx
📚 Learning: in src/components/batch-payout.tsx, the user prefers to keep the simple 2-second timeout for appkit ...
Learnt from: aimensahnoun
PR: RequestNetwork/easy-invoice#64
File: src/components/batch-payout.tsx:100-106
Timestamp: 2025-06-04T10:08:40.123Z
Learning: In src/components/batch-payout.tsx, the user prefers to keep the simple 2-second timeout for AppKit initialization over more complex polling mechanisms when the current approach is working adequately. They favor simplicity over potentially more robust but complex solutions.
Applied to files:
src/components/subscription-plan-preview.tsx
src/components/create-recurring-payment/create-recurring-payment.tsx
src/components/direct-payout.tsx
src/components/batch-payout.tsx
📚 Learning: the easy-invoice project prefers simpler, direct implementations over abstract utilities. for exampl...
Learnt from: aimensahnoun
PR: RequestNetwork/easy-invoice#21
File: src/app/invoices/[ID]/page.tsx:113-148
Timestamp: 2025-02-20T10:27:02.993Z
Learning: The easy-invoice project prefers simpler, direct implementations over abstract utilities. For example, using `.toFixed(2)` directly instead of creating separate number formatting utilities.
Applied to files:
src/components/payment-section.tsx
src/components/invoice-preview.tsx
src/components/dashboard/blocks/invoice-row.tsx
📚 Learning: in the requestnetwork/easy-invoice codebase, monetary amounts are stored as text in the database sch...
Learnt from: bassgeta
PR: RequestNetwork/easy-invoice#91
File: drizzle/0007_messy_silver_fox.sql:1-12
Timestamp: 2025-07-14T14:17:05.340Z
Learning: In the RequestNetwork/easy-invoice codebase, monetary amounts are stored as text in the database schema rather than numeric types. This is a deliberate architectural decision to maintain consistency across all amount fields in the system.
Applied to files:
src/components/payment-section.tsx
📚 Learning: in the paymentsection component of easyinvoice, selectedroute is automatically set to the first rout...
Learnt from: aimensahnoun
PR: RequestNetwork/easy-invoice#42
File: src/components/payment-section.tsx:534-544
Timestamp: 2025-03-25T09:31:47.519Z
Learning: In the PaymentSection component of EasyInvoice, selectedRoute is automatically set to the first route when payment routes are loaded, and users can only switch between routes, not deselect them entirely.
Applied to files:
src/components/payment-section.tsx
src/components/payment-route.tsx
src/components/batch-payout.tsx
📚 Learning: for the directpayment component, amount validation is already handled through zod schema validation ...
Learnt from: aimensahnoun
PR: RequestNetwork/easy-invoice#23
File: src/components/direct-payment.tsx:343-360
Timestamp: 2025-02-27T14:02:35.047Z
Learning: For the DirectPayment component, amount validation is already handled through Zod schema validation in paymentFormSchema, which ensures the amount is greater than zero.
Applied to files:
src/components/direct-payout.tsx
📚 Learning: in the easy invoice project, settimeout is required when submitting a form after modal state changes...
Learnt from: rodrigopavezi
PR: RequestNetwork/easy-invoice#45
File: src/components/invoice-form.tsx:451-453
Timestamp: 2025-05-20T12:59:44.665Z
Learning: In the Easy Invoice project, setTimeout is required when submitting a form after modal state changes in the crypto-to-fiat payment flow. Directly calling handleFormSubmit without setTimeout after closing modals and updating state causes issues.
Applied to files:
src/components/direct-payout.tsx
src/components/invoice-form.tsx
📚 Learning: for webhook handlers in the easy invoice project, unknown or unexpected substatus values in payment ...
Learnt from: MantisClone
PR: RequestNetwork/easy-invoice#59
File: src/app/api/webhook/route.ts:77-95
Timestamp: 2025-05-22T18:19:12.366Z
Learning: For webhook handlers in the Easy Invoice project, unknown or unexpected subStatus values in payment processing should be treated as errors (using console.error) rather than warnings, and should return a 422 Unprocessable Entity status code.
Applied to files:
src/components/direct-payout.tsx
📚 Learning: the invoice me links in the easy-invoice project do not have an expiration mechanism. the invoicemet...
Learnt from: aimensahnoun
PR: RequestNetwork/easy-invoice#8
File: src/app/i/[id]/page.tsx:18-22
Timestamp: 2025-02-13T21:57:39.869Z
Learning: The invoice me links in the easy-invoice project do not have an expiration mechanism. The invoiceMeTable schema only includes id, label, userId, and createdAt fields.
Applied to files:
src/components/dashboard/invoices-sent.tsx
src/components/dashboard/invoices-received.tsx
📚 Learning: in `src/server/routers/payment.ts`, the batchpay input validation already handles empty arrays corre...
Learnt from: aimensahnoun
PR: RequestNetwork/easy-invoice#67
File: src/server/routers/payment.ts:47-49
Timestamp: 2025-06-04T12:02:39.411Z
Learning: In `src/server/routers/payment.ts`, the batchPay input validation already handles empty arrays correctly. The `batchPaymentFormSchema.shape.payouts.optional()` inherits the `.min(1, "At least one payment is required")` validation from the original schema, so empty payouts arrays are automatically rejected even when the field is made optional.
Applied to files:
src/components/batch-payout.tsx
📚 Learning: invoice items are validated at creation time through the schema validation in src/lib/schemas/invoic...
Learnt from: aimensahnoun
PR: RequestNetwork/easy-invoice#2
File: src/app/invoices/[ID]/page.tsx:160-175
Timestamp: 2025-02-12T12:42:40.076Z
Learning: Invoice items are validated at creation time through the schema validation in src/lib/schemas/invoice.ts, ensuring that items array is non-empty and each item has required description, quantity, and price fields. Runtime validation in display components is not necessary.
Applied to files:
src/components/invoice-preview.tsx
🧬 Code Graph Analysis (9)
src/components/dashboard/blocks/table-head-cell.tsx (2)
src/components/ui/table.tsx (1)
TableHead
(113-113)src/lib/utils.ts (1)
cn
(4-6)
src/components/view-recurring-payments/view-recurring-payments.tsx (2)
src/components/ui/card.tsx (4)
Card
(79-79)CardContent
(79-79)CardHeader
(79-79)CardTitle
(79-79)src/components/ui/table.tsx (1)
TableCell
(115-115)
src/app/layout.tsx (5)
src/components/app-kit.tsx (1)
AppKit
(40-42)src/trpc/react.tsx (1)
TRPCReactProvider
(14-60)src/components/background-wrapper.tsx (1)
BackgroundWrapper
(17-104)src/components/ui/sonner.tsx (1)
Toaster
(31-31)src/components/version-badge.tsx (1)
VersionDisplay
(9-19)
src/components/payment-section.tsx (1)
src/lib/constants/currencies.ts (2)
MAINNET_CURRENCIES
(2-18)formatCurrencyLabel
(94-139)
src/components/header.tsx (1)
src/components/mode-toggle.tsx (1)
ModeToggle
(6-40)
src/components/mode-toggle.tsx (1)
src/components/ui/button.tsx (1)
Button
(56-56)
src/components/invoice-preview.tsx (2)
src/components/ui/card.tsx (2)
Card
(79-79)CardContent
(79-79)src/lib/date-utils.ts (1)
formatDate
(9-17)
src/components/dashboard/invoices-received.tsx (3)
src/components/dashboard/blocks/table-head-cell.tsx (1)
TableHeadCell
(9-13)src/components/dashboard/blocks/stat-card.tsx (1)
StatCard
(9-21)src/components/ui/card.tsx (1)
Card
(79-79)
src/components/subscription-plans/blocks/subscription-plan-link.tsx (2)
src/components/ui/card.tsx (2)
Card
(79-79)CardContent
(79-79)src/components/ui/button.tsx (1)
Button
(56-56)
🔇 Additional comments (61)
src/components/view-recurring-payments/blocks/completed-payments.tsx (1)
17-19
: Adopts semantic token – looks goodSwapping
text-zinc-500
fortext-muted-foreground
aligns the component with the new theme system and keeps contrast appropriate in both light / dark modes.src/components/footer.tsx (1)
5-7
: Consistent theming – no issues
text-muted-foreground
provides the right semantic colour for footer copy and matches tokens used elsewhere in the PR.src/components/dashboard/blocks/pagination.tsx (2)
22-24
: Verify design tokens exist in Tailwind configThe new
border-border
token assumes a corresponding entry in the theme’scolors
map; if it’s missing, the border will be transparent. Please confirm the token is defined (light & dark).
32-33
: Semantic text colour – looks good
text-muted-foreground
is the right choice for the page indicator; contrast remains acceptable in both themes.src/components/ui/tooltip.tsx (1)
16-22
: Theme tokens applied correctly
bg-popover
,text-popover-foreground
, andfill-popover
match the token naming used elsewhere; no functional impact detected.src/components/create-recurring-payment/blocks/create-recurring-payment-form.tsx (2)
193-193
: LGTM! Correct semantic color token usage.The replacement of
text-zinc-500
withtext-muted-foreground
is appropriate for help text, ensuring proper contrast in both light and dark themes.
279-279
: LGTM! Proper theme-aware button styling.The replacement of
text-zinc-500 hover:text-zinc-800
withtext-muted-foreground hover:text-foreground
correctly implements semantic color tokens for both normal and hover states, ensuring proper theming across light and dark modes.src/app/i/[id]/page.tsx (1)
40-40
: LGTM! Consistent navigation link theming.The replacement of
text-zinc-600 hover:text-black
withtext-muted-foreground hover:text-foreground
properly implements semantic color tokens for the back navigation link, ensuring consistent theming across light and dark modes.src/components/dashboard/blocks/table-head-cell.tsx (1)
10-10
: LGTM! Appropriate semantic token for table headers.The replacement of
text-zinc-500
withtext-muted-foreground
is ideal for table headers, providing appropriate visual hierarchy while ensuring proper contrast across light and dark themes.src/app/invoices/create/page.tsx (1)
30-30
: LGTM! Consistent with navigation theming pattern.The color token replacement follows the same pattern as other navigation links in the codebase, ensuring consistent theming for back navigation elements across the application.
src/app/dashboard/layout.tsx (1)
5-5
: LGTM! Improved UI consistency with design system.The replacement of a custom-styled Link with a Button component using
asChild
improves consistency with the design system while maintaining the same functionality. This approach provides better theme integration and standardized button styling across the application.Also applies to: 28-33
src/components/dashboard/blocks/empty-state.tsx (1)
17-21
: Semantic token migration looks good
bg-muted
,text-foreground
, andtext-muted-foreground
correctly replace the previous hard-coded zinc shades and align with the new theme system. No functional impact detected.src/components/payment-secured-using-request.tsx (1)
3-8
: Consistent success palette usage confirmed
Usingbg-success/10
,border-success
, and the corresponding foreground tokens keeps the component aligned with the new design-token palette. No issues found.src/components/view-recurring-payments/blocks/frequency-badge.tsx (1)
7-10
: LGTM – badges now leverage theme tokens
The frequency badge palette mirrors the status-badge approach and cleanly adopts semantic tokens. No functional or visual concerns noted.src/components/subscription-plans/subscription-plans.tsx (1)
35-35
: LGTM! Consistent theming implementation.The color class replacements correctly follow the semantic theming pattern - using
text-muted-foreground
for secondary elements andbg-primary
withtext-primary-foreground
for primary actions. The hover states are properly maintained.Also applies to: 45-45
src/components/dashboard/subscriptions.tsx (1)
39-39
: Excellent theming consistency across the component.All color replacements follow the semantic token pattern correctly:
- Table hover states use
hover:bg-muted/50
for subtle interactions- Icons consistently use
text-muted-foreground
for secondary visual elements- Card borders use the semantic
border-border
tokenAlso applies to: 85-85, 179-179, 184-184, 189-189, 193-193, 204-206
src/components/subscription-plan-preview.tsx (1)
120-120
: Comprehensive theming implementation across all text elements.The color replacements consistently follow the semantic token pattern:
- Secondary labels and descriptive text use
text-muted-foreground
- Interactive elements maintain proper hover states with
hover:text-foreground
- Loading states and instructions appropriately use muted styling
Also applies to: 141-143, 151-153, 159-161, 169-171, 179-181, 187-189, 252-252, 283-283, 294-297
src/components/invoice-form.tsx (1)
590-590
: Proper theming implementation in modal and form elements.The color updates correctly use semantic tokens:
- Spinner border uses
border-foreground
for primary visual elements- Modal text uses
text-muted-foreground
for secondary content- Submit button follows the primary color scheme pattern with proper hover states
Also applies to: 591-591, 595-595, 1039-1039
src/components/dashboard/blocks/stat-card.tsx (1)
10-10
: Perfect implementation of card theming pattern.The semantic token usage is exactly right:
bg-card
,border-border
, andtext-card-foreground
provide proper theme support for the card containertext-muted-foreground
appropriately styles the secondary title textThis follows the established theming pattern consistently.
Also applies to: 12-12
src/components/invoice-me-link.tsx (1)
49-76
: LGTM! Consistent theming implementation.The styling updates properly replace hardcoded zinc colors with semantic theme tokens (
text-foreground
,text-muted-foreground
,bg-muted
,hover:bg-muted
). The destructive delete button correctly maintains its red styling for visual clarity.src/app/layout.tsx (3)
12-12
: LGTM! Proper ThemeProvider import.
36-36
: LGTM! Correct hydration warning suppression.The
suppressHydrationWarning
attribute prevents React hydration mismatches that occur during theme initialization, which is a standard practice when implementing themes.
41-51
: LGTM! Excellent ThemeProvider configuration.The ThemeProvider is properly configured with:
attribute="class"
for CSS class-based themingdefaultTheme="system"
to respect user's system preferenceenableSystem
to detect system theme changes- Correct nesting with other providers maintains the component hierarchy
src/components/dashboard/blocks/invoice-row.tsx (1)
52-119
: LGTM! Comprehensive and consistent theming updates.All styling changes properly implement the semantic token approach:
- Row hover states use
bg-muted/50
for subtle interaction feedback- Secondary text elements (recurrence, email, dates) consistently use
text-muted-foreground
- Action buttons use semantic tokens (
bg-card
,border-border
,hover:bg-muted
)- Icons appropriately use
text-muted-foreground
for consistent visual hierarchysrc/components/dashboard/invoices-received.tsx (4)
38-47
: LGTM! Consistent table header styling.Table header cells properly use
text-muted-foreground
for secondary text hierarchy.
190-211
: LGTM! Well-designed selection summary and CTA.The selected invoices summary box uses appropriate muted styling (
bg-muted
,border-border
), while the batch pay button correctly uses primary colors to emphasize the call-to-action.
219-229
: LGTM! Consistent stat card icon styling.All stat card icons consistently use
text-muted-foreground
for proper visual hierarchy.
233-246
: LGTM! Proper card and empty state theming.The table card uses semantic border tokens, and the empty state icon is appropriately styled with muted foreground color.
src/components/invoice-me-links.tsx (3)
60-60
: LGTM! Proper navigation link theming.The back navigation link correctly uses
text-muted-foreground
totext-foreground
transition on hover, maintaining consistent navigation styling.
70-70
: LGTM! Appropriate primary button styling.The "New Link" button properly uses primary color tokens for call-to-action emphasis.
99-99
: LGTM! Consistent CTA button styling.The "Create" button maintains consistency with the primary button styling pattern established throughout the application.
src/components/compliance-status.tsx (1)
29-55
: LGTM! Excellent semantic token implementation.The STATUS_CONFIG object has been consistently updated to use semantic design tokens instead of hardcoded color utilities. The mapping is well-structured:
destructive
tokens for error states (not_started)warning
tokens for in-progress states (initiated, pending)success
tokens for completed states (completed, approved)This change enables proper theme support and maintains visual consistency across light and dark modes.
src/components/mode-toggle.tsx (1)
1-41
: Excellent theme toggle implementation!The ModeToggle component is well-implemented with several notable strengths:
- Smooth animations: Uses CSS transforms with cubic-bezier timing for professional feel
- Accessibility: Includes proper
aria-label
for screen readers- Visual feedback: Clear Sun/Moon icons with rotation animation
- Theme-aware styling: Uses semantic tokens (
bg-muted
,text-foreground
) that adapt to current theme- Clean API: Simple toggle between light/dark modes
The sliding animation with the calculated
translateX
and icon rotation creates an intuitive user experience.src/components/invoice-preview.tsx (3)
32-32
: Good semantic token adoption for card container.The Card component now uses proper theme-aware tokens (
bg-card
,text-card-foreground
,border-border
) instead of hardcoded colors, enabling proper dark mode support.
38-242
: Consistent text color token updates throughout the component.All instances of hardcoded
text-neutral-500
andtext-neutral-600
have been systematically replaced withtext-muted-foreground
. This creates consistent theming for:
- Section labels (INVOICE NO, ISSUED, DUE DATE, etc.)
- Email addresses and contact information
- Table headers and secondary text
- Notes and payment details
The semantic token approach ensures proper contrast ratios in both light and dark themes.
128-157
: Border styling properly updated for theme consistency.Table borders and dividers now use
border-border
instead ofborder-neutral-200
, ensuring they adapt appropriately to the current theme.src/components/header.tsx (4)
3-3
: Good integration of theme toggle component.The ModeToggle component is properly imported and will be integrated into the header navigation.
24-30
: Logo styling updated for theme consistency.The logo container now uses semantic tokens (
bg-primary
,text-primary-foreground
,text-foreground
) ensuring it adapts properly to both light and dark themes while maintaining brand identity.
37-68
: Navigation links properly themed.All navigation links now use consistent semantic tokens:
text-foreground
for normal statetext-muted-foreground
for hover state- Proper theme-aware styling for the "Book A Demo" link
This ensures good readability and visual hierarchy in both light and dark modes.
93-93
: Theme toggle well-positioned in navigation.The ModeToggle component is appropriately placed at the end of the navigation items, providing easy access to theme switching without cluttering the main navigation flow.
src/components/batch-payout.tsx (6)
262-280
: Card styling properly updated for theme support.The main Card container and header now use semantic tokens (
bg-card
,text-card-foreground
,border-border
,bg-muted
) ensuring consistent theming across light and dark modes while maintaining the visual hierarchy.
285-289
: Loading state styling theme-aware.The loading spinner and text now use
text-muted-foreground
for consistent secondary text styling that adapts to the current theme.
298-330
: Step indicators properly themed.The wallet connection and payment steps now use semantic tokens for:
- Active/inactive state colors (
text-foreground
vstext-muted-foreground
)- Step backgrounds (
bg-muted
for active,border-border
for inactive)- Progress bar styling
This maintains clear visual progression while supporting both themes.
350-498
: Table styling comprehensively updated.The payments table now uses consistent semantic tokens throughout:
- Table borders (
border-border
)- Row hover states (
hover:bg-muted/50
)- Input focus rings (
focus-visible:ring-border
)- Action button styling with proper destructive colors
- Cell text hierarchy with
text-muted-foreground
for row numbersAll interactive elements maintain proper accessibility while supporting theme switching.
509-572
: Summary and action sections well-themed.The batch summary card and action buttons use appropriate semantic tokens:
- Summary card background (
bg-muted
)- Text hierarchy for labels and values
- Add payment button with dashed border styling
- Consistent use of
text-muted-foreground
for secondary informationThe theming maintains the component's functional clarity while enabling dark mode support.
578-585
: Footer wallet address styling updated.The connected wallet address display now uses theme-aware colors (
text-muted-foreground
,hover:text-foreground
) ensuring good readability in both light and dark modes.src/components/view-recurring-payments/view-recurring-payments.tsx (1)
150-152
: LGTM – token migration looks solidThe switch to
bg-muted
,border-border
, andtext-card-foreground
is consistent with the rest of the PR. No functional impact detected.src/components/create-recurring-payment/create-recurring-payment.tsx (1)
49-53
: LGTM – loader adopts semantic colourReplacing the hard-coded zinc tint with
text-muted-foreground
aligns the spinner with both light and dark themes.src/components/direct-payout.tsx (1)
216-227
: No changes needed:border-foreground
is valid
The Tailwind config defines a top-levelforeground
color token, and Tailwind generatesborder-<color>
utilities for every theme color. Thereforeborder-foreground
does exist and will correctly apply the foreground border color.src/components/payment-section.tsx (4)
404-410
: LGTM! Proper semantic token usage for success styling.The secure payment section correctly uses semantic success tokens (
bg-success/10
,border-success
,text-success
,text-success-foreground
) which will adapt properly to both light and dark themes.
413-428
: LGTM! Consistent warning styling with semantic tokens.The cryptocurrency warning section properly implements semantic warning tokens (
bg-warning/10
,border-warning
,text-warning
,text-warning-foreground
) for theme-aware styling.
439-448
: LGTM! Proper muted styling implementation.The currency conversion display and recipient address sections correctly use semantic muted tokens (
text-muted-foreground
,bg-muted
,border-border
) for consistent theming.Also applies to: 455-463
472-516
: LGTM! Consistent step indicators and loading states styling.The payment steps, wallet connection UI, and loading states properly implement semantic tokens (
text-foreground
,text-muted-foreground
,bg-muted
,border-foreground
,border-muted
) for theme consistency.Also applies to: 522-567, 584-648
src/components/background-wrapper.tsx (4)
1-2
: LGTM! Proper theme integration.The component correctly integrates the
useTheme
hook fromnext-themes
to enable theme-aware styling. The implementation follows React best practices for theme detection.Also applies to: 28-29, 61-61
49-54
: LGTM! Dark mode color additions.The dark mode color hex codes are properly added to the color mapping. The zinc and slate variations provide good options for dark theme styling.
64-66
: LGTM! Theme-aware background implementation.The dynamic background color switching between light (
#FAFAFA
) and dark (#0A0A0A
) themes is properly implemented using conditional rendering.
93-95
: LGTM! Theme-aware dot pattern implementation.The dot pattern background correctly adapts its color based on the theme (
#1f1f1f
for dark,#e5e5e5
for light), providing consistent visual texture across themes.src/components/subscription-plans/blocks/subscription-plan-link.tsx (4)
79-79
: LGTM! Proper Card styling with semantic tokens.The Card component correctly uses semantic design tokens (
bg-card
,border-border
,text-card-foreground
) for consistent theming across light and dark modes.
84-85
: LGTM! Consistent text styling with semantic tokens.The text elements properly use semantic tokens (
text-foreground
for primary text,text-muted-foreground
for secondary text) ensuring proper contrast and readability in both themes.Also applies to: 101-101, 105-105
114-114
: LGTM! Proper button and icon styling.The action buttons correctly use
hover:bg-muted
for hover states andtext-muted-foreground
for icons, providing consistent interactive feedback across themes.Also applies to: 117-117, 123-123, 127-127
135-139
: LGTM! Appropriate preservation of destructive styling.The delete button intentionally maintains its red styling (
hover:bg-red-50
,text-red-500
) which is correct UX practice - destructive actions should maintain their warning appearance regardless of theme to prevent accidental deletions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for your contribution to Easy Invoice <3
Really good work, thanks for switching our tailwind variable names to something semantic instead of just using the colour names...
On top of the 3 things I commented on, I've noticed a pretty weird bug which happens only when loading the app the very first time:
Something gets mixed up and some components end up in their dark theme variant, while others do not.
Tried this out on multiple Chromium browsers and I can reproduce it constantly.
The error goes away after toggling the theme at least once.
Not sure what the solution could be, but maybe the theme switcher should check if theme isn't yet set, to just default to the light theme.
Other than that loving the dark mode look 😎
Some more issues with dark mode:
- Invoice me links




And sadly, mandatory merge conflicts due to one of our huge PRs coming in, sorry about that 😅
After merging, do check the /subscription-plans
route, there's a ton of added things there now.
After the UI issues and review comments are taken care of, I'll gladly drop an approval 💯
? "border-black bg-zinc-50" | ||
: "border-zinc-300" | ||
? "border-foreground bg-muted" | ||
: "border-border" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it possible to rename border-border into border-primary or something? border-border
is a bit funny :D
812190e
to
b229dcd
Compare
#46 : add dark mode , a few snapshots below
Summary by CodeRabbit
New Features
Style
Bug Fixes
Refactor