Skip to content

Commit 844b318

Browse files
benjamincanacpi0Floscianteatinux
authored
docs: integrate @nuxt/ui-pro (nuxt#739)
Co-authored-by: Pooya Parsa <[email protected]> Co-authored-by: Florent Delerue <[email protected]> Co-authored-by: Sébastien Chopin <[email protected]>
1 parent ed4b5e0 commit 844b318

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+606
-497
lines changed

.github/workflows/ci-dev.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ jobs:
2121
os: [ubuntu-latest] # macos-latest, windows-latest
2222
node: [18]
2323

24+
env:
25+
NUXT_GITHUB_TOKEN: ${{ secrets.NUXT_GITHUB_TOKEN }}
26+
2427
steps:
2528
- uses: actions/setup-node@v4
2629
with:

.github/workflows/ci.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ jobs:
1414
os: [ubuntu-latest] # macos-latest, windows-latest
1515
node: [18]
1616

17+
env:
18+
NUXT_GITHUB_TOKEN: ${{ secrets.NUXT_GITHUB_TOKEN }}
19+
1720
steps:
1821
- uses: actions/setup-node@v4
1922
with:

.vscode/settings.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"prettier.enable": false
3+
}

docs/.env.example

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1-
# To link Nuxt UI Pro in development
1+
# Specify the path of @nuxt/ui-pro locally
22
NUXT_UI_PRO_PATH=
3-
# To use Nuxt UI Pro in production
4-
NUXT_UI_PRO_TOKEN=
3+
# Production token for @nuxt/ui-pro, purchase on https://ui.nuxt.com/pro/purchase
4+
NUXT_UI_PRO_LICENSE=
55
# Used when pre-rendering the docs for dynamic OG images
66
NUXT_PUBLIC_SITE_URL=
7+
# Used to fetch `nuxt/ui-pro` docs content
8+
NUXT_GITHUB_TOKEN=

docs/app.vue

Lines changed: 61 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
<!-- eslint-disable vue/no-v-html -->
22
<template>
33
<div>
4-
<Header />
4+
<Header v-if="!$route.path.startsWith('/examples')" :links="links" />
55

66
<NuxtLayout>
77
<NuxtPage />
88
</NuxtLayout>
99

10-
<Footer />
10+
<Footer v-if="!$route.path.startsWith('/examples')" />
1111

1212
<ClientOnly>
13-
<LazyUDocsSearch ref="searchRef" :files="files" :navigation="navigation" :groups="groups" />
13+
<LazyUDocsSearch ref="searchRef" :files="files" :navigation="navigation" :groups="groups" :links="links" />
1414
</ClientOnly>
1515

