This commit is contained in:
Benjamin Canac
2024-03-27 12:34:25 +01:00
155 changed files with 11236 additions and 3062 deletions

View File

@@ -1,6 +1,6 @@
export default defineAppConfig({
ui: {
primary: 'green',
primary: 'sky',
gray: 'cool'
}
})

View File

@@ -1,23 +1,50 @@
<template>
<UContainer class="min-h-screen flex items-center">
<UCard class="flex-1" :ui="{ background: 'bg-gray-50 dark:bg-gray-800/50', ring: 'ring-1 ring-gray-300 dark:ring-gray-700', divide: 'divide-y divide-gray-300 dark:divide-gray-700', header: { base: 'font-bold' } }">
<template #header>
Welcome to the playground!
</template>
<script setup lang="ts">
import { splitByCase, upperFirst } from 'scule'
<p class="text-gray-500 dark:text-gray-400">
Try your components here!
</p>
</UCard>
</UContainer>
</template>
useHead({
bodyAttrs: {
class: 'antialiased font-sans text-gray-900 dark:text-white bg-white dark:bg-gray-900'
}
})
<script setup>
const components = [
'accordion',
'avatar',
'badge',
'button',
'card',
'checkbox',
'chip',
'collapsible',
'form',
'form-field',
'input',
'kbd',
'link',
'modal',
'navigation-menu',
'popover',
'skeleton',
'slideover',
'switch',
'tabs',
'textarea',
'tooltip'
]
function upperName (name: string) {
return splitByCase(name).map(p => upperFirst(p)).join('')
}
</script>
<style>
body {
@apply antialiased font-sans text-gray-700 dark:text-gray-200 bg-white dark:bg-gray-900;
}
</style>
<template>
<UProvider>
<UContainer class="min-h-screen flex flex-col gap-4 items-center justify-center overflow-y-auto">
<UNavigationMenu :links="components.map(component => ({ label: upperName(component), to: `/${component}` }))" class="border-b border-gray-200 dark:border-gray-800 overflow-x-auto" />
<div class="flex-1 flex flex-col justify-center pb-12">
<NuxtPage />
</div>
</UContainer>
</UProvider>
</template>

View File

@@ -0,0 +1,65 @@
<script setup lang="ts">
import { z } from 'zod'
import type { FormSubmitEvent } from '#ui/types/form'
const schema = z.object({
email: z.string().min(2),
password: z.string().min(8)
})
type Schema = z.output<typeof schema>
const nestedSchema = z.object({
phone: z.string().length(10)
})
type NestedSchema = z.output<typeof nestedSchema>
const state = reactive<Partial<Schema & { nested: Partial<NestedSchema> }>>({
nested: {}
})
const checked = ref(false)
function onSubmit (event: FormSubmitEvent<Schema>) {
console.log('Success', event.data)
}
function onError (event: any) {
console.log('Error', event)
}
</script>
<template>
<UForm
:state="state"
:schema="schema"
class="gap-4 flex flex-col w-60"
@submit="(event) => onSubmit(event)"
@error="(event) => onError(event)"
>
<UFormField label="Email" name="email">
<UInput v-model="state.email" placeholder="john@lennon.com" />
</UFormField>
<UFormField label="Password" name="password">
<UInput v-model="state.password" type="password" />
</UFormField>
<div>
<UCheckbox v-model="checked" name="check" label="Check me" @change="state.nested = {}" />
</div>
<UForm v-if="checked && state.nested" :state="state.nested" :schema="nestedSchema">
<UFormField label="Phone" name="phone">
<UInput v-model="state.nested.phone" />
</UFormField>
</UForm>
<div>
<UButton color="gray" type="submit">
Submit
</UButton>
</div>
</UForm>
</template>

View File

