docs: add version select (#532)

This commit is contained in:
Benjamin Canac
2023-08-14 22:11:04 +02:00
parent ee663157b7
commit 7e7e9d0f85
25 changed files with 198 additions and 45 deletions

View File

@@ -8,6 +8,8 @@
<UPage>
<template #left>
<UAside :links="anchors">
<BranchSelect />
<UNavigationTree :links="mapContentNavigation(navigation)" />
</UAside>
</template>
@@ -35,13 +37,27 @@
<script setup lang="ts">
const colorMode = useColorMode()
const { prefix, removePrefixFromNavigation, removePrefixFromFiles } = useContentSource()
const { mapContentNavigation } = useElementsHelpers()
const { data: navigation } = await useLazyAsyncData('navigation', () => fetchContentNavigation(), {
default: () => []
default: () => [],
transform: (navigation) => {
navigation = navigation.find(link => link._path === prefix.value)?.children || []
return prefix.value === '/main' ? removePrefixFromNavigation(navigation) : navigation
},
watch: [prefix]
})
const { data: files } = await useLazyAsyncData('files', () => queryContent().where({ _type: 'markdown', navigation: { $ne: false } }).find(), {
default: () => []
default: () => [],
transform: (files) => {
files = files.filter(file => file._path.startsWith(prefix.value))
return prefix.value === '/main' ? removePrefixFromFiles(files) : files
},
watch: [prefix]
})
const anchors = [{
@@ -89,4 +105,5 @@ useSeoMeta({
// Provide
provide('navigation', navigation)
provide('files', files)
</script>

View File

@@ -0,0 +1,50 @@
<template>
<div class="mb-3 lg:mb-6">
<label for="branch" class="block mb-1.5 font-semibold text-sm/6">Version</label>
<USelectMenu
id="branch"
:model-value="branch"
name="branch"
:options="branches"
color="gray"
:ui="{ icon: { trailing: { padding: { sm: 'pe-1.5' } } } }"
:ui-menu="{ option: { container: 'gap-1.5' } }"
@update:model-value="selectBranch"
>
<template #label>
<UIcon v-if="branch.icon" :name="branch.icon" class="w-4 h-4 flex-shrink-0 text-gray-600 dark:text-gray-300" />
<span class="font-medium">{{ branch.label }}</span>
<span class="truncate text-gray-400 dark:text-gray-500">{{ branch.suffix }}</span>
</template>
<template #option="{ option }">
<UIcon v-if="option.icon" :name="option.icon" class="w-4 h-4 flex-shrink-0 text-gray-600 dark:text-gray-300" />
<span class="font-medium">{{ option.label }}</span>
<span class="truncate text-gray-400 dark:text-gray-500">{{ option.suffix }}</span>
</template>
</USelectMenu>
</div>
</template>
<script setup lang="ts">
const route = useRoute()
const router = useRouter()
const { branches, branch } = useContentSource()
function selectBranch (branch) {
if (branch.name === 'dev') {
if (route.path.startsWith('/dev')) {
return
}
router.push(`/dev${route.path}`)
} else {
router.push(route.path.replace('/dev', ''))
}
}
</script>

View File

@@ -20,6 +20,8 @@
</template>
<template #panel>
<BranchSelect />
<UNavigationTree :links="mapContentNavigation(navigation)" />
</template>
</UHeader>

View File

@@ -115,7 +115,7 @@ const componentProps = reactive({ ...props.props })
const appConfig = useAppConfig()
const route = useRoute()
// eslint-disable-next-line vue/no-dupe-keys
const slug = props.slug || route.params.slug[1]
const slug = props.slug || route.params.slug[route.params.slug.length - 1]
const camelName = useCamelCase(slug)
const name = `U${useUpperFirst(camelName)}`

View File

@@ -16,7 +16,7 @@ const props = defineProps({
const appConfig = useAppConfig()
const route = useRoute()
// eslint-disable-next-line vue/no-dupe-keys
const slug = props.slug || route.params.slug[1]
const slug = props.slug || route.params.slug[route.params.slug.length - 1]
const camelName = useCamelCase(slug)
const name = `U${useUpperFirst(camelName)}`

View File

@@ -29,7 +29,7 @@ const props = defineProps({
const route = useRoute()
// eslint-disable-next-line vue/no-dupe-keys
const slug = props.slug || route.params.slug[1]
const slug = props.slug || route.params.slug[route.params.slug.length - 1]
const camelName = useCamelCase(slug)
const name = `U${useUpperFirst(camelName)}`

View File

@@ -27,7 +27,7 @@ const props = defineProps({
const route = useRoute()
// eslint-disable-next-line vue/no-dupe-keys
const slug = props.slug || route.params.slug[1]
const slug = props.slug || route.params.slug[route.params.slug.length - 1]
const camelName = useCamelCase(slug)
const name = `U${useUpperFirst(camelName)}`

View File

@@ -2,8 +2,7 @@
const commandPaletteRef = ref()
const navigation = inject('navigation')
const { data: files } = await useLazyAsyncData('search', () => queryContent().where({ _type: 'markdown' }).find(), { default: () => [] })
const files = inject('files')
const groups = computed(() => navigation.value.map(item => ({
key: item._path,

View File

@@ -0,0 +1,57 @@
import type { NavItem, ParsedContent } from '@nuxt/content/dist/runtime/types'
export const useContentSource = () => {
const route = useRoute()
const config = useRuntimeConfig().public
const branches = [{
name: 'dev',
icon: 'i-heroicons-cube',
suffix: 'dev',
label: 'Edge'
}, {
name: 'main',
icon: 'i-heroicons-cube',
suffix: 'latest',
label: `v${config.version}`
}]
const branch = computed(() => branches.find(b => b.name === (route.path.startsWith('/dev') ? 'dev' : 'main')))
const prefix = computed(() => `/${branch.value.name}`)
function removePrefixFromNavigation (navigation: NavItem[]): NavItem[] {
return navigation.map((link) => {
const { _path, children, ...rest } = link
return {
...rest,
_path: route.path.startsWith(prefix.value) ? _path : _path.replace(new RegExp(`^${prefix.value}`, 'g'), ''),
children: children?.length ? removePrefixFromNavigation(children) : undefined
}
})
}
function removePrefixFromFiles (files: ParsedContent[]) {
return files.map((file) => {
if (!file) {
return
}
const { _path, ...rest } = file
return {
...rest,
_path: route.path.startsWith(prefix.value) ? _path : _path.replace(new RegExp(`^${prefix.value}`, 'g'), '')
}
})
}
return {
branches,
branch,
prefix,
removePrefixFromNavigation,
removePrefixFromFiles
}
}

View File

@@ -37,7 +37,7 @@ Likewise, you can't define a `primary` color in your `tailwind.config.ts` as it
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`.
::
The `primary` color also has a `DEFAULT` shade that changes based on the theme. It is `500` in light mode and `400` in dark mode. You can use as a shortcut in your components and pages, e.g. `text-primary`, `bg-primary`, `focus-visible:ring-primary`, etc. :u-badge{label="Edge" class="!rounded-full" variant="subtle"}
The `primary` color also has a `DEFAULT` shade that changes based on the theme. It is `500` in light mode and `400` in dark mode. You can use as a shortcut in your components and pages, e.g. `text-primary`, `bg-primary`, `focus-visible:ring-primary`, etc. :u-badge{label="New" class="!rounded-full" variant="subtle"}
### Smart Safelisting
@@ -107,7 +107,7 @@ Each component has a `ui` prop that allows you to customize everything specifica
You can find the default classes for each component under the `Preset` section.
::
Thanks to [tailwind-merge](https://github.com/dcastil/tailwind-merge), the `ui` prop is smartly merged with the config. This means you don't have to rewrite everything. :u-badge{label="Edge" class="!rounded-full" variant="subtle"}
Thanks to [tailwind-merge](https://github.com/dcastil/tailwind-merge), the `ui` prop is smartly merged with the config. This means you don't have to rewrite everything. :u-badge{label="New" class="!rounded-full" variant="subtle"}
For example, the default preset of the `FormGroup` component looks like this:
@@ -142,7 +142,7 @@ You can also use the `class` attribute to add classes to the component.
</template>
```
Again, with [tailwind-merge](https://github.com/dcastil/tailwind-merge), this will smartly merge the classes with the `ui` prop and the config. :u-badge{label="Edge" class="!rounded-full" variant="subtle"}
Again, with [tailwind-merge](https://github.com/dcastil/tailwind-merge), this will smartly merge the classes with the `ui` prop and the config. :u-badge{label="New" class="!rounded-full" variant="subtle"}
### Default values

View File

@@ -4,8 +4,6 @@ links:
- label: GitHub
icon: i-simple-icons-github
to: https://github.com/nuxtlabs/ui/blob/dev/src/runtime/components/elements/Alert.vue
navigation:
badge: New
---
## Usage

View File

@@ -53,7 +53,7 @@ baseProps:
If there is an error loading the `src` of the avatar or `src` is null / false a background placeholder will be displayed, customizable in `ui.avatar.background`.
#### Icon :u-badge{label="Edge" class="ml-2 align-text-bottom !rounded-full" variant="subtle"}
#### Icon :u-badge{label="New" class="ml-2 align-text-bottom !rounded-full" variant="subtle"}
Use any icon from [Iconify](https://icones.js.org) by setting the `icon` prop by using this pattern: `i-{collection_name}-{icon_name}` or change it globally in `ui.avatar.default.icon` to display an icon on top of the background.

View File

@@ -31,7 +31,7 @@ props:
Use the `color` and `variant` props to change the visual style of the Badge.
- `variant` can be `solid` (default), `outline`, `soft` or `subtle`. :u-badge{label="New" class="!rounded-full" variant="subtle"}
- `variant` can be `solid` (default), `outline`, `soft` or `subtle`.
::component-card
---
@@ -45,7 +45,7 @@ Badge
Besides all the colors from the `ui.colors` object, you can also use the `white` and `black` colors with their pre-defined variants.
#### White :u-badge{label="New" class="ml-2 align-text-bottom !rounded-full" variant="subtle"}
#### White
::component-card
---
@@ -62,7 +62,7 @@ excludedProps:
Badge
::
#### Gray :u-badge{label="New" class="ml-2 align-text-bottom !rounded-full" variant="subtle"}
#### Gray
::component-card
---
@@ -79,7 +79,7 @@ excludedProps:
Badge
::
#### Black :u-badge{label="New" class="ml-2 align-text-bottom !rounded-full" variant="subtle"}
#### Black
::component-card
---

View File

@@ -5,8 +5,6 @@ links:
- label: GitHub
icon: i-simple-icons-github
to: https://github.com/nuxtlabs/ui/blob/dev/src/runtime/components/elements/Link.vue
navigation:
badge: New
---
## Usage

View File

@@ -4,8 +4,6 @@ links:
- label: GitHub
icon: i-simple-icons-github
to: https://github.com/nuxtlabs/ui/blob/dev/src/runtime/components/forms/Form.ts
navigation:
badge: New
---
## Usage

View File

@@ -108,7 +108,7 @@ const selected = ref(people[0])
```
::
If you only want to select a single object property rather than the whole object as value, you can set the `value-attribute` property. This prop defaults to `null`. :u-badge{label="New" class="!rounded-full" variant="subtle"}
If you only want to select a single object property rather than the whole object as value, you can set the `value-attribute` property. This prop defaults to `null`.
::component-example
#default

View File

@@ -159,7 +159,7 @@ code: >-
Learn more about form validation in the `Form` component.
::
### Size :u-badge{label="New" class="ml-2 align-text-bottom !rounded-full" variant="subtle"}
### Size
Use the `size` prop to change the size of the label and the form element.

View File

@@ -4,8 +4,6 @@ links:
- label: GitHub
icon: i-simple-icons-github
to: https://github.com/nuxtlabs/ui/blob/dev/src/runtime/components/navigation/Tabs.vue
navigation:
badge: New
---
## Usage
@@ -87,7 +85,7 @@ const items = [...]
This will have no effect if you are using a `v-model` to control the selected index.
::
### Listen to changes :u-badge{label="Edge" class="ml-2 align-text-bottom !rounded-full" variant="subtle"}
### Listen to changes :u-badge{label="New" class="ml-2 align-text-bottom !rounded-full" variant="subtle"}
You can listen to changes by using the `@change` event. The event will emit the index of the selected item.
@@ -113,7 +111,7 @@ function onChange (index) {
```
::
### Control the selected index :u-badge{label="Edge" class="ml-2 align-text-bottom !rounded-full" variant="subtle"}
### Control the selected index :u-badge{label="New" class="ml-2 align-text-bottom !rounded-full" variant="subtle"}
Use a `v-model` to control the selected index.

View File

@@ -316,7 +316,7 @@ excludedProps:
## Slots
### `title` / `description` :u-badge{label="New" class="ml-2 align-text-bottom !rounded-full" variant="subtle"}
### `title` / `description`
Use the `#title` and `#description` slots to customize the Notification.

View File

@@ -21,6 +21,8 @@
<script setup lang="ts">
import type { NuxtError } from '#app'
const { prefix, removePrefixFromNavigation, removePrefixFromFiles } = useContentSource()
useSeoMeta({
title: 'Page not found',
description: 'We are sorry but this page could not be found.'
@@ -30,14 +32,26 @@ defineProps<{
error: NuxtError
}>()
const { data: navigation } = await useAsyncData('navigation', () => fetchContentNavigation(), {
default: () => []
const { data: navigation } = await useLazyAsyncData('navigation', () => fetchContentNavigation(), {
default: () => [],
transform: (navigation) => {
navigation = navigation.find(link => link._path === prefix.value)?.children || []
return prefix.value === '/main' ? removePrefixFromNavigation(navigation) : navigation
}
})
const { data: files } = await useLazyAsyncData('files', () => queryContent().where({ _type: 'markdown', navigation: { $ne: false } }).find(), {
default: () => []
default: () => [],
transform: (files) => {
files = files.filter(file => file._path.startsWith(prefix.value))
return prefix.value === '/main' ? removePrefixFromFiles(files) : files
}
})
// Provide
provide('navigation', navigation)
provide('files', files)
</script>

View File

@@ -7,7 +7,7 @@ import pkg from '../package.json'
const { resolve } = createResolver(import.meta.url)
export default defineNuxtConfig({
extends: '@nuxthq/elements',
extends: process.env.NUXT_ELEMENTS_PATH || '@nuxthq/elements',
modules: [
'@nuxt/content',
// '@nuxt/devtools',
@@ -30,6 +30,23 @@ export default defineNuxtConfig({
icons: ['heroicons', 'simple-icons'],
safelistColors: excludeColors(colors)
},
content: {
sources: {
// overwrite default source AKA `content` directory
content: {
prefix: '/dev',
driver: 'fs',
base: resolve('./content')
},
main: {
prefix: '/main',
driver: 'github',
repo: 'nuxtlabs/ui',
branch: 'main',
dir: 'docs/content'
}
}
},
googleFonts: {
families: {
Inter: [400, 500, 600, 700]
@@ -40,7 +57,7 @@ export default defineNuxtConfig({
},
nitro: {
prerender: {
routes: ['/getting-started']
routes: ['/getting-started', '/dev/getting-started']
}
},
experimental: {

View File

@@ -10,7 +10,7 @@
"@nuxt/content": "^2.7.2",
"@nuxt/devtools": "^0.8.0",
"@nuxt/eslint-config": "^0.1.1",
"@nuxthq/elements": "npm:@nuxthq/elements-edge@0.0.1-28197629.5e2d155",
"@nuxthq/elements": "npm:@nuxthq/elements-edge@0.0.1-28198976.e8e2f70",
"@nuxthq/studio": "^0.13.4",
"@nuxtjs/fontaine": "^0.4.1",
"@nuxtjs/google-fonts": "^3.0.2",

View File

@@ -11,7 +11,7 @@
<hr v-if="surround?.length" class="my-8">
<UDocsSurround :surround="surround" />
<UDocsSurround :surround="removePrefixFromFiles(surround)" />
<Footer class="not-prose" />
</UPageBody>
@@ -24,17 +24,21 @@
<script setup lang="ts">
const route = useRoute()
const { prefix, removePrefixFromFiles } = useContentSource()
const { findPageHeadline } = useElementsHelpers()
const { data: page } = await useAsyncData(`docs-${route.path}`, () => queryContent(route.path).findOne())
const path = computed(() => route.path.startsWith(prefix.value) ? route.path : `${prefix.value}${route.path}`)
const { data: page } = await useAsyncData(path.value, () => queryContent(path.value).findOne())
if (!page.value) {
throw createError({ statusCode: 404, statusMessage: 'Page not found' })
}
const { data: surround } = await useAsyncData(`docs-${route.path}-surround`, () => queryContent()
.where({ _extension: 'md', navigation: { $ne: false } })
.findSurround(route.path.endsWith('/') ? route.path.slice(0, -1) : route.path)
)
const { data: surround } = await useAsyncData(`${path.value}-surround`, () => {
return queryContent(prefix.value)
.where({ _extension: 'md', navigation: { $ne: false } })
.findSurround((path.value.endsWith('/') ? path.value.slice(0, -1) : path.value))
})
useContentHead(page)

1
docs/public/robots.txt Normal file
View File

@@ -0,0 +1 @@
Disallow: /dev/*

8
pnpm-lock.yaml generated
View File

@@ -121,8 +121,8 @@ importers:
specifier: ^0.1.1
version: 0.1.1(eslint@8.47.0)
'@nuxthq/elements':
specifier: npm:@nuxthq/elements-edge@0.0.1-28197629.5e2d155
version: /@nuxthq/elements-edge@0.0.1-28197629.5e2d155(@nuxt/content@2.7.2)(@nuxthq/ui@)(vue@3.3.4)
specifier: npm:@nuxthq/elements-edge@0.0.1-28198976.e8e2f70
version: /@nuxthq/elements-edge@0.0.1-28198976.e8e2f70(@nuxt/content@2.7.2)(@nuxthq/ui@)(vue@3.3.4)
'@nuxthq/studio':
specifier: ^0.13.4
version: 0.13.4(rollup@3.26.2)
@@ -1852,8 +1852,8 @@ packages:
- vue-tsc
dev: true
/@nuxthq/elements-edge@0.0.1-28197629.5e2d155(@nuxt/content@2.7.2)(@nuxthq/ui@)(vue@3.3.4):
resolution: {integrity: sha512-Kge09WmdOopvvmbuEHoC04zvUa2CnRANH3gg+rnKEaM3rhaBe7s8b8jGzJTWyKIIs1Fz53lrd80feigF7tG84A==}
/@nuxthq/elements-edge@0.0.1-28198976.e8e2f70(@nuxt/content@2.7.2)(@nuxthq/ui@)(vue@3.3.4):
resolution: {integrity: sha512-i3d+HD6JaA7hSgQGkaAS36rSqHWUwa7550KqRIpyOs3VsJ/gT9ry8NW1dRpNamUnGAJqhAt6Btr4NyXDKPfJdQ==}
peerDependencies:
'@nuxt/content': ^2.7.2
'@nuxthq/ui': npm:@nuxthq/ui-edge@latest