1616
<UNotifications>
@@ -42,10 +42,17 @@ const { data: files } = useLazyFetch<ParsedContent[]>('/api/search.json', { defa
4242
// Computed
4343
4444
const navigation = computed(() => {
45-
const main = nav.value.filter(item => item._path !== '/dev')
46-
const dev = nav.value.find(item => item._path === '/dev')?.children
45+
if (branch.value?.name === 'dev') {
46+
const dev = nav.value.find(item => item._path === '/dev')?.children
47+
const pro = nav.value.find(item => item._path === '/pro')
48+
49+
return [
50+
pro,
51+
...dev
52+
]
53+
}
4754
48-
return branch.value?.name === 'dev' ? dev : main
55+
return nav.value.filter(item => item._path !== '/dev')
4956
})
5057
5158
const groups = computed(() => {
@@ -58,6 +65,54 @@ const groups = computed(() => {
5865
5966
const color = computed(() => colorMode.value === 'dark' ? '#18181b' : 'white')
6067
68+
const links = computed(() => {
69+
return [{
70+
label: 'Documentation',
71+
icon: 'i-heroicons-book-open',
72+
to: `${branch.value?.name === 'dev' ? '/dev' : ''}/getting-started`
73+
}, {
74+
label: 'Playground',
75+
icon: 'i-simple-icons-stackblitz',
76+
to: '/playground'
77+
}, {
78+
label: 'Roadmap',
79+
icon: 'i-heroicons-academic-cap',
80+
to: '/roadmap'
81+
}, {
82+
label: 'Pro',
83+
icon: 'i-heroicons-square-3-stack-3d',
84+
to: '/pro',
85+
children: [{
86+
label: 'Features',
87+
to: '/pro#features',
88+
exactHash: true,
89+
icon: 'i-heroicons-beaker',
90+
description: 'Discover all the features of Nuxt UI Pro.'
91+
}, {
92+
label: 'Pricing',
93+
to: '/pro#pricing',
94+
exactHash: true,
95+
icon: 'i-heroicons-credit-card',
96+
description: 'A simple pricing, for solo developers or teams.'
97+
}, {
98+
label: 'Guide',
99+
to: '/pro/guide',
100+
icon: 'i-heroicons-book-open',
101+
description: 'Learn how to use Nuxt UI Pro in your app.'
102+
}, {
103+
label: 'Components',
104+
to: '/pro/components',
105+
icon: 'i-heroicons-cube-transparent',
106+
description: 'Discover all the components available in Nuxt UI Pro.'
107+
}]
108+
}, {
109+
label: 'Releases',
110+
icon: 'i-heroicons-rocket-launch',
111+
to: 'https://github.com/nuxt/ui/releases',
112+
target: '_blank'
113+
}]
114+
})
115+
61116
// Watch
62117
63118
watch(() => searchRef.value?.commandPaletteRef?.query, debounce((query: string) => {

docs/components/Footer.vue

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,16 @@
11
<template>
2-
<div v-if="$route.path !== '/playground'" class="w-full h-px bg-gray-200 dark:bg-gray-800 flex items-center justify-center">
3-
<div class="bg-white dark:bg-gray-900 px-4">
2+
<div class="w-full h-px bg-gray-200 dark:bg-gray-800 flex items-center justify-center">
3+
<div v-if="!['/playground', '/roadmap'].includes($route.path)" class="bg-white dark:bg-gray-900 px-4">
44
<LogoOnly class="w-5 h-5" />
55
</div>
66
</div>
77

8-
<UFooter :links="[]" :ui="{ bottom: { container: 'lg:py-4' } }">
8+
<UFooter>
99
<template #left>
10-
<div class="text-sm text-gray-500 dark:text-gray-400">
11-
Made by
12-
<NuxtLink to="https://nuxtlabs.com" aria-label="NuxtLabs" class="inline-block">
13-
<LogoLabs class="text-gray-900 dark:text-white h-4 w-auto" />
14-
</NuxtLink>
15-
</div>
16-
</template>
17-
18-
<template #center>
19-
<span class="text-sm text-gray-500 dark:text-gray-400">
10+
<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">
11+
Purchase Nuxt UI Pro
12+
</a>
13+
<span v-else class="text-sm text-gray-500 dark:text-gray-400">
2014
Published under <NuxtLink to="https://github.com/nuxt/ui" target="_blank" class="text-gray-900 dark:text-white">
2115
MIT License
2216
</NuxtLink>

docs/components/Header.vue

Lines changed: 19 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -31,42 +31,35 @@
3131
</template>
3232

3333
<template #panel>
34-
<BranchSelect />
34+
<UAsideLinks :links="links" />
3535

36-
<UNavigationTree :links="mapContentNavigation(navigation)" />
36+
<UDivider type="dashed" class="mt-4 mb-3" />
37+
38+
<BranchSelect v-if="!route.path.startsWith('/pro')" />
39+
40+
<UNavigationTree :links="mapContentNavigation(navigation)" :multiple="false" default-open />
3741
</template>
3842
</UHeader>
3943
</template>
4044

4145
<script setup lang="ts">
4246
import type { NavItem } from '@nuxt/content/dist/runtime/types'
47+
import type { Link } from '#ui-pro/types'
4348
49+
defineProps<{
50+
links: Link[]
51+
}>()
52+
53+
const route = useRoute()
4454
const { metaSymbol } = useShortcuts()
4555
46-
const navigation = inject<Ref<NavItem[]>>('navigation')
56+
const nav = inject<Ref<NavItem[]>>('navigation')
57+
58+
const navigation = computed(() => {
59+
if (route.path.startsWith('/pro')) {
60+
return nav.value.find(item => item._path === '/pro')?.children
61+
}
4762
48-
const links = computed(() => {
49-
return [{
50-
label: 'Documentation',
51-
icon: 'i-heroicons-book-open-solid',
52-
to: '/getting-started'
53-
}, {
54-
label: 'Examples',
55-
icon: 'i-heroicons-square-3-stack-3d',
56-
to: '/getting-started/examples'
57-
}, {
58-
label: 'Playground',
59-
icon: 'i-simple-icons-stackblitz',
60-
to: '/playground'
61-
}, {
62-
label: 'Pro',
63-
icon: 'i-heroicons-square-3-stack-3d',
64-
to: '/pro'
65-
}, {
66-
label: 'Releases',
67-
icon: 'i-heroicons-rocket-launch-solid',
68-
to: 'https://github.com/nuxt/ui/releases',
69-
target: '_blank'
70-
}]
63+
return nav.value.filter(item => !item._path.startsWith('/pro'))
7164
})
7265
</script>

docs/components/content/ComponentCard.vue

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@
3636
</div>
3737
</div>
3838

39-
<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]">
40-
<component :is="name" v-model="vModel" v-bind="fullProps">
39+
<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]">
40+
<component :is="name" v-model="vModel" v-bind="fullProps" :class="componentClass">
4141
<ContentSlot v-if="$slots.default" :use="$slots.default" />
4242

4343
<template v-for="slot in Object.keys(slots || {})" :key="slot" #[slot]>
@@ -99,13 +99,17 @@ const props = defineProps({
9999
type: String,
100100
default: 'bg-white dark:bg-gray-900'
101101
},
102-
overflowClass: {
102+
extraClass: {
103103
type: String,
104104
default: ''
105105
},
106106
previewOnly: {
107107
type: Boolean,
108108
default: false
109+
},
110+
componentClass: {
111+
type: String,
112+
default: ''
109113
}
110114
})
111115
@@ -116,10 +120,16 @@ const componentProps = reactive({ ...props.props })
116120
const { $prettier } = useNuxtApp()
117121
const appConfig = useAppConfig()
118122
const route = useRoute()
119-
// eslint-disable-next-line vue/no-dupe-keys
120-
const slug = props.slug || route.params.slug[route.params.slug.length - 1]
121-
const camelName = camelCase(slug)
122-
const name = `U${upperFirst(camelName)}`
123+
124+
let name = props.slug || `U${upperFirst(camelCase(route.params.slug[route.params.slug.length - 1]))}`
125+
126+
// TODO: Remove once merged on `main` branch
127+
if (['AvatarGroup', 'ButtonGroup', 'MeterGroup'].includes(name)) {
128+
name = `U${name}`
129+
}
130+
if (['avatar-group', 'button-group', 'radio'].includes(name)) {
131+
name = `U${upperFirst(camelCase(name))}`
132+
}
123133
124134
const meta = await fetchComponentMeta(name)
125135

docs/components/content/ComponentExample.vue

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
<template>
22
<div class="[&>div>pre]:!rounded-t-none [&>div>pre]:!mt-0">
33
<div
4-
class="flex border border-gray-200 dark:border-gray-700 relative not-prose rounded-t-md"
5-
:class="[{ 'p-4': padding, 'rounded-b-md': !hasCode, 'border-b-0': hasCode }, backgroundClass, overflowClass]"
4+
class="flex border border-gray-200 dark:border-gray-700 relative rounded-t-md"
5+
:class="[{ 'p-4': padding, 'rounded-b-md': !hasCode, 'border-b-0': hasCode, 'not-prose': !prose }, backgroundClass, extraClass]"
66
>
7-
<component :is="camelName" v-if="component" v-bind="componentProps" />
7+
<template v-if="component">
8+
<iframe v-if="iframe" :src="`/examples/${component}`" v-bind="iframeProps" :class="backgroundClass" class="w-full" />
9+
<component :is="camelName" v-else v-bind="componentProps" :class="componentClass" />
10+
</template>
11+
812
<ContentSlot v-if="$slots.default" :use="$slots.default" />
913
</div>
1014
<template v-if="hasCode">
@@ -43,18 +47,36 @@ const props = defineProps({
4347
type: Boolean,
4448
default: true
4549
},
50+
prose: {
51+
type: Boolean,
52+
default: false
53+
},
54+
iframe: {
55+
type: Boolean,
56+
default: false
57+
},
58+
iframeProps: {
59+
type: Object,
60+
default: () => ({})
61+
},
4662
backgroundClass: {
4763
type: String,
4864
default: 'bg-white dark:bg-gray-900'
4965
},
50-
overflowClass: {
66+
extraClass: {
5167
type: String,
5268
default: ''
5369
}
5470
})
5571
72+
let component = props.component
73+
// TODO: Remove once merged on `main` branch
74+
if (['command-palette-theme-algolia', 'command-palette-theme-raycast', 'vertical-navigation-theme-tailwind', 'pagination-theme-rounded'].includes(component)) {
75+
component = component.replace('-theme', '-example-theme')
76+
}
77+
5678
const instance = getCurrentInstance()
57-
const camelName = camelCase(props.component)
79+
const camelName = camelCase(component)
5880
const data = await fetchContentExampleCode(camelName)
5981
6082
const hasCode = computed(() => !props.hiddenCode && (data?.code || instance.slots.code))

docs/components/content/ComponentProps.vue

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,16 @@ const props = defineProps({
1717
})
1818
1919
const route = useRoute()
20-
// eslint-disable-next-line vue/no-dupe-keys
21-
const slug = props.slug || route.params.slug[route.params.slug.length - 1]
22-
const camelName = camelCase(slug)
23-
const name = `U${upperFirst(camelName)}`
20+
21+
let name = props.slug || `U${upperFirst(camelCase(route.params.slug[route.params.slug.length - 1]))}`
22+
23+
// TODO: Remove once merged on `main` branch
24+
if (['AvatarGroup', 'ButtonGroup', 'MeterGroup'].includes(name)) {
25+
name = `U${name}`
26+
}
27+
if (['avatar-group', 'button-group', 'radio'].includes(name)) {
28+
name = `U${upperFirst(camelCase(name))}`
29+
}
2430
2531
const meta = await fetchComponentMeta(name)
2632
</script>

0 commit comments

Comments
 (0)