@@ -0,0 +1,85 @@
<script setup lang="ts">
import { z } from 'zod'
import type { FormSubmitEvent } from '#ui/types/form'
const schema = z.object({
email: z.string().min(2),
password: z.string().min(8)
})
type Schema = z.output<typeof schema>
const itemSchema = z.object({
name: z.string().min(1),
price: z.string().min(1)
})
type ItemSchema = z.output<typeof itemSchema>
const state = reactive<Partial<Schema & { items: Partial<ItemSchema>[] }>>({})
function addItem () {
if (!state.items) {
state.items = []
}
state.items.push({})
}
function removeItem () {
if (state.items) {
state.items.pop()
}
}
const formItemRef = ref()
function onSubmit (event: FormSubmitEvent<Schema>) {
console.log('Success', event.data)
}
function onError (event: any) {
console.log('Error', event)
}
</script>
<template>
<UForm
ref="formItemRef"
:state="state"
:schema="schema"
class="gap-4 flex flex-col w-60"
@submit="onSubmit"
@error="onError"
>
<UFormField label="Email" name="email">
<UInput v-model="state.email" placeholder="john@lennon.com" />
</UFormField>
<UFormField label="Password" name="password">
<UInput v-model="state.password" type="password" />
</UFormField>
<UForm v-for="item, count in state.items" :key="count" :state="item" :schema="itemSchema" class="flex gap-2">
<UFormField label="Name" name="name">
<UInput v-model="item.name" />
</UFormField>
<UFormField label="Price" name="price">
<UInput v-model="item.price" />
</UFormField>
</UForm>
<div class="flex gap-2">
<UButton color="black" @click="addItem()">
Add Item
</UButton>
<UButton color="black" variant="ghost" @click="removeItem()">
Remove Item
</UButton>
</div>
<div>
<UButton color="gray" type="submit">
Submit
</UButton>
</div>
</UForm>
</template>

View File

@@ -0,0 +1,21 @@
<template>
<div class="relative overflow-hidden rounded border border-dashed border-gray-400 dark:border-gray-500 opacity-75 px-4 flex items-center justify-center">
<svg class="absolute inset-0 h-full w-full stroke-gray-900/10 dark:stroke-white/10" fill="none">
<defs>
<pattern
id="pattern-5c1e4f0e-62d5-498b-8ff0-cf77bb448c8e"
x="0"
y="0"
width="10"
height="10"
patternUnits="userSpaceOnUse"
>
<path d="M-3 13 15-5M-5 5l18-18M-1 21 17 3" />
</pattern>
</defs>
<rect stroke="none" fill="url(#pattern-5c1e4f0e-62d5-498b-8ff0-cf77bb448c8e)" width="100%" height="100%" />
</svg>
<slot />
</div>
</template>

View File

@@ -1,5 +1,7 @@
// https://nuxt.com/docs/api/configuration/nuxt-config
export default defineNuxtConfig({
modules: [
'../src/module'
]
modules: ['../src/module'],
ui: {
colors: ['primary', 'red']
}
})

16
playground/package.json Normal file
View File

@@ -0,0 +1,16 @@
{
"private": true,
"name": "nuxt-ui-playground",
"type": "module",
"scripts": {
"dev": "nuxi dev",
"build": "nuxi build",
"generate": "nuxi generate"
},
"dependencies": {
"@nuxt/ui": "latest",
"nuxt": "latest",
"vue": "latest",
"vue-router": "latest"
}
}

View File

