chore(playground): compodium setup

This commit is contained in:
Romain Hamel
2025-03-26 11:40:23 +01:00
parent f68061975c
commit 15fe0039f0
47 changed files with 1077 additions and 152 deletions

View File

@@ -0,0 +1,55 @@
<script setup lang="ts">
defineOptions({
inheritAttrs: false
})
extendCompodiumMeta({
defaultProps: {
items: [{
label: 'Getting Started',
icon: 'i-lucide-info',
content: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed neque elit, tristique placerat feugiat ac, facilisis vitae arcu. Proin eget egestas augue. Praesent ut sem nec arcu pellentesque aliquet. Duis dapibus diam vel metus tempus vulputate.'
}, {
label: 'Installation',
icon: 'i-lucide-download',
disabled: true,
content: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed neque elit, tristique placerat feugiat ac, facilisis vitae arcu. Proin eget egestas augue. Praesent ut sem nec arcu pellentesque aliquet. Duis dapibus diam vel metus tempus vulputate.'
}, {
label: 'Theming',
icon: 'i-lucide-pipette',
content: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed neque elit, tristique placerat feugiat ac, facilisis vitae arcu. Proin eget egestas augue. Praesent ut sem nec arcu pellentesque aliquet. Duis dapibus diam vel metus tempus vulputate.'
}, {
label: 'Layouts',
icon: 'i-lucide-layout-dashboard',
content: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed neque elit, tristique placerat feugiat ac, facilisis vitae arcu. Proin eget egestas augue. Praesent ut sem nec arcu pellentesque aliquet. Duis dapibus diam vel metus tempus vulputate.'
}, {
label: 'Components',
icon: 'i-lucide-layers-3',
content: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed neque elit, tristique placerat feugiat ac, facilisis vitae arcu. Proin eget egestas augue. Praesent ut sem nec arcu pellentesque aliquet. Duis dapibus diam vel metus tempus vulputate.'
}, {
label: 'Utilities',
slot: 'custom' as const,
icon: 'i-lucide-wrench',
content: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed neque elit, tristique placerat feugiat ac, facilisis vitae arcu. Proin eget egestas augue. Praesent ut sem nec arcu pellentesque aliquet. Duis dapibus diam vel metus tempus vulputate.'
}]
}
})
</script>
<template>
<UCard :ui="{ body: 'p-0 sm:p-0' }">
<UAccordion v-bind="$attrs" class="w-96" :ui="{ trigger: 'px-3.5', body: 'px-3.5' }">
<template #body="{ item }">
<p class="text-(--ui-text-muted)">
{{ item.content }}
</p>
</template>
<template #custom-body="{ item }">
<p class="text-(--ui-text-muted)">
Custom: {{ item.content }}
</p>
</template>
</UAccordion>
</UCard>
</template>

View File

@@ -0,0 +1,12 @@
<script setup lang="ts">
extendCompodiumMeta({
defaultProps: {
title: 'Heads up!',
description: 'You can change the primary color in your app config.'
}
})
</script>
<template>
<UAlert />
</template>

View File

@@ -0,0 +1,57 @@
<script setup lang="ts">
extendCompodiumMeta({
combo: ['variant'],
defaultProps: {
icon: 'i-lucide-terminal',
title: 'Heads up!',
description: 'You can change the primary color in your app config.',
close: true,
actions: [
{
label: 'Action',
onClick() {
console.log('Action clicked')
}
},
{
label: 'Another action',
color: 'warning',
onClick() {
console.log('Another action clicked')
}
},
{
label: 'One more action',
color: 'error',
onClick() {
console.log('One more action clicked')
}
},
{
label: 'And one more',
color: 'info',
icon: 'i-lucide-info',
onClick() {
console.log('And one more clicked')
}
},
{
label: 'Last one',
color: 'neutral',
icon: 'i-lucide-info',
onClick() {
console.log('Last one clicked')
}
}
]
}
})
const multipleActions = (color: string) => [
]
</script>
<template>
<UAlert />
</template>

View File

