Skip to content

Commit 10332ef

Browse files
kiwicoppleclaude
andcommitted
Convert website to modern shadcn/ui components
Major updates: - Updated all core components (Button, Avatar, Tabs, DropdownMenu, etc.) to latest shadcn/ui versions - Added modern components: Skeleton, Badge, Card, Separator, Toast with hooks - Modernized typography components to use semantic CSS variables (text-foreground, text-primary) - Replaced custom Loader with Skeleton component for better animations - Enhanced CopyButton using modern Button component patterns - Updated Spinner with size variants and consistent theming - Fixed import system to use lowercase naming convention and named exports - Improved theming with CSS variables instead of hardcoded dark mode classes - Added better accessibility features across all components Breaking changes resolved: - Updated Avatar component size handling with CSS classes - Fixed component imports to use named exports where required - Resolved case-sensitivity issues in file naming - Updated toast system path references All components now follow latest shadcn/ui conventions and patterns. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
1 parent 0049343 commit 10332ef

35 files changed

+3726
-1285
lines changed

website/components/access-tokens/AccessTokenCard.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import dayjs from 'dayjs'
22
import { toast } from 'react-hot-toast'
33
import { useDeleteAccessTokenMutation } from '~/data/access-tokens/delete-access-token'
4-
import { Button } from '~/components/ui/Button'
4+
import { Button } from '~/components/ui/button'
55

