snapshot of https://github.com/shadcn-ui/ui.git (main, 2026-09-15; blobs > 131072B omitted)
This commit is contained in:
@@ -0,0 +1,104 @@
|
||||
"use client"
|
||||
|
||||
import { Button } from "@/registry/bases/radix/ui/button"
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardFooter,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/registry/bases/radix/ui/card"
|
||||
import { Field, FieldGroup, FieldLabel } from "@/registry/bases/radix/ui/field"
|
||||
import { Input } from "@/registry/bases/radix/ui/input"
|
||||
import {
|
||||
Item,
|
||||
ItemContent,
|
||||
ItemDescription,
|
||||
ItemMedia,
|
||||
ItemTitle,
|
||||
} from "@/registry/bases/radix/ui/item"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
export function AccountAccess() {
|
||||
return (
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Account Access</CardTitle>
|
||||
<CardDescription>
|
||||
Update your credentials or re-authenticate.
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<FieldGroup>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="email-address">Email Address</FieldLabel>
|
||||
<Input
|
||||
id="email-address"
|
||||
type="email"
|
||||
defaultValue="artist@studio.inc"
|
||||
/>
|
||||
</Field>
|
||||
<Field>
|
||||
<div className="flex items-center justify-between">
|
||||
<FieldLabel htmlFor="current-password">
|
||||
Current Password
|
||||
</FieldLabel>
|
||||
<a
|
||||
href="#"
|
||||
className="text-xs font-medium tracking-wider text-muted-foreground uppercase hover:text-foreground"
|
||||
>
|
||||
Forgot?
|
||||
</a>
|
||||
</div>
|
||||
<Input
|
||||
id="current-password"
|
||||
type="password"
|
||||
defaultValue="password123"
|
||||
/>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</CardContent>
|
||||
<CardFooter className="flex-col gap-4">
|
||||
<Button className="w-full">
|
||||
<IconPlaceholder
|
||||
lucide="LockKeyholeIcon"
|
||||
tabler="IconLock"
|
||||
hugeicons="SquareLock02Icon"
|
||||
phosphor="LockKeyIcon"
|
||||
remixicon="RiLockLine"
|
||||
/>
|
||||
Update Security
|
||||
</Button>
|
||||
<Item asChild variant="muted">
|
||||
<a href="#">
|
||||
<ItemMedia variant="icon">
|
||||
<IconPlaceholder
|
||||
lucide="AlertCircleIcon"
|
||||
tabler="IconAlertCircle"
|
||||
hugeicons="AlertCircleIcon"
|
||||
phosphor="WarningCircleIcon"
|
||||
remixicon="RiErrorWarningLine"
|
||||
className="text-destructive"
|
||||
/>
|
||||
</ItemMedia>
|
||||
<ItemContent>
|
||||
<ItemTitle>Danger Zone</ItemTitle>
|
||||
<ItemDescription className="line-clamp-1">
|
||||
Archive account and remove catalog
|
||||
</ItemDescription>
|
||||
</ItemContent>
|
||||
<IconPlaceholder
|
||||
lucide="ArrowRightIcon"
|
||||
tabler="IconArrowRight"
|
||||
hugeicons="ArrowRight01Icon"
|
||||
phosphor="ArrowRightIcon"
|
||||
remixicon="RiArrowRightLine"
|
||||
className="size-4"
|
||||
/>
|
||||
</a>
|
||||
</Item>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
import { Badge } from "@/registry/bases/radix/ui/badge"
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardFooter,
|
||||
CardTitle,
|
||||
} from "@/registry/bases/radix/ui/card"
|
||||
import { Separator } from "@/registry/bases/radix/ui/separator"
|
||||
|
||||
export function AlbumCard() {
|
||||
return (
|
||||
<Card>
|
||||
<CardContent className="flex flex-col gap-4">
|
||||
<div className="relative overflow-hidden rounded-lg">
|
||||
<img
|
||||
src="https://images.unsplash.com/photo-1534088568595-a066f410bcda?w=800&h=800&fit=crop"
|
||||
alt="Synthetic Horizons EP cover art"
|
||||
className="aspect-square w-full object-cover"
|
||||
/>
|
||||
<Badge className="absolute top-3 right-3">$26,033.79</Badge>
|
||||
</div>
|
||||
<div className="flex flex-col gap-1">
|
||||
<CardTitle>Synthetic Horizons EP</CardTitle>
|
||||
<CardDescription className="text-xs tracking-wider uppercase">
|
||||
Released Aug 14, 2023
|
||||
</CardDescription>
|
||||
</div>
|
||||
</CardContent>
|
||||
<CardFooter className="flex-col gap-4">
|
||||
<Separator />
|
||||
<div className="grid w-full grid-cols-2 gap-4">
|
||||
<div className="flex flex-col gap-0.5">
|
||||
<span className="text-xs tracking-wider text-muted-foreground uppercase">
|
||||
Tracks
|
||||
</span>
|
||||
<span className="text-lg font-medium tabular-nums">6 Tracks</span>
|
||||
</div>
|
||||
<div className="flex flex-col gap-0.5">
|
||||
<span className="line-clamp-1 text-xs tracking-wider text-muted-foreground uppercase">
|
||||
Cumulative Streams
|
||||
</span>
|
||||
<span className="text-lg font-medium tabular-nums">6,198,524</span>
|
||||
</div>
|
||||
</div>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
"use client"
|
||||
|
||||
import { Bar, BarChart, XAxis } from "recharts"
|
||||
|
||||
import { Badge } from "@/registry/bases/radix/ui/badge"
|
||||
import { Button } from "@/registry/bases/radix/ui/button"
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardTitle,
|
||||
} from "@/registry/bases/radix/ui/card"
|
||||
import {
|
||||
ChartContainer,
|
||||
ChartTooltip,
|
||||
ChartTooltipContent,
|
||||
type ChartConfig,
|
||||
} from "@/registry/bases/radix/ui/chart"
|
||||
|
||||
const activityData = [
|
||||
{ month: "Jan", amount: 40 },
|
||||
{ month: "Feb", amount: 55 },
|
||||
{ month: "Mar", amount: 35 },
|
||||
{ month: "Apr", amount: 60 },
|
||||
{ month: "May", amount: 45 },
|
||||
{ month: "Jun", amount: 50 },
|
||||
{ month: "Jul", amount: 65 },
|
||||
{ month: "Aug", amount: 40 },
|
||||
{ month: "Sep", amount: 55 },
|
||||
{ month: "Oct", amount: 70 },
|
||||
{ month: "Nov", amount: 45 },
|
||||
{ month: "Dec", amount: 80 },
|
||||
]
|
||||
|
||||
const chartConfig = {
|
||||
amount: {
|
||||
label: "Activity",
|
||||
color: "var(--chart-2)",
|
||||
},
|
||||
} satisfies ChartConfig
|
||||
|
||||
export function CardOverview() {
|
||||
return (
|
||||
<div className="grid grid-cols-2 gap-3">
|
||||
<Card>
|
||||
<CardContent>
|
||||
<CardDescription>Card Balance</CardDescription>
|
||||
<CardTitle className="text-2xl tabular-nums">US$12.94</CardTitle>
|
||||
<CardDescription className="tabular-nums">
|
||||
US$11,337.06 Available
|
||||
</CardDescription>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Card className="flex flex-col justify-between">
|
||||
<CardContent className="flex flex-1 flex-col justify-between">
|
||||
<div className="flex flex-col gap-1">
|
||||
<CardDescription>Payment Due</CardDescription>
|
||||
<CardTitle className="text-2xl">1 Apr</CardTitle>
|
||||
</div>
|
||||
<Button variant="outline" size="sm" className="mt-3 w-full">
|
||||
Pay Early
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Card className="col-span-2">
|
||||
<CardContent className="flex flex-col gap-2">
|
||||
<div className="flex items-center justify-between">
|
||||
<CardDescription>Yearly Activity</CardDescription>
|
||||
<Badge variant="secondary">+US$0.25 Daily Cash</Badge>
|
||||
</div>
|
||||
<ChartContainer config={chartConfig} className="h-20 w-full">
|
||||
<BarChart
|
||||
data={activityData}
|
||||
margin={{ top: 4, right: 0, bottom: 0, left: 0 }}
|
||||
>
|
||||
<XAxis
|
||||
dataKey="month"
|
||||
tickLine={false}
|
||||
tickMargin={4}
|
||||
axisLine={false}
|
||||
tickFormatter={(v) => String(v).slice(0, 1)}
|
||||
className="text-[10px]"
|
||||
/>
|
||||
<ChartTooltip
|
||||
cursor={false}
|
||||
content={<ChartTooltipContent hideLabel />}
|
||||
/>
|
||||
<Bar
|
||||
dataKey="amount"
|
||||
fill="var(--color-amount)"
|
||||
radius={[3, 3, 0, 0]}
|
||||
/>
|
||||
</BarChart>
|
||||
</ChartContainer>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
"use client"
|
||||
|
||||
import { Button } from "@/registry/bases/radix/ui/button"
|
||||
import {
|
||||
InputGroup,
|
||||
InputGroupAddon,
|
||||
InputGroupInput,
|
||||
} from "@/registry/bases/radix/ui/input-group"
|
||||
import {
|
||||
ToggleGroup,
|
||||
ToggleGroupItem,
|
||||
} from "@/registry/bases/radix/ui/toggle-group"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
export function CatalogToolbar() {
|
||||
return (
|
||||
<div className="flex items-center gap-3">
|
||||
<InputGroup className="flex-1">
|
||||
<InputGroupAddon>
|
||||
<IconPlaceholder
|
||||
lucide="SearchIcon"
|
||||
tabler="IconSearch"
|
||||
hugeicons="Search01Icon"
|
||||
phosphor="MagnifyingGlassIcon"
|
||||
remixicon="RiSearchLine"
|
||||
/>
|
||||
</InputGroupAddon>
|
||||
<InputGroupInput placeholder="Search releases or catalog..." />
|
||||
</InputGroup>
|
||||
<Button>
|
||||
<IconPlaceholder
|
||||
lucide="PlusIcon"
|
||||
tabler="IconPlus"
|
||||
hugeicons="Add01Icon"
|
||||
phosphor="PlusIcon"
|
||||
remixicon="RiAddLine"
|
||||
/>
|
||||
Upload New Release
|
||||
</Button>
|
||||
<ToggleGroup type="single" defaultValue="releases" variant="outline">
|
||||
<ToggleGroupItem value="all-tracks">All Tracks</ToggleGroupItem>
|
||||
<ToggleGroupItem value="releases">Releases</ToggleGroupItem>
|
||||
<ToggleGroupItem value="top-earners">Top Earners</ToggleGroupItem>
|
||||
</ToggleGroup>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
import { Badge } from "@/registry/bases/radix/ui/badge"
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardFooter,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/registry/bases/radix/ui/card"
|
||||
import { Item, ItemContent } from "@/registry/bases/radix/ui/item"
|
||||
import { Separator } from "@/registry/bases/radix/ui/separator"
|
||||
|
||||
export function ClaimableBalance() {
|
||||
return (
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardDescription>Claimable Balance</CardDescription>
|
||||
<CardTitle className="text-5xl tabular-nums">$0.00</CardTitle>
|
||||
<Badge variant="outline">
|
||||
<span className="size-2 rounded-full bg-yellow-500" />
|
||||
Pending Setup
|
||||
</Badge>
|
||||
</CardHeader>
|
||||
<CardContent className="flex flex-1 flex-col justify-end">
|
||||
<Item variant="muted" className="flex-col items-stretch">
|
||||
<ItemContent className="gap-3">
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-sm text-muted-foreground">
|
||||
Net Royalties
|
||||
</span>
|
||||
<span className="text-sm font-medium tabular-nums">$0.00</span>
|
||||
</div>
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-sm text-muted-foreground">
|
||||
Processing Fee
|
||||
</span>
|
||||
<span className="text-sm font-medium tabular-nums">-$0.00</span>
|
||||
</div>
|
||||
<Separator />
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-sm text-muted-foreground">
|
||||
Total Ready to Claim
|
||||
</span>
|
||||
<span className="text-sm font-semibold tabular-nums">
|
||||
$0.00 USD
|
||||
</span>
|
||||
</div>
|
||||
</ItemContent>
|
||||
</Item>
|
||||
</CardContent>
|
||||
<CardFooter>
|
||||
<CardDescription>
|
||||
Once your bank is connected, balances over $10.00 are automatically
|
||||
eligible for monthly distribution on the 15th of each month.
|
||||
</CardDescription>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
"use client"
|
||||
|
||||
import { Bar, BarChart, XAxis } from "recharts"
|
||||
|
||||
import { Badge } from "@/registry/bases/radix/ui/badge"
|
||||
import { Button } from "@/registry/bases/radix/ui/button"
|
||||
import {
|
||||
Card,
|
||||
CardAction,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardFooter,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/registry/bases/radix/ui/card"
|
||||
import {
|
||||
ChartContainer,
|
||||
ChartTooltip,
|
||||
ChartTooltipContent,
|
||||
type ChartConfig,
|
||||
} from "@/registry/bases/radix/ui/chart"
|
||||
import {
|
||||
Item,
|
||||
ItemContent,
|
||||
ItemDescription,
|
||||
} from "@/registry/bases/radix/ui/item"
|
||||
import { useDesignSystemSearchParams } from "@/app/(app)/create/lib/search-params"
|
||||
|
||||
const chartData = [
|
||||
{ month: "Dec", amount: 800 },
|
||||
{ month: "Jan", amount: 1100 },
|
||||
{ month: "Feb", amount: 900 },
|
||||
{ month: "Mar", amount: 1300 },
|
||||
{ month: "Apr", amount: 750 },
|
||||
{ month: "May", amount: 1400 },
|
||||
]
|
||||
|
||||
const chartConfig = {
|
||||
amount: {
|
||||
label: "Contribution",
|
||||
color: "var(--chart-2)",
|
||||
},
|
||||
} satisfies ChartConfig
|
||||
|
||||
export function ContributionHistory() {
|
||||
const [params] = useDesignSystemSearchParams()
|
||||
const isRounded = !["lyra", "sera"].includes(params.style)
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Contribution History</CardTitle>
|
||||
<CardDescription>Last 6 months of activity</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<ChartContainer config={chartConfig} className="h-[200px] w-full">
|
||||
<BarChart
|
||||
accessibilityLayer
|
||||
data={chartData}
|
||||
margin={{ left: 0, right: 0, top: 8, bottom: 0 }}
|
||||
>
|
||||
<XAxis
|
||||
dataKey="month"
|
||||
tickLine={false}
|
||||
tickMargin={8}
|
||||
axisLine={false}
|
||||
/>
|
||||
<ChartTooltip
|
||||
cursor={false}
|
||||
content={<ChartTooltipContent hideLabel className="min-w-40" />}
|
||||
/>
|
||||
<Bar
|
||||
dataKey="amount"
|
||||
fill="var(--color-amount)"
|
||||
radius={isRounded ? [6, 6, 0, 0] : 0}
|
||||
maxBarSize={40}
|
||||
/>
|
||||
</BarChart>
|
||||
</ChartContainer>
|
||||
</CardContent>
|
||||
<CardContent>
|
||||
<div className="grid w-full grid-cols-1 gap-3 md:grid-cols-2">
|
||||
<Item variant="muted" className="flex-col items-stretch">
|
||||
<ItemContent className="gap-1">
|
||||
<ItemDescription className="text-xs font-medium tracking-wider text-muted-foreground uppercase">
|
||||
Upcoming
|
||||
</ItemDescription>
|
||||
<span className="cn-font-heading text-lg font-semibold">
|
||||
May 25, 2024
|
||||
</span>
|
||||
<span className="text-sm text-muted-foreground">
|
||||
$1,000 scheduled
|
||||
</span>
|
||||
</ItemContent>
|
||||
</Item>
|
||||
<Item variant="muted" className="flex-col items-stretch">
|
||||
<ItemContent className="gap-1">
|
||||
<ItemDescription className="text-xs font-medium tracking-wider text-muted-foreground uppercase">
|
||||
Auto-Save Plan
|
||||
</ItemDescription>
|
||||
<span className="cn-font-heading text-lg font-semibold">
|
||||
Accelerated
|
||||
</span>
|
||||
<span className="text-sm text-muted-foreground">
|
||||
Recurring weekly
|
||||
</span>
|
||||
</ItemContent>
|
||||
</Item>
|
||||
</div>
|
||||
</CardContent>
|
||||
<CardFooter>
|
||||
<Button className="w-full">View Full Report</Button>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
import { Button } from "@/registry/bases/radix/ui/button"
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardFooter,
|
||||
} from "@/registry/bases/radix/ui/card"
|
||||
import { Item } from "@/registry/bases/radix/ui/item"
|
||||
import { Label } from "@/registry/bases/radix/ui/label"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
export function CoverArt() {
|
||||
return (
|
||||
<Card>
|
||||
<CardContent className="flex flex-col gap-3">
|
||||
<Label
|
||||
htmlFor="cover-art"
|
||||
className="text-center text-xs font-normal tracking-wider text-muted-foreground uppercase"
|
||||
>
|
||||
Cover Art
|
||||
</Label>
|
||||
<Item className="aspect-square" variant="outline">
|
||||
<label
|
||||
htmlFor="cover-art"
|
||||
className="flex size-full cursor-pointer items-center justify-center"
|
||||
>
|
||||
<IconPlaceholder
|
||||
lucide="ImageIcon"
|
||||
tabler="IconPhoto"
|
||||
hugeicons="Image01Icon"
|
||||
phosphor="ImageIcon"
|
||||
remixicon="RiImageLine"
|
||||
className="size-10 text-muted-foreground/50"
|
||||
/>
|
||||
</label>
|
||||
</Item>
|
||||
<input
|
||||
id="cover-art"
|
||||
type="file"
|
||||
accept="image/jpeg,image/png"
|
||||
className="sr-only"
|
||||
/>
|
||||
</CardContent>
|
||||
<CardFooter className="flex-col gap-2">
|
||||
<Button variant="secondary" className="w-full" asChild>
|
||||
<label htmlFor="cover-art" className="cursor-pointer">
|
||||
Upload Artwork
|
||||
</label>
|
||||
</Button>
|
||||
<CardDescription className="text-center text-xs">
|
||||
Minimum 3000 × 3000px
|
||||
<br />
|
||||
JPEG or PNG only
|
||||
</CardDescription>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
"use client"
|
||||
|
||||
import { Bar, BarChart, XAxis } from "recharts"
|
||||
|
||||
import { Button } from "@/registry/bases/radix/ui/button"
|
||||
import {
|
||||
Card,
|
||||
CardAction,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/registry/bases/radix/ui/card"
|
||||
import {
|
||||
ChartContainer,
|
||||
ChartTooltip,
|
||||
ChartTooltipContent,
|
||||
type ChartConfig,
|
||||
} from "@/registry/bases/radix/ui/chart"
|
||||
import {
|
||||
Item,
|
||||
ItemContent,
|
||||
ItemDescription,
|
||||
ItemGroup,
|
||||
ItemTitle,
|
||||
} from "@/registry/bases/radix/ui/item"
|
||||
import { useDesignSystemSearchParams } from "@/app/(app)/create/lib/search-params"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
const HOLDINGS = [
|
||||
{
|
||||
name: "Vanguard VIG",
|
||||
shares: "450 Shares",
|
||||
amount: "$1,842.10",
|
||||
data: [
|
||||
{ q: "Q1", value: 380 },
|
||||
{ q: "Q2", value: 420 },
|
||||
{ q: "Q3", value: 390 },
|
||||
{ q: "Q4", value: 652 },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "S&P 500 VOO",
|
||||
shares: "112 Shares",
|
||||
amount: "$928.40",
|
||||
data: [
|
||||
{ q: "Q1", value: 180 },
|
||||
{ q: "Q2", value: 210 },
|
||||
{ q: "Q3", value: 320 },
|
||||
{ q: "Q4", value: 218 },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Apple AAPL",
|
||||
shares: "85 Shares",
|
||||
amount: "$340.00",
|
||||
data: [
|
||||
{ q: "Q1", value: 60 },
|
||||
{ q: "Q2", value: 70 },
|
||||
{ q: "Q3", value: 120 },
|
||||
{ q: "Q4", value: 90 },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Realty Income",
|
||||
shares: "320 Shares",
|
||||
amount: "$1,139.50",
|
||||
data: [
|
||||
{ q: "Q1", value: 240 },
|
||||
{ q: "Q2", value: 260 },
|
||||
{ q: "Q3", value: 280 },
|
||||
{ q: "Q4", value: 360 },
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
const miniChartConfig = {
|
||||
value: {
|
||||
label: "Dividend",
|
||||
color: "var(--chart-2)",
|
||||
},
|
||||
} satisfies ChartConfig
|
||||
|
||||
export function DividendIncome() {
|
||||
const [params] = useDesignSystemSearchParams()
|
||||
const isRounded = !["lyra", "sera"].includes(params.style)
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Q2 Dividend Income</CardTitle>
|
||||
<CardDescription>
|
||||
Quarterly dividend payouts across your portfolio holdings.
|
||||
</CardDescription>
|
||||
<CardAction>
|
||||
<Button variant="ghost" size="icon-sm" className="bg-muted">
|
||||
<IconPlaceholder
|
||||
lucide="XIcon"
|
||||
tabler="IconX"
|
||||
hugeicons="Cancel01Icon"
|
||||
phosphor="XIcon"
|
||||
remixicon="RiCloseLine"
|
||||
/>
|
||||
</Button>
|
||||
</CardAction>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<ItemGroup>
|
||||
{HOLDINGS.map((holding) => (
|
||||
<Item key={holding.name} variant="muted">
|
||||
<ItemContent>
|
||||
<ItemTitle>{holding.name}</ItemTitle>
|
||||
<ItemDescription>{holding.shares}</ItemDescription>
|
||||
</ItemContent>
|
||||
<ChartContainer
|
||||
config={miniChartConfig}
|
||||
className="hidden h-8 w-24 md:block"
|
||||
>
|
||||
<BarChart
|
||||
data={holding.data}
|
||||
margin={{ top: 0, right: 0, bottom: 0, left: 0 }}
|
||||
>
|
||||
<ChartTooltip
|
||||
cursor={false}
|
||||
content={<ChartTooltipContent hideLabel />}
|
||||
/>
|
||||
<Bar
|
||||
dataKey="value"
|
||||
fill="var(--color-value)"
|
||||
radius={isRounded ? [3, 3, 0, 0] : 0}
|
||||
/>
|
||||
</BarChart>
|
||||
</ChartContainer>
|
||||
<span className="hidden text-sm font-semibold tabular-nums md:block">
|
||||
{holding.amount}
|
||||
</span>
|
||||
</Item>
|
||||
))}
|
||||
</ItemGroup>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
import { Button } from "@/registry/bases/radix/ui/button"
|
||||
import { Card, CardContent } from "@/registry/bases/radix/ui/card"
|
||||
import {
|
||||
Empty,
|
||||
EmptyContent,
|
||||
EmptyDescription,
|
||||
EmptyHeader,
|
||||
EmptyMedia,
|
||||
EmptyTitle,
|
||||
} from "@/registry/bases/radix/ui/empty"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
export function EmptyConnectBank() {
|
||||
return (
|
||||
<Card>
|
||||
<CardContent>
|
||||
<Empty className="p-4">
|
||||
<EmptyMedia variant="icon">
|
||||
<IconPlaceholder
|
||||
lucide="CreditCardIcon"
|
||||
tabler="IconCreditCard"
|
||||
hugeicons="CreditCardIcon"
|
||||
phosphor="CreditCardIcon"
|
||||
remixicon="RiBankCardLine"
|
||||
/>
|
||||
</EmptyMedia>
|
||||
<EmptyHeader>
|
||||
<EmptyTitle>Connect Bank</EmptyTitle>
|
||||
<EmptyDescription>
|
||||
Link your payout method to receive monthly royalty distributions
|
||||
automatically.
|
||||
</EmptyDescription>
|
||||
</EmptyHeader>
|
||||
<EmptyContent>
|
||||
<Button>Set Up Payouts</Button>
|
||||
</EmptyContent>
|
||||
</Empty>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
import { Button } from "@/registry/bases/radix/ui/button"
|
||||
import { Card, CardContent } from "@/registry/bases/radix/ui/card"
|
||||
import {
|
||||
Empty,
|
||||
EmptyContent,
|
||||
EmptyDescription,
|
||||
EmptyHeader,
|
||||
EmptyMedia,
|
||||
EmptyTitle,
|
||||
} from "@/registry/bases/radix/ui/empty"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
export function EmptyDistributeTrack() {
|
||||
return (
|
||||
<Card>
|
||||
<CardContent>
|
||||
<Empty className="p-4">
|
||||
<EmptyMedia variant="icon">
|
||||
<IconPlaceholder
|
||||
lucide="PlusIcon"
|
||||
tabler="IconPlus"
|
||||
hugeicons="Add01Icon"
|
||||
phosphor="PlusIcon"
|
||||
remixicon="RiAddLine"
|
||||
/>
|
||||
</EmptyMedia>
|
||||
<EmptyHeader>
|
||||
<EmptyTitle>Distribute Track</EmptyTitle>
|
||||
<EmptyDescription>
|
||||
Upload your first master to start reaching listeners on Spotify,
|
||||
Apple Music, and more.
|
||||
</EmptyDescription>
|
||||
</EmptyHeader>
|
||||
<EmptyContent>
|
||||
<Button>Create Release</Button>
|
||||
</EmptyContent>
|
||||
</Empty>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
import { Button } from "@/registry/bases/radix/ui/button"
|
||||
import { Card, CardContent } from "@/registry/bases/radix/ui/card"
|
||||
import {
|
||||
Empty,
|
||||
EmptyContent,
|
||||
EmptyDescription,
|
||||
EmptyHeader,
|
||||
EmptyMedia,
|
||||
EmptyTitle,
|
||||
} from "@/registry/bases/radix/ui/empty"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
export function EmptyExploreCatalog() {
|
||||
return (
|
||||
<Card>
|
||||
<CardContent>
|
||||
<Empty className="p-4">
|
||||
<EmptyMedia variant="icon">
|
||||
<IconPlaceholder
|
||||
lucide="AudioLinesIcon"
|
||||
tabler="IconPlayerRecordFilled"
|
||||
hugeicons="AudioWave01Icon"
|
||||
phosphor="RecordIcon"
|
||||
remixicon="RiRecordCircleLine"
|
||||
/>
|
||||
</EmptyMedia>
|
||||
<EmptyHeader>
|
||||
<EmptyTitle>Explore Catalog</EmptyTitle>
|
||||
<EmptyDescription>
|
||||
Check your ISRC codes, metadata, and visual assets before going
|
||||
live.
|
||||
</EmptyDescription>
|
||||
</EmptyHeader>
|
||||
<EmptyContent>
|
||||
<Button>View Catalog</Button>
|
||||
</EmptyContent>
|
||||
</Empty>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
124
apps/v4/registry/bases/radix/blocks/preview-02/cards/faq.tsx
Normal file
124
apps/v4/registry/bases/radix/blocks/preview-02/cards/faq.tsx
Normal file
@@ -0,0 +1,124 @@
|
||||
"use client"
|
||||
|
||||
import {
|
||||
Accordion,
|
||||
AccordionContent,
|
||||
AccordionItem,
|
||||
AccordionTrigger,
|
||||
} from "@/registry/bases/radix/ui/accordion"
|
||||
import { Button } from "@/registry/bases/radix/ui/button"
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardFooter,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/registry/bases/radix/ui/card"
|
||||
import {
|
||||
Tabs,
|
||||
TabsContent,
|
||||
TabsList,
|
||||
TabsTrigger,
|
||||
} from "@/registry/bases/radix/ui/tabs"
|
||||
|
||||
const GENERAL_QUESTIONS = [
|
||||
{
|
||||
q: "How secure is my financial data with Ledger?",
|
||||
a: "We use bank-level AES-256 encryption, SOC 2 Type II certified infrastructure, and never store your credentials. All connections use read-only access tokens. We are a SEC registered investment advisor.",
|
||||
},
|
||||
{
|
||||
q: "How do I connect my bank or investment accounts?",
|
||||
a: "Go to Settings > Linked Accounts and search for your institution. We support over 12,000 banks and brokerages via Plaid and MX.",
|
||||
},
|
||||
{
|
||||
q: "Can I export my data for tax purposes?",
|
||||
a: "Yes. Navigate to Reports > Tax Export to download a CSV or PDF summary of your transactions, dividends, and capital gains for any tax year.",
|
||||
},
|
||||
]
|
||||
|
||||
const BILLING_QUESTIONS = [
|
||||
{
|
||||
q: "What is the difference between Basic and Pro pricing tiers?",
|
||||
a: "Basic includes budgeting, goal tracking, and up to 3 linked accounts. Pro adds unlimited accounts, dividend tracking, portfolio analysis, and priority support.",
|
||||
},
|
||||
{
|
||||
q: "How do I cancel my subscription?",
|
||||
a: "Go to Settings > Billing > Manage Plan and click Cancel. Your access continues until the end of your current billing period.",
|
||||
},
|
||||
{
|
||||
q: "Do you offer a free trial?",
|
||||
a: "Yes. All new accounts start with a 14-day Pro trial. No credit card required.",
|
||||
},
|
||||
]
|
||||
|
||||
const GOALS_QUESTIONS = [
|
||||
{
|
||||
q: "How do I set up a custom financial goal?",
|
||||
a: "Click New Goal from the Savings Targets card. Choose a category, set a target amount and date, and we'll calculate the monthly contribution needed.",
|
||||
},
|
||||
{
|
||||
q: "Can I track multiple goals at once?",
|
||||
a: "Yes. Pro accounts can track unlimited goals. Basic accounts support up to 3 active goals.",
|
||||
},
|
||||
{
|
||||
q: "How are monthly contributions calculated?",
|
||||
a: "We divide the remaining amount by the number of months until your target date, adjusted for your current savings rate and any auto-transfer schedules.",
|
||||
},
|
||||
]
|
||||
|
||||
function QuestionList({
|
||||
questions,
|
||||
}: {
|
||||
questions: { q: string; a: string }[]
|
||||
}) {
|
||||
return (
|
||||
<Accordion type="single" collapsible defaultValue="item-0">
|
||||
{questions.map((item, index) => (
|
||||
<AccordionItem key={index} value={`item-${index}`}>
|
||||
<AccordionTrigger>{item.q}</AccordionTrigger>
|
||||
<AccordionContent>{item.a}</AccordionContent>
|
||||
</AccordionItem>
|
||||
))}
|
||||
</Accordion>
|
||||
)
|
||||
}
|
||||
|
||||
export function Faq() {
|
||||
return (
|
||||
<Card>
|
||||
<CardContent>
|
||||
<Tabs defaultValue="general">
|
||||
<TabsList className="w-full">
|
||||
<TabsTrigger value="general" className="flex-1">
|
||||
General
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="billing" className="flex-1">
|
||||
Billing
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="goals" className="flex-1">
|
||||
Goals
|
||||
</TabsTrigger>
|
||||
</TabsList>
|
||||
<TabsContent value="general">
|
||||
<QuestionList questions={GENERAL_QUESTIONS} />
|
||||
</TabsContent>
|
||||
<TabsContent value="billing">
|
||||
<QuestionList questions={BILLING_QUESTIONS} />
|
||||
</TabsContent>
|
||||
<TabsContent value="goals">
|
||||
<QuestionList questions={GOALS_QUESTIONS} />
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
</CardContent>
|
||||
<CardFooter>
|
||||
<Button variant="outline" className="w-full">
|
||||
Contact Support
|
||||
</Button>
|
||||
<Button variant="link" className="w-full">
|
||||
Learn More
|
||||
</Button>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
import { Badge } from "@/registry/bases/radix/ui/badge"
|
||||
import {
|
||||
Card,
|
||||
CardAction,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/registry/bases/radix/ui/card"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
export function FrontDoor() {
|
||||
return (
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Front Door</CardTitle>
|
||||
<CardDescription>Smart Lock Pro</CardDescription>
|
||||
<CardAction>
|
||||
<div className="flex items-center gap-1.5 text-sm text-muted-foreground">
|
||||
Locked
|
||||
<IconPlaceholder
|
||||
lucide="LockIcon"
|
||||
tabler="IconLock"
|
||||
hugeicons="SquareLock02Icon"
|
||||
phosphor="LockKeyIcon"
|
||||
remixicon="RiLockLine"
|
||||
className="size-4"
|
||||
/>
|
||||
</div>
|
||||
</CardAction>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="relative flex aspect-video items-center justify-center overflow-hidden rounded-lg bg-muted bg-[repeating-linear-gradient(45deg,transparent,transparent_10px,var(--border)_10px,var(--border)_11px)]">
|
||||
<Badge variant="destructive" className="absolute top-2 right-2">
|
||||
Live
|
||||
</Badge>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
import { Button } from "@/registry/bases/radix/ui/button"
|
||||
import {
|
||||
Card,
|
||||
CardAction,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/registry/bases/radix/ui/card"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
export function IndexInvesting() {
|
||||
return (
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Dollar-Cost Averaging</CardTitle>
|
||||
<CardDescription>
|
||||
A strategy for building wealth over time.
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<CardDescription className="mt-3 text-sm leading-relaxed style-sera:mt-0">
|
||||
<a
|
||||
href="#"
|
||||
className="underline underline-offset-4 hover:text-primary"
|
||||
>
|
||||
Over time
|
||||
</a>
|
||||
, this smooths out the average cost of your investments. When prices
|
||||
drop, your fixed amount buys more shares. When prices rise, you buy
|
||||
fewer. The result is a lower average cost per share compared to
|
||||
lump-sum investing during volatile periods.
|
||||
</CardDescription>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
|
||||
import {
|
||||
Card,
|
||||
CardAction,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/registry/bases/radix/ui/card"
|
||||
import {
|
||||
Item,
|
||||
ItemActions,
|
||||
ItemContent,
|
||||
ItemGroup,
|
||||
ItemMedia,
|
||||
ItemTitle,
|
||||
} from "@/registry/bases/radix/ui/item"
|
||||
import { Slider } from "@/registry/bases/radix/ui/slider"
|
||||
import { Switch } from "@/registry/bases/radix/ui/switch"
|
||||
import {
|
||||
ToggleGroup,
|
||||
ToggleGroupItem,
|
||||
} from "@/registry/bases/radix/ui/toggle-group"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
const SCENES = {
|
||||
cooking: { brightness: [90], colorTemp: [70], volume: [30], fade: [0] },
|
||||
dining: { brightness: [50], colorTemp: [40], volume: [20], fade: [60] },
|
||||
nightlight: { brightness: [15], colorTemp: [20], volume: [0], fade: [80] },
|
||||
focus: { brightness: [100], colorTemp: [85], volume: [0], fade: [0] },
|
||||
} as const
|
||||
|
||||
export function KitchenIsland() {
|
||||
const [enabled, setEnabled] = React.useState(true)
|
||||
const [scene, setScene] = React.useState("cooking")
|
||||
const [brightness, setBrightness] = React.useState([90])
|
||||
const [colorTemp, setColorTemp] = React.useState([70])
|
||||
const [volume, setVolume] = React.useState([30])
|
||||
const [fade, setFade] = React.useState([0])
|
||||
|
||||
const handleSceneChange = (value: string) => {
|
||||
if (!value) return
|
||||
setScene(value)
|
||||
const preset = SCENES[value as keyof typeof SCENES]
|
||||
setBrightness([...preset.brightness])
|
||||
setColorTemp([...preset.colorTemp])
|
||||
setVolume([...preset.volume])
|
||||
setFade([...preset.fade])
|
||||
}
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Kitchen Island</CardTitle>
|
||||
<CardDescription>Hue Color Ambient</CardDescription>
|
||||
<CardAction>
|
||||
<Switch checked={enabled} onCheckedChange={setEnabled} />
|
||||
</CardAction>
|
||||
</CardHeader>
|
||||
<CardContent className="flex flex-col gap-4">
|
||||
<div className="flex flex-col gap-2">
|
||||
<span className="sr-only">Scenes</span>
|
||||
<ToggleGroup
|
||||
type="single"
|
||||
value={scene}
|
||||
onValueChange={handleSceneChange}
|
||||
variant="outline"
|
||||
spacing={1}
|
||||
className="flex-wrap"
|
||||
>
|
||||
<ToggleGroupItem value="cooking" disabled={!enabled}>
|
||||
Cooking
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem value="dining" disabled={!enabled}>
|
||||
Dining
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem value="nightlight" disabled={!enabled}>
|
||||
Nightlight
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem value="focus" disabled={!enabled}>
|
||||
Focus
|
||||
</ToggleGroupItem>
|
||||
</ToggleGroup>
|
||||
</div>
|
||||
<ItemGroup>
|
||||
<Item size="sm" variant="outline">
|
||||
<ItemMedia variant="icon">
|
||||
<IconPlaceholder
|
||||
lucide="SunIcon"
|
||||
tabler="IconSun"
|
||||
hugeicons="Sun03Icon"
|
||||
phosphor="SunIcon"
|
||||
remixicon="RiSunLine"
|
||||
/>
|
||||
</ItemMedia>
|
||||
<ItemContent className="flex-row items-center gap-3">
|
||||
<ItemTitle className="shrink-0">Brightness</ItemTitle>
|
||||
</ItemContent>
|
||||
<ItemActions className="flex-1">
|
||||
<Slider
|
||||
value={brightness}
|
||||
onValueChange={setBrightness}
|
||||
max={100}
|
||||
disabled={!enabled}
|
||||
className="w-full"
|
||||
/>
|
||||
</ItemActions>
|
||||
</Item>
|
||||
<Item size="sm" variant="outline">
|
||||
<ItemMedia variant="icon">
|
||||
<IconPlaceholder
|
||||
lucide="ThermometerIcon"
|
||||
tabler="IconThermometer"
|
||||
hugeicons="ThermometerWarmIcon"
|
||||
phosphor="ThermometerIcon"
|
||||
remixicon="RiThermometerLine"
|
||||
/>
|
||||
</ItemMedia>
|
||||
<ItemContent className="flex-row items-center gap-3">
|
||||
<ItemTitle className="shrink-0">Color Temp</ItemTitle>
|
||||
</ItemContent>
|
||||
<ItemActions className="flex-1">
|
||||
<Slider
|
||||
value={colorTemp}
|
||||
onValueChange={setColorTemp}
|
||||
max={100}
|
||||
disabled={!enabled}
|
||||
/>
|
||||
</ItemActions>
|
||||
</Item>
|
||||
<Item size="sm" variant="outline">
|
||||
<ItemMedia variant="icon">
|
||||
<IconPlaceholder
|
||||
lucide="Volume2Icon"
|
||||
tabler="IconVolume"
|
||||
hugeicons="VolumeHighIcon"
|
||||
phosphor="SpeakerHighIcon"
|
||||
remixicon="RiVolumeUpLine"
|
||||
/>
|
||||
</ItemMedia>
|
||||
<ItemContent className="flex-row items-center gap-3">
|
||||
<ItemTitle className="shrink-0">Volume</ItemTitle>
|
||||
</ItemContent>
|
||||
<ItemActions className="flex-1">
|
||||
<Slider
|
||||
value={volume}
|
||||
onValueChange={setVolume}
|
||||
max={100}
|
||||
disabled={!enabled}
|
||||
/>
|
||||
</ItemActions>
|
||||
</Item>
|
||||
<Item size="sm" variant="outline">
|
||||
<ItemMedia variant="icon">
|
||||
<IconPlaceholder
|
||||
lucide="TimerIcon"
|
||||
tabler="IconClock"
|
||||
hugeicons="Clock03Icon"
|
||||
phosphor="TimerIcon"
|
||||
remixicon="RiTimerLine"
|
||||
/>
|
||||
</ItemMedia>
|
||||
<ItemContent className="flex-row items-center gap-3">
|
||||
<ItemTitle className="shrink-0">Fade</ItemTitle>
|
||||
</ItemContent>
|
||||
<ItemActions className="flex-1">
|
||||
<Slider
|
||||
value={fade}
|
||||
onValueChange={setFade}
|
||||
max={100}
|
||||
disabled={!enabled}
|
||||
/>
|
||||
</ItemActions>
|
||||
</Item>
|
||||
</ItemGroup>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
import { Card, CardContent, CardHeader } from "@/registry/bases/radix/ui/card"
|
||||
import { Skeleton } from "@/registry/bases/radix/ui/skeleton"
|
||||
|
||||
export function LoadingCard() {
|
||||
return (
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<Skeleton className="h-5 w-32" />
|
||||
<Skeleton className="h-4 w-48" />
|
||||
</CardHeader>
|
||||
<CardContent className="flex flex-col gap-4">
|
||||
<Skeleton className="h-32 w-full rounded-lg" />
|
||||
<div className="flex flex-col gap-2">
|
||||
<Skeleton className="h-4 w-full" />
|
||||
<Skeleton className="h-4 w-3/4" />
|
||||
<Skeleton className="h-4 w-1/2" />
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
<Skeleton className="h-9 flex-1 rounded-md" />
|
||||
<Skeleton className="h-9 flex-1 rounded-md" />
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
"use client"
|
||||
|
||||
import { Button } from "@/registry/bases/radix/ui/button"
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardFooter,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/registry/bases/radix/ui/card"
|
||||
import { Field, FieldGroup, FieldLabel } from "@/registry/bases/radix/ui/field"
|
||||
import { Input } from "@/registry/bases/radix/ui/input"
|
||||
|
||||
export function NewMilestone() {
|
||||
return (
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Set a new milestone</CardTitle>
|
||||
<CardDescription>
|
||||
Define your financial target and we'll help you pace your
|
||||
savings.
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<FieldGroup>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="goal-name">Goal Name</FieldLabel>
|
||||
<Input
|
||||
id="goal-name"
|
||||
placeholder="e.g. New Car, Home Downpayment"
|
||||
/>
|
||||
</Field>
|
||||
<div className="grid grid-cols-2 gap-3">
|
||||
<Field>
|
||||
<FieldLabel htmlFor="target-amount">Target Amount</FieldLabel>
|
||||
<Input id="target-amount" defaultValue="$15,000" />
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="target-date">Target Date</FieldLabel>
|
||||
<Input id="target-date" defaultValue="Dec 2025" />
|
||||
</Field>
|
||||
</div>
|
||||
</FieldGroup>
|
||||
</CardContent>
|
||||
<CardFooter className="flex-col gap-2">
|
||||
<Button className="w-full">Create Goal</Button>
|
||||
<Button variant="outline" className="w-full">
|
||||
Cancel
|
||||
</Button>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
|
||||
import { Button } from "@/registry/bases/radix/ui/button"
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardFooter,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/registry/bases/radix/ui/card"
|
||||
import { Checkbox } from "@/registry/bases/radix/ui/checkbox"
|
||||
import {
|
||||
Field,
|
||||
FieldContent,
|
||||
FieldDescription,
|
||||
FieldGroup,
|
||||
FieldLabel,
|
||||
} from "@/registry/bases/radix/ui/field"
|
||||
|
||||
const NOTIFICATIONS = [
|
||||
{
|
||||
id: "transactions",
|
||||
label: "Transaction alerts",
|
||||
description: "Deposits, withdrawals, and transfers.",
|
||||
defaultChecked: true,
|
||||
},
|
||||
{
|
||||
id: "security",
|
||||
label: "Security alerts",
|
||||
description: "Login attempts and account changes.",
|
||||
defaultChecked: true,
|
||||
},
|
||||
{
|
||||
id: "goals",
|
||||
label: "Goal milestones",
|
||||
description: "Updates at 25%, 50%, 75%, and 100%.",
|
||||
defaultChecked: false,
|
||||
},
|
||||
{
|
||||
id: "market",
|
||||
label: "Market updates",
|
||||
description: "Daily portfolio summary and price alerts.",
|
||||
defaultChecked: false,
|
||||
},
|
||||
]
|
||||
|
||||
export function NotificationSettings() {
|
||||
const [checked, setChecked] = React.useState<Record<string, boolean>>(
|
||||
Object.fromEntries(NOTIFICATIONS.map((n) => [n.id, n.defaultChecked]))
|
||||
)
|
||||
|
||||
const allChecked = NOTIFICATIONS.every((n) => checked[n.id])
|
||||
const someChecked = NOTIFICATIONS.some((n) => checked[n.id]) && !allChecked
|
||||
|
||||
const handleSelectAll = (value: boolean) => {
|
||||
setChecked(Object.fromEntries(NOTIFICATIONS.map((n) => [n.id, value])))
|
||||
}
|
||||
|
||||
const handleToggle = (id: string, value: boolean) => {
|
||||
setChecked((prev) => ({ ...prev, [id]: value }))
|
||||
}
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Notifications</CardTitle>
|
||||
<CardDescription>
|
||||
Choose what you want to be notified about.
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<FieldGroup>
|
||||
<Field orientation="horizontal">
|
||||
<Checkbox
|
||||
id="notify-all"
|
||||
checked={someChecked ? "indeterminate" : allChecked}
|
||||
onCheckedChange={(v) => handleSelectAll(!!v)}
|
||||
/>
|
||||
<FieldContent>
|
||||
<FieldLabel htmlFor="notify-all">Select all</FieldLabel>
|
||||
</FieldContent>
|
||||
</Field>
|
||||
{NOTIFICATIONS.map((n) => (
|
||||
<Field key={n.id} orientation="horizontal">
|
||||
<Checkbox
|
||||
id={`notify-${n.id}`}
|
||||
checked={checked[n.id]}
|
||||
onCheckedChange={(v) => handleToggle(n.id, !!v)}
|
||||
/>
|
||||
<FieldContent>
|
||||
<FieldLabel htmlFor={`notify-${n.id}`}>{n.label}</FieldLabel>
|
||||
<FieldDescription>{n.description}</FieldDescription>
|
||||
</FieldContent>
|
||||
</Field>
|
||||
))}
|
||||
</FieldGroup>
|
||||
</CardContent>
|
||||
<CardFooter>
|
||||
<Button className="w-full">Save Preferences</Button>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
"use client"
|
||||
|
||||
import {
|
||||
Breadcrumb,
|
||||
BreadcrumbItem,
|
||||
BreadcrumbLink,
|
||||
BreadcrumbList,
|
||||
BreadcrumbPage,
|
||||
BreadcrumbSeparator,
|
||||
} from "@/registry/bases/radix/ui/breadcrumb"
|
||||
import { Button } from "@/registry/bases/radix/ui/button"
|
||||
import { Card, CardContent, CardHeader } from "@/registry/bases/radix/ui/card"
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuGroup,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/registry/bases/radix/ui/dropdown-menu"
|
||||
import {
|
||||
Item,
|
||||
ItemContent,
|
||||
ItemDescription,
|
||||
ItemGroup,
|
||||
ItemMedia,
|
||||
ItemTitle,
|
||||
} from "@/registry/bases/radix/ui/item"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
export function Payments() {
|
||||
return (
|
||||
<Card>
|
||||
<CardHeader className="flex flex-col gap-3">
|
||||
<Breadcrumb>
|
||||
<BreadcrumbList>
|
||||
<BreadcrumbItem>
|
||||
<BreadcrumbLink href="#">Home</BreadcrumbLink>
|
||||
</BreadcrumbItem>
|
||||
<BreadcrumbSeparator />
|
||||
<BreadcrumbItem>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button size="icon-sm" variant="ghost">
|
||||
<IconPlaceholder
|
||||
lucide="MoreHorizontalIcon"
|
||||
tabler="IconDots"
|
||||
hugeicons="MoreHorizontalCircle01Icon"
|
||||
phosphor="DotsThreeIcon"
|
||||
remixicon="RiMoreLine"
|
||||
/>
|
||||
<span className="sr-only">Account options</span>
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="start">
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem>Profile</DropdownMenuItem>
|
||||
<DropdownMenuItem>Statements</DropdownMenuItem>
|
||||
<DropdownMenuItem>Documents</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</BreadcrumbItem>
|
||||
<BreadcrumbSeparator />
|
||||
<BreadcrumbItem>
|
||||
<BreadcrumbPage>Payments</BreadcrumbPage>
|
||||
</BreadcrumbItem>
|
||||
</BreadcrumbList>
|
||||
</Breadcrumb>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<ItemGroup>
|
||||
<Item asChild variant="muted">
|
||||
<a href="#">
|
||||
<ItemMedia variant="icon">
|
||||
<IconPlaceholder
|
||||
lucide="GaugeIcon"
|
||||
tabler="IconGauge"
|
||||
hugeicons="Settings01Icon"
|
||||
phosphor="GaugeIcon"
|
||||
remixicon="RiDashboardLine"
|
||||
/>
|
||||
</ItemMedia>
|
||||
<ItemContent>
|
||||
<ItemTitle>Change transfer limit</ItemTitle>
|
||||
<ItemDescription>
|
||||
Adjust how much you can send from your balance.
|
||||
</ItemDescription>
|
||||
</ItemContent>
|
||||
<IconPlaceholder
|
||||
lucide="ChevronRightIcon"
|
||||
tabler="IconChevronRight"
|
||||
hugeicons="ArrowRight01Icon"
|
||||
phosphor="CaretRightIcon"
|
||||
remixicon="RiArrowRightSLine"
|
||||
className="size-4 shrink-0 text-muted-foreground"
|
||||
/>
|
||||
</a>
|
||||
</Item>
|
||||
<Item asChild variant="muted">
|
||||
<a href="#">
|
||||
<ItemMedia variant="icon">
|
||||
<IconPlaceholder
|
||||
lucide="CalendarIcon"
|
||||
tabler="IconCalendar"
|
||||
hugeicons="Calendar03Icon"
|
||||
phosphor="CalendarIcon"
|
||||
remixicon="RiCalendarLine"
|
||||
/>
|
||||
</ItemMedia>
|
||||
<ItemContent>
|
||||
<ItemTitle>Scheduled transfers</ItemTitle>
|
||||
<ItemDescription>
|
||||
Set up a transfer to send at a later date.
|
||||
</ItemDescription>
|
||||
</ItemContent>
|
||||
<IconPlaceholder
|
||||
lucide="ChevronRightIcon"
|
||||
tabler="IconChevronRight"
|
||||
hugeicons="ArrowRight01Icon"
|
||||
phosphor="CaretRightIcon"
|
||||
remixicon="RiArrowRightSLine"
|
||||
className="size-4 shrink-0 text-muted-foreground"
|
||||
/>
|
||||
</a>
|
||||
</Item>
|
||||
<Item asChild variant="muted">
|
||||
<a href="#">
|
||||
<ItemMedia variant="icon">
|
||||
<IconPlaceholder
|
||||
lucide="RepeatIcon"
|
||||
tabler="IconRepeat"
|
||||
hugeicons="RepeatIcon"
|
||||
phosphor="RepeatIcon"
|
||||
remixicon="RiRepeatLine"
|
||||
/>
|
||||
</ItemMedia>
|
||||
<ItemContent>
|
||||
<ItemTitle>Direct Debits</ItemTitle>
|
||||
<ItemDescription>
|
||||
Set up and manage regular payments.
|
||||
</ItemDescription>
|
||||
</ItemContent>
|
||||
<IconPlaceholder
|
||||
lucide="ChevronRightIcon"
|
||||
tabler="IconChevronRight"
|
||||
hugeicons="ArrowRight01Icon"
|
||||
phosphor="CaretRightIcon"
|
||||
remixicon="RiArrowRightSLine"
|
||||
className="size-4 shrink-0 text-muted-foreground"
|
||||
/>
|
||||
</a>
|
||||
</Item>
|
||||
<Item asChild variant="muted">
|
||||
<a href="#">
|
||||
<ItemMedia variant="icon">
|
||||
<IconPlaceholder
|
||||
lucide="RefreshCwIcon"
|
||||
tabler="IconRefresh"
|
||||
hugeicons="RepeatIcon"
|
||||
phosphor="ArrowsClockwiseIcon"
|
||||
remixicon="RiRefreshLine"
|
||||
/>
|
||||
</ItemMedia>
|
||||
<ItemContent>
|
||||
<ItemTitle>Recurring card payments</ItemTitle>
|
||||
<ItemDescription>
|
||||
Manage your repeated card transactions.
|
||||
</ItemDescription>
|
||||
</ItemContent>
|
||||
<IconPlaceholder
|
||||
lucide="ChevronRightIcon"
|
||||
tabler="IconChevronRight"
|
||||
hugeicons="ArrowRight01Icon"
|
||||
phosphor="CaretRightIcon"
|
||||
remixicon="RiArrowRightSLine"
|
||||
className="size-4 shrink-0 text-muted-foreground"
|
||||
/>
|
||||
</a>
|
||||
</Item>
|
||||
</ItemGroup>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
|
||||
import { Button } from "@/registry/bases/radix/ui/button"
|
||||
import {
|
||||
Card,
|
||||
CardAction,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardFooter,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/registry/bases/radix/ui/card"
|
||||
import {
|
||||
Field,
|
||||
FieldDescription,
|
||||
FieldGroup,
|
||||
FieldLabel,
|
||||
} from "@/registry/bases/radix/ui/field"
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectGroup,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/registry/bases/radix/ui/select"
|
||||
import { Slider } from "@/registry/bases/radix/ui/slider"
|
||||
import { Textarea } from "@/registry/bases/radix/ui/textarea"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
export function PayoutThreshold() {
|
||||
const [amount, setAmount] = React.useState([2500])
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Payout Threshold</CardTitle>
|
||||
<CardDescription>
|
||||
Set the minimum balance required before a payout is triggered.
|
||||
</CardDescription>
|
||||
<CardAction>
|
||||
<Button variant="ghost" size="icon-sm" className="bg-muted">
|
||||
<IconPlaceholder
|
||||
lucide="XIcon"
|
||||
tabler="IconX"
|
||||
hugeicons="Cancel01Icon"
|
||||
phosphor="XIcon"
|
||||
remixicon="RiCloseLine"
|
||||
/>
|
||||
</Button>
|
||||
</CardAction>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<FieldGroup>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="preferred-currency">
|
||||
Preferred Currency
|
||||
</FieldLabel>
|
||||
<Select defaultValue="usd">
|
||||
<SelectTrigger id="preferred-currency" className="w-full">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectItem value="usd">
|
||||
USD — United States Dollar
|
||||
</SelectItem>
|
||||
<SelectItem value="eur">EUR — Euro</SelectItem>
|
||||
<SelectItem value="gbp">GBP — British Pound</SelectItem>
|
||||
<SelectItem value="jpy">JPY — Japanese Yen</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</Field>
|
||||
<Field>
|
||||
<div className="flex items-baseline justify-between">
|
||||
<FieldLabel htmlFor="min-payout">
|
||||
Minimum Payout Amount
|
||||
</FieldLabel>
|
||||
<span className="text-2xl font-semibold tabular-nums">
|
||||
${amount[0].toFixed(2)}
|
||||
</span>
|
||||
</div>
|
||||
<Slider
|
||||
id="min-payout"
|
||||
value={amount}
|
||||
onValueChange={setAmount}
|
||||
min={50}
|
||||
max={10000}
|
||||
step={50}
|
||||
/>
|
||||
<div className="flex items-center justify-between">
|
||||
<FieldDescription>$50 (MIN)</FieldDescription>
|
||||
<FieldDescription>$10,000 (MAX)</FieldDescription>
|
||||
</div>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="payout-notes">Notes</FieldLabel>
|
||||
<Textarea
|
||||
id="payout-notes"
|
||||
placeholder="Add any notes for this payout configuration..."
|
||||
className="min-h-[100px]"
|
||||
/>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</CardContent>
|
||||
<CardFooter>
|
||||
<Button className="w-full">Save Threshold</Button>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
"use client"
|
||||
|
||||
import { Bar, BarChart, XAxis } from "recharts"
|
||||
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardFooter,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/registry/bases/radix/ui/card"
|
||||
import {
|
||||
ChartContainer,
|
||||
ChartTooltip,
|
||||
ChartTooltipContent,
|
||||
type ChartConfig,
|
||||
} from "@/registry/bases/radix/ui/chart"
|
||||
import { Progress } from "@/registry/bases/radix/ui/progress"
|
||||
import { Separator } from "@/registry/bases/radix/ui/separator"
|
||||
import { useDesignSystemSearchParams } from "@/app/(app)/create/lib/search-params"
|
||||
|
||||
const chartData = [
|
||||
{ hour: "6a", usage: 1.2 },
|
||||
{ hour: "8a", usage: 2.8 },
|
||||
{ hour: "10a", usage: 3.1 },
|
||||
{ hour: "12p", usage: 2.4 },
|
||||
{ hour: "2p", usage: 3.4 },
|
||||
{ hour: "4p", usage: 2.9 },
|
||||
{ hour: "6p", usage: 3.8 },
|
||||
{ hour: "8p", usage: 3.2 },
|
||||
]
|
||||
|
||||
const chartConfig = {
|
||||
usage: {
|
||||
label: "Usage (kW)",
|
||||
color: "var(--chart-2)",
|
||||
},
|
||||
} satisfies ChartConfig
|
||||
|
||||
export function PowerUsage() {
|
||||
const [params] = useDesignSystemSearchParams()
|
||||
const isRounded = !["lyra", "sera"].includes(params.style)
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Power Usage</CardTitle>
|
||||
<CardDescription>Whole Home</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="flex flex-col gap-4">
|
||||
<ChartContainer config={chartConfig} className="h-[140px] w-full">
|
||||
<BarChart
|
||||
data={chartData}
|
||||
margin={{ left: 0, right: 0, top: 4, bottom: 0 }}
|
||||
>
|
||||
<XAxis
|
||||
dataKey="hour"
|
||||
tickLine={false}
|
||||
tickMargin={6}
|
||||
axisLine={false}
|
||||
className="text-xs"
|
||||
/>
|
||||
<ChartTooltip
|
||||
cursor={false}
|
||||
content={<ChartTooltipContent hideLabel />}
|
||||
/>
|
||||
<Bar
|
||||
dataKey="usage"
|
||||
fill="var(--color-usage)"
|
||||
radius={isRounded ? [4, 4, 0, 0] : 0}
|
||||
/>
|
||||
</BarChart>
|
||||
</ChartContainer>
|
||||
<Separator />
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div className="flex flex-col gap-0.5">
|
||||
<span className="text-sm text-muted-foreground">
|
||||
Currently Using
|
||||
</span>
|
||||
<span className="text-lg font-semibold tabular-nums">3.4 kW</span>
|
||||
</div>
|
||||
<div className="flex flex-col gap-0.5">
|
||||
<span className="text-sm text-muted-foreground">Solar Gen</span>
|
||||
<span className="text-lg font-semibold text-chart-1 tabular-nums">
|
||||
+1.2 kW
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
<CardFooter className="flex-col items-start gap-1">
|
||||
<span className="text-sm text-muted-foreground">Battery Level</span>
|
||||
<div className="flex w-full items-center gap-2">
|
||||
<Progress value={85} className="flex-1" />
|
||||
<span className="text-sm font-medium tabular-nums">85%</span>
|
||||
</div>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
import { Button } from "@/registry/bases/radix/ui/button"
|
||||
import {
|
||||
Card,
|
||||
CardAction,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardFooter,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/registry/bases/radix/ui/card"
|
||||
import {
|
||||
Field,
|
||||
FieldContent,
|
||||
FieldDescription,
|
||||
FieldGroup,
|
||||
FieldLabel,
|
||||
FieldSeparator,
|
||||
} from "@/registry/bases/radix/ui/field"
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectGroup,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/registry/bases/radix/ui/select"
|
||||
import { Switch } from "@/registry/bases/radix/ui/switch"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
export function Preferences() {
|
||||
return (
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Preferences</CardTitle>
|
||||
<CardDescription>
|
||||
Manage your account settings and notifications.
|
||||
</CardDescription>
|
||||
<CardAction>
|
||||
<Button variant="ghost" size="icon-sm" className="bg-muted">
|
||||
<IconPlaceholder
|
||||
lucide="XIcon"
|
||||
tabler="IconX"
|
||||
hugeicons="Cancel01Icon"
|
||||
phosphor="XIcon"
|
||||
remixicon="RiCloseLine"
|
||||
/>
|
||||
</Button>
|
||||
</CardAction>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<FieldGroup>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="default-currency">Default Currency</FieldLabel>
|
||||
<Select defaultValue="usd">
|
||||
<SelectTrigger id="default-currency" className="w-full">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectItem value="usd">
|
||||
USD — United States Dollar
|
||||
</SelectItem>
|
||||
<SelectItem value="eur">EUR — Euro</SelectItem>
|
||||
<SelectItem value="gbp">GBP — British Pound</SelectItem>
|
||||
<SelectItem value="jpy">JPY — Japanese Yen</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</Field>
|
||||
<FieldSeparator className="-my-4 style-sera:hidden" />
|
||||
<Field orientation="horizontal">
|
||||
<FieldContent>
|
||||
<FieldLabel htmlFor="public-statistics">
|
||||
Public Statistics
|
||||
</FieldLabel>
|
||||
<FieldDescription>
|
||||
Allow others to see your total stream count and listening
|
||||
activity
|
||||
</FieldDescription>
|
||||
</FieldContent>
|
||||
<Switch id="public-statistics" defaultChecked />
|
||||
</Field>
|
||||
<FieldSeparator className="-my-4 style-sera:hidden" />
|
||||
<Field orientation="horizontal">
|
||||
<FieldContent>
|
||||
<FieldLabel htmlFor="email-notifications">
|
||||
Email Notifications
|
||||
</FieldLabel>
|
||||
<FieldDescription>
|
||||
Monthly royalty reports and distribution updates
|
||||
</FieldDescription>
|
||||
</FieldContent>
|
||||
<Switch id="email-notifications" defaultChecked />
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</CardContent>
|
||||
<CardFooter>
|
||||
<Button variant="outline">Reset</Button>
|
||||
<Button className="ml-auto">Save Preferences</Button>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
"use client"
|
||||
|
||||
import QRCode from "react-qr-code"
|
||||
|
||||
import { Button } from "@/registry/bases/radix/ui/button"
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardFooter,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/registry/bases/radix/ui/card"
|
||||
|
||||
export function QrConnect() {
|
||||
return (
|
||||
<Card>
|
||||
<CardContent className="flex justify-center pt-6">
|
||||
<div className="rounded-xl border bg-white p-4">
|
||||
<QRCode
|
||||
value="https://ledger.app/connect/jd-4829"
|
||||
size={160}
|
||||
level="M"
|
||||
/>
|
||||
</div>
|
||||
</CardContent>
|
||||
<CardHeader className="text-center">
|
||||
<CardTitle>Scan to connect your mobile device</CardTitle>
|
||||
<CardDescription>
|
||||
Open the Ledger mobile app and scan this code to link your device.
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardFooter>
|
||||
<Button variant="secondary" className="w-full">
|
||||
Got it
|
||||
</Button>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
"use client"
|
||||
|
||||
import { Button } from "@/registry/bases/radix/ui/button"
|
||||
import {
|
||||
Card,
|
||||
CardAction,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardFooter,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/registry/bases/radix/ui/card"
|
||||
import {
|
||||
Field,
|
||||
FieldContent,
|
||||
FieldDescription,
|
||||
FieldGroup,
|
||||
FieldLabel,
|
||||
FieldLegend,
|
||||
FieldSet,
|
||||
FieldTitle,
|
||||
} from "@/registry/bases/radix/ui/field"
|
||||
import { Input } from "@/registry/bases/radix/ui/input"
|
||||
import {
|
||||
RadioGroup,
|
||||
RadioGroupItem,
|
||||
} from "@/registry/bases/radix/ui/radio-group"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
export function ReceivingMethod() {
|
||||
return (
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardDescription>Payout Preferences</CardDescription>
|
||||
<CardTitle>Receiving Method</CardTitle>
|
||||
<CardAction>
|
||||
<Button variant="ghost" size="icon-sm" className="bg-muted">
|
||||
<IconPlaceholder
|
||||
lucide="XIcon"
|
||||
tabler="IconX"
|
||||
hugeicons="Cancel01Icon"
|
||||
phosphor="XIcon"
|
||||
remixicon="RiCloseLine"
|
||||
/>
|
||||
</Button>
|
||||
</CardAction>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<FieldGroup>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="account-holder">
|
||||
Account Holder Name
|
||||
</FieldLabel>
|
||||
<Input
|
||||
id="account-holder"
|
||||
defaultValue="Synthetic Horizons Music LLC"
|
||||
/>
|
||||
</Field>
|
||||
<FieldSet>
|
||||
<FieldLegend variant="label">Receiving Method</FieldLegend>
|
||||
<RadioGroup
|
||||
defaultValue="bank"
|
||||
className="grid grid-cols-1 items-start gap-3 md:grid-cols-2 style-sera:grid-cols-1"
|
||||
>
|
||||
<FieldLabel htmlFor="method-bank">
|
||||
<Field orientation="horizontal" className="pb-2.5">
|
||||
<RadioGroupItem value="bank" id="method-bank" />
|
||||
<FieldContent>
|
||||
<FieldTitle>Bank Transfer</FieldTitle>
|
||||
<FieldDescription>SWIFT / IBAN</FieldDescription>
|
||||
</FieldContent>
|
||||
</Field>
|
||||
</FieldLabel>
|
||||
<FieldLabel htmlFor="method-paypal">
|
||||
<Field orientation="horizontal" className="pb-2.5">
|
||||
<RadioGroupItem value="paypal" id="method-paypal" />
|
||||
<FieldContent>
|
||||
<FieldTitle>PayPal</FieldTitle>
|
||||
<FieldDescription className="line-clamp-1">
|
||||
Instant Payout
|
||||
</FieldDescription>
|
||||
</FieldContent>
|
||||
</Field>
|
||||
</FieldLabel>
|
||||
</RadioGroup>
|
||||
</FieldSet>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="iban">IBAN / Account Number</FieldLabel>
|
||||
<Input id="iban" placeholder="DE89 3704 0044 ...." />
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</CardContent>
|
||||
<CardFooter>
|
||||
<Button className="w-full" disabled>
|
||||
Save Payout Settings
|
||||
</Button>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,307 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
|
||||
import { Button } from "@/registry/bases/radix/ui/button"
|
||||
import {
|
||||
Card,
|
||||
CardAction,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/registry/bases/radix/ui/card"
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/registry/bases/radix/ui/dropdown-menu"
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableRow,
|
||||
} from "@/registry/bases/radix/ui/table"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
export function RecentTransactions() {
|
||||
return (
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Recent Transactions</CardTitle>
|
||||
<CardDescription>Your latest account activity.</CardDescription>
|
||||
<CardAction>
|
||||
<Button variant="outline" size="sm">
|
||||
View All
|
||||
</Button>
|
||||
</CardAction>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<Table>
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell className="w-10">
|
||||
<div className="flex size-10 items-center justify-center rounded-lg bg-muted">
|
||||
<IconPlaceholder
|
||||
className="size-4 shrink-0"
|
||||
lucide="CoffeeIcon"
|
||||
tabler="IconCoffee"
|
||||
hugeicons="CoffeeIcon"
|
||||
phosphor="CoffeeIcon"
|
||||
remixicon="RiCupLine"
|
||||
/>
|
||||
</div>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<div className="flex flex-col">
|
||||
<span className="font-medium">Blue Bottle Coffee</span>
|
||||
<span className="text-sm text-muted-foreground">
|
||||
Food & Drink
|
||||
</span>
|
||||
</div>
|
||||
</TableCell>
|
||||
<TableCell className="text-sm text-muted-foreground">
|
||||
Today, 10:24 AM
|
||||
</TableCell>
|
||||
<TableCell className="text-right">
|
||||
<span className="text-sm font-semibold tabular-nums">
|
||||
-$6.50
|
||||
</span>
|
||||
</TableCell>
|
||||
<TableCell className="w-8">
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="ghost" size="icon-sm">
|
||||
<IconPlaceholder
|
||||
lucide="MoreHorizontalIcon"
|
||||
tabler="IconDotsVertical"
|
||||
hugeicons="MoreVerticalCircle01Icon"
|
||||
phosphor="DotsThreeIcon"
|
||||
remixicon="RiMore2Line"
|
||||
/>
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end">
|
||||
<DropdownMenuItem>View details</DropdownMenuItem>
|
||||
<DropdownMenuItem>Add note</DropdownMenuItem>
|
||||
<DropdownMenuItem>Categorize</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem>Dispute</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell className="w-10">
|
||||
<div className="flex size-10 items-center justify-center rounded-lg bg-muted">
|
||||
<IconPlaceholder
|
||||
className="size-4 shrink-0"
|
||||
lucide="ShoppingCartIcon"
|
||||
tabler="IconShoppingCart"
|
||||
hugeicons="ShoppingCart01Icon"
|
||||
phosphor="ShoppingCartIcon"
|
||||
remixicon="RiShoppingCartLine"
|
||||
/>
|
||||
</div>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<div className="flex flex-col">
|
||||
<span className="font-medium">Whole Foods Market</span>
|
||||
<span className="text-sm text-muted-foreground">
|
||||
Groceries
|
||||
</span>
|
||||
</div>
|
||||
</TableCell>
|
||||
<TableCell className="text-sm text-muted-foreground">
|
||||
Yesterday
|
||||
</TableCell>
|
||||
<TableCell className="text-right">
|
||||
<span className="text-sm font-semibold tabular-nums">
|
||||
-$142.30
|
||||
</span>
|
||||
</TableCell>
|
||||
<TableCell className="w-8">
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="ghost" size="icon-sm">
|
||||
<IconPlaceholder
|
||||
lucide="MoreHorizontalIcon"
|
||||
tabler="IconDotsVertical"
|
||||
hugeicons="MoreVerticalCircle01Icon"
|
||||
phosphor="DotsThreeIcon"
|
||||
remixicon="RiMore2Line"
|
||||
/>
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end">
|
||||
<DropdownMenuItem>View details</DropdownMenuItem>
|
||||
<DropdownMenuItem>Add note</DropdownMenuItem>
|
||||
<DropdownMenuItem>Categorize</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem>Dispute</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell className="w-10">
|
||||
<div className="flex size-10 items-center justify-center rounded-lg bg-muted">
|
||||
<IconPlaceholder
|
||||
className="size-4 shrink-0"
|
||||
lucide="WalletIcon"
|
||||
tabler="IconWallet"
|
||||
hugeicons="Wallet01Icon"
|
||||
phosphor="WalletIcon"
|
||||
remixicon="RiWalletLine"
|
||||
/>
|
||||
</div>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<div className="flex flex-col">
|
||||
<span className="font-medium">Stripe Payout</span>
|
||||
<span className="text-sm text-muted-foreground">Income</span>
|
||||
</div>
|
||||
</TableCell>
|
||||
<TableCell className="text-sm text-muted-foreground">
|
||||
Oct 12
|
||||
</TableCell>
|
||||
<TableCell className="text-right">
|
||||
<span className="text-sm font-semibold text-emerald-500 tabular-nums">
|
||||
+$4,200.00
|
||||
</span>
|
||||
</TableCell>
|
||||
<TableCell className="w-8">
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="ghost" size="icon-sm">
|
||||
<IconPlaceholder
|
||||
lucide="MoreHorizontalIcon"
|
||||
tabler="IconDotsVertical"
|
||||
hugeicons="MoreVerticalCircle01Icon"
|
||||
phosphor="DotsThreeIcon"
|
||||
remixicon="RiMore2Line"
|
||||
/>
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end">
|
||||
<DropdownMenuItem>View details</DropdownMenuItem>
|
||||
<DropdownMenuItem>Add note</DropdownMenuItem>
|
||||
<DropdownMenuItem>Categorize</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem>Dispute</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell className="w-10">
|
||||
<div className="flex size-10 items-center justify-center rounded-lg bg-muted">
|
||||
<IconPlaceholder
|
||||
className="size-4 shrink-0"
|
||||
lucide="CarIcon"
|
||||
tabler="IconCar"
|
||||
hugeicons="Car01Icon"
|
||||
phosphor="CarIcon"
|
||||
remixicon="RiCarLine"
|
||||
/>
|
||||
</div>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<div className="flex flex-col">
|
||||
<span className="font-medium">Uber Technologies</span>
|
||||
<span className="text-sm text-muted-foreground">
|
||||
Transport
|
||||
</span>
|
||||
</div>
|
||||
</TableCell>
|
||||
<TableCell className="text-sm text-muted-foreground">
|
||||
Oct 11
|
||||
</TableCell>
|
||||
<TableCell className="text-right">
|
||||
<span className="text-sm font-semibold tabular-nums">
|
||||
-$24.10
|
||||
</span>
|
||||
</TableCell>
|
||||
<TableCell className="w-8">
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="ghost" size="icon-sm">
|
||||
<IconPlaceholder
|
||||
lucide="MoreHorizontalIcon"
|
||||
tabler="IconDotsVertical"
|
||||
hugeicons="MoreVerticalCircle01Icon"
|
||||
phosphor="DotsThreeIcon"
|
||||
remixicon="RiMore2Line"
|
||||
/>
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end">
|
||||
<DropdownMenuItem>View details</DropdownMenuItem>
|
||||
<DropdownMenuItem>Add note</DropdownMenuItem>
|
||||
<DropdownMenuItem>Categorize</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem>Dispute</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell className="w-10">
|
||||
<div className="flex size-10 items-center justify-center rounded-lg bg-muted">
|
||||
<IconPlaceholder
|
||||
className="size-4 shrink-0"
|
||||
lucide="TvIcon"
|
||||
tabler="IconDeviceTv"
|
||||
hugeicons="Tv01Icon"
|
||||
phosphor="TelevisionIcon"
|
||||
remixicon="RiTvLine"
|
||||
/>
|
||||
</div>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<div className="flex flex-col">
|
||||
<span className="font-medium">Netflix Subscription</span>
|
||||
<span className="text-sm text-muted-foreground">
|
||||
Entertainment
|
||||
</span>
|
||||
</div>
|
||||
</TableCell>
|
||||
<TableCell className="text-sm text-muted-foreground">
|
||||
Oct 10
|
||||
</TableCell>
|
||||
<TableCell className="text-right">
|
||||
<span className="text-sm font-semibold tabular-nums">
|
||||
-$19.99
|
||||
</span>
|
||||
</TableCell>
|
||||
<TableCell className="w-8">
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="ghost" size="icon-sm">
|
||||
<IconPlaceholder
|
||||
lucide="MoreHorizontalIcon"
|
||||
tabler="IconDotsVertical"
|
||||
hugeicons="MoreVerticalCircle01Icon"
|
||||
phosphor="DotsThreeIcon"
|
||||
remixicon="RiMore2Line"
|
||||
/>
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end">
|
||||
<DropdownMenuItem>View details</DropdownMenuItem>
|
||||
<DropdownMenuItem>Add note</DropdownMenuItem>
|
||||
<DropdownMenuItem>Categorize</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem>Dispute</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
</Table>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
"use client"
|
||||
|
||||
import { Badge } from "@/registry/bases/radix/ui/badge"
|
||||
import { Card, CardContent, CardHeader } from "@/registry/bases/radix/ui/card"
|
||||
import {
|
||||
InputGroup,
|
||||
InputGroupAddon,
|
||||
InputGroupInput,
|
||||
} from "@/registry/bases/radix/ui/input-group"
|
||||
import {
|
||||
Item,
|
||||
ItemContent,
|
||||
ItemDescription,
|
||||
ItemGroup,
|
||||
ItemMedia,
|
||||
ItemTitle,
|
||||
} from "@/registry/bases/radix/ui/item"
|
||||
import {
|
||||
ToggleGroup,
|
||||
ToggleGroupItem,
|
||||
} from "@/registry/bases/radix/ui/toggle-group"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
const HOLDINGS = [
|
||||
{
|
||||
ticker: "VOO",
|
||||
name: "Vanguard S&P 500 ETF",
|
||||
type: "ETF",
|
||||
added: "Jan 2021",
|
||||
shares: "112",
|
||||
value: "$48,230.40",
|
||||
},
|
||||
{
|
||||
ticker: "VIG",
|
||||
name: "Vanguard Dividend Appreciation",
|
||||
type: "ETF",
|
||||
added: "Mar 2022",
|
||||
shares: "450",
|
||||
value: "$26,033.79",
|
||||
},
|
||||
{
|
||||
ticker: "AAPL",
|
||||
name: "Apple Inc.",
|
||||
type: "Stock",
|
||||
added: "Nov 2020",
|
||||
shares: "85",
|
||||
value: "$18,488.90",
|
||||
},
|
||||
{
|
||||
ticker: "O",
|
||||
name: "Realty Income Corp",
|
||||
type: "REIT",
|
||||
added: "Jun 2023",
|
||||
shares: "320",
|
||||
value: "$15,136.59",
|
||||
},
|
||||
]
|
||||
|
||||
export function ReleaseCatalog() {
|
||||
return (
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<div className="flex items-center justify-between gap-3">
|
||||
<InputGroup className="max-w-sm">
|
||||
<InputGroupAddon>
|
||||
<IconPlaceholder
|
||||
lucide="SearchIcon"
|
||||
tabler="IconSearch"
|
||||
hugeicons="Search01Icon"
|
||||
phosphor="MagnifyingGlassIcon"
|
||||
remixicon="RiSearchLine"
|
||||
/>
|
||||
</InputGroupAddon>
|
||||
<InputGroupInput placeholder="Search holdings or tickers..." />
|
||||
</InputGroup>
|
||||
<ToggleGroup
|
||||
type="single"
|
||||
defaultValue="etfs"
|
||||
variant="outline"
|
||||
spacing={1}
|
||||
>
|
||||
<ToggleGroupItem value="stocks">Stocks</ToggleGroupItem>
|
||||
<ToggleGroupItem value="etfs">ETFs</ToggleGroupItem>
|
||||
<ToggleGroupItem value="reits">REITs</ToggleGroupItem>
|
||||
</ToggleGroup>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<ItemGroup>
|
||||
{HOLDINGS.map((holding) => (
|
||||
<Item key={holding.ticker} variant="muted">
|
||||
<ItemMedia>
|
||||
<div className="flex size-12 items-center justify-center rounded-lg border text-sm font-semibold">
|
||||
{holding.ticker}
|
||||
</div>
|
||||
</ItemMedia>
|
||||
<ItemContent>
|
||||
<ItemTitle>{holding.name}</ItemTitle>
|
||||
<ItemDescription className="text-xs tracking-wider uppercase">
|
||||
{holding.shares} Shares · {holding.added}
|
||||
</ItemDescription>
|
||||
</ItemContent>
|
||||
<div className="flex shrink-0 items-center gap-6">
|
||||
<Badge variant="outline">{holding.type}</Badge>
|
||||
<div className="flex flex-col items-end gap-0.5">
|
||||
<span className="text-xs tracking-wider text-muted-foreground uppercase">
|
||||
Value
|
||||
</span>
|
||||
<span className="font-medium tabular-nums">
|
||||
{holding.value}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</Item>
|
||||
))}
|
||||
</ItemGroup>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardFooter,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/registry/bases/radix/ui/card"
|
||||
import { Slider } from "@/registry/bases/radix/ui/slider"
|
||||
import {
|
||||
ToggleGroup,
|
||||
ToggleGroupItem,
|
||||
} from "@/registry/bases/radix/ui/toggle-group"
|
||||
|
||||
export function RollerShades() {
|
||||
const [position, setPosition] = React.useState([50])
|
||||
|
||||
const preset =
|
||||
position[0] <= 10 ? "open" : position[0] >= 90 ? "closed" : "half"
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Living Room</CardTitle>
|
||||
<CardDescription>Roller Shades</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="flex flex-col gap-4">
|
||||
<div className="flex h-32 flex-col overflow-hidden rounded-lg border bg-muted">
|
||||
<div
|
||||
className="bg-muted-foreground transition-all duration-300"
|
||||
style={{ height: `${position[0]}%` }}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex items-center gap-3">
|
||||
<span className="text-xs font-medium tracking-wider text-muted-foreground uppercase">
|
||||
Open
|
||||
</span>
|
||||
<Slider
|
||||
value={position}
|
||||
onValueChange={setPosition}
|
||||
max={100}
|
||||
className="flex-1"
|
||||
/>
|
||||
<span className="text-xs font-medium tracking-wider text-muted-foreground uppercase">
|
||||
Close
|
||||
</span>
|
||||
</div>
|
||||
</CardContent>
|
||||
<CardFooter>
|
||||
<ToggleGroup
|
||||
type="single"
|
||||
value={preset}
|
||||
onValueChange={(value) => {
|
||||
if (value === "open") setPosition([0])
|
||||
if (value === "half") setPosition([50])
|
||||
if (value === "closed") setPosition([100])
|
||||
}}
|
||||
variant="outline"
|
||||
spacing={1}
|
||||
className="w-full"
|
||||
>
|
||||
<ToggleGroupItem value="open" className="flex-1">
|
||||
Open
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem value="half" className="flex-1">
|
||||
Half
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem value="closed" className="flex-1">
|
||||
Closed
|
||||
</ToggleGroupItem>
|
||||
</ToggleGroup>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
"use client"
|
||||
|
||||
import { Label, Pie, PieChart } from "recharts"
|
||||
|
||||
import { Card, CardContent, CardFooter } from "@/registry/bases/radix/ui/card"
|
||||
import {
|
||||
ChartContainer,
|
||||
ChartTooltip,
|
||||
ChartTooltipContent,
|
||||
type ChartConfig,
|
||||
} from "@/registry/bases/radix/ui/chart"
|
||||
import { Separator } from "@/registry/bases/radix/ui/separator"
|
||||
|
||||
const chartData = [
|
||||
{ name: "saved", value: 24000, fill: "var(--color-saved)" },
|
||||
{ name: "remaining", value: 6000, fill: "var(--color-remaining)" },
|
||||
]
|
||||
|
||||
const chartConfig = {
|
||||
saved: {
|
||||
label: "Saved",
|
||||
color: "var(--chart-2)",
|
||||
},
|
||||
remaining: {
|
||||
label: "Remaining",
|
||||
color: "var(--chart-1)",
|
||||
},
|
||||
} satisfies ChartConfig
|
||||
|
||||
export function SavingsProgress() {
|
||||
return (
|
||||
<Card>
|
||||
<CardContent>
|
||||
<ChartContainer
|
||||
config={chartConfig}
|
||||
className="mx-auto aspect-square max-h-[220px]"
|
||||
>
|
||||
<PieChart>
|
||||
<ChartTooltip
|
||||
cursor={false}
|
||||
content={<ChartTooltipContent hideLabel />}
|
||||
/>
|
||||
<Pie
|
||||
data={chartData}
|
||||
dataKey="value"
|
||||
nameKey="name"
|
||||
innerRadius={70}
|
||||
outerRadius={95}
|
||||
strokeWidth={0}
|
||||
startAngle={90}
|
||||
endAngle={-270}
|
||||
>
|
||||
<Label
|
||||
content={({ viewBox }) => {
|
||||
if (viewBox && "cx" in viewBox && "cy" in viewBox) {
|
||||
return (
|
||||
<text
|
||||
x={viewBox.cx}
|
||||
y={viewBox.cy}
|
||||
textAnchor="middle"
|
||||
dominantBaseline="middle"
|
||||
>
|
||||
<tspan
|
||||
x={viewBox.cx}
|
||||
y={(viewBox.cy || 0) - 12}
|
||||
className="fill-foreground text-2xl font-bold"
|
||||
>
|
||||
$24,000
|
||||
</tspan>
|
||||
<tspan
|
||||
x={viewBox.cx}
|
||||
y={(viewBox.cy || 0) + 12}
|
||||
className="fill-muted-foreground text-xs"
|
||||
>
|
||||
80% of $30,000
|
||||
</tspan>
|
||||
</text>
|
||||
)
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</Pie>
|
||||
</PieChart>
|
||||
</ChartContainer>
|
||||
</CardContent>
|
||||
<CardFooter className="flex-col gap-0">
|
||||
<div className="flex w-full items-center justify-between py-3">
|
||||
<span className="text-sm text-muted-foreground">
|
||||
Projected Finish
|
||||
</span>
|
||||
<span className="text-sm font-semibold">October 2024</span>
|
||||
</div>
|
||||
<Separator />
|
||||
<div className="flex w-full items-center justify-between py-3">
|
||||
<span className="text-sm text-muted-foreground">Monthly Average</span>
|
||||
<span className="text-sm font-semibold tabular-nums">$1,250</span>
|
||||
</div>
|
||||
<Separator />
|
||||
<div className="flex w-full items-center justify-between py-3">
|
||||
<span className="text-sm text-muted-foreground">Top Contributor</span>
|
||||
<span className="text-sm font-semibold">Auto-Transfer</span>
|
||||
</div>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
import { Button } from "@/registry/bases/radix/ui/button"
|
||||
import {
|
||||
Card,
|
||||
CardAction,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardFooter,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/registry/bases/radix/ui/card"
|
||||
import {
|
||||
Field,
|
||||
FieldDescription,
|
||||
FieldGroup,
|
||||
FieldLabel,
|
||||
} from "@/registry/bases/radix/ui/field"
|
||||
import {
|
||||
InputGroup,
|
||||
InputGroupAddon,
|
||||
InputGroupInput,
|
||||
InputGroupText,
|
||||
} from "@/registry/bases/radix/ui/input-group"
|
||||
import {
|
||||
Item,
|
||||
ItemContent,
|
||||
ItemDescription,
|
||||
ItemFooter,
|
||||
ItemGroup,
|
||||
} from "@/registry/bases/radix/ui/item"
|
||||
import {
|
||||
NativeSelect,
|
||||
NativeSelectOption,
|
||||
} from "@/registry/bases/radix/ui/native-select"
|
||||
import { Progress } from "@/registry/bases/radix/ui/progress"
|
||||
|
||||
export function SavingsTargets() {
|
||||
return (
|
||||
<div className="grid grid-cols-2 gap-(--gap)">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Savings Targets</CardTitle>
|
||||
<CardDescription>Active milestones for 2024</CardDescription>
|
||||
<CardAction>
|
||||
<Button variant="outline" size="sm">
|
||||
New Goal
|
||||
</Button>
|
||||
</CardAction>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<ItemGroup className="gap-3">
|
||||
<Item variant="muted" className="flex-col items-stretch">
|
||||
<ItemContent className="gap-3">
|
||||
<ItemDescription className="cn-font-heading text-xs font-medium tracking-wider text-muted-foreground uppercase">
|
||||
Retirement
|
||||
</ItemDescription>
|
||||
<span className="text-3xl font-semibold tabular-nums">
|
||||
$420,000
|
||||
</span>
|
||||
<Progress value={65} />
|
||||
</ItemContent>
|
||||
<ItemFooter>
|
||||
<span className="text-sm text-muted-foreground">
|
||||
65% achieved
|
||||
</span>
|
||||
<span className="text-sm font-medium tabular-nums">
|
||||
$273,000
|
||||
</span>
|
||||
</ItemFooter>
|
||||
</Item>
|
||||
<Item variant="muted" className="flex-col items-stretch">
|
||||
<ItemContent className="gap-3">
|
||||
<ItemDescription className="cn-font-heading text-xs font-medium tracking-wider text-muted-foreground uppercase">
|
||||
Real Estate
|
||||
</ItemDescription>
|
||||
<span className="text-3xl font-semibold tabular-nums">
|
||||
$85,000
|
||||
</span>
|
||||
<Progress value={32} />
|
||||
</ItemContent>
|
||||
<ItemFooter>
|
||||
<span className="text-sm text-muted-foreground">
|
||||
32% achieved
|
||||
</span>
|
||||
<span className="text-sm font-medium tabular-nums">
|
||||
$27,200
|
||||
</span>
|
||||
</ItemFooter>
|
||||
</Item>
|
||||
</ItemGroup>
|
||||
</CardContent>
|
||||
<CardFooter>
|
||||
<CardDescription className="text-center">
|
||||
You have not met your targets for this year.
|
||||
</CardDescription>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Buy Investment</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="flex flex-1 flex-col gap-3">
|
||||
<FieldGroup className="flex-1">
|
||||
<Field>
|
||||
<FieldLabel htmlFor="invest-amount">Amount to Invest</FieldLabel>
|
||||
<InputGroup>
|
||||
<InputGroupAddon>
|
||||
<InputGroupText>$</InputGroupText>
|
||||
</InputGroupAddon>
|
||||
<InputGroupInput id="invest-amount" defaultValue="1,000.00" />
|
||||
</InputGroup>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="invest-type">Order Type</FieldLabel>
|
||||
<NativeSelect id="invest-type" defaultValue="market">
|
||||
<NativeSelectOption value="market">
|
||||
Market Order
|
||||
</NativeSelectOption>
|
||||
<NativeSelectOption value="limit">
|
||||
Limit Order
|
||||
</NativeSelectOption>
|
||||
<NativeSelectOption value="stop">Stop Order</NativeSelectOption>
|
||||
</NativeSelect>
|
||||
<FieldDescription>
|
||||
Market orders execute at the current price.
|
||||
</FieldDescription>
|
||||
</Field>
|
||||
<div className="flex flex-col gap-2">
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-sm text-muted-foreground">
|
||||
Estimated Shares
|
||||
</span>
|
||||
<span className="text-sm font-semibold tabular-nums">1.95</span>
|
||||
</div>
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-sm text-muted-foreground">
|
||||
Buying Power
|
||||
</span>
|
||||
<span className="text-sm font-semibold tabular-nums">
|
||||
$12,450.00
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</FieldGroup>
|
||||
</CardContent>
|
||||
<CardFooter className="flex-col gap-3">
|
||||
<Button className="w-full">Review Order</Button>
|
||||
<CardDescription className="text-center">
|
||||
Trades are typically executed within minutes during market hours.
|
||||
</CardDescription>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,285 @@
|
||||
"use client"
|
||||
|
||||
import { Card } from "@/registry/bases/radix/ui/card"
|
||||
import {
|
||||
Sidebar,
|
||||
SidebarContent,
|
||||
SidebarGroup,
|
||||
SidebarGroupContent,
|
||||
SidebarGroupLabel,
|
||||
SidebarMenu,
|
||||
SidebarMenuButton,
|
||||
SidebarMenuItem,
|
||||
SidebarProvider,
|
||||
SidebarSeparator,
|
||||
} from "@/registry/bases/radix/ui/sidebar"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
export function SidebarNav() {
|
||||
return (
|
||||
<div className="grid grid-cols-2 items-start gap-6">
|
||||
<Card className="overflow-hidden py-0">
|
||||
<SidebarProvider className="min-h-0">
|
||||
<Sidebar collapsible="none" className="w-full bg-transparent">
|
||||
<SidebarContent className="gap-0">
|
||||
<SidebarGroup className="pb-1">
|
||||
<SidebarGroupLabel>Overview</SidebarGroupLabel>
|
||||
<SidebarGroupContent>
|
||||
<SidebarMenu>
|
||||
<SidebarMenuItem>
|
||||
<SidebarMenuButton isActive>
|
||||
<IconPlaceholder
|
||||
lucide="LayoutDashboardIcon"
|
||||
tabler="IconLayoutDashboard"
|
||||
hugeicons="DashboardSquare01Icon"
|
||||
phosphor="SquaresFourIcon"
|
||||
remixicon="RiDashboardLine"
|
||||
/>
|
||||
Dashboard
|
||||
</SidebarMenuButton>
|
||||
</SidebarMenuItem>
|
||||
<SidebarMenuItem>
|
||||
<SidebarMenuButton>
|
||||
<IconPlaceholder
|
||||
lucide="ArrowLeftRightIcon"
|
||||
tabler="IconArrowsLeftRight"
|
||||
hugeicons="ArrowDataTransferHorizontalIcon"
|
||||
phosphor="ArrowsLeftRightIcon"
|
||||
remixicon="RiArrowLeftRightLine"
|
||||
/>
|
||||
Transactions
|
||||
</SidebarMenuButton>
|
||||
</SidebarMenuItem>
|
||||
<SidebarMenuItem>
|
||||
<SidebarMenuButton>
|
||||
<IconPlaceholder
|
||||
lucide="TrendingUpIcon"
|
||||
tabler="IconTrendingUp"
|
||||
hugeicons="AnalyticsUpIcon"
|
||||
phosphor="TrendUpIcon"
|
||||
remixicon="RiLineChartLine"
|
||||
/>
|
||||
Investments
|
||||
</SidebarMenuButton>
|
||||
</SidebarMenuItem>
|
||||
<SidebarMenuItem>
|
||||
<SidebarMenuButton>
|
||||
<IconPlaceholder
|
||||
lucide="Building2Icon"
|
||||
tabler="IconBuildingBank"
|
||||
hugeicons="BankIcon"
|
||||
phosphor="BankIcon"
|
||||
remixicon="RiBankLine"
|
||||
/>
|
||||
Accounts
|
||||
</SidebarMenuButton>
|
||||
</SidebarMenuItem>
|
||||
<SidebarMenuItem>
|
||||
<SidebarMenuButton>
|
||||
<IconPlaceholder
|
||||
lucide="PieChartIcon"
|
||||
tabler="IconChartPie"
|
||||
hugeicons="PieChartIcon"
|
||||
phosphor="ChartPieIcon"
|
||||
remixicon="RiPieChartLine"
|
||||
/>
|
||||
Spending
|
||||
</SidebarMenuButton>
|
||||
</SidebarMenuItem>
|
||||
</SidebarMenu>
|
||||
</SidebarGroupContent>
|
||||
</SidebarGroup>
|
||||
<SidebarSeparator className="w-auto!" />
|
||||
<SidebarGroup className="pt-1">
|
||||
<SidebarGroupLabel>Planning</SidebarGroupLabel>
|
||||
<SidebarGroupContent>
|
||||
<SidebarMenu>
|
||||
<SidebarMenuItem>
|
||||
<SidebarMenuButton>
|
||||
<IconPlaceholder
|
||||
lucide="TargetIcon"
|
||||
tabler="IconTarget"
|
||||
hugeicons="Target02Icon"
|
||||
phosphor="TargetIcon"
|
||||
remixicon="RiFocus3Line"
|
||||
/>
|
||||
Goals
|
||||
</SidebarMenuButton>
|
||||
</SidebarMenuItem>
|
||||
<SidebarMenuItem>
|
||||
<SidebarMenuButton>
|
||||
<IconPlaceholder
|
||||
lucide="WalletIcon"
|
||||
tabler="IconWallet"
|
||||
hugeicons="Wallet01Icon"
|
||||
phosphor="WalletIcon"
|
||||
remixicon="RiWalletLine"
|
||||
/>
|
||||
Budget
|
||||
</SidebarMenuButton>
|
||||
</SidebarMenuItem>
|
||||
<SidebarMenuItem>
|
||||
<SidebarMenuButton>
|
||||
<IconPlaceholder
|
||||
lucide="FileBarChartIcon"
|
||||
tabler="IconReportAnalytics"
|
||||
hugeicons="ChartBarLineIcon"
|
||||
phosphor="ChartBarIcon"
|
||||
remixicon="RiBarChartLine"
|
||||
/>
|
||||
Reports
|
||||
</SidebarMenuButton>
|
||||
</SidebarMenuItem>
|
||||
<SidebarMenuItem>
|
||||
<SidebarMenuButton>
|
||||
<IconPlaceholder
|
||||
lucide="FileTextIcon"
|
||||
tabler="IconFileText"
|
||||
hugeicons="File02Icon"
|
||||
phosphor="FileTextIcon"
|
||||
remixicon="RiFileTextLine"
|
||||
/>
|
||||
Documents
|
||||
</SidebarMenuButton>
|
||||
</SidebarMenuItem>
|
||||
</SidebarMenu>
|
||||
</SidebarGroupContent>
|
||||
</SidebarGroup>
|
||||
</SidebarContent>
|
||||
</Sidebar>
|
||||
</SidebarProvider>
|
||||
</Card>
|
||||
<Card className="overflow-hidden py-0">
|
||||
<SidebarProvider className="min-h-0">
|
||||
<Sidebar collapsible="none" className="w-full bg-transparent">
|
||||
<SidebarContent className="gap-0">
|
||||
<SidebarGroup className="pb-1">
|
||||
<SidebarGroupLabel>Account</SidebarGroupLabel>
|
||||
<SidebarGroupContent>
|
||||
<SidebarMenu>
|
||||
<SidebarMenuItem>
|
||||
<SidebarMenuButton>
|
||||
<IconPlaceholder
|
||||
lucide="UserIcon"
|
||||
tabler="IconUser"
|
||||
hugeicons="UserIcon"
|
||||
phosphor="UserIcon"
|
||||
remixicon="RiUserLine"
|
||||
/>
|
||||
Profile
|
||||
</SidebarMenuButton>
|
||||
</SidebarMenuItem>
|
||||
<SidebarMenuItem>
|
||||
<SidebarMenuButton isActive>
|
||||
<IconPlaceholder
|
||||
lucide="CreditCardIcon"
|
||||
tabler="IconCreditCard"
|
||||
hugeicons="CreditCardIcon"
|
||||
phosphor="CreditCardIcon"
|
||||
remixicon="RiBankCardLine"
|
||||
/>
|
||||
Billing
|
||||
</SidebarMenuButton>
|
||||
</SidebarMenuItem>
|
||||
<SidebarMenuItem>
|
||||
<SidebarMenuButton>
|
||||
<IconPlaceholder
|
||||
lucide="BellIcon"
|
||||
tabler="IconBell"
|
||||
hugeicons="Notification03Icon"
|
||||
phosphor="BellIcon"
|
||||
remixicon="RiBellLine"
|
||||
/>
|
||||
Notifications
|
||||
</SidebarMenuButton>
|
||||
</SidebarMenuItem>
|
||||
<SidebarMenuItem>
|
||||
<SidebarMenuButton>
|
||||
<IconPlaceholder
|
||||
lucide="ShieldIcon"
|
||||
tabler="IconShield"
|
||||
hugeicons="ShieldIcon"
|
||||
phosphor="ShieldIcon"
|
||||
remixicon="RiShieldLine"
|
||||
/>
|
||||
Security
|
||||
</SidebarMenuButton>
|
||||
</SidebarMenuItem>
|
||||
<SidebarMenuItem>
|
||||
<SidebarMenuButton>
|
||||
<IconPlaceholder
|
||||
lucide="PaintbrushIcon"
|
||||
tabler="IconPalette"
|
||||
hugeicons="PaintBoardIcon"
|
||||
phosphor="PaletteIcon"
|
||||
remixicon="RiPaletteLine"
|
||||
/>
|
||||
Appearance
|
||||
</SidebarMenuButton>
|
||||
</SidebarMenuItem>
|
||||
</SidebarMenu>
|
||||
</SidebarGroupContent>
|
||||
</SidebarGroup>
|
||||
<SidebarSeparator className="w-auto!" />
|
||||
<SidebarGroup className="pt-1">
|
||||
<SidebarGroupLabel>Support</SidebarGroupLabel>
|
||||
<SidebarGroupContent>
|
||||
<SidebarMenu>
|
||||
<SidebarMenuItem>
|
||||
<SidebarMenuButton>
|
||||
<IconPlaceholder
|
||||
lucide="CircleHelpIcon"
|
||||
tabler="IconHelp"
|
||||
hugeicons="HelpCircleIcon"
|
||||
phosphor="QuestionIcon"
|
||||
remixicon="RiQuestionLine"
|
||||
/>
|
||||
Help Center
|
||||
</SidebarMenuButton>
|
||||
</SidebarMenuItem>
|
||||
<SidebarMenuItem>
|
||||
<SidebarMenuButton>
|
||||
<IconPlaceholder
|
||||
lucide="MessageSquareIcon"
|
||||
tabler="IconMessage"
|
||||
hugeicons="Message01Icon"
|
||||
phosphor="ChatIcon"
|
||||
remixicon="RiChat1Line"
|
||||
/>
|
||||
Contact Us
|
||||
</SidebarMenuButton>
|
||||
</SidebarMenuItem>
|
||||
<SidebarMenuItem>
|
||||
<SidebarMenuButton>
|
||||
<IconPlaceholder
|
||||
lucide="BookOpenIcon"
|
||||
tabler="IconBook"
|
||||
hugeicons="BookOpen02Icon"
|
||||
phosphor="BookOpenIcon"
|
||||
remixicon="RiBookOpenLine"
|
||||
/>
|
||||
Documentation
|
||||
</SidebarMenuButton>
|
||||
</SidebarMenuItem>
|
||||
<SidebarMenuItem>
|
||||
<SidebarMenuButton>
|
||||
<IconPlaceholder
|
||||
lucide="ActivityIcon"
|
||||
tabler="IconActivity"
|
||||
hugeicons="ActivityIcon"
|
||||
phosphor="ActivityIcon"
|
||||
remixicon="RiPulseLine"
|
||||
/>
|
||||
Status
|
||||
</SidebarMenuButton>
|
||||
</SidebarMenuItem>
|
||||
</SidebarMenu>
|
||||
</SidebarGroupContent>
|
||||
</SidebarGroup>
|
||||
</SidebarContent>
|
||||
</Sidebar>
|
||||
</SidebarProvider>
|
||||
</Card>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
import { Button } from "@/registry/bases/radix/ui/button"
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardFooter,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/registry/bases/radix/ui/card"
|
||||
import { Field, FieldGroup, FieldLabel } from "@/registry/bases/radix/ui/field"
|
||||
import {
|
||||
InputGroup,
|
||||
InputGroupAddon,
|
||||
InputGroupInput,
|
||||
} from "@/registry/bases/radix/ui/input-group"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
export function SocialLinks() {
|
||||
return (
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Social Links</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<FieldGroup>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="spotify-url">Spotify Artist URL</FieldLabel>
|
||||
<InputGroup>
|
||||
<InputGroupAddon>
|
||||
<IconPlaceholder
|
||||
lucide="CirclePlusIcon"
|
||||
tabler="IconCirclePlus"
|
||||
hugeicons="PlusSignCircleIcon"
|
||||
phosphor="PlusCircleIcon"
|
||||
remixicon="RiAddCircleLine"
|
||||
/>
|
||||
</InputGroupAddon>
|
||||
<InputGroupInput
|
||||
id="spotify-url"
|
||||
defaultValue="spotify.com/artist/3j...2k"
|
||||
/>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="instagram-handle">Instagram Handle</FieldLabel>
|
||||
<InputGroup>
|
||||
<InputGroupAddon>
|
||||
<IconPlaceholder
|
||||
lucide="CameraIcon"
|
||||
tabler="IconCamera"
|
||||
hugeicons="Camera01Icon"
|
||||
phosphor="CameraIcon"
|
||||
remixicon="RiCameraLine"
|
||||
/>
|
||||
</InputGroupAddon>
|
||||
<InputGroupInput
|
||||
id="instagram-handle"
|
||||
defaultValue="@julianduryea_music"
|
||||
/>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="soundcloud-url">SoundCloud URL</FieldLabel>
|
||||
<InputGroup>
|
||||
<InputGroupAddon>
|
||||
<IconPlaceholder
|
||||
lucide="CloudIcon"
|
||||
tabler="IconCloud"
|
||||
hugeicons="CloudUploadIcon"
|
||||
phosphor="CloudIcon"
|
||||
remixicon="RiCloudLine"
|
||||
/>
|
||||
</InputGroupAddon>
|
||||
<InputGroupInput
|
||||
id="soundcloud-url"
|
||||
placeholder="soundcloud.com/username"
|
||||
/>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="website-url">Website</FieldLabel>
|
||||
<InputGroup>
|
||||
<InputGroupAddon>
|
||||
<IconPlaceholder
|
||||
lucide="GlobeIcon"
|
||||
tabler="IconWorld"
|
||||
hugeicons="Globe02Icon"
|
||||
phosphor="GlobeIcon"
|
||||
remixicon="RiGlobalLine"
|
||||
/>
|
||||
</InputGroupAddon>
|
||||
<InputGroupInput
|
||||
id="website-url"
|
||||
placeholder="https://yoursite.com"
|
||||
/>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</CardContent>
|
||||
<CardFooter className="justify-end gap-2 style-sera:justify-center">
|
||||
<Button variant="secondary" className="style-sera:flex-1">
|
||||
Discard
|
||||
</Button>
|
||||
<Button className="style-sera:flex-1">Save Changes</Button>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import { Area, AreaChart, CartesianGrid, XAxis } from "recharts"
|
||||
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/registry/bases/radix/ui/card"
|
||||
import {
|
||||
ChartContainer,
|
||||
ChartTooltip,
|
||||
ChartTooltipContent,
|
||||
type ChartConfig,
|
||||
} from "@/registry/bases/radix/ui/chart"
|
||||
import {
|
||||
Combobox,
|
||||
ComboboxContent,
|
||||
ComboboxEmpty,
|
||||
ComboboxInput,
|
||||
ComboboxItem,
|
||||
ComboboxList,
|
||||
} from "@/registry/bases/radix/ui/combobox"
|
||||
import { Field, FieldGroup, FieldLabel } from "@/registry/bases/radix/ui/field"
|
||||
import { Separator } from "@/registry/bases/radix/ui/separator"
|
||||
|
||||
const TICKERS = ["VOO", "VIG", "AAPL", "MSFT", "GOOGL", "AMZN", "TSLA"]
|
||||
|
||||
const CHART_DATA: Record<string, { month: string; price: number }[]> = {
|
||||
VOO: [
|
||||
{ month: "Jan", price: 412 },
|
||||
{ month: "Feb", price: 438 },
|
||||
{ month: "Mar", price: 395 },
|
||||
{ month: "Apr", price: 450 },
|
||||
{ month: "May", price: 420 },
|
||||
{ month: "Jun", price: 462 },
|
||||
],
|
||||
AAPL: [
|
||||
{ month: "Jan", price: 185 },
|
||||
{ month: "Feb", price: 210 },
|
||||
{ month: "Mar", price: 172 },
|
||||
{ month: "Apr", price: 198 },
|
||||
{ month: "May", price: 178 },
|
||||
{ month: "Jun", price: 215 },
|
||||
],
|
||||
}
|
||||
|
||||
const DEFAULT_DATA = [
|
||||
{ month: "Jan", price: 100 },
|
||||
{ month: "Feb", price: 118 },
|
||||
{ month: "Mar", price: 95 },
|
||||
{ month: "Apr", price: 125 },
|
||||
{ month: "May", price: 108 },
|
||||
{ month: "Jun", price: 130 },
|
||||
]
|
||||
|
||||
const chartConfig = {
|
||||
price: {
|
||||
label: "Price",
|
||||
color: "var(--chart-1)",
|
||||
},
|
||||
} satisfies ChartConfig
|
||||
|
||||
export function StockPerformance() {
|
||||
const [ticker, setTicker] = React.useState("VOO")
|
||||
|
||||
const data = CHART_DATA[ticker] ?? DEFAULT_DATA
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Stock Performance</CardTitle>
|
||||
<CardDescription>6-month price history.</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="flex flex-col gap-4">
|
||||
<FieldGroup>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="ticker-select">Ticker</FieldLabel>
|
||||
<Combobox
|
||||
items={TICKERS}
|
||||
value={ticker}
|
||||
onValueChange={(value) => {
|
||||
if (value !== null) setTicker(value)
|
||||
}}
|
||||
>
|
||||
<ComboboxInput
|
||||
id="ticker-select"
|
||||
placeholder="Search ticker..."
|
||||
/>
|
||||
<ComboboxContent>
|
||||
<ComboboxEmpty>No tickers found.</ComboboxEmpty>
|
||||
<ComboboxList>
|
||||
{(item) => (
|
||||
<ComboboxItem key={item} value={item}>
|
||||
{item}
|
||||
</ComboboxItem>
|
||||
)}
|
||||
</ComboboxList>
|
||||
</ComboboxContent>
|
||||
</Combobox>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
<Separator className="style-sera:hidden" />
|
||||
<ChartContainer config={chartConfig} className="h-[200px] w-full">
|
||||
<AreaChart
|
||||
accessibilityLayer
|
||||
data={data}
|
||||
margin={{ left: 0, right: 0, top: 8, bottom: 0 }}
|
||||
>
|
||||
<defs>
|
||||
<linearGradient id="fillPrice" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop
|
||||
offset="0%"
|
||||
stopColor="var(--color-price)"
|
||||
stopOpacity={0.3}
|
||||
/>
|
||||
<stop
|
||||
offset="100%"
|
||||
stopColor="var(--color-price)"
|
||||
stopOpacity={0.05}
|
||||
/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<CartesianGrid vertical={false} strokeDasharray="3 3" />
|
||||
<ChartTooltip
|
||||
cursor={false}
|
||||
content={<ChartTooltipContent hideLabel />}
|
||||
/>
|
||||
<Area
|
||||
type="monotone"
|
||||
dataKey="price"
|
||||
stroke="var(--color-price)"
|
||||
strokeWidth={2}
|
||||
fill="url(#fillPrice)"
|
||||
/>
|
||||
</AreaChart>
|
||||
</ChartContainer>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
import { Button } from "@/registry/bases/radix/ui/button"
|
||||
import { Card, CardContent } from "@/registry/bases/radix/ui/card"
|
||||
import {
|
||||
Empty,
|
||||
EmptyContent,
|
||||
EmptyDescription,
|
||||
EmptyHeader,
|
||||
EmptyMedia,
|
||||
EmptyTitle,
|
||||
} from "@/registry/bases/radix/ui/empty"
|
||||
import { Spinner } from "@/registry/bases/radix/ui/spinner"
|
||||
|
||||
export function SyncingState() {
|
||||
return (
|
||||
<Card>
|
||||
<CardContent className="p-0">
|
||||
<Empty className="p-4">
|
||||
<EmptyHeader>
|
||||
<EmptyMedia variant="icon">
|
||||
<Spinner />
|
||||
</EmptyMedia>
|
||||
<EmptyTitle>Syncing your accounts</EmptyTitle>
|
||||
<EmptyDescription>
|
||||
We're pulling in your latest transactions. This usually takes
|
||||
a few seconds.
|
||||
</EmptyDescription>
|
||||
</EmptyHeader>
|
||||
<EmptyContent>
|
||||
<Button variant="outline">Cancel</Button>
|
||||
</EmptyContent>
|
||||
</Empty>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
import { Button } from "@/registry/bases/radix/ui/button"
|
||||
import {
|
||||
Card,
|
||||
CardAction,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardFooter,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/registry/bases/radix/ui/card"
|
||||
import { Field, FieldGroup, FieldLabel } from "@/registry/bases/radix/ui/field"
|
||||
import {
|
||||
InputGroup,
|
||||
InputGroupAddon,
|
||||
InputGroupInput,
|
||||
InputGroupText,
|
||||
} from "@/registry/bases/radix/ui/input-group"
|
||||
import { Item, ItemContent } from "@/registry/bases/radix/ui/item"
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectGroup,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/registry/bases/radix/ui/select"
|
||||
import { Separator } from "@/registry/bases/radix/ui/separator"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
export function TransferFunds() {
|
||||
return (
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Transfer Funds</CardTitle>
|
||||
<CardDescription>
|
||||
Move money between your connected accounts.
|
||||
</CardDescription>
|
||||
<CardAction>
|
||||
<Button variant="ghost" size="icon-sm" className="bg-muted">
|
||||
<IconPlaceholder
|
||||
lucide="XIcon"
|
||||
tabler="IconX"
|
||||
hugeicons="Cancel01Icon"
|
||||
phosphor="XIcon"
|
||||
remixicon="RiCloseLine"
|
||||
/>
|
||||
</Button>
|
||||
</CardAction>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<FieldGroup>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="transfer-amount">
|
||||
Amount to Transfer
|
||||
</FieldLabel>
|
||||
<InputGroup>
|
||||
<InputGroupAddon>
|
||||
<InputGroupText>$</InputGroupText>
|
||||
</InputGroupAddon>
|
||||
<InputGroupInput id="transfer-amount" defaultValue="1,200.00" />
|
||||
</InputGroup>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="from-account">From Account</FieldLabel>
|
||||
<Select defaultValue="checking">
|
||||
<SelectTrigger id="from-account" className="w-full">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectItem value="checking">
|
||||
Main Checking (··8402) — $12,450.00
|
||||
</SelectItem>
|
||||
<SelectItem value="business">
|
||||
Business (··7731) — $8,920.00
|
||||
</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="to-account">To Account</FieldLabel>
|
||||
<Select defaultValue="savings">
|
||||
<SelectTrigger id="to-account" className="w-full">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectItem value="savings">
|
||||
High Yield Savings (··1192) — $42,100.00
|
||||
</SelectItem>
|
||||
<SelectItem value="investment">
|
||||
Investment (··3349) — $18,200.00
|
||||
</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</Field>
|
||||
<Item variant="muted" className="flex-col items-stretch">
|
||||
<ItemContent className="gap-3">
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-sm text-muted-foreground">
|
||||
Estimated arrival
|
||||
</span>
|
||||
<span className="text-sm font-medium">Today, Apr 14</span>
|
||||
</div>
|
||||
<Separator />
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-sm text-muted-foreground">
|
||||
Transaction fee
|
||||
</span>
|
||||
<span className="text-sm font-medium tabular-nums">$0.00</span>
|
||||
</div>
|
||||
<Separator />
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-sm font-medium">Total amount</span>
|
||||
<span className="text-sm font-semibold tabular-nums">
|
||||
$1,200.00
|
||||
</span>
|
||||
</div>
|
||||
</ItemContent>
|
||||
</Item>
|
||||
</FieldGroup>
|
||||
</CardContent>
|
||||
<CardFooter>
|
||||
<Button className="w-full">Confirm Transfer</Button>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
|
||||
import { Badge } from "@/registry/bases/radix/ui/badge"
|
||||
import { Calendar } from "@/registry/bases/radix/ui/calendar"
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/registry/bases/radix/ui/card"
|
||||
import {
|
||||
Item,
|
||||
ItemContent,
|
||||
ItemDescription,
|
||||
ItemGroup,
|
||||
ItemMedia,
|
||||
ItemTitle,
|
||||
} from "@/registry/bases/radix/ui/item"
|
||||
|
||||
export function UpcomingPayments() {
|
||||
const [date, setDate] = React.useState<Date | undefined>(new Date())
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Upcoming Payments</CardTitle>
|
||||
<CardDescription>
|
||||
Select a date to view scheduled payments.
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="flex flex-col gap-4">
|
||||
<Item variant="outline" className="justify-center">
|
||||
<Calendar
|
||||
mode="single"
|
||||
selected={date}
|
||||
onSelect={setDate}
|
||||
className="w-full [--cell-size:--spacing(8)] md:[--cell-size:--spacing(10)] style-sera:md:[--cell-size:--spacing(9)]"
|
||||
/>
|
||||
</Item>
|
||||
<ItemGroup className="w-full">
|
||||
<Item variant="muted">
|
||||
<ItemContent>
|
||||
<ItemTitle>Netflix Subscription</ItemTitle>
|
||||
<ItemDescription>Apr 15, 2024</ItemDescription>
|
||||
</ItemContent>
|
||||
<Badge variant="secondary">$19.99</Badge>
|
||||
</Item>
|
||||
<Item variant="muted">
|
||||
<ItemContent>
|
||||
<ItemTitle>Rent Payment</ItemTitle>
|
||||
<ItemDescription>Apr 1, 2024</ItemDescription>
|
||||
</ItemContent>
|
||||
<Badge variant="secondary">$2,400.00</Badge>
|
||||
</Item>
|
||||
<Item variant="muted">
|
||||
<ItemContent>
|
||||
<ItemTitle>Auto Insurance</ItemTitle>
|
||||
<ItemDescription>Apr 22, 2024</ItemDescription>
|
||||
</ItemContent>
|
||||
<Badge variant="secondary">$186.00</Badge>
|
||||
</Item>
|
||||
</ItemGroup>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user