Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
b345cc2
docs: plan the 2.0 design system
TurtIeSocks Aug 24, 2026
7901b36
feat(app): load the display and body fonts
TurtIeSocks Aug 24, 2026
17dea94
feat(app): complete the token set and separate the data palette
TurtIeSocks Aug 24, 2026
72eddaa
docs: fix a dangling pointer in the data palette header
TurtIeSocks Aug 24, 2026
a8fd6cb
feat(app): wire up shadcn and lucide
TurtIeSocks Aug 24, 2026
2a0eeca
feat(app): use the in-game league colours
TurtIeSocks Aug 24, 2026
e80f0b4
feat(app): restyle the shell onto the design tokens
TurtIeSocks Aug 24, 2026
d4650a1
fix(app): lift the dark-mode primary so the active nav destination pa…
TurtIeSocks Aug 24, 2026
93d48f7
fix(app): restore the shadcn meaning of muted as a surface
TurtIeSocks Aug 24, 2026
4911f7a
fix(app): move the six placeholder pages onto the muted-foreground token
TurtIeSocks Aug 24, 2026
9c9ddce
fix(app): give borders and the card ring a boundary you can actually see
TurtIeSocks Aug 24, 2026
4ab676a
fix(app): make the card read its own radius token
TurtIeSocks Aug 24, 2026
cf05f6f
fix(app): flip the primary on-colour in dark and stabilise the button…
TurtIeSocks Aug 24, 2026
4ea03fa
fix(app): give destructive a dark value
TurtIeSocks Aug 24, 2026
058bb17
fix(build): stop documentation reaching the stylesheet
TurtIeSocks Aug 24, 2026
074636d
fix(app): stop the data palette being pruned out of the build
TurtIeSocks Aug 24, 2026
91fb277
chore(ui): install the full shadcn component set
TurtIeSocks Aug 24, 2026
408eb56
fix(ui): restore the local fixes the overwrite discarded
TurtIeSocks Aug 24, 2026
6c29017
feat(tokens): define the token families the component set expects
TurtIeSocks Aug 24, 2026
c73cf5d
fix(ui): satisfy exactOptionalPropertyTypes in the vendored components
TurtIeSocks Aug 24, 2026
33b53ec
chore(lint): format the vendored components and scope the rules they …
TurtIeSocks Aug 24, 2026
8daa1a5
docs(ui): flag the CSS injection path in the chart component
TurtIeSocks Aug 24, 2026
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
84 changes: 84 additions & 0 deletions app/components/ui/accordion.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import { cn } from '@app/lib/utils'
import { ChevronDownIcon, ChevronUpIcon } from 'lucide-react'
import { Accordion as AccordionPrimitive } from 'radix-ui'
import type * as React from 'react'

function Accordion({
className,
...props
}: React.ComponentProps<typeof AccordionPrimitive.Root>) {
return (
<AccordionPrimitive.Root
data-slot="accordion"
className={cn('flex w-full flex-col', className)}
{...props}
/>
)
}

function AccordionItem({
className,
...props
}: React.ComponentProps<typeof AccordionPrimitive.Item>) {
return (
<AccordionPrimitive.Item
data-slot="accordion-item"
className={cn('not-last:border-b', className)}
{...props}
/>
)
}

function AccordionTrigger({
className,
children,
...props
}: React.ComponentProps<typeof AccordionPrimitive.Trigger>) {
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-3 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',
className,
)}
{...props}
>
{children}
<ChevronDownIcon
data-slot="accordion-trigger-icon"
className="pointer-events-none shrink-0 group-aria-expanded/accordion-trigger:hidden"
/>
<ChevronUpIcon
data-slot="accordion-trigger-icon"
className="pointer-events-none hidden shrink-0 group-aria-expanded/accordion-trigger:inline"
/>
</AccordionPrimitive.Trigger>
</AccordionPrimitive.Header>
)
}

function AccordionContent({
className,
children,
...props
}: React.ComponentProps<typeof AccordionPrimitive.Content>) {
return (
<AccordionPrimitive.Content
data-slot="accordion-content"
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',
className,
)}
>
{children}
</div>
</AccordionPrimitive.Content>
)
}

export { Accordion, AccordionContent, AccordionItem, AccordionTrigger }
196 changes: 196 additions & 0 deletions app/components/ui/alert-dialog.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
import { Button } from '@app/components/ui/button'
import { cn } from '@app/lib/utils'
import { AlertDialog as AlertDialogPrimitive } from 'radix-ui'
import type * as React from 'react'

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

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

function AlertDialogPortal({
...props
}: React.ComponentProps<typeof AlertDialogPrimitive.Portal>) {
return (
<AlertDialogPrimitive.Portal data-slot="alert-dialog-portal" {...props} />
)
}

