docs: improve with examples

This commit is contained in:
Benjamin Canac
2023-06-16 17:16:41 +02:00
parent 1b03b8a531
commit c458f388bb
28 changed files with 719 additions and 392 deletions

View File

@@ -0,0 +1,46 @@
<template>
<div class="p-2">
<div class="grid grid-cols-5 gap-px">
<ColorPickerButton v-for="color in primaryColors" :key="color.value" :color="color" :selected="primary" @select="primary = color" />
</div>
<hr class="border-gray-200 dark:border-gray-800 my-2">
<div class="grid grid-cols-5 gap-px">
<ColorPickerButton v-for="color in grayColors" :key="color.value" :color="color" :selected="gray" @select="gray = color" />
</div>
</div>
</template>
<script setup lang="ts">
import colors from '#tailwind-config/theme/colors'
const appConfig = useAppConfig()
const colorMode = useColorMode()
// Computed
const primaryColors = computed(() => useWithout(appConfig.ui.colors, 'primary').map(color => ({ value: color, text: color, hex: colors[color][colorMode.value === 'dark' ? 400 : 500] })))
const primary = computed({
get () {
return primaryColors.value.find(option => option.value === appConfig.ui.primary)
},
set (option) {
appConfig.ui.primary = option.value
window.localStorage.setItem('nuxt-ui-primary', appConfig.ui.primary)
}
})
const grayColors = computed(() => ['slate', 'cool', 'zinc', 'neutral', 'stone'].map(color => ({ value: color, text: color, hex: colors[color][colorMode.value === 'dark' ? 400 : 500] })))
const gray = computed({
get () {
return grayColors.value.find(option => option.value === appConfig.ui.gray)
},
set (option) {
appConfig.ui.gray = option.value
window.localStorage.setItem('nuxt-ui-gray', appConfig.ui.gray)
}
})
</script>

View File

@@ -0,0 +1,25 @@
<template>
<UTooltip :text="color.value" class="capitalize" :open-delay="500">
<UButton
color="gray"
square
:ui="{
color: {
gray: {
solid: 'bg-gray-100 dark:bg-gray-800',
ghost: 'hover:bg-gray-50 dark:hover:bg-gray-800/50'
}
}
}"
:variant="color.value === selected.value ? 'solid' : 'ghost'"
@click.stop.prevent="$emit('select')"
>
<span class="inline-block w-3 h-3 rounded-full" :style="{ backgroundColor: color.hex }" />
</UButton>
</UTooltip>
</template>
<script setup lang="ts">
defineProps<{ color: { value: string, hex: string }, selected: { value: string} }>()
defineEmits(['select'])
</script>

View File

@@ -0,0 +1,76 @@
<script setup lang="ts">
import { DatePicker as VCalendarDatePicker } from 'v-calendar'
import 'v-calendar/dist/style.css'
const props = defineProps({
modelValue: {
type: Date,
default: null
}
})
const emit = defineEmits(['update:model-value', 'close'])
const colorMode = useColorMode()
const isDark = computed(() => colorMode.value === 'dark')
const date = computed({
get: () => props.modelValue,
set: (value) => {
emit('update:model-value', value)
emit('close')
}
})
const attrs = [{
key: 'today',
highlight: {
color: 'blue',
fillMode: 'outline',
class: '!bg-gray-100 dark:!bg-gray-800'
},
dates: new Date()
}]
</script>
<template>
<VCalendarDatePicker
v-model="date"
transparent
borderless
:attributes="attrs"
:is-dark="isDark"
title-position="left"
trim-weeks
:first-day-of-week="2"
/>
</template>
<style>
:root {
--vc-gray-50: rgb(var(--color-gray-50));
--vc-gray-100: rgb(var(--color-gray-100));
--vc-gray-200: rgb(var(--color-gray-200));
--vc-gray-300: rgb(var(--color-gray-300));
--vc-gray-400: rgb(var(--color-gray-400));
--vc-gray-500: rgb(var(--color-gray-500));
--vc-gray-600: rgb(var(--color-gray-600));
--vc-gray-700: rgb(var(--color-gray-700));
--vc-gray-800: rgb(var(--color-gray-800));
--vc-gray-900: rgb(var(--color-gray-900));
}
.vc-blue {
--vc-accent-50: rgb(var(--color-primary-50));
--vc-accent-100: rgb(var(--color-primary-100));
--vc-accent-200: rgb(var(--color-primary-200));
--vc-accent-300: rgb(var(--color-primary-300));
--vc-accent-400: rgb(var(--color-primary-400));
--vc-accent-500: rgb(var(--color-primary-500));
--vc-accent-600: rgb(var(--color-primary-600));
--vc-accent-700: rgb(var(--color-primary-700));
--vc-accent-800: rgb(var(--color-primary-800));
--vc-accent-900: rgb(var(--color-primary-900));
}
</style>

View File

@@ -1,86 +1,16 @@
<template>
<header class="sticky top-0 z-50 w-full backdrop-blur flex-none border-b border-gray-900/10 dark:border-gray-50/[0.06] bg-white/75 dark:bg-gray-900/75">
<header class="sticky top-0 z-50 w-full backdrop-blur flex-none border-b border-gray-200 dark:border-gray-800 bg-white/75 dark:bg-gray-900/75">
<UContainer>
<div class="flex items-center justify-between h-16">
<div class="flex items-center gap-3">
<NuxtLink to="/getting-started" class="flex items-end gap-1.5 font-bold text-xl text-gray-900 dark:text-white">
<Logo class="w-8 h-8 text-primary-500 dark:text-primary-400" />
NuxtLabs<span class="text-primary-500 dark:text-primary-400">UI</span>
</NuxtLink>
</div>
<div class="flex items-center -mr-1.5 gap-1.5">
<div class="hidden lg:block">
<ThemeSelect />
</div>
<UButton
color="gray"
variant="ghost"
class="lg:hidden"
icon="i-heroicons-magnifying-glass-20-solid"
@click="openDocsSearch"
/>
<ClientOnly>
<UButton
:icon="isDark ? 'i-heroicons-moon' : 'i-heroicons-sun'"
color="gray"
variant="ghost"
aria-label="Theme"
@click="isDark = !isDark"
/>
<template #fallback>
<div class="w-8 h-8" />
</template>
</ClientOnly>
<UButton
to="https://github.com/nuxtlabs/ui"
target="_blank"
color="gray"
variant="ghost"
icon="i-simple-icons-github"
/>
<UButton
color="gray"
variant="ghost"
class="lg:hidden"
icon="i-heroicons-bars-3-20-solid"
@click="isDialogOpen = true"
/>
</div>
</div>
<HeaderLinks v-model="isDialogOpen" :links="links" />
</UContainer>
<TransitionRoot :show="isDialogOpen" as="template">
<Dialog as="div" @close="isDialogOpen = false">
<DialogPanel class="fixed inset-0 z-50 overflow-y-auto bg-white dark:bg-gray-900 lg:hidden">
<div class="px-4 sm:px-6 sticky top-0 border-b border-gray-900/10 dark:border-gray-50/[0.06] bg-white/75 dark:bg-gray-900/75 backdrop-blur z-10">
<div class="flex items-center justify-between h-16">
<div class="flex items-center gap-3">
<NuxtLink to="/getting-started" class="flex items-end gap-1.5 font-bold text-xl text-gray-900 dark:text-white">
<Logo class="w-8 h-8 text-primary-500 dark:text-primary-400" />
NuxtLabs<span class="text-primary-500 dark:text-primary-400">UI</span>
</NuxtLink>
</div>
<div class="flex -mr-1.5">
<UButton
color="gray"
variant="ghost"
icon="i-heroicons-x-mark-20-solid"
@click="isDialogOpen = false"
/>
</div>
</div>
<div class="px-4 sm:px-6 sticky top-0 border-b border-gray-200 dark:border-gray-800 bg-white/75 dark:bg-gray-900/75 backdrop-blur z-10">
<HeaderLinks v-model="isDialogOpen" :links="links" />
</div>
<div class="px-4 sm:px-6 py-4 sm:py-6">
<ThemeSelect class="mb-4 sm:mb-6 w-full" />
<DocsAsideLinks @click="isDialogOpen = false" />
</div>
</DialogPanel>
@@ -92,25 +22,11 @@
<script setup lang="ts">
import { Dialog, DialogPanel, TransitionRoot } from '@headlessui/vue'
const { isSearchModalOpen } = useDocs()
const colorMode = useColorMode()
const isDialogOpen = ref(false)
const isDark = computed({
get () {
return colorMode.value === 'dark'
},
set () {
colorMode.preference = colorMode.value === 'dark' ? 'light' : 'dark'
}
})
function openDocsSearch () {
isDialogOpen.value = false
setTimeout(() => {
isSearchModalOpen.value = true
}, 100)
}
const links = [
{ label: 'Documentation', to: '/getting-started' },
{ label: 'Components', to: '/elements/avatar' },
{ label: 'Examples', to: '/examples' }
]
</script>

View File

@@ -0,0 +1,64 @@
<template>
<div class="flex items-center justify-between gap-3 h-16">
<div class="flex items-center gap-6">
<div class="flex items-center gap-3">
<NuxtLink to="/getting-started" class="flex items-end gap-1.5 font-bold text-xl text-gray-900 dark:text-white">
<Logo class="w-8 h-8 text-primary-500 dark:text-primary-400" />
<span class="hidden sm:block">NuxtLabs</span><span class="sm:text-primary-500 dark:sm:text-primary-400">UI</span>
</NuxtLink>
</div>
</div>
<div class="flex items-center justify-end flex-1 -mr-1.5 gap-3">
<DocsSearchButton class="ml-1.5 flex-1 lg:flex-none lg:w-48" />
<div class="flex items-center lg:gap-1.5">
<UPopover>
<template #default="{ open }">
<UButton color="gray" variant="ghost" square :class="[open && 'bg-gray-50 dark:bg-gray-800']">
<UIcon name="i-heroicons-swatch-20-solid" class="w-5 h-5 text-primary-500 dark:text-primary-400" />
</UButton>
</template>
<template #panel>
<ColorPicker />
</template>
</UPopover>
<ColorModeButton />
<UButton
to="https://twitter.com/nuxtlabs"
target="_blank"
color="gray"
variant="ghost"
icon="i-simple-icons-twitter"
/>
<UButton
to="https://github.com/nuxtlabs/ui"
target="_blank"
color="gray"
variant="ghost"
icon="i-simple-icons-github"
/>
<UButton
color="gray"
variant="ghost"
class="lg:hidden"
:icon="isDialogOpen ? 'i-heroicons-x-mark-20-solid' : 'i-heroicons-bars-3-20-solid'"
@click="isDialogOpen = !isDialogOpen"
/>
</div>
</div>
</div>
</template>
<script setup lang="ts">
const props = defineProps<{ modelValue: boolean, links: { to: string, label: string }[] }>()
const emit = defineEmits(['update:modelValue'])
const isDialogOpen = useVModel(props, 'modelValue', emit)
</script>

View File

@@ -1,128 +0,0 @@
<template>
<ClientOnly>
<div class="inline-flex shadow-sm rounded-md">
<USelectMenu
v-model="primary"
name="primary"
class="!rounded-r-none !shadow-none focus:z-[1]"
color="gray"
:ui="{ width: 'w-[194px]' }"
:popper="{ placement: 'bottom-start' }"
:options="primaryOptions"
>
<template #label>
<span class="flex-shrink-0 h-3 w-3 rounded-full" :style="{ backgroundColor: `${primary.hex}`}" />
{{ primary.text }}
</template>
<template #option="{ option }">
<span class="flex-shrink-0 h-3 w-3 rounded-full" :style="{ backgroundColor: `${option.hex}`}" />
{{ option.text }}
</template>
</USelectMenu>
<USelectMenu
v-model="gray"
name="gray"
class="!rounded-l-none !shadow-none"
color="gray"
:ui="{ width: 'w-[194px]', wrapper: '-ml-px' }"
:popper="{ placement: 'bottom-end' }"
:options="grayOptions"
>
<template #label>
<span class="flex-shrink-0 h-3 w-3 rounded-full" :style="{ backgroundColor: `${gray.hex}`}" />
{{ gray.text }}
</template>
<template #option="{ option }">
<span class="flex-shrink-0 h-3 w-3 rounded-full" :style="{ backgroundColor: `${option.hex}`}" />
{{ option.text }}
</template>
</USelectMenu>
</div>
</ClientOnly>
</template>
<script setup lang="ts">
import colors from '#tailwind-config/theme/colors'
const appConfig = useAppConfig()
const colorMode = useColorMode()
const primaryCookie = useCookie('primary', { path: '/', default: () => appConfig.ui.primary })
const grayCookie = useCookie('gray', { path: '/', default: () => appConfig.ui.gray })
watch(primaryCookie, (primary) => {
appConfig.ui.primary = primary
}, { immediate: true })
watch(grayCookie, (gray) => {
appConfig.ui.gray = gray
}, { immediate: true })
// Computed
const primaryOptions = computed(() => useWithout(appConfig.ui.colors, 'primary').map(color => ({ value: color, text: color, hex: colors[color][colorMode.value === 'dark' ? 400 : 500] })))
const primary = computed({
get () {
return primaryOptions.value.find(option => option.value === primaryCookie.value) || primaryOptions.value.find(option => option.value === 'green')
},
set (option) {
primaryCookie.value = option.value
}
})
const grayOptions = computed(() => ['slate', 'cool', 'zinc', 'neutral', 'stone'].map(color => ({ value: color, text: color, hex: colors[color][colorMode.value === 'dark' ? 400 : 500] })))
const gray = computed({
get () {
return grayOptions.value.find(option => option.value === grayCookie.value) || grayOptions.value.find(option => option.value === 'cool')
},
set (option) {
grayCookie.value = option.value
}
})
// Hack for SSG
const hexToRgb = (hex) => {
// Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF")
const shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i
hex = hex.replace(shorthandRegex, function (_, r, g, b) {
return r + r + g + g + b + b
})
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex)
return result
? `${parseInt(result[1], 16)} ${parseInt(result[2], 16)} ${parseInt(result[3], 16)}`
: null
}
const root = computed(() => {
return `:root {
${Object.entries(colors[primary.value.value] || colors.green).map(([key, value]) => `--color-primary-${key}: ${hexToRgb(value)};`).join('\n')}
${Object.entries(colors[gray.value.value] || colors.cool).map(([key, value]) => `--color-gray-${key}: ${hexToRgb(value)};`).join('\n')}
}`
})
if (process.client) {
watch(root, () => {
window.localStorage.setItem('nuxt-ui-root', root.value)
}, { immediate: true })
}
if (process.server) {
useHead({
script: [
{
innerHTML: `
if (localStorage.getItem('nuxt-ui-root')) {
document.querySelector('style#nuxt-ui-colors').innerHTML = localStorage.getItem('nuxt-ui-root')
}`.replace(/\s+/g, ' '),
type: 'text/javascript',
tagPriority: -1
}
]
})
}
</script>

View File

