A responsive settings page block with profile, notification, and security sections.
@corr
registry/corr/components/settings-page.tsx
"use client"
import * as React from "react"
import { BellIcon, ShieldIcon, UserIcon } from "lucide-react"
import { motion, useReducedMotion } from "motion/react"
import { Button } from "@/components/ui/button"
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card"
import { Field, FieldLabel } from "@/components/ui/field"
import { Input } from "@/components/ui/input"
import { Separator } from "@/components/ui/separator"
import { Switch } from "@/components/ui/switch"
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
export function SettingsPage({
defaultTab = "profile",
}: {
defaultTab?: "profile" | "notifications" | "security"
}) {
const reduceMotion = useReducedMotion()
const MotionSection = ({ children }: { children: React.ReactNode }) => (
<motion.div
initial={{ opacity: 0, y: reduceMotion ? 0 : 8 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: reduceMotion ? 0 : 0.18 }}
>
{children}
</motion.div>
)
return (
<div className="rounded-md border bg-card">
<div className="border-b p-4">
<h2 className="text-lg font-semibold">Settings</h2>
<p className="mt-1 text-sm text-muted-foreground">
Manage account details, notifications, and access controls.
</p>
</div>
<Tabs
defaultValue={defaultTab}
orientation="vertical"
className="grid gap-0 md:grid-cols-[14rem_minmax(0,1fr)]"
>
<div className="border-b p-3 md:border-r md:border-b-0">
<TabsList className="grid h-auto w-full grid-cols-3 md:grid-cols-1">
<TabsTrigger value="profile" className="justify-start">
<UserIcon className="size-4" />
Profile
</TabsTrigger>
<TabsTrigger value="notifications" className="justify-start">
<BellIcon className="size-4" />
Alerts
</TabsTrigger>
<TabsTrigger value="security" className="justify-start">
<ShieldIcon className="size-4" />
Security
</TabsTrigger>
</TabsList>
</div>
<div className="min-w-0 p-4">
<TabsContent value="profile" className="mt-0">
<MotionSection>
<Card>
<CardHeader>
<CardTitle>Profile</CardTitle>
<CardDescription>
Keep public account information up to date.
</CardDescription>
</CardHeader>
<CardContent className="grid gap-4 sm:grid-cols-2">
<Field>
<FieldLabel>Name</FieldLabel>
<Input defaultValue="Liam Corrigan" />
</Field>
<Field>
<FieldLabel>Email</FieldLabel>
<Input defaultValue="liam@example.com" />
</Field>
<div className="sm:col-span-2">
<Button>Save profile</Button>
</div>
</CardContent>
</Card>
</MotionSection>
</TabsContent>
<TabsContent value="notifications" className="mt-0">
<MotionSection>
<SettingsPanel
title="Notifications"
description="Choose which operational events should reach you."
rows={[
["Build updates", "Registry build status and failures."],
["Install events", "Notify when a component is installed."],
["Weekly summary", "A digest of usage and changes."],
]}
/>
</MotionSection>
</TabsContent>
<TabsContent value="security" className="mt-0">
<MotionSection>
<SettingsPanel
title="Security"
description="Control account protection and review prompts."
rows={[
["Two-factor authentication", "Require a second factor."],
["Session alerts", "Email when a new device signs in."],
["Destructive confirmations", "Confirm risky workspace actions."],
]}
/>
</MotionSection>
</TabsContent>
</div>
</Tabs>
</div>
)
}
function SettingsPanel({
title,
description,
rows,
}: {
title: string
description: string
rows: [string, string][]
}) {
return (
<Card>
<CardHeader>
<CardTitle>{title}</CardTitle>
<CardDescription>{description}</CardDescription>
</CardHeader>
<CardContent>
<div className="space-y-4">
{rows.map(([label, helper], index) => (
<React.Fragment key={label}>
{index > 0 ? <Separator /> : null}
<div className="flex items-center justify-between gap-4">
<div className="min-w-0">
<div className="text-sm font-medium">{label}</div>
<div className="mt-1 text-xs text-muted-foreground">
{helper}
</div>
</div>
<Switch defaultChecked={index !== rows.length - 1} />
</div>
</React.Fragment>
))}
</div>
</CardContent>
</Card>
)
}






