@@ -0,0 +1,14 @@
<script setup lang="ts">
extendCompodiumMeta({
combo: ['variant'],
defaultProps: {
avatar: { src: 'https://github.com/benjamincanac.png' },
title: 'Heads up!',
description: 'You can change the primary color in your app config.'
}
})
</script>
<template>
<UAlert />
</template>

View File

@@ -0,0 +1,14 @@
<script setup lang="ts">
extendCompodiumMeta({
combo: ['variant'],
defaultProps: {
icon: 'i-lucide-terminal',
title: 'Heads up!',
description: 'You can change the primary color in your app config.'
}
})
</script>
<template>
<UAlert />
</template>

View File

@@ -0,0 +1,13 @@
<script setup lang="ts">
extendCompodiumMeta({
combo: ['variant', 'color'],
defaultProps: {
title: 'Heads up!',
description: 'You can change the primary color in your app config.'
}
})
</script>
<template>
<UAlert />
</template>

View File

@@ -0,0 +1,11 @@
<script setup lang="ts">
extendCompodiumMeta({
defaultProps: {
src: 'https://github.com/benjamincanac.png'
}
})
</script>
<template>
<UAvatar />
</template>

View File

@@ -0,0 +1,12 @@
<script setup lang="ts">
extendCompodiumMeta({
combo: ['size'],
defaultProps: {
icon: 'i-lucide-image'
}
})
</script>
<template>
<UAvatar />
</template>

View File

@@ -0,0 +1,12 @@
<script setup lang="ts">
extendCompodiumMeta({
combo: ['size'],
defaultProps: {
alt: 'Benjamin Canac'
}
})
</script>
<template>
<UAvatar />
</template>

View File

@@ -0,0 +1,12 @@
<script setup lang="ts">
extendCompodiumMeta({
combo: ['size'],
defaultProps: {
src: 'https://github.com/benjamincanac.png'
}
})
</script>
<template>
<UAvatar />
</template>

View File

@@ -0,0 +1,7 @@
<template>
<UAvatarGroup>
<UAvatar src="https://github.com/benjamincanac.png" alt="Benjamin Canac" />
<UAvatar src="https://github.com/romhml.png" alt="Romain Hamel" />
<UAvatar src="https://github.com/noook.png" alt="Neil Richter" />
</UAvatarGroup>
</template>

View File

@@ -0,0 +1,13 @@
<script setup lang="ts">
extendCompodiumMeta({
combo: ['size']
})
</script>
<template>
<UAvatarGroup>
<UAvatar src="https://github.com/benjamincanac.png" alt="Benjamin Canac" />
<UAvatar src="https://github.com/romhml.png" alt="Romain Hamel" />
<UAvatar src="https://github.com/noook.png" alt="Neil Richter" />
</UAvatarGroup>
</template>

View File

@@ -0,0 +1,15 @@
<script setup lang="ts">
extendCompodiumMeta({
combo: ['size']
})
</script>
<template>
<UAvatarGroup>
<UChip inset text="1">
<UAvatar src="https://github.com/benjamincanac.png" alt="Benjamin Canac" />
</UChip>
<UAvatar src="https://github.com/romhml.png" alt="Romain Hamel" />
<UAvatar src="https://github.com/noook.png" alt="Neil Richter" />
</UAvatarGroup>
</template>

View File

@@ -0,0 +1,11 @@
<script setup lang="ts">
extendCompodiumMeta({
defaultProps: {
label: 'Badge'
}
})
</script>
<template>
<UBadge />
</template>

View File

@@ -0,0 +1,13 @@
<script setup lang="ts">
extendCompodiumMeta({
combo: ['size', 'variant'],
defaultProps: {
label: 'Badge',
avatar: { src: 'https://github.com/benjamincanac.png' }
}
})
</script>
<template>
<UBadge />
</template>

View File

@@ -0,0 +1,13 @@
<script setup lang="ts">
extendCompodiumMeta({
combo: ['size', 'variant'],
defaultProps: {
label: 'Badge',
icon: 'i-lucide-rocket'
}
})
</script>
<template>
<UBadge />
</template>

