Account settings card
Setup
npx shadcn@latest add card switch label separator
npm install next-themes
Wrap your app in the theme provider once (for example in app/layout.tsx). Add suppressHydrationWarning to <html>.
import { ThemeProvider } from "next-themes"
<ThemeProvider attribute="class" defaultTheme="system" enableSystem disableTransitionOnChange>
{children}
</ThemeProvider>
components/account-settings-card.tsx
"use client"
import * as React from "react"
import { useTheme } from "next-themes"
import { Moon, Sun, Bell } from "lucide-react"
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card"
import { Label } from "@/components/ui/label"
import { Separator } from "@/components/ui/separator"
import { Switch } from "@/components/ui/switch"
export function AccountSettingsCard() {
const { resolvedTheme, setTheme } = useTheme()
const [mounted, setMounted] = React.useState(false)
const [notifications, setNotifications] = React.useState(true)
// The theme is unknown on the server, so wait for mount to avoid a hydration mismatch.
React.useEffect(() => setMounted(true), [])
const isDark = mounted && resolvedTheme === "dark"
return (
<Card className="mx-auto w-full max-w-sm shadow-sm transition-shadow hover:shadow-md sm:max-w-md lg:max-w-lg">
<CardHeader className="space-y-1 p-4 sm:p-6">
<CardTitle className="text-xl font-semibold tracking-tight sm:text-2xl">
Account settings
</CardTitle>
<CardDescription>Manage your appearance and alerts.</CardDescription>
</CardHeader>
<CardContent className="space-y-4 p-4 pt-0 sm:p-6 sm:pt-0">
<Separator />
{/* Dark mode */}
<div className="flex items-center justify-between gap-4">
<div className="flex items-start gap-3">
<div className="rounded-md bg-muted p-2 text-muted-foreground">
{isDark ? <Moon className="size-4" /> : <Sun className="size-4" />}
</div>
<div className="space-y-0.5">
<Label htmlFor="dark-mode" className="text-sm font-medium">
Dark mode
</Label>
<p className="text-sm text-muted-foreground">
Switch between light and dark themes.
</p>
</div>
</div>
<Switch
id="dark-mode"
checked={isDark}
disabled={!mounted}
onCheckedChange={(checked) => setTheme(checked ? "dark" : "light")}
/>
</div>
<Separator />
{/* Notifications */}
<div className="flex items-center justify-between gap-4">
<div className="flex items-start gap-3">
<div className="rounded-md bg-muted p-2 text-muted-foreground">
<Bell className="size-4" />
</div>
<div className="space-y-0.5">
<Label htmlFor="notifications" className="text-sm font-medium">
Notifications
</Label>
<p className="text-sm text-muted-foreground">
Get email updates about account activity.
</p>
</div>
</div>
<Switch
id="notifications"
checked={notifications}
onCheckedChange={setNotifications}
/>
</div>
</CardContent>
</Card>
)
}
Key utility classes
Responsive sizing
w-full max-w-sm sm:max-w-md lg:max-w-lg mx-auto: the card fills narrow screens, then caps its width at each breakpoint.mx-autocenters it. The styles are mobile-first, so the unprefixed classes apply to phones andsm:/lg:layer on top.p-4 sm:p-6: tighter padding on phones, roomier from 640px up.pt-0 sm:pt-0stopsCardContent's default top padding from stacking on the header's bottom padding.text-xl sm:text-2xl: the title scales up with the viewport.
Row layout
flex items-center justify-between gap-4: the label block sits on the left and the switch is pushed to the right edge.gap-4keeps long text from touching the switch.flex items-start gap-3: the icon aligns with the top of the two-line label and description.space-y-0.5/space-y-4: vertical rhythm between children, with no margins on individual elements.
Theme-aware colors
bg-muted,text-muted-foreground: these are shadcn semantic tokens backed by CSS variables, which.darkredefines. The card therefore re-themes without anydark:prefixes. Reach fordark:only for one-off overrides.rounded-md p-2: a small tinted square behind each icon.size-4: shorthand forw-4 h-4on the icons (Tailwind 3.4+).
Polish
shadow-sm hover:shadow-md transition-shadow: a subtle lift on hover, animating only the shadow.tracking-tight font-semibold: tighter, bolder heading text.
Accessibility and behavior notes
- Each
Label htmlFormatches itsSwitch id, so clicking the text toggles the switch. Radix'sSwitchsuppliesrole="switch",aria-checked, Space-key toggling and focus rings. resolvedThemefollows the OS preference when the theme issystem. The first toggle then pins an explicitlightordark.- The
notificationsstate is local. ReplacesetNotificationswith a call to your API or form action to persist it.
I haven't run this, since there's no project scaffold in the working directory. If you'd like, I can write it into a Vite or Next app here and check it in the browser.
Real run in an isolated folder with only this skill installed. Only the Skill and Read tools were enabled; the model answered from SKILL.md without opening the reference files, and no bundled script was run.
하는 일
shadcn/ui(Radix UI + Tailwind CSS) 스택으로 인터페이스를 만드는 방법을 모델에게 알려 줍니다. 컴포넌트 설치, 폼·대화상자·테이블·내비게이션 구성, 모바일 우선 반응형 레이아웃, 다크 모드와 테마, Tailwind 커스터마이징(@theme 지시문, 사용자 정의 유틸리티, 레이어)을 다룹니다. 캔버스 기반 포스터와 비주얼 디자인 접근법을 설명하는 참고 문서도 있습니다.
동작 방식
SKILL.md에 스택 개요, 빠른 시작(npx shadcn@latest init,add), 자주 쓰는 패턴, 참고 문서 링크가 있습니다.- 모델이 필요할 때 해당 참고 문서(컴포넌트 목록, 테마, 접근성, Tailwind 유틸리티, 반응형, 커스터마이징, 캔버스 디자인)를 엽니다.
- 선택형 보조 스크립트가 두 개 있습니다. 하나는
npx로 shadcn 컴포넌트를 추가하고, 다른 하나는 사용자 정의 색상과 글꼴이 들어간tailwind.config.js를 생성합니다.
이런 때 좋습니다
React, Next.js, Vite, Remix, Astro 인터페이스를 만들거나 새로 꾸밀 때, 접근성 있는 컴포넌트를 추가할 때, 다크 모드와 디자인 토큰을 구현할 때.
Python 보조 스크립트 두 개가 들어 있습니다. `shadcn_add.py`는 지정한 프로젝트 디렉터리에서 `npx shadcn@<버전> add ...`를 실행합니다. npm에서 내려받으므로(네트워크 사용) 컴포넌트 파일이 프로젝트에 기록됩니다. 이미 있는 컴포넌트는 `--overwrite`를 붙이지 않으면 다시 설치하지 않으며 `--dry-run`으로 미리 볼 수 있습니다. `tailwind_config_gen.py`는 Tailwind 설정 파일을 쓰며, 다른 `tailwind.config.*`가 이미 있으면 `--force` 없이는 만들거나 교체하지 않습니다. 실행 전에 작업 내용을 커밋하고, 생성된 파일은 diff를 확인한 뒤 유지하세요. 계정이나 키는 필요 없습니다. 이 사이트의 등록본에는 동봉된 캔버스용 글꼴 파일(선택형 캔버스 디자인에서는 직접 가진 글꼴을 쓰게 됩니다)과 테스트 파일이 빠져 있습니다.