Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions components.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"$schema": "https://ui.shadcn.com/schema.json",
"style": "radix-nova",
"style": "base-nova",
"rsc": false,
"tsx": true,
"tailwind": {
Expand All @@ -10,14 +10,15 @@
"cssVariables": true,
"prefix": ""
},
"iconLibrary": "lucide",
"rtl": true,
"aliases": {
"components": "~/ui/components",
"utils": "~/ui/utils",
"ui": "~/ui/components/core",
"lib": "~/lib",
"hooks": "~/ui/hooks"
},
"iconLibrary": "lucide",
"menuColor": "default",
"menuAccent": "subtle",
"registries": {}
Expand Down
1 change: 1 addition & 0 deletions oxlint.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ export default defineConfig({
'jsx-a11y/aria-role': 'error',
'jsx-a11y/aria-unsupported-elements': 'error',
'jsx-a11y/autocomplete-valid': 'error',
'jsx-a11y/click-events-have-key-events': 'off',
'jsx-a11y/heading-has-content': 'error',
'jsx-a11y/html-has-lang': 'error',
'jsx-a11y/iframe-has-title': 'error',
Expand Down
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
"changeset:publish": "changeset publish"
},
"dependencies": {
"@base-ui/react": "^1.4.1",
"@better-auth/drizzle-adapter": "^1.6.9",
"@devsantara/head": "^0.4.1",
"@fontsource-variable/geist": "^5.2.8",
Expand All @@ -69,12 +70,12 @@
"next-themes": "^0.4.6",
"posthog-js": "^1.372.5",
"posthog-node": "^5.32.0",
"radix-ui": "^1.4.3",
"react": "^19.2.5",
"react-day-picker": "^9.14.0",
"react-dom": "^19.2.5",
"react-resizable-panels": "^4.10.0",
"recharts": "3.8.1",
"recharts": "3.8.0",
"shadcn": "^4.6.0",
"sonner": "^2.0.7",
"tailwind-merge": "^3.5.0",
"tailwindcss": "^4.2.4",
Expand Down
3,366 changes: 1,780 additions & 1,586 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

7 changes: 5 additions & 2 deletions src/lib/form/components/form-select.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,10 @@ export function FormSelect({
const id = field.name;
const isDisabled = fieldSet?.disabled || disabled;

function handleValueChange(value: string) {
function handleValueChange(value: string | null) {
if (value === null) {
return;
}
field.handleChange(value);
}

Expand All @@ -53,7 +56,7 @@ export function FormSelect({
>
<SelectValue placeholder={placeholder} />
</SelectTrigger>
<SelectContent position="popper">
<SelectContent>
<SelectGroup>
{options.map((option) => {
return (
Expand Down
5 changes: 4 additions & 1 deletion src/routes/__root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
} from '~/lib/i18n/runtime';
import { PostHogProvider } from '~/lib/posthog/provider';
import { Toaster } from '~/ui/components/core/sonner';
import { TooltipProvider } from '~/ui/components/core/tooltip';
import { ThemeProvider } from '~/ui/styles/theme';

import appStylesheet from '~/ui/styles/app.css?url';
Expand Down Expand Up @@ -116,7 +117,9 @@ function RootDocument({ children }: { children: React.ReactNode }) {
<body>
<ThemeProvider>
<Toaster />
<PostHogProvider>{children}</PostHogProvider>
<PostHogProvider>
<TooltipProvider>{children}</TooltipProvider>
</PostHogProvider>
<TanStackDevtools
config={{ position: 'bottom-right' }}
plugins={[tanstackRouterDevtools, tanstackFormDevtools]}
Expand Down
13 changes: 7 additions & 6 deletions src/routes/app/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { HomeIcon } from 'lucide-react';

import { authClient } from '~/lib/auth/client';
import { m } from '~/lib/i18n/messages';
import { Button } from '~/ui/components/core/button';
import { Button, buttonVariants } from '~/ui/components/core/button';
import { Separator } from '~/ui/components/core/separator';
import { toast } from '~/ui/components/core/sonner';

Expand Down Expand Up @@ -41,11 +41,12 @@ function RouteComponent() {
<Separator className="my-3" />

<div className="flex items-center justify-center gap-2">
<Button asChild size="icon" variant="outline">
<Link to="/">
<HomeIcon />
</Link>
</Button>
<Link
to="/"
className={buttonVariants({ variant: 'outline', size: 'icon' })}
>
<HomeIcon />
</Link>
<Button size="lg" variant="destructive" onClick={handleSignOut}>
{m.auth_sign_out_action()}
</Button>
Expand Down
25 changes: 15 additions & 10 deletions src/routes/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ import { createFileRoute, Link } from '@tanstack/react-router';

import { authClient } from '~/lib/auth/client';
import { m } from '~/lib/i18n/messages';
import { Button } from '~/ui/components/core/button';
import { buttonVariants } from '~/ui/components/core/button';
import { Skeleton } from '~/ui/components/core/skeleton';
import { cn } from '~/ui/utils';

export const Route = createFileRoute('/')({
component: HomePage,
Expand All @@ -30,15 +31,19 @@ function HomePage() {
{isPendingSession ? (
<Skeleton className="h-9 min-w-40" />
) : (
<Button asChild size="lg" variant="default" className="min-w-40">
<Link to={session?.user ? '/app' : '/auth'}>
{!session?.user
? m.auth_get_started_action()
: m.common_continue_as_name({
name: String(session.user.name.split(' ')[0]),
})}
</Link>
</Button>
<Link
to={session?.user ? '/app' : '/auth'}
className={cn(
buttonVariants({ variant: 'default', size: 'lg' }),
'min-w-40',
)}
>
{!session?.user
? m.auth_get_started_action()
: m.common_continue_as_name({
name: String(session.user.name.split(' ')[0]),
})}
</Link>
)}
</div>
</header>
Expand Down
27 changes: 10 additions & 17 deletions src/ui/components/core/accordion.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
import { Accordion as AccordionPrimitive } from '@base-ui/react/accordion';
import { ChevronDownIcon, ChevronUpIcon } from 'lucide-react';
import { Accordion as AccordionPrimitive } from 'radix-ui';
import * as React from 'react';

import { cn } from '~/ui/utils';

function Accordion({
className,
...props
}: React.ComponentProps<typeof AccordionPrimitive.Root>) {
function Accordion({ className, ...props }: AccordionPrimitive.Root.Props) {
return (
<AccordionPrimitive.Root
data-slot="accordion"
Expand All @@ -17,10 +13,7 @@ function Accordion({
);
}

function AccordionItem({
className,
...props
}: React.ComponentProps<typeof AccordionPrimitive.Item>) {
function AccordionItem({ className, ...props }: AccordionPrimitive.Item.Props) {
return (
<AccordionPrimitive.Item
data-slot="accordion-item"
Expand All @@ -34,13 +27,13 @@ function AccordionTrigger({
className,
children,
...props
}: React.ComponentProps<typeof AccordionPrimitive.Trigger>) {
}: AccordionPrimitive.Trigger.Props) {
return (
<AccordionPrimitive.Header className="flex">
<AccordionPrimitive.Trigger
data-slot="accordion-trigger"
className={cn(
'group/accordion-trigger relative flex flex-1 items-start justify-between rounded-lg border border-transparent py-2.5 text-left text-sm font-medium transition-all outline-none hover:underline focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 focus-visible:after:border-ring disabled:pointer-events-none disabled:opacity-50 **:data-[slot=accordion-trigger-icon]:ml-auto **:data-[slot=accordion-trigger-icon]:size-4 **:data-[slot=accordion-trigger-icon]:text-muted-foreground',
'group/accordion-trigger relative flex flex-1 items-start justify-between rounded-lg border border-transparent py-2.5 text-start text-sm font-medium transition-all outline-none hover:underline focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 focus-visible:after:border-ring aria-disabled:pointer-events-none aria-disabled:opacity-50 **:data-[slot=accordion-trigger-icon]:ms-auto **:data-[slot=accordion-trigger-icon]:size-4 **:data-[slot=accordion-trigger-icon]:text-muted-foreground',
className,
)}
{...props}
Expand All @@ -63,22 +56,22 @@ function AccordionContent({
className,
children,
...props
}: React.ComponentProps<typeof AccordionPrimitive.Content>) {
}: AccordionPrimitive.Panel.Props) {
return (
<AccordionPrimitive.Content
<AccordionPrimitive.Panel
data-slot="accordion-content"
className="overflow-hidden text-sm data-closed:animate-accordion-up data-open:animate-accordion-down"
className="overflow-hidden text-sm data-open:animate-accordion-down data-closed:animate-accordion-up"
{...props}
>
<div
className={cn(
'h-(--radix-accordion-content-height) pt-0 pb-2.5 [&_a]:underline [&_a]:underline-offset-3 [&_a]:hover:text-foreground [&_p:not(:last-child)]:mb-4',
'h-(--accordion-panel-height) pt-0 pb-2.5 data-ending-style:h-0 data-starting-style:h-0 [&_a]:underline [&_a]:underline-offset-3 [&_a]:hover:text-foreground [&_p:not(:last-child)]:mb-4',
className,
)}
>
{children}
</div>
</AccordionPrimitive.Content>
</AccordionPrimitive.Panel>
);
}

Expand Down
62 changes: 25 additions & 37 deletions src/ui/components/core/alert-dialog.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,20 @@
import { AlertDialog as AlertDialogPrimitive } from 'radix-ui';
import { AlertDialog as AlertDialogPrimitive } from '@base-ui/react/alert-dialog';
import * as React from 'react';

import { Button } from '~/ui/components/core/button';
import { cn } from '~/ui/utils';

function AlertDialog({
...props
}: React.ComponentProps<typeof AlertDialogPrimitive.Root>) {
function AlertDialog({ ...props }: AlertDialogPrimitive.Root.Props) {
return <AlertDialogPrimitive.Root data-slot="alert-dialog" {...props} />;
}

function AlertDialogTrigger({
...props
}: React.ComponentProps<typeof AlertDialogPrimitive.Trigger>) {
function AlertDialogTrigger({ ...props }: AlertDialogPrimitive.Trigger.Props) {
return (
<AlertDialogPrimitive.Trigger data-slot="alert-dialog-trigger" {...props} />
);
}

function AlertDialogPortal({
...props
}: React.ComponentProps<typeof AlertDialogPrimitive.Portal>) {
function AlertDialogPortal({ ...props }: AlertDialogPrimitive.Portal.Props) {
return (
<AlertDialogPrimitive.Portal data-slot="alert-dialog-portal" {...props} />
);
Expand All @@ -29,12 +23,12 @@ function AlertDialogPortal({
function AlertDialogOverlay({
className,
...props
}: React.ComponentProps<typeof AlertDialogPrimitive.Overlay>) {
}: AlertDialogPrimitive.Backdrop.Props) {
return (
<AlertDialogPrimitive.Overlay
<AlertDialogPrimitive.Backdrop
data-slot="alert-dialog-overlay"
className={cn(
'fixed inset-0 z-50 bg-black/10 duration-100 data-closed:animate-out data-closed:fade-out-0 data-open:animate-in data-open:fade-in-0 supports-backdrop-filter:backdrop-blur-xs',
'fixed inset-0 isolate z-50 bg-black/10 duration-100 supports-backdrop-filter:backdrop-blur-xs data-open:animate-in data-open:fade-in-0 data-closed:animate-out data-closed:fade-out-0',
className,
)}
{...props}
Expand All @@ -46,17 +40,17 @@ function AlertDialogContent({
className,
size = 'default',
...props
}: React.ComponentProps<typeof AlertDialogPrimitive.Content> & {
}: AlertDialogPrimitive.Popup.Props & {
size?: 'default' | 'sm';
}) {
return (
<AlertDialogPortal>
<AlertDialogOverlay />
<AlertDialogPrimitive.Content
<AlertDialogPrimitive.Popup
data-slot="alert-dialog-content"
data-size={size}
className={cn(
'group/alert-dialog-content fixed top-1/2 left-1/2 z-50 grid w-full -translate-x-1/2 -translate-y-1/2 gap-4 rounded-xl bg-background p-4 ring-1 ring-foreground/10 duration-100 outline-none data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-[size=default]:max-w-xs data-[size=sm]:max-w-xs data-[size=default]:sm:max-w-sm',
'group/alert-dialog-content fixed start-1/2 top-1/2 z-50 grid w-full -translate-x-1/2 -translate-y-1/2 gap-4 rounded-xl bg-popover p-4 text-popover-foreground ring-1 ring-foreground/10 duration-100 outline-none data-[size=default]:max-w-xs data-[size=sm]:max-w-xs data-[size=default]:sm:max-w-sm rtl:translate-x-1/2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95',
className,
)}
{...props}
Expand All @@ -73,7 +67,7 @@ function AlertDialogHeader({
<div
data-slot="alert-dialog-header"
className={cn(
'grid grid-rows-[auto_1fr] place-items-center gap-1.5 text-center has-data-[slot=alert-dialog-media]:grid-rows-[auto_auto_1fr] has-data-[slot=alert-dialog-media]:gap-x-4 sm:group-data-[size=default]/alert-dialog-content:place-items-start sm:group-data-[size=default]/alert-dialog-content:text-left sm:group-data-[size=default]/alert-dialog-content:has-data-[slot=alert-dialog-media]:grid-rows-[auto_1fr]',
'grid grid-rows-[auto_1fr] place-items-center gap-1.5 text-center has-data-[slot=alert-dialog-media]:grid-rows-[auto_auto_1fr] has-data-[slot=alert-dialog-media]:gap-x-4 sm:group-data-[size=default]/alert-dialog-content:place-items-start sm:group-data-[size=default]/alert-dialog-content:text-start sm:group-data-[size=default]/alert-dialog-content:has-data-[slot=alert-dialog-media]:grid-rows-[auto_1fr]',
className,
)}
{...props}
Expand Down Expand Up @@ -121,7 +115,7 @@ function AlertDialogTitle({
<AlertDialogPrimitive.Title
data-slot="alert-dialog-title"
className={cn(
'text-base font-medium sm:group-data-[size=default]/alert-dialog-content:group-has-data-[slot=alert-dialog-media]/alert-dialog-content:col-start-2',
'font-heading text-base font-medium sm:group-data-[size=default]/alert-dialog-content:group-has-data-[slot=alert-dialog-media]/alert-dialog-content:col-start-2',
className,
)}
{...props}
Expand All @@ -147,19 +141,14 @@ function AlertDialogDescription({

function AlertDialogAction({
className,
variant = 'default',
size = 'default',
...props
}: React.ComponentProps<typeof AlertDialogPrimitive.Action> &
Pick<React.ComponentProps<typeof Button>, 'variant' | 'size'>) {
}: React.ComponentProps<typeof Button>) {
return (
<Button variant={variant} size={size} asChild>
<AlertDialogPrimitive.Action
data-slot="alert-dialog-action"
className={cn(className)}
{...props}
/>
</Button>
<Button
data-slot="alert-dialog-action"
className={cn(className)}
{...props}
/>
);
}

Expand All @@ -168,16 +157,15 @@ function AlertDialogCancel({
variant = 'outline',
size = 'default',
...props
}: React.ComponentProps<typeof AlertDialogPrimitive.Cancel> &
}: AlertDialogPrimitive.Close.Props &
Pick<React.ComponentProps<typeof Button>, 'variant' | 'size'>) {
return (
<Button variant={variant} size={size} asChild>
<AlertDialogPrimitive.Cancel
data-slot="alert-dialog-cancel"
className={cn(className)}
{...props}
/>
</Button>
<AlertDialogPrimitive.Close
data-slot="alert-dialog-cancel"
className={cn(className)}
render={<Button variant={variant} size={size} />}
{...props}
/>
);
}

Expand Down
4 changes: 2 additions & 2 deletions src/ui/components/core/alert.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import * as React from 'react';
import { cn } from '~/ui/utils';

const alertVariants = cva(
"group/alert relative grid w-full gap-0.5 rounded-lg border px-2.5 py-2 text-left text-sm has-data-[slot=alert-action]:relative has-data-[slot=alert-action]:pr-18 has-[>svg]:grid-cols-[auto_1fr] has-[>svg]:gap-x-2 *:[svg]:row-span-2 *:[svg]:translate-y-0.5 *:[svg]:text-current *:[svg:not([class*='size-'])]:size-4",
"group/alert relative grid w-full gap-0.5 rounded-lg border px-2.5 py-2 text-start text-sm has-data-[slot=alert-action]:relative has-data-[slot=alert-action]:pe-18 has-[>svg]:grid-cols-[auto_1fr] has-[>svg]:gap-x-2 *:[svg]:row-span-2 *:[svg]:translate-y-0.5 *:[svg]:text-current *:[svg:not([class*='size-'])]:size-4",
{
variants: {
variant: {
Expand Down Expand Up @@ -67,7 +67,7 @@ function AlertAction({ className, ...props }: React.ComponentProps<'div'>) {
return (
<div
data-slot="alert-action"
className={cn('absolute top-2 right-2', className)}
className={cn('absolute end-2 top-2', className)}
{...props}
/>
);
Expand Down
Loading