feat: add themes (#32)

This commit is contained in:
Ahmed Mayara 2023-09-08 05:11:59 +01:00 committed by GitHub
parent 7453797d5b
commit 0a05459492
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 2829 additions and 792 deletions

View File

@ -0,0 +1,688 @@
<script setup lang="ts">
import { ref } from 'vue'
import { ChevronDown, Minus, Plus, Send } from 'lucide-vue-next'
import { addDays, startOfToday } from 'date-fns'
import ThemingLayout from './../../layout/ThemingLayout.vue'
import {
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from './../../../../src/lib/registry/new-york/ui/card'
import {
Avatar,
AvatarFallback,
AvatarImage,
} from './../../../../src/lib/registry/new-york/ui/avatar'
import { Button } from './../../../../src/lib/registry/new-york/ui/button'
import { Textarea } from './../../../../src/lib/registry/new-york/ui/textarea'
import { Calendar } from './../../../../src/lib/registry/new-york/ui/calendar'
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuGroup,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from './../../../../src/lib/registry/new-york/ui/dropdown-menu'
import { Label } from './../../../../src/lib/registry/new-york/ui/label'
import { Switch } from './../../../../src/lib/registry/new-york/ui/switch'
import {
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectTrigger,
SelectValue,
} from './../../../../src/lib/registry/new-york/ui/select'
import { Input } from './../../../../src/lib/registry/new-york/ui/input'
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from './../../../../src/lib/registry/new-york/ui/tooltip'
import {
months,
payments,
roles,
teamMembers,
years,
} from './utils/data'
import RadixIconsGithubLogo from '~icons/radix-icons/github-logo'
import RiGoogleLine from '~icons/ri/google-line'
const strictlyNecessarySwitch = ref<boolean>(true)
const functionalCookiesSwitch = ref<boolean>(false)
const performanceCookiesSwitch = ref<boolean>(false)
const selectedArea = ref('Billing')
const selectedSecurity = ref('Medium')
const selectedMonth = ref<string>(months[0])
const selectedYear = ref<string>(years[0])
const selectedPayment = ref(payments[0])
const goal = ref(350)
function switchPayment(payment: any) {
selectedPayment.value = payment
}
const range = ref({
start: startOfToday(),
end: addDays(startOfToday(), 8),
})
</script>
<template>
<ThemingLayout>
<div
class="items-start justify-center gap-6 rounded-lg md:grids-col-2 grid md:gap-4 lg:grid-cols-10 xl:grid-cols-11 xl:gap-4"
>
<div class="space-y-4 lg:col-span-4 xl:col-span-6 xl:space-y-4">
<div class="grid gap-4 sm:grid-cols-2 xl:grid-cols-2">
<Card>
<CardHeader class="pb-2">
<CardTitle class="text-lg">
Total Revenue
</CardTitle>
</CardHeader>
<CardContent>
<div class="text-2xl font-bold">
$15,231.89
</div>
<p class="text-xs text-muted-foreground">
+20.1% from last month
</p>
<div class="h-24" />
</CardContent>
</Card>
<Card>
<CardHeader class="pb-2">
<CardTitle class="text-lg">
Subscriptions
</CardTitle>
</CardHeader>
<CardContent>
<div class="text-2xl font-bold">
+2,350
</div>
<p class="text-xs text-muted-foreground">
+54.8% from last month
</p>
<div class="h-24" />
</CardContent>
</Card>
</div>
<div class="grid gap-4 md:grid-cols-2 lg:grid-cols-1 xl:grid-cols-2">
<div class="space-y-4">
<Card>
<CardHeader>
<CardTitle> Team Members </CardTitle>
<CardDescription>
Invite your team members to collaborate.
</CardDescription>
</CardHeader>
<CardContent>
<div
v-for="teamMember in teamMembers"
:key="teamMember.name"
class="flex justify-between items-center"
>
<div class="flex items-center space-x-3 my-4">
<Avatar size="sm">
<AvatarImage :src="teamMember.avatar" />
<AvatarFallback>
{{ teamMember.name.slice(0, 2) }}
</AvatarFallback>
</Avatar>
<div class="flex flex-col">
<p class="text-foreground text-sm font-semibold">
{{ teamMember.name }}
</p>
<p class="text-muted-foreground text-sm">
{{ teamMember.username }}
</p>
</div>
</div>
<DropdownMenu>
<DropdownMenuTrigger>
<Button variant="outline" class="h-9">
{{ teamMember.role }}
<ChevronDown class="w-3 h-3 ml-2" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent class="w-[280px]" align="end">
<DropdownMenuGroup>
<DropdownMenuLabel>
Actions
</DropdownMenuLabel>
<DropdownMenuSeparator />
<DropdownMenuItem v-for="role in roles" :key="role.name">
<div class="grid space-y-0.5">
<span class="text-foreground font-semibold">
{{ role.name }}
</span>
<span class="text-muted-foreground text-sm">
{{ role.description }}
</span>
</div>
</DropdownMenuItem>
</DropdownMenuGroup>
</DropdownMenuContent>
</DropdownMenu>
</div>
</CardContent>
</Card>
<Card>
<CardHeader>
<CardTitle> Cookies Settings </CardTitle>
<CardDescription>
Manage your cookies preferences.
</CardDescription>
</CardHeader>
<CardContent>
<div class="grid grid-rows-3 gap-y-5">
<div class="flex justify-between items-center space-x-2">
<Label for="strictly_necessary" class="flex flex-col">
Strictly Necessary
<span
class="text-muted-foreground mt-1 text-xs max-w-[18rem]"
>
These cookies are essential in order to use the website
and use its features.
</span>
</Label>
<Switch
id="strictly_necessary"
v-model:checked="strictlyNecessarySwitch"
/>
</div>
<div class="flex justify-between items-center space-x-2">
<Label for="functional_cookies" class="flex flex-col">
Functional Cookies
<span
class="text-muted-foreground text-xs mt-1 max-w-[18rem]"
>
These cookies enable the website to provide enhanced
functionality and personalization.
</span>
</Label>
<Switch
id="functional_cookies"
v-model:checked="functionalCookiesSwitch"
/>
</div>
<div class="flex justify-between items-center space-x-2">
<Label for="performance_cookies" class="flex flex-col">
Performance Cookies
<span
class="text-muted-foreground text-xs mt-1 max-w-[18rem]"
>
These cookies are used to collect information about how
you use our website.
</span>
</Label>
<Switch
id="performance_cookies"
v-model:checked="performanceCookiesSwitch"
/>
</div>
</div>
</CardContent>
<CardFooter>
<Button variant="outline" class="w-full">
Save Preferences
</Button>
</CardFooter>
</Card>
<Card>
<CardHeader>
<CardTitle class="text-lg">
Payment Method
</CardTitle>
<CardDescription>
Add a new payment method or update your existing payment
method.
</CardDescription>
</CardHeader>
<CardContent>
<div class="grid grid-cols-3 gap-x-4">
<div
v-for="payment in payments"
:key="payment.name"
class="flex flex-col justify-center items-center p-4 rounded-lg cursor-pointer transition-colors ease-in-out duration-200"
:class="[
selectedPayment.name === payment.name
? 'border-2 border-primary'
: 'border border-border hover:bg-accent',
]"
@click="switchPayment(payment)"
>
<component :is="payment.icon" class="w-6 h-6" />
<span class="text-foreground text-sm font-medium mt-1.5">
{{ payment.name }}
</span>
</div>
</div>
<div class="grid gap-2 pt-4">
<Label for="name" class="text-sm"> Name </Label>
<Input id="name" placeholder="Name" />
</div>
<div class="grid gap-2 pt-4">
<Label for="card_number" class="text-sm"> Card number </Label>
<Input id="card_number" placeholder="4242 4242 4242 4242" />
</div>
<div class="grid grid-cols-3 gap-4 pt-4">
<div class="flex flex-col space-y-1.5">
<Label for="expires_month">Month</Label>
<Select v-model="selectedMonth">
<SelectTrigger>
<SelectValue placeholder="Month" />
</SelectTrigger>
<SelectContent side="top">
<SelectGroup>
<SelectItem
v-for="month in months"
:key="month"
:value="month"
>
{{ month }}
</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
</div>
<div class="flex flex-col space-y-1.5">
<Label for="expires_year"> Year </Label>
<Select v-model="selectedYear">
<SelectTrigger>
<SelectValue placeholder="Year" />
</SelectTrigger>
<SelectContent side="top">
<SelectGroup>
<SelectItem
v-for="year in years"
:key="year"
:value="year"
>
{{ year }}
</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
</div>
<div class="flex flex-col space-y-1.5">
<Label for="cvc">CVC</Label>
<Input id="cvc" placeholder="123" />
</div>
</div>
</CardContent>
<CardFooter>
<Button class="w-full">
Continue
</Button>
</CardFooter>
</Card>
</div>
<div class="space-y-4">
<Card>
<CardHeader class="flex flex-row items-center justify-between">
<div class="flex items-center space-x-3 my-2">
<Avatar size="sm">
<AvatarImage
src="https://api.dicebear.com/6.x/lorelei/svg?seed=Bear"
/>
<AvatarFallback>B</AvatarFallback>
</Avatar>
<div class="flex flex-col">
<p class="text-foreground text-sm font-semibold">
Bear Brown
</p>
<p class="text-muted-foreground text-sm">
bear@example.com
</p>
</div>
</div>
<TooltipProvider>
<Tooltip :delay-duration="200">
<TooltipTrigger as-child>
<Button
variant="outline"
class="rounded-full p-2.5 flex items-center justify-center"
>
<Plus class="w-4 h-4" />
</Button>
</TooltipTrigger>
<TooltipContent :side-offset="10">
New message
</TooltipContent>
</Tooltip>
</TooltipProvider>
</CardHeader>
<CardContent>
<div class="space-y-4">
<div
class="flex w-max max-w-[75%] flex-col gap-2 rounded-lg px-3 py-2 text-sm bg-secondary"
>
<p class="text-foreground">
Hi There!, I'm Bear, the founder of Bear Studios. I'm here
to help you with anything you need.
</p>
</div>
<div
class="flex w-max max-w-[75%] flex-col gap-2 rounded-lg px-3 py-2 text-sm ml-auto bg-primary text-primary-foreground"
>
<p>Hey, I'm having trouble with my account.</p>
</div>
<div
class="flex w-max max-w-[75%] flex-col gap-2 rounded-lg px-3 py-2 text-sm bg-secondary"
>
<p class="text-foreground">
Sure, I can help you with that. What seems to be the
problem?
</p>
</div>
<div
class="flex w-max max-w-[75%] flex-col gap-2 rounded-lg px-3 py-2 text-sm ml-auto bg-primary text-primary-foreground"
>
<p>I can't log in.</p>
</div>
</div>
</CardContent>
<CardFooter>
<div class="flex w-full space-x-2 items-center">
<Input placeholder="Type a message..." class="flex-1" />
<Button class="p-2.5 flex items-center justify-center">
<Send class="w-4 h-4" />
</Button>
</div>
</CardFooter>
</Card>
<Card>
<CardHeader>
<CardTitle>Create an account</CardTitle>
<CardDescription>
Enter your details below to create your account.
</CardDescription>
</CardHeader>
<CardContent>
<div class="grid grid-cols-2 gap-6">
<Button variant="outline">
<RiGoogleLine class="w-4 h-4 mr-2" />
Google
</Button>
<Button variant="outline">
<RadixIconsGithubLogo class="w-4 h-4 mr-2" />
Github
</Button>
</div>
<div class="relative mt-4">
<div class="absolute inset-0 flex items-center">
<span class="w-full border-t border-border" />
</div>
<div class="relative flex justify-center text-xs uppercase">
<span class="bg-card text-muted-foreground px-2"> Or </span>
</div>
</div>
<div class="grid gap-2 pt-4">
<Label for="email">Email</Label>
<Input id="email" placeholder="name@example.com" />
</div>
<div class="grid gap-2 pt-4">
<Label for="password">Password</Label>
<Input id="password" type="password" placeholder="••••••••" />
</div>
</CardContent>
<CardFooter>
<Button class="w-full">
Create account
</Button>
</CardFooter>
</Card>
<Card>
<CardHeader>
<CardTitle> Report an issue </CardTitle>
<CardDescription>
What area are you having problems with?
</CardDescription>
</CardHeader>
<CardContent>
<div class="grid gap-4 sm:grid-cols-2">
<div class="grid gap-2">
<Label for="area">Area</Label>
<Select v-model="selectedArea">
<SelectTrigger>
{{ selectedArea || "Area" }}
</SelectTrigger>
<SelectContent class="w-[139px]">
<SelectGroup>
<SelectItem value="Team">
Team
</SelectItem>
<SelectItem value="Billing">
Billing
</SelectItem>
<SelectItem value="Account">
Account
</SelectItem>
<SelectItem value="Deployment">
Deployment
</SelectItem>
<SelectItem value="Support">
Support
</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
</div>
<div class="grid gap-2">
<Label for="security">Security Level</Label>
<Select v-model="selectedSecurity">
<SelectTrigger>
<SelectValue placeholder="Medium" />
</SelectTrigger>
<SelectContent class="w-[139px]">
<SelectGroup>
<SelectItem value="Low">
Low
</SelectItem>
<SelectItem value="Medium">
Medium
</SelectItem>
<SelectItem value="High">
High
</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
</div>
</div>
<div class="grid gap-2 py-4">
<Label for="subject">Subject</Label>
<Input id="subject" placeholder="I need help with..." />
</div>
<div class="grid gap-2">
<Label for="description">Description</Label>
<Textarea
id="description"
placeholder="Describe your issue..."
/>
</div>
</CardContent>
<CardFooter class="flex justify-between items-center">
<Button variant="outline">
Cancel
</Button>
<Button> Submit </Button>
</CardFooter>
</Card>
</div>
</div>
</div>
<div class="space-y-4 lg:col-span-6 xl:col-span-5 xl:space-y-4">
<div class="hidden gap-1 sm:grid-cols-[280px_1fr] md:grid">
<Card class="max-w-[280px]">
<Calendar v-model.range="range" />
</Card>
<div class="pt-3 sm:pl-2 sm:pt-0 xl:pl-3">
<Card>
<CardHeader>
<CardTitle class="text-md">
Move Goal
</CardTitle>
<CardDescription>
Set your daily activity goal.
</CardDescription>
</CardHeader>
<CardContent class="pb-2">
<div class="flex items-center justify-center space-x-2">
<Button
variant="outline"
class="w-8 h-8 rounded-full p-0"
:disabled="goal <= 200"
@click="goal -= 10"
>
<Minus class="w-4 h-4" />
</Button>
<div class="flex-1 text-center">
<p
class="text-foreground text-5xl font-bold tracking-tight"
>
{{ goal }}
</p>
<span class="text-muted-foreground text-[11px] uppercase">
Calories/day
</span>
</div>
<Button
variant="outline"
class="w-8 h-8 rounded-full p-0"
:disabled="goal >= 500"
@click="goal += 10"
>
<Plus class="w-4 h-4" />
</Button>
</div>
<div class="my-2" />
</CardContent>
<CardFooter>
<Button class="w-full">
Set Goal
</Button>
</CardFooter>
</Card>
</div>
<div class="pt-3 sm:col-span-2 xl:pt-3">
<Card>
<CardHeader>
<CardTitle> Exercise Minutes </CardTitle>
<CardDescription>
Your exercise minutes are ahead of where you normally are.
</CardDescription>
</CardHeader>
<CardContent />
</Card>
</div>
<div class="pt-3 sm:col-span-2 xl:pt-3">
<Card>
<CardHeader>
<CardTitle> Payments </CardTitle>
<CardDescription>
Manage your payment methods and view your billing history.
</CardDescription>
</CardHeader>
<CardContent />
</Card>
</div>
<div class="pt-3 sm:col-span-2 xl:pt-3">
<Card>
<CardHeader>
<CardTitle> Share this document </CardTitle>
<CardDescription>
Anyone with this link will be able to view this document.
</CardDescription>
<div class="flex space-x-2 items-center pt-2.5">
<Input
class="flex-1"
placeholder="http://..."
value="http://example.com/link/to/document"
/>
<Button variant="secondary">
Copy Link
</Button>
</div>
</CardHeader>
<CardContent>
<Separator />
<Label class="mt-4"> People with access </Label>
<div
v-for="teamMember in teamMembers"
:key="teamMember.name"
class="flex justify-between items-center"
>
<div class="flex items-center space-x-3 my-4">
<Avatar size="sm">
<AvatarImage :src="teamMember.avatar" />
<AvatarFallback>
{{ teamMember.name.slice(0, 2) }}
</AvatarFallback>
</Avatar>
<div class="flex flex-col">
<p class="text-foreground text-sm font-medium">
{{ teamMember.name }}
</p>
<p class="text-muted-foreground text-sm">
{{ teamMember.username }}
</p>
</div>
</div>
<Select v-model="teamMember.access">
<SelectTrigger class="w-28">
<SelectValue :placeholder="teamMember.access" />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectItem value="Can edit">
Can edit
</SelectItem>
<SelectItem value="Can view">
Can view
</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
</div>
</CardContent>
</Card>
</div>
</div>
</div>
</div>
</ThemingLayout>
</template>

View File

@ -0,0 +1,174 @@
export const totalRevenueChartSeries = [
{
name: 'Revenue',
data: [40, 45, 58, 54, 62, 58, 63, 60, 66],
},
]
export const totalRevenueChartOptions = {
chart: {
type: 'line',
sparkline: {
enabled: true,
},
animations: {
enabled: true,
},
},
markers: {
size: 3,
colors: ['hsl(var(--background))'],
strokeColors: 'hsl(var(--primary))',
},
colors: ['hsl(var(--primary))'],
dataLabels: {
enabled: false,
},
stroke: {
curve: 'smooth',
width: 2,
},
yaxis: {
min: 0,
},
tooltip: {
enabled: false,
},
states: {
normal: {
filter: {
type: 'none',
value: 0,
},
},
hover: {
filter: {
type: 'none',
},
},
active: {
allowMultipleDataPointsSelection: false,
filter: {
type: 'none',
},
},
},
}
export const subscriptionsChartSeries = [
{
name: 'Subscriptions',
data: [40, 45, 32, 54, 65, 53, 63, 35],
},
]
export const subscriptionsChartOptions = {
chart: {
type: 'bar',
sparkline: {
enabled: true,
},
},
plotOptions: {
bar: {
distributed: true,
columnWidth: '80%',
},
},
markers: {
size: 4,
colors: ['hsl(var(--background))'],
strokeColors: 'hsl(var(--primary)',
},
colors: ['hsl(var(--primary)'],
dataLabels: {
enabled: false,
},
stroke: {
curve: 'smooth',
width: 2,
},
yaxis: {
min: 0,
},
tooltip: {
enabled: false,
},
states: {
normal: {
filter: {
type: 'none',
value: 0,
},
},
hover: {
filter: {
type: 'none',
},
},
active: {
allowMultipleDataPointsSelection: false,
filter: {
type: 'none',
},
},
},
}
export const goalsMinutesChartSeries = [
{ name: 'Minutes', data: [15, 5, 60, 30, 45, 38, 42] },
{
name: 'Goal',
data: [25, 18, 13, 21, 11, 17, 22],
},
]
export const goalsMinutesChartOptions = {
chart: {
type: 'line',
sparkline: {
enabled: true,
},
animations: {
enabled: true,
},
},
markers: {
size: 3,
colors: 'hsl(var(--background))',
strokeColors: 'hsl(var(--primary))',
},
colors: ['hsl(var(--primary))', 'hsl(var(--muted-foreground))'],
dataLabels: {
enabled: false,
},
stroke: {
curve: 'smooth',
width: 2,
},
yaxis: {
min: 0,
},
tooltip: {
enabled: false,
},
states: {
normal: {
filter: {
type: 'none',
value: 0,
},
},
hover: {
filter: {
type: 'none',
},
},
active: {
allowMultipleDataPointsSelection: false,
filter: {
type: 'none',
},
},
},
}

View File

@ -0,0 +1,107 @@
import { CreditCard } from 'lucide-vue-next'
import RiAppleFill from '~icons/ri/apple-fill'
import RiPaypalFill from '~icons/ri/paypal-fill'
interface Payment {
status: string
email: string
amount: number
}
interface TeamMember {
name: string
username: string
role: Role['name']
avatar: string
access: string
}
interface Role {
name: string
description: string
}
export const teamMembers: TeamMember[] = [
{
name: 'Bob Smith',
username: '@bobbysmith',
role: 'Owner',
avatar: 'https://api.dicebear.com/6.x/lorelei/svg?seed=Bob',
access: 'Can edit',
},
{
name: 'Nala Sutanovac',
username: '@nalasutanovac',
role: 'Developer',
avatar: 'https://api.dicebear.com/6.x/lorelei/svg?seed=Nala',
access: 'Can view',
},
{
name: 'Jack Lynch',
username: '@jacklynch',
role: 'Designer',
avatar: 'https://api.dicebear.com/6.x/lorelei/svg?seed=Jack',
access: 'Can view',
},
]
export const roles: Role[] = [
{
name: 'Owner',
description: 'Can manage all aspects of the account',
},
{
name: 'Developer',
description: 'Can deploy apps, manage databases, and manage users',
},
{
name: 'Designer',
description: 'Can deploy apps and manage databases',
},
]
export const months = [
'January',
'February',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December',
]
export const years = [
'2023',
'2024',
'2025',
'2026',
'2027',
'2028',
'2029',
'2030',
]
interface Payments {
name: string
icon: any
}
export const payments: Payments[] = [
{
name: 'Card',
icon: CreditCard,
},
{
name: 'Paypal',
icon: RiPaypalFill,
},
{
name: 'Apple',
icon: RiAppleFill,
},
]

View File

@ -7,6 +7,7 @@ import * as components from './components'
import './style.css'
import './styles/vp-doc.css'
import './styles/shiki.css'
import './styles/themes.css'
export default {
Layout,

View File

@ -0,0 +1,262 @@
<script setup lang="ts">
import { onMounted, watch } from 'vue'
import { useDark } from '@vueuse/core'
import { Paintbrush } from 'lucide-vue-next'
import PageHeader from '../components/PageHeader.vue'
import PageHeaderHeading from '../components/PageHeaderHeading.vue'
import PageHeaderDescription from '../components/PageHeaderDescription.vue'
import { RADII, useConfigStore } from '@/stores/config'
import { colors } from '@/lib/registry'
import { Button } from '@/lib/registry/new-york/ui/button'
import { Popover, PopoverContent, PopoverTrigger } from '@/lib/registry/new-york/ui/popover'
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/lib/registry/new-york/ui/tooltip'
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger } from '@/lib/registry/new-york/ui/dialog'
import RadixIconsCheck from '~icons/radix-icons/check'
import RadixIconsSun from '~icons/radix-icons/sun'
import RadixIconsMoon from '~icons/radix-icons/moon'
type Color =
| 'zinc'
| 'slate'
| 'stone'
| 'gray'
| 'neutral'
| 'red'
| 'rose'
| 'orange'
| 'green'
| 'blue'
| 'yellow'
| 'violet'
// Create an array of color values
const allColors: Color[] = [
'zinc',
'rose',
'blue',
'green',
'orange',
'red',
'slate',
'stone',
'gray',
'neutral',
'yellow',
'violet',
]
const { theme, radius, setRadius, setTheme } = useConfigStore()
const isDark = useDark()
// Store an object called config in local storage with the theme and radius values
watch([theme, radius], ([theme, radius]) => {
localStorage.setItem(
'config',
JSON.stringify({
theme,
radius,
}),
)
})
// If there is a config object in local storage, set the theme and radius values to the values in local storage
if (localStorage.getItem('config')) {
const config = JSON.parse(localStorage.getItem('config')!)
setTheme(config.theme)
setRadius(config.radius)
}
// Whenever the component is mounted, update the document class list
onMounted(() => {
document.documentElement.style.setProperty('--radius', `${radius.value}rem`)
document.documentElement.classList.add(`theme-${theme.value}`)
})
// Whenever the theme value changes, update the document class list
watch(theme, (theme) => {
document.documentElement.classList.remove(
...allColors.map(color => `theme-${color}`),
)
document.documentElement.classList.add(`theme-${theme}`)
})
// Whenever the radius value changes, update the document style
watch(radius, (radius) => {
document.documentElement.style.setProperty('--radius', `${radius}rem`)
})
</script>
<template>
<div class="container relative">
<div class="flex justify-between items-center">
<div>
<PageHeader class="page-header pb-8">
<PageHeaderHeading class="hidden md:block">
Make it yours.
</PageHeaderHeading>
<PageHeaderDescription>
Hand-picked themes that you can copy and paste into your apps.
</PageHeaderDescription>
</PageHeader>
</div>
<div class="px-4 pb-8 md:ml-auto md:pb-0">
<div class="flex items-center space-x-2">
<div class="hidden md:flex">
<div class="mr-4 hidden items-center space-x-1 lg:flex">
<TooltipProvider
v-for="(color, index) in allColors.slice(0, 5)"
:key="index"
>
<Tooltip>
<TooltipTrigger as-child>
<button
:key="index"
class="flex h-9 w-9 items-center justify-center rounded-full border-2 border-border text-xs"
:class="
color === theme
? 'border-foreground'
: 'border-transparent'
"
@click="setTheme(color)"
>
<span
class="flex h-6 w-6 items-center justify-center rounded-full"
:style="{ backgroundColor: colors[color][7].rgb }"
>
<RadixIconsCheck
v-if="color === theme"
class="h-4 w-4 text-white"
/>
</span>
</button>
</TooltipTrigger>
<TooltipContent
align="center"
:side-offset="1"
class="capitalize"
>
{{ allColors[index] }}
</TooltipContent>
</Tooltip>
</TooltipProvider>
</div>
<Popover>
<PopoverTrigger as-child>
<Button variant="outline" class="h-9 rounded-[0.5rem]">
<Paintbrush class="w-4 h-4 mr-2" />
Customize
</Button>
</PopoverTrigger>
<PopoverContent :side-offset="8" align="end" class="w-96">
<div class="p-4">
<div class="grid space-y-1">
<h1 class="text-md text-foreground font-semibold">
Customize
</h1>
<p class="text-xs text-muted-foreground">
Pick a style and color for your components.
</p>
</div>
<div class="space-y-1.5 pt-6">
<Label for="color" class="text-xs"> Color </Label>
<div class="grid grid-cols-3 gap-2 py-1.5">
<Button
v-for="(color, index) in allColors"
:key="index"
variant="outline"
class="h-8 justify-start px-3"
:class="
color === theme
? 'border-foreground border-2'
: ''
"
@click="setTheme(color)"
>
<span
class="h-5 w-5 rounded-full flex items-center justify-center"
:style="{ backgroundColor: colors[color][7].rgb }"
>
<RadixIconsCheck
v-if="color === theme"
class="h-3 w-3 text-white"
/>
</span>
<span class="ml-2 text-xs capitalize">
{{ color }}
</span>
</Button>
</div>
</div>
<div class="space-y-1.5 pt-6">
<Label for="radius" class="text-xs"> Radius </Label>
<div class="grid grid-cols-5 gap-2 py-1.5">
<Button
v-for="(r, index) in RADII"
:key="index"
variant="outline"
class="h-8 justify-center px-3"
:class="
r === radius
? 'border-foreground border-2'
: ''
"
@click="setRadius(r)"
>
<span class="text-xs">
{{ r }}
</span>
</Button>
</div>
</div>
<div class="space-y-1.5 pt-6">
<Label for="theme" class="text-xs"> Theme </Label>
<div class="flex space-x-2 py-1.5">
<Button
class="h-8"
variant="outline"
:class="{ 'border-2 border-foreground': !isDark }"
@click="isDark = false"
>
<RadixIconsSun class="w-4 h-4 mr-2" />
<span class="text-xs">Light</span>
</Button>
<Button
class="h-8"
variant="outline"
:class="{ 'border-2 border-foreground': isDark }"
@click="isDark = true"
>
<RadixIconsMoon class="w-4 h-4 mr-2" />
<span class="text-xs">Dark</span>
</Button>
</div>
</div>
</div>
</PopoverContent>
</Popover>
<Dialog>
<DialogTrigger as-child>
<Button class="h-9 ml-2 rounded-[0.5rem]">
Copy code
</Button>
</DialogTrigger>
<DialogContent class="sm:max-w-[625px]">
<DialogHeader>
<DialogTitle>Theme</DialogTitle>
<DialogDescription>
Copy and paste the following code into your CSS file.
</DialogDescription>
</DialogHeader>
</DialogContent>
</Dialog>
</div>
</div>
</div>
</div>
<section>
<slot />
</section>
</div>
</template>

View File

@ -0,0 +1,767 @@
.theme-zinc {
--background: 0 0% 100%;
--foreground: 240 10% 3.9%;
--muted: 240 4.8% 95.9%;
--muted-foreground: 240 3.8% 46.1%;
--popover: 0 0% 100%;
--popover-foreground: 240 10% 3.9%;
--card: 0 0% 100%;
--card-foreground: 240 10% 3.9%;
--border: 240 5.9% 90%;
--input: 240 5.9% 90%;
--primary: 240 5.9% 10%;
--primary-foreground: 0 0% 98%;
--secondary: 240 4.8% 95.9%;
--secondary-foreground: 240 5.9% 10%;
--accent: 240 4.8% 95.9%;
--accent-foreground: 240 5.9% 10%;
--destructive: 0 84.2% 60.2%;
--destructive-foreground: 0 0% 98%;
--ring: 240 5.9% 10%;
--radius: 0.5rem;
}
.theme-zinc.dark {
--background: 240 10% 3.9%;
--foreground: 0 0% 98%;
--muted: 240 3.7% 15.9%;
--muted-foreground: 240 5% 64.9%;
--popover: 240 10% 3.9%;
--popover-foreground: 0 0% 98%;
--card: 240 10% 3.9%;
--card-foreground: 0 0% 98%;
--border: 240 3.7% 15.9%;
--input: 240 3.7% 15.9%;
--primary: 0 0% 98%;
--primary-foreground: 240 5.9% 10%;
--secondary: 240 3.7% 15.9%;
--secondary-foreground: 0 0% 98%;
--accent: 240 3.7% 15.9%;
--accent-foreground: 0 0% 98%;
--destructive: 0 62.8% 30.6%;
--destructive-foreground: 0 0% 98%;
--ring: 240 4.9% 83.9%;
}
.theme-slate {
--background: 0 0% 100%;
--foreground: 222.2 84% 4.9%;
--muted: 210 40% 96.1%;
--muted-foreground: 215.4 16.3% 46.9%;
--popover: 0 0% 100%;
--popover-foreground: 222.2 84% 4.9%;
--card: 0 0% 100%;
--card-foreground: 222.2 84% 4.9%;
--border: 214.3 31.8% 91.4%;
--input: 214.3 31.8% 91.4%;
--primary: 222.2 47.4% 11.2%;
--primary-foreground: 210 40% 98%;
--secondary: 210 40% 96.1%;
--secondary-foreground: 222.2 47.4% 11.2%;
--accent: 210 40% 96.1%;
--accent-foreground: 222.2 47.4% 11.2%;
--destructive: 0 84.2% 60.2%;
--destructive-foreground: 210 40% 98%;
--ring: 222.2 84% 4.9%;
--radius: 0.5rem;
}
.theme-slate.dark {
--background: 222.2 84% 4.9%;
--foreground: 210 40% 98%;
--muted: 217.2 32.6% 17.5%;
--muted-foreground: 215 20.2% 65.1%;
--popover: 222.2 84% 4.9%;
--popover-foreground: 210 40% 98%;
--card: 222.2 84% 4.9%;
--card-foreground: 210 40% 98%;
--border: 217.2 32.6% 17.5%;
--input: 217.2 32.6% 17.5%;
--primary: 210 40% 98%;
--primary-foreground: 222.2 47.4% 11.2%;
--secondary: 217.2 32.6% 17.5%;
--secondary-foreground: 210 40% 98%;
--accent: 217.2 32.6% 17.5%;
--accent-foreground: 210 40% 98%;
--destructive: 0 62.8% 30.6%;
--destructive-foreground: 210 40% 98%;
--ring: 212.7 26.8% 83.9;
}
.theme-stone {
--background: 0 0% 100%;
--foreground: 20 14.3% 4.1%;
--muted: 60 4.8% 95.9%;
--muted-foreground: 25 5.3% 44.7%;
--popover: 0 0% 100%;
--popover-foreground: 20 14.3% 4.1%;
--card: 0 0% 100%;
--card-foreground: 20 14.3% 4.1%;
--border: 20 5.9% 90%;
--input: 20 5.9% 90%;
--primary: 24 9.8% 10%;
--primary-foreground: 60 9.1% 97.8%;
--secondary: 60 4.8% 95.9%;
--secondary-foreground: 24 9.8% 10%;
--accent: 60 4.8% 95.9%;
--accent-foreground: 24 9.8% 10%;
--destructive: 0 84.2% 60.2%;
--destructive-foreground: 60 9.1% 97.8%;
--ring: 20 14.3% 4.1%;
--radius: 0.95rem;
}
.theme-stone.dark {
--background: 20 14.3% 4.1%;
--foreground: 60 9.1% 97.8%;
--muted: 12 6.5% 15.1%;
--muted-foreground: 24 5.4% 63.9%;
--popover: 20 14.3% 4.1%;
--popover-foreground: 60 9.1% 97.8%;
--card: 20 14.3% 4.1%;
--card-foreground: 60 9.1% 97.8%;
--border: 12 6.5% 15.1%;
--input: 12 6.5% 15.1%;
--primary: 60 9.1% 97.8%;
--primary-foreground: 24 9.8% 10%;
--secondary: 12 6.5% 15.1%;
--secondary-foreground: 60 9.1% 97.8%;
--accent: 12 6.5% 15.1%;
--accent-foreground: 60 9.1% 97.8%;
--destructive: 0 62.8% 30.6%;
--destructive-foreground: 60 9.1% 97.8%;
--ring: 24 5.7% 82.9%;
}
.theme-gray {
--background: 0 0% 100%;
--foreground: 224 71.4% 4.1%;
--muted: 220 14.3% 95.9%;
--muted-foreground: 220 8.9% 46.1%;
--popover: 0 0% 100%;
--popover-foreground: 224 71.4% 4.1%;
--card: 0 0% 100%;
--card-foreground: 224 71.4% 4.1%;
--border: 220 13% 91%;
--input: 220 13% 91%;
--primary: 220.9 39.3% 11%;
--primary-foreground: 210 20% 98%;
--secondary: 220 14.3% 95.9%;
--secondary-foreground: 220.9 39.3% 11%;
--accent: 220 14.3% 95.9%;
--accent-foreground: 220.9 39.3% 11%;
--destructive: 0 84.2% 60.2%;
--destructive-foreground: 210 20% 98%;
--ring: 224 71.4% 4.1%;
--radius: 0.35rem;
}
.theme-gray.dark {
--background: 224 71.4% 4.1%;
--foreground: 210 20% 98%;
--muted: 215 27.9% 16.9%;
--muted-foreground: 217.9 10.6% 64.9%;
--popover: 224 71.4% 4.1%;
--popover-foreground: 210 20% 98%;
--card: 224 71.4% 4.1%;
--card-foreground: 210 20% 98%;
--border: 215 27.9% 16.9%;
--input: 215 27.9% 16.9%;
--primary: 210 20% 98%;
--primary-foreground: 220.9 39.3% 11%;
--secondary: 215 27.9% 16.9%;
--secondary-foreground: 210 20% 98%;
--accent: 215 27.9% 16.9%;
--accent-foreground: 210 20% 98%;
--destructive: 0 62.8% 30.6%;
--destructive-foreground: 210 20% 98%;
--ring: 216 12.2% 83.9%;
}
.theme-neutral {
--background: 0 0% 100%;
--foreground: 0 0% 3.9%;
--muted: 0 0% 96.1%;
--muted-foreground: 0 0% 45.1%;
--popover: 0 0% 100%;
--popover-foreground: 0 0% 3.9%;
--card: 0 0% 100%;
--card-foreground: 0 0% 3.9%;
--border: 0 0% 89.8%;
--input: 0 0% 89.8%;
--primary: 0 0% 9%;
--primary-foreground: 0 0% 98%;
--secondary: 0 0% 96.1%;
--secondary-foreground: 0 0% 9%;
--accent: 0 0% 96.1%;
--accent-foreground: 0 0% 9%;
--destructive: 0 84.2% 60.2%;
--destructive-foreground: 0 0% 98%;
--ring: 0 0% 3.9%;
--radius: ;
}
.theme-neutral.dark {
--background: 0 0% 3.9%;
--foreground: 0 0% 98%;
--muted: 0 0% 14.9%;
--muted-foreground: 0 0% 63.9%;
--popover: 0 0% 3.9%;
--popover-foreground: 0 0% 98%;
--card: 0 0% 3.9%;
--card-foreground: 0 0% 98%;
--border: 0 0% 14.9%;
--input: 0 0% 14.9%;
--primary: 0 0% 98%;
--primary-foreground: 0 0% 9%;
--secondary: 0 0% 14.9%;
--secondary-foreground: 0 0% 98%;
--accent: 0 0% 14.9%;
--accent-foreground: 0 0% 98%;
--destructive: 0 62.8% 30.6%;
--destructive-foreground: 0 0% 98%;
--ring: 0 0% 83.1%;
}
.theme-red {
--background: 0 0% 100%;
--foreground: 0 0% 3.9%;
--muted: 0 0% 96.1%;
--muted-foreground: 0 0% 45.1%;
--popover: 0 0% 100%;
--popover-foreground: 0 0% 3.9%;
--card: 0 0% 100%;
--card-foreground: 0 0% 3.9%;
--border: 0 0% 89.8%;
--input: 0 0% 89.8%;
--primary: 0 72.2% 50.6%;
--primary-foreground: 0 85.7% 97.3%;
--secondary: 0 0% 96.1%;
--secondary-foreground: 0 0% 9%;
--accent: 0 0% 96.1%;
--accent-foreground: 0 0% 9%;
--destructive: 0 84.2% 60.2%;
--destructive-foreground: 0 0% 98%;
--ring: 0 72.2% 50.6%;
--radius: 0.4rem;
}
.theme-red.dark {
--background: 0 0% 3.9%;
--foreground: 0 0% 98%;
--muted: 0 0% 14.9%;
--muted-foreground: 0 0% 63.9%;
--popover: 0 0% 3.9%;
--popover-foreground: 0 0% 98%;
--card: 0 0% 3.9%;
--card-foreground: 0 0% 98%;
--border: 0 0% 14.9%;
--input: 0 0% 14.9%;
--primary: 0 72.2% 50.6%;
--primary-foreground: 0 85.7% 97.3%;
--secondary: 0 0% 14.9%;
--secondary-foreground: 0 0% 98%;
--accent: 0 0% 14.9%;
--accent-foreground: 0 0% 98%;
--destructive: 0 62.8% 30.6%;
--destructive-foreground: 0 0% 98%;
--ring: 0 72.2% 50.6%;
}
.theme-rose {
--background: 0 0% 100%;
--foreground: 240 10% 3.9%;
--muted: 240 4.8% 95.9%;
--muted-foreground: 240 3.8% 46.1%;
--popover: 0 0% 100%;
--popover-foreground: 240 10% 3.9%;
--card: 0 0% 100%;
--card-foreground: 240 10% 3.9%;
--border: 240 5.9% 90%;
--input: 240 5.9% 90%;
--primary: 346.8 77.2% 49.8%;
--primary-foreground: 355.7 100% 97.3%;
--secondary: 240 4.8% 95.9%;
--secondary-foreground: 240 5.9% 10%;
--accent: 240 4.8% 95.9%;
--accent-foreground: 240 5.9% 10%;
--destructive: 0 84.2% 60.2%;
--destructive-foreground: 0 0% 98%;
--ring: 346.8 77.2% 49.8%;
--radius: 0.5rem;
}
.theme-rose.dark {
--background: 20 14.3% 4.1%;
--foreground: 0 0% 95%;
--muted: 0 0% 15%;
--muted-foreground: 240 5% 64.9%;
--popover: 0 0% 9%;
--popover-foreground: 0 0% 95%;
--card: 24 9.8% 10%;
--card-foreground: 0 0% 95%;
--border: 240 3.7% 15.9%;
--input: 240 3.7% 15.9%;
--primary: 346.8 77.2% 49.8%;
--primary-foreground: 355.7 100% 97.3%;
--secondary: 240 3.7% 15.9%;
--secondary-foreground: 0 0% 98%;
--accent: 12 6.5% 15.1%;
--accent-foreground: 0 0% 98%;
--destructive: 0 62.8% 30.6%;
--destructive-foreground: 0 85.7% 97.3%;
--ring: 346.8 77.2% 49.8%;
}
.theme-orange {
--background: 0 0% 100%;
--foreground: 20 14.3% 4.1%;
--muted: 60 4.8% 95.9%;
--muted-foreground: 25 5.3% 44.7%;
--popover: 0 0% 100%;
--popover-foreground: 20 14.3% 4.1%;
--card: 0 0% 100%;
--card-foreground: 20 14.3% 4.1%;
--border: 20 5.9% 90%;
--input: 20 5.9% 90%;
--primary: 24.6 95% 53.1%;
--primary-foreground: 60 9.1% 97.8%;
--secondary: 60 4.8% 95.9%;
--secondary-foreground: 24 9.8% 10%;
--accent: 60 4.8% 95.9%;
--accent-foreground: 24 9.8% 10%;
--destructive: 0 84.2% 60.2%;
--destructive-foreground: 60 9.1% 97.8%;
--ring: 24.6 95% 53.1%;
--radius: 0.95rem;
}
.theme-orange.dark {
--background: 20 14.3% 4.1%;
--foreground: 60 9.1% 97.8%;
--muted: 12 6.5% 15.1%;
--muted-foreground: 24 5.4% 63.9%;
--popover: 20 14.3% 4.1%;
--popover-foreground: 60 9.1% 97.8%;
--card: 20 14.3% 4.1%;
--card-foreground: 60 9.1% 97.8%;
--border: 12 6.5% 15.1%;
--input: 12 6.5% 15.1%;
--primary: 20.5 90.2% 48.2%;
--primary-foreground: 60 9.1% 97.8%;
--secondary: 12 6.5% 15.1%;
--secondary-foreground: 60 9.1% 97.8%;
--accent: 12 6.5% 15.1%;
--accent-foreground: 60 9.1% 97.8%;
--destructive: 0 72.2% 50.6%;
--destructive-foreground: 60 9.1% 97.8%;
--ring: 20.5 90.2% 48.2%;
}
.theme-green {
--background: 0 0% 100%;
--foreground: 240 10% 3.9%;
--muted: 240 4.8% 95.9%;
--muted-foreground: 240 3.8% 46.1%;
--popover: 0 0% 100%;
--popover-foreground: 240 10% 3.9%;
--card: 0 0% 100%;
--card-foreground: 240 10% 3.9%;
--border: 240 5.9% 90%;
--input: 240 5.9% 90%;
--primary: 142.1 76.2% 36.3%;
--primary-foreground: 355.7 100% 97.3%;
--secondary: 240 4.8% 95.9%;
--secondary-foreground: 240 5.9% 10%;
--accent: 240 4.8% 95.9%;
--accent-foreground: 240 5.9% 10%;
--destructive: 0 84.2% 60.2%;
--destructive-foreground: 0 0% 98%;
--ring: 142.1 76.2% 36.3%;
--radius: ;
}
.theme-green.dark {
--background: 20 14.3% 4.1%;
--foreground: 0 0% 95%;
--muted: 0 0% 15%;
--muted-foreground: 240 5% 64.9%;
--popover: 0 0% 9%;
--popover-foreground: 0 0% 95%;
--card: 24 9.8% 10%;
--card-foreground: 0 0% 95%;
--border: 240 3.7% 15.9%;
--input: 240 3.7% 15.9%;
--primary: 142.1 70.6% 45.3%;
--primary-foreground: 144.9 80.4% 10%;
--secondary: 240 3.7% 15.9%;
--secondary-foreground: 0 0% 98%;
--accent: 12 6.5% 15.1%;
--accent-foreground: 0 0% 98%;
--destructive: 0 62.8% 30.6%;
--destructive-foreground: 0 85.7% 97.3%;
--ring: 142.4 71.8% 29.2%;
}
.theme-blue {
--background: 0 0% 100%;
--foreground: 222.2 84% 4.9%;
--muted: 210 40% 96.1%;
--muted-foreground: 215.4 16.3% 46.9%;
--popover: 0 0% 100%;
--popover-foreground: 222.2 84% 4.9%;
--card: 0 0% 100%;
--card-foreground: 222.2 84% 4.9%;
--border: 214.3 31.8% 91.4%;
--input: 214.3 31.8% 91.4%;
--primary: 221.2 83.2% 53.3%;
--primary-foreground: 210 40% 98%;
--secondary: 210 40% 96.1%;
--secondary-foreground: 222.2 47.4% 11.2%;
--accent: 210 40% 96.1%;
--accent-foreground: 222.2 47.4% 11.2%;
--destructive: 0 84.2% 60.2%;
--destructive-foreground: 210 40% 98%;
--ring: 221.2 83.2% 53.3%;
--radius: ;
}
.theme-blue.dark {
--background: 222.2 84% 4.9%;
--foreground: 210 40% 98%;
--muted: 217.2 32.6% 17.5%;
--muted-foreground: 215 20.2% 65.1%;
--popover: 222.2 84% 4.9%;
--popover-foreground: 210 40% 98%;
--card: 222.2 84% 4.9%;
--card-foreground: 210 40% 98%;
--border: 217.2 32.6% 17.5%;
--input: 217.2 32.6% 17.5%;
--primary: 217.2 91.2% 59.8%;
--primary-foreground: 222.2 47.4% 11.2%;
--secondary: 217.2 32.6% 17.5%;
--secondary-foreground: 210 40% 98%;
--accent: 217.2 32.6% 17.5%;
--accent-foreground: 210 40% 98%;
--destructive: 0 62.8% 30.6%;
--destructive-foreground: 210 40% 98%;
--ring: 224.3 76.3% 48%;
}
.theme-yellow {
--background: 0 0% 100%;
--foreground: 20 14.3% 4.1%;
--muted: 60 4.8% 95.9%;
--muted-foreground: 25 5.3% 44.7%;
--popover: 0 0% 100%;
--popover-foreground: 20 14.3% 4.1%;
--card: 0 0% 100%;
--card-foreground: 20 14.3% 4.1%;
--border: 20 5.9% 90%;
--input: 20 5.9% 90%;
--primary: 47.9 95.8% 53.1%;
--primary-foreground: 26 83.3% 14.1%;
--secondary: 60 4.8% 95.9%;
--secondary-foreground: 24 9.8% 10%;
--accent: 60 4.8% 95.9%;
--accent-foreground: 24 9.8% 10%;
--destructive: 0 84.2% 60.2%;
--destructive-foreground: 60 9.1% 97.8%;
--ring: 20 14.3% 4.1%;
--radius: 0.95rem;
}
.theme-yellow.dark {
--background: 20 14.3% 4.1%;
--foreground: 60 9.1% 97.8%;
--muted: 12 6.5% 15.1%;
--muted-foreground: 24 5.4% 63.9%;
--popover: 20 14.3% 4.1%;
--popover-foreground: 60 9.1% 97.8%;
--card: 20 14.3% 4.1%;
--card-foreground: 60 9.1% 97.8%;
--border: 12 6.5% 15.1%;
--input: 12 6.5% 15.1%;
--primary: 47.9 95.8% 53.1%;
--primary-foreground: 26 83.3% 14.1%;
--secondary: 12 6.5% 15.1%;
--secondary-foreground: 60 9.1% 97.8%;
--accent: 12 6.5% 15.1%;
--accent-foreground: 60 9.1% 97.8%;
--destructive: 0 62.8% 30.6%;
--destructive-foreground: 60 9.1% 97.8%;
--ring: 35.5 91.7% 32.9%;
}
.theme-violet {
--background: 0 0% 100%;
--foreground: 224 71.4% 4.1%;
--muted: 220 14.3% 95.9%;
--muted-foreground: 220 8.9% 46.1%;
--popover: 0 0% 100%;
--popover-foreground: 224 71.4% 4.1%;
--card: 0 0% 100%;
--card-foreground: 224 71.4% 4.1%;
--border: 220 13% 91%;
--input: 220 13% 91%;
--primary: 262.1 83.3% 57.8%;
--primary-foreground: 210 20% 98%;
--secondary: 220 14.3% 95.9%;
--secondary-foreground: 220.9 39.3% 11%;
--accent: 220 14.3% 95.9%;
--accent-foreground: 220.9 39.3% 11%;
--destructive: 0 84.2% 60.2%;
--destructive-foreground: 210 20% 98%;
--ring: 262.1 83.3% 57.8%;
--radius: ;
}
.theme-violet.dark {
--background: 224 71.4% 4.1%;
--foreground: 210 20% 98%;
--muted: 215 27.9% 16.9%;
--muted-foreground: 217.9 10.6% 64.9%;
--popover: 224 71.4% 4.1%;
--popover-foreground: 210 20% 98%;
--card: 224 71.4% 4.1%;
--card-foreground: 210 20% 98%;
--border: 215 27.9% 16.9%;
--input: 215 27.9% 16.9%;
--primary: 263.4 70% 50.4%;
--primary-foreground: 210 20% 98%;
--secondary: 215 27.9% 16.9%;
--secondary-foreground: 210 20% 98%;
--accent: 215 27.9% 16.9%;
--accent-foreground: 210 20% 98%;
--destructive: 0 62.8% 30.6%;
--destructive-foreground: 210 20% 98%;
--ring: 263.4 70% 50.4%;
}

View File

@ -21,6 +21,7 @@
"clsx": "^2.0.0",
"date-fns": "^2.30.0",
"lucide-vue-next": "^0.268.0",
"pinia": "^2.1.6",
"tailwindcss-animate": "^1.0.6",
"v-calendar": "^3.0.3",
"vitepress": "^1.0.0-rc.10",

View File

@ -0,0 +1,9 @@
---
title: Theming - shadcn-vue
---
<script setup>
import Theming from "../../.vitepress/theme/components/theming/Theming.vue"
</script>
<Theming />

View File

@ -1,5 +1,4 @@
.theme-zinc {
.theme-zinc {
--background: 0 0% 100%;
--foreground: 240 10% 3.9%;
@ -30,9 +29,9 @@
--ring: 240 5.9% 10%;
--radius: 0.5rem;
}
}
.dark .theme-zinc {
.theme-zinc.dark {
--background: 240 10% 3.9%;
--foreground: 0 0% 98%;
@ -61,9 +60,9 @@
--destructive-foreground: 0 0% 98%;
--ring: 240 4.9% 83.9%;
}
}
.theme-slate {
.theme-slate {
--background: 0 0% 100%;
--foreground: 222.2 84% 4.9%;
@ -94,9 +93,9 @@
--ring: 222.2 84% 4.9%;
--radius: 0.5rem;
}
}
.dark .theme-slate {
.theme-slate {
--background: 222.2 84% 4.9%;
--foreground: 210 40% 98%;
@ -125,9 +124,9 @@
--destructive-foreground: 210 40% 98%;
--ring: 212.7 26.8% 83.9;
}
}
.theme-stone {
.theme-stone {
--background: 0 0% 100%;
--foreground: 20 14.3% 4.1%;
@ -157,10 +156,10 @@
--ring: 20 14.3% 4.1%;
--radius: 0.5rem;
}
--radius: 0.95rem;
}
.dark .theme-stone {
.theme-stone.dark {
--background: 20 14.3% 4.1%;
--foreground: 60 9.1% 97.8%;
@ -189,9 +188,9 @@
--destructive-foreground: 60 9.1% 97.8%;
--ring: 24 5.7% 82.9%;
}
}
.theme-gray {
.theme-gray {
--background: 0 0% 100%;
--foreground: 224 71.4% 4.1%;
@ -221,10 +220,10 @@
--ring: 224 71.4% 4.1%;
--radius: 0.5rem;
}
--radius: 0.35rem;
}
.dark .theme-gray {
.theme-gray.dark {
--background: 224 71.4% 4.1%;
--foreground: 210 20% 98%;
@ -253,9 +252,9 @@
--destructive-foreground: 210 20% 98%;
--ring: 216 12.2% 83.9%;
}
}
.theme-neutral {
.theme-neutral {
--background: 0 0% 100%;
--foreground: 0 0% 3.9%;
@ -285,10 +284,10 @@
--ring: 0 0% 3.9%;
--radius: 0.5rem;
}
--radius: ;
}
.dark .theme-neutral {
.theme-neutral.dark {
--background: 0 0% 3.9%;
--foreground: 0 0% 98%;
@ -317,9 +316,9 @@
--destructive-foreground: 0 0% 98%;
--ring: 0 0% 83.1%;
}
}
.theme-red {
.theme-red {
--background: 0 0% 100%;
--foreground: 0 0% 3.9%;
@ -349,10 +348,10 @@
--ring: 0 72.2% 50.6%;
--radius: 0.5rem;
}
--radius: 0.4rem;
}
.dark .theme-red {
.theme-red.dark {
--background: 0 0% 3.9%;
--foreground: 0 0% 98%;
@ -381,9 +380,9 @@
--destructive-foreground: 0 0% 98%;
--ring: 0 72.2% 50.6%;
}
}
.theme-rose {
.theme-rose {
--background: 0 0% 100%;
--foreground: 240 10% 3.9%;
@ -414,9 +413,9 @@
--ring: 346.8 77.2% 49.8%;
--radius: 0.5rem;
}
}
.dark .theme-rose {
.theme-rose.dark {
--background: 20 14.3% 4.1%;
--foreground: 0 0% 95%;
@ -445,9 +444,9 @@
--destructive-foreground: 0 85.7% 97.3%;
--ring: 346.8 77.2% 49.8%;
}
}
.theme-orange {
.theme-orange {
--background: 0 0% 100%;
--foreground: 20 14.3% 4.1%;
@ -477,10 +476,10 @@
--ring: 24.6 95% 53.1%;
--radius: 0.5rem;
}
--radius: 0.95rem;
}
.dark .theme-orange {
.theme-orange.dark {
--background: 20 14.3% 4.1%;
--foreground: 60 9.1% 97.8%;
@ -509,9 +508,9 @@
--destructive-foreground: 60 9.1% 97.8%;
--ring: 20.5 90.2% 48.2%;
}
}
.theme-green {
.theme-green {
--background: 0 0% 100%;
--foreground: 240 10% 3.9%;
@ -541,10 +540,10 @@
--ring: 142.1 76.2% 36.3%;
--radius: 0.5rem;
}
--radius: ;
}
.dark .theme-green {
.theme-green.dark {
--background: 20 14.3% 4.1%;
--foreground: 0 0% 95%;
@ -573,9 +572,9 @@
--destructive-foreground: 0 85.7% 97.3%;
--ring: 142.4 71.8% 29.2%;
}
}
.theme-blue {
.theme-blue {
--background: 0 0% 100%;
--foreground: 222.2 84% 4.9%;
@ -605,10 +604,10 @@
--ring: 221.2 83.2% 53.3%;
--radius: 0.5rem;
}
--radius: ;
}
.dark .theme-blue {
.theme-blue.dark {
--background: 222.2 84% 4.9%;
--foreground: 210 40% 98%;
@ -637,9 +636,9 @@
--destructive-foreground: 210 40% 98%;
--ring: 224.3 76.3% 48%;
}
}
.theme-yellow {
.theme-yellow {
--background: 0 0% 100%;
--foreground: 20 14.3% 4.1%;
@ -669,10 +668,10 @@
--ring: 20 14.3% 4.1%;
--radius: 0.5rem;
}
--radius: 0.95rem;
}
.dark .theme-yellow {
.theme-yellow.dark {
--background: 20 14.3% 4.1%;
--foreground: 60 9.1% 97.8%;
@ -701,9 +700,9 @@
--destructive-foreground: 60 9.1% 97.8%;
--ring: 35.5 91.7% 32.9%;
}
}
.theme-violet {
.theme-violet {
--background: 0 0% 100%;
--foreground: 224 71.4% 4.1%;
@ -733,10 +732,10 @@
--ring: 262.1 83.3% 57.8%;
--radius: 0.5rem;
}
--radius: ;
}
.dark .theme-violet {
.theme-violet.dark {
--background: 224 71.4% 4.1%;
--foreground: 210 20% 98%;
@ -765,4 +764,4 @@
--destructive-foreground: 210 20% 98%;
--ring: 263.4 70% 50.4%;
}
}

View File

@ -0,0 +1,32 @@
import { computed, ref } from 'vue'
import type { Theme } from './../lib/registry/themes'
interface Config {
theme: Theme['name']
radius: number
}
export const RADII = [0, 0.25, 0.5, 0.75, 1]
export function useConfigStore() {
const config = ref<Config>({
theme: 'zinc',
radius: 0.5,
})
const themeClass = computed(() => `theme-${config.value.theme}`)
const theme = computed(() => config.value.theme)
const radius = computed(() => config.value.radius)
function setTheme(themeName: Theme['name']) {
config.value.theme = themeName
}
function setRadius(newRadius: number) {
config.value.radius = newRadius
}
return { config, theme, setTheme, radius, setRadius, themeClass }
}

View File

@ -65,6 +65,9 @@ importers:
lucide-vue-next:
specifier: ^0.268.0
version: 0.268.0(vue@3.3.4)
pinia:
specifier: ^2.1.6
version: 2.1.6(typescript@5.0.2)(vue@3.3.4)
tailwindcss-animate:
specifier: ^1.0.6
version: 1.0.6(tailwindcss@3.3.3)
@ -186,6 +189,9 @@ importers:
lodash.template:
specifier: ^4.5.0
version: 4.5.0
magic-string:
specifier: ^0.30.3
version: 0.30.3
node-fetch:
specifier: ^3.3.2
version: 3.3.2
@ -198,12 +204,18 @@ importers:
recast:
specifier: ^0.23.4
version: 0.23.4
rimraf:
specifier: ^5.0.1
version: 5.0.1
ts-morph:
specifier: ^19.0.0
version: 19.0.0
tsconfig-paths:
specifier: ^4.2.0
version: 4.2.0
vite-tsconfig-paths:
specifier: ^4.2.0
version: 4.2.0(typescript@5.2.2)
zod:
specifier: ^3.22.2
version: 3.22.2
@ -226,12 +238,6 @@ importers:
'@vitest/ui':
specifier: ^0.34.3
version: 0.34.3(vitest@0.34.3)
magic-string:
specifier: ^0.30.3
version: 0.30.3
rimraf:
specifier: ^5.0.1
version: 5.0.1
tsup:
specifier: ^7.2.0
version: 7.2.0(ts-node@10.9.1)(typescript@5.2.2)
@ -241,9 +247,6 @@ importers:
typescript:
specifier: ^5.2.2
version: 5.2.2
vite-tsconfig-paths:
specifier: ^4.2.0
version: 4.2.0(typescript@5.2.2)
packages:
@ -1708,7 +1711,6 @@ packages:
strip-ansi-cjs: /strip-ansi@6.0.1
wrap-ansi: 8.1.0
wrap-ansi-cjs: /wrap-ansi@7.0.0
dev: true
/@jest/schemas@29.6.3:
resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==}
@ -1882,7 +1884,6 @@ packages:
resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
engines: {node: '>=14'}
requiresBuild: true
dev: true
optional: true
/@polka/url@1.0.0-next.21:
@ -2937,7 +2938,6 @@ packages:
/ansi-regex@5.0.1:
resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
engines: {node: '>=8'}
dev: true
/ansi-regex@6.0.1:
resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==}
@ -2958,7 +2958,6 @@ packages:
engines: {node: '>=8'}
dependencies:
color-convert: 2.0.1
dev: true
/ansi-styles@5.2.0:
resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==}
@ -2968,7 +2967,6 @@ packages:
/ansi-styles@6.2.1:
resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==}
engines: {node: '>=12'}
dev: true
/any-promise@1.3.0:
resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==}
@ -3377,14 +3375,12 @@ packages:
engines: {node: '>=7.0.0'}
dependencies:
color-name: 1.1.4
dev: true
/color-name@1.1.3:
resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==}
/color-name@1.1.4:
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
dev: true
/colorette@2.0.20:
resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==}
@ -3996,11 +3992,9 @@ packages:
/emoji-regex@8.0.0:
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
dev: true
/emoji-regex@9.2.2:
resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==}
dev: true
/enhanced-resolve@4.5.0:
resolution: {integrity: sha512-Nv9m36S/vxpsI+Hc4/ZGRs0n9mXqSWGGq49zxb/cJfPAQMbUtttJAlNPS4AQzaBdw/pKskw5bMbekT/Y7W/Wlg==}
@ -4722,7 +4716,6 @@ packages:
dependencies:
cross-spawn: 7.0.3
signal-exit: 4.1.0
dev: true
/formdata-polyfill@4.0.10:
resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==}
@ -4884,7 +4877,6 @@ packages:
minimatch: 9.0.3
minipass: 7.0.3
path-scurry: 1.10.1
dev: true
/glob@7.1.6:
resolution: {integrity: sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==}
@ -4956,7 +4948,7 @@ packages:
/globrex@0.1.2:
resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==}
dev: true
dev: false
/gopd@1.0.1:
resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==}
@ -5238,7 +5230,6 @@ packages:
/is-fullwidth-code-point@3.0.0:
resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
engines: {node: '>=8'}
dev: true
/is-fullwidth-code-point@4.0.0:
resolution: {integrity: sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==}
@ -5385,7 +5376,6 @@ packages:
'@isaacs/cliui': 8.0.2
optionalDependencies:
'@pkgjs/parseargs': 0.11.0
dev: true
/jiti@1.19.3:
resolution: {integrity: sha512-5eEbBDQT/jF1xg6l36P+mWGGoH9Spuy0PCdSr2dtWRDGC6ph/w9ZCL4lmESW8f8F7MwT3XKescfP0wnZWAKL9w==}
@ -5660,7 +5650,6 @@ packages:
/lru-cache@10.0.1:
resolution: {integrity: sha512-IJ4uwUTi2qCccrioU6g9g/5rvvVl13bsdczUUcqbciD9iLr095yj8DQKdObriEvuNSx325N1rV1O0sJFszx75g==}
engines: {node: 14 || >=16.14}
dev: true
/lru-cache@5.1.1:
resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
@ -5829,7 +5818,6 @@ packages:
engines: {node: '>=16 || 14 >=14.17'}
dependencies:
brace-expansion: 2.0.1
dev: true
/minimist-options@4.1.0:
resolution: {integrity: sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==}
@ -5858,7 +5846,6 @@ packages:
/minipass@7.0.3:
resolution: {integrity: sha512-LhbbwCfz3vsb12j/WkWQPZfKTsgqIe1Nf/ti1pKjYESGLHIVjWU96G9/ljLH4F9mWNVhlQOm0VySdAWzf05dpg==}
engines: {node: '>=16 || 14 >=14.17'}
dev: true
/minisearch@6.1.0:
resolution: {integrity: sha512-PNxA/X8pWk+TiqPbsoIYH0GQ5Di7m6326/lwU/S4mlo4wGQddIcf/V//1f9TB0V4j59b57b+HZxt8h3iMROGvg==}
@ -6204,7 +6191,6 @@ packages:
dependencies:
lru-cache: 10.0.1
minipass: 7.0.3
dev: true
/path-type@4.0.0:
resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==}
@ -6246,6 +6232,24 @@ packages:
resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==}
engines: {node: '>=0.10.0'}
/pinia@2.1.6(typescript@5.0.2)(vue@3.3.4):
resolution: {integrity: sha512-bIU6QuE5qZviMmct5XwCesXelb5VavdOWKWaB17ggk++NUwQWWbP5YnsONTk3b752QkW9sACiR81rorpeOMSvQ==}
peerDependencies:
'@vue/composition-api': ^1.4.0
typescript: '>=4.4.4'
vue: ^2.6.14 || ^3.3.0
peerDependenciesMeta:
'@vue/composition-api':
optional: true
typescript:
optional: true
dependencies:
'@vue/devtools-api': 6.5.0
typescript: 5.0.2
vue: 3.3.4
vue-demi: 0.14.5(vue@3.3.4)
dev: false
/pirates@4.0.6:
resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==}
engines: {node: '>= 6'}
@ -6619,7 +6623,6 @@ packages:
hasBin: true
dependencies:
glob: 10.3.3
dev: true
/robust-predicates@3.0.2:
resolution: {integrity: sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==}
@ -6847,7 +6850,6 @@ packages:
emoji-regex: 8.0.0
is-fullwidth-code-point: 3.0.0
strip-ansi: 6.0.1
dev: true
/string-width@5.1.2:
resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==}
@ -6856,7 +6858,6 @@ packages:
eastasianwidth: 0.2.0
emoji-regex: 9.2.2
strip-ansi: 7.1.0
dev: true
/string-width@6.1.0:
resolution: {integrity: sha512-k01swCJAgQmuADB0YIc+7TuatfNvTBVOoaUWJjTB9R4VJzR5vNWzf5t42ESVZFPS8xTySF7CAdV4t/aaIm3UnQ==}
@ -6902,7 +6903,6 @@ packages:
engines: {node: '>=8'}
dependencies:
ansi-regex: 5.0.1
dev: true
/strip-ansi@7.1.0:
resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==}
@ -7235,7 +7235,7 @@ packages:
optional: true
dependencies:
typescript: 5.2.2
dev: true
dev: false
/tsconfig-paths@4.2.0:
resolution: {integrity: sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==}
@ -7388,7 +7388,6 @@ packages:
resolution: {integrity: sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==}
engines: {node: '>=14.17'}
hasBin: true
dev: true
/ufo@1.2.0:
resolution: {integrity: sha512-RsPyTbqORDNDxqAdQPQBpgqhWle1VcTSou/FraClYlHf6TZnQcGslpLcAphNR+sQW4q5lLWLbOsRlh9j24baQg==}
@ -7587,7 +7586,7 @@ packages:
transitivePeerDependencies:
- supports-color
- typescript
dev: true
dev: false
/vite@4.3.9(@types/node@20.4.7):
resolution: {integrity: sha512-qsTNZjO9NoJNW7KnOrgYwczm0WctJ8m/yqYAMAK9Lxt4SoySUfS5S8ia9K7JHpa3KEeMfyF8LoJ3c5NeBJy6pg==}
@ -8001,7 +8000,6 @@ packages:
ansi-styles: 4.3.0
string-width: 4.2.3
strip-ansi: 6.0.1
dev: true
/wrap-ansi@8.1.0:
resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==}
@ -8010,7 +8008,6 @@ packages:
ansi-styles: 6.2.1
string-width: 5.1.2
strip-ansi: 7.1.0
dev: true
/wrappy@1.0.2:
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}