feat: add style switcher

This commit is contained in:
zernonia 2023-09-08 14:51:54 +08:00
parent 22e548f452
commit b37ba515dd
6 changed files with 74 additions and 14 deletions

View File

@ -0,0 +1,20 @@
<script setup lang="ts">
import { defineAsyncComponent } from 'vue'
import Spinner from './Spinner.vue'
import { useConfigStore } from '@/stores/config'
const props = defineProps<{
name: string
}>()
const { style } = useConfigStore()
const Component = defineAsyncComponent({
loadingComponent: Spinner,
loader: () => import(`../../../src/lib/registry/${style.value}/example/${props.name}.vue`),
timeout: 5000,
})
</script>
<template>
<Component :is="Component" />
</template>

View File

@ -1,7 +1,8 @@
<script setup lang="ts"> <script setup lang="ts">
import { defineAsyncComponent } from 'vue' import StyleSwitcher from './StyleSwitcher.vue'
import Spinner from './Spinner.vue' import ComponentLoader from './ComponentLoader.vue'
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/lib/registry/default/ui/tabs' import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/lib/registry/default/ui/tabs'
import { useConfigStore } from '@/stores/config'
import { cn } from '@/lib/utils' import { cn } from '@/lib/utils'
const props = withDefaults(defineProps<{ const props = withDefaults(defineProps<{
@ -11,11 +12,7 @@ const props = withDefaults(defineProps<{
sfcTsHtml?: string sfcTsHtml?: string
}>(), { align: 'center' }) }>(), { align: 'center' })
const Component = defineAsyncComponent({ const { style } = useConfigStore()
loadingComponent: Spinner,
loader: () => import(`../../../src/lib/registry/default/example/${props.name}.vue`),
timeout: 5000,
})
</script> </script>
<template> <template>
@ -40,6 +37,9 @@ const Component = defineAsyncComponent({
</TabsList> </TabsList>
</div> </div>
<TabsContent value="preview" class="relative rounded-md border"> <TabsContent value="preview" class="relative rounded-md border">
<div className="flex items-center justify-between p-4">
<StyleSwitcher />
</div>
<div <div
:class="cn('preview flex min-h-[350px] w-full justify-center p-10', { :class="cn('preview flex min-h-[350px] w-full justify-center p-10', {
'items-center': align === 'center', 'items-center': align === 'center',
@ -47,7 +47,7 @@ const Component = defineAsyncComponent({
'items-end': align === 'end', 'items-end': align === 'end',
})" })"
> >
<Component :is="Component" /> <ComponentLoader :key="style" :name="name" />
</div> </div>
</TabsContent> </TabsContent>
<TabsContent value="code"> <TabsContent value="code">

View File

@ -0,0 +1,33 @@
<script setup lang="ts">
import { type SelectTriggerProps } from 'radix-vue'
import { useConfigStore } from '@/stores/config'
import { cn } from '@/lib/utils'
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from '@/lib/registry/new-york/ui/select'
import { styles } from '@/lib/registry/styles'
const props = defineProps<SelectTriggerProps & { class?: string }>()
const { config } = useConfigStore()
</script>
<template>
<Select v-model="config.style">
<SelectTrigger :class="cn('h-7 w-[145px] text-xs [&_svg]:h-4 [&_svg]:w-4', props.class)">
<span class="text-muted-foreground">Style: </span>
<SelectValue placeholder="Select style">
{{ styles.find(s => s.name === config.style)?.label }}
</SelectValue>
</SelectTrigger>
<SelectContent>
<SelectItem v-for="style in styles" :key="style.name" :value="style.name" class="text-xs">
{{ style.label }}
</SelectItem>
</SelectContent>
</Select>
</template>

View File

@ -0,0 +1,4 @@
import { useStorage } from '@vueuse/core'
import { styles } from '../../../src/lib/registry/styles'
export const useStyle = () => useStorage('selected-style', styles[0].name)

View File

@ -3,10 +3,10 @@ export const styles = [
name: 'default', name: 'default',
label: 'Default', label: 'Default',
}, },
// { {
// name: 'new-york', name: 'new-york',
// label: 'New York', label: 'New York',
// }, },
] as const ] as const
export type Style = (typeof styles)[number] export type Style = (typeof styles)[number]

View File

@ -1,10 +1,12 @@
import { computed } from 'vue' import { computed } from 'vue'
import { useSessionStorage } from '@vueuse/core' import { useSessionStorage } from '@vueuse/core'
import type { Theme } from './../lib/registry/themes' import type { Theme } from './../lib/registry/themes'
import { styles } from '@/lib/registry/styles'
interface Config { interface Config {
theme: Theme['name'] theme: Theme['name']
radius: number radius: number
style: string
} }
export const RADII = [0, 0.25, 0.5, 0.75, 1] export const RADII = [0, 0.25, 0.5, 0.75, 1]
@ -13,13 +15,14 @@ export function useConfigStore() {
const config = useSessionStorage<Config>('config', { const config = useSessionStorage<Config>('config', {
theme: 'zinc', theme: 'zinc',
radius: 0.5, radius: 0.5,
style: styles[0].name,
}) })
const themeClass = computed(() => `theme-${config.value.theme}`) const themeClass = computed(() => `theme-${config.value.theme}`)
const theme = computed(() => config.value.theme) const theme = computed(() => config.value.theme)
const radius = computed(() => config.value.radius) const radius = computed(() => config.value.radius)
const style = computed(() => config.value.style)
function setTheme(themeName: Theme['name']) { function setTheme(themeName: Theme['name']) {
config.value.theme = themeName config.value.theme = themeName
@ -29,5 +32,5 @@ export function useConfigStore() {
config.value.radius = newRadius config.value.radius = newRadius
} }
return { config, theme, setTheme, radius, setRadius, themeClass } return { config, theme, setTheme, radius, setRadius, themeClass, style }
} }