Compare commits

..

134 Commits

Author SHA1 Message Date
Benjamin Canac
f05dbd26d1 chore(release): v3.0.2 2025-03-28 16:57:21 +01:00
Benjamin Canac
9be36d328c playground(app): add title 2025-03-28 16:55:11 +01:00
renovate[bot]
4f28e1fe96 chore(deps): update all non-major dependencies (v3) (#3698)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-28 16:43:12 +01:00
Eugen Istoc
bd99c2d850 fix(useOverlay): refine open method type to infer close emit return type (#3716) 2025-03-28 16:42:48 +01:00
Benjamin Canac
23bfeb9370 fix(vue): mock nuxtApp.hooks & useRuntimeHook 2025-03-28 15:07:54 +01:00
仿生狮子
88f349d0d7 fix(Avatar): proxy $attrs to default slot (#3712) 2025-03-28 10:27:25 +01:00
Daniele Nicosia
e7e6745599 fix(types): add missing export for ButtonGroup (#3709) 2025-03-27 23:41:33 +01:00
Benjamin Canac
d2c832292a chore(deps): update @nuxt/ui-pro 2025-03-27 23:22:44 +01:00
Benjamin Canac
bc61d29cce fix(CommandPalette): use group.id as key 2025-03-27 21:32:38 +01:00
Malik
777fe4a309 playground: improve rtl (#3707) 2025-03-27 19:18:58 +01:00
Benjamin Canac
3074632523 fix(InputMenu): reset searchTerm on update:open
Resolves #3620
2025-03-27 16:27:48 +01:00
Benjamin Canac
94b6e520f5 fix(InputMenu/SelectMenu): empty search results 2025-03-27 12:18:46 +01:00
Benjamin Canac
754dd36473 docs(SupportedLanguages): reorder mapping 2025-03-27 12:16:39 +01:00
Benjamin Canac
67a52b6f4e test(Table): update snapshots 2025-03-26 17:40:36 +01:00
Benjamin Canac
2e7d4989b5 chore(github): prevent running module nuxt-ui-pro job on forks 2025-03-26 17:33:32 +01:00
Benjamin Canac
c07a79571f docs(slug): add purchase and affilitate in community links 2025-03-26 17:31:24 +01:00
Benjamin Canac
4cebdb5152 chore(deps): update @nuxt/ui-pro 2025-03-26 17:31:19 +01:00
Benjamin Canac
06dfb963be chore(CommandPalette): improve placeholder tsdoc 2025-03-26 17:31:19 +01:00
Benjamin Canac
4ebb94cd7e fix(Table): wrong condition on caption slot 2025-03-26 17:31:19 +01:00
Benjamin Canac
afff54fecd feat(Table): add empty prop 2025-03-26 17:31:18 +01:00
renovate[bot]
7ec08017e0 chore(deps): update all non-major dependencies (v3) (#3695)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-26 15:36:26 +01:00
Romain Hamel
3dd88bacec fix(Form): clear dirty state after submit (#3692) 2025-03-26 13:48:28 +01:00
renovate[bot]
d6d7971d44 chore(deps): update tailwindcss to ^4.0.17 (v3) (#3690)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-26 13:48:02 +01:00
Romain Hamel
20c33920d0 fix(FormField): add help to aria-describedby attribute (#3691) 2025-03-26 13:47:38 +01:00
Stijn Slats
a63047b79a docs(accordion): add drag and drop example (#3684)
Co-authored-by: Benjamin Canac <canacb1@gmail.com>
2025-03-26 11:07:47 +01:00
renovate[bot]
f3e32ba5a2 chore(deps): update all non-major dependencies (v3) (#3667)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-26 10:59:21 +01:00
renovate[bot]
bd3f54aa80 chore(deps): update tailwindcss to ^4.0.16 (v3) (#3682)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-26 10:44:06 +01:00
Hugo Richard
9509c37af8 docs: improve lighthouse score and accessibility (#3673) 2025-03-25 16:23:35 +01:00
Benjamin Canac
df00149598 fix(Container): add w-full class 2025-03-25 16:23:05 +01:00
Bobbie Goede
f72c886d3a docs(i18n): remove next tag from @nuxtjs/i18n installation (#3675) 2025-03-25 10:07:58 +01:00
Benjamin Canac
c531d0248b fix(Link): handle aria-current like NuxtLink / RouterLink 2025-03-24 23:57:46 +01:00
Benjamin Canac
d73768b704 fix(Link): prevent active="true" binding on html 2025-03-24 23:56:28 +01:00
Sandro Circi
b9983549a4 fix(components): improve generic types (#3331)
Co-authored-by: Benjamin Canac <canacb1@gmail.com>
2025-03-24 21:38:13 +01:00
Benjamin Canac
370054b20c fix(Link): proxy onClick
Resolves #3631
2025-03-24 19:08:09 +01:00
Hugo Richard
4a2b77d86c feat(Calendar): allow year and month buttons styling (#3672) 2025-03-24 19:00:28 +01:00
Benjamin Canac
ade16b76cf fix(Link): properly pick all aria-* & data-* attrs 2025-03-24 18:58:49 +01:00
Benjamin Canac
1babad4f74 chore(github): update stale to close needs reproduction 2025-03-24 16:22:22 +01:00
Benjamin Canac
8fb8dc29cf docs(nuxt.config): update vite.optimizeDeps 2025-03-24 16:22:22 +01:00
renovate[bot]
e0ec60d1b1 chore(deps): update devdependency wrangler to v4 (v3) (#3554)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-24 15:36:34 +01:00
Benjamin Canac
3db3058395 docs(index): improve marquees performances 2025-03-24 15:33:01 +01:00
Benjamin Canac
0095d8916b fix(NavigationMenu): add z-index on viewport
Resolves #3654
2025-03-24 15:11:47 +01:00
Sébastien Chopin
58ae62413d docs: add missing redirect 2025-03-24 14:49:05 +01:00
Benjamin Canac
1965495768 chore(deps): remove typescript resolution 2025-03-24 14:41:50 +01:00
Benjamin Canac
5465fcb61d chore(deps): update peerDependencies 2025-03-24 14:12:19 +01:00
Benjamin Canac
ef8ebaf687 chore(renovate): ignore peerDependencies 2025-03-24 14:01:57 +01:00
Benjamin Canac
1094881878 playground(deps): add zod 2025-03-24 14:01:14 +01:00
Romain Hamel
d6fd18fc4f chore(deps): declare form validation libraries as peerDependencies (#3666) 2025-03-24 13:53:35 +01:00
Benjamin Canac
e2e079f0d8 chore(github): improve module workflow 2025-03-24 12:37:04 +01:00
Benjamin Canac
cec9dadc7a chore(docs/playground): add vite.optimizeDeps 2025-03-24 12:37:04 +01:00
Vahe Sargsyan
c76f590097 feat(locale): add Armenian language (#3664) 2025-03-24 11:29:32 +01:00
renovate[bot]
4dee7c3bd3 chore(deps): lock file maintenance (v3) (#3662)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-24 11:26:00 +01:00
renovate[bot]
47bbe35d2a chore(deps): update all non-major dependencies (v3) (#3636)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Benjamin Canac <canacb1@gmail.com>
2025-03-24 11:16:11 +01:00
Benjamin Canac
60bcd4fdf0 chore(defineLocale): put back @__NO_SIDE_EFFECTS__ 2025-03-24 11:03:26 +01:00
Benjamin Canac
c231fe5f26 fix(Button): use focus:outline-none instead of focus:outline-hidden
Resolves #3658
2025-03-24 10:50:06 +01:00
Benjamin Canac
1769d5ed6e fix(Tabs): remove focus:outline-hidden class 2025-03-24 10:48:50 +01:00
Benjamin Canac
68787b26fd fix(Switch): prevent transition on focus outline 2025-03-24 10:48:03 +01:00
Benjamin Canac
f7604e565f fix(Drawer): remove fadeFromIndex prop proxy 2025-03-23 15:56:33 +01:00
Benjamin Canac
82e26655a4 fix(defineLocale/defineShortcuts): remove @__NO_SIDE_EFFECTS__ 2025-03-23 14:53:58 +01:00
Benjamin Canac
2453714136 chore(deps): move @standard-schema/spec to dependencies 2025-03-23 12:52:33 +01:00
Benjamin Canac
973f36539d chore(github): enable ui pro integration 2025-03-21 21:24:47 +01:00
Benjamin Canac
05ab54d03a chore(release): v3.0.1 2025-03-21 16:10:20 +01:00
Benjamin Canac
db83df5f5e chore(github): update integration workflow (#3643) 2025-03-21 15:59:34 +01:00
Shadow
a5168666b7 fix(Calendar): grey out days outside of displayed month (#3639) 2025-03-21 11:12:39 +01:00
renovate[bot]
f30d45c79a chore(deps): update tailwindcss to ^4.0.15 (v3) (#3638)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-20 22:40:18 +01:00
Benjamin Canac
31be5f656e chore(Drawer): put back shrink-0 on handle 2025-03-20 22:25:37 +01:00
Benjamin Canac
0ef5f3b77b chore(github): remove integration env 2025-03-20 22:15:05 +01:00
Benjamin Canac
a0fec4e467 docs(deps): use only one motion library 2025-03-20 22:14:14 +01:00
Benjamin Canac
f401766e26 chore(deps): update vaul-vue 2025-03-20 21:52:14 +01:00
Benjamin Canac
70f469b868 chore(github): update integration workflow 2025-03-20 17:38:09 +01:00
Benjamin Canac
f92df1f661 chore(github): update integration workflow 2025-03-20 16:59:06 +01:00
Benjamin Canac
16edbdf1f0 chore(github): update integration workflow 2025-03-20 16:45:34 +01:00
Benjamin Canac
fe0bd83d11 fix(RadioGroup): handle disabled on items
Resolves nuxt/ui-pro#911
2025-03-20 16:36:58 +01:00
Benjamin Canac
8a26de230b chore(github): update integration workflow 2025-03-20 16:29:38 +01:00
Benjamin Canac
65a6861b54 chore(github): update integration workflow 2025-03-20 16:19:22 +01:00
Sandro Circi
ecff9abc72 fix(module): handle tailwindcss import without theme(static) (#3630)
Co-authored-by: Benjamin Canac <canacb1@gmail.com>
2025-03-20 15:53:57 +01:00
renovate[bot]
06bc7d3028 chore(deps): update all non-major dependencies (v3) (#3591)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-20 15:15:49 +01:00
Halwest Manguri
b2034ccc91 feat(locale): add Central Kurdish language (#3566)
Co-authored-by: Benjamin Canac <canacb1@gmail.com>
2025-03-20 15:15:21 +01:00
Mickael Chanrion
53cf1b4c14 feat(locale): add Catalan language (#3550)
Co-authored-by: Benjamin Canac <canacb1@gmail.com>
2025-03-20 15:09:43 +01:00
Mark
0229b0fd46 feat(locale): add Romanian language (#3587) 2025-03-20 15:04:52 +01:00
Ulugbek Nagmatov
302e04bd77 feat(locale): add Uzbek language (#3548)
Co-authored-by: Benjamin Canac <canacb1@gmail.com>
2025-03-20 15:03:51 +01:00
Arbaz Irshad
126ba2326f feat(locale): add Urdu language (#3611) 2025-03-20 15:00:57 +01:00
Sébastien Chopin
dfc27514ec docs: add redirects from v2 structure (#3634) 2025-03-20 12:55:27 +01:00
Benjamin Canac
26321c4857 test: update snapshots 2025-03-20 12:47:15 +01:00
Benjamin Canac
5dec0e16e2 feat(components): handle events in content prop 2025-03-20 12:39:57 +01:00
Benjamin Canac
f4c417d9ef fix(Modal/Slideover/Toast): prevent unnecessary close instantiation 2025-03-20 12:14:21 +01:00
Benjamin Canac
9046b9d679 docs(Header): remove extraneous prop on navigation menu 2025-03-20 11:59:46 +01:00
Benjamin Canac
99df056cad docs(app): remove hydrate attributes on stars 2025-03-20 00:06:35 +01:00
renovate[bot]
08bebcae48 chore(deps): update nuxt framework to ^3.16.1 (v3) (#3626)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-19 22:04:37 +01:00
Norbiros
764c41a0c6 fix(ContextMenu/DropdownMenu): remove any from proxySlots (#3623) 2025-03-19 22:03:09 +01:00
Benjamin Canac
2abcc24018 chore(github): update integration workflow 2025-03-19 18:38:40 +01:00
Benjamin Canac
67f90f5f26 chore(github): update integration workflow 2025-03-19 18:06:22 +01:00
Benjamin Canac
024fccf8bb chore(github): update integration workflow 2025-03-19 17:38:16 +01:00
Benjamin Canac
edb0f0afc6 docs(app): improve stars lazy loading 2025-03-19 14:54:14 +01:00
Benjamin Canac
fd160339a6 chore(deps): update @nuxt/ui-pro 2025-03-19 12:57:51 +01:00
Benjamin Canac
2a023b9060 docs(app): improve safelist 2025-03-19 12:33:23 +01:00
Benjamin Canac
ab52830dc8 docs(Banner): allow to close 2025-03-19 12:33:23 +01:00
Romain Hamel
9a4bb34d7d refactor(Form)!: drop explicit support for zod and valibot (#3617) 2025-03-19 12:18:26 +01:00
Romain Hamel
02184b016a chore(Form): improve TSDoc (#3619) 2025-03-19 12:17:52 +01:00
Daniel Roe
57efc78a3b fix(module): mark functions used in exports as pure (#3604) 2025-03-18 14:48:28 +01:00
Benjamin Canac
dec2730aae fix(useLocale): unique symbol to use in @nuxt/ui-pro (#3603) 2025-03-18 12:09:36 +01:00
Rizwan
c8ca604bdf docs(migration): improve useOverlay section (#3601) 2025-03-18 12:04:22 +01:00
Benjamin Canac
ef86108f14 chore(components): add eol in script tag to fix syntax highlight 2025-03-18 10:52:04 +01:00
Harlan Wilton
a1caac47c5 docs: broken 404 pages (#3598) 2025-03-18 10:01:19 +01:00
renovate[bot]
fad715d8df chore(deps): lock file maintenance (v3) (#3582)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-17 18:32:13 +01:00
Benjamin Canac
b0d0d926ab chore(colors): put back tagPriority
Partial revert of #3589
2025-03-17 18:24:14 +01:00
Romain Hamel
a8e6b74e38 docs(installation): improve vscode recommendations (#3592)
Co-authored-by: Benjamin Canac <canacb1@gmail.com>
2025-03-17 17:01:44 +01:00
renovate[bot]
177fb79cb4 chore(deps): update all non-major dependencies (v3) (#3551)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Benjamin Canac <canacb1@gmail.com>
2025-03-17 16:08:26 +01:00
Benjamin Canac
175c7027a3 docs(app): put back carbon ads 2025-03-17 16:05:32 +01:00
Romain Hamel
cc504b8a4b fix(unplugin): include @compodium/examples in auto-imports paths (#3585) 2025-03-17 15:16:42 +01:00
Harlan Wilton
0897e9ef05 fix(vue): missing unhead context (#3589)
Co-authored-by: Benjamin Canac <canacb1@gmail.com>
2025-03-17 15:09:02 +01:00
Benjamin Canac
6588ae8669 docs: clean badges 2025-03-17 14:25:37 +01:00
Benjamin Canac
0b41cebee4 docs(nuxt.config): fix local extends
Related to https://github.com/nuxt/nuxt/issues/31311
2025-03-17 14:24:40 +01:00
Kheuval
e80cc1592f fix(Table): allow links to be opened when @select is used (#3580) 2025-03-17 11:38:37 +01:00
Estéban
5d52af6292 docs(pro): update barbapapazes description (#3577) 2025-03-16 12:06:46 +01:00
Nils Evers
5e62493321 fix(types): add missing export for Icon (#3568) 2025-03-15 12:13:50 +01:00
Jeremy Woertink
37f8619c1a docs(migration): fix typo (#3563) 2025-03-15 12:12:34 +01:00
Benjamin Canac
5376a835f7 docs(pro): disable launch offer 2025-03-15 11:03:43 +01:00
Benjamin Canac
f2ba755ba5 chore(github): update integration workflow 2025-03-13 16:15:17 +01:00
Benjamin Canac
c8d712747f chore(github): update integration workflow 2025-03-13 16:09:00 +01:00
Benjamin Canac
816cf50b37 chore(github): update integration workflow 2025-03-13 15:59:42 +01:00
Benjamin Canac
3c60f70cab chore(github): add integration workflow 2025-03-13 15:27:09 +01:00
renovate[bot]
05758fa915 chore(deps): update tailwindcss to ^4.0.14 (v3) (#3553)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-13 14:43:05 +01:00
Maxime Pauvert
ce4b229264 chore(readme): fix npm badge (#3540) 2025-03-13 14:30:39 +01:00
Benjamin Canac
09b4e9e282 chore(vercel): put back config 2025-03-13 13:59:57 +01:00
Sébastien Chopin
50d68a636c docs: add ui pro banner 2025-03-12 18:16:15 +01:00
Sébastien Chopin
7646c95c73 docs(pro): launch offer 2025-03-12 17:05:52 +01:00
Benjamin Canac
4c30baffe0 chore(vercel): remove useless file 2025-03-12 16:19:12 +01:00
Benjamin Canac
0b411936c4 chore: use ui.nuxt.com url 2025-03-12 16:17:43 +01:00
Benjamin Canac
047582c246 chore(deps): update @nuxt/ui-pro 2025-03-12 16:17:43 +01:00
Benjamin Canac
b00f1206f6 docs: update for v3.0.0 release 2025-03-12 16:17:43 +01:00
Benjamin Canac
9ba5cfe70c chore(github): use ui.nuxt.com url in v3 2025-03-12 16:17:43 +01:00
Benjamin Canac
ee9aca33fd chore(github): use ui2.nuxt.com 2025-03-12 16:17:43 +01:00
Sébastien Chopin
8d29e50340 docs: fix og image 2025-03-12 16:09:41 +01:00
Sébastien Chopin
0ad18d0a7a docs(installation): rename template to ui 2025-03-12 15:39:52 +01:00
266 changed files with 9700 additions and 7393 deletions

View File

@@ -5,7 +5,7 @@ body:
- type: markdown - type: markdown
attributes: attributes:
value: | value: |
Before reporting a bug, please make sure that you have read through our [v3 documentation](https://ui3.nuxt.dev/) and existing [issues](https://github.com/nuxt/ui/issues?q=is%3Aissue%20is%3Aopen%20sort%3Aupdated-desc%20label%3Av3). Before reporting a bug, please make sure that you have read through our [v3 documentation](https://ui.nuxt.com/) and existing [issues](https://github.com/nuxt/ui/issues?q=is%3Aissue%20is%3Aopen%20sort%3Aupdated-desc%20label%3Av3).
- type: textarea - type: textarea
id: env id: env
attributes: attributes:
@@ -37,7 +37,7 @@ body:
id: version id: version
attributes: attributes:
label: Version label: Version
placeholder: v3.0.0-alpha.x placeholder: v3.0.0
validations: validations:
required: true required: true
- type: textarea - type: textarea

View File

@@ -5,7 +5,7 @@ body:
- type: markdown - type: markdown
attributes: attributes:
value: | value: |
Before reporting a bug, please make sure that you have read through our [documentation](https://ui.nuxt.com) and existing [issues](https://github.com/nuxt/ui/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc). Before reporting a bug, please make sure that you have read through our [documentation](https://ui2.nuxt.com) and existing [issues](https://github.com/nuxt/ui/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc).
- type: textarea - type: textarea
id: env id: env
attributes: attributes:

View File

@@ -5,7 +5,7 @@ body:
- type: markdown - type: markdown
attributes: attributes:
value: | value: |
Before requesting a feature, please make sure that you have read through our [v3 documentation](https://ui3.nuxt.dev/) and existing [issues](https://github.com/nuxt/ui/issues?q=is%3Aissue%20is%3Aopen%20sort%3Aupdated-desc%20label%3Av3). Before requesting a feature, please make sure that you have read through our [v3 documentation](https://ui.nuxt.com/) and existing [issues](https://github.com/nuxt/ui/issues?q=is%3Aissue%20is%3Aopen%20sort%3Aupdated-desc%20label%3Av3).
- type: textarea - type: textarea
id: description id: description
attributes: attributes:

View File

@@ -5,7 +5,7 @@ body:
- type: markdown - type: markdown
attributes: attributes:
value: | value: |
Before requesting a feature, please make sure that you have read through our [documentation](https://ui.nuxt.com) and existing [issues](https://github.com/nuxt/ui/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc). Before requesting a feature, please make sure that you have read through our [documentation](https://ui2.nuxt.com) and existing [issues](https://github.com/nuxt/ui/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc).
- type: textarea - type: textarea
id: description id: description
attributes: attributes:

View File

@@ -5,7 +5,7 @@ body:
- type: markdown - type: markdown
attributes: attributes:
value: | value: |
Before asking a question, please make sure that you have read through our [v3 documentation](https://ui3.nuxt.dev/) and existing [issues](https://github.com/nuxt/ui/issues?q=is%3Aissue%20is%3Aopen%20sort%3Aupdated-desc%20label%3Av3). Before asking a question, please make sure that you have read through our [v3 documentation](https://ui.nuxt.com/) and existing [issues](https://github.com/nuxt/ui/issues?q=is%3Aissue%20is%3Aopen%20sort%3Aupdated-desc%20label%3Av3).
- type: textarea - type: textarea
id: description id: description
attributes: attributes:

View File

@@ -5,7 +5,7 @@ body:
- type: markdown - type: markdown
attributes: attributes:
value: | value: |
Before asking a question, please make sure that you have read through our [documentation](https://ui.nuxt.com) and existing [issues](https://github.com/nuxt/ui/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc). Before asking a question, please make sure that you have read through our [documentation](https://ui2.nuxt.com) and existing [issues](https://github.com/nuxt/ui/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc).
- type: textarea - type: textarea
id: description id: description
attributes: attributes:

View File

@@ -50,16 +50,164 @@ jobs:
run: pnpm run typecheck run: pnpm run typecheck
- name: Test - name: Test
run: pnpm run test run: pnpm run test run
- name: Test (vue) - name: Test (vue)
run: pnpm run test:vue run: pnpm run test:vue run
- name: Build - name: Build
run: pnpm run build run: pnpm run build
- name: Build vue fixture - name: Build playground
run: pnpm run test:vue:build run: pnpm run dev:build
- name: Build playground (vue)
run: pnpm run dev:vue:build
- name: Publish - name: Publish
run: pnpx pkg-pr-new publish --compact --no-template --pnpm run: pnpx pkg-pr-new publish --compact --no-template --pnpm
starter-nuxt:
needs: build
runs-on: ${{ matrix.os }}
permissions:
contents: read
pull-requests: read
strategy:
matrix:
os: [ubuntu-latest] # macos-latest, windows-latest
node: [22]
steps:
- name: Checkout
uses: actions/checkout@v4
with:
repository: nuxtlabs/nuxt-ui-starter
- name: Store commit SHA
run: |
echo "COMMIT_SHA=$(echo ${{ github.workflow_sha }} | cut -c1-7)" >> $GITHUB_ENV
- name: Install pnpm
uses: pnpm/action-setup@v4
- name: Install node
uses: actions/setup-node@v4
with:
node-version: 22
cache: pnpm
- name: Install latest nuxt/ui
run: pnpm install https://pkg.pr.new/@nuxt/ui@${{ env.COMMIT_SHA }} --lockfile-only
- name: Install dependencies
run: pnpm install
- name: Typecheck
run: pnpm run typecheck
- name: Build
run: pnpm run build
starter-vue:
needs: build
runs-on: ${{ matrix.os }}
permissions:
contents: read
pull-requests: read
strategy:
matrix:
os: [ubuntu-latest] # macos-latest, windows-latest
node: [22]
steps:
- name: Checkout
uses: actions/checkout@v4
with:
repository: nuxtlabs/nuxt-ui-vue-starter
- name: Store commit SHA
run: |
echo "COMMIT_SHA=$(echo ${{ github.workflow_sha }} | cut -c1-7)" >> $GITHUB_ENV
- name: Install pnpm
uses: pnpm/action-setup@v4
- name: Install node
uses: actions/setup-node@v4
with:
node-version: 22
cache: pnpm
- name: Install latest nuxt/ui
run: pnpm install https://pkg.pr.new/@nuxt/ui@${{ env.COMMIT_SHA }} --lockfile-only
- name: Install dependencies
run: pnpm install
- name: Typecheck
run: pnpm run typecheck
- name: Build
run: pnpm run build
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:
contents: read
pull-requests: read
strategy:
matrix:
os: [ubuntu-latest] # macos-latest, windows-latest
node: [22]
env:
NUXT_UI_PRO_LICENSE: ${{ secrets.NUXT_UI_PRO_LICENSE }}
steps:
- name: Checkout
uses: actions/checkout@v4
with:
repository: nuxt/ui-pro
token: ${{ secrets.NUXT_GITHUB_TOKEN }}
- name: Store commit SHA
run: |
echo "COMMIT_SHA=$(echo ${{ github.workflow_sha }} | cut -c1-7)" >> $GITHUB_ENV
- name: Install pnpm
uses: pnpm/action-setup@v4
- name: Install node
uses: actions/setup-node@v4
with:
node-version: 22
cache: pnpm
- name: Install latest nuxt/ui
run: pnpm install https://pkg.pr.new/@nuxt/ui@${{ env.COMMIT_SHA }} --lockfile-only
- name: Install dependencies
run: pnpm install
- name: Prepare
run: pnpm run dev:prepare
- name: Typecheck
run: pnpm run typecheck
- name: Build
run: pnpm run build

View File

@@ -10,14 +10,16 @@ jobs:
permissions: permissions:
issues: write issues: write
pull-requests: write
steps: steps:
- uses: actions/stale@v9 - uses: actions/stale@v9
with: with:
exempt-issue-labels: triage,v3 days-before-stale: -1 # Issues and PR will never be flagged stale automatically.
stale-issue-message: 'This issue is stale because it has been open for 30 days with no activity.' stale-issue-label: 'needs reproduction' # Label that flags an issue as stale.
stale-issue-label: stale only-labels: 'needs reproduction' # Only process these issues
stale-pr-label: stale days-before-issue-close: 7
days-before-stale: 30 ignore-updates: true
days-before-close: -1 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

View File

@@ -1,5 +1,71 @@
# Changelog # 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
* **Form:** drop explicit support for `zod` and `valibot` (#3617)
### Features
* **components:** handle events in `content` prop ([5dec0e1](https://github.com/nuxt/ui/commit/5dec0e16e28549b8833aaab17a87fada63d6598c))
* **locale:** add Catalan language ([#3550](https://github.com/nuxt/ui/issues/3550)) ([53cf1b4](https://github.com/nuxt/ui/commit/53cf1b4c14a2a0e076e1e77688852e6bd0a28a74))
* **locale:** add Central Kurdish language ([#3566](https://github.com/nuxt/ui/issues/3566)) ([b2034cc](https://github.com/nuxt/ui/commit/b2034ccc91eec6a2842c6f83d159e5aa6fd5f2fd))
* **locale:** add Romanian language ([#3587](https://github.com/nuxt/ui/issues/3587)) ([0229b0f](https://github.com/nuxt/ui/commit/0229b0fd4644a97db7eb3154c3c87a26634dcfbb))
* **locale:** add Urdu language ([#3611](https://github.com/nuxt/ui/issues/3611)) ([126ba23](https://github.com/nuxt/ui/commit/126ba2326f8153e155e1013db92c6ee417117610))
* **locale:** add Uzbek language ([#3548](https://github.com/nuxt/ui/issues/3548)) ([302e04b](https://github.com/nuxt/ui/commit/302e04bd77ae8b165046b264c8d23626e92f8fb5))
### Bug Fixes
* **Calendar:** grey out days outside of displayed month ([#3639](https://github.com/nuxt/ui/issues/3639)) ([a516866](https://github.com/nuxt/ui/commit/a5168666b7dff08e714d57f497737e7a670f457c))
* **ContextMenu/DropdownMenu:** remove `any` from `proxySlots` ([#3623](https://github.com/nuxt/ui/issues/3623)) ([764c41a](https://github.com/nuxt/ui/commit/764c41a0c60dd1c12d39a86af9f5f11b9e6cdc8c))
* **Modal/Slideover/Toast:** prevent unnecessary close instantiation ([f4c417d](https://github.com/nuxt/ui/commit/f4c417d9ef5409b52084bdf9d8cbccee3139709f))
* **module:** handle tailwindcss import without `theme(static)` ([#3630](https://github.com/nuxt/ui/issues/3630)) ([ecff9ab](https://github.com/nuxt/ui/commit/ecff9abc720bdda3a279d5bcfb7b477ff885f2e4))
* **module:** mark functions used in exports as pure ([#3604](https://github.com/nuxt/ui/issues/3604)) ([57efc78](https://github.com/nuxt/ui/commit/57efc78a3b3fa4a54bcd13df47d570a18fba2bc4))
* **RadioGroup:** handle `disabled` on items ([fe0bd83](https://github.com/nuxt/ui/commit/fe0bd83d11b0dfa53b58d423bc917f8e21d73444)), closes [nuxt/ui-pro#911](https://github.com/nuxt/ui-pro/issues/911)
* **Table:** allow links to be opened when [@select](https://github.com/select) is used ([#3580](https://github.com/nuxt/ui/issues/3580)) ([e80cc15](https://github.com/nuxt/ui/commit/e80cc1592fb244dd7692486a4c1ca5b1c2008112))
* **types:** add missing export for Icon ([#3568](https://github.com/nuxt/ui/issues/3568)) ([5e62493](https://github.com/nuxt/ui/commit/5e624933216db95cbfd1b8034b2eb0f13846ae55))
* **unplugin:** include `@compodium/examples` in auto-imports paths ([#3585](https://github.com/nuxt/ui/issues/3585)) ([cc504b8](https://github.com/nuxt/ui/commit/cc504b8a4b69dd76b49659d5c206ef23dcb9e475))
* **useLocale:** unique symbol to use in `@nuxt/ui-pro` ([#3603](https://github.com/nuxt/ui/issues/3603)) ([dec2730](https://github.com/nuxt/ui/commit/dec2730aaea1327434837cfa022ea04056757cbf))
* **vue:** missing unhead context ([#3589](https://github.com/nuxt/ui/issues/3589)) ([0897e9e](https://github.com/nuxt/ui/commit/0897e9ef05fbee4f021f317bb7c2d0b7007f1b75))
### Code Refactoring
* **Form:** drop explicit support for `zod` and `valibot` ([#3617](https://github.com/nuxt/ui/issues/3617)) ([9a4bb34](https://github.com/nuxt/ui/commit/9a4bb34d7d14add0a3199103f4b583e8307d1d6d))
## [3.0.0](https://github.com/nuxt/ui/compare/v3.0.0-beta.4...v3.0.0) (2025-03-12) ## [3.0.0](https://github.com/nuxt/ui/compare/v3.0.0-beta.4...v3.0.0) (2025-03-12)
## [3.0.0-beta.4](https://github.com/nuxt/ui/compare/v3.0.0-beta.3...v3.0.0-beta.4) (2025-03-12) ## [3.0.0-beta.4](https://github.com/nuxt/ui/compare/v3.0.0-beta.3...v3.0.0-beta.4) (2025-03-12)

View File

@@ -11,31 +11,31 @@
[![License][license-src]][license-href] [![License][license-src]][license-href]
[![Nuxt][nuxt-src]][nuxt-href] [![Nuxt][nuxt-src]][nuxt-href]
We're thrilled to introduce Nuxt UI v3, a significant upgrade to our UI library that delivers extensive improvements and robust new capabilities. This major update harnesses the combined strengths of [Reka UI](https://reka-ui.com/), [Tailwind CSS v4](https://tailwindcss.com/), and [Tailwind Variants](https://www.tailwind-variants.org/) to offer developers an unparalleled set of tools for creating sophisticated, accessible, and highly performant user interfaces. Nuxt UI harnesses the combined strengths of [Reka UI](https://reka-ui.com/), [Tailwind CSS](https://tailwindcss.com/), and [Tailwind Variants](https://www.tailwind-variants.org/) to offer developers an unparalleled set of tools for creating sophisticated, accessible, and highly performant user interfaces.
> [!NOTE] > [!NOTE]
> You are on the `v3` development branch, check out the [v2 branch](https://github.com/nuxt/ui/tree/v2) for Nuxt UI v2. > You are on the `v3` development branch, check out the [v2 branch](https://github.com/nuxt/ui/tree/v2) for Nuxt UI v2.
## Documentation ## Documentation
Visit https://ui3.nuxt.dev to explore the documentation. Visit https://ui.nuxt.com to explore the documentation.
## Installation ## Installation
```bash [pnpm] ```bash [pnpm]
pnpm add @nuxt/ui@next pnpm add @nuxt/ui
``` ```
```bash [yarn] ```bash [yarn]
yarn add @nuxt/ui@next yarn add @nuxt/ui
``` ```
```bash [npm] ```bash [npm]
npm install @nuxt/ui@next npm install @nuxt/ui
``` ```
```bash [bun] ```bash [bun]
bun add @nuxt/ui@next bun add @nuxt/ui
``` ```
### Nuxt ### Nuxt
@@ -51,11 +51,11 @@ export default defineNuxtConfig({
2. Import Tailwind CSS and Nuxt UI in your CSS: 2. Import Tailwind CSS and Nuxt UI in your CSS:
```css [assets/css/main.css] ```css [assets/css/main.css]
@import "tailwindcss" theme(static); @import "tailwindcss";
@import "@nuxt/ui"; @import "@nuxt/ui";
``` ```
Learn more in the [installation guide](https://ui3.nuxt.dev/getting-started/installation/nuxt). Learn more in the [installation guide](https://ui.nuxt.com/getting-started/installation/nuxt).
### Vue ### Vue
@@ -98,11 +98,11 @@ app.mount('#app')
3. Import Tailwind CSS and Nuxt UI in your CSS: 3. Import Tailwind CSS and Nuxt UI in your CSS:
```css [assets/main.css] ```css [assets/main.css]
@import "tailwindcss" theme(static); @import "tailwindcss";
@import "@nuxt/ui"; @import "@nuxt/ui";
``` ```
Learn more in the [installation guide](https://ui3.nuxt.dev/getting-started/installation/vue). Learn more in the [installation guide](https://ui.nuxt.com/getting-started/installation/vue).
## Credits ## Credits
@@ -119,7 +119,7 @@ Learn more in the [installation guide](https://ui3.nuxt.dev/getting-started/inst
Licensed under the [MIT license](https://github.com/nuxt/ui/blob/v3/LICENSE.md). Licensed under the [MIT license](https://github.com/nuxt/ui/blob/v3/LICENSE.md).
<!-- Badges --> <!-- Badges -->
[npm-version-src]: https://img.shields.io/npm/v/@nuxt/ui/next.svg?style=flat&colorA=18181B&colorB=28CF8D [npm-version-src]: https://img.shields.io/npm/v/@nuxt/ui/latest.svg?style=flat&colorA=18181B&colorB=28CF8D
[npm-version-href]: https://npmjs.com/package/@nuxt/ui [npm-version-href]: https://npmjs.com/package/@nuxt/ui
[npm-downloads-src]: https://img.shields.io/npm/dm/@nuxt/ui.svg?style=flat&colorA=18181B&colorB=28CF8D [npm-downloads-src]: https://img.shields.io/npm/dm/@nuxt/ui.svg?style=flat&colorA=18181B&colorB=28CF8D

View File

@@ -6,7 +6,7 @@
}, },
"dependencies": { "dependencies": {
"citty": "^0.1.6", "citty": "^0.1.6",
"consola": "^3.4.0", "consola": "^3.4.2",
"pathe": "^2.0.3", "pathe": "^2.0.3",
"scule": "^1.3.0" "scule": "^1.3.0"
} }

View File

@@ -1,7 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
// import { withoutTrailingSlash } from 'ufo' import { withoutTrailingSlash } from 'ufo'
import colors from 'tailwindcss/colors' import colors from 'tailwindcss/colors'
// import { debounce } from 'perfect-debounce'
const route = useRoute() const route = useRoute()
const appConfig = useAppConfig() const appConfig = useAppConfig()
@@ -12,16 +11,6 @@ const { data: files } = useLazyAsyncData('search', () => queryCollectionSearchSe
server: false server: false
}) })
const searchTerm = ref('')
// watch(searchTerm, debounce((query: string) => {
// if (!query) {
// return
// }
// useTrackEvent('Search', { props: { query: `${query} - ${searchTerm.value?.commandPaletteRef.results.length} results` } })
// }, 500))
const links = useLinks() const links = useLinks()
const color = computed(() => colorMode.value === 'dark' ? (colors as any)[appConfig.ui.colors.neutral][900] : 'white') 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 radius = computed(() => `:root { --ui-radius: ${appConfig.theme.radius}rem; }`)
@@ -33,8 +22,8 @@ useHead({
{ key: 'theme-color', name: 'theme-color', content: color } { key: 'theme-color', name: 'theme-color', content: color }
], ],
link: [ link: [
{ rel: 'icon', type: 'image/svg+xml', href: '/icon.svg' } { rel: 'icon', type: 'image/svg+xml', href: '/icon.svg' },
// { rel: 'canonical', href: `https://ui.nuxt.com${withoutTrailingSlash(route.path)}` } { rel: 'canonical', href: `https://ui.nuxt.com${withoutTrailingSlash(route.path)}` }
], ],
style: [ style: [
{ innerHTML: radius, id: 'nuxt-ui-radius', tagPriority: -2 }, { innerHTML: radius, id: 'nuxt-ui-radius', tagPriority: -2 },
@@ -61,7 +50,7 @@ provide('navigation', mappedNavigation)
<NuxtLoadingIndicator color="var(--ui-primary)" :height="2" /> <NuxtLoadingIndicator color="var(--ui-primary)" :height="2" />
<template v-if="!route.path.startsWith('/examples')"> <template v-if="!route.path.startsWith('/examples')">
<!-- <Banner /> --> <Banner />
<Header :links="links" /> <Header :links="links" />
</template> </template>
@@ -75,7 +64,6 @@ provide('navigation', mappedNavigation)
<ClientOnly> <ClientOnly>
<LazyUContentSearch <LazyUContentSearch
v-model:search-term="searchTerm"
:files="files" :files="files"
:groups="[{ :groups="[{
id: 'framework', id: 'framework',
@@ -95,5 +83,5 @@ provide('navigation', mappedNavigation)
</template> </template>
<style> <style>
/* Safelist (do not remove): [&>div]:*:my-0 [&>div]:*:w-full h-64 !px-0 !py-0 !pt-0 !pb-0 !p-0 !justify-start !min-h-96 h-136 */ /* Safelist (do not remove): [&>div]:*:my-0 [&>div]:*:w-full h-64 !px-0 !py-0 !pt-0 !pb-0 !p-0 !justify-start !justify-end !min-h-96 h-136 */
</style> </style>

View File

@@ -0,0 +1,50 @@
<script setup lang="ts">
const el = ref<HTMLDivElement | null>(null)
onMounted(() => {
if (!el.value) {
return
}
const script = document.createElement('script')
script.setAttribute('type', 'text/javascript')
script.setAttribute('src', 'https://cdn.carbonads.com/carbon.js?serve=CWYIVK3E&placement=uinuxtcom')
script.setAttribute('id', '_carbonads_js')
el.value?.appendChild(script)
})
</script>
<template>
<div ref="el" class="carbon" />
</template>
<style scoped>
@reference "../assets/css/main.css";
.carbon :deep(#carbonads) {
@apply relative border border-(--ui-border) rounded-[calc(var(--ui-radius)*1.5)] hover:bg-(--ui-bg-elevated)/50 w-full transition-colors min-h-[220px] p-2;
.carbon-img {
@apply flex justify-center w-full;
& > img {
@apply !max-w-full w-full rounded-(--ui-radius);
}
}
.carbon-text {
@apply text-sm text-(--ui-text-muted) transition-colors text-center text-pretty flex pt-2;
}
.carbon-poweredby {
@apply block text-xs text-center text-(--ui-text-muted) pt-2;
}
&:hover {
.carbon-text {
@apply text-(--ui-text);
}
}
}
</style>

View File

@@ -1,7 +1,18 @@
<template> <template>
<UBanner icon="i-lucide-construction" :actions="[{ label: 'Go to Nuxt UI v2', to: 'https://ui.nuxt.com', trailingIcon: 'i-lucide-arrow-right' }]" :close="false"> <UBanner
id="ui3-launch"
icon="i-lucide-rocket"
:actions="[
{
label: 'Discover Nuxt UI Pro',
to: '/pro/pricing',
trailingIcon: 'i-lucide-arrow-right'
}
]"
close
>
<template #title> <template #title>
You're looking at the documentation for <span class="font-semibold">Nuxt UI v3</span>! <span class="font-semibold">Nuxt UI v3</span> is officially released.
</template> </template>
</UBanner> </UBanner>
</template> </template>

View File

@@ -0,0 +1,51 @@
<script setup lang="ts">
const endDate = new Date('2025-03-14T23:59:59Z')
const second = 1000
const minute = second * 60
const hour = minute * 60
const day = hour * 24
function getCountdown() {
const distance = Math.floor((endDate.getTime() - Date.now()))
return {
day: Math.floor(distance / day),
hour: Math.floor((distance % (day)) / (hour)),
minute: Math.floor((distance % (hour)) / (minute)),
second: Math.floor((distance % (minute)) / (second)),
distance
}
}
const countdown = ref(getCountdown())
let interval: any
if (countdown.value.distance > 0) {
onMounted(() => {
interval = setInterval(() => {
countdown.value = getCountdown()
if (countdown.value.distance <= 0) {
clearInterval(interval)
}
}, 1000)
})
}
const plural = (value: number) => (value === 1 ? '' : 's')
const double = (value: number) => (value < 10 ? `0${value}` : value)
</script>
<template>
<div>
<p class="font-semibold text-gray-900 dark:text-white text-sm mb-3">
Nuxt UI v3 launch offer ends in:
</p>
<div class="flex items-center justify-center gap-2 text-center">
<template v-for="(value, key) in countdown" :key="key">
<div v-if="key !== 'distance'" class="flex flex-col items-center gap-2">
<UBadge color="primary" class="w-14 h-14 font-bold text-2xl flex items-center justify-center tabular-nums" variant="subtle">
{{ double(value) }}
</UBadge>
<span class="text-[10px] font-semibold text-gray-900 dark:text-white tracking-wide tabular-nums uppercase">{{ key }}{{ plural(value) }}</span>
</div>
</template>
</div>
</div>
</template>

View File

@@ -41,7 +41,7 @@ const mobileLinks = computed(() => props.links.map(link => ({ ...link, defaultOp
<UDropdownMenu <UDropdownMenu
v-slot="{ open }" v-slot="{ open }"
:modal="false" :modal="false"
:items="[{ label: `v${config.version}`, active: true, color: 'primary', checked: true, type: 'checkbox' }, { label: module === 'ui-pro' ? 'v1.5' : 'v2.19', to: module === 'ui-pro' ? 'https://ui.nuxt.com/pro' : 'https://ui.nuxt.com' }]" :items="[{ label: `v${config.version}`, active: true, color: 'primary', checked: true, type: 'checkbox' }, { label: module === 'ui-pro' ? 'v1.7.1' : 'v2.21.1', to: module === 'ui-pro' ? 'https://ui2.nuxt.com/pro' : 'https://ui2.nuxt.com' }]"
:ui="{ content: 'w-(--reka-dropdown-menu-trigger-width) min-w-0' }" :ui="{ content: 'w-(--reka-dropdown-menu-trigger-width) min-w-0' }"
size="xs" size="xs"
> >
@@ -82,7 +82,7 @@ const mobileLinks = computed(() => props.links.map(link => ({ ...link, defaultOp
</template> </template>
<template #body> <template #body>
<UNavigationMenu orientation="vertical" :items="mobileLinks" class="-mx-2.5" default-open /> <UNavigationMenu orientation="vertical" :items="mobileLinks" class="-mx-2.5" />
<USeparator type="dashed" class="mt-4 mb-6" /> <USeparator type="dashed" class="mt-4 mb-6" />

View File

@@ -1,4 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import { kebabCase } from 'scule'
interface Star { interface Star {
x: number x: number
y: number y: number
@@ -22,6 +24,8 @@ const props = withDefaults(defineProps<{
speed: 'normal' speed: 'normal'
}) })
const route = useRoute()
// Generate random stars // Generate random stars
const generateStars = (count: number): Star[] => { const generateStars = (count: number): Star[] => {
return Array.from({ length: count }, () => { return Array.from({ length: count }, () => {
@@ -35,7 +39,7 @@ const generateStars = (count: number): Star[] => {
} }
// Generate all stars // Generate all stars
const stars = ref<Star[]>(generateStars(props.starCount)) const stars = useState<Star[]>(`${kebabCase(route.path)}-sky`, () => generateStars(props.starCount))
// Compute twinkle animation duration based on speed // Compute twinkle animation duration based on speed
const twinkleDuration = computed(() => { const twinkleDuration = computed(() => {
@@ -50,22 +54,20 @@ const twinkleDuration = computed(() => {
<template> <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] inset-y-0 left-4 right-4 lg:right-[50%] overflow-hidden">
<ClientOnly> <div
<div v-for="star in stars"
v-for="star in stars" :key="star.id"
:key="star.id" class="star absolute"
class="star absolute" :style="{
:style="{ 'left': `${star.x}%`,
'left': `${star.x}%`, 'top': `${star.y}%`,
'top': `${star.y}%`, 'transform': 'translate(-50%, -50%)',
'transform': 'translate(-50%, -50%)', '--star-size': `${star.size}px`,
'--star-size': `${star.size}px`, '--star-color': color,
'--star-color': color, '--twinkle-delay': `${star.twinkleDelay}s`,
'--twinkle-delay': `${star.twinkleDelay}s`, '--twinkle-duration': twinkleDuration
'--twinkle-duration': twinkleDuration }"
}" />
/>
</ClientOnly>
</div> </div>
</template> </template>

View File

@@ -1,4 +1,12 @@
<script setup lang="ts"> <script setup lang="ts">
import { kebabCase } from 'scule'
interface Star {
x: number
y: number
size: number
}
const props = withDefaults(defineProps<{ const props = withDefaults(defineProps<{
starCount?: number starCount?: number
color?: string color?: string
@@ -14,8 +22,10 @@ const props = withDefaults(defineProps<{
}) })
}) })
const route = useRoute()
// Generate random star positions and sizes // Generate random star positions and sizes
const generateStars = (count: number) => { const generateStars = (count: number): Star[] => {
return Array.from({ length: count }, () => ({ return Array.from({ length: count }, () => ({
x: Math.floor(Math.random() * 2000), x: Math.floor(Math.random() * 2000),
y: Math.floor(Math.random() * 2000), y: Math.floor(Math.random() * 2000),
@@ -25,52 +35,58 @@ const generateStars = (count: number) => {
})) }))
} }
// Compute star layers with different speeds and opacities // Define speed configurations once
const starLayers = computed(() => { const speedMap = {
const speedMap = { slow: { duration: 200, opacity: 0.5, ratio: 0.3 },
slow: { duration: 200, opacity: 0.5 }, normal: { duration: 150, opacity: 0.75, ratio: 0.3 },
normal: { duration: 150, opacity: 0.75 }, fast: { duration: 100, opacity: 1, ratio: 0.4 }
fast: { duration: 100, opacity: 1 } }
}
return [ // Use a more efficient approach to generate and store stars
{ stars: generateStars(props.starCount), ...speedMap.fast }, const stars = useState<{ slow: Star[], normal: Star[], fast: Star[] }>(`${kebabCase(route.path)}-stars`, () => {
{ stars: generateStars(Math.floor(props.starCount * 0.6)), ...speedMap.normal }, return {
{ stars: generateStars(Math.floor(props.starCount * 0.3)), ...speedMap.slow } slow: generateStars(Math.floor(props.starCount * speedMap.slow.ratio)),
] normal: generateStars(Math.floor(props.starCount * speedMap.normal.ratio)),
fast: generateStars(Math.floor(props.starCount * speedMap.fast.ratio))
}
}) })
// Compute star layers with different speeds and opacities
const starLayers = computed(() => [
{ stars: stars.value.fast, ...speedMap.fast },
{ stars: stars.value.normal, ...speedMap.normal },
{ stars: stars.value.slow, ...speedMap.slow }
])
</script> </script>
<template> <template>
<div class="absolute pointer-events-none z-[-1] inset-y-0 inset-x-5 sm:inset-x-7 lg:inset-x-9 overflow-hidden"> <div class="absolute pointer-events-none z-[-1] inset-y-0 inset-x-5 sm:inset-x-7 lg:inset-x-9 overflow-hidden">
<ClientOnly> <div class="stars size-full absolute inset-x-0 top-0">
<div class="stars size-full absolute inset-x-0 top-0"> <div
v-for="(layer, index) in starLayers"
:key="index"
class="star-layer"
:style="{
'--star-duration': `${layer.duration}s`,
'--star-opacity': layer.opacity,
'--star-color': color
}"
>
<div <div
v-for="(layer, index) in starLayers" v-for="(star, starIndex) in layer.stars"
:key="index" :key="starIndex"
class="star-layer" class="star absolute rounded-full"
:style="{ :style="{
'--star-duration': `${layer.duration}s`, left: `${star.x}px`,
'--star-opacity': layer.opacity, top: `${star.y}px`,
'--star-color': color width: `${star.size}px`,
height: `${star.size}px`,
backgroundColor: 'var(--star-color)',
opacity: 'var(--star-opacity)'
}" }"
> />
<div
v-for="(star, starIndex) in layer.stars"
:key="starIndex"
class="star absolute rounded-full"
:style="{
left: `${star.x}px`,
top: `${star.y}px`,
width: `${star.size}px`,
height: `${star.size}px`,
backgroundColor: 'var(--star-color)',
opacity: 'var(--star-opacity)'
}"
/>
</div>
</div> </div>
</ClientOnly> </div>
</div> </div>
</template> </template>

View File

@@ -1,5 +1,6 @@
<!-- eslint-disable no-useless-escape --> <!-- eslint-disable no-useless-escape -->
<script setup lang="ts"> <script setup lang="ts">
import type { ChipProps } from '@nuxt/ui'
import json5 from 'json5' import json5 from 'json5'
import { upperFirst, camelCase, kebabCase } from 'scule' import { upperFirst, camelCase, kebabCase } from 'scule'
import { hash } from 'ohash' import { hash } from 'ohash'
@@ -53,6 +54,8 @@ const props = defineProps<{
hide?: string[] hide?: string[]
/** List of props to externalize in script setup */ /** List of props to externalize in script setup */
external?: string[] external?: string[]
/** The types of the externalized props */
externalTypes?: string[]
/** List of props to use with `v-model` */ /** List of props to use with `v-model` */
model?: string[] model?: string[]
/** List of props to cast from code and selection */ /** List of props to cast from code and selection */
@@ -209,11 +212,21 @@ ${props.slots?.default}
code += ` code += `
<script setup lang="ts"> <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 cast = props.cast?.[key]
const value = cast ? castMap[cast]!.template(componentProps[key]) : json5.stringify(componentProps[key], null, 2)?.replace(/,([ |\t\n]+[}|\]])/g, '$1') 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> code += `<\/script>
@@ -346,7 +359,7 @@ const { data: ast } = await useAsyncData(`component-code-${name}-${hash({ props:
inset inset
standalone standalone
:color="(modelValue as any)" :color="(modelValue as any)"
:size="ui.itemLeadingChipSize()" :size="(ui.itemLeadingChipSize() as ChipProps['size'])"
class="size-2" class="size-2"
/> />
</template> </template>

View File

@@ -1,4 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import type { ChipProps } from '@nuxt/ui'
import { camelCase } from 'scule' import { camelCase } from 'scule'
import { useElementSize } from '@vueuse/core' import { useElementSize } from '@vueuse/core'
import { get, set } from '#ui/utils' import { get, set } from '#ui/utils'
@@ -185,7 +186,7 @@ const urlSearchParams = computed(() => {
inset inset
standalone standalone
:color="(modelValue as any)" :color="(modelValue as any)"
:size="ui.itemLeadingChipSize()" :size="(ui.itemLeadingChipSize() as ChipProps['size'])"
class="size-2" class="size-2"
/> />
</template> </template>

View File

@@ -11,19 +11,23 @@ function getEmojiFlag(locale: string): string {
const languageToCountry: Record<string, string> = { const languageToCountry: Record<string, string> = {
ar: 'sa', // Arabic -> Saudi Arabia ar: 'sa', // Arabic -> Saudi Arabia
bn: 'bd', // Bengali -> Bangladesh bn: 'bd', // Bengali -> Bangladesh
ca: 'es', // Catalan -> Spain
ckb: 'iq', // Central Kurdish -> Iraq
cs: 'cz', // Czech -> Czech Republic (note: modern country code is actually 'cz') cs: 'cz', // Czech -> Czech Republic (note: modern country code is actually 'cz')
da: 'dk', // Danish -> Denmark da: 'dk', // Danish -> Denmark
el: 'gr', // Greek -> Greece el: 'gr', // Greek -> Greece
et: 'ee', // Estonian -> Estonia
en: 'gb', // English -> Great Britain en: 'gb', // English -> Great Britain
et: 'ee', // Estonian -> Estonia
he: 'il', // Hebrew -> Israel he: 'il', // Hebrew -> Israel
hi: 'in', // Hindi -> India hi: 'in', // Hindi -> India
hy: 'am', // Armenian -> Armenia
ja: 'jp', // Japanese -> Japan ja: 'jp', // Japanese -> Japan
km: 'kh', // Khmer -> Cambodia km: 'kh', // Khmer -> Cambodia
ko: 'kr', // Korean -> South Korea ko: 'kr', // Korean -> South Korea
nb: 'no', // Norwegian Bokmål -> Norway nb: 'no', // Norwegian Bokmål -> Norway
sv: 'se', // Swedish -> Sweden sv: 'se', // Swedish -> Sweden
uk: 'ua', // Ukrainian -> Ukraine uk: 'ua', // Ukrainian -> Ukraine
ur: 'pk', // Urdu -> Pakistan
vi: 'vn' // Vietnamese -> Vietnam vi: 'vn' // Vietnamese -> Vietnam
} }

View File

@@ -1,5 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
const items = [ import type { AccordionItem } from '@nuxt/ui'
const items: AccordionItem[] = [
{ {
label: 'Icons', label: 'Icons',
icon: 'i-lucide-smile' icon: 'i-lucide-smile'

View File

@@ -1,5 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
const items = [ import type { AccordionItem } from '@nuxt/ui'
const items: AccordionItem[] = [
{ {
label: 'Icons', label: 'Icons',
icon: 'i-lucide-smile' icon: 'i-lucide-smile'

View File

@@ -1,4 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import type { AccordionItem } from '@nuxt/ui'
const items = [ const items = [
{ {
label: 'Icons', label: 'Icons',
@@ -8,7 +10,7 @@ const items = [
{ {
label: 'Colors', label: 'Colors',
icon: 'i-lucide-swatch-book', icon: 'i-lucide-swatch-book',
slot: 'colors', slot: 'colors' as const,
content: 'Choose a primary and a neutral color from your Tailwind CSS theme.' content: 'Choose a primary and a neutral color from your Tailwind CSS theme.'
}, },
{ {
@@ -16,7 +18,7 @@ const items = [
icon: 'i-lucide-box', icon: 'i-lucide-box',
content: 'You can customize components by using the `class` / `ui` props or in your app.config.ts.' content: 'You can customize components by using the `class` / `ui` props or in your app.config.ts.'
} }
] ] satisfies AccordionItem[]
</script> </script>
<template> <template>

View File

@@ -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>

View File

@@ -1,5 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
const items = [ import type { AccordionItem } from '@nuxt/ui'
const items: AccordionItem[] = [
{ {
label: 'Icons', label: 'Icons',
icon: 'i-lucide-smile', icon: 'i-lucide-smile',

View File

@@ -1,9 +1,11 @@
<script setup lang="ts"> <script setup lang="ts">
import type { BreadcrumbItem } from '@nuxt/ui'
const items = [{ const items = [{
label: 'Home', label: 'Home',
to: '/' to: '/'
}, { }, {
slot: 'dropdown', slot: 'dropdown' as const,
icon: 'i-lucide-ellipsis', icon: 'i-lucide-ellipsis',
children: [{ children: [{
label: 'Documentation' label: 'Documentation'
@@ -18,7 +20,7 @@ const items = [{
}, { }, {
label: 'Breadcrumb', label: 'Breadcrumb',
to: '/components/breadcrumb' to: '/components/breadcrumb'
}] }] satisfies BreadcrumbItem[]
</script> </script>
<template> <template>

View File

@@ -1,5 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
const items = [{ import type { BreadcrumbItem } from '@nuxt/ui'
const items: BreadcrumbItem[] = [{
label: 'Home', label: 'Home',
to: '/' to: '/'
}, { }, {

View File

@@ -1,5 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
const items = [{ import type { DropdownMenuItem } from '@nuxt/ui'
const items: DropdownMenuItem[] = [{
label: 'Team', label: 'Team',
icon: 'i-lucide-users' icon: 'i-lucide-users'
}, { }, {

View File

@@ -11,7 +11,7 @@ const groups = [{
label: 'Billing', label: 'Billing',
icon: 'i-lucide-credit-card', icon: 'i-lucide-credit-card',
kbds: ['meta', 'B'], kbds: ['meta', 'B'],
slot: 'billing' slot: 'billing' as const
}, },
{ {
label: 'Notifications', label: 'Notifications',
@@ -25,7 +25,7 @@ const groups = [{
}, { }, {
id: 'users', id: 'users',
label: 'Users', label: 'Users',
slot: 'users', slot: 'users' as const,
items: [ items: [
{ {
label: 'Benjamin Canac', label: 'Benjamin Canac',

View File

@@ -1,8 +1,10 @@
<script setup lang="ts"> <script setup lang="ts">
import type { ContextMenuItem } from '@nuxt/ui'
const showSidebar = ref(true) const showSidebar = ref(true)
const showToolbar = ref(false) const showToolbar = ref(false)
const items = computed(() => [{ const items = computed<ContextMenuItem[]>(() => [{
label: 'View', label: 'View',
type: 'label' as const type: 'label' as const
}, { }, {

View File

@@ -1,5 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
const items = [ import type { ContextMenuItem } from '@nuxt/ui'
const items: ContextMenuItem[][] = [
[ [
{ {
label: 'View', label: 'View',

View File

@@ -1,7 +1,9 @@
<script setup lang="ts"> <script setup lang="ts">
import type { ContextMenuItem } from '@nuxt/ui'
const loading = ref(true) const loading = ref(true)
const items = [{ const items: ContextMenuItem[] = [{
label: 'Refresh the Page', label: 'Refresh the Page',
slot: 'refresh' slot: 'refresh'
}, { }, {

View File

@@ -1,4 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import type { DropdownMenuItem } from '@nuxt/ui'
const showBookmarks = ref(true) const showBookmarks = ref(true)
const showHistory = ref(false) const showHistory = ref(false)
const showDownloads = ref(false) const showDownloads = ref(false)
@@ -36,7 +38,7 @@ const items = computed(() => [{
onUpdateChecked(checked: boolean) { onUpdateChecked(checked: boolean) {
showDownloads.value = checked showDownloads.value = checked
} }
}]) }] satisfies DropdownMenuItem[])
</script> </script>
<template> <template>

View File

@@ -1,5 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
const items = [ import type { DropdownMenuItem } from '@nuxt/ui'
const items: DropdownMenuItem[][] = [
[ [
{ {
label: 'View', label: 'View',
@@ -17,7 +19,7 @@ const items = [
[ [
{ {
label: 'Delete', label: 'Delete',
color: 'error' as const, color: 'error',
icon: 'i-lucide-trash' icon: 'i-lucide-trash'
} }
] ]
@@ -27,9 +29,5 @@ const items = [
<template> <template>
<UDropdownMenu :items="items" :ui="{ content: 'w-48' }"> <UDropdownMenu :items="items" :ui="{ content: 'w-48' }">
<UButton label="Open" color="neutral" variant="outline" icon="i-lucide-menu" /> <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> </UDropdownMenu>
</template> </template>

View File

@@ -1,15 +1,19 @@
<script setup lang="ts"> <script setup lang="ts">
const items = [{ import type { DropdownMenuItem } from '@nuxt/ui'
label: 'Profile',
icon: 'i-lucide-user', const items = [
slot: 'profile' {
}, { label: 'Profile',
label: 'Billing', icon: 'i-lucide-user',
icon: 'i-lucide-credit-card' slot: 'profile' as const
}, { }, {
label: 'Settings', label: 'Billing',
icon: 'i-lucide-cog' icon: 'i-lucide-credit-card'
}] }, {
label: 'Settings',
icon: 'i-lucide-cog'
}
] satisfies DropdownMenuItem[]
</script> </script>
<template> <template>

View File

@@ -1,20 +1,24 @@
<script setup lang="ts"> <script setup lang="ts">
import type { DropdownMenuItem } from '@nuxt/ui'
const open = ref(false) const open = ref(false)
defineShortcuts({ defineShortcuts({
o: () => open.value = !open.value o: () => open.value = !open.value
}) })
const items = [{ const items: DropdownMenuItem[] = [
label: 'Profile', {
icon: 'i-lucide-user' label: 'Profile',
}, { icon: 'i-lucide-user'
label: 'Billing', }, {
icon: 'i-lucide-credit-card' label: 'Billing',
}, { icon: 'i-lucide-credit-card'
label: 'Settings', }, {
icon: 'i-lucide-cog' label: 'Settings',
}] icon: 'i-lucide-cog'
}
]
</script> </script>
<template> <template>

View File

@@ -22,7 +22,7 @@ async function onSubmit(event: FormSubmitEvent<Schema>) {
</script> </script>
<template> <template>
<UForm :schema="v.safeParser(schema)" :state="state" class="space-y-4" @submit="onSubmit"> <UForm :schema="schema" :state="state" class="space-y-4" @submit="onSubmit">
<UFormField label="Email" name="email"> <UFormField label="Email" name="email">
<UInput v-model="state.email" /> <UInput v-model="state.email" />
</UFormField> </UFormField>

View File

@@ -16,7 +16,7 @@ function onOpen() {
<template> <template>
<UInputMenu <UInputMenu
:items="countries || []" :items="countries"
:loading="status === 'pending'" :loading="status === 'pending'"
label-key="name" label-key="name"
:search-input="{ icon: 'i-lucide-search' }" :search-input="{ icon: 'i-lucide-search' }"

View File

@@ -1,4 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import type { AvatarProps } from '@nuxt/ui'
const { data: users, status } = await useFetch('https://jsonplaceholder.typicode.com/users', { const { data: users, status } = await useFetch('https://jsonplaceholder.typicode.com/users', {
key: 'typicode-users', key: 'typicode-users',
transform: (data: { id: number, name: string }[]) => { transform: (data: { id: number, name: string }[]) => {
@@ -6,7 +8,7 @@ const { data: users, status } = await useFetch('https://jsonplaceholder.typicode
label: user.name, label: user.name,
value: String(user.id), value: String(user.id),
avatar: { src: `https://i.pravatar.cc/120?img=${user.id}` } avatar: { src: `https://i.pravatar.cc/120?img=${user.id}` }
})) || [] }))
}, },
lazy: true lazy: true
}) })
@@ -14,7 +16,7 @@ const { data: users, status } = await useFetch('https://jsonplaceholder.typicode
<template> <template>
<UInputMenu <UInputMenu
:items="users || []" :items="users"
:loading="status === 'pending'" :loading="status === 'pending'"
icon="i-lucide-user" icon="i-lucide-user"
placeholder="Select user" placeholder="Select user"
@@ -23,7 +25,7 @@ const { data: users, status } = await useFetch('https://jsonplaceholder.typicode
<UAvatar <UAvatar
v-if="modelValue" v-if="modelValue"
v-bind="modelValue.avatar" v-bind="modelValue.avatar"
:size="ui.leadingAvatarSize()" :size="(ui.leadingAvatarSize() as AvatarProps['size'])"
:class="ui.leadingAvatar()" :class="ui.leadingAvatar()"
/> />
</template> </template>

View File

@@ -1,4 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import type { AvatarProps } from '@nuxt/ui'
const { data: users, status } = await useFetch('https://jsonplaceholder.typicode.com/users', { const { data: users, status } = await useFetch('https://jsonplaceholder.typicode.com/users', {
key: 'typicode-users-email', key: 'typicode-users-email',
transform: (data: { id: number, name: string, email: string }[]) => { transform: (data: { id: number, name: string, email: string }[]) => {
@@ -7,7 +9,7 @@ const { data: users, status } = await useFetch('https://jsonplaceholder.typicode
email: user.email, email: user.email,
value: String(user.id), value: String(user.id),
avatar: { src: `https://i.pravatar.cc/120?img=${user.id}` } avatar: { src: `https://i.pravatar.cc/120?img=${user.id}` }
})) || [] }))
}, },
lazy: true lazy: true
}) })
@@ -15,7 +17,7 @@ const { data: users, status } = await useFetch('https://jsonplaceholder.typicode
<template> <template>
<UInputMenu <UInputMenu
:items="users || []" :items="users"
:loading="status === 'pending'" :loading="status === 'pending'"
:filter-fields="['label', 'email']" :filter-fields="['label', 'email']"
icon="i-lucide-user" icon="i-lucide-user"
@@ -26,7 +28,7 @@ const { data: users, status } = await useFetch('https://jsonplaceholder.typicode
<UAvatar <UAvatar
v-if="modelValue" v-if="modelValue"
v-bind="modelValue.avatar" v-bind="modelValue.avatar"
:size="ui.leadingAvatarSize()" :size="(ui.leadingAvatarSize() as AvatarProps['size'])"
:class="ui.leadingAvatar()" :class="ui.leadingAvatar()"
/> />
</template> </template>

View File

@@ -1,4 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import type { AvatarProps } from '@nuxt/ui'
const searchTerm = ref('') const searchTerm = ref('')
const searchTermDebounced = refDebounced(searchTerm, 200) const searchTermDebounced = refDebounced(searchTerm, 200)
@@ -10,7 +12,7 @@ const { data: users, status } = await useFetch('https://jsonplaceholder.typicode
label: user.name, label: user.name,
value: String(user.id), value: String(user.id),
avatar: { src: `https://i.pravatar.cc/120?img=${user.id}` } avatar: { src: `https://i.pravatar.cc/120?img=${user.id}` }
})) || [] }))
}, },
lazy: true lazy: true
}) })
@@ -19,7 +21,7 @@ const { data: users, status } = await useFetch('https://jsonplaceholder.typicode
<template> <template>
<UInputMenu <UInputMenu
v-model:search-term="searchTerm" v-model:search-term="searchTerm"
:items="users || []" :items="users"
:loading="status === 'pending'" :loading="status === 'pending'"
ignore-filter ignore-filter
icon="i-lucide-user" icon="i-lucide-user"
@@ -29,7 +31,7 @@ const { data: users, status } = await useFetch('https://jsonplaceholder.typicode
<UAvatar <UAvatar
v-if="modelValue" v-if="modelValue"
v-bind="modelValue.avatar" v-bind="modelValue.avatar"
:size="ui.leadingAvatarSize()" :size="(ui.leadingAvatarSize() as AvatarProps['size'])"
:class="ui.leadingAvatar()" :class="ui.leadingAvatar()"
/> />
</template> </template>

View File

@@ -1,4 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import type { InputMenuItem } from '@nuxt/ui'
const items = ref([ const items = ref([
{ {
label: 'benjamincanac', label: 'benjamincanac',
@@ -23,8 +25,16 @@ const items = ref([
src: 'https://github.com/noook.png', src: 'https://github.com/noook.png',
alt: 'noook' alt: 'noook'
} }
},
{
label: 'sandros94',
value: 'sandros94',
avatar: {
src: 'https://github.com/sandros94.png',
alt: 'sandros94'
}
} }
]) ] satisfies InputMenuItem[])
const value = ref(items.value[0]) const value = ref(items.value[0])
</script> </script>

View File

@@ -1,27 +1,30 @@
<script setup lang="ts"> <script setup lang="ts">
import type { InputMenuItem, ChipProps } from '@nuxt/ui'
const items = ref([ const items = ref([
{ {
label: 'bug', label: 'bug',
value: 'bug', value: 'bug',
chip: { chip: {
color: 'error' as const color: 'error'
} }
}, },
{ {
label: 'feature', label: 'feature',
value: 'feature', value: 'feature',
chip: { chip: {
color: 'success' as const color: 'success'
} }
}, },
{ {
label: 'enhancement', label: 'enhancement',
value: 'enhancement', value: 'enhancement',
chip: { chip: {
color: 'info' as const color: 'info'
} }
} }
]) ] satisfies InputMenuItem[])
const value = ref(items.value[0]) const value = ref(items.value[0])
</script> </script>
@@ -33,7 +36,7 @@ const value = ref(items.value[0])
v-bind="modelValue.chip" v-bind="modelValue.chip"
inset inset
standalone standalone
:size="ui.itemLeadingChipSize()" :size="(ui.itemLeadingChipSize() as ChipProps['size'])"
:class="ui.itemLeadingChip()" :class="ui.itemLeadingChip()"
/> />
</template> </template>

View File

@@ -1,4 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import type { InputMenuItem } from '@nuxt/ui'
const items = ref([ const items = ref([
{ {
label: 'Backlog', label: 'Backlog',
@@ -20,7 +22,8 @@ const items = ref([
value: 'done', value: 'done',
icon: 'i-lucide-circle-check' icon: 'i-lucide-circle-check'
} }
]) ] satisfies InputMenuItem[])
const value = ref(items.value[0]) const value = ref(items.value[0])
</script> </script>

View File

@@ -1,9 +1,11 @@
<script setup lang="ts"> <script setup lang="ts">
import type { NavigationMenuItem } from '@nuxt/ui'
const items = [ const items = [
{ {
label: 'Docs', label: 'Docs',
icon: 'i-lucide-book-open', icon: 'i-lucide-book-open',
slot: 'docs', slot: 'docs' as const,
children: [ children: [
{ {
label: 'Icons', label: 'Icons',
@@ -22,7 +24,7 @@ const items = [
{ {
label: 'Components', label: 'Components',
icon: 'i-lucide-box', icon: 'i-lucide-box',
slot: 'components', slot: 'components' as const,
children: [ children: [
{ {
label: 'Link', label: 'Link',
@@ -54,7 +56,7 @@ const items = [
label: 'GitHub', label: 'GitHub',
icon: 'i-simple-icons-github' icon: 'i-simple-icons-github'
} }
] ] satisfies NavigationMenuItem[]
</script> </script>
<template> <template>

View File

@@ -1,5 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
const items = [ import type { NavigationMenuItem } from '@nuxt/ui'
const items: NavigationMenuItem[] = [
{ {
label: 'Guide', label: 'Guide',
icon: 'i-lucide-book-open' icon: 'i-lucide-book-open'

View File

@@ -1,5 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
const items = [ import type { NavigationMenuItem } from '@nuxt/ui'
const items: NavigationMenuItem[] = [
{ {
label: 'Guide', label: 'Guide',
icon: 'i-lucide-book-open', icon: 'i-lucide-book-open',

View File

@@ -4,8 +4,7 @@ const { data: countries, status, execute } = await useLazyFetch<{
code: string code: string
emoji: string emoji: string
}[]>('/api/countries.json', { }[]>('/api/countries.json', {
immediate: false, immediate: false
default: () => []
}) })
function onOpen() { function onOpen() {

View File

@@ -1,4 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import type { AvatarProps } from '@nuxt/ui'
const { data: users, status } = await useFetch('https://jsonplaceholder.typicode.com/users', { const { data: users, status } = await useFetch('https://jsonplaceholder.typicode.com/users', {
key: 'typicode-users', key: 'typicode-users',
transform: (data: { id: number, name: string }[]) => { transform: (data: { id: number, name: string }[]) => {
@@ -6,7 +8,7 @@ const { data: users, status } = await useFetch('https://jsonplaceholder.typicode
label: user.name, label: user.name,
value: String(user.id), value: String(user.id),
avatar: { src: `https://i.pravatar.cc/120?img=${user.id}` } avatar: { src: `https://i.pravatar.cc/120?img=${user.id}` }
})) || [] }))
}, },
lazy: true lazy: true
}) })
@@ -14,7 +16,7 @@ const { data: users, status } = await useFetch('https://jsonplaceholder.typicode
<template> <template>
<USelectMenu <USelectMenu
:items="users || []" :items="users"
:loading="status === 'pending'" :loading="status === 'pending'"
icon="i-lucide-user" icon="i-lucide-user"
placeholder="Select user" placeholder="Select user"
@@ -24,7 +26,7 @@ const { data: users, status } = await useFetch('https://jsonplaceholder.typicode
<UAvatar <UAvatar
v-if="modelValue" v-if="modelValue"
v-bind="modelValue.avatar" v-bind="modelValue.avatar"
:size="ui.leadingAvatarSize()" :size="(ui.leadingAvatarSize() as AvatarProps['size'])"
:class="ui.leadingAvatar()" :class="ui.leadingAvatar()"
/> />
</template> </template>

View File

@@ -1,4 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import type { AvatarProps } from '@nuxt/ui'
const { data: users, status } = await useFetch('https://jsonplaceholder.typicode.com/users', { const { data: users, status } = await useFetch('https://jsonplaceholder.typicode.com/users', {
key: 'typicode-users-email', key: 'typicode-users-email',
transform: (data: { id: number, name: string, email: string }[]) => { transform: (data: { id: number, name: string, email: string }[]) => {
@@ -7,7 +9,7 @@ const { data: users, status } = await useFetch('https://jsonplaceholder.typicode
email: user.email, email: user.email,
value: String(user.id), value: String(user.id),
avatar: { src: `https://i.pravatar.cc/120?img=${user.id}` } avatar: { src: `https://i.pravatar.cc/120?img=${user.id}` }
})) || [] }))
}, },
lazy: true lazy: true
}) })
@@ -15,7 +17,7 @@ const { data: users, status } = await useFetch('https://jsonplaceholder.typicode
<template> <template>
<USelectMenu <USelectMenu
:items="users || []" :items="users"
:loading="status === 'pending'" :loading="status === 'pending'"
:filter-fields="['label', 'email']" :filter-fields="['label', 'email']"
icon="i-lucide-user" icon="i-lucide-user"
@@ -26,7 +28,7 @@ const { data: users, status } = await useFetch('https://jsonplaceholder.typicode
<UAvatar <UAvatar
v-if="modelValue" v-if="modelValue"
v-bind="modelValue.avatar" v-bind="modelValue.avatar"
:size="ui.leadingAvatarSize()" :size="(ui.leadingAvatarSize() as AvatarProps['size'])"
:class="ui.leadingAvatar()" :class="ui.leadingAvatar()"
/> />
</template> </template>

View File

@@ -1,4 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import type { AvatarProps } from '@nuxt/ui'
const searchTerm = ref('') const searchTerm = ref('')
const searchTermDebounced = refDebounced(searchTerm, 200) const searchTermDebounced = refDebounced(searchTerm, 200)
@@ -10,7 +12,7 @@ const { data: users, status } = await useFetch('https://jsonplaceholder.typicode
label: user.name, label: user.name,
value: String(user.id), value: String(user.id),
avatar: { src: `https://i.pravatar.cc/120?img=${user.id}` } avatar: { src: `https://i.pravatar.cc/120?img=${user.id}` }
})) || [] }))
}, },
lazy: true lazy: true
}) })
@@ -19,7 +21,7 @@ const { data: users, status } = await useFetch('https://jsonplaceholder.typicode
<template> <template>
<USelectMenu <USelectMenu
v-model:search-term="searchTerm" v-model:search-term="searchTerm"
:items="users || []" :items="users"
:loading="status === 'pending'" :loading="status === 'pending'"
ignore-filter ignore-filter
icon="i-lucide-user" icon="i-lucide-user"
@@ -30,7 +32,7 @@ const { data: users, status } = await useFetch('https://jsonplaceholder.typicode
<UAvatar <UAvatar
v-if="modelValue" v-if="modelValue"
v-bind="modelValue.avatar" v-bind="modelValue.avatar"
:size="ui.leadingAvatarSize()" :size="(ui.leadingAvatarSize() as AvatarProps['size'])"
:class="ui.leadingAvatar()" :class="ui.leadingAvatar()"
/> />
</template> </template>

View File

@@ -1,4 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import type { SelectMenuItem } from '@nuxt/ui'
const items = ref([ const items = ref([
{ {
label: 'benjamincanac', label: 'benjamincanac',
@@ -23,8 +25,16 @@ const items = ref([
src: 'https://github.com/noook.png', src: 'https://github.com/noook.png',
alt: 'noook' alt: 'noook'
} }
},
{
label: 'sandros94',
value: 'sandros94',
avatar: {
src: 'https://github.com/sandros94.png',
alt: 'sandros94'
}
} }
]) ] satisfies SelectMenuItem[])
const value = ref(items.value[0]) const value = ref(items.value[0])
</script> </script>

View File

@@ -1,27 +1,29 @@
<script setup lang="ts"> <script setup lang="ts">
import type { SelectMenuItem, ChipProps } from '@nuxt/ui'
const items = ref([ const items = ref([
{ {
label: 'bug', label: 'bug',
value: 'bug', value: 'bug',
chip: { chip: {
color: 'error' as const color: 'error'
} }
}, },
{ {
label: 'feature', label: 'feature',
value: 'feature', value: 'feature',
chip: { chip: {
color: 'success' as const color: 'success'
} }
}, },
{ {
label: 'enhancement', label: 'enhancement',
value: 'enhancement', value: 'enhancement',
chip: { chip: {
color: 'info' as const color: 'info'
} }
} }
]) ] satisfies SelectMenuItem[])
const value = ref(items.value[0]) const value = ref(items.value[0])
</script> </script>
@@ -33,7 +35,7 @@ const value = ref(items.value[0])
v-bind="modelValue.chip" v-bind="modelValue.chip"
inset inset
standalone standalone
:size="ui.itemLeadingChipSize()" :size="(ui.itemLeadingChipSize() as ChipProps['size'])"
:class="ui.itemLeadingChip()" :class="ui.itemLeadingChip()"
/> />
</template> </template>

View File

@@ -1,4 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import type { SelectMenuItem } from '@nuxt/ui'
const items = ref([ const items = ref([
{ {
label: 'Backlog', label: 'Backlog',
@@ -20,7 +22,7 @@ const items = ref([
value: 'done', value: 'done',
icon: 'i-lucide-circle-check' icon: 'i-lucide-circle-check'
} }
]) ] satisfies SelectMenuItem[])
const value = ref(items.value[0]) const value = ref(items.value[0])
</script> </script>

View File

@@ -1,4 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import type { AvatarProps } from '@nuxt/ui'
const { data: users, status } = await useFetch('https://jsonplaceholder.typicode.com/users', { const { data: users, status } = await useFetch('https://jsonplaceholder.typicode.com/users', {
key: 'typicode-users', key: 'typicode-users',
transform: (data: { id: number, name: string }[]) => { transform: (data: { id: number, name: string }[]) => {
@@ -6,7 +8,7 @@ const { data: users, status } = await useFetch('https://jsonplaceholder.typicode
label: user.name, label: user.name,
value: String(user.id), value: String(user.id),
avatar: { src: `https://i.pravatar.cc/120?img=${user.id}` } avatar: { src: `https://i.pravatar.cc/120?img=${user.id}` }
})) || [] }))
}, },
lazy: true lazy: true
}) })
@@ -18,17 +20,18 @@ function getUserAvatar(value: string) {
<template> <template>
<USelect <USelect
:items="users || []" :items="users"
:loading="status === 'pending'" :loading="status === 'pending'"
icon="i-lucide-user" icon="i-lucide-user"
placeholder="Select user" placeholder="Select user"
class="w-48" class="w-48"
value-key="value"
> >
<template #leading="{ modelValue, ui }"> <template #leading="{ modelValue, ui }">
<UAvatar <UAvatar
v-if="modelValue" v-if="modelValue"
v-bind="getUserAvatar(modelValue as string)" v-bind="getUserAvatar(modelValue)"
:size="ui.leadingAvatarSize()" :size="(ui.leadingAvatarSize() as AvatarProps['size'])"
:class="ui.leadingAvatar()" :class="ui.leadingAvatar()"
/> />
</template> </template>

View File

@@ -1,4 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import type { SelectItem } from '@nuxt/ui'
const items = ref([ const items = ref([
{ {
label: 'benjamincanac', label: 'benjamincanac',
@@ -23,13 +25,21 @@ const items = ref([
src: 'https://github.com/noook.png', src: 'https://github.com/noook.png',
alt: 'noook' 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 value = ref(items.value[0]?.value)
const avatar = computed(() => items.value.find(item => item.value === value.value)?.avatar) const avatar = computed(() => items.value.find(item => item.value === value.value)?.avatar)
</script> </script>
<template> <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> </template>

View File

@@ -1,27 +1,30 @@
<script setup lang="ts"> <script setup lang="ts">
import type { SelectItem, ChipProps } from '@nuxt/ui'
const items = ref([ const items = ref([
{ {
label: 'bug', label: 'bug',
value: 'bug', value: 'bug',
chip: { chip: {
color: 'error' as const color: 'error'
} }
}, },
{ {
label: 'feature', label: 'feature',
value: 'feature', value: 'feature',
chip: { chip: {
color: 'success' as const color: 'success'
} }
}, },
{ {
label: 'enhancement', label: 'enhancement',
value: 'enhancement', value: 'enhancement',
chip: { chip: {
color: 'info' as const color: 'info'
} }
} }
]) ] satisfies SelectItem[])
const value = ref(items.value[0]?.value) const value = ref(items.value[0]?.value)
function getChip(value: string) { function getChip(value: string) {
@@ -30,14 +33,14 @@ function getChip(value: string) {
</script> </script>
<template> <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 }"> <template #leading="{ modelValue, ui }">
<UChip <UChip
v-if="modelValue" v-if="modelValue"
v-bind="getChip(modelValue as string)" v-bind="getChip(modelValue)"
inset inset
standalone standalone
:size="ui.itemLeadingChipSize()" :size="(ui.itemLeadingChipSize() as ChipProps['size'])"
:class="ui.itemLeadingChip()" :class="ui.itemLeadingChip()"
/> />
</template> </template>

View File

@@ -1,4 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import type { SelectItem } from '@nuxt/ui'
const items = ref([ const items = ref([
{ {
label: 'Backlog', label: 'Backlog',
@@ -20,12 +22,12 @@ const items = ref([
value: 'done', value: 'done',
icon: 'i-lucide-circle-check' icon: 'i-lucide-circle-check'
} }
]) ] satisfies SelectItem[])
const value = ref(items.value[0]?.value) const value = ref(items.value[0]?.value)
const icon = computed(() => items.value.find(item => item.value === value.value)?.icon) const icon = computed(() => items.value.find(item => item.value === value.value)?.icon)
</script> </script>
<template> <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> </template>

View File

@@ -1,5 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
const items = [ import type { StepperItem } from '@nuxt/ui'
const items: StepperItem[] = [
{ {
title: 'Address', title: 'Address',
description: 'Add your address here', description: 'Add your address here',

View File

@@ -1,5 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
const items = [ import type { StepperItem } from '@nuxt/ui'
const items: StepperItem[] = [
{ {
slot: 'address', slot: 'address',
title: 'Address', title: 'Address',

View File

@@ -1,7 +1,8 @@
<script setup lang="ts"> <script setup lang="ts">
import type { StepperItem } from '@nuxt/ui'
import { onMounted, ref } from 'vue' import { onMounted, ref } from 'vue'
const items = [ const items: StepperItem[] = [
{ {
title: 'Address', title: 'Address',
description: 'Add your address here', description: 'Add your address here',

View File

@@ -1,5 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
const items = [ import type { StepperItem } from '@nuxt/ui'
const items: StepperItem[] = [
{ {
slot: 'address', slot: 'address',
title: 'Address', title: 'Address',

View File

@@ -97,10 +97,11 @@ function getHeader(column: Column<Payment>, label: string) {
const isSorted = column.getIsSorted() const isSorted = column.getIsSorted()
return h(UDropdownMenu, { return h(UDropdownMenu, {
content: { 'content': {
align: 'start' align: 'start'
}, },
items: [{ 'aria-label': 'Actions dropdown',
'items': [{
label: 'Asc', label: 'Asc',
type: 'checkbox', type: 'checkbox',
icon: 'i-lucide-arrow-up-narrow-wide', icon: 'i-lucide-arrow-up-narrow-wide',
@@ -126,11 +127,12 @@ function getHeader(column: Column<Payment>, label: string) {
} }
}] }]
}, () => h(UButton, { }, () => h(UButton, {
color: 'neutral', 'color': 'neutral',
variant: 'ghost', 'variant': 'ghost',
label, label,
icon: isSorted ? (isSorted === 'asc' ? 'i-lucide-arrow-up-narrow-wide' : 'i-lucide-arrow-down-wide-narrow') : 'i-lucide-arrow-up-down', '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)' 'class': '-mx-2.5 data-[state=open]:bg-(--ui-bg-elevated)',
'aria-label': `Sort by ${isSorted === 'asc' ? 'descending' : 'ascending'}`
})) }))
} }

View File

@@ -145,12 +145,12 @@ const columns: TableColumn<Payment>[] = [{
header: ({ table }) => h(UCheckbox, { header: ({ table }) => h(UCheckbox, {
'modelValue': table.getIsSomePageRowsSelected() ? 'indeterminate' : table.getIsAllPageRowsSelected(), 'modelValue': table.getIsSomePageRowsSelected() ? 'indeterminate' : table.getIsAllPageRowsSelected(),
'onUpdate:modelValue': (value: boolean | 'indeterminate') => table.toggleAllPageRowsSelected(!!value), 'onUpdate:modelValue': (value: boolean | 'indeterminate') => table.toggleAllPageRowsSelected(!!value),
'ariaLabel': 'Select all' 'aria-label': 'Select all'
}), }),
cell: ({ row }) => h(UCheckbox, { cell: ({ row }) => h(UCheckbox, {
'modelValue': row.getIsSelected(), 'modelValue': row.getIsSelected(),
'onUpdate:modelValue': (value: boolean | 'indeterminate') => row.toggleSelected(!!value), 'onUpdate:modelValue': (value: boolean | 'indeterminate') => row.toggleSelected(!!value),
'ariaLabel': 'Select row' 'aria-label': 'Select row'
}), }),
enableSorting: false, enableSorting: false,
enableHiding: false enableHiding: false
@@ -242,15 +242,17 @@ const columns: TableColumn<Payment>[] = [{
}] }]
return h('div', { class: 'text-right' }, h(UDropdownMenu, { return h('div', { class: 'text-right' }, h(UDropdownMenu, {
content: { 'content': {
align: 'end' align: 'end'
}, },
items items,
'aria-label': 'Actions dropdown'
}, () => h(UButton, { }, () => h(UButton, {
icon: 'i-lucide-ellipsis-vertical', 'icon': 'i-lucide-ellipsis-vertical',
color: 'neutral', 'color': 'neutral',
variant: 'ghost', 'variant': 'ghost',
class: 'ml-auto' 'class': 'ml-auto',
'aria-label': 'Actions dropdown'
}))) })))
} }
}] }]
@@ -294,6 +296,7 @@ function randomize() {
variant="outline" variant="outline"
trailing-icon="i-lucide-chevron-down" trailing-icon="i-lucide-chevron-down"
class="ml-auto" class="ml-auto"
aria-label="Columns select dropdown"
/> />
</UDropdownMenu> </UDropdownMenu>
</div> </div>

View File

@@ -17,7 +17,7 @@ const { data, status } = await useFetch<User[]>('https://jsonplaceholder.typicod
transform: (data) => { transform: (data) => {
return data?.map(user => ({ return data?.map(user => ({
...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 lazy: true

View File

@@ -97,15 +97,17 @@ const columns: TableColumn<Payment>[] = [{
id: 'actions', id: 'actions',
cell: ({ row }) => { cell: ({ row }) => {
return h('div', { class: 'text-right' }, h(UDropdownMenu, { return h('div', { class: 'text-right' }, h(UDropdownMenu, {
content: { 'content': {
align: 'end' align: 'end'
}, },
items: getRowItems(row) 'items': getRowItems(row),
'aria-label': 'Actions dropdown'
}, () => h(UButton, { }, () => h(UButton, {
icon: 'i-lucide-ellipsis-vertical', 'icon': 'i-lucide-ellipsis-vertical',
color: 'neutral', 'color': 'neutral',
variant: 'ghost', 'variant': 'ghost',
class: 'ml-auto' 'class': 'ml-auto',
'aria-label': 'Actions dropdown'
}))) })))
} }
}] }]

View File

@@ -48,14 +48,15 @@ const data = ref<Payment[]>([{
const columns: TableColumn<Payment>[] = [{ const columns: TableColumn<Payment>[] = [{
id: 'expand', id: 'expand',
cell: ({ row }) => h(UButton, { cell: ({ row }) => h(UButton, {
color: 'neutral', 'color': 'neutral',
variant: 'ghost', 'variant': 'ghost',
icon: 'i-lucide-chevron-down', 'icon': 'i-lucide-chevron-down',
square: true, 'square': true,
ui: { 'aria-label': 'Expand',
'ui': {
leadingIcon: ['transition-transform', row.getIsExpanded() ? 'duration-200 rotate-180' : ''] leadingIcon: ['transition-transform', row.getIsExpanded() ? 'duration-200 rotate-180' : '']
}, },
onClick: () => row.toggleExpanded() 'onClick': () => row.toggleExpanded()
}) })
}, { }, {
accessorKey: 'id', accessorKey: 'id',

View File

@@ -50,12 +50,12 @@ const columns: TableColumn<Payment>[] = [{
header: ({ table }) => h(UCheckbox, { header: ({ table }) => h(UCheckbox, {
'modelValue': table.getIsSomePageRowsSelected() ? 'indeterminate' : table.getIsAllPageRowsSelected(), 'modelValue': table.getIsSomePageRowsSelected() ? 'indeterminate' : table.getIsAllPageRowsSelected(),
'onUpdate:modelValue': (value: boolean | 'indeterminate') => table.toggleAllPageRowsSelected(!!value), 'onUpdate:modelValue': (value: boolean | 'indeterminate') => table.toggleAllPageRowsSelected(!!value),
'ariaLabel': 'Select all' 'aria-label': 'Select all'
}), }),
cell: ({ row }) => h(UCheckbox, { cell: ({ row }) => h(UCheckbox, {
'modelValue': row.getIsSelected(), 'modelValue': row.getIsSelected(),
'onUpdate:modelValue': (value: boolean | 'indeterminate') => row.toggleSelected(!!value), 'onUpdate:modelValue': (value: boolean | 'indeterminate') => row.toggleSelected(!!value),
'ariaLabel': 'Select row' 'aria-label': 'Select row'
}) })
}, { }, {
accessorKey: 'date', accessorKey: 'date',

View File

@@ -50,12 +50,12 @@ const columns: TableColumn<Payment>[] = [{
header: ({ table }) => h(UCheckbox, { header: ({ table }) => h(UCheckbox, {
'modelValue': table.getIsSomePageRowsSelected() ? 'indeterminate' : table.getIsAllPageRowsSelected(), 'modelValue': table.getIsSomePageRowsSelected() ? 'indeterminate' : table.getIsAllPageRowsSelected(),
'onUpdate:modelValue': (value: boolean | 'indeterminate') => table.toggleAllPageRowsSelected(!!value), 'onUpdate:modelValue': (value: boolean | 'indeterminate') => table.toggleAllPageRowsSelected(!!value),
'ariaLabel': 'Select all' 'aria-label': 'Select all'
}), }),
cell: ({ row }) => h(UCheckbox, { cell: ({ row }) => h(UCheckbox, {
'modelValue': row.getIsSelected(), 'modelValue': row.getIsSelected(),
'onUpdate:modelValue': (value: boolean | 'indeterminate') => row.toggleSelected(!!value), 'onUpdate:modelValue': (value: boolean | 'indeterminate') => row.toggleSelected(!!value),
'ariaLabel': 'Select row' 'aria-label': 'Select row'
}) })
}, { }, {
accessorKey: 'date', accessorKey: 'date',

View File

@@ -95,7 +95,7 @@ function getDropdownActions(user: User): DropdownMenuItem[][] {
<UTable :data="data" :columns="columns" class="flex-1"> <UTable :data="data" :columns="columns" class="flex-1">
<template #name-cell="{ row }"> <template #name-cell="{ row }">
<div class="flex items-center gap-3"> <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> <div>
<p class="font-medium text-(--ui-text-highlighted)"> <p class="font-medium text-(--ui-text-highlighted)">
{{ row.original.name }} {{ row.original.name }}
@@ -108,7 +108,7 @@ function getDropdownActions(user: User): DropdownMenuItem[][] {
</template> </template>
<template #action-cell="{ row }"> <template #action-cell="{ row }">
<UDropdownMenu :items="getDropdownActions(row.original)"> <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> </UDropdownMenu>
</template> </template>
</UTable> </UTable>

View File

@@ -1,5 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
const items = [ import type { TabsItem } from '@nuxt/ui'
const items: TabsItem[] = [
{ {
label: 'Account', label: 'Account',
icon: 'i-lucide-user' icon: 'i-lucide-user'

View File

@@ -1,18 +1,20 @@
<script setup lang="ts"> <script setup lang="ts">
import type { TabsItem } from '@nuxt/ui'
const items = [ const items = [
{ {
label: 'Account', label: 'Account',
description: 'Make changes to your account here. Click save when you\'re done.', description: 'Make changes to your account here. Click save when you\'re done.',
icon: 'i-lucide-user', icon: 'i-lucide-user',
slot: 'account' slot: 'account' as const
}, },
{ {
label: 'Password', label: 'Password',
description: 'Change your password here. After saving, you\'ll be logged out.', description: 'Change your password here. After saving, you\'ll be logged out.',
icon: 'i-lucide-lock', icon: 'i-lucide-lock',
slot: 'password' slot: 'password' as const
} }
] ] satisfies TabsItem[]
const state = reactive({ const state = reactive({
name: 'Benjamin Canac', name: 'Benjamin Canac',

View File

@@ -1,5 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
const items = [ import type { TabsItem } from '@nuxt/ui'
const items: TabsItem[] = [
{ {
label: 'Account' label: 'Account'
}, },

View File

@@ -1,10 +1,10 @@
<script setup lang="ts"> <script setup lang="ts">
import type { TreeItem } from '@nuxt/ui' import type { TreeItem } from '@nuxt/ui'
const items: TreeItem[] = [ const items = [
{ {
label: 'app/', label: 'app/',
slot: 'app', slot: 'app' as const,
defaultExpanded: true, defaultExpanded: true,
children: [{ children: [{
label: 'composables/', label: 'composables/',
@@ -24,7 +24,7 @@ const items: TreeItem[] = [
}, },
{ label: 'app.vue', icon: 'i-vscode-icons-file-type-vue' }, { label: 'app.vue', icon: 'i-vscode-icons-file-type-vue' },
{ label: 'nuxt.config.ts', icon: 'i-vscode-icons-file-type-nuxt' } { label: 'nuxt.config.ts', icon: 'i-vscode-icons-file-type-nuxt' }
] ] satisfies TreeItem[]
</script> </script>
<template> <template>

View File

@@ -25,7 +25,7 @@ const items: TreeItem[] = [
{ label: 'nuxt.config.ts', icon: 'i-vscode-icons-file-type-nuxt' } { label: 'nuxt.config.ts', icon: 'i-vscode-icons-file-type-nuxt' }
] ]
const value = ref(items[items.length - 1]) const value = ref()
</script> </script>
<template> <template>

View File

@@ -3,7 +3,7 @@ withDefaults(defineProps<{
title: string title: string
description: string description: string
component: string component: string
module: string module?: string
}>(), { }>(), {
module: '' module: ''
}) })

View File

@@ -3,8 +3,8 @@ withDefaults(defineProps<{
title: string title: string
description: string description: string
headline: string headline: string
framework: string framework?: string
module: string module?: string
}>(), { }>(), {
framework: 'nuxt', framework: 'nuxt',
module: '' module: ''

View File

@@ -81,7 +81,6 @@ function setBlackAsPrimary(value: boolean) {
<div class="grid grid-cols-3 gap-1 -mx-2"> <div class="grid grid-cols-3 gap-1 -mx-2">
<ThemePickerButton <ThemePickerButton
chip="primary"
label="Black" label="Black"
:selected="appConfig.theme.blackAsPrimary" :selected="appConfig.theme.blackAsPrimary"
@click="setBlackAsPrimary(true)" @click="setBlackAsPrimary(true)"
@@ -90,6 +89,7 @@ function setBlackAsPrimary(value: boolean) {
<span class="inline-block w-2 h-2 rounded-full bg-black dark:bg-white" /> <span class="inline-block w-2 h-2 rounded-full bg-black dark:bg-white" />
</template> </template>
</ThemePickerButton> </ThemePickerButton>
<ThemePickerButton <ThemePickerButton
v-for="color in primaryColors" v-for="color in primaryColors"
:key="color" :key="color"

View File

@@ -5,6 +5,10 @@ defineProps<{
chip?: string chip?: string
selected?: boolean selected?: boolean
}>() }>()
const slots = defineSlots<{
leading: () => any
}>()
</script> </script>
<template> <template>
@@ -17,7 +21,7 @@ defineProps<{
class="capitalize ring-(--ui-border) rounded-[calc(var(--ui-radius))] text-[11px]" class="capitalize ring-(--ui-border) rounded-[calc(var(--ui-radius))] text-[11px]"
:class="[selected ? 'bg-(--ui-bg-elevated)' : 'hover:bg-(--ui-bg-elevated)/50']" :class="[selected ? 'bg-(--ui-bg-elevated)' : 'hover:bg-(--ui-bg-elevated)/50']"
> >
<template v-if="chip" #leading> <template v-if="chip || !!slots.leading" #leading>
<slot name="leading"> <slot name="leading">
<span <span
class="inline-block size-2 rounded-full" class="inline-block size-2 rounded-full"

View File

@@ -1,6 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import colors from 'tailwindcss/colors' import colors from 'tailwindcss/colors'
// import { debounce } from 'perfect-debounce'
import type { NuxtError } from '#app' import type { NuxtError } from '#app'
const props = defineProps<{ const props = defineProps<{
@@ -15,16 +14,6 @@ const { data: files } = useLazyAsyncData('search', () => queryCollectionSearchSe
server: false server: false
}) })
const searchTerm = ref('')
// watch(searchTerm, debounce((query: string) => {
// if (!query) {
// return
// }
// useTrackEvent('Search', { props: { query: `${query} - ${searchTerm.value?.commandPaletteRef.results.length} results` } })
// }, 500))
const links = useLinks() const links = useLinks()
const color = computed(() => colorMode.value === 'dark' ? (colors as any)[appConfig.ui.colors.neutral][900] : 'white') 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 radius = computed(() => `:root { --ui-radius: ${appConfig.theme.radius}rem; }`)
@@ -48,7 +37,7 @@ useHead({
}) })
useSeoMeta({ useSeoMeta({
titleTemplate: '%s - Nuxt UI v3', titleTemplate: '%s - Nuxt UI',
title: String(props.error.statusCode) title: String(props.error.statusCode)
}) })
@@ -67,17 +56,16 @@ provide('navigation', mappedNavigation)
<UApp> <UApp>
<NuxtLoadingIndicator color="#FFF" /> <NuxtLoadingIndicator color="#FFF" />
<!-- <Banner /> --> <Banner />
<Header :links="links" /> <Header :links="links" />
<UError :error="error" /> <UError :error="error" />
<!-- <Footer /> --> <Footer />
<ClientOnly> <ClientOnly>
<LazyUContentSearch <LazyUContentSearch
v-model:search-term="searchTerm"
:files="files" :files="files"
:groups="[{ :groups="[{
id: 'framework', id: 'framework',

View File

@@ -97,7 +97,7 @@ design_system:
``` ```
```css [main.css] ```css [main.css]
@import "tailwindcss" theme(static); @import "tailwindcss";
@import "@nuxt/ui"; @import "@nuxt/ui";
:root { :root {

View File

@@ -1,7 +1,8 @@
<script setup lang="ts"> <script setup lang="ts">
import { kebabCase } from 'scule' import { kebabCase } from 'scule'
import type { ContentNavigationItem } from '@nuxt/content' 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 route = useRoute()
const { framework, module } = useSharedData() const { framework, module } = useSharedData()
@@ -82,6 +83,8 @@ if (route.path.startsWith('/components')) {
}) })
} else { } else {
defineOgImageComponent('Docs', { defineOgImageComponent('Docs', {
title: page.value.title,
description: page.value.description,
headline: breadcrumb.value?.[breadcrumb.value.length - 1]?.label || 'Nuxt UI', headline: breadcrumb.value?.[breadcrumb.value.length - 1]?.label || 'Nuxt UI',
framework: page.value?.framework, framework: page.value?.framework,
module: page.value.module module: page.value.module
@@ -98,6 +101,16 @@ const communityLinks = computed(() => [{
label: 'Star on GitHub', label: 'Star on GitHub',
to: `https://github.com/nuxt/${page.value?.module === 'ui-pro' ? 'ui-pro' : 'ui'}`, to: `https://github.com/nuxt/${page.value?.module === 'ui-pro' ? 'ui-pro' : 'ui'}`,
target: '_blank' 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-life-buoy',
label: 'Contribution', label: 'Contribution',
@@ -106,24 +119,7 @@ const communityLinks = computed(() => [{
label: 'Roadmap', label: 'Roadmap',
icon: 'i-lucide-map', icon: 'i-lucide-map',
to: '/roadmap' to: '/roadmap'
}]) }].filter(Boolean) as PageLink[])
// const resourcesLinks = [{
// icon: 'i-simple-icons-figma',
// label: 'Figma Kit',
// to: 'https://www.figma.com/community/file/1288455405058138934',
// target: '_blank'
// }, {
// label: 'Playground',
// icon: 'i-simple-icons-stackblitz',
// to: 'https://stackblitz.com/edit/nuxt-ui',
// target: '_blank'
// }, {
// icon: 'i-simple-icons-nuxtdotjs',
// label: 'Nuxt docs',
// to: 'https://nuxt.com',
// target: '_blank'
// }]
</script> </script>
<template> <template>
@@ -151,7 +147,7 @@ const communityLinks = computed(() => [{
v-bind="link" v-bind="link"
> >
<template v-if="link.avatar" #leading> <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> </template>
</UButton> </UButton>
</template> </template>
@@ -172,14 +168,9 @@ const communityLinks = computed(() => [{
<UPageLinks title="Community" :links="communityLinks" /> <UPageLinks title="Community" :links="communityLinks" />
<!-- <USeparator type="dashed" />
<UPageLinks title="Resources" :links="resourcesLinks" />
<USeparator type="dashed" /> <USeparator type="dashed" />
<AdsPro /> <AdsCarbon />
<AdsCarbon /> -->
</template> </template>
</UContentToc> </UContentToc>
</template> </template>

View File

@@ -119,7 +119,8 @@ onMounted(() => {
/> />
</template> </template>
<StarsBg /> <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 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" />
</UPageHero> </UPageHero>
@@ -168,6 +169,7 @@ onMounted(() => {
:loading="index >= 4 ? 'lazy' : 'eager'" :loading="index >= 4 ? 'lazy' : 'eager'"
width="640" width="640"
height="360" height="360"
:alt="`${component.name} preview`"
/> />
</div> </div>
</UPageCard> </UPageCard>

View File

@@ -178,6 +178,7 @@ pricing:
- title: Solo License - title: Solo License
description: Design faster with all Nuxt UI Pro components. description: Design faster with all Nuxt UI Pro components.
price: $149 price: $149
# discount: $119
billing_period: one-time payment billing_period: one-time payment
billing_cycle: plus local taxes billing_cycle: plus local taxes
class: bg-(--ui-bg-elevated)/50 class: bg-(--ui-bg-elevated)/50
@@ -199,6 +200,7 @@ pricing:
- title: Team License - title: Team License
description: Everything you need to deliver faster as a team. description: Everything you need to deliver faster as a team.
price: $349 price: $349
# discount: $279
billing_period: one-time payment billing_period: one-time payment
billing_cycle: plus local taxes billing_cycle: plus local taxes
class: bg-(--ui-bg-elevated)/50 class: bg-(--ui-bg-elevated)/50

View File

@@ -1,7 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
// @ts-expect-error yaml is not typed // @ts-expect-error yaml is not typed
import page from '.figma.yml' import page from '.figma.yml'
import { animate } from 'motion' import { animate } from 'motion-v'
import { joinURL } from 'ufo' import { joinURL } from 'ufo'
const { url } = useSiteConfig() const { url } = useSiteConfig()
@@ -233,6 +233,7 @@ onMounted(async () => {
:title="plan.title" :title="plan.title"
:description="plan.description" :description="plan.description"
:price="plan.price" :price="plan.price"
:discount="plan.discount"
:billing-period="plan.billing_period" :billing-period="plan.billing_period"
:billing-cycle="plan.billing_cycle" :billing-cycle="plan.billing_cycle"
:highlight="plan.highlight" :highlight="plan.highlight"

View File

@@ -76,7 +76,7 @@ useIntersectionObserver(contributorsRef, ([entry]) => {
:key="feature.title" :key="feature.title"
as-child as-child
:initial="{ opacity: 0, transform: 'translateX(-10px)' }" :initial="{ opacity: 0, transform: 'translateX(-10px)' }"
:in-view="{ opacity: 1, transform: 'translateX(0)' }" :while-in-view="{ opacity: 1, transform: 'translateX(0)' }"
:transition="{ delay: 0.2 + 0.4 * index }" :transition="{ delay: 0.2 + 0.4 * index }"
:in-view-options="{ once: true }" :in-view-options="{ once: true }"
> >
@@ -85,7 +85,7 @@ useIntersectionObserver(contributorsRef, ([entry]) => {
</div> </div>
</template> </template>
<SkyBg /> <LazySkyBg />
<div class="h-[344px] lg:h-full lg:relative w-full lg:min-h-[calc(100vh-var(--ui-header-height)-1px)] overflow-hidden"> <div class="h-[344px] lg:h-full lg:relative w-full lg:min-h-[calc(100vh-var(--ui-header-height)-1px)] overflow-hidden">
<UPageMarquee <UPageMarquee
@@ -93,7 +93,7 @@ useIntersectionObserver(contributorsRef, ([entry]) => {
:overlay="false" :overlay="false"
:ui="{ :ui="{
root: '[--gap:--spacing(4)] [--duration:40s] border-(--ui-border) absolute w-full left-0 border-y lg:border-x lg:border-y-0 lg:w-[calc(50%-6px)] 2xl:w-[320px] lg:flex-col', root: '[--gap:--spacing(4)] [--duration:40s] border-(--ui-border) absolute w-full left-0 border-y lg:border-x lg:border-y-0 lg:w-[calc(50%-6px)] 2xl:w-[320px] lg:flex-col',
content: 'lg:w-auto lg:h-full lg:flex-col lg:animate-[marquee-vertical_var(--duration)_linear_infinite] lg:rtl:animate-[marquee-vertical-rtl_var(--duration)_linear_infinite] lg:h-[fit-content]' content: 'lg:w-auto lg:flex-col lg:animate-[marquee-vertical_var(--duration)_linear_infinite] lg:rtl:animate-[marquee-vertical-rtl_var(--duration)_linear_infinite] lg:h-[fit-content]'
}" }"
> >
<ULink <ULink
@@ -103,10 +103,14 @@ useIntersectionObserver(contributorsRef, ([entry]) => {
:to="component.path" :to="component.path"
> >
<UColorModeImage <UColorModeImage
:light="`${component.path.replace('/components/', '/components/light/')}.png`" :light="`${component.path.replace('/components/', '/components/light/')}.png`"
:dark="`${component.path.replace('/components/', '/components/dark/')}.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" 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" /> <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> </ULink>
@@ -118,7 +122,7 @@ useIntersectionObserver(contributorsRef, ([entry]) => {
:overlay="false" :overlay="false"
:ui="{ :ui="{
root: '[--gap:--spacing(4)] [--duration:40s] border-(--ui-border) absolute w-full mt-[180px] left-0 border-y lg:mt-auto lg:left-auto lg:border-y-0 lg:border-x lg:w-[calc(50%-6px)] 2xl:w-[320px] lg:right-0 lg:flex-col', root: '[--gap:--spacing(4)] [--duration:40s] border-(--ui-border) absolute w-full mt-[180px] left-0 border-y lg:mt-auto lg:left-auto lg:border-y-0 lg:border-x lg:w-[calc(50%-6px)] 2xl:w-[320px] lg:right-0 lg:flex-col',
content: 'lg:w-auto lg:h-full lg:flex-col lg:animate-[marquee-vertical_var(--duration)_linear_infinite] lg:rtl:animate-[marquee-vertical-rtl_var(--duration)_linear_infinite] lg:h-[fit-content] lg:[animation-direction:reverse]' content: 'lg:w-auto lg:flex-col lg:animate-[marquee-vertical_var(--duration)_linear_infinite] lg:rtl:animate-[marquee-vertical-rtl_var(--duration)_linear_infinite] lg:h-[fit-content] lg:[animation-direction:reverse]'
}" }"
> >
<ULink <ULink
@@ -130,7 +134,12 @@ useIntersectionObserver(contributorsRef, ([entry]) => {
<UColorModeImage <UColorModeImage
:light="`${component.path.replace('/components/', '/components/light/')}.png`" :light="`${component.path.replace('/components/', '/components/light/')}.png`"
:dark="`${component.path.replace('/components/', '/components/dark/')}.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" 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" /> <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> </ULink>
@@ -147,12 +156,14 @@ useIntersectionObserver(contributorsRef, ([entry]) => {
:key="feature.title" :key="feature.title"
as="li" as="li"
:initial="{ opacity: 0, transform: 'translateY(10px)' }" :initial="{ opacity: 0, transform: 'translateY(10px)' }"
:in-view="{ opacity: 1, transform: 'translateY(0)' }" :while-in-view="{ opacity: 1, transform: 'translateY(0)' }"
:transition="{ delay: 0.1 * index }" :transition="{ delay: 0.1 * index }"
:in-view-options="{ once: true }" :in-view-options="{ once: true }"
class="flex items-start gap-x-3 relative group" 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"> <div class="relative p-3">
<svg class="absolute inset-0" viewBox="0 0 44 44" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg class="absolute inset-0" viewBox="0 0 44 44" fill="none" xmlns="http://www.w3.org/2000/svg">
@@ -218,26 +229,32 @@ useIntersectionObserver(contributorsRef, ([entry]) => {
class="border-b border-(--ui-border)" class="border-b border-(--ui-border)"
> >
<template #features> <template #features>
<NuxtLink to="https://npm.chart.dev/@nuxt/ui" target="_blank" class="min-w-0"> <li>
<p class="text-4xl font-semibold text-(--ui-text-highlighted) truncate"> <NuxtLink to="https://npm.chart.dev/@nuxt/ui" target="_blank" class="min-w-0">
{{ format(module?.stats?.downloads ?? 0) }}+ <p class="text-4xl font-semibold text-(--ui-text-highlighted) truncate">
</p> {{ format(module?.stats?.downloads ?? 0) }}+
<p class="text-(--ui-text-muted) text-sm truncate">monthly downloads</p> </p>
</NuxtLink> <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"> <li>
<p class="text-4xl font-semibold text-(--ui-text-highlighted) truncate"> <NuxtLink to="https://github.com/nuxt/ui" target="_blank" class="min-w-0">
{{ format(module?.stats?.stars ?? 0) }}+ <p class="text-4xl font-semibold text-(--ui-text-highlighted) truncate">
</p> {{ format(module?.stats?.stars ?? 0) }}+
<p class="text-(--ui-text-muted) text-sm truncate">GitHub stars</p> </p>
</NuxtLink> <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"> <li>
<p class="text-4xl font-semibold text-(--ui-text-highlighted) truncate"> <NuxtLink to="https://github.com/nuxt/ui/graphs/contributors" target="_blank" class="min-w-0">
175+ <p class="text-4xl font-semibold text-(--ui-text-highlighted) truncate">
</p> 175+
<p class="text-(--ui-text-muted) text-sm truncate">Contributors</p> </p>
</NuxtLink> <p class="text-(--ui-text-muted) text-sm truncate">Contributors</p>
</NuxtLink>
</li>
</template> </template>
<div ref="contributorsRef" class="p-4 sm:px-6 md:px-8 lg:px-12 xl:px-14 overflow-hidden flex relative"> <div ref="contributorsRef" class="p-4 sm:px-6 md:px-8 lg:px-12 xl:px-14 overflow-hidden flex relative">
@@ -261,7 +278,7 @@ useIntersectionObserver(contributorsRef, ([entry]) => {
</UButton> </UButton>
</template> </template>
<StarsBg /> <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 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="relative h-[400px] border border-(--ui-border) bg-(--ui-bg-muted) overflow-hidden border-x-0 -mx-4 sm:-mx-6 lg:mx-0 lg:border-x w-screen lg:w-full"> <div class="relative h-[400px] border border-(--ui-border) bg-(--ui-bg-muted) overflow-hidden border-x-0 -mx-4 sm:-mx-6 lg:mx-0 lg:border-x w-screen lg:w-full">

View File

@@ -17,7 +17,10 @@ pricing:
title: Figma Kit Pro title: Figma Kit Pro
description: Get all Nuxt UI Pro components in a Figma kit to design your next application before coding. Everything you need, from wire-framing to high-fidelity web integration. description: Get all Nuxt UI Pro components in a Figma kit to design your next application before coding. Everything you need, from wire-framing to high-fidelity web integration.
orientation: horizontal orientation: horizontal
price: $149 - $349 price: $149
# discount: $119
billing_period: one-time payment
billing_cycle: plus local taxes
terms: Solo & Team licenses available. terms: Solo & Team licenses available.
features: features:
- 1700+ components & variants from Nuxt UI & UI Pro - 1700+ components & variants from Nuxt UI & UI Pro
@@ -36,6 +39,7 @@ pricing:
- title: Solo - title: Solo
description: Tailored for indie hackers, freelancers and solo founders. description: Tailored for indie hackers, freelancers and solo founders.
price: $249 price: $249
# discount: $199
billing_period: one-time payment billing_period: one-time payment
billing_cycle: plus local taxes billing_cycle: plus local taxes
features: features:
@@ -50,6 +54,7 @@ pricing:
- title: Startup - title: Startup
description: Best suited for small teams, startups and agencies. description: Best suited for small teams, startups and agencies.
price: $499 price: $499
# discount: $399
billing_period: one-time payment billing_period: one-time payment
billing_cycle: plus local taxes billing_cycle: plus local taxes
features: features:
@@ -65,6 +70,7 @@ pricing:
- title: Organization - title: Organization
description: Ideal for larger teams and organizations. description: Ideal for larger teams and organizations.
price: $999 price: $999
# discount: $799
billing_period: one-time payment billing_period: one-time payment
billing_cycle: plus local taxes billing_cycle: plus local taxes
features: features:
@@ -174,7 +180,7 @@ testimonials:
- quote: "Nuxt UI Pro is my preferred choice for everything, from a POC to a web platform. It's ready to use out-of-the-box and assists me in crafting pixel-perfect UIs. It saves me a significant amount of time while remaining highly customizable. Give it a try, and you won't be let down." - quote: "Nuxt UI Pro is my preferred choice for everything, from a POC to a web platform. It's ready to use out-of-the-box and assists me in crafting pixel-perfect UIs. It saves me a significant amount of time while remaining highly customizable. Give it a try, and you won't be let down."
user: user:
name: 'Estéban Soubiran' name: 'Estéban Soubiran'
description: 'Web developer and UnJS member' description: 'Software engineer'
to: 'https://x.com/soubiran_' to: 'https://x.com/soubiran_'
target: _blank target: _blank
avatar: avatar:

View File

@@ -71,7 +71,8 @@ onMounted(() => {
<template> <template>
<UMain> <UMain>
<UPageHero headline="License Activation" :title="title" :description="description" :ui="{ container: 'relative overflow-hidden', wrapper: 'lg:px-12', description: 'text-pretty' }"> <UPageHero headline="License Activation" :title="title" :description="description" :ui="{ container: 'relative overflow-hidden', wrapper: 'lg:px-12', description: 'text-pretty' }">
<StarsBg /> <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 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="px-4 py-10 lg:border border-(--ui-border) bg-(--ui-bg)"> <div class="px-4 py-10 lg:border border-(--ui-border) bg-(--ui-bg)">

View File

@@ -32,7 +32,7 @@ useSeoMeta({
<MDC :value="page.hero.description" tag="span" unwrap="p" cache-key="pro-hero-description" /> <MDC :value="page.hero.description" tag="span" unwrap="p" cache-key="pro-hero-description" />
</template> </template>
<StarsBg /> <LazyStarsBg />
<Motion as-child :initial="{ height: 0 }" :animate="{ height: 'auto' }" :transition="{ delay: 0.2, duration: 1 }"> <Motion as-child :initial="{ height: 0 }" :animate="{ height: 'auto' }" :transition="{ delay: 0.2, duration: 1 }">
<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 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" />
@@ -82,11 +82,11 @@ useSeoMeta({
}" }"
> >
<template #description> <template #description>
<Motion :initial="{ opacity: 0, transform: 'translateY(10px)' }" :in-view="{ opacity: 1, transform: 'translateY(0)' }" :in-view-options="{ once: true }" :transition="{ delay: 0.2 }"> <Motion :initial="{ opacity: 0, transform: 'translateY(10px)' }" :while-in-view="{ opacity: 1, transform: 'translateY(0)' }" :in-view-options="{ once: true }" :transition="{ delay: 0.2 }">
<MDC :value="page.testimonial.quote" tag="span" unwrap="p" class="before:content-[open-quote] after:content-[close-quote]" cache-key="pro-testimonial-quote" /> <MDC :value="page.testimonial.quote" tag="span" unwrap="p" class="before:content-[open-quote] after:content-[close-quote]" cache-key="pro-testimonial-quote" />
</Motion> </Motion>
</template> </template>
<Motion :initial="{ opacity: 0, transform: 'translateY(10px)' }" :in-view="{ opacity: 1, transform: 'translateY(0)' }" :in-view-options="{ once: true }" :transition="{ delay: 0.3 }"> <Motion :initial="{ opacity: 0, transform: 'translateY(10px)' }" :while-in-view="{ opacity: 1, transform: 'translateY(0)' }" :in-view-options="{ once: true }" :transition="{ delay: 0.3 }">
<UUser <UUser
v-bind="page.testimonial.user" v-bind="page.testimonial.user"
class="justify-center" class="justify-center"
@@ -103,7 +103,7 @@ useSeoMeta({
}" }"
class="border-t border-(--ui-border)" class="border-t border-(--ui-border)"
> >
<Motion as-child :initial="{ height: 0 }" :in-view="{ height: 'auto' }" :transition="{ delay: 0.4, duration: 1 }"> <Motion as-child :initial="{ height: 0 }" :while-in-view="{ height: 'auto' }" :transition="{ delay: 0.4, duration: 1 }">
<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 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" />
</Motion> </Motion>
</UPageSection> </UPageSection>
@@ -196,7 +196,7 @@ useSeoMeta({
class="overflow-hidden" class="overflow-hidden"
orientation="horizontal" orientation="horizontal"
> >
<StarsBg /> <LazyStarsBg />
<video <video
class="rounded-[var(--ui-radius)] z-10" class="rounded-[var(--ui-radius)] z-10"

View File

@@ -27,8 +27,10 @@ useSeoMeta({
<MDC :value="page.pricing.title" unwrap="p" cache-key="pro-pricing-title" /> <MDC :value="page.pricing.title" unwrap="p" cache-key="pro-pricing-title" />
</template> </template>
<StarsBg /> <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 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="flex flex-col bg-(--ui-bg) gap-8 lg:gap-0"> <div class="flex flex-col bg-(--ui-bg) gap-8 lg:gap-0">
<UPricingPlan <UPricingPlan
v-bind="page.pricing.freePlan" v-bind="page.pricing.freePlan"
@@ -42,6 +44,7 @@ useSeoMeta({
:title="plan.title" :title="plan.title"
:description="plan.description" :description="plan.description"
:price="plan.price" :price="plan.price"
:discount="plan.discount"
:billing-period="plan.billing_period" :billing-period="plan.billing_period"
:billing-cycle="plan.billing_cycle" :billing-cycle="plan.billing_cycle"
:variant="plan.highlight ? 'soft' : 'outline'" :variant="plan.highlight ? 'soft' : 'outline'"
@@ -53,6 +56,8 @@ useSeoMeta({
<UPricingPlan <UPricingPlan
v-bind="page.pricing.figma" v-bind="page.pricing.figma"
variant="naked" variant="naked"
:billing-period="page.pricing.figma.billing_period"
:billing-cycle="page.pricing.figma.billing_cycle"
class="lg:rounded-none border lg:border-y-0 border-(--ui-border)" class="lg:rounded-none border lg:border-y-0 border-(--ui-border)"
> >
<template #features> <template #features>

View File

@@ -18,7 +18,8 @@ useSeoMeta({
<template> <template>
<div class="relative"> <div class="relative">
<UPageHero :links="page.links" :ui="{ container: 'relative' }"> <UPageHero :links="page.links" :ui="{ container: 'relative' }">
<StarsBg /> <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 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" />
<template #title> <template #title>
@@ -50,11 +51,12 @@ useSeoMeta({
</template> </template>
<div class="lg:border-x border-(--ui-border) h-full flex items-center lg:bg-(--ui-bg-muted)/20"> <div class="lg:border-x border-(--ui-border) h-full flex items-center lg:bg-(--ui-bg-muted)/20">
<Motion class="flex-1" :initial="{ opacity: 0, transform: 'translateY(10px)' }" :in-view="{ opacity: 1, transform: 'translateY(0px)' }" :in-view-options="{ once: true }" :transition="{ duration: 0.5, delay: 0.2 }"> <Motion class="flex-1" :initial="{ opacity: 0, transform: 'translateY(10px)' }" :while-in-view="{ opacity: 1, transform: 'translateY(0px)' }" :in-view-options="{ once: true }" :transition="{ duration: 0.5, delay: 0.2 }">
<UColorModeImage <UColorModeImage
v-if="template.thumbnail" v-if="template.thumbnail"
v-bind="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" 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" width="656"
height="369" height="369"
loading="lazy" loading="lazy"

View File

@@ -3,7 +3,7 @@ const title = 'Roadmap'
const description = 'Discover our Volta board for @nuxt/ui development status.' const description = 'Discover our Volta board for @nuxt/ui development status.'
useSeoMeta({ useSeoMeta({
titleTemplate: '%s - Nuxt UI v3', titleTemplate: '%s - Nuxt UI',
title, title,
ogTitle: 'Nuxt UI Roadmap', ogTitle: 'Nuxt UI Roadmap',
description description

View File

@@ -41,16 +41,16 @@ export default defineNuxtPlugin({
const primaryColor = localStorage.getItem('nuxt-ui-primary'); const primaryColor = localStorage.getItem('nuxt-ui-primary');
if (primaryColor !== 'black') { if (primaryColor !== 'black') {
html = html.replace( html = html.replace(
/(--ui-color-primary-\\d{2,3}:\\s*var\\()--color-${appConfig.ui.colors.primary}-(\\d{2,3}\\))/g, /(--ui-color-primary-\\d{2,3}:\\s*var\\(--color-)${appConfig.ui.colors.primary}(-\\d{2,3}.*?\\))/g,
\`$1--color-\${primaryColor}-$2\` \`$1\${primaryColor}$2\`
); );
} }
} }
if (localStorage.getItem('nuxt-ui-neutral')) { if (localStorage.getItem('nuxt-ui-neutral')) {
let neutralColor = localStorage.getItem('nuxt-ui-neutral'); let neutralColor = localStorage.getItem('nuxt-ui-neutral');
html = html.replace( html = html.replace(
/(--ui-color-neutral-\\d{2,3}:\\s*var\\()--color-${appConfig.ui.colors.neutral}-(\\d{2,3}\\))/g, /(--ui-color-neutral-\\d{2,3}:\\s*var\\(--color-)${appConfig.ui.colors.neutral}(-\\d{2,3}.*?\\))/g,
\`$1--color-\${neutralColor === 'neutral' ? 'old-neutral' : neutralColor}-$2\` \`$1\${neutralColor === 'neutral' ? 'old-neutral' : neutralColor}$2\`
); );
} }

View File

@@ -1,17 +1,12 @@
--- ---
navigation.title: Introduction title: Introduction
title: Nuxt UI v3 description: 'Nuxt UI harnesses the combined strengths of Reka UI, Tailwind CSS, and Tailwind Variants to offer developers an unparalleled set of tools for creating sophisticated, accessible, and highly performant user interfaces.'
description: 'A comprehensive, Nuxt-integrated UI library providing a rich set of fully-styled, accessible and highly customizable components for building modern web applications.'
navigation.icon: i-lucide-house navigation.icon: i-lucide-house
--- ---
We're thrilled to introduce this major update to our UI library, bringing significant improvements and powerful new features. Nuxt UI v3 represents a leap forward in creating robust, accessible, and highly customizable user interfaces for Nuxt applications.
## What's New in v3?
<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> <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: 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:
@@ -22,9 +17,9 @@ 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. 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 v3 integrates the latest Tailwind CSS v4, bringing significant improvements: Nuxt UI integrates the latest Tailwind CSS v4, bringing significant improvements:
- **Built for performance**: Full builds in the new engine are up to 5x faster, and incremental builds are over 100x faster — and measured in microseconds. - **Built for performance**: Full builds in the new engine are up to 5x faster, and incremental builds are over 100x faster — and measured in microseconds.
- **Unified toolchain**: Built-in import handling, vendor prefixing, and syntax transforms, with no additional tooling required. - **Unified toolchain**: Built-in import handling, vendor prefixing, and syntax transforms, with no additional tooling required.
@@ -35,7 +30,7 @@ Nuxt UI v3 integrates the latest Tailwind CSS v4, bringing significant improveme
Learn about all the breaking changes in Tailwind CSS v4. 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: We've adopted [Tailwind Variants](https://www.tailwind-variants.org/) to manage our design system, offering:
@@ -45,9 +40,9 @@ We've adopted [Tailwind Variants](https://www.tailwind-variants.org/) to manage
This integration unifies the styling of components, ensuring consistency and code maintainability. This integration unifies the styling of components, ensuring consistency and code maintainability.
### TypeScript Integration ## TypeScript Integration
Nuxt UI v3 offers significantly improved TypeScript integration, providing a superior developer experience: Nuxt UI offers significantly improved TypeScript integration, providing a superior developer experience:
- **Enhanced Auto-completion**: - **Enhanced Auto-completion**:
- Full auto-completion for component props based on your theme - Full auto-completion for component props based on your theme
@@ -65,7 +60,7 @@ Nuxt UI v3 offers significantly improved TypeScript integration, providing a sup
Check out an example of the Accordion component with auto-completion for props and slots. 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: You can now use Nuxt UI in any Vue project without Nuxt by adding the Vite and Vue plugins to your configuration. This provides:
@@ -77,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**. 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: 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:
@@ -112,11 +107,7 @@ Key points to consider:
## FAQ ## FAQ
::accordion ::accordion
::accordion-item{label="What are the main considerations when upgrading to Nuxt UI v3?"} ::accordion-item{label="Is Nuxt UI compatible with standalone Vue projects?"}
The transition to v3 involves significant changes, including new component structures, updated theming approaches, and revised TypeScript definitions. We recommend a careful, incremental upgrade process, starting with thorough testing in a development environment.
::
::accordion-item{label="Is Nuxt UI v3 compatible with standalone Vue projects?"}
Nuxt UI is now compatible with Vue! You can follow the [installation guide](/getting-started/installation/vue) to get started. Nuxt UI is now compatible with Vue! You can follow the [installation guide](/getting-started/installation/vue) to get started.
:: ::
@@ -124,23 +115,19 @@ Key points to consider:
We've also rebuilt Nuxt UI Pro from scratch as v3 to match Nuxt UI version. The license you bought or will buy is valid for both Nuxt UI Pro v1 and v3, this is a **free update**. You can follow the [installation guide](/getting-started/installation/pro/nuxt) to get started. We've also rebuilt Nuxt UI Pro from scratch as v3 to match Nuxt UI version. The license you bought or will buy is valid for both Nuxt UI Pro v1 and v3, this is a **free update**. You can follow the [installation guide](/getting-started/installation/pro/nuxt) to get started.
:: ::
::accordion-item{label="Will Nuxt UI v3 work with other CSS frameworks like UnoCSS?"} ::accordion-item{label="Will Nuxt UI work with other CSS frameworks like UnoCSS?"}
Nuxt UI v3 is currently designed to work exclusively with Tailwind CSS. While there's interest in UnoCSS support, implementing it would require significant changes to the theme structure due to differences in class naming conventions. As a result, we don't have plans to add UnoCSS support in v3. Nuxt UI is currently designed to work exclusively with Tailwind CSS. While there's interest in UnoCSS support, implementing it would require significant changes to the theme structure due to differences in class naming conventions. As a result, we don't have plans to add UnoCSS support.
:: ::
::accordion-item{label="How does Nuxt UI v3 handle accessibility?"} ::accordion-item{label="How does Nuxt UI handle accessibility?"}
Nuxt UI v3 enhances accessibility through Reka UI integration. This provides automatic ARIA attributes, keyboard navigation support, intelligent focus management, and screen reader announcements. While offering a strong foundation, proper implementation and testing in your specific use case remains crucial for full accessibility compliance. For more detailed information, refer to [Reka UI's accessibility documentation](https://reka-ui.com/docs/overview/accessibility). Nuxt UI enhances accessibility through Reka UI integration. This provides automatic ARIA attributes, keyboard navigation support, intelligent focus management, and screen reader announcements. While offering a strong foundation, proper implementation and testing in your specific use case remains crucial for full accessibility compliance. For more detailed information, refer to [Reka UI's accessibility documentation](https://reka-ui.com/docs/overview/accessibility).
:: ::
::accordion-item{label="What is the testing approach for Nuxt UI v3?"} ::accordion-item{label="What is the testing approach for Nuxt UI?"}
Nuxt UI v3 ensures reliability with 1000+ Vitest tests, covering core functionality and accessibility. This robust testing suite supports the library's stability and serves as a reference for developers. Nuxt UI ensures reliability with 1000+ Vitest tests, covering core functionality and accessibility. This robust testing suite supports the library's stability and serves as a reference for developers.
::
::accordion-item{label="Is this version stable and suitable for production use?"}
Nuxt UI v3 is now in beta and is stable enough to be used in production. We now recommend using v3 over v2. We welcome feedback from users to help improve the library further. Feel free to report any issues you encounter on our [GitHub repository](https://github.com/nuxt/ui/issues).
:: ::
:: ::
:hr :hr
We're excited about the possibilities Nuxt UI v3 brings to your projects. Explore our documentation to learn more about new features, components, and best practices for building powerful, accessible user interfaces with Nuxt UI v3. We're excited about the possibilities Nuxt UI v3 brings to your projects. Explore our documentation to learn more about new features, components, and best practices for building powerful, accessible user interfaces.

View File

@@ -20,24 +20,24 @@ Looking for the **Vue** version?
::steps{level="4"} ::steps{level="4"}
#### Install the Nuxt UI v3 beta package #### Install the Nuxt UI package
::code-group{sync="pm"} ::code-group{sync="pm"}
```bash [pnpm] ```bash [pnpm]
pnpm add @nuxt/ui@next pnpm add @nuxt/ui
``` ```
```bash [yarn] ```bash [yarn]
yarn add @nuxt/ui@next yarn add @nuxt/ui
``` ```
```bash [npm] ```bash [npm]
npm install @nuxt/ui@next npm install @nuxt/ui
``` ```
```bash [bun] ```bash [bun]
bun add @nuxt/ui@next bun add @nuxt/ui
``` ```
:: ::
@@ -59,7 +59,7 @@ export default defineNuxtConfig({
::code-group ::code-group
```css [app/assets/css/main.css] ```css [app/assets/css/main.css]
@import "tailwindcss" theme(static); @import "tailwindcss";
@import "@nuxt/ui"; @import "@nuxt/ui";
``` ```
@@ -72,10 +72,6 @@ export default defineNuxtConfig({
:: ::
::warning
The `theme(static)` is required since [`tailwindcss@4.0.8`](https://github.com/tailwindlabs/tailwindcss/releases/tag/v4.0.8) introduced a breaking change to only expose used CSS variables.
::
::callout{icon="i-simple-icons-visualstudiocode"} ::callout{icon="i-simple-icons-visualstudiocode"}
It's recommended to install the [Tailwind CSS IntelliSense](https://marketplace.visualstudio.com/items?itemName=bradlc.vscode-tailwindcss) extension for VSCode and add the following settings: It's recommended to install the [Tailwind CSS IntelliSense](https://marketplace.visualstudio.com/items?itemName=bradlc.vscode-tailwindcss) extension for VSCode and add the following settings:
@@ -85,7 +81,11 @@ It's recommended to install the [Tailwind CSS IntelliSense](https://marketplace.
}, },
"editor.quickSuggestions": { "editor.quickSuggestions": {
"strings": "on" "strings": "on"
} },
"tailwindCSS.classAttributes": ["class", "ui"],
"tailwindCSS.experimental.classRegex": [
["ui:\\s*{([^)]*)\\s*}", "(?:'|\"|`)([^']*)(?:'|\"|`)"]
]
``` ```
:: ::
@@ -108,12 +108,12 @@ The `App` component provides global configurations and is required for **Toast**
### Use our Nuxt Starter ### Use our Nuxt Starter
Start your project using the [nuxt/starter#ui3](https://github.com/nuxt/starter/tree/ui3) template with Nuxt UI v3 pre-configured. Start your project using the [nuxt/starter#ui](https://github.com/nuxt/starter/tree/ui) template with Nuxt UI pre-configured.
Create a new project locally by running the following command: Create a new project locally by running the following command:
```bash [Terminal] ```bash [Terminal]
npx nuxi init -t ui3 <my-app> npx nuxi init -t ui <my-app>
``` ```
::note ::note
@@ -225,15 +225,15 @@ This option adds the `transition-colors` class on components with hover or activ
## Continuous Releases ## Continuous Releases
Nuxt UI v3 uses [pkg.pr.new](https://github.com/stackblitz-labs/pkg.pr.new) for continuous preview releases, providing developers with instant access to the latest features and bug fixes without waiting for official releases. Nuxt UI uses [pkg.pr.new](https://github.com/stackblitz-labs/pkg.pr.new) for continuous preview releases, providing developers with instant access to the latest features and bug fixes without waiting for official releases.
Automatic preview releases are created for all commits and PRs to the `v3` branch. Use them by replacing your package version with the specific commit hash or PR number. Automatic preview releases are created for all commits and PRs to the `v3` branch. Use them by replacing your package version with the specific commit hash or PR number.
```diff [package.json] ```diff [package.json]
{ {
"dependencies": { "dependencies": {
- "@nuxt/ui": "^3.0.0-beta.3", - "@nuxt/ui": "^3.0.0",
+ "@nuxt/ui": "https://pkg.pr.new/@nuxt/ui@83725ac", + "@nuxt/ui": "https://pkg.pr.new/@nuxt/ui@4c96909",
} }
} }
``` ```

View File

@@ -20,24 +20,24 @@ Looking for the **Nuxt** version?
::steps{level="4"} ::steps{level="4"}
#### Install the Nuxt UI v3 beta package #### Install the Nuxt UI package
::code-group{sync="pm"} ::code-group{sync="pm"}
```bash [pnpm] ```bash [pnpm]
pnpm add @nuxt/ui@next pnpm add @nuxt/ui
``` ```
```bash [yarn] ```bash [yarn]
yarn add @nuxt/ui@next yarn add @nuxt/ui
``` ```
```bash [npm] ```bash [npm]
npm install @nuxt/ui@next npm install @nuxt/ui
``` ```
```bash [bun] ```bash [bun]
bun add @nuxt/ui@next bun add @nuxt/ui
``` ```
:: ::
@@ -102,14 +102,10 @@ app.mount('#app')
#### Import Tailwind CSS and Nuxt UI in your CSS #### Import Tailwind CSS and Nuxt UI in your CSS
```css [assets/main.css] ```css [assets/main.css]
@import "tailwindcss" theme(static); @import "tailwindcss";
@import "@nuxt/ui"; @import "@nuxt/ui";
``` ```
::warning
The `theme(static)` is required since [`tailwindcss@4.0.8`](https://github.com/tailwindlabs/tailwindcss/releases/tag/v4.0.8) introduced a breaking change to only expose used CSS variables.
::
::tip ::tip
Import the CSS file in your `main.ts`. Import the CSS file in your `main.ts`.
@@ -145,7 +141,11 @@ It's recommended to install the [Tailwind CSS IntelliSense](https://marketplace.
}, },
"editor.quickSuggestions": { "editor.quickSuggestions": {
"strings": "on" "strings": "on"
} },
"tailwindCSS.classAttributes": ["class", "ui"],
"tailwindCSS.experimental.classRegex": [
["ui:\\s*{([^)]*)\\s*}", "(?:'|\"|`)([^']*)(?:'|\"|`)"]
]
``` ```
:: ::
@@ -168,7 +168,7 @@ The `App` component provides global configurations and is required for **Toast**
### Use our Vue starter ### Use our Vue starter
Start your project using the [nuxtlabs/nuxt-ui-vue-starter](https://github.com/nuxtlabs/nuxt-ui-vue-starter) template with Nuxt UI v3 pre-configured. Start your project using the [nuxtlabs/nuxt-ui-vue-starter](https://github.com/nuxtlabs/nuxt-ui-vue-starter) template with Nuxt UI pre-configured.
Create a new project locally by running the following command: Create a new project locally by running the following command:
@@ -313,15 +313,15 @@ This option adds the `transition-colors` class on components with hover or activ
## Continuous Releases ## Continuous Releases
Nuxt UI v3 uses [pkg.pr.new](https://github.com/stackblitz-labs/pkg.pr.new) for continuous preview releases, providing developers with instant access to the latest features and bug fixes without waiting for official releases. Nuxt UI uses [pkg.pr.new](https://github.com/stackblitz-labs/pkg.pr.new) for continuous preview releases, providing developers with instant access to the latest features and bug fixes without waiting for official releases.
Automatic preview releases are created for all commits and PRs to the `v3` branch. Use them by replacing your package version with the specific commit hash or PR number. Automatic preview releases are created for all commits and PRs to the `v3` branch. Use them by replacing your package version with the specific commit hash or PR number.
```diff [package.json] ```diff [package.json]
{ {
"dependencies": { "dependencies": {
- "@nuxt/ui": "^3.0.0-beta.3", - "@nuxt/ui": "^3.0.0",
+ "@nuxt/ui": "https://pkg.pr.new/@nuxt/ui@83725ac", + "@nuxt/ui": "https://pkg.pr.new/@nuxt/ui@4c96909",
} }
} }
``` ```

View File

@@ -28,7 +28,7 @@ For a detailed walkthrough of all changes, refer to the official **Tailwind CSS
::code-group ::code-group
```css [app/assets/css/main.css] ```css [app/assets/css/main.css]
@import "tailwindcss" theme(static); @import "tailwindcss";
``` ```
```ts [nuxt.config.ts] ```ts [nuxt.config.ts]
@@ -56,19 +56,19 @@ npx @tailwindcss/upgrade
::::code-group{sync="pm"} ::::code-group{sync="pm"}
```bash [pnpm] ```bash [pnpm]
pnpm add @nuxt/ui@next pnpm add @nuxt/ui
``` ```
```bash [yarn] ```bash [yarn]
yarn add @nuxt/ui@next yarn add @nuxt/ui
``` ```
```bash [npm] ```bash [npm]
npm install @nuxt/ui@next npm install @nuxt/ui
``` ```
```bash [bun] ```bash [bun]
bun add @nuxt/ui@next bun add @nuxt/ui
``` ```
:::: ::::
@@ -81,19 +81,19 @@ bun add @nuxt/ui@next
::::code-group{sync="pm"} ::::code-group{sync="pm"}
```bash [pnpm] ```bash [pnpm]
pnpm add @nuxt/ui-pro@next pnpm add @nuxt/ui-pro
``` ```
```bash [yarn] ```bash [yarn]
yarn add @nuxt/ui-pro@next yarn add @nuxt/ui-pro
``` ```
```bash [npm] ```bash [npm]
npm install @nuxt/ui-pro@next npm install @nuxt/ui-pro
``` ```
```bash [bun] ```bash [bun]
bun add @nuxt/ui-pro@next bun add @nuxt/ui-pro
``` ```
:::: ::::
@@ -109,7 +109,7 @@ bun add @nuxt/ui-pro@next
:::div :::div
```css [app/assets/css/main.css]{2} ```css [app/assets/css/main.css]{2}
@import "tailwindcss" theme(static); @import "tailwindcss";
@import "@nuxt/ui"; @import "@nuxt/ui";
``` ```
@@ -119,7 +119,7 @@ bun add @nuxt/ui-pro@next
:::div :::div
```css [app/assets/css/main.css]{2} ```css [app/assets/css/main.css]{2}
@import "tailwindcss" theme(static); @import "tailwindcss";
@import "@nuxt/ui-pro"; @import "@nuxt/ui-pro";
``` ```
@@ -130,7 +130,7 @@ bun add @nuxt/ui-pro@next
#ui #ui
:::div :::div
5. Wrap you app with the [App](/components/app) component: 5. Wrap your app with the [App](/components/app) component:
::: :::
#ui-pro #ui-pro
@@ -145,7 +145,7 @@ export default defineNuxtConfig({
}) })
``` ```
6. Wrap you app with the [App](/components/app) component: 6. Wrap your app with the [App](/components/app) component:
::: :::
:: ::
@@ -458,8 +458,8 @@ const toast = useToast()
Some important differences: Some important differences:
- The `useOverlay` composable is now used to create overlay instances - The `useOverlay` composable is now used to create overlay instances
- Overlays that are opened, can be awaited for their result - Overlays that are opened, can be awaited for their result
- Overlays can no longer be closed using `modal.close()` or `slideover.close()`, rather, they close automatically: either when a `closed` event is fired explicitly from the opened component OR when the overlay closes itself (clicking on backdrop, pressing the ESC key, etc) - Overlays can no longer be close using `modal.close()` or `slideover.close()`, rather, they close automatically: either when a `close` event is fired explicitly from the opened component OR when the overlay closes itself (clicking on backdrop, pressing the ESC key, etc)
- To capture the return value in the parent component you must explictly emit a `closed` event with the desired value - To capture the return value in the parent component you must explictly emit a `close` event with the desired value
```diff ```diff
@@ -496,7 +496,7 @@ const count = ref(0)
</script> </script>
``` ```
Closing a modal is now done through the `closed` event. The `modal.open` method now returns a promise that resolves to the result of the modal whenever the modal is closed: Closing a modal is now done through the `close` event. The `modal.open` method now returns a promise that resolves to the result of the modal whenever the modal is close:
```diff ```diff
<script setup lang="ts"> <script setup lang="ts">

View File

@@ -6,7 +6,7 @@ navigation.icon: i-lucide-swatch-book
## Tailwind CSS ## Tailwind CSS
Nuxt UI v3 uses Tailwind CSS v4, you can read the official [upgrade guide](https://tailwindcss.com/docs/upgrade-guide#changes-from-v3) to learn about all the breaking changes. Nuxt UI uses Tailwind CSS v4, you can read the official [upgrade guide](https://tailwindcss.com/docs/upgrade-guide#changes-from-v3) to learn about all the breaking changes.
### `@theme` ### `@theme`
@@ -17,7 +17,7 @@ Tailwind CSS v4 takes a CSS-first configuration approach, you now customize your
:::div :::div
```css [app/assets/css/main.css] ```css [app/assets/css/main.css]
@import "tailwindcss" theme(static); @import "tailwindcss";
@import "@nuxt/ui"; @import "@nuxt/ui";
@theme static { @theme static {
@@ -45,7 +45,7 @@ Tailwind CSS v4 takes a CSS-first configuration approach, you now customize your
:::div :::div
```css [app/assets/css/main.css] ```css [app/assets/css/main.css]
@import "tailwindcss" theme(static); @import "tailwindcss";
@import "@nuxt/ui-pro"; @import "@nuxt/ui-pro";
@theme static { @theme static {
@@ -87,7 +87,7 @@ This can be useful when writing Tailwind CSS classes in markdown files with [`@n
:::div :::div
```css [app/assets/css/main.css] ```css [app/assets/css/main.css]
@import "tailwindcss" theme(static); @import "tailwindcss";
@import "@nuxt/ui"; @import "@nuxt/ui";
@source "../../../content"; @source "../../../content";
@@ -101,7 +101,7 @@ This can be useful when writing Tailwind CSS classes in markdown files with [`@n
:::div :::div
```css [app/assets/css/main.css] ```css [app/assets/css/main.css]
@import "tailwindcss" theme(static); @import "tailwindcss";
@import "@nuxt/ui-pro"; @import "@nuxt/ui-pro";
@source "../../../content"; @source "../../../content";
@@ -380,7 +380,7 @@ You can change which shade is used for each color on light and dark mode:
:::div{class="*:!mb-0 *:!mt-2.5"} :::div{class="*:!mb-0 *:!mt-2.5"}
```css [app/assets/css/main.css] ```css [app/assets/css/main.css]
@import "tailwindcss" theme(static); @import "tailwindcss";
@import "@nuxt/ui"; @import "@nuxt/ui";
:root { :root {
@@ -398,7 +398,7 @@ You can change which shade is used for each color on light and dark mode:
:::div{class="*:!mb-0 *:!mt-2.5"} :::div{class="*:!mb-0 *:!mt-2.5"}
```css [app/assets/css/main.css] ```css [app/assets/css/main.css]
@import "tailwindcss" theme(static); @import "tailwindcss";
@import "@nuxt/ui-pro"; @import "@nuxt/ui-pro";
:root { :root {
@@ -434,7 +434,7 @@ You cannot set `primary: 'black'`{lang="ts-type"} in your [`vite.config.ts`](#co
:::div{class="*:!mb-0 *:!mt-2.5"} :::div{class="*:!mb-0 *:!mt-2.5"}
```css [app/assets/css/main.css] ```css [app/assets/css/main.css]
@import "tailwindcss" theme(static); @import "tailwindcss";
@import "@nuxt/ui"; @import "@nuxt/ui";
:root { :root {
@@ -452,7 +452,7 @@ You cannot set `primary: 'black'`{lang="ts-type"} in your [`vite.config.ts`](#co
:::div{class="*:!mb-0 *:!mt-2.5"} :::div{class="*:!mb-0 *:!mt-2.5"}
```css [app/assets/css/main.css] ```css [app/assets/css/main.css]
@import "tailwindcss" theme(static); @import "tailwindcss";
@import "@nuxt/ui-pro"; @import "@nuxt/ui-pro";
:root { :root {
@@ -564,7 +564,7 @@ You can customize these CSS variables to tailor the appearance of your applicati
:::div{class="*:!mb-0 *:!mt-2.5"} :::div{class="*:!mb-0 *:!mt-2.5"}
```css [app/assets/css/main.css] ```css [app/assets/css/main.css]
@import "tailwindcss" theme(static); @import "tailwindcss";
@import "@nuxt/ui"; @import "@nuxt/ui";
:root { :root {
@@ -584,7 +584,7 @@ You can customize these CSS variables to tailor the appearance of your applicati
:::div{class="*:!mb-0 *:!mt-2.5"} :::div{class="*:!mb-0 *:!mt-2.5"}
```css [app/assets/css/main.css] ```css [app/assets/css/main.css]
@import "tailwindcss" theme(static); @import "tailwindcss";
@import "@nuxt/ui-pro"; @import "@nuxt/ui-pro";
:root { :root {
@@ -625,7 +625,7 @@ You can customize the default radius value using the default Tailwind CSS variab
:::div{class="*:!mb-0 *:!mt-2.5"} :::div{class="*:!mb-0 *:!mt-2.5"}
```css [app/assets/css/main.css] ```css [app/assets/css/main.css]
@import "tailwindcss" theme(static); @import "tailwindcss";
@import "@nuxt/ui"; @import "@nuxt/ui";
:root { :root {
@@ -639,7 +639,7 @@ You can customize the default radius value using the default Tailwind CSS variab
:::div{class="*:!mb-0 *:!mt-2.5"} :::div{class="*:!mb-0 *:!mt-2.5"}
```css [app/assets/css/main.css] ```css [app/assets/css/main.css]
@import "tailwindcss" theme(static); @import "tailwindcss";
@import "@nuxt/ui-pro"; @import "@nuxt/ui-pro";
:root { :root {
@@ -670,7 +670,7 @@ You can customize the default container width using the default Tailwind CSS var
:::div{class="*:!mb-0 *:!mt-2.5"} :::div{class="*:!mb-0 *:!mt-2.5"}
```css [app/assets/css/main.css] ```css [app/assets/css/main.css]
@import "tailwindcss" theme(static); @import "tailwindcss";
@import "@nuxt/ui"; @import "@nuxt/ui";
@theme { @theme {
@@ -688,7 +688,7 @@ You can customize the default container width using the default Tailwind CSS var
:::div{class="*:!mb-0 *:!mt-2.5"} :::div{class="*:!mb-0 *:!mt-2.5"}
```css [app/assets/css/main.css] ```css [app/assets/css/main.css]
@import "tailwindcss" theme(static); @import "tailwindcss";
@import "@nuxt/ui-pro"; @import "@nuxt/ui-pro";
@theme { @theme {

View File

@@ -19,7 +19,7 @@ Nuxt UI automatically registers the [`@nuxt/fonts`](https://github.com/nuxt/font
:::div :::div
```css [app/assets/css/main.css] ```css [app/assets/css/main.css]
@import "tailwindcss" theme(static); @import "tailwindcss";
@import "@nuxt/ui"; @import "@nuxt/ui";
@theme { @theme {
@@ -33,7 +33,7 @@ Nuxt UI automatically registers the [`@nuxt/fonts`](https://github.com/nuxt/font
:::div :::div
```css [app/assets/css/main.css] ```css [app/assets/css/main.css]
@import "tailwindcss" theme(static); @import "tailwindcss";
@import "@nuxt/ui-pro"; @import "@nuxt/ui-pro";
@theme { @theme {

Some files were not shown because too many files have changed in this diff Show More