mirror of
https://github.com/ArthurDanjou/ui.git
synced 2026-01-15 12:39:35 +01:00
Compare commits
93 Commits
chore/comp
...
fix/sfc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c532a6f930 | ||
|
|
6bbcb40c9e | ||
|
|
befda895b9 | ||
|
|
d227a105d8 | ||
|
|
f6ff157bc4 | ||
|
|
21fbd07639 | ||
|
|
de234e8aeb | ||
|
|
95a7707963 | ||
|
|
24b54f6d9a | ||
|
|
b3e37688d9 | ||
|
|
eeba3b4049 | ||
|
|
a0c9731f63 | ||
|
|
af1bf1bbde | ||
|
|
54a7d04217 | ||
|
|
dfa2113db4 | ||
|
|
abe0859691 | ||
|
|
cf91f3c4cf | ||
|
|
175fc73e63 | ||
|
|
1d459803dc | ||
|
|
60e2ee9a6c | ||
|
|
7f1c6caa6e | ||
|
|
7ac17ae7e8 | ||
|
|
52a97e2df7 | ||
|
|
041989549a | ||
|
|
31c37ce1a1 | ||
|
|
74cb2c3769 | ||
|
|
5025e15d14 | ||
|
|
36c24ffe5c | ||
|
|
b3a6b861cd | ||
|
|
c21eb32c70 | ||
|
|
44e6ba039d | ||
|
|
ef75610244 | ||
|
|
ffafd81e1e | ||
|
|
06414d344b | ||
|
|
cb193f1d25 | ||
|
|
4d8179ba08 | ||
|
|
ce767c8429 | ||
|
|
1ae5cc09cb | ||
|
|
9d2fed1250 | ||
|
|
924515ad07 | ||
|
|
4d138ad671 | ||
|
|
615fcfd73b | ||
|
|
f5e62849c9 | ||
|
|
f25fed58e9 | ||
|
|
ca15bc0c75 | ||
|
|
29f004db95 | ||
|
|
97274f15b8 | ||
|
|
8471fb9fa4 | ||
|
|
9ec159e207 | ||
|
|
0456670dac | ||
|
|
f05dbd26d1 | ||
|
|
9be36d328c | ||
|
|
4f28e1fe96 | ||
|
|
bd99c2d850 | ||
|
|
23bfeb9370 | ||
|
|
88f349d0d7 | ||
|
|
e7e6745599 | ||
|
|
d2c832292a | ||
|
|
bc61d29cce | ||
|
|
777fe4a309 | ||
|
|
3074632523 | ||
|
|
94b6e520f5 | ||
|
|
754dd36473 | ||
|
|
67a52b6f4e | ||
|
|
2e7d4989b5 | ||
|
|
c07a79571f | ||
|
|
4cebdb5152 | ||
|
|
06dfb963be | ||
|
|
4ebb94cd7e | ||
|
|
afff54fecd | ||
|
|
7ec08017e0 | ||
|
|
3dd88bacec | ||
|
|
d6d7971d44 | ||
|
|
20c33920d0 | ||
|
|
a63047b79a | ||
|
|
f3e32ba5a2 | ||
|
|
bd3f54aa80 | ||
|
|
9509c37af8 | ||
|
|
df00149598 | ||
|
|
f72c886d3a | ||
|
|
c531d0248b | ||
|
|
d73768b704 | ||
|
|
b9983549a4 | ||
|
|
370054b20c | ||
|
|
4a2b77d86c | ||
|
|
ade16b76cf | ||
|
|
1babad4f74 | ||
|
|
8fb8dc29cf | ||
|
|
e0ec60d1b1 | ||
|
|
3db3058395 | ||
|
|
0095d8916b | ||
|
|
58ae62413d | ||
|
|
1965495768 |
3
.github/workflows/module.yml
vendored
3
.github/workflows/module.yml
vendored
@@ -160,6 +160,9 @@ jobs:
|
||||
nuxt-ui-pro:
|
||||
needs: build
|
||||
|
||||
# Only run this job if not a fork PR (when push event or PR from same repo)
|
||||
if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
permissions:
|
||||
|
||||
16
.github/workflows/stale.yml
vendored
16
.github/workflows/stale.yml
vendored
@@ -10,14 +10,16 @@ jobs:
|
||||
|
||||
permissions:
|
||||
issues: write
|
||||
pull-requests: write
|
||||
|
||||
steps:
|
||||
- uses: actions/stale@v9
|
||||
with:
|
||||
exempt-issue-labels: triage,v3
|
||||
stale-issue-message: 'This issue is stale because it has been open for 30 days with no activity.'
|
||||
stale-issue-label: stale
|
||||
stale-pr-label: stale
|
||||
days-before-stale: 30
|
||||
days-before-close: -1
|
||||
days-before-stale: -1 # Issues and PR will never be flagged stale automatically.
|
||||
stale-issue-label: 'needs reproduction' # Label that flags an issue as stale.
|
||||
only-labels: 'needs reproduction' # Only process these issues
|
||||
days-before-issue-close: 7
|
||||
ignore-updates: true
|
||||
remove-stale-when-updated: false
|
||||
close-issue-message: This issue was closed because it was open for 7 days without a reproduction.
|
||||
close-issue-label: closed-by-bot
|
||||
operations-per-run: 300 #default 30
|
||||
|
||||
33
CHANGELOG.md
33
CHANGELOG.md
@@ -1,5 +1,38 @@
|
||||
# Changelog
|
||||
|
||||
## [3.0.2](https://github.com/nuxt/ui/compare/v3.0.1...v3.0.2) (2025-03-28)
|
||||
|
||||
### Features
|
||||
|
||||
* **Calendar:** allow year and month buttons styling ([#3672](https://github.com/nuxt/ui/issues/3672)) ([4a2b77d](https://github.com/nuxt/ui/commit/4a2b77d86c28806234002340eda39de4dc78cce0))
|
||||
* **locale:** add Armenian language ([#3664](https://github.com/nuxt/ui/issues/3664)) ([c76f590](https://github.com/nuxt/ui/commit/c76f5900970e3f5c451192b1207ccea04771e8b3))
|
||||
* **Table:** add `empty` prop ([afff54f](https://github.com/nuxt/ui/commit/afff54fecd31497238461e0a44abd8668ed734c3))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **Avatar:** proxy `$attrs` to default slot ([#3712](https://github.com/nuxt/ui/issues/3712)) ([88f349d](https://github.com/nuxt/ui/commit/88f349d0d74eb1c2ce5066818731759c25a9e83e))
|
||||
* **Button:** use `focus:outline-none` instead of `focus:outline-hidden` ([c231fe5](https://github.com/nuxt/ui/commit/c231fe5f26ca7614df46a7ec8a5ce7f4ec8884e7)), closes [#3658](https://github.com/nuxt/ui/issues/3658)
|
||||
* **CommandPalette:** use `group.id` as key ([bc61d29](https://github.com/nuxt/ui/commit/bc61d29cce531715a6279444845f02a002a22af7))
|
||||
* **components:** improve generic types ([#3331](https://github.com/nuxt/ui/issues/3331)) ([b998354](https://github.com/nuxt/ui/commit/b9983549a4b743724ea3ef99cc4a243f5ca41e53))
|
||||
* **Container:** add `w-full` class ([df00149](https://github.com/nuxt/ui/commit/df001495980647cab1e67fd16154f1bc778de5e2))
|
||||
* **defineLocale/defineShortcuts:** remove `@__NO_SIDE_EFFECTS__` ([82e2665](https://github.com/nuxt/ui/commit/82e26655a40782555299516f32a76046fa0dbd3a))
|
||||
* **Drawer:** remove `fadeFromIndex` prop proxy ([f7604e5](https://github.com/nuxt/ui/commit/f7604e565f717001a4d4c2974cf23559a3f01c21))
|
||||
* **Form:** clear dirty state after submit ([#3692](https://github.com/nuxt/ui/issues/3692)) ([3dd88ba](https://github.com/nuxt/ui/commit/3dd88bacecb2945efba8cc3cb4fe59fcbc056e9a))
|
||||
* **FormField:** add `help` to `aria-describedby` attribute ([#3691](https://github.com/nuxt/ui/issues/3691)) ([20c3392](https://github.com/nuxt/ui/commit/20c33920d005332db3c83f33a8c54c7c227ce0a0))
|
||||
* **InputMenu/SelectMenu:** empty search results ([94b6e52](https://github.com/nuxt/ui/commit/94b6e520f5ccf011204e953421fcc5b44b637e51))
|
||||
* **InputMenu:** reset `searchTerm` on `update:open` ([3074632](https://github.com/nuxt/ui/commit/3074632523e67fa6a0ad3d9a71e5692c285bdc3a)), closes [#3620](https://github.com/nuxt/ui/issues/3620)
|
||||
* **Link:** handle `aria-current` like `NuxtLink` / `RouterLink` ([c531d02](https://github.com/nuxt/ui/commit/c531d0248be7863980a1f676643c2dea8301c009))
|
||||
* **Link:** prevent `active="true"` binding on html ([d73768b](https://github.com/nuxt/ui/commit/d73768b70453d60dd4186a996c1cf808b0294bf6))
|
||||
* **Link:** properly pick all `aria-*` & `data-*` attrs ([ade16b7](https://github.com/nuxt/ui/commit/ade16b76cf535924a8d0f402b4d5d65cb67a55eb))
|
||||
* **Link:** proxy `onClick` ([370054b](https://github.com/nuxt/ui/commit/370054b20c0201c9dba84ddfcd1e916594619b93)), closes [#3631](https://github.com/nuxt/ui/issues/3631)
|
||||
* **NavigationMenu:** add `z-index` on viewport ([0095d89](https://github.com/nuxt/ui/commit/0095d8916bf361c0c89972e2f86b79850510c6a9)), closes [#3654](https://github.com/nuxt/ui/issues/3654)
|
||||
* **Switch:** prevent transition on focus outline ([68787b2](https://github.com/nuxt/ui/commit/68787b26fdf2bd5f9d9e812e5bfddb19abe45d1d))
|
||||
* **Table:** wrong condition on `caption` slot ([4ebb94c](https://github.com/nuxt/ui/commit/4ebb94cd7ef909b3547bce0922f75fe3ff74de4c))
|
||||
* **Tabs:** remove `focus:outline-hidden` class ([1769d5e](https://github.com/nuxt/ui/commit/1769d5ed6ea46b1f7eafdc48cb6456512229f98b))
|
||||
* **types:** add missing export for ButtonGroup ([#3709](https://github.com/nuxt/ui/issues/3709)) ([e7e6745](https://github.com/nuxt/ui/commit/e7e674559981177ad08be42418746060d7737df9))
|
||||
* **useOverlay:** refine `open` method type to infer close emit return type ([#3716](https://github.com/nuxt/ui/issues/3716)) ([bd99c2d](https://github.com/nuxt/ui/commit/bd99c2d850d57baccc51e049c0b578a6fc6ab431))
|
||||
* **vue:** mock `nuxtApp.hooks` & `useRuntimeHook` ([23bfeb9](https://github.com/nuxt/ui/commit/23bfeb937004d619187a67fb43e4c76b13d00069))
|
||||
|
||||
## [3.0.1](https://github.com/nuxt/ui/compare/v3.0.0...v3.0.1) (2025-03-21)
|
||||
|
||||
### ⚠ BREAKING CHANGES
|
||||
|
||||
11
README.md
11
README.md
@@ -104,6 +104,17 @@ app.mount('#app')
|
||||
|
||||
Learn more in the [installation guide](https://ui.nuxt.com/getting-started/installation/vue).
|
||||
|
||||
## Contribution
|
||||
|
||||
Thank you for considering contributing to Nuxt UI. Here are a few ways you can get involved:
|
||||
|
||||
- Reporting Bugs: If you come across any bugs or issues, please check out the reporting bugs guide to learn how to submit a bug report.
|
||||
- Suggestions: Have any thoughts to enhance Nuxt UI? We'd love to hear them! Check out the [contribution guide](https://ui.nuxt.com/getting-started/contribution) to share your suggestions.
|
||||
|
||||
## Local Development
|
||||
|
||||
Follow the docs to [set up your local development environment](https://ui.nuxt.com/getting-started/contribution#local-development) and contribute.
|
||||
|
||||
## Credits
|
||||
|
||||
- [nuxt/nuxt](https://github.com/nuxt/nuxt)
|
||||
|
||||
@@ -6,9 +6,6 @@ export default defineBuildConfig({
|
||||
'./src/unplugin',
|
||||
'./src/vite'
|
||||
],
|
||||
rollup: {
|
||||
emitCJS: true
|
||||
},
|
||||
replace: {
|
||||
'process.env.DEV': 'false'
|
||||
},
|
||||
|
||||
@@ -33,7 +33,7 @@ const component = ({ name, primitive, pro, prose, content }) => {
|
||||
import type { AppConfig } from '@nuxt/schema'
|
||||
import _appConfig from '#build/app.config'
|
||||
import theme from '#build/${path}/${prose ? 'prose/' : ''}${content ? 'content/' : ''}${kebabName}'
|
||||
import { tv } from '${pro ? '#ui/utils/tv' : '../utils/tv'}'
|
||||
import { tv } from '../utils/tv'
|
||||
|
||||
const appConfig${camelName} = _appConfig as AppConfig & { ${key}: { ${prose ? 'prose: { ' : ''}${camelName}: Partial<typeof theme> } }${prose ? ' }' : ''}
|
||||
|
||||
@@ -76,7 +76,7 @@ import type { ${upperName}RootProps, ${upperName}RootEmits } from 'reka-ui'
|
||||
import type { AppConfig } from '@nuxt/schema'
|
||||
import _appConfig from '#build/app.config'
|
||||
import theme from '#build/${path}/${prose ? 'prose/' : ''}${content ? 'content/' : ''}${kebabName}'
|
||||
import { tv } from '${pro ? '#ui/utils/tv' : '../utils/tv'}'
|
||||
import { tv } from '../utils/tv'
|
||||
|
||||
const appConfig${camelName} = _appConfig as AppConfig & { ${key}: { ${prose ? 'prose: { ' : ''}${camelName}: Partial<typeof theme> } }${prose ? ' }' : ''}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ const { data: files } = useLazyAsyncData('search', () => queryCollectionSearchSe
|
||||
})
|
||||
|
||||
const links = useLinks()
|
||||
const searchLinks = useSearchLinks()
|
||||
const color = computed(() => colorMode.value === 'dark' ? (colors as any)[appConfig.ui.colors.neutral][900] : 'white')
|
||||
const radius = computed(() => `:root { --ui-radius: ${appConfig.theme.radius}rem; }`)
|
||||
const blackAsPrimary = computed(() => appConfig.theme.blackAsPrimary ? `:root { --ui-primary: black; } .dark { --ui-primary: white; }` : ':root {}')
|
||||
@@ -64,6 +65,7 @@ provide('navigation', mappedNavigation)
|
||||
|
||||
<ClientOnly>
|
||||
<LazyUContentSearch
|
||||
:links="searchLinks"
|
||||
:files="files"
|
||||
:groups="[{
|
||||
id: 'framework',
|
||||
|
||||
@@ -38,7 +38,7 @@ onMounted(() => {
|
||||
}
|
||||
|
||||
.carbon-poweredby {
|
||||
@apply block text-[10px] text-center text-(--ui-text-dimmed) pt-2;
|
||||
@apply block text-xs text-center text-(--ui-text-muted) pt-2;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
const route = useRoute()
|
||||
|
||||
const links = [{
|
||||
label: 'Figma',
|
||||
to: '/figma'
|
||||
label: 'Team',
|
||||
to: '/team'
|
||||
}, {
|
||||
label: 'Roadmap',
|
||||
to: '/roadmap'
|
||||
|
||||
@@ -22,8 +22,20 @@ onMounted(() => {
|
||||
|
||||
const navigation = inject<Ref<ContentNavigationItem[]>>('navigation')
|
||||
|
||||
const githubLink = computed(() => {
|
||||
return `https://github.com/nuxt/${value.value}`
|
||||
})
|
||||
|
||||
const desktopLinks = computed(() => props.links.map(({ icon, ...link }) => link))
|
||||
const mobileLinks = computed(() => props.links.map(link => ({ ...link, defaultOpen: link.children && route.path.startsWith(link.to as string) })))
|
||||
const mobileLinks = computed(() => [
|
||||
...props.links.map(link => ({ ...link, defaultOpen: link.children && route.path.startsWith(link.to as string) })),
|
||||
{
|
||||
label: 'Open on GitHub',
|
||||
to: githubLink.value,
|
||||
icon: 'i-simple-icons-github',
|
||||
target: '_blank'
|
||||
}
|
||||
])
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -73,7 +85,7 @@ const mobileLinks = computed(() => props.links.map(link => ({ ...link, defaultOp
|
||||
:key="value"
|
||||
color="neutral"
|
||||
variant="ghost"
|
||||
:to="`https://github.com/nuxt/${value}`"
|
||||
:to="githubLink"
|
||||
target="_blank"
|
||||
icon="i-simple-icons-github"
|
||||
aria-label="GitHub"
|
||||
|
||||
@@ -14,6 +14,7 @@ const props = withDefaults(defineProps<{
|
||||
color?: string
|
||||
size?: { min: number, max: number }
|
||||
speed?: 'slow' | 'normal' | 'fast'
|
||||
isIndex?: boolean
|
||||
}>(), {
|
||||
starCount: 50,
|
||||
color: 'var(--ui-primary)',
|
||||
@@ -21,7 +22,8 @@ const props = withDefaults(defineProps<{
|
||||
min: 1,
|
||||
max: 3
|
||||
}),
|
||||
speed: 'normal'
|
||||
speed: 'normal',
|
||||
isIndex: false
|
||||
})
|
||||
|
||||
const route = useRoute()
|
||||
@@ -53,7 +55,7 @@ const twinkleDuration = computed(() => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="absolute pointer-events-none z-[-1] inset-y-0 left-4 right-4 lg:right-[50%] overflow-hidden">
|
||||
<div class="absolute pointer-events-none z-[-1] overflow-hidden" :class="isIndex ? 'inset-y-0 left-4 right-4 lg:right-[50%]' : 'inset-0'">
|
||||
<div
|
||||
v-for="star in stars"
|
||||
:key="star.id"
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<!-- eslint-disable no-useless-escape -->
|
||||
<script setup lang="ts">
|
||||
import type { ChipProps } from '@nuxt/ui'
|
||||
import json5 from 'json5'
|
||||
import { upperFirst, camelCase, kebabCase } from 'scule'
|
||||
import { hash } from 'ohash'
|
||||
@@ -53,6 +54,8 @@ const props = defineProps<{
|
||||
hide?: string[]
|
||||
/** List of props to externalize in script setup */
|
||||
external?: string[]
|
||||
/** The types of the externalized props */
|
||||
externalTypes?: string[]
|
||||
/** List of props to use with `v-model` */
|
||||
model?: string[]
|
||||
/** List of props to cast from code and selection */
|
||||
@@ -209,11 +212,21 @@ ${props.slots?.default}
|
||||
code += `
|
||||
<script setup lang="ts">
|
||||
`
|
||||
for (const key of props.external) {
|
||||
if (props.externalTypes?.length) {
|
||||
const removeArrayBrackets = (type: string): string => type.endsWith('[]') ? removeArrayBrackets(type.slice(0, -2)) : type
|
||||
|
||||
const types = props.externalTypes.map(type => removeArrayBrackets(type))
|
||||
code += `import type { ${types.join(', ')} } from '@nuxt/ui${props.pro ? '-pro' : ''}'
|
||||
|
||||
`
|
||||
}
|
||||
|
||||
for (const [i, key] of props.external.entries()) {
|
||||
const cast = props.cast?.[key]
|
||||
const value = cast ? castMap[cast]!.template(componentProps[key]) : json5.stringify(componentProps[key], null, 2)?.replace(/,([ |\t\n]+[}|\]])/g, '$1')
|
||||
const type = props.externalTypes?.[i] ? `<${props.externalTypes[i]}>` : ''
|
||||
|
||||
code += `const ${key === 'modelValue' ? 'value' : key} = ref(${value})
|
||||
code += `const ${key === 'modelValue' ? 'value' : key} = ref${type}(${value})
|
||||
`
|
||||
}
|
||||
code += `<\/script>
|
||||
@@ -346,7 +359,7 @@ const { data: ast } = await useAsyncData(`component-code-${name}-${hash({ props:
|
||||
inset
|
||||
standalone
|
||||
:color="(modelValue as any)"
|
||||
:size="ui.itemLeadingChipSize()"
|
||||
:size="(ui.itemLeadingChipSize() as ChipProps['size'])"
|
||||
class="size-2"
|
||||
/>
|
||||
</template>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import type { ChipProps } from '@nuxt/ui'
|
||||
import { camelCase } from 'scule'
|
||||
import { useElementSize } from '@vueuse/core'
|
||||
import { get, set } from '#ui/utils'
|
||||
@@ -185,7 +186,7 @@ const urlSearchParams = computed(() => {
|
||||
inset
|
||||
standalone
|
||||
:color="(modelValue as any)"
|
||||
:size="ui.itemLeadingChipSize()"
|
||||
:size="(ui.itemLeadingChipSize() as ChipProps['size'])"
|
||||
class="size-2"
|
||||
/>
|
||||
</template>
|
||||
|
||||
@@ -12,14 +12,15 @@ function getEmojiFlag(locale: string): string {
|
||||
ar: 'sa', // Arabic -> Saudi Arabia
|
||||
bn: 'bd', // Bengali -> Bangladesh
|
||||
ca: 'es', // Catalan -> Spain
|
||||
cs: 'cz', // Czech -> Czech Republic (note: modern country code is actually 'cz')
|
||||
ckb: 'iq', // Central Kurdish -> Iraq
|
||||
cs: 'cz', // Czech -> Czech Republic (note: modern country code is actually 'cz')
|
||||
da: 'dk', // Danish -> Denmark
|
||||
el: 'gr', // Greek -> Greece
|
||||
et: 'ee', // Estonian -> Estonia
|
||||
en: 'gb', // English -> Great Britain
|
||||
et: 'ee', // Estonian -> Estonia
|
||||
he: 'il', // Hebrew -> Israel
|
||||
hi: 'in', // Hindi -> India
|
||||
hy: 'am', // Armenian -> Armenia
|
||||
ja: 'jp', // Japanese -> Japan
|
||||
km: 'kh', // Khmer -> Cambodia
|
||||
ko: 'kr', // Korean -> South Korea
|
||||
@@ -27,8 +28,7 @@ function getEmojiFlag(locale: string): string {
|
||||
sv: 'se', // Swedish -> Sweden
|
||||
uk: 'ua', // Ukrainian -> Ukraine
|
||||
ur: 'pk', // Urdu -> Pakistan
|
||||
vi: 'vn', // Vietnamese -> Vietnam
|
||||
hy: 'am' // Armenian -> Armenia
|
||||
vi: 'vn' // Vietnamese -> Vietnam
|
||||
}
|
||||
|
||||
const baseLanguage = locale.split('-')[0]?.toLowerCase() || locale
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
const items = [
|
||||
import type { AccordionItem } from '@nuxt/ui'
|
||||
|
||||
const items: AccordionItem[] = [
|
||||
{
|
||||
label: 'Icons',
|
||||
icon: 'i-lucide-smile'
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
const items = [
|
||||
import type { AccordionItem } from '@nuxt/ui'
|
||||
|
||||
const items: AccordionItem[] = [
|
||||
{
|
||||
label: 'Icons',
|
||||
icon: 'i-lucide-smile'
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import type { AccordionItem } from '@nuxt/ui'
|
||||
|
||||
const items = [
|
||||
{
|
||||
label: 'Icons',
|
||||
@@ -8,7 +10,7 @@ const items = [
|
||||
{
|
||||
label: 'Colors',
|
||||
icon: 'i-lucide-swatch-book',
|
||||
slot: 'colors',
|
||||
slot: 'colors' as const,
|
||||
content: 'Choose a primary and a neutral color from your Tailwind CSS theme.'
|
||||
},
|
||||
{
|
||||
@@ -16,7 +18,7 @@ const items = [
|
||||
icon: 'i-lucide-box',
|
||||
content: 'You can customize components by using the `class` / `ui` props or in your app.config.ts.'
|
||||
}
|
||||
]
|
||||
] satisfies AccordionItem[]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
<script setup lang="ts">
|
||||
import type { AccordionItem } from '@nuxt/ui'
|
||||
import { useSortable } from '@vueuse/integrations/useSortable'
|
||||
|
||||
const items = shallowRef<AccordionItem[]>([
|
||||
{
|
||||
label: 'Icons',
|
||||
icon: 'i-lucide-smile',
|
||||
content: 'You have nothing to do, @nuxt/icon will handle it automatically.'
|
||||
},
|
||||
{
|
||||
label: 'Colors',
|
||||
icon: 'i-lucide-swatch-book',
|
||||
slot: 'colors' as const,
|
||||
content: 'Choose a primary and a neutral color from your Tailwind CSS theme.'
|
||||
},
|
||||
{
|
||||
label: 'Components',
|
||||
icon: 'i-lucide-box',
|
||||
content: 'You can customize components by using the `class` / `ui` props or in your app.config.ts.'
|
||||
}
|
||||
])
|
||||
|
||||
const accordion = useTemplateRef<HTMLElement>('accordion')
|
||||
|
||||
useSortable(accordion, items, {
|
||||
animation: 150
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UAccordion ref="accordion" :items="items" />
|
||||
</template>
|
||||
@@ -1,5 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
const items = [
|
||||
import type { AccordionItem } from '@nuxt/ui'
|
||||
|
||||
const items: AccordionItem[] = [
|
||||
{
|
||||
label: 'Icons',
|
||||
icon: 'i-lucide-smile',
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
<script setup lang="ts">
|
||||
import type { BreadcrumbItem } from '@nuxt/ui'
|
||||
|
||||
const items = [{
|
||||
label: 'Home',
|
||||
to: '/'
|
||||
}, {
|
||||
slot: 'dropdown',
|
||||
slot: 'dropdown' as const,
|
||||
icon: 'i-lucide-ellipsis',
|
||||
children: [{
|
||||
label: 'Documentation'
|
||||
@@ -18,7 +20,7 @@ const items = [{
|
||||
}, {
|
||||
label: 'Breadcrumb',
|
||||
to: '/components/breadcrumb'
|
||||
}]
|
||||
}] satisfies BreadcrumbItem[]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
const items = [{
|
||||
import type { BreadcrumbItem } from '@nuxt/ui'
|
||||
|
||||
const items: BreadcrumbItem[] = [{
|
||||
label: 'Home',
|
||||
to: '/'
|
||||
}, {
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
const items = [{
|
||||
import type { DropdownMenuItem } from '@nuxt/ui'
|
||||
|
||||
const items: DropdownMenuItem[] = [{
|
||||
label: 'Team',
|
||||
icon: 'i-lucide-users'
|
||||
}, {
|
||||
|
||||
@@ -11,7 +11,7 @@ const groups = [{
|
||||
label: 'Billing',
|
||||
icon: 'i-lucide-credit-card',
|
||||
kbds: ['meta', 'B'],
|
||||
slot: 'billing'
|
||||
slot: 'billing' as const
|
||||
},
|
||||
{
|
||||
label: 'Notifications',
|
||||
@@ -25,7 +25,7 @@ const groups = [{
|
||||
}, {
|
||||
id: 'users',
|
||||
label: 'Users',
|
||||
slot: 'users',
|
||||
slot: 'users' as const,
|
||||
items: [
|
||||
{
|
||||
label: 'Benjamin Canac',
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
<script setup lang="ts">
|
||||
import type { ContextMenuItem } from '@nuxt/ui'
|
||||
|
||||
const showSidebar = ref(true)
|
||||
const showToolbar = ref(false)
|
||||
|
||||
const items = computed(() => [{
|
||||
const items = computed<ContextMenuItem[]>(() => [{
|
||||
label: 'View',
|
||||
type: 'label' as const
|
||||
}, {
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
const items = [
|
||||
import type { ContextMenuItem } from '@nuxt/ui'
|
||||
|
||||
const items: ContextMenuItem[][] = [
|
||||
[
|
||||
{
|
||||
label: 'View',
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
<script setup lang="ts">
|
||||
import type { ContextMenuItem } from '@nuxt/ui'
|
||||
|
||||
const loading = ref(true)
|
||||
|
||||
const items = [{
|
||||
const items: ContextMenuItem[] = [{
|
||||
label: 'Refresh the Page',
|
||||
slot: 'refresh'
|
||||
}, {
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
<script lang="ts" setup>
|
||||
import { createReusableTemplate, useMediaQuery } from '@vueuse/core'
|
||||
|
||||
const [DefineFormTemplate, ReuseFormTemplate] = createReusableTemplate()
|
||||
const isDesktop = useMediaQuery('(min-width: 768px)')
|
||||
|
||||
const open = ref(false)
|
||||
|
||||
const state = reactive({
|
||||
email: undefined
|
||||
})
|
||||
|
||||
const title = 'Edit profile'
|
||||
const description = 'Make changes to your profile here. Click save when you\'re done.'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DefineFormTemplate>
|
||||
<UForm :state="state" class="space-y-4">
|
||||
<UFormField label="Email" name="email" required>
|
||||
<UInput v-model="state.email" placeholder="shadcn@example.com" required />
|
||||
</UFormField>
|
||||
|
||||
<UButton label="Save changes" type="submit" />
|
||||
</UForm>
|
||||
</DefineFormTemplate>
|
||||
|
||||
<UModal v-if="isDesktop" v-model:open="open" :title="title" :description="description">
|
||||
<UButton label="Edit profile" color="neutral" variant="outline" />
|
||||
|
||||
<template #body>
|
||||
<ReuseFormTemplate />
|
||||
</template>
|
||||
</UModal>
|
||||
|
||||
<UDrawer v-else v-model:open="open" :title="title" :description="description">
|
||||
<UButton label="Edit profile" color="neutral" variant="outline" />
|
||||
|
||||
<template #body>
|
||||
<ReuseFormTemplate />
|
||||
</template>
|
||||
</UDrawer>
|
||||
</template>
|
||||
@@ -1,4 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import type { DropdownMenuItem } from '@nuxt/ui'
|
||||
|
||||
const showBookmarks = ref(true)
|
||||
const showHistory = ref(false)
|
||||
const showDownloads = ref(false)
|
||||
@@ -36,7 +38,7 @@ const items = computed(() => [{
|
||||
onUpdateChecked(checked: boolean) {
|
||||
showDownloads.value = checked
|
||||
}
|
||||
}])
|
||||
}] satisfies DropdownMenuItem[])
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
const items = [
|
||||
import type { DropdownMenuItem } from '@nuxt/ui'
|
||||
|
||||
const items: DropdownMenuItem[][] = [
|
||||
[
|
||||
{
|
||||
label: 'View',
|
||||
@@ -17,7 +19,7 @@ const items = [
|
||||
[
|
||||
{
|
||||
label: 'Delete',
|
||||
color: 'error' as const,
|
||||
color: 'error',
|
||||
icon: 'i-lucide-trash'
|
||||
}
|
||||
]
|
||||
@@ -27,9 +29,5 @@ const items = [
|
||||
<template>
|
||||
<UDropdownMenu :items="items" :ui="{ content: 'w-48' }">
|
||||
<UButton label="Open" color="neutral" variant="outline" icon="i-lucide-menu" />
|
||||
|
||||
<template #profile-trailing>
|
||||
<UIcon name="i-lucide-badge-check" class="shrink-0 size-5 text-(--ui-primary)" />
|
||||
</template>
|
||||
</UDropdownMenu>
|
||||
</template>
|
||||
|
||||
@@ -1,15 +1,19 @@
|
||||
<script setup lang="ts">
|
||||
const items = [{
|
||||
label: 'Profile',
|
||||
icon: 'i-lucide-user',
|
||||
slot: 'profile'
|
||||
}, {
|
||||
label: 'Billing',
|
||||
icon: 'i-lucide-credit-card'
|
||||
}, {
|
||||
label: 'Settings',
|
||||
icon: 'i-lucide-cog'
|
||||
}]
|
||||
import type { DropdownMenuItem } from '@nuxt/ui'
|
||||
|
||||
const items = [
|
||||
{
|
||||
label: 'Profile',
|
||||
icon: 'i-lucide-user',
|
||||
slot: 'profile' as const
|
||||
}, {
|
||||
label: 'Billing',
|
||||
icon: 'i-lucide-credit-card'
|
||||
}, {
|
||||
label: 'Settings',
|
||||
icon: 'i-lucide-cog'
|
||||
}
|
||||
] satisfies DropdownMenuItem[]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -1,20 +1,24 @@
|
||||
<script setup lang="ts">
|
||||
import type { DropdownMenuItem } from '@nuxt/ui'
|
||||
|
||||
const open = ref(false)
|
||||
|
||||
defineShortcuts({
|
||||
o: () => open.value = !open.value
|
||||
})
|
||||
|
||||
const items = [{
|
||||
label: 'Profile',
|
||||
icon: 'i-lucide-user'
|
||||
}, {
|
||||
label: 'Billing',
|
||||
icon: 'i-lucide-credit-card'
|
||||
}, {
|
||||
label: 'Settings',
|
||||
icon: 'i-lucide-cog'
|
||||
}]
|
||||
const items: DropdownMenuItem[] = [
|
||||
{
|
||||
label: 'Profile',
|
||||
icon: 'i-lucide-user'
|
||||
}, {
|
||||
label: 'Billing',
|
||||
icon: 'i-lucide-credit-card'
|
||||
}, {
|
||||
label: 'Settings',
|
||||
icon: 'i-lucide-cog'
|
||||
}
|
||||
]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -16,7 +16,7 @@ function onOpen() {
|
||||
|
||||
<template>
|
||||
<UInputMenu
|
||||
:items="countries || []"
|
||||
:items="countries"
|
||||
:loading="status === 'pending'"
|
||||
label-key="name"
|
||||
:search-input="{ icon: 'i-lucide-search' }"
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import type { AvatarProps } from '@nuxt/ui'
|
||||
|
||||
const { data: users, status } = await useFetch('https://jsonplaceholder.typicode.com/users', {
|
||||
key: 'typicode-users',
|
||||
transform: (data: { id: number, name: string }[]) => {
|
||||
@@ -6,7 +8,7 @@ const { data: users, status } = await useFetch('https://jsonplaceholder.typicode
|
||||
label: user.name,
|
||||
value: String(user.id),
|
||||
avatar: { src: `https://i.pravatar.cc/120?img=${user.id}` }
|
||||
})) || []
|
||||
}))
|
||||
},
|
||||
lazy: true
|
||||
})
|
||||
@@ -14,7 +16,7 @@ const { data: users, status } = await useFetch('https://jsonplaceholder.typicode
|
||||
|
||||
<template>
|
||||
<UInputMenu
|
||||
:items="users || []"
|
||||
:items="users"
|
||||
:loading="status === 'pending'"
|
||||
icon="i-lucide-user"
|
||||
placeholder="Select user"
|
||||
@@ -23,7 +25,7 @@ const { data: users, status } = await useFetch('https://jsonplaceholder.typicode
|
||||
<UAvatar
|
||||
v-if="modelValue"
|
||||
v-bind="modelValue.avatar"
|
||||
:size="ui.leadingAvatarSize()"
|
||||
:size="(ui.leadingAvatarSize() as AvatarProps['size'])"
|
||||
:class="ui.leadingAvatar()"
|
||||
/>
|
||||
</template>
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import type { AvatarProps } from '@nuxt/ui'
|
||||
|
||||
const { data: users, status } = await useFetch('https://jsonplaceholder.typicode.com/users', {
|
||||
key: 'typicode-users-email',
|
||||
transform: (data: { id: number, name: string, email: string }[]) => {
|
||||
@@ -7,7 +9,7 @@ const { data: users, status } = await useFetch('https://jsonplaceholder.typicode
|
||||
email: user.email,
|
||||
value: String(user.id),
|
||||
avatar: { src: `https://i.pravatar.cc/120?img=${user.id}` }
|
||||
})) || []
|
||||
}))
|
||||
},
|
||||
lazy: true
|
||||
})
|
||||
@@ -15,7 +17,7 @@ const { data: users, status } = await useFetch('https://jsonplaceholder.typicode
|
||||
|
||||
<template>
|
||||
<UInputMenu
|
||||
:items="users || []"
|
||||
:items="users"
|
||||
:loading="status === 'pending'"
|
||||
:filter-fields="['label', 'email']"
|
||||
icon="i-lucide-user"
|
||||
@@ -26,7 +28,7 @@ const { data: users, status } = await useFetch('https://jsonplaceholder.typicode
|
||||
<UAvatar
|
||||
v-if="modelValue"
|
||||
v-bind="modelValue.avatar"
|
||||
:size="ui.leadingAvatarSize()"
|
||||
:size="(ui.leadingAvatarSize() as AvatarProps['size'])"
|
||||
:class="ui.leadingAvatar()"
|
||||
/>
|
||||
</template>
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import type { AvatarProps } from '@nuxt/ui'
|
||||
|
||||
const searchTerm = ref('')
|
||||
const searchTermDebounced = refDebounced(searchTerm, 200)
|
||||
|
||||
@@ -10,7 +12,7 @@ const { data: users, status } = await useFetch('https://jsonplaceholder.typicode
|
||||
label: user.name,
|
||||
value: String(user.id),
|
||||
avatar: { src: `https://i.pravatar.cc/120?img=${user.id}` }
|
||||
})) || []
|
||||
}))
|
||||
},
|
||||
lazy: true
|
||||
})
|
||||
@@ -19,7 +21,7 @@ const { data: users, status } = await useFetch('https://jsonplaceholder.typicode
|
||||
<template>
|
||||
<UInputMenu
|
||||
v-model:search-term="searchTerm"
|
||||
:items="users || []"
|
||||
:items="users"
|
||||
:loading="status === 'pending'"
|
||||
ignore-filter
|
||||
icon="i-lucide-user"
|
||||
@@ -29,7 +31,7 @@ const { data: users, status } = await useFetch('https://jsonplaceholder.typicode
|
||||
<UAvatar
|
||||
v-if="modelValue"
|
||||
v-bind="modelValue.avatar"
|
||||
:size="ui.leadingAvatarSize()"
|
||||
:size="(ui.leadingAvatarSize() as AvatarProps['size'])"
|
||||
:class="ui.leadingAvatar()"
|
||||
/>
|
||||
</template>
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import type { InputMenuItem } from '@nuxt/ui'
|
||||
|
||||
const items = ref([
|
||||
{
|
||||
label: 'benjamincanac',
|
||||
@@ -23,8 +25,16 @@ const items = ref([
|
||||
src: 'https://github.com/noook.png',
|
||||
alt: 'noook'
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'sandros94',
|
||||
value: 'sandros94',
|
||||
avatar: {
|
||||
src: 'https://github.com/sandros94.png',
|
||||
alt: 'sandros94'
|
||||
}
|
||||
}
|
||||
])
|
||||
] satisfies InputMenuItem[])
|
||||
const value = ref(items.value[0])
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,27 +1,30 @@
|
||||
<script setup lang="ts">
|
||||
import type { InputMenuItem, ChipProps } from '@nuxt/ui'
|
||||
|
||||
const items = ref([
|
||||
{
|
||||
label: 'bug',
|
||||
value: 'bug',
|
||||
chip: {
|
||||
color: 'error' as const
|
||||
color: 'error'
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'feature',
|
||||
value: 'feature',
|
||||
chip: {
|
||||
color: 'success' as const
|
||||
color: 'success'
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'enhancement',
|
||||
value: 'enhancement',
|
||||
chip: {
|
||||
color: 'info' as const
|
||||
color: 'info'
|
||||
}
|
||||
}
|
||||
])
|
||||
] satisfies InputMenuItem[])
|
||||
|
||||
const value = ref(items.value[0])
|
||||
</script>
|
||||
|
||||
@@ -33,7 +36,7 @@ const value = ref(items.value[0])
|
||||
v-bind="modelValue.chip"
|
||||
inset
|
||||
standalone
|
||||
:size="ui.itemLeadingChipSize()"
|
||||
:size="(ui.itemLeadingChipSize() as ChipProps['size'])"
|
||||
:class="ui.itemLeadingChip()"
|
||||
/>
|
||||
</template>
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import type { InputMenuItem } from '@nuxt/ui'
|
||||
|
||||
const items = ref([
|
||||
{
|
||||
label: 'Backlog',
|
||||
@@ -20,7 +22,8 @@ const items = ref([
|
||||
value: 'done',
|
||||
icon: 'i-lucide-circle-check'
|
||||
}
|
||||
])
|
||||
] satisfies InputMenuItem[])
|
||||
|
||||
const value = ref(items.value[0])
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
<script setup lang="ts">
|
||||
import type { NavigationMenuItem } from '@nuxt/ui'
|
||||
|
||||
const items = [
|
||||
{
|
||||
label: 'Docs',
|
||||
icon: 'i-lucide-book-open',
|
||||
slot: 'docs',
|
||||
slot: 'docs' as const,
|
||||
children: [
|
||||
{
|
||||
label: 'Icons',
|
||||
@@ -22,7 +24,7 @@ const items = [
|
||||
{
|
||||
label: 'Components',
|
||||
icon: 'i-lucide-box',
|
||||
slot: 'components',
|
||||
slot: 'components' as const,
|
||||
children: [
|
||||
{
|
||||
label: 'Link',
|
||||
@@ -54,7 +56,7 @@ const items = [
|
||||
label: 'GitHub',
|
||||
icon: 'i-simple-icons-github'
|
||||
}
|
||||
]
|
||||
] satisfies NavigationMenuItem[]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
const items = [
|
||||
import type { NavigationMenuItem } from '@nuxt/ui'
|
||||
|
||||
const items: NavigationMenuItem[] = [
|
||||
{
|
||||
label: 'Guide',
|
||||
icon: 'i-lucide-book-open'
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
const items = [
|
||||
import type { NavigationMenuItem } from '@nuxt/ui'
|
||||
|
||||
const items: NavigationMenuItem[] = [
|
||||
{
|
||||
label: 'Guide',
|
||||
icon: 'i-lucide-book-open',
|
||||
|
||||
@@ -40,7 +40,7 @@ const label = ref([])
|
||||
multiple
|
||||
placeholder="Search labels..."
|
||||
:groups="[{ id: 'labels', items }]"
|
||||
:ui="{ input: '[&>input]:h-8' }"
|
||||
:ui="{ input: '[&>input]:h-8 [&>input]:text-sm' }"
|
||||
/>
|
||||
</template>
|
||||
</UPopover>
|
||||
|
||||
@@ -4,8 +4,7 @@ const { data: countries, status, execute } = await useLazyFetch<{
|
||||
code: string
|
||||
emoji: string
|
||||
}[]>('/api/countries.json', {
|
||||
immediate: false,
|
||||
default: () => []
|
||||
immediate: false
|
||||
})
|
||||
|
||||
function onOpen() {
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import type { AvatarProps } from '@nuxt/ui'
|
||||
|
||||
const { data: users, status } = await useFetch('https://jsonplaceholder.typicode.com/users', {
|
||||
key: 'typicode-users',
|
||||
transform: (data: { id: number, name: string }[]) => {
|
||||
@@ -6,7 +8,7 @@ const { data: users, status } = await useFetch('https://jsonplaceholder.typicode
|
||||
label: user.name,
|
||||
value: String(user.id),
|
||||
avatar: { src: `https://i.pravatar.cc/120?img=${user.id}` }
|
||||
})) || []
|
||||
}))
|
||||
},
|
||||
lazy: true
|
||||
})
|
||||
@@ -14,7 +16,7 @@ const { data: users, status } = await useFetch('https://jsonplaceholder.typicode
|
||||
|
||||
<template>
|
||||
<USelectMenu
|
||||
:items="users || []"
|
||||
:items="users"
|
||||
:loading="status === 'pending'"
|
||||
icon="i-lucide-user"
|
||||
placeholder="Select user"
|
||||
@@ -24,7 +26,7 @@ const { data: users, status } = await useFetch('https://jsonplaceholder.typicode
|
||||
<UAvatar
|
||||
v-if="modelValue"
|
||||
v-bind="modelValue.avatar"
|
||||
:size="ui.leadingAvatarSize()"
|
||||
:size="(ui.leadingAvatarSize() as AvatarProps['size'])"
|
||||
:class="ui.leadingAvatar()"
|
||||
/>
|
||||
</template>
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import type { AvatarProps } from '@nuxt/ui'
|
||||
|
||||
const { data: users, status } = await useFetch('https://jsonplaceholder.typicode.com/users', {
|
||||
key: 'typicode-users-email',
|
||||
transform: (data: { id: number, name: string, email: string }[]) => {
|
||||
@@ -7,7 +9,7 @@ const { data: users, status } = await useFetch('https://jsonplaceholder.typicode
|
||||
email: user.email,
|
||||
value: String(user.id),
|
||||
avatar: { src: `https://i.pravatar.cc/120?img=${user.id}` }
|
||||
})) || []
|
||||
}))
|
||||
},
|
||||
lazy: true
|
||||
})
|
||||
@@ -15,7 +17,7 @@ const { data: users, status } = await useFetch('https://jsonplaceholder.typicode
|
||||
|
||||
<template>
|
||||
<USelectMenu
|
||||
:items="users || []"
|
||||
:items="users"
|
||||
:loading="status === 'pending'"
|
||||
:filter-fields="['label', 'email']"
|
||||
icon="i-lucide-user"
|
||||
@@ -26,7 +28,7 @@ const { data: users, status } = await useFetch('https://jsonplaceholder.typicode
|
||||
<UAvatar
|
||||
v-if="modelValue"
|
||||
v-bind="modelValue.avatar"
|
||||
:size="ui.leadingAvatarSize()"
|
||||
:size="(ui.leadingAvatarSize() as AvatarProps['size'])"
|
||||
:class="ui.leadingAvatar()"
|
||||
/>
|
||||
</template>
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import type { AvatarProps } from '@nuxt/ui'
|
||||
|
||||
const searchTerm = ref('')
|
||||
const searchTermDebounced = refDebounced(searchTerm, 200)
|
||||
|
||||
@@ -10,7 +12,7 @@ const { data: users, status } = await useFetch('https://jsonplaceholder.typicode
|
||||
label: user.name,
|
||||
value: String(user.id),
|
||||
avatar: { src: `https://i.pravatar.cc/120?img=${user.id}` }
|
||||
})) || []
|
||||
}))
|
||||
},
|
||||
lazy: true
|
||||
})
|
||||
@@ -19,7 +21,7 @@ const { data: users, status } = await useFetch('https://jsonplaceholder.typicode
|
||||
<template>
|
||||
<USelectMenu
|
||||
v-model:search-term="searchTerm"
|
||||
:items="users || []"
|
||||
:items="users"
|
||||
:loading="status === 'pending'"
|
||||
ignore-filter
|
||||
icon="i-lucide-user"
|
||||
@@ -30,7 +32,7 @@ const { data: users, status } = await useFetch('https://jsonplaceholder.typicode
|
||||
<UAvatar
|
||||
v-if="modelValue"
|
||||
v-bind="modelValue.avatar"
|
||||
:size="ui.leadingAvatarSize()"
|
||||
:size="(ui.leadingAvatarSize() as AvatarProps['size'])"
|
||||
:class="ui.leadingAvatar()"
|
||||
/>
|
||||
</template>
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import type { SelectMenuItem } from '@nuxt/ui'
|
||||
|
||||
const items = ref([
|
||||
{
|
||||
label: 'benjamincanac',
|
||||
@@ -23,8 +25,16 @@ const items = ref([
|
||||
src: 'https://github.com/noook.png',
|
||||
alt: 'noook'
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'sandros94',
|
||||
value: 'sandros94',
|
||||
avatar: {
|
||||
src: 'https://github.com/sandros94.png',
|
||||
alt: 'sandros94'
|
||||
}
|
||||
}
|
||||
])
|
||||
] satisfies SelectMenuItem[])
|
||||
const value = ref(items.value[0])
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,27 +1,29 @@
|
||||
<script setup lang="ts">
|
||||
import type { SelectMenuItem, ChipProps } from '@nuxt/ui'
|
||||
|
||||
const items = ref([
|
||||
{
|
||||
label: 'bug',
|
||||
value: 'bug',
|
||||
chip: {
|
||||
color: 'error' as const
|
||||
color: 'error'
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'feature',
|
||||
value: 'feature',
|
||||
chip: {
|
||||
color: 'success' as const
|
||||
color: 'success'
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'enhancement',
|
||||
value: 'enhancement',
|
||||
chip: {
|
||||
color: 'info' as const
|
||||
color: 'info'
|
||||
}
|
||||
}
|
||||
])
|
||||
] satisfies SelectMenuItem[])
|
||||
const value = ref(items.value[0])
|
||||
</script>
|
||||
|
||||
@@ -33,7 +35,7 @@ const value = ref(items.value[0])
|
||||
v-bind="modelValue.chip"
|
||||
inset
|
||||
standalone
|
||||
:size="ui.itemLeadingChipSize()"
|
||||
:size="(ui.itemLeadingChipSize() as ChipProps['size'])"
|
||||
:class="ui.itemLeadingChip()"
|
||||
/>
|
||||
</template>
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import type { SelectMenuItem } from '@nuxt/ui'
|
||||
|
||||
const items = ref([
|
||||
{
|
||||
label: 'Backlog',
|
||||
@@ -20,7 +22,7 @@ const items = ref([
|
||||
value: 'done',
|
||||
icon: 'i-lucide-circle-check'
|
||||
}
|
||||
])
|
||||
] satisfies SelectMenuItem[])
|
||||
const value = ref(items.value[0])
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import type { AvatarProps } from '@nuxt/ui'
|
||||
|
||||
const { data: users, status } = await useFetch('https://jsonplaceholder.typicode.com/users', {
|
||||
key: 'typicode-users',
|
||||
transform: (data: { id: number, name: string }[]) => {
|
||||
@@ -6,7 +8,7 @@ const { data: users, status } = await useFetch('https://jsonplaceholder.typicode
|
||||
label: user.name,
|
||||
value: String(user.id),
|
||||
avatar: { src: `https://i.pravatar.cc/120?img=${user.id}` }
|
||||
})) || []
|
||||
}))
|
||||
},
|
||||
lazy: true
|
||||
})
|
||||
@@ -18,17 +20,18 @@ function getUserAvatar(value: string) {
|
||||
|
||||
<template>
|
||||
<USelect
|
||||
:items="users || []"
|
||||
:items="users"
|
||||
:loading="status === 'pending'"
|
||||
icon="i-lucide-user"
|
||||
placeholder="Select user"
|
||||
class="w-48"
|
||||
value-key="value"
|
||||
>
|
||||
<template #leading="{ modelValue, ui }">
|
||||
<UAvatar
|
||||
v-if="modelValue"
|
||||
v-bind="getUserAvatar(modelValue as string)"
|
||||
:size="ui.leadingAvatarSize()"
|
||||
v-bind="getUserAvatar(modelValue)"
|
||||
:size="(ui.leadingAvatarSize() as AvatarProps['size'])"
|
||||
:class="ui.leadingAvatar()"
|
||||
/>
|
||||
</template>
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import type { SelectItem } from '@nuxt/ui'
|
||||
|
||||
const items = ref([
|
||||
{
|
||||
label: 'benjamincanac',
|
||||
@@ -23,13 +25,21 @@ const items = ref([
|
||||
src: 'https://github.com/noook.png',
|
||||
alt: 'noook'
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'sandros94',
|
||||
value: 'sandros94',
|
||||
avatar: {
|
||||
src: 'https://github.com/sandros94.png',
|
||||
alt: 'sandros94'
|
||||
}
|
||||
}
|
||||
])
|
||||
] satisfies SelectItem[])
|
||||
const value = ref(items.value[0]?.value)
|
||||
|
||||
const avatar = computed(() => items.value.find(item => item.value === value.value)?.avatar)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<USelect v-model="value" :avatar="avatar" :items="items" class="w-48" />
|
||||
<USelect v-model="value" :items="items" value-key="value" :avatar="avatar" class="w-48" />
|
||||
</template>
|
||||
|
||||
@@ -1,27 +1,30 @@
|
||||
<script setup lang="ts">
|
||||
import type { SelectItem, ChipProps } from '@nuxt/ui'
|
||||
|
||||
const items = ref([
|
||||
{
|
||||
label: 'bug',
|
||||
value: 'bug',
|
||||
chip: {
|
||||
color: 'error' as const
|
||||
color: 'error'
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'feature',
|
||||
value: 'feature',
|
||||
chip: {
|
||||
color: 'success' as const
|
||||
color: 'success'
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'enhancement',
|
||||
value: 'enhancement',
|
||||
chip: {
|
||||
color: 'info' as const
|
||||
color: 'info'
|
||||
}
|
||||
}
|
||||
])
|
||||
] satisfies SelectItem[])
|
||||
|
||||
const value = ref(items.value[0]?.value)
|
||||
|
||||
function getChip(value: string) {
|
||||
@@ -30,14 +33,14 @@ function getChip(value: string) {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<USelect v-model="value" :items="items" class="w-48">
|
||||
<USelect v-model="value" :items="items" value-key="value" class="w-48">
|
||||
<template #leading="{ modelValue, ui }">
|
||||
<UChip
|
||||
v-if="modelValue"
|
||||
v-bind="getChip(modelValue as string)"
|
||||
v-bind="getChip(modelValue)"
|
||||
inset
|
||||
standalone
|
||||
:size="ui.itemLeadingChipSize()"
|
||||
:size="(ui.itemLeadingChipSize() as ChipProps['size'])"
|
||||
:class="ui.itemLeadingChip()"
|
||||
/>
|
||||
</template>
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import type { SelectItem } from '@nuxt/ui'
|
||||
|
||||
const items = ref([
|
||||
{
|
||||
label: 'Backlog',
|
||||
@@ -20,12 +22,12 @@ const items = ref([
|
||||
value: 'done',
|
||||
icon: 'i-lucide-circle-check'
|
||||
}
|
||||
])
|
||||
] satisfies SelectItem[])
|
||||
const value = ref(items.value[0]?.value)
|
||||
|
||||
const icon = computed(() => items.value.find(item => item.value === value.value)?.icon)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<USelect v-model="value" :icon="icon" :items="items" class="w-48" />
|
||||
<USelect v-model="value" :items="items" value-key="value" :icon="icon" class="w-48" />
|
||||
</template>
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
const items = [
|
||||
import type { StepperItem } from '@nuxt/ui'
|
||||
|
||||
const items: StepperItem[] = [
|
||||
{
|
||||
title: 'Address',
|
||||
description: 'Add your address here',
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
const items = [
|
||||
import type { StepperItem } from '@nuxt/ui'
|
||||
|
||||
const items: StepperItem[] = [
|
||||
{
|
||||
slot: 'address',
|
||||
title: 'Address',
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
<script setup lang="ts">
|
||||
import type { StepperItem } from '@nuxt/ui'
|
||||
import { onMounted, ref } from 'vue'
|
||||
|
||||
const items = [
|
||||
const items: StepperItem[] = [
|
||||
{
|
||||
title: 'Address',
|
||||
description: 'Add your address here',
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
const items = [
|
||||
import type { StepperItem } from '@nuxt/ui'
|
||||
|
||||
const items: StepperItem[] = [
|
||||
{
|
||||
slot: 'address',
|
||||
title: 'Address',
|
||||
|
||||
@@ -97,10 +97,11 @@ function getHeader(column: Column<Payment>, label: string) {
|
||||
const isSorted = column.getIsSorted()
|
||||
|
||||
return h(UDropdownMenu, {
|
||||
content: {
|
||||
'content': {
|
||||
align: 'start'
|
||||
},
|
||||
items: [{
|
||||
'aria-label': 'Actions dropdown',
|
||||
'items': [{
|
||||
label: 'Asc',
|
||||
type: 'checkbox',
|
||||
icon: 'i-lucide-arrow-up-narrow-wide',
|
||||
@@ -126,11 +127,12 @@ function getHeader(column: Column<Payment>, label: string) {
|
||||
}
|
||||
}]
|
||||
}, () => h(UButton, {
|
||||
color: 'neutral',
|
||||
variant: 'ghost',
|
||||
'color': 'neutral',
|
||||
'variant': 'ghost',
|
||||
label,
|
||||
icon: isSorted ? (isSorted === 'asc' ? 'i-lucide-arrow-up-narrow-wide' : 'i-lucide-arrow-down-wide-narrow') : 'i-lucide-arrow-up-down',
|
||||
class: '-mx-2.5 data-[state=open]:bg-(--ui-bg-elevated)'
|
||||
'icon': isSorted ? (isSorted === 'asc' ? 'i-lucide-arrow-up-narrow-wide' : 'i-lucide-arrow-down-wide-narrow') : 'i-lucide-arrow-up-down',
|
||||
'class': '-mx-2.5 data-[state=open]:bg-(--ui-bg-elevated)',
|
||||
'aria-label': `Sort by ${isSorted === 'asc' ? 'descending' : 'ascending'}`
|
||||
}))
|
||||
}
|
||||
|
||||
|
||||
@@ -145,12 +145,12 @@ const columns: TableColumn<Payment>[] = [{
|
||||
header: ({ table }) => h(UCheckbox, {
|
||||
'modelValue': table.getIsSomePageRowsSelected() ? 'indeterminate' : table.getIsAllPageRowsSelected(),
|
||||
'onUpdate:modelValue': (value: boolean | 'indeterminate') => table.toggleAllPageRowsSelected(!!value),
|
||||
'ariaLabel': 'Select all'
|
||||
'aria-label': 'Select all'
|
||||
}),
|
||||
cell: ({ row }) => h(UCheckbox, {
|
||||
'modelValue': row.getIsSelected(),
|
||||
'onUpdate:modelValue': (value: boolean | 'indeterminate') => row.toggleSelected(!!value),
|
||||
'ariaLabel': 'Select row'
|
||||
'aria-label': 'Select row'
|
||||
}),
|
||||
enableSorting: false,
|
||||
enableHiding: false
|
||||
@@ -242,15 +242,17 @@ const columns: TableColumn<Payment>[] = [{
|
||||
}]
|
||||
|
||||
return h('div', { class: 'text-right' }, h(UDropdownMenu, {
|
||||
content: {
|
||||
'content': {
|
||||
align: 'end'
|
||||
},
|
||||
items
|
||||
items,
|
||||
'aria-label': 'Actions dropdown'
|
||||
}, () => h(UButton, {
|
||||
icon: 'i-lucide-ellipsis-vertical',
|
||||
color: 'neutral',
|
||||
variant: 'ghost',
|
||||
class: 'ml-auto'
|
||||
'icon': 'i-lucide-ellipsis-vertical',
|
||||
'color': 'neutral',
|
||||
'variant': 'ghost',
|
||||
'class': 'ml-auto',
|
||||
'aria-label': 'Actions dropdown'
|
||||
})))
|
||||
}
|
||||
}]
|
||||
@@ -294,6 +296,7 @@ function randomize() {
|
||||
variant="outline"
|
||||
trailing-icon="i-lucide-chevron-down"
|
||||
class="ml-auto"
|
||||
aria-label="Columns select dropdown"
|
||||
/>
|
||||
</UDropdownMenu>
|
||||
</div>
|
||||
|
||||
@@ -17,7 +17,7 @@ const { data, status } = await useFetch<User[]>('https://jsonplaceholder.typicod
|
||||
transform: (data) => {
|
||||
return data?.map(user => ({
|
||||
...user,
|
||||
avatar: { src: `https://i.pravatar.cc/120?img=${user.id}` }
|
||||
avatar: { src: `https://i.pravatar.cc/120?img=${user.id}`, alt: `${user.name} avatar` }
|
||||
})) || []
|
||||
},
|
||||
lazy: true
|
||||
|
||||
@@ -97,15 +97,17 @@ const columns: TableColumn<Payment>[] = [{
|
||||
id: 'actions',
|
||||
cell: ({ row }) => {
|
||||
return h('div', { class: 'text-right' }, h(UDropdownMenu, {
|
||||
content: {
|
||||
'content': {
|
||||
align: 'end'
|
||||
},
|
||||
items: getRowItems(row)
|
||||
'items': getRowItems(row),
|
||||
'aria-label': 'Actions dropdown'
|
||||
}, () => h(UButton, {
|
||||
icon: 'i-lucide-ellipsis-vertical',
|
||||
color: 'neutral',
|
||||
variant: 'ghost',
|
||||
class: 'ml-auto'
|
||||
'icon': 'i-lucide-ellipsis-vertical',
|
||||
'color': 'neutral',
|
||||
'variant': 'ghost',
|
||||
'class': 'ml-auto',
|
||||
'aria-label': 'Actions dropdown'
|
||||
})))
|
||||
}
|
||||
}]
|
||||
|
||||
@@ -48,14 +48,15 @@ const data = ref<Payment[]>([{
|
||||
const columns: TableColumn<Payment>[] = [{
|
||||
id: 'expand',
|
||||
cell: ({ row }) => h(UButton, {
|
||||
color: 'neutral',
|
||||
variant: 'ghost',
|
||||
icon: 'i-lucide-chevron-down',
|
||||
square: true,
|
||||
ui: {
|
||||
'color': 'neutral',
|
||||
'variant': 'ghost',
|
||||
'icon': 'i-lucide-chevron-down',
|
||||
'square': true,
|
||||
'aria-label': 'Expand',
|
||||
'ui': {
|
||||
leadingIcon: ['transition-transform', row.getIsExpanded() ? 'duration-200 rotate-180' : '']
|
||||
},
|
||||
onClick: () => row.toggleExpanded()
|
||||
'onClick': () => row.toggleExpanded()
|
||||
})
|
||||
}, {
|
||||
accessorKey: 'id',
|
||||
|
||||
@@ -50,12 +50,12 @@ const columns: TableColumn<Payment>[] = [{
|
||||
header: ({ table }) => h(UCheckbox, {
|
||||
'modelValue': table.getIsSomePageRowsSelected() ? 'indeterminate' : table.getIsAllPageRowsSelected(),
|
||||
'onUpdate:modelValue': (value: boolean | 'indeterminate') => table.toggleAllPageRowsSelected(!!value),
|
||||
'ariaLabel': 'Select all'
|
||||
'aria-label': 'Select all'
|
||||
}),
|
||||
cell: ({ row }) => h(UCheckbox, {
|
||||
'modelValue': row.getIsSelected(),
|
||||
'onUpdate:modelValue': (value: boolean | 'indeterminate') => row.toggleSelected(!!value),
|
||||
'ariaLabel': 'Select row'
|
||||
'aria-label': 'Select row'
|
||||
})
|
||||
}, {
|
||||
accessorKey: 'date',
|
||||
|
||||
@@ -50,12 +50,12 @@ const columns: TableColumn<Payment>[] = [{
|
||||
header: ({ table }) => h(UCheckbox, {
|
||||
'modelValue': table.getIsSomePageRowsSelected() ? 'indeterminate' : table.getIsAllPageRowsSelected(),
|
||||
'onUpdate:modelValue': (value: boolean | 'indeterminate') => table.toggleAllPageRowsSelected(!!value),
|
||||
'ariaLabel': 'Select all'
|
||||
'aria-label': 'Select all'
|
||||
}),
|
||||
cell: ({ row }) => h(UCheckbox, {
|
||||
'modelValue': row.getIsSelected(),
|
||||
'onUpdate:modelValue': (value: boolean | 'indeterminate') => row.toggleSelected(!!value),
|
||||
'ariaLabel': 'Select row'
|
||||
'aria-label': 'Select row'
|
||||
})
|
||||
}, {
|
||||
accessorKey: 'date',
|
||||
|
||||
@@ -95,7 +95,7 @@ function getDropdownActions(user: User): DropdownMenuItem[][] {
|
||||
<UTable :data="data" :columns="columns" class="flex-1">
|
||||
<template #name-cell="{ row }">
|
||||
<div class="flex items-center gap-3">
|
||||
<UAvatar :src="`https://i.pravatar.cc/120?img=${row.original.id}`" size="lg" />
|
||||
<UAvatar :src="`https://i.pravatar.cc/120?img=${row.original.id}`" size="lg" :alt="`${row.original.name} avatar`" />
|
||||
<div>
|
||||
<p class="font-medium text-(--ui-text-highlighted)">
|
||||
{{ row.original.name }}
|
||||
@@ -108,7 +108,7 @@ function getDropdownActions(user: User): DropdownMenuItem[][] {
|
||||
</template>
|
||||
<template #action-cell="{ row }">
|
||||
<UDropdownMenu :items="getDropdownActions(row.original)">
|
||||
<UButton icon="i-lucide-ellipsis-vertical" color="neutral" variant="ghost" />
|
||||
<UButton icon="i-lucide-ellipsis-vertical" color="neutral" variant="ghost" aria-label="Actions" />
|
||||
</UDropdownMenu>
|
||||
</template>
|
||||
</UTable>
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
const items = [
|
||||
import type { TabsItem } from '@nuxt/ui'
|
||||
|
||||
const items: TabsItem[] = [
|
||||
{
|
||||
label: 'Account',
|
||||
icon: 'i-lucide-user'
|
||||
|
||||
@@ -1,18 +1,20 @@
|
||||
<script setup lang="ts">
|
||||
import type { TabsItem } from '@nuxt/ui'
|
||||
|
||||
const items = [
|
||||
{
|
||||
label: 'Account',
|
||||
description: 'Make changes to your account here. Click save when you\'re done.',
|
||||
icon: 'i-lucide-user',
|
||||
slot: 'account'
|
||||
slot: 'account' as const
|
||||
},
|
||||
{
|
||||
label: 'Password',
|
||||
description: 'Change your password here. After saving, you\'ll be logged out.',
|
||||
icon: 'i-lucide-lock',
|
||||
slot: 'password'
|
||||
slot: 'password' as const
|
||||
}
|
||||
]
|
||||
] satisfies TabsItem[]
|
||||
|
||||
const state = reactive({
|
||||
name: 'Benjamin Canac',
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
const items = [
|
||||
import type { TabsItem } from '@nuxt/ui'
|
||||
|
||||
const items: TabsItem[] = [
|
||||
{
|
||||
label: 'Account'
|
||||
},
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<script setup lang="ts">
|
||||
import type { TreeItem } from '@nuxt/ui'
|
||||
|
||||
const items: TreeItem[] = [
|
||||
const items = [
|
||||
{
|
||||
label: 'app/',
|
||||
slot: 'app',
|
||||
slot: 'app' as const,
|
||||
defaultExpanded: true,
|
||||
children: [{
|
||||
label: 'composables/',
|
||||
@@ -24,7 +24,7 @@ const items: TreeItem[] = [
|
||||
},
|
||||
{ label: 'app.vue', icon: 'i-vscode-icons-file-type-vue' },
|
||||
{ label: 'nuxt.config.ts', icon: 'i-vscode-icons-file-type-nuxt' }
|
||||
]
|
||||
] satisfies TreeItem[]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -25,7 +25,7 @@ const items: TreeItem[] = [
|
||||
{ label: 'nuxt.config.ts', icon: 'i-vscode-icons-file-type-nuxt' }
|
||||
]
|
||||
|
||||
const value = ref(items[items.length - 1])
|
||||
const value = ref()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -111,7 +111,7 @@ function setBlackAsPrimary(value: boolean) {
|
||||
v-for="color in neutralColors"
|
||||
:key="color"
|
||||
:label="color"
|
||||
:chip="color"
|
||||
:chip="color === 'neutral' ? 'old-neutral' : color"
|
||||
:selected="neutral === color"
|
||||
@click="neutral = color"
|
||||
/>
|
||||
|
||||
@@ -84,10 +84,10 @@ export function useLinks() {
|
||||
label: 'Community',
|
||||
icon: 'i-lucide-users',
|
||||
children: [{
|
||||
label: 'Roadmap',
|
||||
description: 'Track our development progress in real-time.',
|
||||
icon: 'i-lucide-map',
|
||||
to: '/roadmap'
|
||||
icon: 'i-lucide-presentation',
|
||||
label: 'Showcase',
|
||||
description: 'Check out some amazing projects built with Nuxt UI.',
|
||||
to: '/showcase'
|
||||
}, {
|
||||
label: 'Devtools Integration',
|
||||
description: 'Integrate Nuxt UI with Nuxt Devtools with Compodium.',
|
||||
@@ -112,5 +112,5 @@ export function useLinks() {
|
||||
icon: 'i-lucide-rocket',
|
||||
to: 'https://github.com/nuxt/ui/releases',
|
||||
target: '_blank'
|
||||
}].filter(Boolean))
|
||||
}])
|
||||
}
|
||||
|
||||
66
docs/app/composables/useSearchLinks.ts
Normal file
66
docs/app/composables/useSearchLinks.ts
Normal file
@@ -0,0 +1,66 @@
|
||||
export function useSearchLinks() {
|
||||
return [{
|
||||
label: 'Docs',
|
||||
icon: 'i-lucide-square-play',
|
||||
to: '/getting-started'
|
||||
}, {
|
||||
label: 'Components',
|
||||
icon: 'i-lucide-square-code',
|
||||
to: '/components'
|
||||
}, {
|
||||
icon: 'i-lucide-sparkles',
|
||||
label: 'Pro > Features',
|
||||
description: 'A collection of premium Vue components.',
|
||||
to: '/pro'
|
||||
}, {
|
||||
icon: 'i-lucide-credit-card',
|
||||
label: 'Pro > Pricing',
|
||||
description: 'Free in development, buy when ready to launch.',
|
||||
to: '/pro/pricing'
|
||||
}, {
|
||||
icon: 'i-lucide-panels-top-left',
|
||||
label: 'Pro > Templates',
|
||||
description: 'Official templates made with Nuxt UI Pro.',
|
||||
to: '/pro/templates'
|
||||
}, {
|
||||
icon: 'i-lucide-circle-check',
|
||||
label: 'Pro > Activate',
|
||||
description: 'Enable Nuxt UI Pro in your production projects.',
|
||||
to: '/pro/activate'
|
||||
}, {
|
||||
label: 'Figma',
|
||||
icon: 'i-simple-icons-figma',
|
||||
to: '/figma'
|
||||
}, {
|
||||
icon: 'i-lucide-presentation',
|
||||
label: 'Community > Showcase',
|
||||
description: 'Check out some of the amazing projects built with Nuxt UI.',
|
||||
to: '/showcase'
|
||||
}, {
|
||||
label: 'Community > Contribution',
|
||||
description: 'A comprehensive guide on contributing to Nuxt UI, including project structure, development workflow, and best practices.',
|
||||
icon: 'i-lucide-git-pull-request-arrow',
|
||||
to: '/getting-started/contribution'
|
||||
}, {
|
||||
label: 'Community > Roadmap',
|
||||
description: 'Track our development progress in real-time.',
|
||||
icon: 'i-lucide-map',
|
||||
to: '/roadmap'
|
||||
}, {
|
||||
label: 'Community > Devtools',
|
||||
description: 'Integrate Nuxt UI with Nuxt Devtools with Compodium.',
|
||||
icon: 'i-lucide-code',
|
||||
to: 'https://github.com/romhml/compodium',
|
||||
target: '_blank'
|
||||
}, {
|
||||
label: 'Community > Team',
|
||||
description: 'Meet the team behind Nuxt UI.',
|
||||
icon: 'i-lucide-users',
|
||||
to: '/team'
|
||||
}, {
|
||||
label: 'Releases',
|
||||
icon: 'i-lucide-rocket',
|
||||
to: 'https://github.com/nuxt/ui/releases',
|
||||
target: '_blank'
|
||||
}]
|
||||
}
|
||||
@@ -15,6 +15,7 @@ const { data: files } = useLazyAsyncData('search', () => queryCollectionSearchSe
|
||||
})
|
||||
|
||||
const links = useLinks()
|
||||
const searchLinks = useSearchLinks()
|
||||
const color = computed(() => colorMode.value === 'dark' ? (colors as any)[appConfig.ui.colors.neutral][900] : 'white')
|
||||
const radius = computed(() => `:root { --ui-radius: ${appConfig.theme.radius}rem; }`)
|
||||
const blackAsPrimary = computed(() => appConfig.theme.blackAsPrimary ? `:root { --ui-primary: black; } .dark { --ui-primary: white; }` : ':root {}')
|
||||
@@ -66,6 +67,7 @@ provide('navigation', mappedNavigation)
|
||||
|
||||
<ClientOnly>
|
||||
<LazyUContentSearch
|
||||
:links="searchLinks"
|
||||
:files="files"
|
||||
:groups="[{
|
||||
id: 'framework',
|
||||
|
||||
@@ -176,7 +176,11 @@ community:
|
||||
links:
|
||||
- label: Star on GitHub
|
||||
color: neutral
|
||||
variant: outline
|
||||
to: https://github.com/nuxt/ui
|
||||
target: _blank
|
||||
icon: i-lucide-star
|
||||
- label: Meet the team
|
||||
color: neutral
|
||||
variant: outline
|
||||
to: /team
|
||||
trailingIcon: i-lucide-arrow-right
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
<script setup lang="ts">
|
||||
import { kebabCase } from 'scule'
|
||||
import type { ContentNavigationItem } from '@nuxt/content'
|
||||
import { findPageBreadcrumb, mapContentNavigation } from '#ui-pro/utils/content'
|
||||
import type { PageLink } from '@nuxt/ui-pro'
|
||||
import { findPageBreadcrumb, mapContentNavigation } from '@nuxt/ui-pro/utils/content'
|
||||
|
||||
const route = useRoute()
|
||||
const { framework, module } = useSharedData()
|
||||
@@ -66,9 +67,9 @@ if (!import.meta.prerender) {
|
||||
|
||||
const type = page.value?.path.includes('components') ? 'Vue Component ' : page.value?.path.includes('composables') ? 'Vue Composable ' : ''
|
||||
useSeoMeta({
|
||||
titleTemplate: `%s ${type}- Nuxt UI ${page.value.module === 'ui-pro' ? 'Pro' : ''} v3${page.value.framework === 'vue' ? ' for Vue' : ''}`,
|
||||
titleTemplate: `%s ${type}- Nuxt UI ${page.value.module === 'ui-pro' ? 'Pro' : ''} ${page.value.framework === 'vue' ? ' for Vue' : ''}`,
|
||||
title: page.value.navigation?.title ? page.value.navigation.title : page.value.title,
|
||||
ogTitle: `${page.value.navigation?.title ? page.value.navigation.title : page.value.title} ${type}- Nuxt UI ${page.value.module === 'ui-pro' ? 'Pro' : ''} v3${page.value.framework === 'vue' ? ' for Vue' : ''}`,
|
||||
ogTitle: `${page.value.navigation?.title ? page.value.navigation.title : page.value.title} ${type}- Nuxt UI ${page.value.module === 'ui-pro' ? 'Pro' : ''} ${page.value.framework === 'vue' ? ' for Vue' : ''}`,
|
||||
description: page.value.description,
|
||||
ogDescription: page.value.description
|
||||
})
|
||||
@@ -100,15 +101,25 @@ const communityLinks = computed(() => [{
|
||||
label: 'Star on GitHub',
|
||||
to: `https://github.com/nuxt/${page.value?.module === 'ui-pro' ? 'ui-pro' : 'ui'}`,
|
||||
target: '_blank'
|
||||
}, module.value === 'ui-pro' && {
|
||||
icon: 'i-lucide-credit-card',
|
||||
label: 'Purchase a license',
|
||||
to: 'https://nuxt.lemonsqueezy.com/checkout/buy/057dacb2-87ba-4dc1-9256-59ee5b3bd394',
|
||||
target: '_blank'
|
||||
}, module.value === 'ui-pro' && {
|
||||
icon: 'i-lucide-ticket-percent',
|
||||
label: 'Become an affiliate',
|
||||
to: 'https://nuxt.lemonsqueezy.com/affiliates',
|
||||
target: '_blank'
|
||||
}, {
|
||||
icon: 'i-lucide-life-buoy',
|
||||
icon: 'i-lucide-git-pull-request-arrow',
|
||||
label: 'Contribution',
|
||||
to: '/getting-started/contribution'
|
||||
}, {
|
||||
label: 'Roadmap',
|
||||
icon: 'i-lucide-map',
|
||||
to: '/roadmap'
|
||||
}])
|
||||
}].filter(Boolean) as PageLink[])
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -136,7 +147,7 @@ const communityLinks = computed(() => [{
|
||||
v-bind="link"
|
||||
>
|
||||
<template v-if="link.avatar" #leading>
|
||||
<UAvatar v-bind="link.avatar" size="2xs" />
|
||||
<UAvatar v-bind="link.avatar" size="2xs" :alt="`${link.label} avatar`" />
|
||||
</template>
|
||||
</UButton>
|
||||
</template>
|
||||
|
||||
@@ -7,7 +7,7 @@ const title = 'Vue Components'
|
||||
const description = 'Explore 99+ customizable UI components for Vue and Nuxt built with Tailwind CSS and Reka UI.'
|
||||
|
||||
useSeoMeta({
|
||||
titleTemplate: `%s - Nuxt UI`,
|
||||
titleTemplate: '%s - Nuxt UI',
|
||||
title,
|
||||
description,
|
||||
ogTitle: `${title} - Nuxt UI`,
|
||||
@@ -169,6 +169,7 @@ onMounted(() => {
|
||||
:loading="index >= 4 ? 'lazy' : 'eager'"
|
||||
width="640"
|
||||
height="360"
|
||||
:alt="`${component.name} preview`"
|
||||
/>
|
||||
</div>
|
||||
</UPageCard>
|
||||
|
||||
@@ -5,6 +5,7 @@ import { animate } from 'motion-v'
|
||||
import { joinURL } from 'ufo'
|
||||
|
||||
const { url } = useSiteConfig()
|
||||
|
||||
useSeoMeta({
|
||||
title: page.title,
|
||||
description: page.description,
|
||||
@@ -155,7 +156,7 @@ onMounted(async () => {
|
||||
:src="item.src"
|
||||
:alt="item.alt"
|
||||
class="w-full h-auto rounded-[calc(var(--ui-radius)*2)]"
|
||||
lazy
|
||||
loading="lazy"
|
||||
/>
|
||||
</template>
|
||||
</UTabs>
|
||||
@@ -165,7 +166,7 @@ onMounted(async () => {
|
||||
v-if="page.section2.image"
|
||||
v-bind="page.section2.image"
|
||||
class="w-full h-auto rounded-[calc(var(--ui-radius)*2)]"
|
||||
lazy
|
||||
loading="lazy"
|
||||
/>
|
||||
</UPageSection>
|
||||
<UPageSection v-bind="page.section3" orientation="horizontal" :ui="{ container: 'py-16 sm:pt-16 lg:pt-16' }">
|
||||
@@ -173,7 +174,7 @@ onMounted(async () => {
|
||||
v-if="page.section3.image"
|
||||
v-bind="page.section3.image"
|
||||
class="w-full h-auto rounded-[calc(var(--ui-radius)*2)]"
|
||||
lazy
|
||||
loading="lazy"
|
||||
/>
|
||||
</UPageSection>
|
||||
<USeparator />
|
||||
@@ -198,7 +199,7 @@ onMounted(async () => {
|
||||
v-if="step.image"
|
||||
v-bind="step.image"
|
||||
class="rounded-(--ui-radius)"
|
||||
lazy
|
||||
loading="lazy"
|
||||
/>
|
||||
<div>
|
||||
<h2 class="font-semibold inline-flex items-center gap-x-1">
|
||||
@@ -272,6 +273,7 @@ onMounted(async () => {
|
||||
:key="index"
|
||||
v-bind="logo"
|
||||
class="h-6 shrink-0 max-w-[140px] filter invert dark:invert-0"
|
||||
loading="lazy"
|
||||
>
|
||||
</UPageMarquee>
|
||||
</UPageCTA>
|
||||
|
||||
@@ -23,18 +23,7 @@ const { data: components } = await useAsyncData('ui-components', () => {
|
||||
.all()
|
||||
})
|
||||
|
||||
const { data: module } = await useFetch<{
|
||||
stats: {
|
||||
downloads: number
|
||||
stars: number
|
||||
}
|
||||
contributors: {
|
||||
username: string
|
||||
}[]
|
||||
}>('https://api.nuxt.com/modules/ui', {
|
||||
key: 'stats',
|
||||
transform: ({ stats, contributors }) => ({ stats, contributors })
|
||||
})
|
||||
const { data: module } = await useFetch('/api/module.json')
|
||||
|
||||
const { format } = Intl.NumberFormat('en', { notation: 'compact' })
|
||||
|
||||
@@ -85,7 +74,7 @@ useIntersectionObserver(contributorsRef, ([entry]) => {
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<LazySkyBg />
|
||||
<LazySkyBg is-index />
|
||||
|
||||
<div class="h-[344px] lg:h-full lg:relative w-full lg:min-h-[calc(100vh-var(--ui-header-height)-1px)] overflow-hidden">
|
||||
<UPageMarquee
|
||||
@@ -103,10 +92,14 @@ useIntersectionObserver(contributorsRef, ([entry]) => {
|
||||
:to="component.path"
|
||||
>
|
||||
<UColorModeImage
|
||||
|
||||
:light="`${component.path.replace('/components/', '/components/light/')}.png`"
|
||||
:dark="`${component.path.replace('/components/', '/components/dark/')}.png`"
|
||||
:alt="`${component.title} preview`"
|
||||
width="290"
|
||||
height="163"
|
||||
format="webp"
|
||||
class="hover:scale-105 lg:hover:scale-110 transition-transform aspect-video w-full border-x lg:border-x-0 lg:border-y border-(--ui-border) 2xl:border-y-0"
|
||||
loading="lazy"
|
||||
/>
|
||||
<UBadge color="neutral" variant="outline" size="md" :label="component.title" class="hidden lg:block absolute mx-auto top-4 left-6 xl:left-4 group-hover/link:opacity-100 opacity-0 transition-all duration-300 pointer-events-none -translate-y-2 group-hover/link:translate-y-0" />
|
||||
</ULink>
|
||||
@@ -130,7 +123,12 @@ useIntersectionObserver(contributorsRef, ([entry]) => {
|
||||
<UColorModeImage
|
||||
:light="`${component.path.replace('/components/', '/components/light/')}.png`"
|
||||
:dark="`${component.path.replace('/components/', '/components/dark/')}.png`"
|
||||
:alt="`${component.title} preview`"
|
||||
width="290"
|
||||
height="163"
|
||||
format="webp"
|
||||
class="hover:scale-105 lg:hover:scale-110 transition-transform aspect-video w-full border-x lg:border-x-0 lg:border-y border-(--ui-border) 2xl:border-y-0"
|
||||
loading="lazy"
|
||||
/>
|
||||
<UBadge color="neutral" variant="outline" size="md" :label="component.title" class="hidden lg:block absolute mx-auto top-4 left-6 xl:left-4 group-hover/link:opacity-100 opacity-0 transition-all duration-300 pointer-events-none -translate-y-2 group-hover/link:translate-y-0" />
|
||||
</ULink>
|
||||
@@ -152,7 +150,9 @@ useIntersectionObserver(contributorsRef, ([entry]) => {
|
||||
:in-view-options="{ once: true }"
|
||||
class="flex items-start gap-x-3 relative group"
|
||||
>
|
||||
<NuxtLink v-if="feature.to" :to="feature.to" class="absolute inset-0 z-10" />
|
||||
<NuxtLink v-if="feature.to" :to="feature.to" class="absolute inset-0 z-10">
|
||||
<span class="sr-only">Go to {{ feature.title }}</span>
|
||||
</NuxtLink>
|
||||
|
||||
<div class="relative p-3">
|
||||
<svg class="absolute inset-0" viewBox="0 0 44 44" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
@@ -165,12 +165,12 @@ useIntersectionObserver(contributorsRef, ([entry]) => {
|
||||
<circle cx="6.53711" cy="37.4551" r="1.5" fill="var(--ui-border-accented)" />
|
||||
<circle cx="38.5957" cy="37.4551" r="1.5" fill="var(--ui-border-accented)" />
|
||||
</svg>
|
||||
<UIcon :name="feature.icon" class="size-5 flex-shrink-0" />
|
||||
<UIcon :name="feature.icon" class="size-5 shrink-0" />
|
||||
</div>
|
||||
<div class="flex flex-col">
|
||||
<h2 class="font-medium text-(--ui-text-highlighted) inline-flex items-center gap-x-1">
|
||||
{{ feature.title }}
|
||||
<UIcon v-if="feature.to" name="i-lucide-arrow-right" class="size-4 flex-shrink-0 opacity-0 group-hover:opacity-100 transition-all duration-200 -translate-x-1 group-hover:translate-x-0" />
|
||||
<UIcon v-if="feature.to" name="i-lucide-arrow-right" class="size-4 shrink-0 opacity-0 group-hover:opacity-100 transition-all duration-200 -translate-x-1 group-hover:translate-x-0" />
|
||||
</h2>
|
||||
<p class="text-sm text-(--ui-text-muted)">
|
||||
{{ feature.description }}
|
||||
@@ -218,26 +218,32 @@ useIntersectionObserver(contributorsRef, ([entry]) => {
|
||||
class="border-b border-(--ui-border)"
|
||||
>
|
||||
<template #features>
|
||||
<NuxtLink to="https://npm.chart.dev/@nuxt/ui" target="_blank" class="min-w-0">
|
||||
<p class="text-4xl font-semibold text-(--ui-text-highlighted) truncate">
|
||||
{{ format(module?.stats?.downloads ?? 0) }}+
|
||||
</p>
|
||||
<p class="text-(--ui-text-muted) text-sm truncate">monthly downloads</p>
|
||||
</NuxtLink>
|
||||
<li>
|
||||
<NuxtLink to="https://npm.chart.dev/@nuxt/ui" target="_blank" class="min-w-0">
|
||||
<p class="text-4xl font-semibold text-(--ui-text-highlighted) truncate">
|
||||
{{ format(module?.stats?.downloads ?? 0) }}+
|
||||
</p>
|
||||
<p class="text-(--ui-text-muted) text-sm truncate">monthly downloads</p>
|
||||
</NuxtLink>
|
||||
</li>
|
||||
|
||||
<NuxtLink to="https://github.com/nuxt/ui" target="_blank" class="min-w-0">
|
||||
<p class="text-4xl font-semibold text-(--ui-text-highlighted) truncate">
|
||||
{{ format(module?.stats?.stars ?? 0) }}+
|
||||
</p>
|
||||
<p class="text-(--ui-text-muted) text-sm truncate">GitHub stars</p>
|
||||
</NuxtLink>
|
||||
<li>
|
||||
<NuxtLink to="https://github.com/nuxt/ui" target="_blank" class="min-w-0">
|
||||
<p class="text-4xl font-semibold text-(--ui-text-highlighted) truncate">
|
||||
{{ format(module?.stats?.stars ?? 0) }}+
|
||||
</p>
|
||||
<p class="text-(--ui-text-muted) text-sm truncate">GitHub stars</p>
|
||||
</NuxtLink>
|
||||
</li>
|
||||
|
||||
<NuxtLink to="https://github.com/nuxt/ui/graphs/contributors" target="_blank" class="min-w-0">
|
||||
<p class="text-4xl font-semibold text-(--ui-text-highlighted) truncate">
|
||||
175+
|
||||
</p>
|
||||
<p class="text-(--ui-text-muted) text-sm truncate">Contributors</p>
|
||||
</NuxtLink>
|
||||
<li>
|
||||
<NuxtLink to="https://github.com/nuxt/ui/graphs/contributors" target="_blank" class="min-w-0">
|
||||
<p class="text-4xl font-semibold text-(--ui-text-highlighted) truncate">
|
||||
175+
|
||||
</p>
|
||||
<p class="text-(--ui-text-muted) text-sm truncate">Contributors</p>
|
||||
</NuxtLink>
|
||||
</li>
|
||||
</template>
|
||||
|
||||
<div ref="contributorsRef" class="p-4 sm:px-6 md:px-8 lg:px-12 xl:px-14 overflow-hidden flex relative">
|
||||
@@ -296,8 +302,8 @@ useIntersectionObserver(contributorsRef, ([entry]) => {
|
||||
:src="`/pro/blocks/image${i}.png`"
|
||||
width="460"
|
||||
height="258"
|
||||
:alt="`Nuxt UI Pro Screenshot ${i}`"
|
||||
loading="lazy"
|
||||
:alt="`Nuxt UI Pro Screenshot ${i}`"
|
||||
class="aspect-video border border-(--ui-border) rounded-[calc(var(--ui-radius)*2)] bg-white"
|
||||
>
|
||||
</UPageMarquee>
|
||||
|
||||
@@ -12,7 +12,7 @@ const { url } = useSiteConfig()
|
||||
useSeoMeta({
|
||||
title,
|
||||
description,
|
||||
ogTitle: `${title} - Nuxt UI Pro`,
|
||||
ogTitle: title,
|
||||
ogDescription: description,
|
||||
ogImage: joinURL(url, '/pro/og-image.png')
|
||||
})
|
||||
|
||||
@@ -9,10 +9,10 @@ const { url } = useSiteConfig()
|
||||
|
||||
useSeoMeta({
|
||||
title: page.title,
|
||||
ogTitle: page.title,
|
||||
ogImage: joinURL(url, '/pro/og-image.png'),
|
||||
description: page.description,
|
||||
ogDescription: page.description
|
||||
ogTitle: page.title,
|
||||
ogDescription: page.description,
|
||||
ogImage: joinURL(url, '/pro/og-image.png')
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
@@ -7,8 +7,8 @@ const { url } = useSiteConfig()
|
||||
|
||||
useSeoMeta({
|
||||
title: page.title,
|
||||
ogTitle: page.title,
|
||||
description: page.description,
|
||||
ogTitle: page.title,
|
||||
ogDescription: page.description,
|
||||
ogImage: joinURL(url, '/pro/og-image.png')
|
||||
})
|
||||
@@ -81,6 +81,7 @@ useSeoMeta({
|
||||
:key="index"
|
||||
v-bind="logo"
|
||||
class="h-6 shrink-0 max-w-[140px] filter invert dark:invert-0"
|
||||
loading="lazy"
|
||||
>
|
||||
</UPageMarquee>
|
||||
<UContainer>
|
||||
|
||||
@@ -56,6 +56,7 @@ useSeoMeta({
|
||||
v-if="template.thumbnail"
|
||||
v-bind="template.thumbnail"
|
||||
class="w-full h-auto border lg:border-y lg:border-x-0 border-(--ui-border) rounded-(--ui-radius) lg:rounded-none"
|
||||
:alt="`Template ${index} thumbnail`"
|
||||
width="656"
|
||||
height="369"
|
||||
loading="lazy"
|
||||
@@ -66,7 +67,7 @@ useSeoMeta({
|
||||
:items="(template.images as any[])"
|
||||
dots
|
||||
>
|
||||
<NuxtImg v-bind="item" class="w-full h-full object-cover" width="576" height="360" />
|
||||
<NuxtImg v-bind="item" class="w-full h-full object-cover" width="576" height="360" loading="lazy" />
|
||||
</UCarousel>
|
||||
<Placeholder v-else class="w-full h-full aspect-video" />
|
||||
</Motion>
|
||||
|
||||
@@ -13,7 +13,7 @@ const description = page.value.description
|
||||
useSeoMeta({
|
||||
title,
|
||||
description,
|
||||
ogTitle: `${title} - Nuxt UI Pro`,
|
||||
ogTitle: title,
|
||||
ogDescription: description,
|
||||
ogImage: joinURL(url, '/pro/og-image.png')
|
||||
})
|
||||
|
||||
@@ -5,8 +5,9 @@ const description = 'Discover our Volta board for @nuxt/ui development status.'
|
||||
useSeoMeta({
|
||||
titleTemplate: '%s - Nuxt UI',
|
||||
title,
|
||||
ogTitle: 'Nuxt UI Roadmap',
|
||||
description
|
||||
description,
|
||||
ogTitle: `${title} - Nuxt UI`,
|
||||
ogDescription: description
|
||||
})
|
||||
|
||||
defineOgImageComponent('Docs', {
|
||||
|
||||
83
docs/app/pages/showcase.vue
Normal file
83
docs/app/pages/showcase.vue
Normal file
@@ -0,0 +1,83 @@
|
||||
<script setup lang="ts">
|
||||
const { data: page } = await useAsyncData('showcase', () => queryCollection('showcase').first())
|
||||
if (!page.value) {
|
||||
throw createError({ statusCode: 404, statusMessage: 'Page not found', fatal: true })
|
||||
}
|
||||
|
||||
useSeoMeta({
|
||||
titleTemplate: `%s - Nuxt UI`,
|
||||
title: page.value.title,
|
||||
description: page.value.description,
|
||||
ogTitle: `${page.value.title} - Nuxt UI`,
|
||||
ogDescription: page.value.description
|
||||
})
|
||||
|
||||
defineOgImageComponent('Docs', {
|
||||
headline: 'Community'
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UMain v-if="page">
|
||||
<UPageHero
|
||||
:title="page.hero.title"
|
||||
:description="page.hero.description"
|
||||
:links="page.hero.links"
|
||||
:ui="{
|
||||
wrapper: 'lg:px-12',
|
||||
container: 'relative'
|
||||
}"
|
||||
>
|
||||
<template #top>
|
||||
<div class="absolute z-[-1] rounded-full bg-(--ui-primary) blur-[300px] size-60 sm:size-80 transform -translate-x-1/2 left-1/2 -translate-y-80" />
|
||||
</template>
|
||||
|
||||
<LazyStarsBg />
|
||||
|
||||
<div aria-hidden="true" class="hidden lg:block absolute z-[-1] border-x border-(--ui-border) inset-0 mx-4 sm:mx-6 lg:mx-8" />
|
||||
|
||||
<div class="border-l border-t border-(--ui-border)">
|
||||
<ul class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 items-start justify-center divide-y divide-x divide-(--ui-border)">
|
||||
<li
|
||||
v-for="item in page.items"
|
||||
:key="item.name"
|
||||
class="group relative flex items-center justify-center flex-1 size-full p-2 last:border-r last:border-b border-(--ui-border) overflow-hidden"
|
||||
>
|
||||
<NuxtLink class="inset-0 absolute" :to="item.url" target="_blank">
|
||||
<span class="sr-only">Go to {{ item.name }}</span>
|
||||
</NuxtLink>
|
||||
|
||||
<NuxtImg
|
||||
:src="`/assets/showcase/${item.name.toLowerCase().replace(/\s/g, '-')}.png`"
|
||||
:alt="`Screenshot of ${item.name}`"
|
||||
width="327"
|
||||
height="184"
|
||||
:modifiers="{
|
||||
position: 'top'
|
||||
}"
|
||||
class="aspect-[16/9] size-full opacity-75 group-hover:opacity-100 group-hover:scale-110 duration-200 transition-[scale,opacity] pointer-events-none"
|
||||
/>
|
||||
|
||||
<div class="absolute flex items-center px-2.5 py-0.75 gap-1 opacity-0 group-hover:opacity-100 transition-opacity duration-200 pointer-events-none bg-black/90 rounded-full">
|
||||
<span class="text-sm text-white font-medium">
|
||||
{{ item.name }}
|
||||
</span>
|
||||
<UIcon name="i-lucide-arrow-up-right" class="size-4 shrink-0 text-white" />
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-center -mb-[36px]">
|
||||
<UButton
|
||||
label="Submit your project"
|
||||
trailing-icon="i-lucide-plus"
|
||||
color="neutral"
|
||||
size="lg"
|
||||
to="https://github.com/nuxt/ui/edit/v3/docs/content/showcase.yml"
|
||||
target="_blank"
|
||||
/>
|
||||
</div>
|
||||
</UPageHero>
|
||||
</UMain>
|
||||
</template>
|
||||
156
docs/app/pages/team.vue
Normal file
156
docs/app/pages/team.vue
Normal file
@@ -0,0 +1,156 @@
|
||||
<script setup lang="ts">
|
||||
const title = 'Meet the Team'
|
||||
const description = 'The development of Nuxt UI is led by a community of developers from all over the world.'
|
||||
|
||||
useSeoMeta({
|
||||
titleTemplate: '%s - Nuxt UI',
|
||||
title,
|
||||
description,
|
||||
ogTitle: `${title} - Nuxt UI`,
|
||||
ogDescription: description
|
||||
})
|
||||
|
||||
defineOgImageComponent('Docs', {
|
||||
headline: 'Community'
|
||||
})
|
||||
|
||||
const { data: module } = await useFetch('/api/module.json')
|
||||
|
||||
const contributors = computed(() => module.value?.contributors?.filter(contributor => !module.value?.team?.find(user => user.login === contributor.username)))
|
||||
|
||||
const icons = {
|
||||
website: 'i-lucide-link',
|
||||
twitter: 'i-simple-icons-x',
|
||||
twitch: 'i-simple-icons-twitch',
|
||||
youtube: 'i-simple-icons-youtube',
|
||||
instagram: 'i-simple-icons-instagram',
|
||||
linkedin: 'i-simple-icons-linkedin',
|
||||
mastodon: 'i-simple-icons-mastodon',
|
||||
bluesky: 'i-simple-icons-bluesky',
|
||||
github: 'i-simple-icons-github'
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UMain>
|
||||
<UPageHero
|
||||
:title="title"
|
||||
:description="description"
|
||||
class="relative"
|
||||
orientation="vertical"
|
||||
:ui="{ title: 'text-balance', container: 'relative' }"
|
||||
>
|
||||
<template #top>
|
||||
<div class="absolute z-[-1] rounded-full bg-(--ui-primary) blur-[300px] size-60 sm:size-80 transform -translate-x-1/2 left-1/2 -translate-y-80" />
|
||||
</template>
|
||||
|
||||
<LazyStarsBg />
|
||||
</UPageHero>
|
||||
|
||||
<UPageSection :ui="{ container: '!pt-0' }">
|
||||
<UPageGrid class="xl:grid-cols-4">
|
||||
<UPageCard
|
||||
v-for="(user, index) in module?.team"
|
||||
:key="index"
|
||||
:title="user.name"
|
||||
:description="[user.pronouns, user.location].filter(Boolean).join(' ・ ')"
|
||||
:ui="{
|
||||
container: 'gap-y-4 lg:p-8',
|
||||
leading: 'flex justify-center',
|
||||
title: 'text-center',
|
||||
description: 'text-center text-(--ui-text-muted)'
|
||||
}"
|
||||
variant="subtle"
|
||||
>
|
||||
<template #leading>
|
||||
<UAvatar
|
||||
:src="`https://ipx.nuxt.com/f_auto,s_80x80/gh_avatar/${user.login}`"
|
||||
:srcset="`https://ipx.nuxt.com/f_auto,s_160x160/gh_avatar/${user.login} 2x`"
|
||||
size="3xl"
|
||||
class="mx-auto"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<div class="flex items-center justify-center gap-1">
|
||||
<UButton
|
||||
v-for="(link, key) in user.socialAccounts"
|
||||
:key="key"
|
||||
color="neutral"
|
||||
variant="link"
|
||||
:to="link.url"
|
||||
:icon="icons[key as keyof typeof icons] || icons.website"
|
||||
:alt="`Link to ${user.name}'s ${key} profile`"
|
||||
target="_blank"
|
||||
size="sm"
|
||||
/>
|
||||
<UButton
|
||||
:to="`https://github.com/${user.login}`"
|
||||
color="neutral"
|
||||
variant="link"
|
||||
:alt="`Link to ${user.name}'s GitHub profile`"
|
||||
:icon="icons.github"
|
||||
target="_blank"
|
||||
/>
|
||||
<UButton
|
||||
v-if="user.websiteUrl"
|
||||
:to="user.websiteUrl"
|
||||
color="neutral"
|
||||
variant="link"
|
||||
:alt="`Link to ${user.name}'s personal website`"
|
||||
:icon="icons.website"
|
||||
target="_blank"
|
||||
/>
|
||||
</div>
|
||||
<div v-if="user.sponsorsListing" class="flex items-center justify-center">
|
||||
<UButton
|
||||
:to="user.sponsorsListing"
|
||||
target="_blank"
|
||||
color="neutral"
|
||||
variant="subtle"
|
||||
icon="i-lucide-heart"
|
||||
label="Sponsor"
|
||||
:ui="{ leadingIcon: 'text-pink-500 dark:text-pink-400' }"
|
||||
/>
|
||||
</div>
|
||||
</UPageCard>
|
||||
</UPageGrid>
|
||||
|
||||
<ProseHr />
|
||||
|
||||
<UPageGrid class="xl:grid-cols-6">
|
||||
<UPageCard
|
||||
v-for="contributor in contributors"
|
||||
:key="contributor.username"
|
||||
:title="contributor.username"
|
||||
:ui="{
|
||||
container: 'gap-y-2',
|
||||
leading: 'flex justify-center',
|
||||
title: 'text-center',
|
||||
description: 'text-center text-(--ui-text-muted)'
|
||||
}"
|
||||
>
|
||||
<template #leading>
|
||||
<UAvatar
|
||||
:src="`https://ipx.nuxt.com/f_auto,s_80x80/gh_avatar/${contributor.username}`"
|
||||
:srcset="`https://ipx.nuxt.com/f_auto,s_160x160/gh_avatar/${contributor.username} 2x`"
|
||||
size="3xl"
|
||||
class="mx-auto"
|
||||
loading="lazy"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<div class="flex items-center justify-center gap-1">
|
||||
<UButton
|
||||
:to="`https://github.com/${contributor.username}`"
|
||||
color="neutral"
|
||||
variant="link"
|
||||
:alt="`Link to ${contributor.username}'s GitHub profile`"
|
||||
:icon="icons.github"
|
||||
target="_blank"
|
||||
/>
|
||||
</div>
|
||||
</UPageCard>
|
||||
</UPageGrid>
|
||||
</UPageSection>
|
||||
</UMain>
|
||||
</template>
|
||||
@@ -1,6 +1,18 @@
|
||||
import { defineCollection, z } from '@nuxt/content'
|
||||
import { resolve } from 'node:path'
|
||||
|
||||
const Button = z.object({
|
||||
label: z.string(),
|
||||
icon: z.string().optional(),
|
||||
trailingIcon: z.string().optional(),
|
||||
to: z.string().optional(),
|
||||
color: z.enum(['primary', 'neutral', 'success', 'warning', 'error', 'info']).optional(),
|
||||
size: z.enum(['xs', 'sm', 'md', 'lg', 'xl']).optional(),
|
||||
variant: z.enum(['solid', 'outline', 'subtle', 'soft', 'ghost', 'link']).optional(),
|
||||
id: z.string().optional(),
|
||||
target: z.enum(['_blank', '_self']).optional()
|
||||
})
|
||||
|
||||
const schema = z.object({
|
||||
category: z.enum(['layout', 'form', 'element', 'navigation', 'data', 'overlay']).optional(),
|
||||
framework: z.string().optional(),
|
||||
@@ -42,5 +54,26 @@ export const collections = {
|
||||
include: '**/*'
|
||||
}, pro!].filter(Boolean),
|
||||
schema
|
||||
}),
|
||||
showcase: defineCollection({
|
||||
type: 'page',
|
||||
source: 'showcase.yml',
|
||||
schema: z.object({
|
||||
title: z.string(),
|
||||
description: z.string(),
|
||||
hero: z.object({
|
||||
title: z.string(),
|
||||
description: z.string(),
|
||||
links: z.array(Button)
|
||||
}),
|
||||
items: z.array(z.object({
|
||||
name: z.string(),
|
||||
url: z.string(),
|
||||
screenshotUrl: z.string().optional(),
|
||||
screenshotOptions: z.object({
|
||||
delay: z.number()
|
||||
})
|
||||
}))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ navigation.icon: i-lucide-house
|
||||
|
||||
<iframe width="100%" height="100%" src="https://www.youtube-nocookie.com/embed/_eQxomah-nA?si=pDSzchUBDKb2NQu7" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen style="aspect-ratio: 16/9;" class="rounded-[calc(var(--ui-radius)*1.5)]"></iframe>
|
||||
|
||||
### Reka UI
|
||||
## Reka UI
|
||||
|
||||
We've transitioned from [Headless UI](https://headlessui.com/) to [Reka UI](https://reka-ui.com/) as our core component foundation. This shift brings several key advantages:
|
||||
|
||||
@@ -17,7 +17,7 @@ We've transitioned from [Headless UI](https://headlessui.com/) to [Reka UI](http
|
||||
|
||||
This transition empowers Nuxt UI to become a more comprehensive and flexible UI library, offering developers greater power and customization options.
|
||||
|
||||
### Tailwind CSS v4
|
||||
## Tailwind CSS v4
|
||||
|
||||
Nuxt UI integrates the latest Tailwind CSS v4, bringing significant improvements:
|
||||
|
||||
@@ -30,7 +30,7 @@ Nuxt UI integrates the latest Tailwind CSS v4, bringing significant improvements
|
||||
Learn about all the breaking changes in Tailwind CSS v4.
|
||||
::
|
||||
|
||||
### Tailwind Variants
|
||||
## Tailwind Variants
|
||||
|
||||
We've adopted [Tailwind Variants](https://www.tailwind-variants.org/) to manage our design system, offering:
|
||||
|
||||
@@ -40,7 +40,7 @@ We've adopted [Tailwind Variants](https://www.tailwind-variants.org/) to manage
|
||||
|
||||
This integration unifies the styling of components, ensuring consistency and code maintainability.
|
||||
|
||||
### TypeScript Integration
|
||||
## TypeScript Integration
|
||||
|
||||
Nuxt UI offers significantly improved TypeScript integration, providing a superior developer experience:
|
||||
|
||||
@@ -60,7 +60,7 @@ Nuxt UI offers significantly improved TypeScript integration, providing a superi
|
||||
Check out an example of the Accordion component with auto-completion for props and slots.
|
||||
::
|
||||
|
||||
### Vue compatibility
|
||||
## Vue compatibility
|
||||
|
||||
You can now use Nuxt UI in any Vue project without Nuxt by adding the Vite and Vue plugins to your configuration. This provides:
|
||||
|
||||
@@ -72,7 +72,7 @@ You can now use Nuxt UI in any Vue project without Nuxt by adding the Vite and V
|
||||
Learn how to install and configure Nuxt UI in a Vue project in the **Vue installation guide**.
|
||||
::
|
||||
|
||||
### Nuxt DevTools Integration
|
||||
## Nuxt DevTools Integration
|
||||
|
||||
You can play with Nuxt UI components as well as your app components directly from Nuxt Devtools with the [compodium](https://github.com/romhml/compodium) module, providing a powerful development experience:
|
||||
|
||||
|
||||
@@ -136,19 +136,19 @@ To dynamically switch between languages, you can use the [Nuxt I18n](https://i18
|
||||
::code-group{sync="pm"}
|
||||
|
||||
```bash [pnpm]
|
||||
pnpm add @nuxtjs/i18n@next
|
||||
pnpm add @nuxtjs/i18n
|
||||
```
|
||||
|
||||
```bash [yarn]
|
||||
yarn add @nuxtjs/i18n@next
|
||||
yarn add @nuxtjs/i18n
|
||||
```
|
||||
|
||||
```bash [npm]
|
||||
npm install @nuxtjs/i18n@next
|
||||
npm install @nuxtjs/i18n
|
||||
```
|
||||
|
||||
```bash [bun]
|
||||
bun add @nuxtjs/i18n@next
|
||||
bun add @nuxtjs/i18n
|
||||
```
|
||||
|
||||
::
|
||||
|
||||
@@ -30,6 +30,8 @@ ignore:
|
||||
- items
|
||||
external:
|
||||
- items
|
||||
externalTypes:
|
||||
- AccordionItem[]
|
||||
hide:
|
||||
- class
|
||||
props:
|
||||
@@ -58,6 +60,8 @@ ignore:
|
||||
- items
|
||||
external:
|
||||
- items
|
||||
externalTypes:
|
||||
- AccordionItem[]
|
||||
hide:
|
||||
- class
|
||||
props:
|
||||
@@ -87,6 +91,8 @@ ignore:
|
||||
- items
|
||||
external:
|
||||
- items
|
||||
externalTypes:
|
||||
- AccordionItem[]
|
||||
hide:
|
||||
- class
|
||||
props:
|
||||
@@ -115,6 +121,8 @@ ignore:
|
||||
- items
|
||||
external:
|
||||
- items
|
||||
externalTypes:
|
||||
- AccordionItem[]
|
||||
hide:
|
||||
- class
|
||||
props:
|
||||
@@ -149,6 +157,8 @@ ignore:
|
||||
- items
|
||||
external:
|
||||
- items
|
||||
externalTypes:
|
||||
- AccordionItem[]
|
||||
hide:
|
||||
- class
|
||||
props:
|
||||
@@ -182,6 +192,8 @@ ignore:
|
||||
- items
|
||||
external:
|
||||
- items
|
||||
externalTypes:
|
||||
- AccordionItem[]
|
||||
hide:
|
||||
- class
|
||||
props:
|
||||
@@ -280,6 +292,18 @@ props:
|
||||
---
|
||||
::
|
||||
|
||||
### With drag and drop
|
||||
|
||||
Use the [`useSortable`](https://vueuse.org/integrations/useSortable/) composable from [`@vueuse/integrations`](https://vueuse.org/integrations/README.html) to enable drag and drop functionality on the accordion. This integration wraps [Sortable.js](https://sortablejs.github.io/Sortable/) to provide a seamless drag and drop experience.
|
||||
|
||||
The `useSortable` composable accepts various options, see the [Usage](https://vueuse.org/integrations/useSortable/#usage) for more examples.
|
||||
|
||||
::component-example
|
||||
---
|
||||
name: 'accordion-drag-and-drop-example'
|
||||
---
|
||||
::
|
||||
|
||||
## API
|
||||
|
||||
### Props
|
||||
|
||||
@@ -27,6 +27,8 @@ ignore:
|
||||
- items
|
||||
external:
|
||||
- items
|
||||
externalTypes:
|
||||
- BreadcrumbItem[]
|
||||
props:
|
||||
items:
|
||||
- label: 'Home'
|
||||
@@ -54,6 +56,8 @@ ignore:
|
||||
- items
|
||||
external:
|
||||
- items
|
||||
externalTypes:
|
||||
- BreadcrumbItem[]
|
||||
props:
|
||||
separatorIcon: 'i-lucide-arrow-right'
|
||||
items:
|
||||
|
||||
@@ -44,6 +44,8 @@ ignore:
|
||||
- ui.content
|
||||
external:
|
||||
- items
|
||||
externalTypes:
|
||||
- ContextMenuItem[][]
|
||||
props:
|
||||
items:
|
||||
- - label: Appearance
|
||||
@@ -124,6 +126,8 @@ ignore:
|
||||
- ui.content
|
||||
external:
|
||||
- items
|
||||
externalTypes:
|
||||
- ContextMenuItem[]
|
||||
props:
|
||||
size: xl
|
||||
items:
|
||||
@@ -158,6 +162,8 @@ ignore:
|
||||
- ui.content
|
||||
external:
|
||||
- items
|
||||
externalTypes:
|
||||
- ContextMenuItem[]
|
||||
props:
|
||||
disabled: true
|
||||
items:
|
||||
|
||||
@@ -306,6 +306,17 @@ name: 'drawer-dismissible-example'
|
||||
In this example, the `header` slot is used to add a close button which is not done by default.
|
||||
::
|
||||
|
||||
### Responsive drawer
|
||||
|
||||
You can render a [Modal](/components/modal) component on desktop and a Drawer on mobile for example.
|
||||
|
||||
::component-example
|
||||
---
|
||||
prettier: true
|
||||
name: 'drawer-responsive-example'
|
||||
---
|
||||
::
|
||||
|
||||
### With footer slot
|
||||
|
||||
Use the `#footer` slot to add content after the Drawer's body.
|
||||
|
||||
@@ -44,6 +44,8 @@ ignore:
|
||||
- ui.content
|
||||
external:
|
||||
- items
|
||||
externalTypes:
|
||||
- DropdownMenuItem[][]
|
||||
props:
|
||||
items:
|
||||
- - label: Benjamin
|
||||
@@ -123,6 +125,8 @@ ignore:
|
||||
- ui.content
|
||||
external:
|
||||
- items
|
||||
externalTypes:
|
||||
- DropdownMenuItem[]
|
||||
items:
|
||||
content.align:
|
||||
- start
|
||||
@@ -169,6 +173,8 @@ ignore:
|
||||
- ui.content
|
||||
external:
|
||||
- items
|
||||
externalTypes:
|
||||
- DropdownMenuItem[]
|
||||
props:
|
||||
arrow: true
|
||||
items:
|
||||
@@ -202,6 +208,8 @@ ignore:
|
||||
- ui.content
|
||||
external:
|
||||
- items
|
||||
externalTypes:
|
||||
- DropdownMenuItem[]
|
||||
props:
|
||||
size: xl
|
||||
items:
|
||||
@@ -244,6 +252,8 @@ ignore:
|
||||
- ui.content
|
||||
external:
|
||||
- items
|
||||
externalTypes:
|
||||
- DropdownMenuItem[]
|
||||
props:
|
||||
disabled: true
|
||||
items:
|
||||
@@ -334,7 +344,9 @@ Inside the `defineShortcuts` composable, there is an `extractShortcuts` utility
|
||||
|
||||
```vue
|
||||
<script setup lang="ts">
|
||||
const items = [{
|
||||
import type { DropdownMenuItem } from '@nuxt/ui'
|
||||
|
||||
const items: DropdownMenuItem[] = [{
|
||||
label: 'Invite users',
|
||||
icon: 'i-lucide-user-plus',
|
||||
children: [{
|
||||
|
||||
@@ -39,6 +39,8 @@ ignore:
|
||||
- class
|
||||
external:
|
||||
- items
|
||||
externalTypes:
|
||||
- NavigationMenuItem[]
|
||||
props:
|
||||
items:
|
||||
- label: Guide
|
||||
@@ -148,6 +150,8 @@ ignore:
|
||||
- class
|
||||
external:
|
||||
- items
|
||||
externalTypes:
|
||||
- NavigationMenuItem[][]
|
||||
props:
|
||||
orientation: 'vertical'
|
||||
items:
|
||||
@@ -247,6 +251,8 @@ ignore:
|
||||
- class
|
||||
external:
|
||||
- items
|
||||
externalTypes:
|
||||
- NavigationMenuItem[][]
|
||||
props:
|
||||
highlight: true
|
||||
highlightColor: 'primary'
|
||||
@@ -346,6 +352,8 @@ ignore:
|
||||
- class
|
||||
external:
|
||||
- items
|
||||
externalTypes:
|
||||
- NavigationMenuItem[][]
|
||||
props:
|
||||
color: neutral
|
||||
items:
|
||||
@@ -379,6 +387,8 @@ ignore:
|
||||
- class
|
||||
external:
|
||||
- items
|
||||
externalTypes:
|
||||
- NavigationMenuItem[][]
|
||||
props:
|
||||
color: neutral
|
||||
variant: link
|
||||
@@ -423,6 +433,8 @@ ignore:
|
||||
- class
|
||||
external:
|
||||
- items
|
||||
externalTypes:
|
||||
- NavigationMenuItem[]
|
||||
props:
|
||||
trailingIcon: 'i-lucide-arrow-down'
|
||||
items:
|
||||
@@ -519,6 +531,8 @@ ignore:
|
||||
- class
|
||||
external:
|
||||
- items
|
||||
externalTypes:
|
||||
- NavigationMenuItem[]
|
||||
props:
|
||||
arrow: true
|
||||
items:
|
||||
@@ -611,6 +625,8 @@ ignore:
|
||||
- class
|
||||
external:
|
||||
- items
|
||||
externalTypes:
|
||||
- NavigationMenuItem[]
|
||||
props:
|
||||
arrow: true
|
||||
contentOrientation: 'vertical'
|
||||
@@ -682,6 +698,8 @@ ignore:
|
||||
- class
|
||||
external:
|
||||
- items
|
||||
externalTypes:
|
||||
- NavigationMenuItem[]
|
||||
props:
|
||||
unmountOnHide: false
|
||||
items:
|
||||
|
||||
@@ -177,6 +177,12 @@ props:
|
||||
|
||||
:component-emits
|
||||
|
||||
When accessing the component via a template ref, you can use the following:
|
||||
|
||||
| Name | Type |
|
||||
| ---- | ---- |
|
||||
| `inputsRef`{lang="ts-type"} | `Ref<ComponentPublicInstance[]>`{lang="ts-type"} |
|
||||
|
||||
## Theme
|
||||
|
||||
:component-theme
|
||||
|
||||
@@ -17,7 +17,7 @@ Use the `v-model` directive to control the value of the RadioGroup or the `defau
|
||||
|
||||
### Items
|
||||
|
||||
Use the `items` prop as an array of strings, numbers or booleans:
|
||||
Use the `items` prop as an array of strings or numbers:
|
||||
|
||||
::component-code
|
||||
---
|
||||
@@ -28,6 +28,9 @@ ignore:
|
||||
external:
|
||||
- items
|
||||
- modelValue
|
||||
externalTypes:
|
||||
- RadioGroupItem[]
|
||||
- RadioGroupValue
|
||||
props:
|
||||
modelValue: 'System'
|
||||
items:
|
||||
@@ -52,6 +55,9 @@ ignore:
|
||||
external:
|
||||
- items
|
||||
- modelValue
|
||||
externalTypes:
|
||||
- RadioGroupItem[]
|
||||
- RadioGroupValue
|
||||
props:
|
||||
modelValue: 'system'
|
||||
items:
|
||||
@@ -84,6 +90,9 @@ ignore:
|
||||
external:
|
||||
- items
|
||||
- modelValue
|
||||
externalTypes:
|
||||
- RadioGroupItem[]
|
||||
- RadioGroupValue
|
||||
props:
|
||||
modelValue: 'light'
|
||||
valueKey: 'id'
|
||||
@@ -112,6 +121,8 @@ ignore:
|
||||
- items
|
||||
external:
|
||||
- items
|
||||
externalTypes:
|
||||
- RadioGroupItem[]
|
||||
props:
|
||||
legend: 'Theme'
|
||||
defaultValue: 'System'
|
||||
@@ -122,28 +133,6 @@ props:
|
||||
---
|
||||
::
|
||||
|
||||
### Orientation
|
||||
|
||||
Use the `orientation` prop to change the orientation of the RadioGroup. Defaults to `vertical`.
|
||||
|
||||
::component-code
|
||||
---
|
||||
prettier: true
|
||||
ignore:
|
||||
- defaultValue
|
||||
- items
|
||||
external:
|
||||
- items
|
||||
props:
|
||||
orientation: 'horizontal'
|
||||
defaultValue: 'System'
|
||||
items:
|
||||
- 'System'
|
||||
- 'Light'
|
||||
- 'Dark'
|
||||
---
|
||||
::
|
||||
|
||||
### Color
|
||||
|
||||
Use the `color` prop to change the color of the RadioGroup.
|
||||
@@ -156,6 +145,8 @@ ignore:
|
||||
- items
|
||||
external:
|
||||
- items
|
||||
externalTypes:
|
||||
- RadioGroupItem[]
|
||||
props:
|
||||
color: neutral
|
||||
defaultValue: 'System'
|
||||
@@ -166,6 +157,35 @@ props:
|
||||
---
|
||||
::
|
||||
|
||||
### Variant :badge{label="Not released" class="align-text-top"}
|
||||
|
||||
Use the `variant` prop to change the variant of the RadioGroup.
|
||||
|
||||
::component-code
|
||||
---
|
||||
prettier: true
|
||||
ignore:
|
||||
- defaultValue
|
||||
- items
|
||||
external:
|
||||
- items
|
||||
props:
|
||||
color: 'primary'
|
||||
variant: 'table'
|
||||
defaultValue: 'pro'
|
||||
items:
|
||||
- label: 'Pro'
|
||||
value: 'pro'
|
||||
description: 'Tailored for indie hackers, freelancers and solo founders.'
|
||||
- label: 'Startup'
|
||||
value: 'startup'
|
||||
description: 'Best suited for small teams, startups and agencies.'
|
||||
- label: 'Enterprise'
|
||||
value: 'enterprise'
|
||||
description: 'Ideal for larger teams and organizations.'
|
||||
---
|
||||
::
|
||||
|
||||
### Size
|
||||
|
||||
Use the `size` prop to change the size of the RadioGroup.
|
||||
@@ -178,8 +198,61 @@ ignore:
|
||||
- items
|
||||
external:
|
||||
- items
|
||||
externalTypes:
|
||||
- RadioGroupItem[]
|
||||
props:
|
||||
size: 'xl'
|
||||
variant: 'list'
|
||||
defaultValue: 'System'
|
||||
items:
|
||||
- 'System'
|
||||
- 'Light'
|
||||
- 'Dark'
|
||||
---
|
||||
::
|
||||
|
||||
### Orientation
|
||||
|
||||
Use the `orientation` prop to change the orientation of the RadioGroup. Defaults to `vertical`.
|
||||
|
||||
::component-code
|
||||
---
|
||||
prettier: true
|
||||
ignore:
|
||||
- defaultValue
|
||||
- items
|
||||
external:
|
||||
- items
|
||||
externalTypes:
|
||||
- RadioGroupItem[]
|
||||
props:
|
||||
orientation: 'horizontal'
|
||||
variant: 'list'
|
||||
defaultValue: 'System'
|
||||
items:
|
||||
- 'System'
|
||||
- 'Light'
|
||||
- 'Dark'
|
||||
---
|
||||
::
|
||||
|
||||
### Indicator :badge{label="Not released" class="align-text-top"}
|
||||
|
||||
Use the `indicator` prop to change the position or hide the indicator. Defaults to `start`.
|
||||
|
||||
::component-code
|
||||
---
|
||||
prettier: true
|
||||
ignore:
|
||||
- defaultValue
|
||||
- items
|
||||
external:
|
||||
- items
|
||||
externalTypes:
|
||||
- RadioGroupItem[]
|
||||
props:
|
||||
indicator: 'end'
|
||||
variant: 'card'
|
||||
defaultValue: 'System'
|
||||
items:
|
||||
- 'System'
|
||||
@@ -200,6 +273,8 @@ ignore:
|
||||
- items
|
||||
external:
|
||||
- items
|
||||
externalTypes:
|
||||
- RadioGroupItem[]
|
||||
props:
|
||||
disabled: true
|
||||
defaultValue: 'System'
|
||||
|
||||
@@ -31,6 +31,8 @@ ignore:
|
||||
- class
|
||||
external:
|
||||
- items
|
||||
externalTypes:
|
||||
- StepperItem[]
|
||||
props:
|
||||
items:
|
||||
- title: 'Address'
|
||||
@@ -61,6 +63,8 @@ ignore:
|
||||
- class
|
||||
external:
|
||||
- items
|
||||
externalTypes:
|
||||
- StepperItem[]
|
||||
props:
|
||||
color: neutral
|
||||
items:
|
||||
@@ -88,6 +92,8 @@ ignore:
|
||||
- class
|
||||
external:
|
||||
- items
|
||||
externalTypes:
|
||||
- StepperItem[]
|
||||
props:
|
||||
size: xl
|
||||
items:
|
||||
@@ -115,6 +121,8 @@ ignore:
|
||||
- class
|
||||
external:
|
||||
- items
|
||||
externalTypes:
|
||||
- StepperItem[]
|
||||
props:
|
||||
orientation: vertical
|
||||
items:
|
||||
@@ -142,6 +150,8 @@ ignore:
|
||||
- class
|
||||
external:
|
||||
- items
|
||||
externalTypes:
|
||||
- StepperItem[]
|
||||
props:
|
||||
disabled: true
|
||||
items:
|
||||
|
||||
@@ -23,7 +23,7 @@ class: '!p-0'
|
||||
---
|
||||
::
|
||||
|
||||
::callout{icon="i-simple-icons-github" to="https://github.com/nuxt/ui/tree/v3/docs/app/components/content/examples/table/TableExample.vue"}
|
||||
::callout{icon="i-simple-icons-github" to="https://github.com/nuxt/ui/tree/v3/docs/app/components/content/examples/table/TableExample.vue" aria-label="View source code"}
|
||||
This example demonstrates the most common use case of the `Table` component. Check out the source code on GitHub.
|
||||
::
|
||||
|
||||
@@ -85,7 +85,7 @@ Use the `columns` prop as an array of [ColumnDef](https://tanstack.com/table/lat
|
||||
|
||||
In order to render components or other HTML elements, you will need to use the Vue [`h` function](https://vuejs.org/api/render-function.html#h) inside the `header` and `cell` props. This is different from other components that use slots but allows for more flexibility.
|
||||
|
||||
::tip{to="#with-slots"}
|
||||
::tip{to="#with-slots" aria-label="Table columns with slots"}
|
||||
You can also use slots to customize the header and data cells of the table.
|
||||
::
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user