feat(dashboard): scaffold BetterBase Next.js dashboard app#5
feat(dashboard): scaffold BetterBase Next.js dashboard app#5Helal-maker merged 2 commits intomainfrom
Conversation
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
📝 WalkthroughWalkthroughCreates a new Next.js 15 dashboard application for BetterBase with authentication pages, dashboard layout with navigation, multiple feature pages, reusable UI components, client integration, TanStack Query setup, and Tailwind CSS styling. Includes 35+ new files establishing app structure, configuration, and foundational features. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (4)
betterbase/apps/dashboard/src/components/layout/header.tsx (2)
24-29: Theme preference not persisted.The toggle updates the DOM class but doesn't persist to
localStorage. On page refresh, the theme resets. For a scaffold this is acceptable, but consider adding persistence when implementing full theme support.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@betterbase/apps/dashboard/src/components/layout/header.tsx` around lines 24 - 29, The toggleTheme function updates the DOM and state but doesn't persist the user's preference; update toggleTheme to write the chosen theme to localStorage (e.g., set 'theme' = 'dark' or 'light') when calling setIsDark, and add initialization logic (e.g., in a useEffect) to read localStorage on mount and apply the stored value to document.documentElement.classList and setIsDark so the preference survives page refreshes; reference the existing toggleTheme function, setIsDark state setter, and document.documentElement when implementing this.
18-22: Theme state may flash on hydration.Initial
useState(false)followed byuseEffectsync can cause a brief mismatch if the page loads in dark mode (server renders light icon, client corrects to dark). Consider initializing from a cookie or usingsuppressHydrationWarningon the icon container.💡 Alternative: check system preference or cookie for initial state
- const [isDark, setIsDark] = useState(false); + const [isDark, setIsDark] = useState(() => { + if (typeof window !== 'undefined') { + return document.documentElement.classList.contains('dark'); + } + return false; + });Note: This still won't fully solve SSR mismatch. For robust theming, consider a dedicated theme provider (e.g.,
next-themes).🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@betterbase/apps/dashboard/src/components/layout/header.tsx` around lines 18 - 22, The current useState(false) + useEffect sync for isDark causes a hydration flash; change the initialization to a function that reads a persisted preference (cookie/localStorage) or system setting via window.matchMedia and return that value to useState (e.g., replace useState(false) with useState(() => { /* read cookie or matchMedia */ })), and/or add suppressHydrationWarning on the icon container that uses isDark to avoid the SSR mismatch; update references to isDark, setIsDark, and the useEffect that currently calls document.documentElement.classList.contains('dark') so the initial client value matches the rendered markup.betterbase/apps/dashboard/src/components/layout/sidebar.tsx (1)
32-33:startsWithmatch can produce false positives.
pathname.startsWith('/api')will also highlight for paths like/api-keysor/api-explorer. If more specific matching is needed later, consider exact match or segment-based logic.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@betterbase/apps/dashboard/src/components/layout/sidebar.tsx` around lines 32 - 33, The current active-check using pathname.startsWith(item.href) in the navigation.map callback can produce false positives (e.g., '/api' matching '/api-keys'); update the isActive logic in the sidebar component to use a boundary-aware check such as pathname === item.href || pathname.startsWith(item.href + '/') or compare path segments (split pathname and item.href and compare the first N segments) so only exact or child routes of item.href match; modify the isActive assignment where pathname.startsWith(item.href) is used to implement this safer matching.betterbase/apps/dashboard/src/app/(dashboard)/page.tsx (1)
54-60: Consider addingtype="button"to prevent accidental form submission.While these buttons are not currently inside a form, adding
type="button"explicitly is a defensive practice that prevents unintended behavior if the component is ever wrapped in a form context.💡 Suggested improvement
<button key={action} + type="button" className="w-full rounded-lg border border-zinc-200 p-3 text-left text-sm hover:bg-zinc-50 dark:border-zinc-800 dark:hover:bg-zinc-900" >🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@betterbase/apps/dashboard/src/app/`(dashboard)/page.tsx around lines 54 - 60, The mapped JSX button elements rendering {action} lack an explicit type and can submit a surrounding form unexpectedly; update the button element in the mapping (the JSX that uses key={action} and renders {action}) to include type="button" so it will never act as a submit button if this component is later placed inside a form.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@betterbase/apps/dashboard/next-env.d.ts`:
- Around line 1-3: Remove the unused triple-slash reference to typed routes by
deleting the line containing /// <reference path="./.next/types/routes.d.ts" />
from the file; this will stop tsc --noEmit from failing in clean checkouts when
typedRoutes is not enabled in next.config.ts and the referenced routes.d.ts does
not exist.
In `@betterbase/apps/dashboard/src/components/layout/sidebar.tsx`:
- Line 10: The sidebar entry { name: 'API', href: '/api', icon: Code } uses the
reserved Next.js /api path and can conflict with App Router API routes; change
the href to a non-reserved route such as '/api-explorer' (or '/api-docs') in the
sidebar component and update any corresponding Link/navigation usage and route
handlers that expect the old path so they point to the new route name (search
for occurrences of "/api" and the symbol name 'API' in Link/route references and
adjust them to '/api-explorer').
In `@betterbase/apps/dashboard/src/components/ui/card.tsx`:
- Around line 14-16: CardTitle's forwardRef generic types are wrong: it
currently uses HTMLParagraphElement but renders an <h3> (HTMLHeadingElement).
Update the forwardRef generics so the ref type and props use HTMLHeadingElement
(e.g., React.forwardRef<HTMLHeadingElement,
React.HTMLAttributes<HTMLHeadingElement>>) to match the rendered <h3> in the
CardTitle component.
- Around line 29-34: The export list exports CardFooter before it's declared,
causing CardFooter to be undefined; move the CardFooter declaration (the
React.forwardRef component named CardFooter and its displayName assignment)
above the export statement so the exported symbols (Card, CardHeader,
CardFooter, CardTitle, CardDescription, CardContent) reference initialized
bindings.
---
Nitpick comments:
In `@betterbase/apps/dashboard/src/app/`(dashboard)/page.tsx:
- Around line 54-60: The mapped JSX button elements rendering {action} lack an
explicit type and can submit a surrounding form unexpectedly; update the button
element in the mapping (the JSX that uses key={action} and renders {action}) to
include type="button" so it will never act as a submit button if this component
is later placed inside a form.
In `@betterbase/apps/dashboard/src/components/layout/header.tsx`:
- Around line 24-29: The toggleTheme function updates the DOM and state but
doesn't persist the user's preference; update toggleTheme to write the chosen
theme to localStorage (e.g., set 'theme' = 'dark' or 'light') when calling
setIsDark, and add initialization logic (e.g., in a useEffect) to read
localStorage on mount and apply the stored value to
document.documentElement.classList and setIsDark so the preference survives page
refreshes; reference the existing toggleTheme function, setIsDark state setter,
and document.documentElement when implementing this.
- Around line 18-22: The current useState(false) + useEffect sync for isDark
causes a hydration flash; change the initialization to a function that reads a
persisted preference (cookie/localStorage) or system setting via
window.matchMedia and return that value to useState (e.g., replace
useState(false) with useState(() => { /* read cookie or matchMedia */ })),
and/or add suppressHydrationWarning on the icon container that uses isDark to
avoid the SSR mismatch; update references to isDark, setIsDark, and the
useEffect that currently calls
document.documentElement.classList.contains('dark') so the initial client value
matches the rendered markup.
In `@betterbase/apps/dashboard/src/components/layout/sidebar.tsx`:
- Around line 32-33: The current active-check using
pathname.startsWith(item.href) in the navigation.map callback can produce false
positives (e.g., '/api' matching '/api-keys'); update the isActive logic in the
sidebar component to use a boundary-aware check such as pathname === item.href
|| pathname.startsWith(item.href + '/') or compare path segments (split pathname
and item.href and compare the first N segments) so only exact or child routes of
item.href match; modify the isActive assignment where
pathname.startsWith(item.href) is used to implement this safer matching.
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (1)
betterbase/apps/dashboard/src/app/(dashboard)/page.tsx (1)
23-26: Mark decorative icons as aria-hidden.These icons appear purely decorative; add
aria-hidden="true"(and optionallyfocusable="false") to avoid extra noise for screen readers.♿ Suggested tweak
- <stat.icon className="h-4 w-4 text-zinc-600 dark:text-zinc-400" /> + <stat.icon aria-hidden="true" focusable="false" className="h-4 w-4 text-zinc-600 dark:text-zinc-400" />🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@betterbase/apps/dashboard/src/app/`(dashboard)/page.tsx around lines 23 - 26, The decorative icon rendered as <stat.icon /> inside the CardHeader is not marked for accessibility; update the JSX where <stat.icon className="h-4 w-4 ..."/> is used (near CardHeader/CardTitle) to add aria-hidden="true" and optionally focusable="false" so screen readers ignore it, e.g. set these attributes on the stat.icon element to make it non-interactive decorative content.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@betterbase/apps/dashboard/src/app/`(dashboard)/page.tsx:
- Around line 52-60: The Quick Actions buttons rendered in the map (the array
['Create new table','Test API endpoint','View logs'] and the corresponding
<button> elements in page.tsx) are non-functional; either wire each action to
its route using next/link (replace the button with Link or wrap it and navigate
to the correct path for each label) or make them explicitly disabled by adding
disabled/aria-disabled, a visual “coming soon” affordance and preventing pointer
events. Update the mapping logic that generates these action buttons so each
label maps to a route slug (e.g., create-table, test-api, logs) and use Link for
navigation, or set disabled plus a tooltip/aria-label if the routes don’t exist.
In `@betterbase/apps/dashboard/src/components/layout/header.tsx`:
- Around line 60-99: Several icon-only Button components (e.g., the mobile menu
Button with <Menu />, the close Button with <X />, the theme toggle Button that
calls toggleTheme, and Buttons with <HelpCircle />, <Bell />, and the user menu
trigger with <User />) are missing accessible labels; add meaningful aria-label
attributes (or visually-hidden text) to each icon-only Button (for example:
aria-label="Open menu", aria-label="Close menu", aria-label="Toggle theme",
aria-label="Help", aria-label="Notifications", aria-label="User menu") ensuring
the theme toggle still uses isDark state for the visual icon but includes an
unchanged aria-label, and update any Dialog.Close or DropdownMenuTrigger Buttons
accordingly so screen readers can announce their purpose.
- Around line 64-75: The Dialog.Content lacks an accessible label — add a
Dialog.Title inside the drawer content to provide a screen-reader title (it can
be visually hidden using an sr-only class if you don't want it visible). Locate
the Dialog.Content block (the component using Dialog.Content) and insert a
Dialog.Title element (for example immediately after Dialog.Content opens or
before Sidebar) with appropriate text, or wrap the Dialog.Title with the
"sr-only" utility so the title is present for assistive tech but not visible;
keep existing Dialog.Close and Sidebar as-is.
---
Nitpick comments:
In `@betterbase/apps/dashboard/src/app/`(dashboard)/page.tsx:
- Around line 23-26: The decorative icon rendered as <stat.icon /> inside the
CardHeader is not marked for accessibility; update the JSX where <stat.icon
className="h-4 w-4 ..."/> is used (near CardHeader/CardTitle) to add
aria-hidden="true" and optionally focusable="false" so screen readers ignore it,
e.g. set these attributes on the stat.icon element to make it non-interactive
decorative content.
| <div className="space-y-2"> | ||
| {['Create new table', 'Test API endpoint', 'View logs'].map((action) => ( | ||
| <button | ||
| type="button" | ||
| key={action} | ||
| className="w-full rounded-lg border border-zinc-200 p-3 text-left text-sm hover:bg-zinc-50 dark:border-zinc-800 dark:hover:bg-zinc-900" | ||
| > | ||
| {action} | ||
| </button> |
There was a problem hiding this comment.
Quick Actions are non-functional — wire to routes or mark disabled.
These buttons render without handlers or navigation, so clicks do nothing. That’s a small but visible UX break. Suggest turning them into links (if the routes exist) or explicitly disabled with a “coming soon” affordance.
🛠️ Example: wire to routes via next/link
+import Link from 'next/link';
import { ApiUsageChart } from '@/components/charts/api-usage-chart';
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
import { Activity, Code, Database, Users } from 'lucide-react';
export default function DashboardPage() {
const stats = [
{ name: 'Total Tables', value: '12', icon: Database, change: '+2 this week' },
{ name: 'API Calls', value: '45.2K', icon: Code, change: '+12% from last week' },
{ name: 'Active Users', value: '2,547', icon: Users, change: '+234 this week' },
{ name: 'Uptime', value: '99.9%', icon: Activity, change: '30 days' },
];
+ const actions = [
+ { label: 'Create new table', href: '/tables' },
+ { label: 'Test API endpoint', href: '/api' },
+ { label: 'View logs', href: '/logs' },
+ ];
return (
@@
<CardContent>
<div className="space-y-2">
- {['Create new table', 'Test API endpoint', 'View logs'].map((action) => (
- <button
- type="button"
- key={action}
- className="w-full rounded-lg border border-zinc-200 p-3 text-left text-sm hover:bg-zinc-50 dark:border-zinc-800 dark:hover:bg-zinc-900"
- >
- {action}
- </button>
- ))}
+ {actions.map((action) => (
+ <Link
+ key={action.label}
+ href={action.href}
+ className="block w-full rounded-lg border border-zinc-200 p-3 text-left text-sm hover:bg-zinc-50 dark:border-zinc-800 dark:hover:bg-zinc-900"
+ >
+ {action.label}
+ </Link>
+ ))}
</div>
</CardContent>📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <div className="space-y-2"> | |
| {['Create new table', 'Test API endpoint', 'View logs'].map((action) => ( | |
| <button | |
| type="button" | |
| key={action} | |
| className="w-full rounded-lg border border-zinc-200 p-3 text-left text-sm hover:bg-zinc-50 dark:border-zinc-800 dark:hover:bg-zinc-900" | |
| > | |
| {action} | |
| </button> | |
| <div className="space-y-2"> | |
| {actions.map((action) => ( | |
| <Link | |
| key={action.label} | |
| href={action.href} | |
| className="block w-full rounded-lg border border-zinc-200 p-3 text-left text-sm hover:bg-zinc-50 dark:border-zinc-800 dark:hover:bg-zinc-900" | |
| > | |
| {action.label} | |
| </Link> | |
| ))} | |
| </div> |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@betterbase/apps/dashboard/src/app/`(dashboard)/page.tsx around lines 52 - 60,
The Quick Actions buttons rendered in the map (the array ['Create new
table','Test API endpoint','View logs'] and the corresponding <button> elements
in page.tsx) are non-functional; either wire each action to its route using
next/link (replace the button with Link or wrap it and navigate to the correct
path for each label) or make them explicitly disabled by adding
disabled/aria-disabled, a visual “coming soon” affordance and preventing pointer
events. Update the mapping logic that generates these action buttons so each
label maps to a route slug (e.g., create-table, test-api, logs) and use Link for
navigation, or set disabled plus a tooltip/aria-label if the routes don’t exist.
| <Button variant="ghost" size="icon" className="md:hidden"> | ||
| <Menu className="h-5 w-5" /> | ||
| </Button> | ||
| </Dialog.Trigger> | ||
| <Dialog.Portal> | ||
| <Dialog.Overlay className="fixed inset-0 z-40 bg-black/30" /> | ||
| <Dialog.Content className="fixed inset-y-0 left-0 z-50 w-72 bg-white dark:bg-zinc-900"> | ||
| <div className="flex items-center justify-end p-2"> | ||
| <Dialog.Close asChild> | ||
| <Button variant="ghost" size="icon"> | ||
| <X className="h-4 w-4" /> | ||
| </Button> | ||
| </Dialog.Close> | ||
| </div> | ||
| <Sidebar mobile /> | ||
| </Dialog.Content> | ||
| </Dialog.Portal> | ||
| </Dialog.Root> | ||
| <h1 className="text-base font-semibold md:text-xl">My Project</h1> | ||
| <span className="rounded-full bg-green-100 px-2 py-1 text-xs font-medium text-green-700 dark:bg-green-950 dark:text-green-400"> | ||
| Active | ||
| </span> | ||
| </div> | ||
|
|
||
| <div className="flex items-center gap-2"> | ||
| <Button variant="ghost" size="icon" onClick={toggleTheme} aria-label="Toggle theme"> | ||
| <span suppressHydrationWarning>{isDark ? <Sun className="h-5 w-5" /> : <Moon className="h-5 w-5" />}</span> | ||
| </Button> | ||
| <Button variant="ghost" size="icon"> | ||
| <HelpCircle className="h-5 w-5" /> | ||
| </Button> | ||
| <Button variant="ghost" size="icon"> | ||
| <Bell className="h-5 w-5" /> | ||
| </Button> | ||
| <DropdownMenu> | ||
| <DropdownMenuTrigger asChild> | ||
| <Button variant="ghost" size="icon"> | ||
| <User className="h-5 w-5" /> | ||
| </Button> | ||
| </DropdownMenuTrigger> |
There was a problem hiding this comment.
Add accessible labels to icon-only buttons.
Icon-only controls need aria-label (or SR-only text) so screen readers can announce their purpose.
✅ Suggested fix
- <Button variant="ghost" size="icon" className="md:hidden">
+ <Button variant="ghost" size="icon" className="md:hidden" aria-label="Open navigation">
<Menu className="h-5 w-5" />
</Button>
...
- <Button variant="ghost" size="icon">
+ <Button variant="ghost" size="icon" aria-label="Close navigation">
<X className="h-4 w-4" />
</Button>
...
- <Button variant="ghost" size="icon">
+ <Button variant="ghost" size="icon" aria-label="Help">
<HelpCircle className="h-5 w-5" />
</Button>
- <Button variant="ghost" size="icon">
+ <Button variant="ghost" size="icon" aria-label="Notifications">
<Bell className="h-5 w-5" />
</Button>
...
- <Button variant="ghost" size="icon">
+ <Button variant="ghost" size="icon" aria-label="User menu">
<User className="h-5 w-5" />
</Button>🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@betterbase/apps/dashboard/src/components/layout/header.tsx` around lines 60 -
99, Several icon-only Button components (e.g., the mobile menu Button with <Menu
/>, the close Button with <X />, the theme toggle Button that calls toggleTheme,
and Buttons with <HelpCircle />, <Bell />, and the user menu trigger with <User
/>) are missing accessible labels; add meaningful aria-label attributes (or
visually-hidden text) to each icon-only Button (for example: aria-label="Open
menu", aria-label="Close menu", aria-label="Toggle theme", aria-label="Help",
aria-label="Notifications", aria-label="User menu") ensuring the theme toggle
still uses isDark state for the visual icon but includes an unchanged
aria-label, and update any Dialog.Close or DropdownMenuTrigger Buttons
accordingly so screen readers can announce their purpose.
| <Dialog.Portal> | ||
| <Dialog.Overlay className="fixed inset-0 z-40 bg-black/30" /> | ||
| <Dialog.Content className="fixed inset-y-0 left-0 z-50 w-72 bg-white dark:bg-zinc-900"> | ||
| <div className="flex items-center justify-end p-2"> | ||
| <Dialog.Close asChild> | ||
| <Button variant="ghost" size="icon"> | ||
| <X className="h-4 w-4" /> | ||
| </Button> | ||
| </Dialog.Close> | ||
| </div> | ||
| <Sidebar mobile /> | ||
| </Dialog.Content> |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check Dialog usage in the header component
rg -n "Dialog\." betterbase/apps/dashboard/src/components/layout/header.tsxRepository: Helal-maker/Betterbase
Length of output: 534
🏁 Script executed:
#!/bin/bash
# Check if Dialog.Title exists anywhere in the file
cat -n betterbase/apps/dashboard/src/components/layout/header.tsx | sed -n '58,80p'Repository: Helal-maker/Betterbase
Length of output: 1275
🏁 Script executed:
#!/bin/bash
# Search for other Dialog.Content usages in the codebase to check patterns
rg -B2 -A3 "Dialog\.Content" betterbase/apps/dashboard/src --type tsx --type ts | head -50Repository: Helal-maker/Betterbase
Length of output: 93
🏁 Script executed:
#!/bin/bash
# Search for other Dialog.Content usages to check patterns
rg -B2 -A3 "Dialog\.Content" betterbase/apps/dashboard/src | head -80Repository: Helal-maker/Betterbase
Length of output: 1345
🌐 Web query:
Radix Dialog accessibility requirements Dialog.Title screen reader
💡 Result:
Radix Dialog.Content must have an accessible name so screen readers can announce what the dialog is. Radix’s recommended/expected way to provide that name is <Dialog.Title>. (radix-ui.com)
What to do (requirements + options)
-
Include
Dialog.Titleinside the dialog- Radix describes
Dialog.Titleas “an accessible title to be announced when the dialog is opened.” (radix-ui.com)
- Radix describes
-
If you don’t want a visible title, still render it (screen-reader-only)
- Wrap the title with Radix VisuallyHidden so it remains available to assistive tech. (radix-ui.com)
-
Alternative (less common): label the dialog via ARIA
- A dialog can be named via
aria-labeloraria-labelledby(this is what tools like axe check under “aria-dialog-name”). (developer.mozilla.org) - In Radix, using
Dialog.Titleeffectively supports this requirement by providing the title that’s announced. (radix-ui.com)
- A dialog can be named via
Example (recommended)
<Dialog.Content>
<Dialog.Title>Account settings</Dialog.Title>
...
</Dialog.Content>Example (title visually hidden, still accessible)
<Dialog.Content>
<VisuallyHidden asChild>
<Dialog.Title>Account settings</Dialog.Title>
</VisuallyHidden>
...
</Dialog.Content>If you’re seeing Radix’s console error (“DialogContent requires a DialogTitle…”), it’s that same accessibility requirement being enforced. (github.com)
Citations:
- 1: https://www.radix-ui.com/primitives/docs/components/dialog?utm_source=openai
- 2: https://www.radix-ui.com/primitives/docs/components/dialog?utm_source=openai
- 3: https://www.radix-ui.com/primitives/docs/components/dialog?utm_source=openai
- 4: https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/dialog_role?utm_source=openai
- 5: https://www.radix-ui.com/primitives/docs/components/dialog?utm_source=openai
- 6: Misleading error log for Dialog Title radix-ui/themes#556
Add Dialog.Title to make the drawer accessible.
Dialog.Content requires a title for screen readers. Either add a visible Dialog.Title or wrap it with sr-only to keep it visually hidden.
✅ Suggested fix
<Dialog.Content className="fixed inset-y-0 left-0 z-50 w-72 bg-white dark:bg-zinc-900">
+ <Dialog.Title className="sr-only">Navigation</Dialog.Title>
<div className="flex items-center justify-end p-2">🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@betterbase/apps/dashboard/src/components/layout/header.tsx` around lines 64 -
75, The Dialog.Content lacks an accessible label — add a Dialog.Title inside the
drawer content to provide a screen-reader title (it can be visually hidden using
an sr-only class if you don't want it visible). Locate the Dialog.Content block
(the component using Dialog.Content) and insert a Dialog.Title element (for
example immediately after Dialog.Content opens or before Sidebar) with
appropriate text, or wrap the Dialog.Title with the "sr-only" utility so the
title is present for assistive tech but not visible; keep existing Dialog.Close
and Sidebar as-is.
Motivation
Description
apps/dashboardNext.js 15 App Router app with strict TypeScript, Tailwind, PostCSS, and Bun-first scripts includingpackage.json,tsconfig.json,next.config.ts, andtailwind.config.ts.layout, TanStack QueryProviders, responsiveSidebar,Header(with mobile drawer and theme toggle), KPI overviewpage, routes fortables,api,auth,logs,settings, and auth entry pages (/login,/signup), plus UI primitives (ui/*), charts (recharts) and table placeholders.@betterbase/clientviasrc/lib/betterbase.tsand a small React Query hookuseCurrentUser; added a local type shimsrc/types/betterbase-client.d.tsso strict typechecking passes while the client package emits its own build artifacts.tailwind.config.tsdarkModeto'class', addingpostcss.config.mjsthat uses@tailwindcss/postcss, updatingpackage.jsondeps (e.g.tailwind-mergeversion), and replacing CSS rules that caused Tailwind compile errors; includedsrc/app/globals.csswith theme CSS variables.Testing
bun installand saved lockfile successfully.bun run typecheckinapps/dashboardand it completed with no errors.bun run buildinapps/dashboardand the Next build completed successfully.bun run dev --port 3100and validated the UI loaded by capturing a Playwright screenshot of the dashboard home page; the dev server started and pages rendered correctly.Codex Task
Summary by CodeRabbit