mirror of
https://github.com/ArthurDanjou/ui.git
synced 2026-01-22 16:00:39 +01:00
docs: integrate @nuxt/ui-pro (#739)
Co-authored-by: Pooya Parsa <pooya@pi0.io> Co-authored-by: Florent Delerue <florentdelerue@hotmail.com> Co-authored-by: Sébastien Chopin <seb@nuxt.com>
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
# To link Nuxt UI Pro in development
|
||||
# Specify the path of @nuxt/ui-pro locally
|
||||
NUXT_UI_PRO_PATH=
|
||||
# To use Nuxt UI Pro in production
|
||||
NUXT_UI_PRO_TOKEN=
|
||||
# Production token for @nuxt/ui-pro, purchase on https://ui.nuxt.com/pro/purchase
|
||||
NUXT_UI_PRO_LICENSE=
|
||||
# Used when pre-rendering the docs for dynamic OG images
|
||||
NUXT_PUBLIC_SITE_URL=
|
||||
# Used to fetch `nuxt/ui-pro` docs content
|
||||
NUXT_GITHUB_TOKEN=
|
||||
|
||||
67
docs/app.vue
67
docs/app.vue
@@ -1,16 +1,16 @@
|
||||
<!-- eslint-disable vue/no-v-html -->
|
||||
<template>
|
||||
<div>
|
||||
<Header />
|
||||
<Header v-if="!$route.path.startsWith('/examples')" :links="links" />
|
||||
|
||||
<NuxtLayout>
|
||||
<NuxtPage />
|
||||
</NuxtLayout>
|
||||
|
||||
<Footer />
|
||||
<Footer v-if="!$route.path.startsWith('/examples')" />
|
||||
|
||||
<ClientOnly>
|
||||
<LazyUDocsSearch ref="searchRef" :files="files" :navigation="navigation" :groups="groups" />
|
||||
<LazyUDocsSearch ref="searchRef" :files="files" :navigation="navigation" :groups="groups" :links="links" />
|
||||
</ClientOnly>
|
||||
|
||||
<UNotifications>
|
||||
@@ -42,10 +42,17 @@ const { data: files } = useLazyFetch<ParsedContent[]>('/api/search.json', { defa
|
||||
// Computed
|
||||
|
||||
const navigation = computed(() => {
|
||||
const main = nav.value.filter(item => item._path !== '/dev')
|
||||
const dev = nav.value.find(item => item._path === '/dev')?.children
|
||||
if (branch.value?.name === 'dev') {
|
||||
const dev = nav.value.find(item => item._path === '/dev')?.children
|
||||
const pro = nav.value.find(item => item._path === '/pro')
|
||||
|
||||
return branch.value?.name === 'dev' ? dev : main
|
||||
return [
|
||||
pro,
|
||||
...dev
|
||||
]
|
||||
}
|
||||
|
||||
return nav.value.filter(item => item._path !== '/dev')
|
||||
})
|
||||
|
||||
const groups = computed(() => {
|
||||
@@ -58,6 +65,54 @@ const groups = computed(() => {
|
||||
|
||||
const color = computed(() => colorMode.value === 'dark' ? '#18181b' : 'white')
|
||||
|
||||
const links = computed(() => {
|
||||
return [{
|
||||
label: 'Documentation',
|
||||
icon: 'i-heroicons-book-open',
|
||||
to: `${branch.value?.name === 'dev' ? '/dev' : ''}/getting-started`
|
||||
}, {
|
||||
label: 'Playground',
|
||||
icon: 'i-simple-icons-stackblitz',
|
||||
to: '/playground'
|
||||
}, {
|
||||
label: 'Roadmap',
|
||||
icon: 'i-heroicons-academic-cap',
|
||||
to: '/roadmap'
|
||||
}, {
|
||||
label: 'Pro',
|
||||
icon: 'i-heroicons-square-3-stack-3d',
|
||||
to: '/pro',
|
||||
children: [{
|
||||
label: 'Features',
|
||||
to: '/pro#features',
|
||||
exactHash: true,
|
||||
icon: 'i-heroicons-beaker',
|
||||
description: 'Discover all the features of Nuxt UI Pro.'
|
||||
}, {
|
||||
label: 'Pricing',
|
||||
to: '/pro#pricing',
|
||||
exactHash: true,
|
||||
icon: 'i-heroicons-credit-card',
|
||||
description: 'A simple pricing, for solo developers or teams.'
|
||||
}, {
|
||||
label: 'Guide',
|
||||
to: '/pro/guide',
|
||||
icon: 'i-heroicons-book-open',
|
||||
description: 'Learn how to use Nuxt UI Pro in your app.'
|
||||
}, {
|
||||
label: 'Components',
|
||||
to: '/pro/components',
|
||||
icon: 'i-heroicons-cube-transparent',
|
||||
description: 'Discover all the components available in Nuxt UI Pro.'
|
||||
}]
|
||||
}, {
|
||||
label: 'Releases',
|
||||
icon: 'i-heroicons-rocket-launch',
|
||||
to: 'https://github.com/nuxt/ui/releases',
|
||||
target: '_blank'
|
||||
}]
|
||||
})
|
||||
|
||||
// Watch
|
||||
|
||||
watch(() => searchRef.value?.commandPaletteRef?.query, debounce((query: string) => {
|
||||
|
||||
@@ -1,22 +1,16 @@
|
||||
<template>
|
||||
<div v-if="$route.path !== '/playground'" class="w-full h-px bg-gray-200 dark:bg-gray-800 flex items-center justify-center">
|
||||
<div class="bg-white dark:bg-gray-900 px-4">
|
||||
<div class="w-full h-px bg-gray-200 dark:bg-gray-800 flex items-center justify-center">
|
||||
<div v-if="!['/playground', '/roadmap'].includes($route.path)" class="bg-white dark:bg-gray-900 px-4">
|
||||
<LogoOnly class="w-5 h-5" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<UFooter :links="[]" :ui="{ bottom: { container: 'lg:py-4' } }">
|
||||
<UFooter>
|
||||
<template #left>
|
||||
<div class="text-sm text-gray-500 dark:text-gray-400">
|
||||
Made by
|
||||
<NuxtLink to="https://nuxtlabs.com" aria-label="NuxtLabs" class="inline-block">
|
||||
<LogoLabs class="text-gray-900 dark:text-white h-4 w-auto" />
|
||||
</NuxtLink>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #center>
|
||||
<span class="text-sm text-gray-500 dark:text-gray-400">
|
||||
<a v-if="$route.path.startsWith('/pro')" class="text-sm text-gray-500 dark:text-gray-400 hover:underline" href="https://ui.nuxt.com/pro/purchase" target="_blank">
|
||||
Purchase Nuxt UI Pro
|
||||
</a>
|
||||
<span v-else class="text-sm text-gray-500 dark:text-gray-400">
|
||||
Published under <NuxtLink to="https://github.com/nuxt/ui" target="_blank" class="text-gray-900 dark:text-white">
|
||||
MIT License
|
||||
</NuxtLink>
|
||||
|
||||
@@ -31,42 +31,35 @@
|
||||
</template>
|
||||
|
||||
<template #panel>
|
||||
<BranchSelect />
|
||||
<UAsideLinks :links="links" />
|
||||
|
||||
<UNavigationTree :links="mapContentNavigation(navigation)" />
|
||||
<UDivider type="dashed" class="mt-4 mb-3" />
|
||||
|
||||
<BranchSelect v-if="!route.path.startsWith('/pro')" />
|
||||
|
||||
<UNavigationTree :links="mapContentNavigation(navigation)" :multiple="false" default-open />
|
||||
</template>
|
||||
</UHeader>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { NavItem } from '@nuxt/content/dist/runtime/types'
|
||||
import type { Link } from '#ui-pro/types'
|
||||
|
||||
defineProps<{
|
||||
links: Link[]
|
||||
}>()
|
||||
|
||||
const route = useRoute()
|
||||
const { metaSymbol } = useShortcuts()
|
||||
|
||||
const navigation = inject<Ref<NavItem[]>>('navigation')
|
||||
const nav = inject<Ref<NavItem[]>>('navigation')
|
||||
|
||||
const links = computed(() => {
|
||||
return [{
|
||||
label: 'Documentation',
|
||||
icon: 'i-heroicons-book-open-solid',
|
||||
to: '/getting-started'
|
||||
}, {
|
||||
label: 'Examples',
|
||||
icon: 'i-heroicons-square-3-stack-3d',
|
||||
to: '/getting-started/examples'
|
||||
}, {
|
||||
label: 'Playground',
|
||||
icon: 'i-simple-icons-stackblitz',
|
||||
to: '/playground'
|
||||
}, {
|
||||
label: 'Pro',
|
||||
icon: 'i-heroicons-square-3-stack-3d',
|
||||
to: '/pro'
|
||||
}, {
|
||||
label: 'Releases',
|
||||
icon: 'i-heroicons-rocket-launch-solid',
|
||||
to: 'https://github.com/nuxt/ui/releases',
|
||||
target: '_blank'
|
||||
}]
|
||||
const navigation = computed(() => {
|
||||
if (route.path.startsWith('/pro')) {
|
||||
return nav.value.find(item => item._path === '/pro')?.children
|
||||
}
|
||||
|
||||
return nav.value.filter(item => !item._path.startsWith('/pro'))
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -36,8 +36,8 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex border border-b-0 border-gray-200 dark:border-gray-700 relative not-prose" :class="[{ 'p-4': padding }, propsToSelect.length ? 'border-t-0' : 'rounded-t-md', backgroundClass, overflowClass]">
|
||||
<component :is="name" v-model="vModel" v-bind="fullProps">
|
||||
<div class="flex border border-b-0 border-gray-200 dark:border-gray-700 relative not-prose" :class="[{ 'p-4': padding }, propsToSelect.length ? 'border-t-0' : 'rounded-t-md', backgroundClass, extraClass]">
|
||||
<component :is="name" v-model="vModel" v-bind="fullProps" :class="componentClass">
|
||||
<ContentSlot v-if="$slots.default" :use="$slots.default" />
|
||||
|
||||
<template v-for="slot in Object.keys(slots || {})" :key="slot" #[slot]>
|
||||
@@ -99,13 +99,17 @@ const props = defineProps({
|
||||
type: String,
|
||||
default: 'bg-white dark:bg-gray-900'
|
||||
},
|
||||
overflowClass: {
|
||||
extraClass: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
previewOnly: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
componentClass: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
})
|
||||
|
||||
@@ -116,10 +120,16 @@ const componentProps = reactive({ ...props.props })
|
||||
const { $prettier } = useNuxtApp()
|
||||
const appConfig = useAppConfig()
|
||||
const route = useRoute()
|
||||
// eslint-disable-next-line vue/no-dupe-keys
|
||||
const slug = props.slug || route.params.slug[route.params.slug.length - 1]
|
||||
const camelName = camelCase(slug)
|
||||
const name = `U${upperFirst(camelName)}`
|
||||
|
||||
let name = props.slug || `U${upperFirst(camelCase(route.params.slug[route.params.slug.length - 1]))}`
|
||||
|
||||
// TODO: Remove once merged on `main` branch
|
||||
if (['AvatarGroup', 'ButtonGroup', 'MeterGroup'].includes(name)) {
|
||||
name = `U${name}`
|
||||
}
|
||||
if (['avatar-group', 'button-group', 'radio'].includes(name)) {
|
||||
name = `U${upperFirst(camelCase(name))}`
|
||||
}
|
||||
|
||||
const meta = await fetchComponentMeta(name)
|
||||
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
<template>
|
||||
<div class="[&>div>pre]:!rounded-t-none [&>div>pre]:!mt-0">
|
||||
<div
|
||||
class="flex border border-gray-200 dark:border-gray-700 relative not-prose rounded-t-md"
|
||||
:class="[{ 'p-4': padding, 'rounded-b-md': !hasCode, 'border-b-0': hasCode }, backgroundClass, overflowClass]"
|
||||
class="flex border border-gray-200 dark:border-gray-700 relative rounded-t-md"
|
||||
:class="[{ 'p-4': padding, 'rounded-b-md': !hasCode, 'border-b-0': hasCode, 'not-prose': !prose }, backgroundClass, extraClass]"
|
||||
>
|
||||
<component :is="camelName" v-if="component" v-bind="componentProps" />
|
||||
<template v-if="component">
|
||||
<iframe v-if="iframe" :src="`/examples/${component}`" v-bind="iframeProps" :class="backgroundClass" class="w-full" />
|
||||
<component :is="camelName" v-else v-bind="componentProps" :class="componentClass" />
|
||||
</template>
|
||||
|
||||
<ContentSlot v-if="$slots.default" :use="$slots.default" />
|
||||
</div>
|
||||
<template v-if="hasCode">
|
||||
@@ -43,18 +47,36 @@ const props = defineProps({
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
prose: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
iframe: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
iframeProps: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
backgroundClass: {
|
||||
type: String,
|
||||
default: 'bg-white dark:bg-gray-900'
|
||||
},
|
||||
overflowClass: {
|
||||
extraClass: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
})
|
||||
|
||||
let component = props.component
|
||||
// TODO: Remove once merged on `main` branch
|
||||
if (['command-palette-theme-algolia', 'command-palette-theme-raycast', 'vertical-navigation-theme-tailwind', 'pagination-theme-rounded'].includes(component)) {
|
||||
component = component.replace('-theme', '-example-theme')
|
||||
}
|
||||
|
||||
const instance = getCurrentInstance()
|
||||
const camelName = camelCase(props.component)
|
||||
const camelName = camelCase(component)
|
||||
const data = await fetchContentExampleCode(camelName)
|
||||
|
||||
const hasCode = computed(() => !props.hiddenCode && (data?.code || instance.slots.code))
|
||||
|
||||
@@ -17,10 +17,16 @@ const props = defineProps({
|
||||
})
|
||||
|
||||
const route = useRoute()
|
||||
// eslint-disable-next-line vue/no-dupe-keys
|
||||
const slug = props.slug || route.params.slug[route.params.slug.length - 1]
|
||||
const camelName = camelCase(slug)
|
||||
const name = `U${upperFirst(camelName)}`
|
||||
|
||||
let name = props.slug || `U${upperFirst(camelCase(route.params.slug[route.params.slug.length - 1]))}`
|
||||
|
||||
// TODO: Remove once merged on `main` branch
|
||||
if (['AvatarGroup', 'ButtonGroup', 'MeterGroup'].includes(name)) {
|
||||
name = `U${name}`
|
||||
}
|
||||
if (['avatar-group', 'button-group', 'radio'].includes(name)) {
|
||||
name = `U${upperFirst(camelCase(name))}`
|
||||
}
|
||||
|
||||
const meta = await fetchComponentMeta(name)
|
||||
</script>
|
||||
|
||||
@@ -1,21 +1,24 @@
|
||||
<template>
|
||||
<Field v-bind="prop">
|
||||
<code v-if="prop.default">{{ prop.default }}</code>
|
||||
<p v-if="prop.description">
|
||||
{{ prop.description }}
|
||||
</p>
|
||||
|
||||
<Collapsible v-if="prop.schema?.kind === 'array' && prop.schema?.schema?.filter(schema => schema.kind === 'object').length">
|
||||
<FieldGroup v-for="schema in prop.schema.schema" :key="schema.name" class="!mt-0">
|
||||
<FieldGroup v-for="schema in prop.schema.schema" :key="schema.name">
|
||||
<ComponentPropsField v-for="subProp in Object.values(schema.schema)" :key="(subProp as any).name" :prop="subProp" />
|
||||
</FieldGroup>
|
||||
</Collapsible>
|
||||
<Collapsible v-else-if="prop.schema?.kind === 'array' && prop.schema?.schema?.filter(schema => schema.kind === 'array').length">
|
||||
<FieldGroup v-for="schema in prop.schema.schema" :key="schema.name" class="!mt-0">
|
||||
<FieldGroup v-for="schema in prop.schema.schema" :key="schema.name">
|
||||
<template v-for="subSchema in schema.schema" :key="subSchema.name">
|
||||
<ComponentPropsField v-for="subProp in Object.values(subSchema.schema)" :key="(subProp as any).name" :prop="subProp" />
|
||||
</template>
|
||||
</FieldGroup>
|
||||
</Collapsible>
|
||||
<Collapsible v-else-if="prop.schema?.kind === 'object' && prop.schema.type !== 'Function' && Object.values(prop.schema.schema)?.length">
|
||||
<FieldGroup class="!mt-0">
|
||||
<FieldGroup>
|
||||
<ComponentPropsField v-for="subProp in Object.values(prop.schema.schema)" :key="(subProp as any).name" :prop="subProp" />
|
||||
</FieldGroup>
|
||||
</Collapsible>
|
||||
|
||||
@@ -1,19 +1,8 @@
|
||||
<template>
|
||||
<div>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Slot</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="slot in (meta.meta.slots as any[])" :key="slot.name">
|
||||
<td class="whitespace-nowrap">
|
||||
<code>{{ slot.name }}</code>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<FieldGroup>
|
||||
<Field v-for="slot in meta?.meta.slots" :key="slot.name" v-bind="slot" />
|
||||
</FieldGroup>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -28,10 +17,8 @@ const props = defineProps({
|
||||
})
|
||||
|
||||
const route = useRoute()
|
||||
// eslint-disable-next-line vue/no-dupe-keys
|
||||
const slug = props.slug || route.params.slug[route.params.slug.length - 1]
|
||||
const camelName = camelCase(slug)
|
||||
const name = `U${upperFirst(camelName)}`
|
||||
|
||||
const name = props.slug || `U${upperFirst(camelCase(route.params.slug[route.params.slug.length - 1]))}`
|
||||
|
||||
const meta = await fetchComponentMeta(name)
|
||||
</script>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="relative overflow-hidden rounded border border-dashed border-gray-400 dark:border-gray-500 opacity-75">
|
||||
<div class="relative overflow-hidden rounded border border-dashed border-gray-400 dark:border-gray-500 opacity-75 px-4 flex items-center justify-center">
|
||||
<svg class="absolute inset-0 h-full w-full stroke-gray-900/10 dark:stroke-white/10" fill="none">
|
||||
<defs>
|
||||
<pattern
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
<template>
|
||||
<iframe :src="src" class="w-full min-h-[calc(100vh/1.5)] border border-gray-200 dark:border-gray-800 rounded-md" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const props = defineProps({
|
||||
token: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
})
|
||||
|
||||
const appConfig = useAppConfig()
|
||||
const colorMode = useColorMode()
|
||||
|
||||
const src = computed(() => `https://volta.net/embed/${props.token}?theme=${colorMode.value}&gray=${appConfig.ui.gray}&primary=${appConfig.ui.primary}`)
|
||||
</script>
|
||||
@@ -84,11 +84,11 @@ const pageFrom = computed(() => (page.value - 1) * pageCount.value + 1)
|
||||
const pageTo = computed(() => Math.min(page.value * pageCount.value, pageTotal.value))
|
||||
|
||||
// Data
|
||||
const { data: todos, pending } = await useLazyAsyncData('todos', () => $fetch<{
|
||||
const { data: todos, pending } = await useLazyAsyncData<{
|
||||
id: number
|
||||
title: string
|
||||
completed: string
|
||||
}[]>(`https://jsonplaceholder.typicode.com/todos${searchStatus.value}`, {
|
||||
}[]>('todos', () => ($fetch as any)(`https://jsonplaceholder.typicode.com/todos${searchStatus.value}`, {
|
||||
query: {
|
||||
q: search.value,
|
||||
'_page': page.value,
|
||||
|
||||
@@ -150,4 +150,13 @@ Update your `package.json` to the following:
|
||||
}
|
||||
```
|
||||
|
||||
```diff [package.json]
|
||||
{
|
||||
"devDependencies": {
|
||||
- "@nuxt/ui": "^2.9.0"
|
||||
+ "@nuxt/ui": "npm:@nuxt/ui-edge@latest"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Then run `pnpm install`, `yarn install` or `npm install`.
|
||||
|
||||
@@ -134,14 +134,14 @@ Here is some examples of what you can do with the [CommandPalette](/navigation/c
|
||||
::component-example
|
||||
---
|
||||
padding: false
|
||||
component: 'command-palette-theme-algolia'
|
||||
component: 'command-palette-example-theme-algolia'
|
||||
componentProps:
|
||||
class: 'max-h-[480px] rounded-md'
|
||||
hiddenCode: true
|
||||
---
|
||||
::
|
||||
|
||||
::callout{icon="i-simple-icons-github" to="https://github.com/nuxt/ui/blob/dev/docs/components/content/themes/CommandPaletteThemeAlgolia.vue#L23" target="_blank"}
|
||||
::callout{icon="i-simple-icons-github" to="https://github.com/nuxt/ui/blob/dev/docs/components/content/examples/CommandPaletteExampleThemeAlgolia.vue#L23" target="_blank"}
|
||||
Take a look at the component!
|
||||
::
|
||||
|
||||
@@ -150,24 +150,24 @@ Take a look at the component!
|
||||
::component-example
|
||||
---
|
||||
padding: false
|
||||
component: 'command-palette-theme-raycast'
|
||||
component: 'command-palette-example-theme-raycast'
|
||||
componentProps:
|
||||
class: 'max-h-[480px] rounded-md'
|
||||
hiddenCode: true
|
||||
---
|
||||
::
|
||||
|
||||
::callout{icon="i-simple-icons-github" to="https://github.com/nuxt/ui/blob/dev/docs/components/content/themes/CommandPaletteThemeRaycast.vue#L30" target="_blank"}
|
||||
::callout{icon="i-simple-icons-github" to="https://github.com/nuxt/ui/blob/dev/docs/components/content/examples/CommandPaletteExampleThemeRaycast.vue#L30" target="_blank"}
|
||||
Take a look at the component!
|
||||
::
|
||||
|
||||
### VerticalNavigation
|
||||
|
||||
:component-example{component="vertical-navigation-theme-tailwind"}
|
||||
:component-example{component="vertical-navigation-example-theme-tailwind"}
|
||||
|
||||
### Pagination
|
||||
|
||||
:component-example{component="pagination-theme-rounded"}
|
||||
:component-example{component="pagination-example-theme-rounded"}
|
||||
|
||||
## RTL Support
|
||||
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
---
|
||||
title: Roadmap
|
||||
description: Discover our Volta board for @nuxt/ui development status.
|
||||
toc: false
|
||||
---
|
||||
|
||||
:volta-embed{token="eyJ2aWV3IjoiYm9hcmQiLCJib2FyZFN0YXR1c2VzIjpbInRyaWFnZSIsImJhY2tsb2ciLCJ0b2RvIiwiaW5fcHJvZ3Jlc3MiLCJpbl9yZXZpZXciLCJkb25lIiwicmVsZWFzZWQiLCJjYW5jZWxsZWQiXSwiYm9hcmRMaW5rZWRQcnMiOnRydWUsImxpc3RHcm91cCI6InN0YXR1cyIsImxpc3RPcmRlciI6ImNyZWF0ZWRfYXQiLCJ0aW1lbGluZVpvb20iOiJtb250aCIsInRpbWVsaW5lT3JkZXIiOiJzdGF0ZSIsInRpbWVsaW5lRGlzcGxheSI6ImFsbF9taWxlc3RvbmVzIiwiZmlsdGVycyI6e30sIm93bmVyIjoibnV4dCIsIm5hbWUiOiJ1aSJ9"}
|
||||
@@ -117,7 +117,7 @@ To group multiple meters into a group, adding all values, use the `MeterGroup` c
|
||||
- To show a label for each meter, use the `label` prop on each meter.
|
||||
- To change the icon for each meter, use the `icon` prop.
|
||||
|
||||
::component-card{slug="MeterGroup"}
|
||||
::component-card{slug="UMeterGroup"}
|
||||
---
|
||||
baseProps:
|
||||
icon: i-heroicons-minus
|
||||
@@ -169,7 +169,7 @@ The `label` slot can be used to change how the label below the meter bar is show
|
||||
|
||||
:u-divider{label="MeterGroup" type="dashed" class="my-12"}
|
||||
|
||||
:component-props{slug="MeterGroup"}
|
||||
:component-props{slug="UMeterGroup"}
|
||||
|
||||
## Config
|
||||
|
||||
|
||||
@@ -90,7 +90,7 @@ To stack avatars as a group, use the `AvatarGroup` component.
|
||||
- To size all the avatars equally, pass the `size` prop
|
||||
- To adjust the spacing or the ring between avatars, customize with `ui.avatarGroup.margin` or `ui.avatarGroup.ring`
|
||||
|
||||
::component-card{slug="AvatarGroup"}
|
||||
::component-card{slug="UAvatarGroup"}
|
||||
---
|
||||
props:
|
||||
size: 'sm'
|
||||
@@ -113,10 +113,10 @@ code: |
|
||||
|
||||
:u-divider{label="AvatarGroup" type="dashed" class="my-12"}
|
||||
|
||||
:component-props{slug="avatar-group"}
|
||||
:component-props{slug="UAvatarGroup"}
|
||||
|
||||
## Config
|
||||
|
||||
:component-preset
|
||||
|
||||
:component-preset{slug="avatar-group"}
|
||||
:component-preset{slug="AvatarGroup"}
|
||||
|
||||
@@ -295,7 +295,7 @@ To stack buttons as a group, use the `ButtonGroup` component.
|
||||
- To change the orientation of the buttons, set the `orientation` prop to `vertical`
|
||||
- To adjust the rounded or the shadow around buttons, customize with `ui.buttonGroup.rounded` or `ui.buttonGroup.shadow`
|
||||
|
||||
::component-card{slug="ButtonGroup"}
|
||||
::component-card{slug="UButtonGroup"}
|
||||
---
|
||||
props:
|
||||
size: 'sm'
|
||||
@@ -312,7 +312,7 @@ code: |
|
||||
|
||||
This can also work with an [Input](/forms/input) component for example:
|
||||
|
||||
::component-card{slug="ButtonGroup"}
|
||||
::component-card{slug="UButtonGroup"}
|
||||
---
|
||||
props:
|
||||
size: 'sm'
|
||||
@@ -375,7 +375,7 @@ excludedProps:
|
||||
|
||||
:u-divider{label="ButtonGroup" type="dashed" class="my-12"}
|
||||
|
||||
:component-props{slug="ButtonGroup"}
|
||||
:component-props{slug="UButtonGroup"}
|
||||
|
||||
## Config
|
||||
|
||||
|
||||
@@ -75,7 +75,7 @@ This prop also work on the Radio component.
|
||||
|
||||
Use the `label` prop to display a label on the right of the Radio.
|
||||
|
||||
::component-card{slug="radio"}
|
||||
::component-card{slug="URadio"}
|
||||
---
|
||||
props:
|
||||
label: 'Label'
|
||||
@@ -86,7 +86,7 @@ props:
|
||||
|
||||
Use the `required` prop to display a red star next to the label of the Radio.
|
||||
|
||||
::component-card{slug="radio"}
|
||||
::component-card{slug="URadio"}
|
||||
---
|
||||
props:
|
||||
label: 'Label'
|
||||
@@ -98,7 +98,7 @@ props:
|
||||
|
||||
Use the `help` prop to display some text under the Radio.
|
||||
|
||||
::component-card{slug="radio"}
|
||||
::component-card{slug="URadio"}
|
||||
---
|
||||
props:
|
||||
label: 'Label'
|
||||
@@ -116,7 +116,7 @@ Use the `#label` slot to override the label of each option.
|
||||
|
||||
Alternatively, you can do the same with individual Radio:
|
||||
|
||||
::component-card{slug="radio"}
|
||||
::component-card{slug="URadio"}
|
||||
---
|
||||
slots:
|
||||
label: <span class="italic">Label</span>
|
||||
@@ -149,10 +149,10 @@ slots:
|
||||
|
||||
:u-divider{label="Radio" type="dashed" class="my-12"}
|
||||
|
||||
:component-props{slug="radio"}
|
||||
:component-props{slug="URadio"}
|
||||
|
||||
## Config
|
||||
|
||||
:component-preset
|
||||
|
||||
:component-preset{slug="radio"}
|
||||
:component-preset{slug="Radio"}
|
||||
|
||||
@@ -13,7 +13,6 @@ Use the `rows` prop to set the data to display in the table. By default, the tab
|
||||
::component-example{class="grid"}
|
||||
---
|
||||
padding: false
|
||||
overflowClass: 'overflow-x-auto'
|
||||
component: 'table-example-basic'
|
||||
componentProps:
|
||||
class: 'flex-1'
|
||||
@@ -33,7 +32,6 @@ Use the `columns` prop to configure which columns to display. It's an array of o
|
||||
::component-example{class="grid"}
|
||||
---
|
||||
padding: false
|
||||
overflowClass: 'overflow-x-auto'
|
||||
component: 'table-example-columns'
|
||||
componentProps:
|
||||
class: 'flex-1'
|
||||
@@ -45,7 +43,6 @@ You can easily use the [SelectMenu](/forms/select-menu) component to change the
|
||||
::component-example{class="grid"}
|
||||
---
|
||||
padding: false
|
||||
overflowClass: 'overflow-x-auto'
|
||||
component: 'table-example-columns-selectable'
|
||||
componentProps:
|
||||
class: 'flex-1'
|
||||
@@ -59,7 +56,6 @@ You can make the columns sortable by setting the `sortable` property to `true` i
|
||||
::component-example{class="grid"}
|
||||
---
|
||||
padding: false
|
||||
overflowClass: 'overflow-x-auto'
|
||||
component: 'table-example-columns-sortable'
|
||||
componentProps:
|
||||
class: 'flex-1'
|
||||
@@ -82,7 +78,6 @@ Use the `sort-button` prop to customize the sort button in the header. You can p
|
||||
::component-card{class="grid"}
|
||||
---
|
||||
padding: false
|
||||
overflowClass: 'overflow-x-auto'
|
||||
baseProps:
|
||||
class: 'w-full'
|
||||
columns:
|
||||
@@ -187,7 +182,6 @@ The initial value of `sort` will be respected as the initial sort column and dir
|
||||
::component-example{class="grid"}
|
||||
---
|
||||
padding: false
|
||||
overflowClass: 'overflow-x-auto'
|
||||
component: 'table-example-reactive-sorting'
|
||||
componentProps:
|
||||
class: 'flex-1'
|
||||
@@ -201,7 +195,6 @@ Use a `v-model` to make the table selectable. The `v-model` will be an array of
|
||||
::component-example{class="grid"}
|
||||
---
|
||||
padding: false
|
||||
overflowClass: 'overflow-x-auto'
|
||||
component: 'table-example-selectable'
|
||||
componentProps:
|
||||
class: 'flex-1'
|
||||
@@ -219,7 +212,6 @@ You can use this to navigate to a page, open a modal or even to select the row m
|
||||
::component-example{class="grid"}
|
||||
---
|
||||
padding: false
|
||||
overflowClass: 'overflow-x-auto'
|
||||
component: 'table-example-clickable'
|
||||
componentProps:
|
||||
class: 'flex-1'
|
||||
@@ -233,7 +225,6 @@ You can easily use the [Input](/forms/input) component to filter the rows.
|
||||
::component-example{class="grid"}
|
||||
---
|
||||
padding: false
|
||||
overflowClass: 'overflow-x-auto'
|
||||
component: 'table-example-searchable'
|
||||
componentProps:
|
||||
class: 'flex-1'
|
||||
@@ -247,7 +238,6 @@ You can easily use the [Pagination](/navigation/pagination) component to paginat
|
||||
::component-example{class="grid"}
|
||||
---
|
||||
padding: false
|
||||
overflowClass: 'overflow-x-auto'
|
||||
component: 'table-example-paginable'
|
||||
componentProps:
|
||||
class: 'flex-1'
|
||||
@@ -265,7 +255,6 @@ You can also set it to `null` to hide the loading state.
|
||||
::component-card
|
||||
---
|
||||
padding: false
|
||||
overflowClass: 'overflow-x-auto'
|
||||
baseProps:
|
||||
class: 'w-full'
|
||||
columns:
|
||||
@@ -314,7 +303,6 @@ You can also set it to `null` to hide the empty state.
|
||||
::component-card
|
||||
---
|
||||
padding: false
|
||||
overflowClass: 'overflow-x-auto'
|
||||
baseProps:
|
||||
class: 'w-full'
|
||||
columns:
|
||||
@@ -380,7 +368,6 @@ You can for example create an extra column for actions with a [Dropdown](/elemen
|
||||
::component-example{class="grid"}
|
||||
---
|
||||
padding: false
|
||||
overflowClass: 'overflow-x-auto'
|
||||
component: 'table-example-slots'
|
||||
componentProps:
|
||||
class: 'flex-1'
|
||||
@@ -394,7 +381,6 @@ Use the `#loading-state` slot to customize the loading state.
|
||||
::component-example{class="grid"}
|
||||
---
|
||||
padding: false
|
||||
overflowClass: 'overflow-x-auto'
|
||||
component: 'table-example-loading-slot'
|
||||
componentProps:
|
||||
class: 'flex-1'
|
||||
@@ -408,7 +394,6 @@ Use the `#empty-state` slot to customize the empty state.
|
||||
::component-example{class="grid"}
|
||||
---
|
||||
padding: false
|
||||
overflowClass: 'overflow-x-auto'
|
||||
component: 'table-example-empty-slot'
|
||||
componentProps:
|
||||
class: 'flex-1'
|
||||
|
||||
@@ -225,7 +225,6 @@ Use the `#empty-state` slot to customize the empty state.
|
||||
::component-example
|
||||
---
|
||||
padding: false
|
||||
overflowClass: 'overflow-x-auto'
|
||||
component: 'command-palette-example-empty-slot'
|
||||
componentProps:
|
||||
class: 'flex-1'
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
navigation: false
|
||||
title: 'Nuxt UI: Fully styled and customizable components for Nuxt'
|
||||
title: 'Nuxt UI: A UI Library for Modern Web Apps'
|
||||
description: 'It provides everything related to UI when building your Nuxt app. This includes components, icons, colors, dark mode but also keyboard shortcuts. Built with Headless UI and Tailwind CSS, published under MIT License.'
|
||||
hero:
|
||||
title: 'A <span class="text-primary">UI Library</span> for<br class="hidden lg:block"> Modern Web Apps'
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div>
|
||||
<Header />
|
||||
<Header :links="links" />
|
||||
|
||||
<UContainer>
|
||||
<UMain>
|
||||
@@ -11,7 +11,7 @@
|
||||
</UContainer>
|
||||
|
||||
<ClientOnly>
|
||||
<LazyUDocsSearch :files="files" :navigation="navigation" />
|
||||
<LazyUDocsSearch :files="files" :navigation="navigation" :links="links" />
|
||||
</ClientOnly>
|
||||
|
||||
<UNotifications />
|
||||
@@ -45,6 +45,54 @@ const navigation = computed(() => {
|
||||
return branch.value?.name === 'dev' ? dev : main
|
||||
})
|
||||
|
||||
const links = computed(() => {
|
||||
return [{
|
||||
label: 'Documentation',
|
||||
icon: 'i-heroicons-book-open',
|
||||
to: `${branch.value?.name === 'dev' ? '/dev' : ''}/getting-started`
|
||||
}, {
|
||||
label: 'Playground',
|
||||
icon: 'i-simple-icons-stackblitz',
|
||||
to: '/playground'
|
||||
}, {
|
||||
label: 'Roadmap',
|
||||
icon: 'i-heroicons-academic-cap',
|
||||
to: '/roadmap'
|
||||
}, {
|
||||
label: 'Pro',
|
||||
icon: 'i-heroicons-square-3-stack-3d',
|
||||
to: '/pro',
|
||||
children: [{
|
||||
label: 'Features',
|
||||
to: '/pro#features',
|
||||
exactHash: true,
|
||||
icon: 'i-heroicons-beaker',
|
||||
description: 'Discover all the features of Nuxt UI Pro.'
|
||||
}, {
|
||||
label: 'Pricing',
|
||||
to: '/pro#pricing',
|
||||
exactHash: true,
|
||||
icon: 'i-heroicons-credit-card',
|
||||
description: 'A simple pricing, for solo developers or teams.'
|
||||
}, {
|
||||
label: 'Guide',
|
||||
to: '/pro/guide',
|
||||
icon: 'i-heroicons-book-open',
|
||||
description: 'Learn how to use Nuxt UI Pro in your app.'
|
||||
}, {
|
||||
label: 'Components',
|
||||
to: '/pro/components',
|
||||
icon: 'i-heroicons-cube-transparent',
|
||||
description: 'Discover all the components available in Nuxt UI Pro.'
|
||||
}]
|
||||
}, {
|
||||
label: 'Releases',
|
||||
icon: 'i-heroicons-rocket-launch',
|
||||
to: 'https://github.com/nuxt/ui/releases',
|
||||
target: '_blank'
|
||||
}]
|
||||
})
|
||||
|
||||
// Provide
|
||||
|
||||
provide('navigation', navigation)
|
||||
|
||||
@@ -19,5 +19,7 @@
|
||||
<script setup lang="ts">
|
||||
import type { NavItem } from '@nuxt/content/dist/runtime/types'
|
||||
|
||||
const navigation = inject<NavItem[]>('navigation')
|
||||
const nav = inject<Ref<NavItem[]>>('navigation')
|
||||
|
||||
const navigation = computed(() => nav.value.filter(item => !item._path.startsWith('/pro')))
|
||||
</script>
|
||||
|
||||
@@ -74,11 +74,7 @@ export default defineNuxtModule({
|
||||
|
||||
nuxt.hook('components:extend', async (_components) => {
|
||||
components = _components
|
||||
.filter(
|
||||
(v) =>
|
||||
v.shortPath.startsWith('components/content/examples/') ||
|
||||
v.shortPath.startsWith('components/content/themes/')
|
||||
)
|
||||
.filter((v) => v.shortPath.includes('components/content/examples/'))
|
||||
.reduce((acc, component) => {
|
||||
acc[component.pascalName] = component
|
||||
return acc
|
||||
|
||||
@@ -8,7 +8,13 @@ const { resolve } = createResolver(import.meta.url)
|
||||
|
||||
export default defineNuxtConfig({
|
||||
// @ts-ignore
|
||||
extends: process.env.NUXT_UI_PRO_PATH || '@nuxt/ui-pro',
|
||||
extends: process.env.NUXT_UI_PRO_PATH ? [
|
||||
process.env.NUXT_UI_PRO_PATH,
|
||||
resolve(process.env.NUXT_UI_PRO_PATH, '.docs')
|
||||
] : [
|
||||
'@nuxt/ui-pro',
|
||||
process.env.NUXT_GITHUB_TOKEN && ['github:nuxt/ui-pro/.docs#dev', { giget: { auth: process.env.NUXT_GITHUB_TOKEN } }]
|
||||
].filter(Boolean),
|
||||
modules: [
|
||||
'@nuxt/content',
|
||||
'nuxt-og-image',
|
||||
@@ -30,7 +36,7 @@ export default defineNuxtConfig({
|
||||
},
|
||||
ui: {
|
||||
global: true,
|
||||
icons: ['heroicons', 'simple-icons'],
|
||||
icons: ['heroicons', 'logos', 'simple-icons'],
|
||||
safelistColors: excludeColors(colors)
|
||||
},
|
||||
content: {
|
||||
@@ -46,7 +52,19 @@ export default defineNuxtConfig({
|
||||
repo: 'nuxt/ui',
|
||||
branch: 'main',
|
||||
dir: 'docs/content'
|
||||
}
|
||||
},
|
||||
pro: process.env.NUXT_UI_PRO_PATH ? {
|
||||
prefix: '/pro',
|
||||
driver: 'fs',
|
||||
base: resolve(process.env.NUXT_UI_PRO_PATH, '.docs/content/pro')
|
||||
} : process.env.NUXT_GITHUB_TOKEN ? {
|
||||
prefix: '/pro',
|
||||
driver: 'github',
|
||||
repo: 'nuxt/ui-pro',
|
||||
branch: 'dev',
|
||||
dir: '.docs/content/pro',
|
||||
token: process.env.NUXT_GITHUB_TOKEN || ''
|
||||
} : undefined
|
||||
}
|
||||
},
|
||||
fontMetrics: {
|
||||
@@ -70,11 +88,20 @@ export default defineNuxtConfig({
|
||||
}
|
||||
},
|
||||
componentMeta: {
|
||||
globalsOnly: true,
|
||||
exclude: ['@nuxtjs/mdc', resolve('./components'), resolve('@nuxt/ui-pro/components')],
|
||||
exclude: [
|
||||
'@nuxt/content',
|
||||
'@nuxt/ui-templates',
|
||||
'@nuxtjs/color-mode',
|
||||
'@nuxtjs/mdc',
|
||||
'nuxt/dist',
|
||||
'nuxt-og-image',
|
||||
'nuxt-site-config',
|
||||
resolve('./components'),
|
||||
process.env.NUXT_UI_PRO_PATH ? resolve(process.env.NUXT_UI_PRO_PATH, '.docs', 'components') : '.c12'
|
||||
],
|
||||
metaFields: {
|
||||
props: true,
|
||||
slots: false,
|
||||
slots: true,
|
||||
events: false,
|
||||
exposed: false
|
||||
}
|
||||
@@ -87,7 +114,9 @@ export default defineNuxtConfig({
|
||||
// Related to https://github.com/nuxt/nuxt/pull/22558
|
||||
'components:extend': (components) => {
|
||||
components.forEach((component) => {
|
||||
if (component.global) {
|
||||
if (component.shortPath.includes(process.env.NUXT_UI_PRO_PATH || '@nuxt/ui-pro')) {
|
||||
component.global = true
|
||||
} else if (component.global) {
|
||||
component.global = 'sync'
|
||||
}
|
||||
})
|
||||
|
||||
@@ -6,22 +6,24 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@iconify-json/heroicons": "^1.1.13",
|
||||
"@iconify-json/logos": "^1.1.37",
|
||||
"@iconify-json/simple-icons": "^1.1.76",
|
||||
"@nuxt/content": "^2.8.5",
|
||||
"@nuxt/content": "^2.9.0",
|
||||
"@nuxt/devtools": "^1.0.0",
|
||||
"@nuxt/eslint-config": "^0.2.0",
|
||||
"@nuxt/ui-pro": "npm:@nuxt/ui-pro-edge@0.3.1-28304178.1b14f22",
|
||||
"@nuxthq/studio": "^1.0.2",
|
||||
"@nuxt/ui-pro": "^0.4.1",
|
||||
"@nuxthq/studio": "^1.0.3",
|
||||
"@nuxtjs/fontaine": "^0.4.1",
|
||||
"@nuxtjs/google-fonts": "^3.0.2",
|
||||
"@nuxtjs/mdc": "^0.2.6",
|
||||
"@nuxtjs/plausible": "^0.2.3",
|
||||
"@vueuse/nuxt": "^10.5.0",
|
||||
"eslint": "^8.52.0",
|
||||
"joi": "^17.11.0",
|
||||
"nuxt": "^3.8.0",
|
||||
"nuxt-cloudflare-analytics": "^1.0.8",
|
||||
"nuxt-component-meta": "^0.5.4",
|
||||
"nuxt-og-image": "^2.1.3",
|
||||
"nuxt-component-meta": "npm:nuxt-component-meta-edge@0.5.5-28315603.0a285c7",
|
||||
"nuxt-og-image": "^2.2.3",
|
||||
"prettier": "^3.0.3",
|
||||
"typescript": "^5.2.2",
|
||||
"ufo": "^1.3.1",
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
<hr v-if="surround?.length">
|
||||
|
||||
<UDocsSurround :surround="(surround as ParsedContent[])" />
|
||||
<UDocsSurround :surround="surround" />
|
||||
</UPageBody>
|
||||
|
||||
<template v-if="page.body?.toc?.links?.length" #right>
|
||||
@@ -26,7 +26,6 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { withoutTrailingSlash } from 'ufo'
|
||||
import type { ParsedContent } from '@nuxt/content/dist/runtime/types'
|
||||
|
||||
const route = useRoute()
|
||||
const { branch } = useContentSource()
|
||||
|
||||
11
docs/pages/examples/[...slug].vue
Normal file
11
docs/pages/examples/[...slug].vue
Normal file
@@ -0,0 +1,11 @@
|
||||
<template>
|
||||
<div class="p-4 flex flex-col justify-center h-screen overflow-auto">
|
||||
<component :is="name" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const route = useRoute()
|
||||
|
||||
const name = route.params.slug[0]
|
||||
</script>
|
||||
@@ -1,7 +1,19 @@
|
||||
<!-- eslint-disable vue/no-v-html -->
|
||||
<template>
|
||||
<div>
|
||||
<ULandingHero v-bind="page.hero" :ui="{ base: 'relative z-[1]', container: 'max-w-3xl' }" class="mb-[calc(var(--header-height)*2)]">
|
||||
<ULandingHero :ui="{ base: 'relative z-[1]', container: 'max-w-4xl' }" class="mb-[calc(var(--header-height)*2)]">
|
||||
<template #headline>
|
||||
<UBadge variant="subtle" size="md" class="hover:bg-primary-100 dark:bg-primary-950/100 dark:hover:bg-primary-900 transition-color relative font-medium rounded-full shadow-none">
|
||||
<NuxtLink :to="`https://github.com/nuxt/ui/releases/tag/v${config.version}`" target="_blank" class="focus:outline-none" tabindex="-1">
|
||||
<span class="absolute inset-0" aria-hidden="true" />
|
||||
</NuxtLink>
|
||||
|
||||
<span class="flex items-center gap-1">
|
||||
Nuxt UI {{ config.version.split('.').slice(0, -1).join('.') }} is out!
|
||||
</span>
|
||||
</UBadge>
|
||||
</template>
|
||||
|
||||
<template #title>
|
||||
<span v-html="page.hero?.title" />
|
||||
</template>
|
||||
@@ -72,16 +84,14 @@
|
||||
}"
|
||||
class="flex flex-col"
|
||||
>
|
||||
<div v-if="card.image">
|
||||
<UColorModeImage
|
||||
:light="`${card.image.path}-light.svg`"
|
||||
:dark="`${card.image.path}-dark.svg`"
|
||||
:width="card.image.width"
|
||||
:height="card.image.height"
|
||||
:alt="card.title"
|
||||
class="object-cover w-full"
|
||||
/>
|
||||
</div>
|
||||
<UColorModeImage
|
||||
:light="`${card.image.path}-light.svg`"
|
||||
:dark="`${card.image.path}-dark.svg`"
|
||||
:width="card.image.width"
|
||||
:height="card.image.height"
|
||||
:alt="card.title"
|
||||
class="object-cover w-full"
|
||||
/>
|
||||
</ULandingCard>
|
||||
</ULandingGrid>
|
||||
</template>
|
||||
@@ -199,6 +209,7 @@ const { data: module } = await useFetch<{
|
||||
|
||||
const source = ref('npm i @nuxt/ui')
|
||||
|
||||
const config = useRuntimeConfig().public
|
||||
const { copy, copied } = useClipboard({ source })
|
||||
const breakpoints = useBreakpoints(breakpointsTailwind)
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ defineOgImage({
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="h-[calc(100vh-var(--header-height))]">
|
||||
<div class="h-[calc(100vh-var(--header-height)-var(--header-height)-1px)]">
|
||||
<ClientOnly>
|
||||
<iframe :src="`https://stackblitz.com/edit/nuxt-ui?embed=1&file=app.config.ts,app.vue&theme=${$colorMode.preference}`" width="100%" height="100%" />
|
||||
</ClientOnly>
|
||||
|
||||
@@ -1,91 +0,0 @@
|
||||
<template>
|
||||
<UMain>
|
||||
<ULandingHero>
|
||||
<template #top>
|
||||
<svg class="hidden dark:block absolute inset-0 -z-10 h-full w-full stroke-white/5 [mask-image:radial-gradient(100%_100%_at_top,white,transparent)]" aria-hidden="true">
|
||||
<defs>
|
||||
<pattern
|
||||
id="983e3e4c-de6d-4c3f-8d64-b9761d1534cc"
|
||||
width="200"
|
||||
height="200"
|
||||
x="50%"
|
||||
y="-1"
|
||||
patternUnits="userSpaceOnUse"
|
||||
>
|
||||
<path d="M.5 200V.5H200" fill="none" />
|
||||
</pattern>
|
||||
</defs>
|
||||
<svg x="50%" y="-1" class="overflow-visible fill-gray-800/20">
|
||||
<path d="M-200 0h201v201h-201Z M600 0h201v201h-201Z M-400 600h201v201h-201Z M200 800h201v201h-201Z" stroke-width="0" />
|
||||
</svg>
|
||||
<rect width="100%" height="100%" stroke-width="0" fill="url(#983e3e4c-de6d-4c3f-8d64-b9761d1534cc)" />
|
||||
</svg>
|
||||
|
||||
<svg class="dark:hidden absolute inset-0 -z-10 h-full w-full stroke-gray-200 [mask-image:radial-gradient(100%_100%_at_top,white,transparent)]" aria-hidden="true">
|
||||
<defs>
|
||||
<pattern
|
||||
id="0787a7c5-978c-4f66-83c7-11c213f99cb7"
|
||||
width="200"
|
||||
height="200"
|
||||
x="50%"
|
||||
y="-1"
|
||||
patternUnits="userSpaceOnUse"
|
||||
>
|
||||
<path d="M.5 200V.5H200" fill="none" />
|
||||
</pattern>
|
||||
</defs>
|
||||
<rect width="100%" height="100%" stroke-width="0" fill="url(#0787a7c5-978c-4f66-83c7-11c213f99cb7)" />
|
||||
</svg>
|
||||
|
||||
<div class="absolute left-[calc(50%-4rem)] top-10 -z-10 transform-gpu blur-3xl sm:left-[calc(50%-18rem)] lg:left-48 lg:top-[calc(50%-30rem)] xl:left-[calc(50%-24rem)] right-0" aria-hidden="true">
|
||||
<div class="aspect-[1108/632] w-full bg-gradient-to-r from-[rgb(var(--color-primary-DEFAULT))] to-white/20 opacity-20" style="clip-path: polygon(73.6% 51.7%, 91.7% 11.8%, 100% 46.4%, 97.4% 82.2%, 92.5% 84.9%, 75.7% 64%, 55.3% 47.5%, 46.5% 49.4%, 45% 62.9%, 50.3% 87.2%, 21.3% 64.1%, 0.1% 100%, 5.4% 51.1%, 21.4% 63.9%, 58.9% 0.2%, 73.6% 51.7%)" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #badges>
|
||||
<UBadge color="primary" size="lg" variant="subtle">
|
||||
Coming Soon 🚀
|
||||
</UBadge>
|
||||
</template>
|
||||
|
||||
<template #links>
|
||||
<UButton
|
||||
trailing-icon="i-heroicons-arrow-right"
|
||||
color="gray"
|
||||
size="md"
|
||||
variant="solid"
|
||||
to="https://ui.nuxt.com/pro/purchase"
|
||||
>
|
||||
Early access
|
||||
</UButton>
|
||||
</template>
|
||||
|
||||
<template #title>
|
||||
The <span class="text-primary">Building Blocks</span> for<br>Modern Web Apps
|
||||
</template>
|
||||
|
||||
<template #description>
|
||||
Nuxt UI Pro is a collection of premium components built on top of Nuxt UI to create beautiful & responsive Nuxt applications in minutes.<br>It includes all primitives to build landing pages, documentation, blogs, changelog, dashboards or entire SaaS products.
|
||||
</template>
|
||||
|
||||
<MDC
|
||||
:value="pro.code"
|
||||
tag="pre"
|
||||
class="prose prose-primary dark:prose-invert max-w-none -mt-6"
|
||||
/>
|
||||
</ULandingHero>
|
||||
</UMain>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
const title = 'Nuxt UI Pro: The Building Blocks for Modern Web Apps'
|
||||
const description = 'Nuxt UI Pro is a collection of premium components built on top of Nuxt UI to create beautiful & responsive Nuxt applications in minutes. It includes all primitives to build landing pages, marketing pages, blogs, documentations or entire SaaS products.'
|
||||
|
||||
useSeoMeta({
|
||||
titleTemplate: '',
|
||||
title: title,
|
||||
ogTitle: `${title} - Nuxt UI`,
|
||||
description: description,
|
||||
ogDescription: description
|
||||
})
|
||||
</script>
|
||||
31
docs/pages/roadmap.vue
Normal file
31
docs/pages/roadmap.vue
Normal file
@@ -0,0 +1,31 @@
|
||||
<script setup>
|
||||
const title = 'Roadmap'
|
||||
const description = 'Discover our Volta board for @nuxt/ui development status.'
|
||||
|
||||
useSeoMeta({
|
||||
title,
|
||||
ogTitle: 'Nuxt UI Roadmap',
|
||||
description
|
||||
})
|
||||
|
||||
defineOgImage({
|
||||
component: 'Docs',
|
||||
title,
|
||||
description
|
||||
})
|
||||
|
||||
const appConfig = useAppConfig()
|
||||
const colorMode = useColorMode()
|
||||
|
||||
const token = 'eyJ2aWV3IjoiYm9hcmQiLCJib2FyZFN0YXR1c2VzIjpbInRyaWFnZSIsImJhY2tsb2ciLCJ0b2RvIiwiaW5fcHJvZ3Jlc3MiLCJpbl9yZXZpZXciLCJkb25lIiwicmVsZWFzZWQiXSwiYm9hcmRMaW5rZWRQcnMiOmZhbHNlLCJsaXN0R3JvdXAiOiJzdGF0ZSIsImxpc3RPcmRlciI6ImNyZWF0ZWRfYXQiLCJ0aW1lbGluZVpvb20iOiJtb250aCIsInRpbWVsaW5lT3JkZXIiOiJzdGF0ZSIsInRpbWVsaW5lRGlzcGxheSI6ImFsbF9taWxlc3RvbmVzIiwiZmlsdGVycyI6e30sIm93bmVyIjoibnV4dCIsIm5hbWUiOiJ1aSJ9'
|
||||
|
||||
const src = computed(() => `https://volta.net/embed/${token}?theme=${colorMode.value}&gray=${appConfig.ui.gray}&primary=${appConfig.ui.primary}`)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="h-[calc(100vh-var(--header-height)-var(--header-height)-1px)]">
|
||||
<ClientOnly>
|
||||
<iframe :src="src" width="100%" height="100%" />
|
||||
</ClientOnly>
|
||||
</div>
|
||||
</template>
|
||||
@@ -1,31 +0,0 @@
|
||||
export const pro = {
|
||||
code: `
|
||||
\`\`\`vue [app.vue]
|
||||
<script setup lang="ts">
|
||||
const links = [
|
||||
{ to: '/', label: 'Home' },
|
||||
{ to: '/about', label: 'About' },
|
||||
{ to: '/contact', label: 'Contact' }
|
||||
]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UHeader :links="links" />
|
||||
|
||||
<UMain>
|
||||
<ULandingHero title="Hello World" />
|
||||
|
||||
<ULandingSection title="Features">
|
||||
<UPageGrid>
|
||||
<ULandingCard title="First Card" />
|
||||
<ULandingCard title="Second Card" />
|
||||
<ULandingCard title="Third Card" />
|
||||
</UPageGrid>
|
||||
</ULandingSection>
|
||||
</UMain>
|
||||
|
||||
<UFooter />
|
||||
</template>
|
||||
\`\`\`
|
||||
`
|
||||
}
|
||||
Reference in New Issue
Block a user