function AlertDialogOverlay({
className,
...props
}: React.ComponentProps<typeof AlertDialogPrimitive.Overlay>) {
return (
<AlertDialogPrimitive.Overlay
data-slot="alert-dialog-overlay"
className={cn(
'fixed inset-0 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}
/>
)
}

function AlertDialogContent({
className,
size = 'default',
...props
}: React.ComponentProps<typeof AlertDialogPrimitive.Content> & {
size?: 'default' | 'sm'
}) {
return (
<AlertDialogPortal>
<AlertDialogOverlay />
<AlertDialogPrimitive.Content
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-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 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}
/>
</AlertDialogPortal>
)
}

function AlertDialogHeader({
className,
...props
}: React.ComponentProps<'div'>) {
return (
<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]',
className,
)}
{...props}
/>
)
}

function AlertDialogFooter({
className,
...props
}: React.ComponentProps<'div'>) {
return (
<div
data-slot="alert-dialog-footer"
className={cn(
'-mx-4 -mb-4 flex flex-col-reverse gap-2 rounded-b-xl border-t bg-muted/50 p-4 group-data-[size=sm]/alert-dialog-content:grid group-data-[size=sm]/alert-dialog-content:grid-cols-2 sm:flex-row sm:justify-end',
className,
)}
{...props}
/>
)
}

function AlertDialogMedia({
className,
...props
}: React.ComponentProps<'div'>) {
return (
<div
data-slot="alert-dialog-media"
className={cn(
"mb-2 inline-flex size-10 items-center justify-center rounded-md bg-muted sm:group-data-[size=default]/alert-dialog-content:row-span-2 *:[svg:not([class*='size-'])]:size-6",
className,
)}
{...props}
/>
)
}

function AlertDialogTitle({
className,
...props
}: React.ComponentProps<typeof AlertDialogPrimitive.Title>) {
return (
<AlertDialogPrimitive.Title
data-slot="alert-dialog-title"
className={cn(
'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}
/>
)
}

function AlertDialogDescription({
className,
...props
}: React.ComponentProps<typeof AlertDialogPrimitive.Description>) {
return (
<AlertDialogPrimitive.Description
data-slot="alert-dialog-description"
className={cn(
'text-sm text-balance text-muted-foreground md:text-pretty *:[a]:underline *:[a]:underline-offset-3 *:[a]:hover:text-foreground',
className,
)}
{...props}
/>
)
}

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

function AlertDialogCancel({
className,
variant = 'outline',
size = 'default',
...props
}: React.ComponentProps<typeof AlertDialogPrimitive.Cancel> &
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>
)
}

export {
AlertDialog,
AlertDialogAction,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogMedia,
AlertDialogOverlay,
AlertDialogPortal,
AlertDialogTitle,
AlertDialogTrigger,
}
75 changes: 75 additions & 0 deletions app/components/ui/alert.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { cn } from '@app/lib/utils'
import { cva, type VariantProps } from 'class-variance-authority'
import type * as React from 'react'

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",
{
variants: {
variant: {
default: 'bg-card text-card-foreground',
destructive:
'bg-card text-destructive *:data-[slot=alert-description]:text-destructive/90 *:[svg]:text-current',
},
},
defaultVariants: {
variant: 'default',
},
},
)

function Alert({
className,
variant,
...props
}: React.ComponentProps<'div'> & VariantProps<typeof alertVariants>) {
return (
<div
data-slot="alert"
role="alert"
className={cn(alertVariants({ variant }), className)}
{...props}
/>
)
}

function AlertTitle({ className, ...props }: React.ComponentProps<'div'>) {
return (
<div
data-slot="alert-title"
className={cn(
'font-medium group-has-[>svg]/alert:col-start-2 [&_a]:underline [&_a]:underline-offset-3 [&_a]:hover:text-foreground',
className,
)}
{...props}
/>
)
}

function AlertDescription({
className,
...props
}: React.ComponentProps<'div'>) {
return (
<div
data-slot="alert-description"
className={cn(
'text-sm text-balance text-muted-foreground md:text-pretty [&_a]:underline [&_a]:underline-offset-3 [&_a]:hover:text-foreground [&_p:not(:last-child)]:mb-4',
className,
)}
{...props}
/>
)
}

function AlertAction({ className, ...props }: React.ComponentProps<'div'>) {
return (
<div
data-slot="alert-action"
className={cn('absolute top-2 right-2', className)}
{...props}
/>
)
}

export { Alert, AlertAction, AlertDescription, AlertTitle }
11 changes: 11 additions & 0 deletions app/components/ui/aspect-ratio.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
'use client'

import { AspectRatio as AspectRatioPrimitive } from 'radix-ui'

function AspectRatio({
...props
}: React.ComponentProps<typeof AspectRatioPrimitive.Root>) {
return <AspectRatioPrimitive.Root data-slot="aspect-ratio" {...props} />
}

export { AspectRatio }
Loading
Loading