Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
110 commits
Select commit Hold shift + click to select a range
c706d36
chore(github): deduplicate issue templates
benjamincanac Aug 6, 2025
709e9d3
chore(github): update workflows to use `v4` branch
benjamincanac Aug 6, 2025
9d925e5
chore(readme): update branch to `v4`
benjamincanac Aug 6, 2025
1e0bf6f
chore(renovate): update branch to `v4`
benjamincanac Aug 6, 2025
fa1007a
docs: update branch to `v4`
benjamincanac Aug 6, 2025
d3cb9c1
chore: reorganize under `playgrounds/`
benjamincanac Aug 6, 2025
f6ae153
feat: import `@nuxt/ui-pro` components (#4675)
benjamincanac Aug 11, 2025
9545fdd
feat(components)!: upgrade `ai-sdk` to v5 (#4698)
HugoRCD Aug 11, 2025
9fbe306
chore(vercel): enable deployments
benjamincanac Aug 11, 2025
8aa96d1
feat(FieldGroup)!: rename from `ButtonGroup` (#4596)
J-Michalek Aug 12, 2025
99d3227
fix(ContentSearch/DashboardSearch): make `ui.modal` work
benjamincanac Aug 12, 2025
841c369
fix(ProseImg): ensure unique motion layout id for images (#4720)
HugoRCD Aug 12, 2025
4926c97
chore(deps): update dependency @nuxt/icon to v2
benjamincanac Aug 12, 2025
5d51785
docs(figma): merge free and pro kits (#4707)
HugoRCD Aug 12, 2025
1ef53f6
docs(app): improve navigation links
benjamincanac Aug 12, 2025
96c8306
docs(components): add index page
benjamincanac Aug 12, 2025
d88019e
docs(templates): improve marketing
benjamincanac Aug 12, 2025
7f705a3
chore(deps): remove wrangler dependency
benjamincanac Aug 13, 2025
6606fa3
fix(PageCard): improve keyboard accessibility (#4733)
HugoRCD Aug 13, 2025
f618af5
docs(components): add changelog section
benjamincanac Aug 13, 2025
79ae89a
docs(getting-started): improve categories
benjamincanac Aug 13, 2025
e780a03
docs(app): add `key` on navigation
benjamincanac Aug 13, 2025
314e661
fix(AuthForm): use `error` from form field (#4738)
Barbapapazes Aug 14, 2025
44e0178
fix(BlogPost): ensure date slot renders (#4743)
EvanSchleret Aug 14, 2025
0a4d9b4
feat(Marquee)!: rename from `PageMarquee` (#4741)
HugoRCD Aug 14, 2025
1c63aab
feat(PageAccordion)!: remove in favor of `Accordion` (#4734)
HugoRCD Aug 14, 2025
731e136
docs(nuxt.config): update route rules
benjamincanac Aug 14, 2025
2a5fbc8
docs(app): remove `module` field from content collection
benjamincanac Aug 14, 2025
35c84c5
docs(app): wrong og image on components index page
benjamincanac Aug 14, 2025
abd2584
test: update snapshots
benjamincanac Aug 15, 2025
53c4831
chore: prepare for `alpha`
benjamincanac Aug 15, 2025
f1a0166
chore(release): v4.0.0-alpha.0
benjamincanac Aug 15, 2025
5f3b6d4
docs: use `@nuxt/ui@alpha` package
benjamincanac Aug 16, 2025
e978f0d
docs: use `https://ui4.nuxt.com` url
benjamincanac Aug 16, 2025
9820424
docs(app): hide banner
benjamincanac Aug 16, 2025
a572927
docs(server): fix raw route collection
benjamincanac Aug 16, 2025
9ad9f55
feat(docs): add blocks
HugoRCD Aug 19, 2025
38808e7
docs(ColorMode): fix `framework-only` display (#4780)
HugoRCD Aug 19, 2025
6cc86a2
Merge branch 'v4' into feat/blocks
HugoRCD Aug 19, 2025
674e3dd
fix(docs): never display empty components category (#4792)
HugoRCD Aug 19, 2025
94b7a54
fix(docs): fix `framework-only` display for `ColorModeSwitch` (#4793)
HugoRCD Aug 19, 2025
08cdf0a
Merge branch 'v4' into feat/blocks
HugoRCD Aug 21, 2025
b876b99
update structure
HugoRCD Aug 21, 2025
8d0ab20
up
HugoRCD Aug 21, 2025
7fb3d1d
improve BlockExample
HugoRCD Aug 22, 2025
fcd1919
up
HugoRCD Aug 25, 2025
3ee5424
chore(github): deduplicate issue templates
benjamincanac Aug 6, 2025
5cc883c
chore(github): update workflows to use `v4` branch
benjamincanac Aug 6, 2025
d38f3f2
chore(readme): update branch to `v4`
benjamincanac Aug 6, 2025
674f8b4
chore(renovate): update branch to `v4`
benjamincanac Aug 6, 2025
9edce97
docs: update branch to `v4`
benjamincanac Aug 6, 2025
1765425
chore: reorganize under `playgrounds/`
benjamincanac Aug 6, 2025
ec71baf
feat: import `@nuxt/ui-pro` components (#4675)
benjamincanac Aug 11, 2025
a3be6ad
feat(components)!: upgrade `ai-sdk` to v5 (#4698)
HugoRCD Aug 11, 2025
3105d60
chore(vercel): enable deployments
benjamincanac Aug 11, 2025
c2c1c26
feat(FieldGroup)!: rename from `ButtonGroup` (#4596)
J-Michalek Aug 12, 2025
7f8d919
fix(ContentSearch/DashboardSearch): make `ui.modal` work
benjamincanac Aug 12, 2025
1015430
fix(ProseImg): ensure unique motion layout id for images (#4720)
HugoRCD Aug 12, 2025
0d552cb
chore(deps): update dependency @nuxt/icon to v2
benjamincanac Aug 12, 2025
4aa443c
docs(figma): merge free and pro kits (#4707)
HugoRCD Aug 12, 2025
be8f287
docs(app): improve navigation links
benjamincanac Aug 12, 2025
2a72b32
docs(components): add index page
benjamincanac Aug 12, 2025
0a0ec21
docs(templates): improve marketing
benjamincanac Aug 12, 2025
38a14a4
chore(deps): remove wrangler dependency
benjamincanac Aug 13, 2025
203b59b
fix(PageCard): improve keyboard accessibility (#4733)
HugoRCD Aug 13, 2025
f52f470
docs(components): add changelog section
benjamincanac Aug 13, 2025
343465c
docs(getting-started): improve categories
benjamincanac Aug 13, 2025
be190ae
docs(app): add `key` on navigation
benjamincanac Aug 13, 2025
db44a06
fix(AuthForm): use `error` from form field (#4738)
Barbapapazes Aug 14, 2025
84a78e7
fix(BlogPost): ensure date slot renders (#4743)
EvanSchleret Aug 14, 2025
7a99712
feat(Marquee)!: rename from `PageMarquee` (#4741)
HugoRCD Aug 14, 2025
0d5baae
feat(PageAccordion)!: remove in favor of `Accordion` (#4734)
HugoRCD Aug 14, 2025
9c65b7b
docs(nuxt.config): update route rules
benjamincanac Aug 14, 2025
ee7a26f
docs(app): remove `module` field from content collection
benjamincanac Aug 14, 2025
1887f93
docs(app): wrong og image on components index page
benjamincanac Aug 14, 2025
a055d5d
test: update snapshots
benjamincanac Aug 15, 2025
a756017
chore: prepare for `alpha`
benjamincanac Aug 15, 2025
f204f4d
chore(release): v4.0.0-alpha.0
benjamincanac Aug 15, 2025
677380d
docs: use `@nuxt/ui@alpha` package
benjamincanac Aug 16, 2025
9b364e2
docs: use `https://ui4.nuxt.com` url
benjamincanac Aug 16, 2025
472ddc8
docs(app): hide banner
benjamincanac Aug 16, 2025
b82f53d
docs(server): fix raw route collection
benjamincanac Aug 16, 2025
f9e0148
docs(color-mode): typo in MDC syntax (#4780)
HugoRCD Aug 19, 2025
f34d636
fix(ChangelogVersion/ChangelogVersions): handle RTL mode (#4777)
malik-jouda Aug 25, 2025
c9765ca
docs(app): never display empty components category (#4792)
HugoRCD Aug 19, 2025
c14fccb
docs(typography) : update `@nuxt/content` installation guide link (#4…
maximepvrt Aug 25, 2025
400a8c9
docs(getting-started): add `llms.txt` page (#4799)
HugoRCD Aug 25, 2025
fe66e83
fix(unplugin): handle components overrides in subdirectories (#4781)
HugoRCD Aug 25, 2025
268871d
chore(deps): update dependencies unplugin-auto-import and unplugin-vu…
benjamincanac Aug 25, 2025
3e38fac
feat(module)!: update compatibility to nuxt 4
benjamincanac Aug 25, 2025
2d5d1fa
docs(app): hide empty categories using class
benjamincanac Aug 26, 2025
c14be22
docs(templates): add framework select
benjamincanac Aug 26, 2025
3480408
docs(index): improve page
benjamincanac Aug 26, 2025
75f4ad6
docs(getting-started): rewrite introduction
benjamincanac Aug 26, 2025
b206c99
Merge remote-tracking branch 'origin/v4' into feat/blocks
HugoRCD Aug 27, 2025
e2d6567
fix(module): add `@source` on components
benjamincanac Aug 27, 2025
3545d92
up
HugoRCD Aug 27, 2025
0774748
Merge remote-tracking branch 'origin/v4' into feat/blocks
HugoRCD Aug 27, 2025
1d2e705
up
HugoRCD Aug 27, 2025
8936662
up
HugoRCD Aug 27, 2025
1b2c2dd
docs(migration): write guide from v3 to v4 (#4802)
HugoRCD Aug 27, 2025
e3b7a8d
up
HugoRCD Aug 27, 2025
bfa114a
Merge remote-tracking branch 'origin/v4' into feat/blocks
HugoRCD Aug 27, 2025
606bd31
up
HugoRCD Aug 28, 2025
c3c67c3
Merge remote-tracking branch 'origin/v4' into feat/blocks
HugoRCD Sep 1, 2025
b4f8d65
fix merge
HugoRCD Sep 1, 2025
636902f
up
HugoRCD Sep 1, 2025
14662f2
Merge remote-tracking branch 'origin/v4' into feat/blocks
HugoRCD Sep 1, 2025
9af26fc
Merge remote-tracking branch 'origin/v4' into feat/blocks
HugoRCD Sep 5, 2025
6cc0897
Merge remote-tracking branch 'origin/v4' into feat/blocks
HugoRCD Sep 8, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/app/app.vue
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ provide('navigation', mappedNavigation)
<Analytics />
<SpeedInsights />

<div :class="[route.path.startsWith('/docs/') && 'root']">
<div :class="[(route.path.startsWith('/docs/') || route.path.startsWith('/blocks/')) && 'root']">
<template v-if="!route.path.startsWith('/examples')">
<!-- <Banner /> -->

Expand Down
33 changes: 30 additions & 3 deletions docs/app/components/Header.vue
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,20 @@ const docsNavigation = computed(() => mapContentNavigation(navigation?.value.map
active: route.path.startsWith(item.to as string)
})))

const blocksNavigation = computed(() => [{
label: 'Headers',
to: '/blocks/headers',
active: route.path.startsWith('/blocks/headers')
}, {
label: 'Hero',
to: '/blocks/hero',
active: route.path.startsWith('/blocks/hero')
}, {
label: 'Footer',
to: '/blocks/footer',
active: route.path.startsWith('/blocks/footer')
}])

const logoElement = ref()
const { copy } = useClipboard()
const toast = useToast()
Expand Down Expand Up @@ -133,13 +147,26 @@ const logoContextMenuItems = [
<UContentNavigation :navigation="navigation" highlight :ui="{ linkTrailingBadge: 'font-semibold uppercase' }" />
</template>

<template v-if="route.path.startsWith('/docs/')" #bottom>
<template v-if="route.path.startsWith('/docs/') || route.path.startsWith('/blocks/')" #bottom>
<USeparator class="hidden lg:flex" />

<UContainer class="hidden lg:flex items-center justify-between">
<UNavigationMenu :items="docsNavigation" variant="pill" highlight class="-mx-2.5 -mb-px" />
<UNavigationMenu
v-if="route.path.startsWith('/docs/')"
:items="docsNavigation"
variant="pill"
highlight
class="-mx-2.5 -mb-px"
/>
<UNavigationMenu
v-else-if="route.path.startsWith('/blocks/')"
:items="blocksNavigation"
variant="pill"
highlight
class="-mx-2.5 -mb-px"
/>

<FrameworkSelect class="w-40" />
<FrameworkSelect v-if="route.path.startsWith('/docs/')" class="w-40" />
</UContainer>
</template>
</UHeader>
Expand Down
281 changes: 281 additions & 0 deletions docs/app/components/content/BlockExample.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,281 @@
<script setup lang="ts">
import { camelCase } from 'scule'
import { SplitterGroup, SplitterPanel, SplitterResizeHandle } from 'reka-ui'
import type { TabsItem } from '@nuxt/ui'

const props = withDefaults(defineProps<{
name: string
/**
* Whether to format the code with Prettier
* @defaultValue false
*/
prettier?: boolean
/**
* Custom height for the iframe container
* @defaultValue '500px'
*/
height?: string
/**
* Whether to collapse the code block
* @defaultValue false
*/
collapse?: boolean
/**
* Whether to show the source code
* @defaultValue true
*/
source?: boolean
/**
* A list of line numbers to highlight in the code block
*/
highlights?: number[]
/**
* Whether to center the example content
* @defaultValue true
*/
centered?: boolean
title?: string
description?: string
hint?: string
}>(), {
source: true,
height: '500px',
centered: true
})

const toast = useToast()
const colorMode = useColorMode()

const { $prettier } = useNuxtApp()
const camelName = camelCase(props.name)

const id = computed(() => props.name ? `block-${props.name}` : undefined)

const localTheme = ref<'light' | 'dark'>()
const effectiveTheme = computed(() => {
return localTheme.value || colorMode.value
})

const toggleTheme = () => {
if (effectiveTheme.value === 'light') {
localTheme.value = 'dark'
} else {
localTheme.value = 'light'
}
}

const themeIcon = computed(() => {
return effectiveTheme.value === 'light' ? 'i-lucide-moon' : 'i-lucide-sun'
})

const themeTooltip = computed(() => {
return effectiveTheme.value === 'light' ? 'Switch to dark mode' : 'Switch to light mode'
})

const data = await fetchComponentExample(camelName)

const code = computed(() => {
let code = ''

if (props.collapse) {
code += `::code-collapse
`
}

code += `\`\`\`vue${props.highlights?.length ? `{${props.highlights.join('-')}}` : ''}
${data?.code ?? ''}
\`\`\``

if (props.collapse) {
code += `
::`
}

return code
})

const { data: ast } = await useAsyncData(`block-example-${camelName}`, async () => {
if (!props.prettier) {
return parseMarkdown(code.value)
}

let formatted = ''
try {
formatted = await $prettier.format(code.value, {
trailingComma: 'none',
semi: false,
singleQuote: true,
printWidth: 100
})
} catch {
formatted = code.value
}

return parseMarkdown(formatted)
}, { watch: [code] })

const items = [
{
label: 'Preview',
slot: 'preview' as const
},
{
label: 'Code',
slot: 'code' as const
}
] satisfies TabsItem[]

const openFullscreen = () => {
const url = `/examples/blocks/${props.name}?centered=${props.centered}&theme=${effectiveTheme.value}`
window.open(url, '_blank', 'width=1200,height=800,scrollbars=yes,resizable=yes')
}

const copyCode = async () => {
if (data?.code) {
try {
await navigator.clipboard.writeText(data.code)
toast.add({
title: 'Code copied to clipboard',
color: 'success'
})
} catch (err) {
console.error('Failed to copy code:', err)
}
}
}
</script>

<template>
<div :id="id" class="relative border border-default mb-10 scroll-mt-[calc(45px+var(--ui-header-height))] lg:scroll-mt-(--ui-header-height)">
<div v-if="title || description" class="flex flex-col gap-1 p-4">
<span v-if="title" class="text-xl font-bold text-highlighted">
<a v-if="id" :href="`#${id}`" class="inline-flex items-center gap-1 group hover:underline underline-offset-2 decoration-1">
{{ title }}
<UIcon
name="i-lucide-link"
class="size-4 hidden group-hover:block"
/>
</a>
<template v-else>
{{ title }}
</template>
</span>
<span v-if="description" class="text-muted">
{{ description }}
</span>
</div>
<div class="border-t border-default overflow-hidden" :style="{ height: props.height }">
<UTabs
:items="items"
class="size-full gap-0"
variant="link"
:ui="{
content: 'relative size-full border-t border-default',
indicator: 'z-10'
}"
>
<template #preview>
<span v-if="hint" class="absolute bottom-2 left-2 bg-muted/50 backdrop-blur-3xl border border-default px-2 py-1 rounded text-xs">
{{ hint }}
</span>
<SplitterGroup
:id="`splitter-${camelName}`"
direction="horizontal"
>
<SplitterPanel
:id="`splitter-${camelName}-panel-1`"
:default-size="70"
:min-size="30"
class="overflow-hidden"
>
<iframe
:src="`/examples/blocks/${name}?centered=${centered}&theme=${effectiveTheme}`"
class="size-full"
/>
</SplitterPanel>
<SplitterResizeHandle
:id="`splitter-${camelName}-handle`"
class="group w-4 flex items-center justify-center bg-default"
>
<div class="w-1 h-8 group-hover:h-16 bg-elevated transition-all rounded-full" />
</SplitterResizeHandle>

<SplitterPanel
:id="`splitter-${camelName}-panel-2`"
class="bg-stripes"
:default-size="0"
:min-size="0"
/>
</SplitterGroup>
</template>

<template #code>
<div
v-if="source"
class="overflow-y-auto h-full"
>
<MDCRenderer v-if="ast" :body="ast.body" :data="ast.data" class="*:my-0 *:*:border-none *:*:rounded-none" />
</div>
</template>

<template #list-trailing>
<div class="flex flex-1 items-center justify-end gap-2">
<UButton
variant="ghost"
size="sm"
square
color="neutral"
icon="i-lucide-copy"
label="Copy code"
@click="copyCode"
/>

<UTooltip
:text="themeTooltip"
:delay-duration="0"
:content="{
side: 'top'
}"
>
<UButton
variant="ghost"
size="sm"
square
color="neutral"
:icon="themeIcon"
@click="toggleTheme"
/>
</UTooltip>

<UTooltip
text="Open in fullscreen"
:delay-duration="0"
:content="{
side: 'top'
}"
>
<UButton
variant="ghost"
size="sm"
square
color="neutral"
icon="i-lucide-maximize"
@click="openFullscreen"
/>
</UTooltip>
</div>
</template>
</UTabs>
</div>
</div>
</template>

<style>
@reference '../../assets/css/main.css';

.bg-stripes {
@apply w-full [background-size:8px_8px];
@apply dark:[background-image:linear-gradient(-45deg,var(--color-neutral-800)_12.50%,transparent_12.50%,transparent_50%,var(--color-neutral-800)_50%,var(--color-neutral-800)_62.50%,transparent_62.50%,transparent_100%)];
@apply not-dark:[background-image:linear-gradient(-45deg,var(--color-neutral-100)_12.50%,transparent_12.50%,transparent_50%,var(--color-neutral-100)_50%,var(--color-neutral-100)_62.50%,transparent_62.50%,transparent_100%)];
}
</style>
Loading
Loading