@@ -0,0 +1,35 @@
<script setup lang="ts">
const items = [{
label: 'Getting Started',
icon: 'i-heroicons-information-circle',
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-heroicons-arrow-down-tray',
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-heroicons-eye-dropper',
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-heroicons-rectangle-group',
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-heroicons-square-3-stack-3d',
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: 'toto',
icon: 'i-heroicons-wrench-screwdriver',
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 :items="items" class="w-96" :ui="{ trigger: 'px-3.5', content: 'px-3.5' }" />
</UCard>
</template>

View File

@@ -0,0 +1,22 @@
<script setup lang="ts">
import theme from '#build/ui/avatar'
const sizes = Object.keys(theme.variants.size)
</script>
<template>
<div class="flex flex-col gap-2">
<div class="flex items-center gap-1.5">
<UAvatar v-for="size in sizes" :key="size" src="https://avatars.githubusercontent.com/u/739984?v=4" alt="Benjamin Canac" :size="(size as any)" />
</div>
<div class="flex items-center gap-1.5">
<UAvatar v-for="size in sizes" :key="size" icon="i-heroicons-photo" :size="(size as any)" />
</div>
<div class="flex items-center gap-1.5">
<UAvatar v-for="size in sizes" :key="size" alt="Benjamin Canac" :size="(size as any)" />
</div>
<div class="flex items-center gap-1.5">
<UAvatar v-for="size in sizes" :key="size" :text="size" :size="(size as any)" />
</div>
</div>
</template>

View File

@@ -0,0 +1,33 @@
<script setup lang="ts">
import theme from '#build/ui/badge'
const sizes = Object.keys(theme.variants.size)
</script>
<template>
<div class="flex flex-col gap-2">
<div class="flex items-center gap-2">
<UBadge class="font-bold">
Badge
</UBadge>
</div>
<div class="flex items-center gap-2">
<UBadge label="Badge" />
<UBadge label="Badge" variant="outline" />
<UBadge label="Badge" variant="soft" />
<UBadge label="Badge" variant="subtle" />
</div>
<div class="flex items-center gap-2">
<UBadge label="Badge" color="white" />
</div>
<div class="flex items-center gap-2">
<UBadge label="Badge" color="gray" />
</div>
<div class="flex items-center gap-2">
<UBadge label="Badge" color="black" />
</div>
<div class="flex items-center gap-2 ml-[-56px]">
<UBadge v-for="size in sizes" :key="size" label="Badge" :size="(size as any)" />
</div>
</div>
</template>

View File

@@ -0,0 +1,88 @@
<script setup lang="ts">
import theme from '#build/ui/button'
const sizes = Object.keys(theme.variants.size)
</script>
<template>
<div class="flex flex-col gap-2">
<div class="flex items-center gap-2">
<UButton class="font-bold">
Button
</UButton>
</div>
<div class="flex items-center gap-2">
<UButton disabled>
Disabled
</UButton>
</div>
<div class="flex items-center gap-2">
<UButton loading>
Loading
</UButton>
<UButton loading leading-icon="i-heroicons-rocket-launch">
Loading
</UButton>
</div>
<div class="flex items-center gap-2">
<UButton loading trailing>
Loading
</UButton>
<UButton loading trailing-icon="i-heroicons-paper-airplane">
Loading
</UButton>
</div>
<div class="flex items-center gap-2">
<UButton truncate class="w-16">
Truncate
</UButton>
</div>
<div class="flex items-center gap-2">
<UButton icon="i-heroicons-rocket-launch" label="Button" />
<UButton icon="i-heroicons-rocket-launch" label="Button" variant="outline" />
<UButton icon="i-heroicons-rocket-launch" label="Button" variant="soft" />
<UButton icon="i-heroicons-rocket-launch" label="Button" variant="ghost" />
<UButton icon="i-heroicons-rocket-launch" label="Button" variant="link" />
</div>
<div class="flex items-center gap-2">
<UButton icon="i-heroicons-rocket-launch" label="Button" color="white" />
<UButton icon="i-heroicons-rocket-launch" label="Button" color="white" variant="ghost" />
</div>
<div class="flex items-center gap-2">
<UButton icon="i-heroicons-rocket-launch" label="Button" color="gray" />
<UButton icon="i-heroicons-rocket-launch" label="Button" color="gray" variant="ghost" />
<UButton icon="i-heroicons-rocket-launch" label="Button" color="gray" variant="link" />
</div>
<div class="flex items-center gap-2">
<UButton icon="i-heroicons-rocket-launch" label="Button" color="black" />
<UButton icon="i-heroicons-rocket-launch" label="Button" color="black" variant="link" />
</div>
<div class="flex items-center gap-2 ml-[-129px]">
<UButton v-for="size in sizes" :key="size" label="Button" :size="(size as any)" />
</div>
<div class="flex items-center gap-2 ml-[-171px]">
<UButton v-for="size in sizes" :key="size" icon="i-heroicons-rocket-launch" label="Button" :size="(size as any)" />
</div>
<div class="flex items-center gap-2 ml-[-159px]">
<UButton
v-for="size in sizes"
:key="size"
icon="i-heroicons-rocket-launch"
label="Square"
square
:size="(size as any)"
/>
</div>
<div class="flex items-center gap-2 ml-[-67px]">
<UButton v-for="size in sizes" :key="size" icon="i-heroicons-rocket-launch" :size="(size as any)" />
</div>
<div class="flex items-center gap-2">
<UButton icon="i-heroicons-rocket-launch" trailing-icon="i-heroicons-chevron-down-20-solid" label="Block" loading block />
</div>
<div class="flex items-center gap-2">
<UButton icon="i-heroicons-cloud-arrow-down" label="Button" class="group" :ui="{ leadingIcon: 'group-hover:animate-pulse' }" />
</div>
</div>
</template>

15
playground/pages/card.vue Normal file
View File

@@ -0,0 +1,15 @@
<template>
<div class="flex flex-col gap-4">
<UCard class="w-96">
<template #header>
<Placeholder class="h-8" />
</template>
<Placeholder class="h-32" />
<template #footer>
<Placeholder class="h-8" />
</template>
</UCard>
</div>
</template>

View File

@@ -0,0 +1,25 @@
<script setup lang="ts">
import theme from '#build/ui/checkbox'
const sizes = Object.keys(theme.variants.size)
</script>
<template>
<div class="flex flex-col items-center gap-4">
<div class="flex flex-col gap-4 ml-[-272px]">
<UCheckbox label="Normal" />
<UCheckbox label="Checked" :model-value="true" />
<UCheckbox label="Indeterminate" indeterminate />
<UCheckbox label="Default checked" default-checked />
<UCheckbox label="Required" required />
<UCheckbox label="Disabled" disabled />
<UCheckbox label="Custom icon" color="red" icon="i-heroicons-heart-solid" :model-value="true" />
</div>
<div class="flex items-center gap-4 ml-[-156px]">
<UCheckbox v-for="size in sizes" :key="size" label="Check me" :size="(size as any)" />
</div>
<div class="flex items-center gap-4">
<UCheckbox v-for="size in sizes" :key="size" label="Check me" description="This is a description" :size="(size as any)" />
</div>
</div>
</template>

38
playground/pages/chip.vue Normal file
View File

@@ -0,0 +1,38 @@
<script setup lang="ts">
import theme from '#build/ui/chip'
const sizes = Object.keys(theme.variants.size)
const positions = Object.keys(theme.variants.position)
const items = [{
name: 'messages',
icon: 'i-heroicons-chat-bubble-oval-left',
count: 3
}, {
name: 'notifications',
icon: 'i-heroicons-bell',
count: 0
}]
</script>
<template>
<div class="flex flex-col gap-4">
<div class="flex items-center gap-2">
<UChip v-for="position in positions" :key="position" :position="(position as any)">
<UButton icon="i-heroicons-inbox" color="gray" />
</UChip>
</div>
<div class="flex items-center gap-2">
<UChip v-for="{ name, icon, count } in items" :key="name" :text="count" :show="count > 0" size="lg">
<UButton :icon="icon" color="gray" />
</UChip>
</div>
<div class="flex items-center gap-2 ml-[-84px]">
<UChip v-for="size in sizes" :key="size" :size="(size as any)" inset text="1">
<UAvatar src="https://avatars.githubusercontent.com/u/739984?v=4" :size="(size as any)" />
</UChip>
</div>
</div>
</template>

View File

@@ -0,0 +1,16 @@
<template>
<UCollapsible class="space-y-2 w-48">
<UButton
class="group"
trailing-icon="i-heroicons-chevron-right-20-solid"
color="gray"
label="Open"
block
:ui="{ trailingIcon: 'group-data-[state=open]:rotate-90 transition-transform duration-200' }"
/>
<template #content>
<Placeholder class="h-24 w-full" />
</template>
</UCollapsible>
</template>

View File

@@ -0,0 +1,49 @@
<script setup lang="ts">
import theme from '#build/ui/formField'
const sizes = Object.keys(theme.variants.size)
const feedbacks = [
{ description: 'This is a description' },
{ error: 'This is an error' },
{ hint: 'This is a hint' },
{ help: 'Help! I need somebody!' },
{ required: true }
]
</script>
<template>
<div class="flex flex-col items-center gap-4">
<div class="flex flex-col gap-4 ml-[-258px]">
<div v-for="(feedback, count) in feedbacks" :key="count" class="flex items-center">
<UFormField v-bind="feedback" label="Email" name="email">
<UInput placeholder="john@lennon.com" />
</UFormField>
</div>
</div>
<div class="flex items-center gap-4">
<UFormField
v-for="size in sizes"
:key="size"
:size="(size as any)"
label="Email"
name="email"
>
<UInput placeholder="john@lennon.com" />
</UFormField>
</div>
<div class="flex items-center gap-4">
<UFormField
v-for="size in sizes"
:key="size"
:size="(size as any)"
label="Email"
description="This is a description"
name="email"
>
<UInput placeholder="john@lennon.com" />
</UFormField>
</div>
</div>
</template>

121
playground/pages/form.vue Normal file
View File

@@ -0,0 +1,121 @@
<script setup lang="ts">
import { z } from 'zod'
import type { Form, FormSubmitEvent } from '#ui/types/form'
type User = {
email: string
password: string
tos: boolean
}
const state = reactive<Partial<User>>({})
const state2 = reactive<Partial<User>>({})
const state3 = reactive<Partial<User>>({})
const schema = z.object({
email: z.string().email(),
password: z.string().min(8),
tos: z.literal(true)
})
const disabledForm = ref<Form<User>>()
function onSubmit (event: FormSubmitEvent<User>) {
console.log(event.data)
}
</script>
<template>
<div class="flex flex-col gap-4">
<div class="flex gap-4">
<UForm
:state="state"
:schema="schema"
class="gap-4 flex flex-col w-60"
@submit="(event) => onSubmit(event)"
>
<UFormField label="Email" name="email">
<UInput v-model="state.email" placeholder="john@lennon.com" />
</UFormField>
<UFormField label="Password" name="password">
<UInput v-model="state.password" type="password" />
</UFormField>
<UFormField name="tos">
<UCheckbox v-model="state.tos" label="I accept the terms and conditions" />
</UFormField>
<div>
<UButton color="gray" type="submit">
Submit
</UButton>
</div>
</UForm>
<UForm
:state="state2"
:schema="schema"
class="gap-4 flex flex-col w-60"
:validate-on-input-delay="2000"
@submit="(event) => onSubmit(event)"
>
<UFormField label="Email" name="email">
<UInput v-model="state2.email" placeholder="john@lennon.com" />
</UFormField>
<UFormField
label="Password"
name="password"
:validate-on-input-delay="50"
eager-validation
>
<UInput v-model="state2.password" type="password" />
</UFormField>
<div>
<UButton color="gray" type="submit">
Submit
</UButton>
</div>
</UForm>
<UForm
ref="disabledForm"
:state="state3"
:schema="schema"
class="gap-4 flex flex-col w-60"
disabled
@submit="(event) => onSubmit(event)"
>
<UFormField label="Email" name="email">
<UInput v-model="state3.email" placeholder="john@lennon.com" />
</UFormField>
<UFormField
label="Password"
name="password"
:validate-on-input-delay="50"
eager-validation
>
<UInput v-model="state3.password" type="password" />
</UFormField>
<UFormField name="tos">
<UCheckbox v-model="state3.tos" label="I accept the terms and conditions" />
</UFormField>
<div>
<UButton color="gray" type="submit" :disabled="disabledForm?.disabled">
Submit
</UButton>
</div>
</UForm>
</div>
<div class="flex gap-4">
<FormNestedExample />
<FormNestedListExample />
</div>
</div>
</template>

View File

@@ -0,0 +1,3 @@
<template>
<div />
</template>

View File

@@ -0,0 +1,51 @@
<script setup lang="ts">
import theme from '#build/ui/input'
const sizes = Object.keys(theme.variants.size)
</script>
<template>
<div class="flex flex-col items-center gap-4">
<div class="flex flex-col gap-4 ml-[-120px]">
<UInput placeholder="Search..." autofocus />
<UInput placeholder="Search..." color="gray" />
<UInput placeholder="Search..." color="primary" />
<UInput placeholder="Search..." disabled />
<UInput placeholder="Search..." type="number" />
<UInput icon="i-heroicons-folder" placeholder="Search..." type="file" />
<UInput icon="i-heroicons-calendar" placeholder="Search..." type="date" />
<UInput icon="i-heroicons-lock-closed" placeholder="Search..." type="password" value="password" />
<UInput loading placeholder="Search..." />
<UInput loading leading-icon="i-heroicons-magnifying-glass" placeholder="Search..." />
<UInput loading trailing placeholder="Search..." />
<UInput loading trailing-icon="i-heroicons-magnifying-glass" placeholder="Search..." />
</div>
<div class="flex items-center gap-4">
<UInput
v-for="size in sizes"
:key="size"
placeholder="Search..."
:size="(size as any)"
/>
</div>
<div class="flex items-center gap-4">
<UInput
v-for="size in sizes"
:key="size"
icon="i-heroicons-magnifying-glass"
placeholder="Search..."
:size="(size as any)"
/>
</div>
<div class="flex items-center gap-4">
<UInput
v-for="size in sizes"
:key="size"
icon="i-heroicons-magnifying-glass"
trailing
placeholder="Search..."
:size="(size as any)"
/>
</div>
</div>
</template>

6
playground/pages/kbd.vue Normal file
View File

@@ -0,0 +1,6 @@
<template>
<div class="flex items-center gap-1">
<UKbd value="⌘" />
<UKbd value="K" />
</div>
</template>

55
playground/pages/link.vue Normal file
View File

@@ -0,0 +1,55 @@
<template>
<div class="flex items-center gap-4">
<div class="flex flex-col items-start gap-2 text-sm">
<ULink raw>
Button raw
</ULink>
<ULink active>
Button active
</ULink>
<ULink active class="font-medium" active-class="text-gray-900 dark:text-white">
Button active with class
</ULink>
<ULink active disabled>
Button active disabled
</ULink>
<ULink>
Button inactive
</ULink>
<ULink class="font-medium" inactive-class="hover:text-primary-500 dark:hover:text-primary-400">
Button inactive with class
</ULink>
<ULink disabled>
Button inactive disabled
</ULink>
</div>
<div class="flex flex-col items-start gap-2 text-sm">
<ULink to="/link" raw>
Link raw
</ULink>
<ULink to="/link">
Link active
</ULink>
<ULink to="/link" class="font-medium" active-class="text-gray-900 dark:text-white">
Link active with class
</ULink>
<ULink to="/link" disabled>
Link active disabled
</ULink>
<ULink to="/button">
Link inactive
</ULink>
<ULink to="/button" class="font-medium" inactive-class="hover:text-primary-500 dark:hover:text-primary-400">
Link inactive with class
</ULink>
<ULink to="/button" disabled>
Link inactive disabled
</ULink>
</div>
</div>
</template>

View File

@@ -0,0 +1,53 @@
<script setup lang="ts">
const open = ref(false)
</script>
<template>
<div class="flex flex-col gap-2">
<UModal title="First modal">
<UButton color="white" label="Open with nested" />
<template #footer>
<UModal title="Second modal">
<UButton label="Open second" />
</UModal>
</template>
</UModal>
<UModal v-model:open="open" title="Modal with v-model" description="This can be useful to control the state of the modal yourself." />
<UButton label="Open with v-model" color="gray" @click="open = true" />
<UModal title="Modal without overlay" description="This modal has `overlay: false` prop." :overlay="false">
<UButton label="Open without overlay" color="white" />
</UModal>
<UModal title="Modal without modal & overlay" description="This modal has `modal: false` and `overlay: false` to interact with outside content." :overlay="false" :modal="false">
<UButton label="Open without modal" color="gray" />
</UModal>
<UModal title="Modal without transition" description="This modal has `transition: false` prop." :transition="false">
<UButton label="Open without transition" color="white" />
</UModal>
<UModal title="Modal without portal" description="This modal has `portal: false` prop." :portal="false">
<UButton label="Open without portal" color="gray" />
</UModal>
<UModal title="Modal fullscreen" description="This modal has `fullscreen: true` prop." fullscreen>
<UButton label="Open fullscreen" color="white" />
</UModal>
<UModal title="Modal prevent close" description="This modal has `prevent-close: true` prop so it won't close when clicking outside." prevent-close>
<UButton label="Open unclosable" color="gray" />
</UModal>
<UModal title="Modal without close button" description="This modal has `close: null` prop." :close="null">
<UButton label="Open without close button" color="white" />
</UModal>
<UModal title="Modal with custom close button" description="The `close` prop inherits from the Button props." :close="{ color: 'primary', variant: 'solid', size: 'xs' }" :ui="{ close: 'top-3.5 rounded-full' }">
<UButton label="Open with custom close button" color="gray" />
</UModal>
</div>
</template>

View File

@@ -0,0 +1,43 @@
<script setup lang="ts">
const links = [
[{
label: 'Profile',
active: true,
avatar: {
src: 'https://avatars.githubusercontent.com/u/739984?v=4'
},
badge: 100,
click () {
console.log('Profile clicked')
}
}, {
label: 'Modal',
icon: 'i-heroicons-home',
to: '/modal'
}, {
label: 'NavigationMenu',
icon: 'i-heroicons-chart-bar',
to: '/navigation-menu'
}, {
label: 'Popover',
icon: 'i-heroicons-command-line',
to: '/popover'
}], [{
label: 'Examples',
icon: 'i-heroicons-light-bulb',
to: 'https://ui.nuxt.com',
target: '_blank'
}, {
label: 'Help',
icon: 'i-heroicons-question-mark-circle'
}]
]
</script>
<template>
<div class="flex flex-col gap-12 w-4xl">
<UNavigationMenu :links="links" class="border-b border-gray-200 dark:border-gray-800" />
<UNavigationMenu :links="links" orientation="vertical" class="w-48" />
</div>
</template>

View File

@@ -0,0 +1,64 @@
<script setup lang="ts">
const open = ref(false)
const loading = ref(false)
function send () {
loading.value = true
setTimeout(() => {
loading.value = false
open.value = false
}, 1000)
}
</script>
<template>
<div class="text-center">
<UPopover v-model:open="open" arrow>
<UButton label="Click me" color="white" />
<template #content>
<div class="flex justify-center gap-2 p-4 w-48">
<UButton label="Close" color="gray" @click="open = false" />
<UButton label="Send" color="black" trailing-icon="i-heroicons-paper-airplane" :loading="loading" @click="send" />
</div>
</template>
</UPopover>
<div class="mt-24">
<UPopover mode="hover" :content="{ side: 'top' }">
<UButton label="Hover me top" color="white" />
<template #content>
<div class="w-48 h-16" />
</template>
</UPopover>
<div class="flex items-center gap-2 my-2">
<UPopover mode="hover" :content="{ side: 'left' }">
<UButton label="Hover me left" color="white" />
<template #content>
<div class="w-48 h-16" />
</template>
</UPopover>
<UPopover mode="hover" :content="{ side: 'right' }">
<UButton label="Hover me right" color="white" />
<template #content>
<div class="w-48 h-16" />
</template>
</UPopover>
</div>
<UPopover mode="hover">
<UButton label="Hover me bottom" color="white" />
<template #content>
<div class="w-48 h-16" />
</template>
</UPopover>
</div>
</div>
</template>

View File

@@ -0,0 +1,10 @@
<template>
<div class="flex items-center gap-4">
<USkeleton class="h-12 w-12 rounded-full" />
<div class="space-y-2">
<USkeleton class="h-4 w-[250px]" />
<USkeleton class="h-4 w-[200px]" />
</div>
</div>
</template>

View File

@@ -0,0 +1,109 @@
<script setup lang="ts">
const open = ref(false)
</script>
<template>
<div class="flex flex-col gap-2">
<USlideover title="First slideover">
<UButton color="white" label="Open with nested" />
<template #body>
<Placeholder class="h-full w-full" />
</template>
<template #footer>
<USlideover title="Second slideover">
<UButton label="Open second" />
</USlideover>
</template>
</USlideover>
<USlideover title="Slideover on left side" description="This slideover has `side: 'left'` prop." side="left">
<UButton label="Open on left" color="gray" />
<template #body>
<Placeholder class="h-full w-full" />
</template>
</USlideover>
<USlideover title="Slideover on top side" description="This slideover has `side: 'top'` prop." side="top">
<UButton label="Open on top" color="white" />
<template #body>
<Placeholder class="h-48 w-full" />
</template>
</USlideover>
<USlideover title="Slideover on bottom side" description="This slideover has `side: 'bottom'` prop." side="bottom">
<UButton label="Open on bottom" color="gray" />
<template #body>
<Placeholder class="h-48 w-full" />
</template>
</USlideover>
<USlideover v-model:open="open" title="Slideover with v-model" description="This can be useful to control the state of the slideover yourself.">
<template #body>
<Placeholder class="h-full w-full" />
</template>
</USlideover>
<UButton label="Open with v-model" color="white" @click="open = true" />
<USlideover title="Slideover without overlay" description="This slideover has `overlay: false` prop." :overlay="false">
<UButton label="Open without overlay" color="gray" />
<template #body>
<Placeholder class="h-full w-full" />
</template>
</USlideover>
<USlideover title="Slideover without modal & overlay" description="This slideover has `modal: false` and `overlay: false` to interact with outside content." :overlay="false" :modal="false">
<UButton label="Open without modal" color="white" />
<template #body>
<Placeholder class="h-full w-full" />
</template>
</USlideover>
<USlideover title="Slideover without transition" description="This slideover has `transition: false` prop." :transition="false">
<UButton label="Open without transition" color="gray" />
<template #body>
<Placeholder class="h-full w-full" />
</template>
</USlideover>
<USlideover title="Slideover without portal" description="This slideover has `portal: false` prop." :portal="false">
<UButton label="Open without portal" color="white" />
<template #body>
<Placeholder class="h-full w-full" />
</template>
</USlideover>
<USlideover title="Slideover prevent close" description="This slideover has `prevent-close: true` prop so it won't close when clicking outside." prevent-close>
<UButton label="Open unclosable" color="gray" />
<template #body>
<Placeholder class="h-full w-full" />
</template>
</USlideover>
<USlideover title="Slideover without close button" description="This slideover has `close: null` prop." :close="null">
<UButton label="Open without close button" color="white" />
<template #body>
<Placeholder class="h-full w-full" />
</template>
</USlideover>
<USlideover title="Slideover with custom close button" description="The `close` prop inherits from the Button props." :close="{ color: 'primary', variant: 'solid', size: 'xs' }" :ui="{ close: 'top-3.5 rounded-full' }">
<UButton label="Open with custom close button" color="gray" />
<template #body>
<Placeholder class="h-full w-full" />
</template>
</USlideover>
</div>
</template>

View File

@@ -0,0 +1,41 @@
<script setup lang="ts">
import theme from '#build/ui/switch'
const sizes = Object.keys(theme.variants.size)
const checked = ref(false)
</script>
<template>
<div class="flex flex-col gap-2">
<div>
<USwitch v-model:checked="checked" />
</div>
<div>
<USwitch v-model:checked="checked" disabled />
</div>
<div class="flex items-center gap-2 ml-[-64px]">
<USwitch v-for="size in sizes" :key="size" v-model:checked="checked" :size="(size as any)" />
</div>
<div class="flex items-center gap-2 ml-[-64px]">
<USwitch
v-for="size in sizes"
:key="size"
v-model:checked="checked"
:size="(size as any)"
unchecked-icon="i-heroicons-x-mark-20-solid"
checked-icon="i-heroicons-check-20-solid"
/>
</div>
<div class="flex items-center gap-2 ml-[-64px]">
<USwitch
v-for="size in sizes"
:key="size"
v-model:checked="checked"
:size="(size as any)"
unchecked-icon="i-heroicons-x-mark-20-solid"
checked-icon="i-heroicons-check-20-solid"
loading
/>
</div>
</div>
</template>

16
playground/pages/tabs.vue Normal file
View File

@@ -0,0 +1,16 @@
<script setup lang="ts">
const items = [{
label: 'Tab1',
content: 'This is the content shown for Tab1'
}, {
label: 'Tab2',
content: 'And, this is the content for Tab2'
}, {
label: 'Tab3',
content: 'Finally, this is the content for Tab3'
}]
</script>
<template>
<UTabs :items="items" />
</template>

View File

@@ -0,0 +1,36 @@
<script setup lang="ts">
import theme from '#build/ui/textarea'
const sizes = Object.keys(theme.variants.size)
</script>
<template>
<div class="flex flex-col items-center gap-4">
<div class="flex gap-4">
<UTextarea />
</div>
<div class="flex gap-4">
<UTextarea placeholder="Search..." autofocus />
<UTextarea placeholder="Search..." color="gray" />
<UTextarea placeholder="Search..." color="primary" />
<UTextarea placeholder="Search..." disabled />
</div>
<div class="flex items-center gap-4">
<UTextarea
v-for="size in sizes"
:key="size"
placeholder="Search..."
:size="(size as any)"
/>
</div>
<div class="flex gap-4">
<UTextarea autofocus />
<UTextarea autofocus :autofocus-delay="500" />
<UTextarea autoresize />
<UTextarea autoresize :maxrows="5" :rows="1" />
</div>
<div class="flex gap-4">
<UTextarea variant="none" placeholder="You can't see me" />
</div>
</div>
</template>

View File

@@ -0,0 +1,21 @@
<template>
<div class="flex flex-col">
<UTooltip text="Top" :shortcuts="['⌘', 'T']" :content="{ side: 'top' }" arrow>
<UAvatar text="T" />
</UTooltip>
<div class="flex items-center gap-2 ml-[-20px]">
<UTooltip text="Left" :shortcuts="['⌘', 'L']" :content="{ side: 'left' }" arrow>
<UAvatar text="L" />
</UTooltip>
<UTooltip text="Right" :shortcuts="['⌘', 'R']" :content="{ side: 'right' }" arrow>
<UAvatar text="R" />
</UTooltip>
</div>
<UTooltip text="Bottom" :shortcuts="['⌘', 'B']" arrow>
<UAvatar text="B" />
</UTooltip>
</div>
</template>

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB