mirror of
https://github.com/ArthurDanjou/ui.git
synced 2026-01-14 12:14:41 +01:00
docs: migrate to @nuxthq/ui-kit (#405)
Co-authored-by: Sébastien Chopin <seb@nuxt.com>
This commit is contained in:
52
docs/app.vue
52
docs/app.vue
@@ -1,17 +1,41 @@
|
||||
<template>
|
||||
<div>
|
||||
<Header />
|
||||
<UHeader>
|
||||
<template #left>
|
||||
<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" />
|
||||
|
||||
<UContainer class="grid lg:grid-cols-10 lg:gap-8">
|
||||
<DocsAside class="lg:col-span-2" />
|
||||
<span class="hidden sm:block">NuxtLabs</span><span class="sm:text-primary-500 dark:sm:text-primary-400">UI</span>
|
||||
</NuxtLink>
|
||||
</template>
|
||||
|
||||
<div class="lg:col-span-8 min-h-0 flex flex-col">
|
||||
<template #center>
|
||||
<UDocsSearchButton class="ml-1.5 flg:w-64 xl:w-96" />
|
||||
</template>
|
||||
|
||||
<template #right>
|
||||
<ColorPicker />
|
||||
|
||||
<UColorModeButton />
|
||||
|
||||
<USocialButton to="https://twitter.com/nuxtlabs" icon="i-simple-icons-twitter" class="hidden lg:inline-flex" />
|
||||
<USocialButton to="https://github.com/nuxtlabs/ui" icon="i-simple-icons-github" class="hidden lg:inline-flex" />
|
||||
</template>
|
||||
|
||||
<template #links>
|
||||
<UDocsAsideAnchors :links="anchors" />
|
||||
<UDocsAsideLinks :links="navigation" />
|
||||
</template>
|
||||
</UHeader>
|
||||
|
||||
<UContainer>
|
||||
<UDocsLayout :links="navigation" :anchors="anchors">
|
||||
<NuxtPage />
|
||||
</div>
|
||||
</UDocsLayout>
|
||||
</UContainer>
|
||||
|
||||
<ClientOnly>
|
||||
<DocsSearch />
|
||||
<UDocsSearch :files="files" :links="navigation" />
|
||||
</ClientOnly>
|
||||
|
||||
<UNotifications />
|
||||
@@ -22,9 +46,24 @@
|
||||
const colorMode = useColorMode()
|
||||
|
||||
const { data: navigation } = await useAsyncData('navigation', () => fetchContentNavigation())
|
||||
const { data: files } = await useLazyAsyncData('files', () => queryContent().where({ _type: 'markdown', navigation: { $ne: false } }).find(), { default: () => [] })
|
||||
|
||||
provide('navigation', navigation)
|
||||
|
||||
const anchors = [{
|
||||
label: 'Documentation',
|
||||
icon: 'i-heroicons-book-open-solid',
|
||||
to: '/getting-started'
|
||||
}, {
|
||||
label: 'Playground',
|
||||
icon: 'i-simple-icons-stackblitz',
|
||||
to: 'https://stackblitz.com/edit/nuxtlabs-ui?file=app.config.ts,app.vue'
|
||||
}, {
|
||||
label: 'Releases',
|
||||
icon: 'i-heroicons-rocket-launch-solid',
|
||||
to: 'https://github.com/nuxtlabs/ui/releases'
|
||||
}]
|
||||
|
||||
// Computed
|
||||
|
||||
const color = computed(() => colorMode.value === 'dark' ? '#18181b' : 'white')
|
||||
@@ -38,7 +77,6 @@ useHead({
|
||||
{ key: 'theme-color', name: 'theme-color', content: color }
|
||||
],
|
||||
link: [
|
||||
{ rel: 'stylesheet', href: 'https://rsms.me/inter/inter.css' },
|
||||
{ rel: 'icon', type: 'image/svg+xml', href: '/icon.svg' }
|
||||
],
|
||||
htmlAttrs: {
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
import type { RouterConfig } from '@nuxt/schema'
|
||||
|
||||
function findHashPosition (hash): { el: any, behavior: ScrollBehavior, top: number } {
|
||||
const el = document.querySelector(hash)
|
||||
// vue-router does not incorporate scroll-margin-top on its own.
|
||||
if (el) {
|
||||
const top = parseFloat(getComputedStyle(el).scrollMarginTop)
|
||||
|
||||
return {
|
||||
el: hash,
|
||||
behavior: 'smooth',
|
||||
top
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// https://router.vuejs.org/api/#routeroptions
|
||||
export default <RouterConfig>{
|
||||
scrollBehavior (to, from, savedPosition) {
|
||||
const nuxtApp = useNuxtApp()
|
||||
|
||||
// If history back
|
||||
if (savedPosition) {
|
||||
// Handle Suspense resolution
|
||||
return new Promise((resolve) => {
|
||||
nuxtApp.hooks.hookOnce('page:finish', () => {
|
||||
setTimeout(() => resolve(savedPosition), 50)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// Scroll to heading on click
|
||||
if (to.hash) {
|
||||
return new Promise((resolve) => {
|
||||
if (to.path === from.path) {
|
||||
setTimeout(() => resolve(findHashPosition(to.hash)), 50)
|
||||
} else {
|
||||
nuxtApp.hooks.hookOnce('page:finish', () => {
|
||||
setTimeout(() => resolve(findHashPosition(to.hash)), 50)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Scroll to top of window
|
||||
return { top: 0 }
|
||||
}
|
||||
}
|
||||
23
docs/components/Footer.vue
Normal file
23
docs/components/Footer.vue
Normal file
@@ -0,0 +1,23 @@
|
||||
<template>
|
||||
<footer class="flex items-center gap-1.5 mt-12">
|
||||
<div class="flex-1 flex items-baseline gap-1.5 text-sm text-gray-600 dark:text-gray-300 leading-6">
|
||||
Made by
|
||||
<NuxtLink to="https://nuxtlabs.com" aria-label="NuxtLabs">
|
||||
<LogoLabs class="text-gray-900 dark:text-white w-14 h-auto" />
|
||||
</NuxtLink>
|
||||
</div>
|
||||
|
||||
<NuxtLink :to="`https://github.com/nuxtlabs/ui/releases/tag/v${config.version}`" target="_blank" class="inline-flex">
|
||||
<UBadge :label="`v${config.version}`" />
|
||||
</NuxtLink>
|
||||
|
||||
<div class="flex-1 flex items-center justify-end gap-1.5 -my-1 lg:hidden">
|
||||
<USocialButton to="https://twitter.com/nuxtlabs" icon="i-simple-icons-twitter" />
|
||||
<USocialButton to="https://github.com/nuxtlabs/ui" icon="i-simple-icons-github" />
|
||||
</div>
|
||||
</footer>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const config = useRuntimeConfig().public
|
||||
</script>
|
||||
@@ -1,32 +0,0 @@
|
||||
<template>
|
||||
<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>
|
||||
<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-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">
|
||||
<DocsAsideLinks @click="isDialogOpen = false" />
|
||||
</div>
|
||||
</DialogPanel>
|
||||
</Dialog>
|
||||
</TransitionRoot>
|
||||
</header>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Dialog, DialogPanel, TransitionRoot } from '@headlessui/vue'
|
||||
|
||||
const isDialogOpen = ref(false)
|
||||
|
||||
const links = [
|
||||
{ label: 'Documentation', to: '/getting-started' },
|
||||
{ label: 'Components', to: '/elements/avatar' },
|
||||
{ label: 'Examples', to: '/examples' }
|
||||
]
|
||||
</script>
|
||||
@@ -1,66 +0,0 @@
|
||||
<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"
|
||||
class="hidden lg:inline-flex"
|
||||
icon="i-simple-icons-twitter"
|
||||
/>
|
||||
|
||||
<UButton
|
||||
to="https://github.com/nuxtlabs/ui"
|
||||
target="_blank"
|
||||
color="gray"
|
||||
variant="ghost"
|
||||
class="hidden lg:inline-flex"
|
||||
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>
|
||||
@@ -1,15 +1,25 @@
|
||||
<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>
|
||||
<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>
|
||||
|
||||
<hr class="border-gray-200 dark:border-gray-800 my-2">
|
||||
<template #panel>
|
||||
<div class="p-2">
|
||||
<div class="grid grid-cols-5 gap-px">
|
||||
<ColorPickerPill v-for="color in primaryColors" :key="color.value" :color="color" :selected="primary" @select="primary = color" />
|
||||
</div>
|
||||
|
||||
<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>
|
||||
<hr class="border-gray-200 dark:border-gray-800 my-2">
|
||||
|
||||
<div class="grid grid-cols-5 gap-px">
|
||||
<ColorPickerPill v-for="color in grayColors" :key="color.value" :color="color" :selected="gray" @select="gray = color" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</UPopover>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
@@ -1,33 +0,0 @@
|
||||
<template>
|
||||
<component
|
||||
:is="to ? NuxtLink : 'div'"
|
||||
:to="to"
|
||||
class="block pl-4 pr-6 py-3 rounded-md !border !border-gray-200 dark:!border-gray-700 bg-gray-50 dark:bg-gray-800 text-gray-700 dark:text-gray-300 text-sm leading-6 my-5 last:mb-0 font-normal group relative prose-code:bg-white dark:prose-code:bg-gray-900"
|
||||
:class="[to ? 'hover:!border-primary-500 dark:hover:!border-primary-400 hover:text-primary-500 dark:hover:text-primary-400 border-dashed hover:text-gray-800 dark:hover:text-gray-200' : '']"
|
||||
>
|
||||
<UIcon v-if="!!to" name="i-heroicons-link-20-solid" class="w-3 h-3 absolute right-2 top-2 text-gray-400 dark:text-gray-500 group-hover:text-primary-500 dark:group-hover:text-primary-400" />
|
||||
|
||||
<UIcon v-if="icon" :name="icon" class="w-4 h-4 mr-2 inline-flex items-center align-text-top" :class="color" />
|
||||
|
||||
<ContentSlot :use="$slots.default" unwrap="p" />
|
||||
</component>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const NuxtLink = resolveComponent('NuxtLink')
|
||||
|
||||
defineProps({
|
||||
icon: {
|
||||
type: String,
|
||||
default: null
|
||||
},
|
||||
color: {
|
||||
type: String,
|
||||
default: 'text-primary-500 dark:text-primary-400'
|
||||
},
|
||||
to: {
|
||||
type: String,
|
||||
default: null
|
||||
}
|
||||
})
|
||||
</script>
|
||||
@@ -1,18 +0,0 @@
|
||||
<template>
|
||||
<UKbd class="!my-0 align-text-top">
|
||||
{{ shortcut }}
|
||||
</UKbd>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const props = defineProps({
|
||||
value: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
})
|
||||
|
||||
const { metaSymbol } = useShortcuts()
|
||||
|
||||
const shortcut = computed(() => props.value === 'meta' ? metaSymbol.value : props.value)
|
||||
</script>
|
||||
@@ -1,53 +0,0 @@
|
||||
<template>
|
||||
<div :selected-index="selectedIndex" @change="changeTab">
|
||||
<div class="flex border border-gray-200 dark:border-gray-700 border-b-0 rounded-t-md overflow-hidden -mb-px">
|
||||
<div
|
||||
v-for="(tab, index) in tabs"
|
||||
:key="index"
|
||||
as="template"
|
||||
@click="selectedIndex = index"
|
||||
>
|
||||
<button
|
||||
class="px-4 py-2 focus:outline-none text-sm border-r border-r-gray-200 dark:border-r-gray-700 transition-colors"
|
||||
tabindex="-1"
|
||||
:class="[selectedIndex === index ? 'font-medium text-primary-500 dark:text-primary-400 bg-gray-50 dark:bg-gray-800' : 'hover:bg-gray-50 dark:hover:bg-gray-800']"
|
||||
>
|
||||
{{ tab.label }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="[&>div>pre]:!rounded-t-none">
|
||||
<component :is="selectedTab.component" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const slots = useSlots()
|
||||
|
||||
const selectedIndex = ref(0)
|
||||
|
||||
// Computed
|
||||
|
||||
const tabs = computed(() => slots.default?.().map((slot, index) => {
|
||||
return {
|
||||
label: slot.props?.filename || slot.props?.label || `${index}`,
|
||||
component: slot
|
||||
}
|
||||
}) || [])
|
||||
|
||||
const selectedTab = computed(() => tabs.value.find((_, index) => index === selectedIndex.value))
|
||||
|
||||
// Methods
|
||||
|
||||
function changeTab (index) {
|
||||
selectedIndex.value = index
|
||||
}
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
export default {
|
||||
inheritAttrs: false
|
||||
}
|
||||
</script>
|
||||
@@ -1,71 +0,0 @@
|
||||
<script lang="ts">
|
||||
import { defineComponent } from '#imports'
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
code: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
language: {
|
||||
type: String,
|
||||
default: null
|
||||
},
|
||||
filename: {
|
||||
type: String,
|
||||
default: null
|
||||
},
|
||||
highlights: {
|
||||
type: Array as () => number[],
|
||||
default: () => []
|
||||
},
|
||||
meta: {
|
||||
type: String,
|
||||
default: null
|
||||
}
|
||||
},
|
||||
setup (props) {
|
||||
const clipboard = useCopyToClipboard({ timeout: 2000 })
|
||||
const icon = ref('i-heroicons-clipboard-document')
|
||||
|
||||
function copy () {
|
||||
clipboard.copy(props.code, { title: 'Copied to clipboard!' })
|
||||
|
||||
icon.value = 'i-heroicons-clipboard-document-check'
|
||||
|
||||
setTimeout(() => {
|
||||
icon.value = 'i-heroicons-clipboard-document'
|
||||
}, 2000)
|
||||
}
|
||||
|
||||
return {
|
||||
icon,
|
||||
copy
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="group relative" :class="`language-${language}`">
|
||||
<UButton
|
||||
:icon="icon"
|
||||
variant="solid"
|
||||
class="absolute right-3 top-3 opacity-0 group-hover:opacity-100 transition-opacity z-[1]"
|
||||
size="xs"
|
||||
tabindex="-1"
|
||||
@click="copy"
|
||||
/>
|
||||
|
||||
<span v-if="filename" class="text-gray-400 dark:text-gray-500 absolute right-3 bottom-3 text-sm group-hover:opacity-0 transition-opacity">{{ filename }}</span>
|
||||
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
pre code .line {
|
||||
display: block;
|
||||
min-height: 1rem;
|
||||
}
|
||||
</style>
|
||||
@@ -1,15 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
defineProps<{ id: string }>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<h2 :id="id" class="scroll-mt-[161px] lg:scroll-mt-[112px]">
|
||||
<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>
|
||||
</h2>
|
||||
</template>
|
||||
@@ -1,15 +0,0 @@
|
||||
<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>
|
||||
@@ -1,15 +0,0 @@
|
||||
<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>
|
||||
@@ -1,15 +0,0 @@
|
||||
<template>
|
||||
<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="h-8 bg-white dark:bg-gray-900" />
|
||||
<div class="bg-white dark:bg-gray-900 relative pointer-events-auto">
|
||||
<DocsSearchButton class="w-full" />
|
||||
</div>
|
||||
<div class="h-8 bg-gradient-to-b from-white dark:from-gray-900" />
|
||||
</div> -->
|
||||
|
||||
<DocsAsideLinks />
|
||||
</div>
|
||||
</aside>
|
||||
</template>
|
||||
@@ -1,40 +0,0 @@
|
||||
<template>
|
||||
<div class="space-y-8">
|
||||
<div v-for="(group, index) in navigation" :key="index" class="space-y-3">
|
||||
<p class="text-sm font-semibold text-gray-900 dark:text-gray-200 truncate leading-6">
|
||||
{{ group.title }}
|
||||
</p>
|
||||
|
||||
<UVerticalNavigation
|
||||
:links="mapContentLinks(group.children)"
|
||||
class="mt-1"
|
||||
:ui="{
|
||||
wrapper: 'border-l border-gray-200 dark:border-gray-800 space-y-2',
|
||||
base: 'group block border-l -ml-px lg:leading-6 flex items-center gap-2',
|
||||
padding: 'pl-4',
|
||||
rounded: '',
|
||||
font: '',
|
||||
ring: '',
|
||||
active: 'text-primary-500 dark:text-primary-400 border-current',
|
||||
inactive: 'border-transparent hover:border-gray-400 dark:hover:border-gray-500 text-gray-700 hover:text-gray-900 dark:text-gray-400 dark:hover:text-gray-300'
|
||||
}"
|
||||
>
|
||||
<template #badge="{ link }">
|
||||
<UBadge v-if="link.badge" size="xs" :ui="{ rounded: 'rounded-full' }">
|
||||
{{ link.badge }}
|
||||
</UBadge>
|
||||
</template>
|
||||
</UVerticalNavigation>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { NavItem } from '@nuxt/content/dist/runtime/types'
|
||||
|
||||
const navigation: Ref<NavItem[]> = inject('navigation')
|
||||
|
||||
function mapContentLinks (links: NavItem[]) {
|
||||
return links?.map(link => ({ label: link.title, icon: link.icon, to: link._path, badge: link.badge })) || []
|
||||
}
|
||||
</script>
|
||||
@@ -1,40 +0,0 @@
|
||||
<template>
|
||||
<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>
|
||||
|
||||
<div class="flex items-center gap-3 -my-1">
|
||||
<div class="flex lg:hidden items-center gap-1.5">
|
||||
<UButton
|
||||
to="https://twitter.com/nuxtlabs"
|
||||
target="_blank"
|
||||
color="gray"
|
||||
size="2xs"
|
||||
variant="ghost"
|
||||
icon="i-simple-icons-twitter"
|
||||
/>
|
||||
|
||||
<UButton
|
||||
to="https://github.com/nuxtlabs/ui"
|
||||
target="_blank"
|
||||
color="gray"
|
||||
size="2xs"
|
||||
variant="ghost"
|
||||
icon="i-simple-icons-github"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<NuxtLink :to="`https://github.com/nuxtlabs/ui/releases/tag/v${config.version}`" target="_blank">
|
||||
<UBadge :label="`v${config.version}`" />
|
||||
</NuxtLink>
|
||||
</div>
|
||||
</footer>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const config = useRuntimeConfig().public
|
||||
</script>
|
||||
@@ -1,22 +0,0 @@
|
||||
<template>
|
||||
<div class="flex items-center justify-between gap-1.5">
|
||||
<UButton
|
||||
v-if="page"
|
||||
:to="`https://github.com/nuxtlabs/ui/edit/dev/docs/content/${page._file}`"
|
||||
label="Edit this page on GitHub"
|
||||
color="primary"
|
||||
variant="link"
|
||||
:padded="false"
|
||||
icon="i-heroicons-pencil-square"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
defineProps({
|
||||
page: {
|
||||
type: Object,
|
||||
default: null
|
||||
}
|
||||
})
|
||||
</script>
|
||||
@@ -1,42 +0,0 @@
|
||||
<template>
|
||||
<header v-if="page" class="relative border-b border-gray-200 dark:border-gray-800 pb-8 mb-12">
|
||||
<p class="mb-4 text-sm leading-6 font-semibold text-primary-500 dark:text-primary-400 capitalize">
|
||||
{{ page._dir?.title ? page._dir.title : useLowerCase(page._dir) }}
|
||||
</p>
|
||||
<div class="flex flex-col lg:flex-row lg:items-center lg:justify-between">
|
||||
<h1 class="text-3xl sm:text-4xl font-extrabold text-gray-900 tracking-tight dark:text-white">
|
||||
{{ page.title }}
|
||||
</h1>
|
||||
|
||||
<div v-if="page.headlessui || page.github" class="flex items-center gap-2 mt-4 lg:mt-0">
|
||||
<UButton
|
||||
v-if="page.headlessui"
|
||||
:label="page.headlessui.label"
|
||||
:to="page.headlessui.to"
|
||||
icon="i-simple-icons-headlessui"
|
||||
color="white"
|
||||
/>
|
||||
|
||||
<UButton
|
||||
v-if="page.github"
|
||||
label="GitHub"
|
||||
icon="i-simple-icons-github"
|
||||
color="white"
|
||||
:to="`https://github.com/nuxtlabs/ui/blob/dev/src/runtime/components/${page._dir}/${page.title.replace(' ', '')}${page.github.suffix || '.vue'}`"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<p v-if="page.description" class="mt-4 text-lg text-gray-500 dark:text-gray-400">
|
||||
{{ page.description }}
|
||||
</p>
|
||||
</header>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
defineProps({
|
||||
page: {
|
||||
type: Object,
|
||||
default: null
|
||||
}
|
||||
})
|
||||
</script>
|
||||
@@ -1,33 +0,0 @@
|
||||
<template>
|
||||
<div class="grid gap-6 sm:grid-cols-2">
|
||||
<DocsPrevNextCard
|
||||
v-if="prev"
|
||||
:title="prev.title"
|
||||
:description="prev.description"
|
||||
:to="prev._path"
|
||||
icon="i-heroicons-arrow-left-20-solid"
|
||||
/>
|
||||
<span v-else class="hidden sm:block"> </span>
|
||||
<DocsPrevNextCard
|
||||
v-if="next"
|
||||
:title="next.title"
|
||||
:description="next.description"
|
||||
:to="next._path"
|
||||
icon="i-heroicons-arrow-right-20-solid"
|
||||
class="text-right"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
defineProps({
|
||||
prev: {
|
||||
type: Object,
|
||||
default: null
|
||||
},
|
||||
next: {
|
||||
type: Object,
|
||||
default: null
|
||||
}
|
||||
})
|
||||
</script>
|
||||
@@ -1,36 +0,0 @@
|
||||
<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/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>
|
||||
|
||||
<p class="text-gray-900 dark:text-gray-50 font-medium text-[15px] mb-1">
|
||||
{{ title }}
|
||||
</p>
|
||||
|
||||
<p class="text-sm font-normal text-gray-500 dark:text-gray-400">
|
||||
{{ description }}
|
||||
</p>
|
||||
</NuxtLink>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
defineProps({
|
||||
icon: {
|
||||
type: String,
|
||||
default: null
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
description: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
to: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
})
|
||||
</script>
|
||||
@@ -1,181 +0,0 @@
|
||||
<template>
|
||||
<UModal
|
||||
v-model="isSearchModalOpen"
|
||||
:overlay="!isXs"
|
||||
:transition="!isXs"
|
||||
:ui="{
|
||||
padding: 'sm:p-4',
|
||||
rounded: 'sm:rounded-lg',
|
||||
width: 'sm:max-w-3xl',
|
||||
height: 'h-screen sm:h-[28rem]'
|
||||
}"
|
||||
>
|
||||
<UCommandPalette
|
||||
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
|
||||
}"
|
||||
@update:model-value="onSelect"
|
||||
@close="isSearchModalOpen = false"
|
||||
/>
|
||||
</UModal>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { NavItem } from '@nuxt/content/dist/runtime/types'
|
||||
import type { Command } from '../../../src/runtime/types'
|
||||
|
||||
const navigation: Ref<NavItem[]> = inject('navigation')
|
||||
|
||||
const router = useRouter()
|
||||
const { usingInput } = useShortcuts()
|
||||
const { isSearchModalOpen } = useDocs()
|
||||
const breakpoints = useBreakpoints({ mobile: 640 })
|
||||
|
||||
const isXs = breakpoints.smaller('mobile')
|
||||
|
||||
const commandPaletteRef = ref<HTMLElement & { query: Ref<string>, results: { item: Command }[] }>()
|
||||
|
||||
const { data: files } = await useLazyAsyncData('search', () => queryContent().where({ _type: 'markdown' }).find(), { default: () => [] })
|
||||
|
||||
// Computed
|
||||
|
||||
const defaultGroups = computed(() => navigation.value.map(item => ({
|
||||
key: item._path,
|
||||
label: item.title,
|
||||
commands: files.value.filter(file => file._path.startsWith(item._path)).map(file => ({
|
||||
id: file._id,
|
||||
title: file.navigation?.title || file.title,
|
||||
to: file._path,
|
||||
suffix: file.description,
|
||||
icon: file.icon
|
||||
}))
|
||||
})))
|
||||
|
||||
const queryGroups = computed(() => navigation.value.map(item => ({
|
||||
key: item._path,
|
||||
label: item.title,
|
||||
commands: files.value.filter(file => file._path.startsWith(item._path)).flatMap((file) => {
|
||||
return [{
|
||||
id: file._id,
|
||||
title: file.navigation?.title || file.title,
|
||||
to: file._path,
|
||||
description: file.description,
|
||||
icon: file.icon
|
||||
},
|
||||
// @ts-ignore
|
||||
...Object.entries(groupByHeading(file.body.children)).map(([hash, { title, children }]) => ({
|
||||
id: `${file._path}${hash}`,
|
||||
title,
|
||||
prefix: `${file.navigation?.title || file.title} ->`,
|
||||
prefixClass: 'text-gray-700 dark:text-gray-200',
|
||||
to: `${file._path}${hash}`,
|
||||
children: concatChildren(children),
|
||||
icon: file.icon
|
||||
}))]
|
||||
})
|
||||
})))
|
||||
|
||||
const groups = computed(() => commandPaletteRef.value?.query ? queryGroups.value : defaultGroups.value)
|
||||
|
||||
// avoid conflicts between multiple meta_k shortcuts
|
||||
const canToggleModal = computed(() => isSearchModalOpen.value || !usingInput.value)
|
||||
|
||||
// Methods
|
||||
|
||||
function remapChildren (children: any[]) {
|
||||
return children?.map((grandChild) => {
|
||||
if (['code-inline', 'em', 'a', 'strong'].includes(grandChild.tag)) {
|
||||
return { type: 'text', value: grandChild.children.find(child => child.type === 'text')?.value || '' }
|
||||
}
|
||||
|
||||
return grandChild
|
||||
})
|
||||
}
|
||||
|
||||
function concatChildren (children: any[]) {
|
||||
return children.map((child) => {
|
||||
if (['alert'].includes(child.tag)) {
|
||||
child.children = concatChildren(child.children)
|
||||
}
|
||||
if (child.tag === 'p') {
|
||||
child.children = remapChildren(child.children)
|
||||
|
||||
child.children = child.children?.reduce((acc, grandChild) => {
|
||||
if (grandChild.type === 'text') {
|
||||
if (acc.length && acc[acc.length - 1].type === 'text') {
|
||||
acc[acc.length - 1].value += grandChild.value
|
||||
} else {
|
||||
acc.push(grandChild)
|
||||
}
|
||||
} else {
|
||||
acc.push(grandChild)
|
||||
}
|
||||
return acc
|
||||
}, [])
|
||||
}
|
||||
if (['style'].includes(child.tag)) {
|
||||
return null
|
||||
}
|
||||
|
||||
return child
|
||||
})
|
||||
}
|
||||
|
||||
function groupByHeading (children: any[]) {
|
||||
const groups = {} // grouped by path
|
||||
let hash = '' // file.page with potential `#anchor` concat
|
||||
let title: string | null
|
||||
for (const node of children) {
|
||||
// if heading found, udpate current path
|
||||
if (['h2', 'h3'].includes(node.tag)) {
|
||||
// find heading text value
|
||||
title = node.children?.find(child => child.type === 'text')?.value
|
||||
if (title) {
|
||||
hash = `#${node.props.id}`
|
||||
}
|
||||
}
|
||||
// push to existing/new group based on path
|
||||
if (groups[hash]) {
|
||||
groups[hash].children.push(node)
|
||||
} else {
|
||||
groups[hash] = { children: [node], title }
|
||||
}
|
||||
}
|
||||
return groups
|
||||
}
|
||||
|
||||
function onSelect (option) {
|
||||
isSearchModalOpen.value = false
|
||||
|
||||
if (option.click) {
|
||||
option.click()
|
||||
} else if (option.to) {
|
||||
router.push(option.to)
|
||||
} else if (option.href) {
|
||||
window.open(option.href, '_blank')
|
||||
}
|
||||
}
|
||||
|
||||
// Shortcuts
|
||||
|
||||
defineShortcuts({
|
||||
meta_k: {
|
||||
usingInput: true,
|
||||
whenever: [canToggleModal],
|
||||
handler: () => {
|
||||
isSearchModalOpen.value = !isSearchModalOpen.value
|
||||
}
|
||||
},
|
||||
escape: {
|
||||
usingInput: true,
|
||||
whenever: [isSearchModalOpen],
|
||||
handler: () => { isSearchModalOpen.value = false }
|
||||
}
|
||||
})
|
||||
</script>
|
||||
@@ -1,33 +0,0 @@
|
||||
<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>
|
||||
@@ -1,24 +0,0 @@
|
||||
<template>
|
||||
<div class="sticky top-16 bg-white/75 dark:bg-gray-900/75 backdrop-blur group lg:self-start -mx-4 sm:-mx-6 lg:mx-0 px-4 sm:px-6 lg:pl-8 lg:pr-0">
|
||||
<div class="py-3 lg:py-8 border-b border-dashed border-gray-200 dark:border-gray-800 lg:border-0">
|
||||
<button class="flex items-center gap-2" tabindex="-1" @click="isTocOpen = !isTocOpen">
|
||||
<span class="text-sm text-slate-900 font-semibold text-sm leading-6 dark:text-slate-100 truncate">Table of Contents</span>
|
||||
|
||||
<UIcon name="i-heroicons-chevron-right-20-solid" class="lg:hidden w-4 h-4 transition-transform duration-100 transform text-gray-400 dark:text-gray-500" :class="[isTocOpen ? 'rotate-90' : 'rotate-0']" />
|
||||
</button>
|
||||
|
||||
<DocsTocLinks class="mt-2 lg:mt-4" :links="toc.links" :class="[isTocOpen ? 'lg:block' : 'hidden lg:block']" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
defineProps({
|
||||
toc: {
|
||||
type: Object,
|
||||
default: null
|
||||
}
|
||||
})
|
||||
|
||||
const isTocOpen = ref(false)
|
||||
</script>
|
||||
@@ -1,49 +0,0 @@
|
||||
<template>
|
||||
<ul>
|
||||
<li v-for="link in links" :key="link.text" :class="{ 'ml-3': link.depth === 3 }">
|
||||
<a
|
||||
:href="`#${link.id}`"
|
||||
class="block py-1 font-medium text-sm"
|
||||
:class="[activeHeadings.includes(link.id) ? 'text-primary-500 dark:text-primary-400' : 'hover:text-gray-900 dark:text-gray-400 dark:hover:text-gray-300']"
|
||||
@click.prevent="scrollToHeading(link.id)"
|
||||
>
|
||||
{{ link.text }}
|
||||
</a>
|
||||
|
||||
<DocsTocLinks v-if="link.children" :links="link.children" />
|
||||
</li>
|
||||
</ul>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { TocLink } from '@nuxt/content/dist/runtime/types'
|
||||
|
||||
defineProps({
|
||||
links: {
|
||||
type: Array as PropType<TocLink[]>,
|
||||
default: () => []
|
||||
}
|
||||
})
|
||||
|
||||
const emit = defineEmits(['move'])
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const { activeHeadings, updateHeadings } = useScrollspy()
|
||||
|
||||
watch(() => route.path, () => {
|
||||
setTimeout(() => {
|
||||
if (process.client) {
|
||||
updateHeadings([
|
||||
...document.querySelectorAll('h2'),
|
||||
...document.querySelectorAll('h3')
|
||||
])
|
||||
}
|
||||
}, 300)
|
||||
}, { immediate: true })
|
||||
|
||||
const scrollToHeading = (id: string) => {
|
||||
router.push(`#${id}`)
|
||||
emit('move', id)
|
||||
}
|
||||
</script>
|
||||
@@ -1,11 +0,0 @@
|
||||
import { createSharedComposable } from '@vueuse/core'
|
||||
|
||||
const _useDocs = () => {
|
||||
const isSearchModalOpen = ref(false)
|
||||
|
||||
return {
|
||||
isSearchModalOpen
|
||||
}
|
||||
}
|
||||
|
||||
export const useDocs = createSharedComposable(_useDocs)
|
||||
@@ -1,37 +0,0 @@
|
||||
/**
|
||||
* Scrollspy allows you to watch visible headings in a specific page.
|
||||
* Useful for table of contents live style updates.
|
||||
*/
|
||||
export const useScrollspy = () => {
|
||||
const observer = ref() as Ref<IntersectionObserver>
|
||||
const visibleHeadings = ref([]) as Ref<string[]>
|
||||
const activeHeadings = ref([]) as Ref<string[]>
|
||||
|
||||
const observerCallback = (entries: IntersectionObserverEntry[]) =>
|
||||
entries.forEach((entry) => {
|
||||
const id = entry.target.id
|
||||
|
||||
if (entry.isIntersecting) { visibleHeadings.value.push(id) } else { visibleHeadings.value = visibleHeadings.value.filter(t => t !== id) }
|
||||
})
|
||||
|
||||
const updateHeadings = (headings: Element[]) =>
|
||||
headings.forEach((heading) => {
|
||||
observer.value.observe(heading)
|
||||
})
|
||||
|
||||
watch(visibleHeadings, (val, oldVal) => {
|
||||
if (val.length === 0) { activeHeadings.value = oldVal } else { activeHeadings.value = val }
|
||||
})
|
||||
|
||||
// Create intersection observer
|
||||
onBeforeMount(() => (observer.value = new IntersectionObserver(observerCallback)))
|
||||
|
||||
// Destroy it
|
||||
onBeforeUnmount(() => observer.value?.disconnect())
|
||||
|
||||
return {
|
||||
visibleHeadings,
|
||||
activeHeadings,
|
||||
updateHeadings
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@ head:
|
||||
|
||||
This module has been developed by the [NuxtLabs](https://nuxtlabs.com/) team for [Volta](https://volta.net) and [Nuxt Studio](https://nuxt.studio/), its goal is to provide everything related to UI when building a Nuxt app. This includes components, icons, colors, dark mode but also keyboard shortcuts.
|
||||
|
||||
::alert{icon="i-heroicons-light-bulb"}
|
||||
::callout{icon="i-heroicons-light-bulb"}
|
||||
[Volta](https://volta.net/) entire UI is built with this module alongside the 50+ keyboard shortcuts defined.
|
||||
::
|
||||
|
||||
@@ -31,7 +31,3 @@ This module has been developed by the [NuxtLabs](https://nuxtlabs.com/) team for
|
||||
- [tailwindlabs/headlessui](https://github.com/tailwindlabs/headlessui)
|
||||
- [vueuse/vueuse](https://github.com/vueuse/vueuse)
|
||||
- [egoist/tailwindcss-icons](https://github.com/egoist/tailwindcss-icons)
|
||||
|
||||
::alert{icon="i-heroicons-exclamation-triangle"}
|
||||
This documentation is still a work in progress and will be updated regularly.
|
||||
::
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
description: 'Learn how to install and configure the module in your Nuxt app.'
|
||||
---
|
||||
|
||||
## Quick Start
|
||||
|
||||
1. Install `@nuxthq/ui` dependency to your project:
|
||||
|
||||
::code-group
|
||||
@@ -30,14 +32,10 @@ export default defineNuxtConfig({
|
||||
|
||||
That's it! You can now use all the components and composables in your Nuxt app ✨
|
||||
|
||||
::alert{icon="i-heroicons-exclamation-triangle"}
|
||||
::callout{icon="i-heroicons-exclamation-triangle"}
|
||||
As this module installs [@nuxtjs/tailwindcss](https://tailwindcss.nuxtjs.org/) and [@nuxtjs/color-mode](https://color-mode.nuxtjs.org/) for you, you should remove them from your `modules` and `dependencies` if you've previously installed them manually.
|
||||
::
|
||||
|
||||
## Playground
|
||||
|
||||
:u-button{icon="i-simple-icons-stackblitz" label="Play on StackBlitz" size="lg" to="https://stackblitz.com/edit/nuxtlabs-ui?file=app.config.ts,app.vue" target="_blank"}
|
||||
|
||||
## IntelliSense
|
||||
|
||||
If you're using VSCode, you can install the [Tailwind CSS IntelliSense](https://marketplace.visualstudio.com/items?itemName=bradlc.vscode-tailwindcss) extension to get autocompletion for the classes.
|
||||
|
||||
@@ -19,7 +19,7 @@ export default defineAppConfig({
|
||||
})
|
||||
```
|
||||
|
||||
::alert{icon="i-heroicons-light-bulb"}
|
||||
::callout{icon="i-heroicons-light-bulb"}
|
||||
Try to change the `primary` and `gray` colors by clicking on the :u-icon{name="i-heroicons-swatch-20-solid" class="w-4 h-4 align-middle text-primary-500 dark:text-primary-400"} button in the header.
|
||||
::
|
||||
|
||||
@@ -29,11 +29,11 @@ To provide dynamic colors that can be changed at runtime, this module uses CSS v
|
||||
|
||||
Likewise, you can't define a `primary` color in your `tailwind.config.ts` as it would conflict with the `primary` color defined by the module.
|
||||
|
||||
::alert{icon="i-heroicons-light-bulb"}
|
||||
::callout{icon="i-heroicons-light-bulb"}
|
||||
We'd advise you to use those colors in your components and pages, e.g. `text-primary-500 dark:text-primary-400`, `bg-gray-100 dark:bg-gray-900`, etc. so your app automatically adapts when changing your `app.config.ts`.
|
||||
::
|
||||
|
||||
Components having a `color` prop like [Avatar](/elements/avatar#chip), [Badge](/elements/badge#style), [Button](/elements/button#style), [Input](/elements/input#style) (inherited in [Select](/forms/select) and [SelectMenu](/forms/select-menu)), [Radio](/forms/radio), [Checkbox](/forms/checkbox), [Toggle](/forms/toggle), [Range](/forms/range) and [Notification](/overlays/notification#timeout) will use the `primary` color by default but will handle all the colors defined in your `tailwind.config.ts` or the default Tailwind CSS colors.
|
||||
Components having a `color` prop like [Avatar](/elements/avatar#chip), [Badge](/elements/badge#style), [Button](/elements/button#style), [Input](/forms/input#style) (inherited in [Select](/forms/select) and [SelectMenu](/forms/select-menu)), [Radio](/forms/radio), [Checkbox](/forms/checkbox), [Toggle](/forms/toggle), [Range](/forms/range) and [Notification](/overlays/notification#timeout) will use the `primary` color by default but will handle all the colors defined in your `tailwind.config.ts` or the default Tailwind CSS colors.
|
||||
|
||||
Variant classes of those components are defined with a syntax like `bg-{color}-500 dark:bg-{color}-400` so they can be used with any color. However, this means that Tailwind will not find those classes and therefore will not generate the corresponding CSS.
|
||||
|
||||
@@ -73,7 +73,7 @@ All the components are styled with dark mode in mind.
|
||||
|
||||
Thanks to [Tailwind CSS dark mode](https://tailwindcss.com/docs/dark-mode#toggling-dark-mode-manually) class strategy and the [@nuxtjs/color-mode](https://github.com/nuxt-modules/color-mode) module, you literally have nothing to do.
|
||||
|
||||
::alert{icon="i-heroicons-puzzle-piece"}
|
||||
::callout{icon="i-heroicons-puzzle-piece"}
|
||||
Learn how to build a color mode button in the [Examples](/getting-started/examples#color-mode-button) page.
|
||||
::
|
||||
|
||||
@@ -87,7 +87,7 @@ export default defineNuxtConfig({
|
||||
})
|
||||
```
|
||||
|
||||
::alert{icon="i-heroicons-light-bulb"}
|
||||
::callout{icon="i-heroicons-light-bulb"}
|
||||
If you're stuck in dark mode even after changing this setting, you might need to remove the `nuxt-color-mode` entry from your browser's local storage.
|
||||
::
|
||||
|
||||
@@ -115,7 +115,7 @@ Each component has a `ui` prop that allows you to customize everything specifica
|
||||
</template>
|
||||
```
|
||||
|
||||
::alert{icon="i-heroicons-light-bulb"}
|
||||
::callout{icon="i-heroicons-light-bulb"}
|
||||
You can find the default classes for each component under the `Preset` section.
|
||||
::
|
||||
|
||||
@@ -165,7 +165,7 @@ export default defineNuxtConfig({
|
||||
})
|
||||
```
|
||||
|
||||
::alert{icon="i-heroicons-light-bulb"}
|
||||
::callout{icon="i-heroicons-light-bulb"}
|
||||
Search the icon you want to use on https://icones.js.org built by [@antfu](https://github.com/antfu).
|
||||
::
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ Shortcuts are displayed and styled through the [Kbd](/elements/kbd) component.
|
||||
</template>
|
||||
```
|
||||
|
||||
::alert{icon="i-heroicons-light-bulb"}
|
||||
::callout{icon="i-heroicons-light-bulb"}
|
||||
You will have a preview of how shortcuts are rendered in each component page.
|
||||
::
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ title: Examples
|
||||
description: Discover some real-life examples of components you can build.
|
||||
---
|
||||
|
||||
::alert{icon="i-heroicons-wrench-screwdriver"}
|
||||
::callout{icon="i-heroicons-wrench-screwdriver"}
|
||||
If you have any ideas of examples you'd like to see, please comment on [this issue](https://github.com/nuxtlabs/ui/issues/297).
|
||||
::
|
||||
|
||||
@@ -153,7 +153,7 @@ padding: false
|
||||
:command-palette-theme-algolia{class="max-h-[480px] rounded-md"}
|
||||
::
|
||||
|
||||
::alert{icon="i-simple-icons-github" to="https://github.com/nuxtlabs/ui/blob/dev/docs/components/content/themes/CommandPaletteThemeAlgolia.vue#L23"}
|
||||
::callout{icon="i-simple-icons-github" to="https://github.com/nuxtlabs/ui/blob/dev/docs/components/content/themes/CommandPaletteThemeAlgolia.vue#L23"}
|
||||
Take a look at the component!
|
||||
::
|
||||
|
||||
@@ -168,7 +168,7 @@ padding: false
|
||||
:command-palette-theme-raycast{class="max-h-[480px] rounded-md"}
|
||||
::
|
||||
|
||||
::alert{icon="i-simple-icons-github" to="https://github.com/nuxtlabs/ui/blob/dev/docs/components/content/themes/CommandPaletteThemeRaycast.vue#L30"}
|
||||
::callout{icon="i-simple-icons-github" to="https://github.com/nuxtlabs/ui/blob/dev/docs/components/content/themes/CommandPaletteThemeRaycast.vue#L30"}
|
||||
Take a look at the component!
|
||||
::
|
||||
|
||||
@@ -261,6 +261,6 @@ Here are some examples of how components look like in RTL mode.
|
||||
:pagination-example-r-t-l
|
||||
::
|
||||
|
||||
::alert{icon="i-simple-icons-github" to="https://github.com/nuxtlabs/ui/blob/dev/docs/components/content/examples/PaginationExampleRTL.vue"}
|
||||
::callout{icon="i-simple-icons-github" to="https://github.com/nuxtlabs/ui/blob/dev/docs/components/content/examples/PaginationExampleRTL.vue"}
|
||||
Take a look at the component!
|
||||
::
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
---
|
||||
github: true
|
||||
description: Display an image that represents a resource or a group of resources.
|
||||
links:
|
||||
- label: GitHub
|
||||
icon: i-simple-icons-github
|
||||
to: https://github.com/nuxtlabs/ui/blob/dev/src/runtime/components/elements/Avatar.vue
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
---
|
||||
github: true
|
||||
description: Display a short text to represent a status or a category.
|
||||
links:
|
||||
- label: GitHub
|
||||
icon: i-simple-icons-github
|
||||
to: https://github.com/nuxtlabs/ui/blob/dev/src/runtime/components/elements/Badge.vue
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
---
|
||||
github: true
|
||||
description: Create a button with icon or link capabilities.
|
||||
links:
|
||||
- label: GitHub
|
||||
icon: i-simple-icons-github
|
||||
to: https://github.com/nuxtlabs/ui/blob/dev/src/runtime/components/elements/Button.vue
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
---
|
||||
github: true
|
||||
description: Display a list of actions in a dropdown menu.
|
||||
headlessui:
|
||||
label: 'Menu'
|
||||
to: 'https://headlessui.com/vue/menu'
|
||||
links:
|
||||
- label: GitHub
|
||||
icon: i-simple-icons-github
|
||||
to: https://github.com/nuxtlabs/ui/blob/dev/src/runtime/components/elements/Dropdown.vue
|
||||
- label: Menu
|
||||
icon: i-simple-icons-headlessui
|
||||
to: https://headlessui.com/vue/menu
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
---
|
||||
github: true
|
||||
description: Display togglable accordion panels.
|
||||
headlessui:
|
||||
label: 'Disclosure'
|
||||
to: 'https://headlessui.com/vue/disclosure'
|
||||
links:
|
||||
- label: GitHub
|
||||
icon: i-simple-icons-github
|
||||
to: https://github.com/nuxtlabs/ui/blob/dev/src/runtime/components/elements/Accordion.vue
|
||||
- label: Disclosure
|
||||
icon: i-simple-icons-headlessui
|
||||
to: 'https://headlessui.com/vue/disclosure'
|
||||
navigation:
|
||||
badge: 'Edge'
|
||||
---
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
---
|
||||
github: true
|
||||
description: Display an icon from Iconify library.
|
||||
links:
|
||||
- label: GitHub
|
||||
icon: i-simple-icons-github
|
||||
to: https://github.com/nuxtlabs/ui/blob/dev/src/runtime/components/elements/Icon.vue
|
||||
---
|
||||
|
||||
## Usage
|
||||
@@ -12,7 +15,7 @@ props:
|
||||
---
|
||||
::
|
||||
|
||||
::alert{icon="i-heroicons-exclamation-triangle"}
|
||||
::callout{icon="i-heroicons-exclamation-triangle"}
|
||||
When playing with the `name` prop above, you won't be able to use any icon you want as icons are bundled on build as explained in the [theming section](/getting-started/theming#icons).
|
||||
::
|
||||
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
---
|
||||
github: true
|
||||
title: 'Keyboard Key'
|
||||
description: Display a keyboard key in a text block.
|
||||
links:
|
||||
- label: GitHub
|
||||
icon: i-simple-icons-github
|
||||
to: https://github.com/nuxtlabs/ui/blob/dev/src/runtime/components/elements/Kbd.vue
|
||||
navigation:
|
||||
title: 'Kbd'
|
||||
---
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
---
|
||||
github: true
|
||||
description: Display an input field.
|
||||
links:
|
||||
- label: GitHub
|
||||
icon: i-simple-icons-github
|
||||
to: https://github.com/nuxtlabs/ui/blob/dev/src/runtime/components/forms/Input.vue
|
||||
---
|
||||
|
||||
## Usage
|
||||
@@ -218,7 +221,7 @@ const q = ref('')
|
||||
```
|
||||
::
|
||||
|
||||
::alert{icon="i-heroicons-exclamation-triangle-20-solid"}
|
||||
::callout{icon="i-heroicons-exclamation-triangle-20-solid"}
|
||||
As leading and trailing icons are wrapped around a `pointer-events-none` class, if you inject a clickable element in the slot, you need to remove this class to make it clickable by adding `:ui="{ icon: { trailing: { pointer: '' } } }"` to the Input.
|
||||
::
|
||||
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
---
|
||||
github: true
|
||||
description: Display a textarea field.
|
||||
links:
|
||||
- label: GitHub
|
||||
icon: i-simple-icons-github
|
||||
to: https://github.com/nuxtlabs/ui/blob/dev/src/runtime/components/forms/Textarea.vue
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
---
|
||||
github: true
|
||||
description: Display a select field.
|
||||
links:
|
||||
- label: GitHub
|
||||
icon: i-simple-icons-github
|
||||
to: https://github.com/nuxtlabs/ui/blob/dev/src/runtime/components/forms/Select.vue
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
---
|
||||
github: true
|
||||
description: Display a select menu with advanced features.
|
||||
headlessui:
|
||||
label: 'Listbox'
|
||||
to: 'https://headlessui.com/vue/listbox'
|
||||
links:
|
||||
- label: GitHub
|
||||
icon: i-simple-icons-github
|
||||
to: https://github.com/nuxtlabs/ui/blob/dev/src/runtime/components/forms/SelectMenu.vue
|
||||
- label: 'Listbox'
|
||||
icon: i-simple-icons-headlessui
|
||||
to: 'https://headlessui.com/vue/listbox'
|
||||
---
|
||||
|
||||
## Usage
|
||||
@@ -122,7 +125,7 @@ excludedProps:
|
||||
---
|
||||
::
|
||||
|
||||
::alert{icon="i-heroicons-light-bulb"}
|
||||
::callout{icon="i-heroicons-light-bulb"}
|
||||
Learn how to customize icons from the [Select](/forms/select#icon) component.
|
||||
::
|
||||
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
---
|
||||
github: true
|
||||
description: Display a checkbox field.
|
||||
links:
|
||||
- label: GitHub
|
||||
icon: i-simple-icons-github
|
||||
to: https://github.com/nuxtlabs/ui/blob/dev/src/runtime/components/forms/Checkbox.vue
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
---
|
||||
github: true
|
||||
description: Display a radio field.
|
||||
links:
|
||||
- label: GitHub
|
||||
icon: i-simple-icons-github
|
||||
to: https://github.com/nuxtlabs/ui/blob/dev/src/runtime/components/forms/Radio.vue
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
---
|
||||
github: true
|
||||
description: Display a toggle field.
|
||||
headlessui:
|
||||
label: 'Switch'
|
||||
to: 'https://headlessui.com/vue/switch'
|
||||
links:
|
||||
- label: GitHub
|
||||
icon: i-simple-icons-github
|
||||
to: https://github.com/nuxtlabs/ui/blob/dev/src/runtime/components/forms/Toggle.vue
|
||||
- label: 'Switch'
|
||||
icon: i-simple-icons-headlessui
|
||||
to: 'https://headlessui.com/vue/switch'
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
---
|
||||
github: true
|
||||
description: Display a range field
|
||||
links:
|
||||
- label: GitHub
|
||||
icon: i-simple-icons-github
|
||||
to: https://github.com/nuxtlabs/ui/blob/dev/src/runtime/components/forms/Range.vue
|
||||
navigation:
|
||||
badge: New
|
||||
---
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
---
|
||||
github:
|
||||
suffix: .ts
|
||||
description: Display a label and additional informations around a form element.
|
||||
links:
|
||||
- label: GitHub
|
||||
icon: i-simple-icons-github
|
||||
to: https://github.com/nuxtlabs/ui/blob/dev/src/runtime/components/forms/FormGroup.ts
|
||||
---
|
||||
|
||||
|
||||
@@ -128,7 +130,7 @@ code: >-
|
||||
|
||||
You can also use the `error` prop as a boolean to mark the form element as invalid.
|
||||
|
||||
::alert{icon="i-heroicons-light-bulb"}
|
||||
::callout{icon="i-heroicons-light-bulb"}
|
||||
The `error` prop will automatically set the `color` prop of the form element to `red`.
|
||||
::
|
||||
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
---
|
||||
github: true
|
||||
description: 'Display data in a table.'
|
||||
links:
|
||||
- label: GitHub
|
||||
icon: i-simple-icons-github
|
||||
to: https://github.com/nuxtlabs/ui/blob/dev/src/runtime/components/data/Table.vue
|
||||
---
|
||||
|
||||
## Usage
|
||||
@@ -210,7 +213,7 @@ You can specify a default sort for the table through the `sort` prop. It's an ob
|
||||
- `column` - The column to sort by.
|
||||
- `direction` - The sort direction. Can be either `asc` or `desc` and defaults to `asc`.
|
||||
|
||||
::alert{icon="i-heroicons-light-bulb"}
|
||||
::callout{icon="i-heroicons-light-bulb"}
|
||||
This will set the default sort and will work even if no column is set as `sortable`.
|
||||
::
|
||||
|
||||
@@ -289,7 +292,7 @@ Use the `sort-asc-icon` prop to set a different icon or change it globally in `u
|
||||
|
||||
Use the `sort-desc-icon` prop to set a different icon or change it globally in `ui.table.default.sortDescIcon`. Defaults to `i-heroicons-bars-arrow-down-20-solid`.
|
||||
|
||||
::alert{icon="i-heroicons-light-bulb"}
|
||||
::callout{icon="i-heroicons-light-bulb"}
|
||||
You can also customize the entire header cell, read more in the [Slots](#slots) section.
|
||||
::
|
||||
|
||||
@@ -320,7 +323,7 @@ const selected = ref([people[1]])
|
||||
```
|
||||
::
|
||||
|
||||
::alert{icon="i-heroicons-light-bulb"}
|
||||
::callout{icon="i-heroicons-light-bulb"}
|
||||
You can use the `by` prop to compare objects by a field instead of comparing object instances. We've replicated the behavior of Headless UI [Combobox](https://headlessui.com/vue/combobox#binding-objects-as-values).
|
||||
::
|
||||
|
||||
@@ -500,7 +503,7 @@ The `sort` property is an object with the following properties:
|
||||
|
||||
The `on-sort` property is a function that you can call to sort the table and accepts the column as parameter.
|
||||
|
||||
::alert{icon="i-heroicons-light-bulb"}
|
||||
::callout{icon="i-heroicons-light-bulb"}
|
||||
Even though you can customize the sort button as mentioned in the [Sortable](#sortable) section, you can use this slot to completely override its behavior, with a custom dropdown for example.
|
||||
::
|
||||
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
---
|
||||
github: true
|
||||
description: Display a vertical navigation.
|
||||
links:
|
||||
- label: GitHub
|
||||
icon: i-simple-icons-github
|
||||
to: https://github.com/nuxtlabs/ui/blob/dev/src/runtime/components/navigation/VerticalNavigation.vue
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
---
|
||||
github: true
|
||||
description: Add a customizable command palette to your app.
|
||||
headlessui:
|
||||
label: 'Combobox'
|
||||
to: 'https://headlessui.com/vue/combobox'
|
||||
links:
|
||||
- label: GitHub
|
||||
icon: i-simple-icons-github
|
||||
to: https://github.com/nuxtlabs/ui/blob/dev/src/runtime/components/navigation/CommandPalette.vue
|
||||
- label: 'Combobox'
|
||||
icon: i-simple-icons-headlessui
|
||||
to: 'https://headlessui.com/vue/combobox'
|
||||
---
|
||||
|
||||
## Usage
|
||||
@@ -278,8 +281,8 @@ You can also highlight the matches in the command by setting the `fuse.fuseOptio
|
||||
</template>
|
||||
```
|
||||
|
||||
::alert{icon="i-heroicons-light-bulb"}
|
||||
Try it yourself in this documentation's search by pressing :badge-shortcut{value="meta"} :badge-shortcut{value="K" class="ml-1"}.
|
||||
::callout{icon="i-heroicons-light-bulb"}
|
||||
Try it yourself in this documentation's search by pressing :kbd{value="meta"} :kbd{value="K" class="ml-1"}.
|
||||
::
|
||||
|
||||
## Async search
|
||||
@@ -319,7 +322,7 @@ const groups = computed(() => {
|
||||
```
|
||||
::
|
||||
|
||||
::alert{icon="i-heroicons-light-bulb"}
|
||||
::callout{icon="i-heroicons-light-bulb"}
|
||||
The `loading` state will automatically be enabled when a `search` function is loading. You can disable this behavior by setting the `loading-icon` prop to `null` or globally in `ui.commandPalette.default.loadingIcon`.
|
||||
::
|
||||
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
---
|
||||
github: true
|
||||
description: Add a pagination to handle pages.
|
||||
links:
|
||||
- label: GitHub
|
||||
icon: i-simple-icons-github
|
||||
to: https://github.com/nuxtlabs/ui/blob/dev/src/runtime/components/navigation/Pagination.vue
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
---
|
||||
github: true
|
||||
description: Display a modal within your application.
|
||||
headlessui:
|
||||
label: 'Dialog'
|
||||
to: 'https://headlessui.com/vue/dialog'
|
||||
links:
|
||||
- label: GitHub
|
||||
icon: i-simple-icons-github
|
||||
to: https://github.com/nuxtlabs/ui/blob/dev/src/runtime/components/overlays/Modal.vue
|
||||
- label: 'Dialog'
|
||||
icon: i-simple-icons-headlessui
|
||||
to: 'https://headlessui.com/vue/dialog'
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
---
|
||||
github: true
|
||||
description: Display a dialog that slides in from the edge of the screen.
|
||||
headlessui:
|
||||
label: 'Dialog'
|
||||
to: 'https://headlessui.com/vue/dialog'
|
||||
links:
|
||||
- label: GitHub
|
||||
icon: i-simple-icons-github
|
||||
to: https://github.com/nuxtlabs/ui/blob/dev/src/runtime/components/overlays/Slideover.vue
|
||||
- label: 'Dialog'
|
||||
icon: i-simple-icons-headlessui
|
||||
to: 'https://headlessui.com/vue/dialog'
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
---
|
||||
github: true
|
||||
description: Display a non-modal dialog that floats around a trigger element.
|
||||
headlessui:
|
||||
label: 'Popover'
|
||||
to: 'https://headlessui.com/vue/popover'
|
||||
links:
|
||||
- label: GitHub
|
||||
icon: i-simple-icons-github
|
||||
to: https://github.com/nuxtlabs/ui/blob/dev/src/runtime/components/overlays/Popover.vue
|
||||
- label: 'Popover'
|
||||
icon: i-simple-icons-headlessui
|
||||
to: 'https://headlessui.com/vue/popover'
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
---
|
||||
github: true
|
||||
description: Display content that appears on hover next to an element.
|
||||
links:
|
||||
- label: GitHub
|
||||
icon: i-simple-icons-github
|
||||
to: https://github.com/nuxtlabs/ui/blob/dev/src/runtime/components/overlays/Tooltip.vue
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
---
|
||||
github: true
|
||||
description: Display a menu that appears on right click.
|
||||
links:
|
||||
- label: GitHub
|
||||
icon: i-simple-icons-github
|
||||
to: https://github.com/nuxtlabs/ui/blob/dev/src/runtime/components/overlays/ContextMenu.vue
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
---
|
||||
github: true
|
||||
description: Display a toast notification in your app.
|
||||
links:
|
||||
- label: GitHub
|
||||
icon: i-simple-icons-github
|
||||
to: https://github.com/nuxtlabs/ui/blob/dev/src/runtime/components/overlays/Notification.vue
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
---
|
||||
github: true
|
||||
description: Display a card for content with a header, body and footer.
|
||||
links:
|
||||
- label: GitHub
|
||||
icon: i-simple-icons-github
|
||||
to: https://github.com/nuxtlabs/ui/blob/dev/src/runtime/components/layout/Card.vue
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
---
|
||||
github: true
|
||||
description: A container lets you center and constrain the width of your content.
|
||||
links:
|
||||
- label: GitHub
|
||||
icon: i-simple-icons-github
|
||||
to: https://github.com/nuxtlabs/ui/blob/dev/src/runtime/components/layout/Container.vue
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
---
|
||||
github: true
|
||||
description: Display a placeholder while content is loading.
|
||||
links:
|
||||
- label: GitHub
|
||||
icon: i-simple-icons-github
|
||||
to: https://github.com/nuxtlabs/ui/blob/dev/src/runtime/components/layout/Skeleton.vue
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -1,49 +1,43 @@
|
||||
import ui from '../src/module'
|
||||
import { excludeColors } from '../src/colors'
|
||||
import colors from 'tailwindcss/colors'
|
||||
import module from '../src/module'
|
||||
import { excludeColors } from '../src/colors'
|
||||
import pkg from '../package.json'
|
||||
|
||||
export default defineNuxtConfig({
|
||||
// @ts-ignore
|
||||
extends: '@nuxthq/ui-kit',
|
||||
modules: [
|
||||
ui,
|
||||
'@vueuse/nuxt',
|
||||
'@nuxt/content',
|
||||
'@nuxt/devtools',
|
||||
'@nuxthq/studio',
|
||||
module,
|
||||
'@nuxtjs/google-fonts',
|
||||
'@nuxtjs/plausible',
|
||||
'nuxt-lodash',
|
||||
'nuxt-component-meta'
|
||||
'@vueuse/nuxt',
|
||||
'nuxt-component-meta',
|
||||
'nuxt-lodash'
|
||||
],
|
||||
runtimeConfig: {
|
||||
public: {
|
||||
version: pkg.version
|
||||
}
|
||||
},
|
||||
content: {
|
||||
highlight: {
|
||||
theme: {
|
||||
light: 'material-lighter',
|
||||
default: 'material-default',
|
||||
dark: 'material-palenight'
|
||||
},
|
||||
preload: ['json', 'js', 'ts', 'html', 'css', 'vue', 'diff', 'shell', 'markdown', 'yaml', 'bash', 'ini']
|
||||
}
|
||||
},
|
||||
ui: {
|
||||
global: true,
|
||||
icons: ['heroicons', 'simple-icons'],
|
||||
safelistColors: excludeColors(colors)
|
||||
},
|
||||
typescript: {
|
||||
strict: false,
|
||||
includeWorkspace: true
|
||||
googleFonts: {
|
||||
families: {
|
||||
Inter: [400, 500, 600, 700]
|
||||
}
|
||||
},
|
||||
routeRules: {
|
||||
'/': { redirect: '/getting-started' }
|
||||
'/': { redirect: '/getting-started', prerender: false }
|
||||
},
|
||||
generate: {
|
||||
routes: ['/getting-started']
|
||||
nitro: {
|
||||
prerender: {
|
||||
routes: ['/getting-started']
|
||||
}
|
||||
},
|
||||
componentMeta: {
|
||||
metaFields: {
|
||||
@@ -52,5 +46,9 @@ export default defineNuxtConfig({
|
||||
events: false,
|
||||
exposed: false
|
||||
}
|
||||
},
|
||||
typescript: {
|
||||
strict: false,
|
||||
includeWorkspace: true
|
||||
}
|
||||
})
|
||||
|
||||
22
docs/package.json
Normal file
22
docs/package.json
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"name": "@nuxthq/ui-docs",
|
||||
"private": true,
|
||||
"devDependencies": {
|
||||
"@iconify-json/heroicons": "latest",
|
||||
"@iconify-json/simple-icons": "latest",
|
||||
"@nuxt/content": "npm:@nuxt/content-edge@latest",
|
||||
"@nuxt/devtools": "^0.6.7",
|
||||
"@nuxt/eslint-config": "^0.1.1",
|
||||
"@nuxthq/studio": "^0.13.4",
|
||||
"@nuxthq/ui-kit": "npm:@nuxthq/ui-kit-edge@0.0.1-28159938.cd087ba",
|
||||
"@nuxtjs/google-fonts": "^3.0.1",
|
||||
"@nuxtjs/plausible": "^0.2.1",
|
||||
"@vueuse/nuxt": "^10.2.1",
|
||||
"eslint": "^8.45.0",
|
||||
"nuxt": "^3.6.2",
|
||||
"nuxt-component-meta": "^0.5.3",
|
||||
"nuxt-lodash": "^2.5.0",
|
||||
"typescript": "^5.1.6",
|
||||
"v-calendar": "^3.0.3"
|
||||
}
|
||||
}
|
||||
@@ -1,43 +1,17 @@
|
||||
<template>
|
||||
<div v-if="page" class="grid lg:grid-cols-10 lg:gap-8">
|
||||
<div class="pt-8 pb-16" :class="page.body?.toc ? 'lg:col-span-8' : 'lg:col-span-10'">
|
||||
<DocsPageHeader :page="page" />
|
||||
|
||||
<ContentRenderer v-if="page.body" :value="page" class="prose prose-primary dark:prose-invert max-w-none" />
|
||||
|
||||
<DocsPageFooter :page="page" class="mt-12" />
|
||||
|
||||
<hr class="border-gray-200 dark:border-gray-800 my-6">
|
||||
|
||||
<DocsPrevNext :prev="prev" :next="next" />
|
||||
|
||||
<DocsFooter class="mt-16" />
|
||||
</div>
|
||||
|
||||
<DocsToc v-if="page.body?.toc" :toc="page.body.toc" class="lg:col-span-2 order-first lg:order-last" />
|
||||
</div>
|
||||
<div v-else class="flex-1 flex flex-col items-center justify-center">
|
||||
<div class="text-center">
|
||||
<p class="text-base font-semibold text-primary-500 dark:text-primary-400">
|
||||
404
|
||||
</p>
|
||||
<h1 class="mt-2 text-4xl tracking-tight font-extrabold u-text-gray-900 sm:text-5xl">
|
||||
Page not found
|
||||
</h1>
|
||||
<p class="mt-2 text-base u-text-gray-500">
|
||||
Sorry, we couldn’t find the page you’re looking for.
|
||||
</p>
|
||||
<div class="mt-6">
|
||||
<NuxtLink to="/" class="text-base font-medium text-primary-500 dark:text-primary-400 hover:u-text-gray-900">
|
||||
Go back home
|
||||
<span aria-hidden="true"> →</span>
|
||||
</NuxtLink>
|
||||
</div>
|
||||
</div>
|
||||
<UDocsPage v-if="page" :page="page" :surround="(surround as ParsedContent[])">
|
||||
<template #footer>
|
||||
<Footer />
|
||||
</template>
|
||||
</UDocsPage>
|
||||
<div v-else class="pt-8">
|
||||
Page not found
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { ParsedContent } from '@nuxt/content/dist/runtime/types'
|
||||
|
||||
const route = useRoute()
|
||||
|
||||
const { data: page } = await useAsyncData(`docs-${route.path}`, () => queryContent(route.path).findOne())
|
||||
@@ -47,7 +21,10 @@ const { data: surround } = await useAsyncData(`docs-${route.path}-surround`, ()
|
||||
.findSurround(route.path.endsWith('/') ? route.path.slice(0, -1) : route.path)
|
||||
)
|
||||
|
||||
const [prev, next] = surround.value
|
||||
if (process.server && !page.value) {
|
||||
const event = useRequestEvent()
|
||||
setResponseStatus(event, 404)
|
||||
}
|
||||
|
||||
useContentHead(page)
|
||||
</script>
|
||||
|
||||
@@ -1,185 +1,11 @@
|
||||
import type { Config } from 'tailwindcss'
|
||||
import defaultTheme from 'tailwindcss/defaultTheme'
|
||||
|
||||
export default <Partial<Config>> {
|
||||
content: [
|
||||
'docs/content/**/*.md'
|
||||
],
|
||||
export default <Partial<Config>>{
|
||||
theme: {
|
||||
extend: {
|
||||
fontFamily: {
|
||||
sans: ['Inter var', ...defaultTheme.fontFamily.sans]
|
||||
},
|
||||
maxWidth: {
|
||||
'8xl': '90rem'
|
||||
},
|
||||
typography: (theme) => {
|
||||
return {
|
||||
DEFAULT: {
|
||||
css: {
|
||||
'h1, h2, h3, h4': {
|
||||
fontWeight: theme('fontWeight.bold'),
|
||||
'scroll-margin-top': 'var(--scroll-mt)'
|
||||
},
|
||||
'h1 a, h2 a, h3 a, h4 a': {
|
||||
borderBottom: 'none !important',
|
||||
color: 'inherit',
|
||||
fontWeight: 'inherit'
|
||||
},
|
||||
a: {
|
||||
fontWeight: theme('fontWeight.medium'),
|
||||
textDecoration: 'none',
|
||||
borderBottom: '1px solid transparent'
|
||||
},
|
||||
'a:hover': {
|
||||
borderColor: 'var(--tw-prose-links)'
|
||||
},
|
||||
'a:has(> code)': {
|
||||
borderColor: 'transparent !important'
|
||||
},
|
||||
'a code': {
|
||||
color: 'var(--tw-prose-code)',
|
||||
border: '1px dashed var(--tw-prose-pre-border)'
|
||||
},
|
||||
'a:hover code': {
|
||||
color: 'var(--tw-prose-links)',
|
||||
borderColor: 'var(--tw-prose-links)'
|
||||
},
|
||||
pre: {
|
||||
margin: '0',
|
||||
borderRadius: '0.375rem',
|
||||
border: '1px solid var(--tw-prose-pre-border)',
|
||||
whiteSpace: 'pre-wrap',
|
||||
wordBreak: 'break-word'
|
||||
},
|
||||
code: {
|
||||
backgroundColor: 'var(--tw-prose-pre-bg)',
|
||||
padding: '0.25rem 0.375rem',
|
||||
borderRadius: '0.375rem',
|
||||
border: '1px solid var(--tw-prose-pre-border)'
|
||||
},
|
||||
'code::before': {
|
||||
content: ''
|
||||
},
|
||||
'code::after': {
|
||||
content: ''
|
||||
},
|
||||
'blockquote p:first-of-type::before': {
|
||||
content: ''
|
||||
},
|
||||
'blockquote p:last-of-type::after': {
|
||||
content: ''
|
||||
},
|
||||
'input[type="checkbox"]': {
|
||||
color: 'rgb(var(--color-primary-500))',
|
||||
borderRadius: theme('borderRadius.DEFAULT'),
|
||||
borderColor: 'rgb(var(--color-gray-300))',
|
||||
height: theme('spacing.4'),
|
||||
width: theme('spacing.4'),
|
||||
marginTop: '-3.5px !important',
|
||||
marginBottom: '0 !important',
|
||||
'&:focus': {
|
||||
'--tw-ring-offset-width': 0
|
||||
}
|
||||
},
|
||||
'input[type="checkbox"]:checked': {
|
||||
borderColor: 'rgb(var(--color-primary-500))'
|
||||
},
|
||||
'input[type="checkbox"]:disabled': {
|
||||
opacity: 0.5,
|
||||
cursor: 'not-allowed'
|
||||
},
|
||||
'ul.contains-task-list': {
|
||||
marginLeft: '-1.625em'
|
||||
},
|
||||
'ul ul': {
|
||||
paddingLeft: theme('padding.6')
|
||||
},
|
||||
'ul ol': {
|
||||
paddingLeft: theme('padding.6')
|
||||
},
|
||||
'ul > li.task-list-item': {
|
||||
paddingLeft: '0 !important'
|
||||
},
|
||||
'ul > li.task-list-item input': {
|
||||
marginRight: '7px'
|
||||
},
|
||||
'ul > li.task-list-item > ul.contains-task-list': {
|
||||
marginLeft: 'initial'
|
||||
},
|
||||
'ul > li.task-list-item a': {
|
||||
marginBottom: 0
|
||||
},
|
||||
'ul > li.task-list-item::marker': {
|
||||
content: 'none'
|
||||
},
|
||||
'ul > li > p': {
|
||||
margin: 0
|
||||
},
|
||||
'ul > li > span.issue-badge, p > span.issue-badge': {
|
||||
verticalAlign: 'text-top',
|
||||
margin: '0 !important'
|
||||
},
|
||||
'ul > li > button': {
|
||||
verticalAlign: 'baseline !important'
|
||||
},
|
||||
table: {
|
||||
wordBreak: 'break-all'
|
||||
}
|
||||
}
|
||||
},
|
||||
primary: {
|
||||
css: {
|
||||
'--tw-prose-body': 'rgb(var(--color-gray-700))',
|
||||
'--tw-prose-headings': 'rgb(var(--color-gray-900))',
|
||||
'--tw-prose-lead': 'rgb(var(--color-gray-600))',
|
||||
'--tw-prose-links': 'rgb(var(--color-primary-500))',
|
||||
'--tw-prose-bold': 'rgb(var(--color-gray-900))',
|
||||
'--tw-prose-counters': 'rgb(var(--color-gray-500))',
|
||||
'--tw-prose-bullets': 'rgb(var(--color-gray-300))',
|
||||
'--tw-prose-hr': 'rgb(var(--color-gray-100))',
|
||||
'--tw-prose-quotes': 'rgb(var(--color-gray-900))',
|
||||
'--tw-prose-quote-borders': 'rgb(var(--color-gray-200))',
|
||||
'--tw-prose-captions': 'rgb(var(--color-gray-500))',
|
||||
'--tw-prose-code': 'rgb(var(--color-gray-900))',
|
||||
'--tw-prose-pre-code': 'rgb(var(--color-gray-900))',
|
||||
'--tw-prose-pre-bg': 'rgb(var(--color-gray-50))',
|
||||
'--tw-prose-pre-border': 'rgb(var(--color-gray-200))',
|
||||
'--tw-prose-th-borders': 'rgb(var(--color-gray-300))',
|
||||
'--tw-prose-td-borders': 'rgb(var(--color-gray-200))',
|
||||
'--tw-prose-invert-body': 'rgb(var(--color-gray-200))',
|
||||
'--tw-prose-invert-headings': theme('colors.white'),
|
||||
'--tw-prose-invert-lead': 'rgb(var(--color-gray-400))',
|
||||
'--tw-prose-invert-links': 'rgb(var(--color-primary-400))',
|
||||
'--tw-prose-invert-bold': theme('colors.white'),
|
||||
'--tw-prose-invert-counters': 'rgb(var(--color-gray-400))',
|
||||
'--tw-prose-invert-bullets': 'rgb(var(--color-gray-600))',
|
||||
'--tw-prose-invert-hr': 'rgb(var(--color-gray-800))',
|
||||
'--tw-prose-invert-quotes': 'rgb(var(--color-gray-100))',
|
||||
'--tw-prose-invert-quote-borders': 'rgb(var(--color-gray-700))',
|
||||
'--tw-prose-invert-captions': 'rgb(var(--color-gray-400))',
|
||||
'--tw-prose-invert-code': theme('colors.white'),
|
||||
'--tw-prose-invert-pre-code': theme('colors.white'),
|
||||
'--tw-prose-invert-pre-bg': 'rgb(var(--color-gray-800))',
|
||||
'--tw-prose-invert-pre-border': 'rgb(var(--color-gray-700))',
|
||||
'--tw-prose-invert-th-borders': 'rgb(var(--color-gray-700))',
|
||||
'--tw-prose-invert-td-borders': 'rgb(var(--color-gray-800))'
|
||||
}
|
||||
},
|
||||
invert: {
|
||||
css: {
|
||||
'--tw-prose-pre-border': 'var(--tw-prose-invert-pre-border)',
|
||||
'input[type="checkbox"]': {
|
||||
backgroundColor: 'rgb(var(--color-gray-800))',
|
||||
borderColor: 'rgb(var(--color-gray-700))'
|
||||
},
|
||||
'input[type="checkbox"]:checked': {
|
||||
backgroundColor: 'rgb(var(--color-primary-400))',
|
||||
borderColor: 'rgb(var(--color-primary-400))'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
sans: ['Inter', ...defaultTheme.fontFamily.sans]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
12
package.json
12
package.json
@@ -49,24 +49,14 @@
|
||||
"tailwindcss": "^3.3.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@iconify-json/simple-icons": "^1.1.59",
|
||||
"@nuxt/content": "^2.7.0",
|
||||
"@nuxt/devtools": "^0.6.7",
|
||||
"@nuxt/eslint-config": "^0.1.1",
|
||||
"@nuxt/module-builder": "^0.4.0",
|
||||
"@nuxthq/studio": "^0.13.3",
|
||||
"@nuxtjs/plausible": "^0.2.1",
|
||||
"@release-it/conventional-changelog": "^7.0.0",
|
||||
"@types/lodash-es": "^4.17.7",
|
||||
"@types/node": "^20.4.1",
|
||||
"@vueuse/nuxt": "^10.2.1",
|
||||
"eslint": "^8.44.0",
|
||||
"nuxt": "^3.6.2",
|
||||
"nuxt-component-meta": "^0.5.3",
|
||||
"nuxt-lodash": "^2.5.0",
|
||||
"release-it": "^16.1.0",
|
||||
"unbuild": "^1.2.1",
|
||||
"v-calendar": "^3.0.3",
|
||||
"typescript": "^5.1.6",
|
||||
"vue-tsc": "^1.8.4"
|
||||
}
|
||||
}
|
||||
|
||||
3197
pnpm-lock.yaml
generated
3197
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
3
pnpm-workspace.yaml
Normal file
3
pnpm-workspace.yaml
Normal file
@@ -0,0 +1,3 @@
|
||||
packages:
|
||||
- "docs"
|
||||
- "./"
|
||||
@@ -5,6 +5,7 @@
|
||||
<NuxtLink
|
||||
v-else
|
||||
v-slot="{ href, navigate, exact, isActive, isExactActive }"
|
||||
:to="$attrs.to"
|
||||
custom
|
||||
>
|
||||
<a
|
||||
|
||||
Reference in New Issue
Block a user