@@ -0,0 +1,28 @@
<template>
<ClientOnly>
<UButton
:icon="isDark ? 'i-heroicons-moon-20-solid' : 'i-heroicons-sun-20-solid'"
color="gray"
variant="ghost"
aria-label="Theme"
@click="isDark = !isDark"
/>
<template #fallback>
<div class="w-8 h-8" />
</template>
</ClientOnly>
</template>
<script setup lang="ts">
const colorMode = useColorMode()
const isDark = computed({
get () {
return colorMode.value === 'dark'
},
set () {
colorMode.preference = colorMode.value === 'dark' ? 'light' : 'dark'
}
})
</script>

View File

@@ -0,0 +1,16 @@
<script setup>
const date = ref(new Date())
const label = computed(() => date.value.toLocaleDateString('en-us', { weekday: 'long', year: 'numeric', month: 'short', day: 'numeric' })
)
</script>
<template>
<UPopover :popper="{ placement: 'bottom-start' }">
<UButton icon="i-heroicons-calendar-days-20-solid" :label="label" />
<template #panel="{ close }">
<DatePicker v-model="date" @close="close" />
</template>
</UPopover>
</template>

View File

@@ -0,0 +1,15 @@
<script setup lang="ts">
defineProps<{ id: string }>()
</script>
<template>
<h3 :id="id" class="scroll-mt-[145px] lg:scroll-mt-[96px]">
<NuxtLink :href="`#${id}`" class="group">
<div class="-ml-6 pr-2 py-2 inline-flex opacity-0 group-hover:opacity-100 transition-opacity absolute">
<UIcon name="i-heroicons-hashtag-20-solid" class="w-4 h-4 text-primary-500 dark:text-primary-400" />
</div>
<slot />
</NuxtLink>
</h3>
</template>

View File

@@ -1,13 +1,22 @@
<script setup>
const links = [{
label: 'Introduction',
to: '/getting-started'
}, {
label: 'Installation',
to: '/getting-started/installation'
}, {
label: 'Vertical Navigation',
to: '/navigation/vertical-navigation'
label: 'Theming',
to: '/getting-started/theming'
}, {
label: 'Command Palette',
to: '/navigation/command-palette'
label: 'Shortcuts',
to: '/getting-started/shortcuts'
}, {
label: 'Examples',
to: '/getting-started/examples'
}, {
label: 'Roadmap',
to: '/getting-started/roadmap'
}]
</script>

View File

@@ -1,32 +1,15 @@
<template>
<aside class="hidden pb-8 overflow-y-auto lg:block lg:self-start lg:top-16 lg:max-h-[calc(100vh-64px)] lg:sticky lg:pr-8 lg:pl-[2px]">
<aside class="hidden py-8 overflow-y-auto lg:block lg:self-start lg:top-16 lg:max-h-[calc(100vh-65px)] lg:sticky lg:pr-8 lg:pl-[2px]">
<div class="relative">
<div class="sticky top-0 pointer-events-none z-[1]">
<!-- <div class="sticky top-0 pointer-events-none z-[1]">
<div class="h-8 bg-white dark:bg-gray-900" />
<div class="bg-white dark:bg-gray-900 relative pointer-events-auto">
<UButton
icon="i-heroicons-magnifying-glass-20-solid"
class="w-full"
color="gray"
@click="isSearchModalOpen = true"
>
Search
<div class="hidden lg:flex items-center gap-0.5 ml-auto -my-1">
<UKbd>{{ metaSymbol }}</UKbd>
<UKbd>K</UKbd>
</div>
</UButton>
<DocsSearchButton class="w-full" />
</div>
<div class="h-8 bg-gradient-to-b from-white dark:from-gray-900" />
</div>
</div> -->
<DocsAsideLinks />
</div>
</aside>
</template>
<script setup lang="ts">
const { isSearchModalOpen } = useDocs()
const { metaSymbol } = useShortcuts()
</script>

View File