66
export interface ApiTokenCardProps {
77
tokenId: string

website/components/forms/FormButton.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { forwardRef } from 'react'
22
import { useFormState } from 'react-final-form'
33
import { cn } from '~/lib/utils'
4-
import { Button, ButtonProps } from '~/components/ui/Button'
4+
import { Button, ButtonProps } from '~/components/ui/button'
55

66
export interface FormButtonProps extends ButtonProps {}
77

website/components/forms/FormInput.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { ComponentPropsWithoutRef, forwardRef, PropsWithoutRef } from 'react'
22
import { useField, UseFieldConfig } from 'react-final-form'
33
import { Input } from '~/components/ui/input'
4-
import Label from '../ui/Label'
4+
import { Label } from '../ui/label'
55
import { cn } from '~/lib/utils'
66

77
export interface FormInputProps

website/components/layouts/Navbar.tsx

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,22 @@ import { useRouter } from 'next/router'
33
import { useCallback, useMemo } from 'react'
44
import { toast } from 'react-hot-toast'
55
import Search from '~/components/search/Search'
6-
import { Avatar, AvatarFallback, AvatarImage } from '~/components/ui/Avatar'
7-
import DropdownMenu, {
6+
import { Avatar, AvatarFallback, AvatarImage } from '~/components/ui/avatar'
7+
import {
8+
DropdownMenu,
89
DropdownMenuContent,
910
DropdownMenuItem,
1011
DropdownMenuLabel,
1112
DropdownMenuSeparator,
1213
DropdownMenuTrigger,
13-
} from '~/components/ui/DropdownMenu'
14+
} from '~/components/ui/dropdown-menu'
1415
import { useSignOutMutation } from '~/data/auth/sign-out-mutation'
1516
import { useUsersOrganizationsQuery } from '~/data/organizations/users-organizations-query'
1617
import { useUser } from '~/lib/auth'
1718
import { getAvatarUrl } from '~/lib/avatars'
1819
import { useTheme } from '../themes/ThemeContext'
1920
import ThemeSwitcher from '../themes/ThemeSwitcher'
20-
import { Button } from '~/components/ui/Button'
21+
import { Button } from '~/components/ui/button'
2122

2223
const Navbar = () => {
2324
const router = useRouter()
@@ -66,11 +67,15 @@ const Navbar = () => {
6667

6768
const AvatarWrapper = ({ size = 'sm' }: { size?: 'sm' | 'md' }) =>
6869
user?.user_metadata.avatar_path === undefined ? (
69-
<div className="flex items-center justify-center w-6 h-6 text-gray-600 bg-gray-300 border-gray-400 rounded-full border-1 dark:border-slate-400 dark:bg-slate-500 dark:text-white">
70+
<div
71+
className={`flex items-center justify-center text-gray-600 bg-gray-300 border-gray-400 rounded-full border-1 dark:border-slate-400 dark:bg-slate-500 dark:text-white ${size === 'sm' ? 'w-6 h-6' : 'w-10 h-10'}`}
72+
>
7073
{displayName[0].toUpperCase()}
7174
</div>
7275
) : (
73-
<Avatar size={size} className="border dark:border-slate-700">
76+
<Avatar
77+
className={`border dark:border-slate-700 ${size === 'sm' ? 'w-6 h-6' : 'w-10 h-10'}`}
78+
>
7479
<AvatarImage src={avatarUrl} alt={avatarName} />
7580
<AvatarFallback>{avatarFallback}</AvatarFallback>
7681
</Avatar>

website/components/ui/Avatar.tsx

Lines changed: 22 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,68 +1,48 @@
1-
'use client'
2-
1+
import * as React from 'react'
32
import * as AvatarPrimitive from '@radix-ui/react-avatar'
4-
import { cva, VariantProps } from 'class-variance-authority'
5-
import { ComponentPropsWithoutRef, ElementRef, forwardRef } from 'react'
6-
import { cn } from '~/lib/utils'
7-
8-
const avatarVariants = cva(
9-
'relative flex shrink-0 overflow-hidden rounded-full',
10-
{
11-
variants: {
12-
size: {
13-
sm: 'w-6 h-6',
14-
md: 'w-10 h-10',
15-
},
16-
},
17-
defaultVariants: {
18-
size: 'md',
19-
},
20-
}
21-
)
22-
23-
export interface AvatarProps
24-
extends ComponentPropsWithoutRef<typeof AvatarPrimitive.Root>,
25-
VariantProps<typeof avatarVariants> {}
263

27-
const Avatar = forwardRef<ElementRef<typeof AvatarPrimitive.Root>, AvatarProps>(
28-
({ className, size, ...props }, ref) => (
29-
<AvatarPrimitive.Root
30-
ref={ref}
31-
className={cn(avatarVariants({ size, className }))}
32-
{...props}
33-
/>
34-
)
35-
)
4+
import { cn } from '~/lib/utils'
365

6+
const Avatar = React.forwardRef<
7+
React.ElementRef<typeof AvatarPrimitive.Root>,
8+
React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Root>
9+
>(({ className, ...props }, ref) => (
10+
<AvatarPrimitive.Root
11+
ref={ref}
12+
className={cn(
13+
'relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full',
14+
className
15+
)}
16+
{...props}
17+
/>
18+
))
3719
Avatar.displayName = AvatarPrimitive.Root.displayName
3820

39-
const AvatarImage = forwardRef<
40-
ElementRef<typeof AvatarPrimitive.Image>,
41-
ComponentPropsWithoutRef<typeof AvatarPrimitive.Image>
21+
const AvatarImage = React.forwardRef<
22+
React.ElementRef<typeof AvatarPrimitive.Image>,
23+
React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Image>
4224
>(({ className, ...props }, ref) => (
4325
<AvatarPrimitive.Image
4426
ref={ref}
4527
className={cn('aspect-square h-full w-full', className)}
4628
{...props}
4729
/>
4830
))
49-
5031
AvatarImage.displayName = AvatarPrimitive.Image.displayName
5132

52-
const AvatarFallback = forwardRef<
53-
ElementRef<typeof AvatarPrimitive.Fallback>,
54-
ComponentPropsWithoutRef<typeof AvatarPrimitive.Fallback>
33+
const AvatarFallback = React.forwardRef<
34+
React.ElementRef<typeof AvatarPrimitive.Fallback>,
35+
React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Fallback>
5536
>(({ className, ...props }, ref) => (
5637
<AvatarPrimitive.Fallback
5738
ref={ref}
5839
className={cn(
59-
'flex h-full w-full items-center justify-center rounded-full bg-slate-100 dark:bg-slate-700',
40+
'flex h-full w-full items-center justify-center rounded-full bg-muted',
6041
className
6142
)}
6243
{...props}
6344
/>
6445
))
65-
6646
AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName
6747

6848
export { Avatar, AvatarImage, AvatarFallback }

website/components/ui/Button.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { cva, type VariantProps } from 'class-variance-authority'
55
import { cn } from '~/lib/utils'
66

77
const buttonVariants = cva(
8-
'inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50',
8+
'inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0',
99
{
1010
variants: {
1111
variant: {

website/components/ui/CopyButton.tsx

Lines changed: 12 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,26 +4,11 @@ import { CheckIcon, ClipboardDocumentIcon } from '@heroicons/react/24/outline'
44
import { cva, VariantProps } from 'class-variance-authority'
55
import { HTMLAttributes, useEffect, useState } from 'react'
66
import { cn } from '~/lib/utils'
7+
import { Button } from './button'
78

8-
export const copyButtonVariants = cva(
9-
'inline-flex items-center justify-center rounded-md p-2 text-sm font-medium transition-all',
10-
{
11-
variants: {
12-
variant: {
13-
light: 'text-slate-900 border-slate-200 hover:bg-slate-100',
14-
dark: 'text-white border-slate-900 hover:bg-slate-900',
15-
},
16-
},
17-
defaultVariants: {
18-
variant: 'light',
19-
},
20-
}
21-
)
22-
23-
interface CopyButtonProps
24-
extends HTMLAttributes<HTMLButtonElement>,
25-
VariantProps<typeof copyButtonVariants> {
9+
interface CopyButtonProps extends HTMLAttributes<HTMLButtonElement> {
2610
getValue: () => string
11+
variant?: 'light' | 'dark'
2712
}
2813

2914
async function copyToClipboardWithMeta(value: string) {
@@ -33,7 +18,7 @@ async function copyToClipboardWithMeta(value: string) {
3318
const CopyButton = ({
3419
getValue,
3520
className,
36-
variant,
21+
variant = 'light',
3722
...props
3823
}: CopyButtonProps) => {
3924
const [hasCopied, setHasCopied] = useState(false)
@@ -54,10 +39,12 @@ const CopyButton = ({
5439
}, [hasCopied])
5540

5641
return (
57-
<button
42+
<Button
43+
variant="ghost"
44+
size="icon"
5845
className={cn(
59-
copyButtonVariants({ variant }),
60-
'bg-gray-50 text-slate-700 dark:text-slate-100 dark:bg-gray-700 dark:hover:bg-gray-900 transition-colors',
46+
'h-8 w-8',
47+
variant === 'dark' && 'text-muted-foreground hover:text-foreground',
6148
className
6249
)}
6350
onClick={() => {
@@ -68,11 +55,11 @@ const CopyButton = ({
6855
>
6956
<span className="sr-only">Copy</span>
7057
{hasCopied ? (
71-
<CheckIcon className="w-5 h-5" />
58+
<CheckIcon className="h-4 w-4" />
7259
) : (
73-
<ClipboardDocumentIcon className="w-5 h-5" />
60+
<ClipboardDocumentIcon className="h-4 w-4" />
7461
)}
75-
</button>
62+
</Button>
7663
)
7764
}
7865

0 commit comments

Comments
 (0)