View File

@@ -0,0 +1,13 @@
<script setup lang="ts">
extendCompodiumMeta({
combo: ['size', 'variant'],
defaultProps: {
label: 'Badge',
disabled: true
}
})
</script>
<template>
<UBadge />
</template>

View File

@@ -2,12 +2,11 @@
extendCompodiumMeta({
combo: ['variant', 'color'],
defaultProps: {
label: 'Click me!',
disabled: true
label: 'Badge'
}
})
</script>
<template>
<UButton />
<UBadge />
</template>

View File

@@ -0,0 +1,30 @@
<script setup lang="ts">
extendCompodiumMeta({
defaultProps: {
items: [{
label: 'Home',
to: '/'
}, {
slot: 'dropdown' as const,
icon: 'i-lucide-ellipsis',
children: [{
label: 'Documentation'
}, {
label: 'Themes'
}, {
label: 'GitHub'
}]
}, {
label: 'Components',
disabled: true
}, {
label: 'Breadcrumb',
to: '/components/breadcrumb'
}]
}
})
</script>
<template>
<UBreadcrumb />
</template>

View File

@@ -1,6 +1,6 @@
<script setup lang="ts">
extendCompodiumMeta({
combo: ['variant', 'size'],
combo: ['size', 'variant'],
defaultProps: {
avatar: { src: 'https://github.com/benjamincanac.png' }
}

View File

@@ -1,6 +1,6 @@
<script setup lang="ts">
extendCompodiumMeta({
combo: ['variant', 'size'],
combo: ['size', 'variant'],
defaultProps: {
label: 'Click me!',
icon: 'i-lucide-rocket'

View File

@@ -1,6 +1,6 @@
<script setup lang="ts">
extendCompodiumMeta({
combo: ['variant', 'size'],
combo: ['size', 'variant'],
defaultProps: {
label: 'Click me!',
loading: true

View File

@@ -0,0 +1,12 @@
<script setup lang="ts">
extendCompodiumMeta({
combo: ['size', 'variant'],
defaultProps: {
label: 'Click me!'
}
})
</script>
<template>
<UButton />
</template>

View File

@@ -0,0 +1,55 @@
<script setup lang="ts">
defineOptions({
inheritAttrs: false
})
</script>
<template>
<div class="flex flex-col gap-4">
<UButtonGroup v-bind="$attrs">
<UButton>Button</UButton>
</UButtonGroup>
<UButtonGroup v-bind="$attrs">
<UInput placeholder="Search..." />
</UButtonGroup>
<UButtonGroup v-bind="$attrs">
<UButton color="neutral" variant="outline">
Button
</UButton>
<UButton color="neutral" variant="subtle">
Button
</UButton>
<UButton color="neutral" variant="outline">
Button
</UButton>
</UButtonGroup>
<UButtonGroup v-bind="$attrs" orientation="vertical">
<UButton color="neutral" variant="outline">
Button
</UButton>
<UInput placeholder="Search..." />
</UButtonGroup>
<UButtonGroup v-bind="$attrs">
<UButton color="neutral" variant="outline">
Button
</UButton>
<UInput placeholder="Search..." />
</UButtonGroup>
<UButtonGroup v-bind="$attrs">
<UInput placeholder="Search..." />
<UButton color="neutral" variant="outline">
Button
</UButton>
</UButtonGroup>
<UButtonGroup v-bind="$attrs">
<UBadge color="neutral" variant="outline" size="lg" label="https://" />
<UInput color="neutral" variant="outline" placeholder="www.example.com" />
</UButtonGroup>
</div>
</template>

View File

@@ -0,0 +1,14 @@
<script setup lang="ts">
extendCompodiumMeta({
combo: ['size', 'orientation']
})
</script>
<template>
<UButtonGroup v-bind="$attrs">
<UButton color="neutral" variant="outline">
Button
</UButton>
<UInput placeholder="Search..." />
</UButtonGroup>
</template>

View File

@@ -0,0 +1,13 @@
<template>
<UCard class="w-96">
<template #header>
<Placeholder class="h-8" />
</template>
<Placeholder class="h-32" />
<template #footer>
<Placeholder class="h-8" />
</template>
</UCard>
</template>

View File

@@ -0,0 +1,23 @@
<script setup lang="ts">
extendCompodiumMeta({
defaultProps: {
items: [
'https://picsum.photos/320/320?v=1',
'https://picsum.photos/320/320?v=2',
'https://picsum.photos/320/320?v=3'
]
}
})
</script>
<template>
<UCarousel
v-slot="{ item }"
class="w-xs h-xs"
>
<img
:src="item"
class="rounded-lg"
>
</UCarousel>
</template>

View File

@@ -1,13 +1,13 @@
<script setup lang="ts">
extendCompodiumMeta({
combo: ['variant', 'size'],
combo: ['size', 'color'],
defaultProps: {
label: 'Click me!',
disabled: true
modelValue: true
}
})
</script>
<template>
<UButton v-bind="$attrs" />
<UCheckbox />
</template>

View File

@@ -0,0 +1,14 @@
<script setup lang="ts">
extendCompodiumMeta({
combo: ['size', 'color'],
defaultProps: {
label: 'Click me!',
description: 'This is a description',
modelValue: true
}
})
</script>
<template>
<UCheckbox />
</template>

View File

@@ -0,0 +1,14 @@
<script setup lang="ts">
extendCompodiumMeta({
combo: ['size', 'color'],
defaultProps: {
label: 'Click me!',
icon: 'lucide:heart',
modelValue: true
}
})
</script>
<template>
<UCheckbox />
</template>

View File

@@ -0,0 +1,14 @@
<script setup lang="ts">
extendCompodiumMeta({
combo: ['size', 'color'],
defaultProps: {
label: 'Click me!',
modelValue: 'indeterminate',
indeterminate: true
}
})
</script>
<template>
<UCheckbox />
</template>

View File

@@ -0,0 +1,5 @@
<template>
<UChip>
<UButton icon="i-lucide-inbox" color="neutral" variant="subtle" />
</UChip>
</template>

View File

@@ -0,0 +1,11 @@
<script setup lang="ts">
extendCompodiumMeta({
combo: ['position']
})
</script>
<template>
<UChip>
<UButton icon="i-lucide-inbox" color="neutral" variant="subtle" />
</UChip>
</template>

View File

@@ -0,0 +1,11 @@
<script setup lang="ts">
extendCompodiumMeta({
combo: ['size']
})
</script>
<template>
<UChip>
<UAvatar src="https://github.com/benjamincanac.png" />
</UChip>
</template>

View File

@@ -0,0 +1,24 @@
<script setup lang="ts">
import { useAppConfig } from '#imports'
const appConfig = useAppConfig()
</script>
<template>
<UCollapsible class="flex flex-col gap-2 w-48">
<UButton
class="group"
icon="i-lucide-lightbulb"
:trailing-icon="appConfig.ui.icons.chevronDown"
color="neutral"
variant="outline"
label="Open"
block
:ui="{ trailingIcon: 'group-data-[state=open]:rotate-180 transition-transform duration-200' }"
/>
<template #content>
<Placeholder class="h-96 w-full" />
</template>
</UCollapsible>
</template>

View File

@@ -0,0 +1,104 @@
<script setup lang="ts">
import type { User } from '~/types'
import { ref, computed, useFetch, useToast } from '#imports'
const toast = useToast()
const open = ref(false)
const searchTerm = ref('')
const selected = ref([])
const { data: users, status } = await useFetch('https://jsonplaceholder.typicode.com/users', {
transform: (data: User[]) => {
return data?.map(user => ({ id: user.id, label: user.name, suffix: user.email, avatar: { src: `https://i.pravatar.cc/120?img=${user.id}` } })) || []
},
lazy: true
})
const loading = ref(false)
const groups = computed(() => [{
id: 'users',
label: searchTerm.value ? `Users matching “${searchTerm.value}”...` : 'Users',
items: users.value || []
}, {
id: 'actions',
items: [{
label: 'Add new file',
suffix: 'Create a new file in the current directory or workspace.',
icon: 'i-lucide-file-plus',
loading: loading.value,
onSelect(e: Event) {
e.preventDefault()
toast.add({ title: 'New file added!' })
loading.value = true
setTimeout(() => {
loading.value = false
}, 2000)
},
kbds: ['meta', 'N']
}, {
label: 'Add new folder',
suffix: 'Create a new folder in the current directory or workspace.',
icon: 'i-lucide-folder-plus',
onSelect(e: Event) {
e.preventDefault()
toast.add({ title: 'New folder added!' })
},
kbds: ['meta', 'F']
}, {
label: 'Add hashtag',
suffix: 'Add a hashtag to the current item.',
icon: 'i-lucide-hash',
onSelect(e: Event) {
e.preventDefault()
toast.add({ title: 'Hashtag added!' })
},
kbds: ['meta', 'H']
}, {
label: 'Add label',
suffix: 'Add a label to the current item.',
icon: 'i-lucide-tag',
onSelect(e: Event) {
e.preventDefault()
toast.add({ title: 'Label added!' })
},
kbds: ['meta', 'L']
}]
}])
// function onSelect(item: typeof groups.value[number]['items'][number]) {
function onSelect(item: any) {
console.log('Selected', item)
}
defineShortcuts({
meta_k: () => open.value = !open.value,
...extractShortcuts(groups.value)
})
</script>
<template>
<UCard :ui="{ body: '!p-0' }">
<UCommandPalette
v-model="selected"
v-model:search-term="searchTerm"
:loading="status === 'pending'"
:groups="groups"
:fuse="{
fuseOptions: {
includeMatches: true
}
}"
multiple
class="sm:max-h-80"
@update:model-value="onSelect"
/>
</UCard>
</template>

View File

@@ -0,0 +1,121 @@
<script setup lang="ts">
import { ref, computed, useFetch, useToast } from '#imports'
import type { User } from '~/types'
const toast = useToast()
const searchTerm = ref('')
const selected = ref([])
const { data: users, status } = await useFetch('https://jsonplaceholder.typicode.com/users', {
// params: { q: searchTermDebounced },
transform: (data: User[]) => {
return data?.map(user => ({ id: user.id, label: user.name, suffix: user.email, avatar: { src: `https://i.pravatar.cc/120?img=${user.id}` } })) || []
},
lazy: true
})
const loading = ref(false)
const groups = computed(() => [{
id: 'users',
label: searchTerm.value ? `Users matching “${searchTerm.value}”...` : 'Users',
items: users.value || []
}, {
id: 'actions',
items: [{
label: 'Add new file',
suffix: 'Create a new file in the current directory or workspace.',
icon: 'i-lucide-file-plus',
loading: loading.value,
onSelect(e: Event) {
e.preventDefault()
toast.add({ title: 'New file added!' })
loading.value = true
setTimeout(() => {
loading.value = false
}, 2000)
},
kbds: ['meta', 'N']
}, {
label: 'Add new folder',
suffix: 'Create a new folder in the current directory or workspace.',
icon: 'i-lucide-folder-plus',
onSelect(e: Event) {
e.preventDefault()
toast.add({ title: 'New folder added!' })
},
kbds: ['meta', 'F']
}, {
label: 'Add hashtag',
suffix: 'Add a hashtag to the current item.',
icon: 'i-lucide-hash',
onSelect(e: Event) {
e.preventDefault()
toast.add({ title: 'Hashtag added!' })
},
kbds: ['meta', 'H']
}, {
label: 'Add label',
suffix: 'Add a label to the current item.',
icon: 'i-lucide-tag',
onSelect(e: Event) {
e.preventDefault()
toast.add({ title: 'Label added!' })
},
kbds: ['meta', 'L']
}]
}])
const labels = [{
label: 'bug',
chip: {
color: 'error' as const
}
}, {
label: 'feature',
chip: {
color: 'success' as const
}
}, {
label: 'enhancement',
chip: {
color: 'info' as const
}
}]
// function onSelect(item: typeof groups.value[number]['items'][number]) {
function onSelect(item: any) {
console.log('Selected', item)
}
</script>
<template>
<UDrawer should-scale-background>
<UButton label="Open in drawer" color="neutral" variant="outline" />
<template #content>
<UCommandPalette
v-model="selected"
v-model:search-term="searchTerm"
v-bind="$attrs"
:loading="status === 'pending'"
:groups="groups"
:fuse="{
fuseOptions: {
includeMatches: true
}
}"
multiple
class="sm:max-h-80 border-t border-(--ui-border) mt-4"
@update:model-value="onSelect"
/>
</template>
</UDrawer>
</template>

View File

@@ -0,0 +1,107 @@
<script setup lang="ts">
import type { User } from '~/types'
import { ref, computed, useFetch, useToast } from '#imports'
const toast = useToast()
const open = ref(false)
const searchTerm = ref('')
const selected = ref([])
const { data: users, status } = await useFetch('https://jsonplaceholder.typicode.com/users', {
// params: { q: searchTermDebounced },
transform: (data: User[]) => {
return data?.map(user => ({ id: user.id, label: user.name, suffix: user.email, avatar: { src: `https://i.pravatar.cc/120?img=${user.id}` } })) || []
},
lazy: true
})
const loading = ref(false)
const groups = computed(() => [{
id: 'users',
label: searchTerm.value ? `Users matching “${searchTerm.value}”...` : 'Users',
items: users.value || []
}, {
id: 'actions',
items: [{
label: 'Add new file',
suffix: 'Create a new file in the current directory or workspace.',
icon: 'i-lucide-file-plus',
loading: loading.value,
onSelect(e: Event) {
e.preventDefault()
toast.add({ title: 'New file added!' })
loading.value = true
setTimeout(() => {
loading.value = false
}, 2000)
},
kbds: ['meta', 'N']
}, {
label: 'Add new folder',
suffix: 'Create a new folder in the current directory or workspace.',
icon: 'i-lucide-folder-plus',
onSelect(e: Event) {
e.preventDefault()
toast.add({ title: 'New folder added!' })
},
kbds: ['meta', 'F']
}, {
label: 'Add hashtag',
suffix: 'Add a hashtag to the current item.',
icon: 'i-lucide-hash',
onSelect(e: Event) {
e.preventDefault()
toast.add({ title: 'Hashtag added!' })
},
kbds: ['meta', 'H']
}, {
label: 'Add label',
suffix: 'Add a label to the current item.',
icon: 'i-lucide-tag',
onSelect(e: Event) {
e.preventDefault()
toast.add({ title: 'Label added!' })
},
kbds: ['meta', 'L']
}]
}])
// function onSelect(item: typeof groups.value[number]['items'][number]) {
function onSelect(item: any) {
console.log('Selected', item)
}
</script>
<template>
<UModal v-model:open="open">
<UButton label="Open in modal" color="neutral" variant="outline" />
<template #content>
<UCommandPalette
v-bind="$attrs"
v-model="selected"
v-model:search-term="searchTerm"
:loading="status === 'pending'"
:groups="groups"
:fuse="{
fuseOptions: {
includeMatches: true
}
}"
multiple
close
class="sm:max-h-80"
@update:open="open = $event"
@update:model-value="onSelect"
/>
</template>
</UModal>
</template>

View File

@@ -0,0 +1,32 @@
<script setup lang="ts">
import { ref } from '#imports'
const labels = [{
label: 'bug',
chip: {
color: 'error' as const
}
}, {
label: 'feature',
chip: {
color: 'success' as const
}
}, {
label: 'enhancement',
chip: {
color: 'info' as const
}
}]
const label = ref()
</script>
<template>
<UPopover :content="{ side: 'right', align: 'start' }">
<UButton label="Select label (popover)" color="neutral" variant="outline" />
<template #content>
<UCommandPalette v-model="label" placeholder="Search labels..." :groups="[{ id: 'labels', items: labels }]" :ui="{ input: '[&>input]:h-9' }" />
</template>
</UPopover>
</template>