@@ -1,9 +1,9 @@
<template>
<div class="space-y-8">
<div v-for="(group, index) in navigation" :key="index" class="space-y-3">
<div class="text-sm font-semibold text-gray-900 dark:text-gray-200">
<span class="truncate">{{ group.title }}</span>
</div>
<p class="text-sm font-semibold text-gray-900 dark:text-gray-200 truncate leading-6">
{{ group.title }}
</p>
<UVerticalNavigation
:links="mapContentLinks(group.children)"

View File

@@ -1,10 +1,14 @@
<template>
<footer class="flex items-center justify-end gap-1.5">
<footer class="flex items-center justify-between gap-1.5">
<div class="flex items-baseline gap-1.5 text-sm text-center text-gray-500 dark:text-gray-400">
Made by
<NuxtLink to="https://nuxtlabs.com" aria-label="NuxtLabs">
<LogoLabs class="text-primary-500 w-14 h-auto dark:text-primary-400" />
</NuxtLink>
</div>
<NuxtLink to="https://github.com/nuxtlabs/ui/releases" target="_blank">
<UBadge label="v2.4.0" />
</NuxtLink>
</footer>
</template>

View File

@@ -26,7 +26,7 @@
/>
</div>
</div>
<p v-if="page.description" class="mt-4 text-lg">
<p v-if="page.description" class="mt-4 text-lg text-gray-500 dark:text-gray-400">
{{ page.description }}
</p>
</header>

View File

@@ -1,5 +1,5 @@
<template>
<NuxtLink :to="to" class="block px-5 py-8 border not-prose rounded-lg border-gray-200 dark:border-gray-800 hover:bg-gray-50 dark:hover:bg-gray-800/25 group">
<NuxtLink :to="to" class="block px-5 py-8 border not-prose rounded-lg border-gray-200 dark:border-gray-800 hover:bg-gray-50 dark:hover:bg-gray-800/50 group">
<div v-if="icon" class="inline-flex items-center rounded-full p-1.5 bg-gray-50 dark:bg-gray-800 group-hover:bg-primary-50 dark:group-hover:bg-primary-400/10 ring-1 ring-gray-300 dark:ring-gray-700 mb-4 group-hover:ring-primary-500/50 dark:group-hover:ring-primary-400/50">
<UIcon :name="icon" class="w-5 h-5 text-gray-900 dark:text-gray-100 group-hover:text-primary-500 dark:group-hover:text-primary-400" />
</div>

View File

@@ -12,6 +12,8 @@
ref="commandPaletteRef"
:groups="groups"
command-attribute="title"
:close-button="{ icon: 'i-heroicons-x-mark-20-solid', color: 'gray', variant: 'ghost', size: 'sm', class: '-mr-1.5' }"
:ui="{ input: { height: 'h-16 sm:h-12', icon: { size: 'h-5 w-5', padding: 'pl-11' } } }"
:fuse="{
fuseOptions: { ignoreLocation: true, includeMatches: true, threshold: 0, keys: ['title', 'description', 'children.children.value', 'children.children.children.value'] },
resultLimit: 10

View File

@@ -0,0 +1,33 @@
<template>
<UButton
color="white"
variant="outline"
icon="i-heroicons-magnifying-glass-20-solid"
label="Search..."
truncate
:ui="{
color: {
white: {
outline: 'ring-1 ring-inset ring-gray-200 dark:ring-gray-800 hover:ring-gray-300 dark:hover:ring-gray-700 hover:bg-gray-50 dark:hover:bg-gray-800/50 text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-200 focus-visible:ring-2 focus-visible:ring-primary-500 dark:focus-visible:ring-primary-400'
}
}
}"
@click="isSearchModalOpen = true"
>
<template #trailing>
<div class="hidden lg:flex items-center gap-0.5 ml-auto -my-1 flex-shrink-0">
<UKbd class="!text-inherit">
{{ metaSymbol }}
</UKbd>
<UKbd class="!text-inherit">
K
</UKbd>
</div>
</template>
</UButton>
</template>
<script setup lang="ts">
const { isSearchModalOpen } = useDocs()
const { metaSymbol } = useShortcuts()
</script>