Compare commits
160 Commits
v3.0.0-bet
...
v3.0.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
05ab54d03a | ||
|
|
db83df5f5e | ||
|
|
a5168666b7 | ||
|
|
f30d45c79a | ||
|
|
31be5f656e | ||
|
|
0ef5f3b77b | ||
|
|
a0fec4e467 | ||
|
|
f401766e26 | ||
|
|
70f469b868 | ||
|
|
f92df1f661 | ||
|
|
16edbdf1f0 | ||
|
|
fe0bd83d11 | ||
|
|
8a26de230b | ||
|
|
65a6861b54 | ||
|
|
ecff9abc72 | ||
|
|
06bc7d3028 | ||
|
|
b2034ccc91 | ||
|
|
53cf1b4c14 | ||
|
|
0229b0fd46 | ||
|
|
302e04bd77 | ||
|
|
126ba2326f | ||
|
|
dfc27514ec | ||
|
|
26321c4857 | ||
|
|
5dec0e16e2 | ||
|
|
f4c417d9ef | ||
|
|
9046b9d679 | ||
|
|
99df056cad | ||
|
|
08bebcae48 | ||
|
|
764c41a0c6 | ||
|
|
2abcc24018 | ||
|
|
67f90f5f26 | ||
|
|
024fccf8bb | ||
|
|
edb0f0afc6 | ||
|
|
fd160339a6 | ||
|
|
2a023b9060 | ||
|
|
ab52830dc8 | ||
|
|
9a4bb34d7d | ||
|
|
02184b016a | ||
|
|
57efc78a3b | ||
|
|
dec2730aae | ||
|
|
c8ca604bdf | ||
|
|
ef86108f14 | ||
|
|
a1caac47c5 | ||
|
|
fad715d8df | ||
|
|
b0d0d926ab | ||
|
|
a8e6b74e38 | ||
|
|
177fb79cb4 | ||
|
|
175c7027a3 | ||
|
|
cc504b8a4b | ||
|
|
0897e9ef05 | ||
|
|
6588ae8669 | ||
|
|
0b41cebee4 | ||
|
|
e80cc1592f | ||
|
|
5d52af6292 | ||
|
|
5e62493321 | ||
|
|
37f8619c1a | ||
|
|
5376a835f7 | ||
|
|
f2ba755ba5 | ||
|
|
c8d712747f | ||
|
|
816cf50b37 | ||
|
|
3c60f70cab | ||
|
|
05758fa915 | ||
|
|
ce4b229264 | ||
|
|
09b4e9e282 | ||
|
|
50d68a636c | ||
|
|
7646c95c73 | ||
|
|
4c30baffe0 | ||
|
|
0b411936c4 | ||
|
|
047582c246 | ||
|
|
b00f1206f6 | ||
|
|
9ba5cfe70c | ||
|
|
ee9aca33fd | ||
|
|
8d29e50340 | ||
|
|
0ad18d0a7a | ||
|
|
4c96909020 | ||
|
|
06dee66722 | ||
|
|
8494f50d98 | ||
|
|
cc7bdf9247 | ||
|
|
8cbf6d2d58 | ||
|
|
881f977fe4 | ||
|
|
6e03d9c6ef | ||
|
|
5ecd2271ca | ||
|
|
556ebb0b36 | ||
|
|
3a56e3cf45 | ||
|
|
34dfe7d4b3 | ||
|
|
54468ca0f2 | ||
|
|
a9c8eb3f60 | ||
|
|
04fc367568 | ||
|
|
2b4e88d727 | ||
|
|
c713f3015d | ||
|
|
0a603e41f9 | ||
|
|
8329fedd1a | ||
|
|
e289db874d | ||
|
|
cbc5675e04 | ||
|
|
66686d2d2a | ||
|
|
e67906aa0b | ||
|
|
20fb8252f7 | ||
|
|
97c8098d4a | ||
|
|
fbc3200ec5 | ||
|
|
243f981ff4 | ||
|
|
9979a1c818 | ||
|
|
619bf0d7c9 | ||
|
|
21dbf01888 | ||
|
|
a208dedaea | ||
|
|
6120a15a99 | ||
|
|
b1552e447d | ||
|
|
36ec141c16 | ||
|
|
7940f5c0aa | ||
|
|
cfe9b2ecf3 | ||
|
|
ed7710a890 | ||
|
|
83725ac048 | ||
|
|
af2f8987a3 | ||
|
|
f6250f979a | ||
|
|
87ecee6308 | ||
|
|
476408f6e5 | ||
|
|
e016fdea18 | ||
|
|
d9a6218524 | ||
|
|
2ae338e8a5 | ||
|
|
a6f93ca1ce | ||
|
|
63266d366d | ||
|
|
5671618c9a | ||
|
|
60497174a3 | ||
|
|
704abf7917 | ||
|
|
a1de006055 | ||
|
|
4f51d19e2b | ||
|
|
196ffbc989 | ||
|
|
a6f58cba14 | ||
|
|
977fed0122 | ||
|
|
bd2d4848d2 | ||
|
|
e3ce1f7a41 | ||
|
|
08f092fd15 | ||
|
|
3f7df7be9b | ||
|
|
99e531d8df | ||
|
|
a47c5ff466 | ||
|
|
60b7e2d69e | ||
|
|
01fa230eae | ||
|
|
e823022b19 | ||
|
|
25e503bc83 | ||
|
|
629c54261a | ||
|
|
fb4e05c65f | ||
|
|
ccbd89c908 | ||
|
|
145fce1b30 | ||
|
|
52a92c658f | ||
|
|
557dca9a22 | ||
|
|
bd23cf3e9d | ||
|
|
4514171a3f | ||
|
|
d76f9c4fe4 | ||
|
|
62f71f3fbc | ||
|
|
6daa8f1e31 | ||
|
|
5783d0d931 | ||
|
|
58568c642d | ||
|
|
02329c78c2 | ||
|
|
9f241de1b5 | ||
|
|
7f420d9bec | ||
|
|
80b701d270 | ||
|
|
21175c8c59 | ||
|
|
dd708da235 | ||
|
|
f1758ef9d0 | ||
|
|
0d1fccc3c5 | ||
|
|
6446130b5d |
4
.github/ISSUE_TEMPLATE/bug-report-v3.yml
vendored
@@ -5,7 +5,7 @@ body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
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
|
||||
id: env
|
||||
attributes:
|
||||
@@ -37,7 +37,7 @@ body:
|
||||
id: version
|
||||
attributes:
|
||||
label: Version
|
||||
placeholder: v3.0.0-alpha.x
|
||||
placeholder: v3.0.0
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
|
||||
2
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
@@ -5,7 +5,7 @@ body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
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
|
||||
id: env
|
||||
attributes:
|
||||
|
||||
@@ -5,7 +5,7 @@ body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
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
|
||||
id: description
|
||||
attributes:
|
||||
|
||||
2
.github/ISSUE_TEMPLATE/feature-request.yml
vendored
@@ -5,7 +5,7 @@ body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
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
|
||||
id: description
|
||||
attributes:
|
||||
|
||||
2
.github/ISSUE_TEMPLATE/question-v3.yml
vendored
@@ -5,7 +5,7 @@ body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
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
|
||||
id: description
|
||||
attributes:
|
||||
|
||||
2
.github/ISSUE_TEMPLATE/question.yml
vendored
@@ -5,7 +5,7 @@ body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
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
|
||||
id: description
|
||||
attributes:
|
||||
|
||||
142
.github/workflows/module.yml
vendored
@@ -63,3 +63,145 @@ jobs:
|
||||
|
||||
- name: Publish
|
||||
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
|
||||
|
||||
# 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
|
||||
|
||||
64
CHANGELOG.md
@@ -1,5 +1,69 @@
|
||||
# Changelog
|
||||
|
||||
## [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-beta.4](https://github.com/nuxt/ui/compare/v3.0.0-beta.3...v3.0.0-beta.4) (2025-03-12)
|
||||
|
||||
### Features
|
||||
|
||||
* **Form:** global errors ([#3482](https://github.com/nuxt/ui/issues/3482)) ([6e03d9c](https://github.com/nuxt/ui/commit/6e03d9c6efc8f4cfc306813e733d7d3e03706323))
|
||||
* **Input/Textarea:** allow `null` value in model ([#3415](https://github.com/nuxt/ui/issues/3415)) ([cfe9b2e](https://github.com/nuxt/ui/commit/cfe9b2ecf34827bc11a5281a069988ab96030047))
|
||||
* **useLocale:** handle generic messages ([#3100](https://github.com/nuxt/ui/issues/3100)) ([a9c8eb3](https://github.com/nuxt/ui/commit/a9c8eb3f60a10d1a71632991c9db594716b0fba1))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **Button:** missing import ([21dbf01](https://github.com/nuxt/ui/commit/21dbf01888a161a9d8ac6eb0d957c1342f6cc30d)), closes [nuxt/ui#3417](https://github.com/nuxt/ui/issues/3417)
|
||||
* **Form:** input blur validation on submit ([#3504](https://github.com/nuxt/ui/issues/3504)) ([97c8098](https://github.com/nuxt/ui/commit/97c8098d4a35c392719ae179d36aa008d6f8f78a))
|
||||
* **vue:** prevent calling `useHead` in colors ([5ecd227](https://github.com/nuxt/ui/commit/5ecd2271ca86087cb805548397d75c38763ad412))
|
||||
|
||||
## [3.0.0-beta.3](https://github.com/nuxt/ui/compare/v3.0.0-beta.2...v3.0.0-beta.3) (2025-03-07)
|
||||
|
||||
### Features
|
||||
|
||||
* **Button:** handle `active` state ([bd2d484](https://github.com/nuxt/ui/commit/bd2d4848d246a3d5930f8059913f5a1a0abe29fd)), closes [#3417](https://github.com/nuxt/ui/issues/3417)
|
||||
* **Table:** add `loading` slot ([99e531d](https://github.com/nuxt/ui/commit/99e531d8dfb7954322b7ab7feda3d8814c6d8d02)), closes [#3444](https://github.com/nuxt/ui/issues/3444)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **InputMenu/SelectMenu:** proxy `required` in root props ([60b7e2d](https://github.com/nuxt/ui/commit/60b7e2d69e80afa7e221855dcec46479d0ca5c6c))
|
||||
* **InputMenu:** wrong `required` in multiple mode ([01fa230](https://github.com/nuxt/ui/commit/01fa230eae4b6623c5fd71cc218d114d9f6f0f25)), closes [#2741](https://github.com/nuxt/ui/issues/2741)
|
||||
* **Pagination:** add missing slots ([a47c5ff](https://github.com/nuxt/ui/commit/a47c5ff46616eafee3158cb9801183965f5f9874)), closes [#3441](https://github.com/nuxt/ui/issues/3441)
|
||||
* **Pagination:** wrong next link ([e823022](https://github.com/nuxt/ui/commit/e823022b19bb172d2e5fabb9144b4a4286a25a5f)), closes [#3008](https://github.com/nuxt/ui/issues/3008)
|
||||
* **templates:** prevent overriding existing colors ([ccbd89c](https://github.com/nuxt/ui/commit/ccbd89c908fe8af54c7d723dd12da5b7f3906c8f)), closes [#3426](https://github.com/nuxt/ui/issues/3426)
|
||||
|
||||
## [3.0.0-beta.2](https://github.com/nuxt/ui/compare/v3.0.0-beta.1...v3.0.0-beta.2) (2025-02-28)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
24
README.md
@@ -11,31 +11,31 @@
|
||||
[![License][license-src]][license-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]
|
||||
> You are on the `v3` development branch, check out the [dev branch](https://github.com/nuxt/ui/tree/dev) 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
|
||||
|
||||
Visit https://ui3.nuxt.dev to explore the documentation.
|
||||
Visit https://ui.nuxt.com to explore the documentation.
|
||||
|
||||
## Installation
|
||||
|
||||
```bash [pnpm]
|
||||
pnpm add @nuxt/ui@next
|
||||
pnpm add @nuxt/ui
|
||||
```
|
||||
|
||||
```bash [yarn]
|
||||
yarn add @nuxt/ui@next
|
||||
yarn add @nuxt/ui
|
||||
```
|
||||
|
||||
```bash [npm]
|
||||
npm install @nuxt/ui@next
|
||||
npm install @nuxt/ui
|
||||
```
|
||||
|
||||
```bash [bun]
|
||||
bun add @nuxt/ui@next
|
||||
bun add @nuxt/ui
|
||||
```
|
||||
|
||||
### Nuxt
|
||||
@@ -51,11 +51,11 @@ export default defineNuxtConfig({
|
||||
2. Import Tailwind CSS and Nuxt UI in your CSS:
|
||||
|
||||
```css [assets/css/main.css]
|
||||
@import "tailwindcss" theme(static);
|
||||
@import "tailwindcss";
|
||||
@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
|
||||
|
||||
@@ -98,11 +98,11 @@ app.mount('#app')
|
||||
3. Import Tailwind CSS and Nuxt UI in your CSS:
|
||||
|
||||
```css [assets/main.css]
|
||||
@import "tailwindcss" theme(static);
|
||||
@import "tailwindcss";
|
||||
@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
|
||||
|
||||
@@ -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).
|
||||
|
||||
<!-- 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-downloads-src]: https://img.shields.io/npm/dm/@nuxt/ui.svg?style=flat&colorA=18181B&colorB=28CF8D
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"citty": "^0.1.6",
|
||||
"consola": "^3.4.0",
|
||||
"consola": "^3.4.2",
|
||||
"pathe": "^2.0.3",
|
||||
"scule": "^1.3.0"
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
// import { withoutTrailingSlash } from 'ufo'
|
||||
import { withoutTrailingSlash } from 'ufo'
|
||||
import colors from 'tailwindcss/colors'
|
||||
// import { debounce } from 'perfect-debounce'
|
||||
|
||||
const route = useRoute()
|
||||
const appConfig = useAppConfig()
|
||||
@@ -12,16 +11,6 @@ const { data: files } = useLazyAsyncData('search', () => queryCollectionSearchSe
|
||||
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 color = computed(() => colorMode.value === 'dark' ? (colors as any)[appConfig.ui.colors.neutral][900] : 'white')
|
||||
const radius = computed(() => `:root { --ui-radius: ${appConfig.theme.radius}rem; }`)
|
||||
@@ -33,8 +22,8 @@ useHead({
|
||||
{ key: 'theme-color', name: 'theme-color', content: color }
|
||||
],
|
||||
link: [
|
||||
{ rel: 'icon', type: 'image/svg+xml', href: '/icon.svg' }
|
||||
// { rel: 'canonical', href: `https://ui.nuxt.com${withoutTrailingSlash(route.path)}` }
|
||||
{ rel: 'icon', type: 'image/svg+xml', href: '/icon.svg' },
|
||||
{ rel: 'canonical', href: `https://ui.nuxt.com${withoutTrailingSlash(route.path)}` }
|
||||
],
|
||||
style: [
|
||||
{ innerHTML: radius, id: 'nuxt-ui-radius', tagPriority: -2 },
|
||||
@@ -61,7 +50,7 @@ provide('navigation', mappedNavigation)
|
||||
<NuxtLoadingIndicator color="var(--ui-primary)" :height="2" />
|
||||
|
||||
<template v-if="!route.path.startsWith('/examples')">
|
||||
<!-- <Banner /> -->
|
||||
<Banner />
|
||||
|
||||
<Header :links="links" />
|
||||
</template>
|
||||
@@ -75,7 +64,6 @@ provide('navigation', mappedNavigation)
|
||||
|
||||
<ClientOnly>
|
||||
<LazyUContentSearch
|
||||
v-model:search-term="searchTerm"
|
||||
:files="files"
|
||||
:groups="[{
|
||||
id: 'framework',
|
||||
@@ -95,5 +83,5 @@ provide('navigation', mappedNavigation)
|
||||
</template>
|
||||
|
||||
<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>
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
@import "@nuxt/ui-pro";
|
||||
|
||||
@source "../../../content";
|
||||
@source "../../../node_modules/.c12";
|
||||
|
||||
@theme static {
|
||||
--container-8xl: 90rem;
|
||||
|
||||
50
docs/app/components/AdsCarbon.vue
Normal 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-[10px] text-center text-(--ui-text-dimmed) pt-2;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.carbon-text {
|
||||
@apply text-(--ui-text);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,7 +1,18 @@
|
||||
<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>
|
||||
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>
|
||||
</UBanner>
|
||||
</template>
|
||||
|
||||
51
docs/app/components/Countdown.vue
Normal 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>
|
||||
@@ -1,4 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
const route = useRoute()
|
||||
|
||||
const links = [{
|
||||
label: 'Figma',
|
||||
to: '/figma'
|
||||
@@ -16,7 +18,7 @@ const links = [{
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<USeparator icon="i-simple-icons-nuxtdotjs" class="h-px" />
|
||||
<USeparator :icon="route.path === '/' ? undefined : 'i-simple-icons-nuxtdotjs'" class="h-px" />
|
||||
|
||||
<UFooter>
|
||||
<template #left>
|
||||
|
||||
@@ -30,14 +30,18 @@ const mobileLinks = computed(() => props.links.map(link => ({ ...link, defaultOp
|
||||
<UHeader :ui="{ left: 'min-w-0' }" :menu="{ shouldScaleBackground: true }">
|
||||
<template #left>
|
||||
<NuxtLink to="/" class="flex items-end gap-2 font-bold text-xl text-(--ui-text-highlighted) min-w-0 focus-visible:outline-(--ui-primary) shrink-0" aria-label="Nuxt UI">
|
||||
<LogoPro class="w-auto h-6 shrink-0 ui-pro-only" />
|
||||
<Logo class="w-auto h-6 shrink-0 ui-only" />
|
||||
<Logo v-if="route.path === '/'" class="w-auto h-6 shrink-0" />
|
||||
<LogoPro v-else-if="route.path.startsWith('/pro')" class="w-auto h-6 shrink-0" />
|
||||
<template v-else>
|
||||
<LogoPro class="w-auto h-6 shrink-0 ui-pro-only" />
|
||||
<Logo class="w-auto h-6 shrink-0 ui-only" />
|
||||
</template>
|
||||
</NuxtLink>
|
||||
|
||||
<UDropdownMenu
|
||||
v-slot="{ open }"
|
||||
: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' }"
|
||||
size="xs"
|
||||
>
|
||||
@@ -78,7 +82,7 @@ const mobileLinks = computed(() => props.links.map(link => ({ ...link, defaultOp
|
||||
</template>
|
||||
|
||||
<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" />
|
||||
|
||||
|
||||
93
docs/app/components/SkyBg.vue
Normal file
@@ -0,0 +1,93 @@
|
||||
<script setup lang="ts">
|
||||
import { kebabCase } from 'scule'
|
||||
|
||||
interface Star {
|
||||
x: number
|
||||
y: number
|
||||
size: number
|
||||
twinkleDelay: number
|
||||
id: string
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
starCount?: number
|
||||
color?: string
|
||||
size?: { min: number, max: number }
|
||||
speed?: 'slow' | 'normal' | 'fast'
|
||||
}>(), {
|
||||
starCount: 50,
|
||||
color: 'var(--ui-primary)',
|
||||
size: () => ({
|
||||
min: 1,
|
||||
max: 3
|
||||
}),
|
||||
speed: 'normal'
|
||||
})
|
||||
|
||||
const route = useRoute()
|
||||
|
||||
// Generate random stars
|
||||
const generateStars = (count: number): Star[] => {
|
||||
return Array.from({ length: count }, () => {
|
||||
const x = Math.floor(Math.random() * 100)
|
||||
const y = Math.floor(Math.random() * 100)
|
||||
const size = Math.random() * (props.size.max - props.size.min) + props.size.min
|
||||
const twinkleDelay = Math.random() * 5
|
||||
|
||||
return { x, y, size, twinkleDelay, id: Math.random().toString(36).substring(2, 9) }
|
||||
})
|
||||
}
|
||||
|
||||
// Generate all stars
|
||||
const stars = useState<Star[]>(`${kebabCase(route.path)}-sky`, () => generateStars(props.starCount))
|
||||
|
||||
// Compute twinkle animation duration based on speed
|
||||
const twinkleDuration = computed(() => {
|
||||
const speedMap: Record<string, string> = {
|
||||
slow: '4s',
|
||||
normal: '2s',
|
||||
fast: '1s'
|
||||
}
|
||||
return speedMap[props.speed]
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="absolute pointer-events-none z-[-1] inset-y-0 left-4 right-4 lg:right-[50%] overflow-hidden">
|
||||
<div
|
||||
v-for="star in stars"
|
||||
:key="star.id"
|
||||
class="star absolute"
|
||||
:style="{
|
||||
'left': `${star.x}%`,
|
||||
'top': `${star.y}%`,
|
||||
'transform': 'translate(-50%, -50%)',
|
||||
'--star-size': `${star.size}px`,
|
||||
'--star-color': color,
|
||||
'--twinkle-delay': `${star.twinkleDelay}s`,
|
||||
'--twinkle-duration': twinkleDuration
|
||||
}"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.star {
|
||||
width: var(--star-size);
|
||||
height: var(--star-size);
|
||||
background-color: var(--star-color);
|
||||
border-radius: 50%;
|
||||
animation: twinkle var(--twinkle-duration) ease-in-out infinite;
|
||||
animation-delay: var(--twinkle-delay);
|
||||
will-change: opacity;
|
||||
}
|
||||
|
||||
@keyframes twinkle {
|
||||
0%, 100% {
|
||||
opacity: 0.2;
|
||||
}
|
||||
50% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { upperFirst, camelCase } from 'scule'
|
||||
import { upperFirst, camelCase, kebabCase } from 'scule'
|
||||
import type { ComponentMeta } from 'vue-component-meta'
|
||||
import * as theme from '#build/ui'
|
||||
import * as themePro from '#build/ui-pro'
|
||||
@@ -112,7 +112,7 @@ const metaProps: ComputedRef<ComponentMeta['props']> = computed(() => {
|
||||
<ProseTd>
|
||||
<HighlightInlineType v-if="prop.type" :type="prop.type" />
|
||||
|
||||
<MDC v-if="prop.description" :value="prop.description" class="text-(--ui-text-toned) mt-1" />
|
||||
<MDC v-if="prop.description" :value="prop.description" class="text-(--ui-text-toned) mt-1" :cache-key="`${kebabCase(route.path)}-${prop.name}-description`" />
|
||||
|
||||
<ComponentPropsLinks v-if="prop.tags?.length" :prop="prop" />
|
||||
<ComponentPropsSchema v-if="prop.schema" :prop="prop" :ignore="ignore" />
|
||||
|
||||
@@ -1,17 +1,20 @@
|
||||
<script setup lang="ts">
|
||||
import { kebabCase } from 'scule'
|
||||
import type { PropertyMeta } from 'vue-component-meta'
|
||||
|
||||
const props = defineProps<{
|
||||
prop: PropertyMeta
|
||||
}>()
|
||||
|
||||
const route = useRoute()
|
||||
|
||||
const links = computed(() => props.prop.tags?.filter((tag: any) => tag.name === 'link'))
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ProseUl v-if="links?.length">
|
||||
<ProseLi v-for="link in links" :key="link.name">
|
||||
<MDC :value="link.text ?? ''" class="my-1" />
|
||||
<ProseLi v-for="(link, index) in links" :key="index">
|
||||
<MDC :value="link.text ?? ''" class="my-1" :cache-key="`${kebabCase(route.path)}-${prop.name}-link-${index}`" />
|
||||
</ProseLi>
|
||||
</ProseUl>
|
||||
</template>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { kebabCase } from 'scule'
|
||||
import type { PropertyMeta } from 'vue-component-meta'
|
||||
|
||||
const props = defineProps<{
|
||||
@@ -6,6 +7,8 @@ const props = defineProps<{
|
||||
ignore?: string[]
|
||||
}>()
|
||||
|
||||
const route = useRoute()
|
||||
|
||||
function getSchemaProps(schema: PropertyMeta['schema']): any {
|
||||
if (!schema || typeof schema === 'string' || !schema.schema) {
|
||||
return []
|
||||
@@ -40,7 +43,7 @@ const schemaProps = computed(() => {
|
||||
<ProseLi v-for="schemaProp in schemaProps" :key="schemaProp.name">
|
||||
<HighlightInlineType :type="`${schemaProp.name}${schemaProp.required === false ? '?' : ''}: ${schemaProp.type}`" />
|
||||
|
||||
<MDC v-if="schemaProp.description" :value="schemaProp.description" class="text-(--ui-text-muted) my-1" />
|
||||
<MDC v-if="schemaProp.description" :value="schemaProp.description" class="text-(--ui-text-muted) my-1" :cache-key="`${kebabCase(route.path)}-${prop.name}-${schemaProp.name}-description`" />
|
||||
</ProseLi>
|
||||
</ProseUl>
|
||||
</ProseCollapsible>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { upperFirst, camelCase } from 'scule'
|
||||
import { upperFirst, camelCase, kebabCase } from 'scule'
|
||||
|
||||
const props = defineProps<{
|
||||
prose?: boolean
|
||||
@@ -36,7 +36,7 @@ const meta = await fetchComponentMeta(name as any)
|
||||
<ProseTd>
|
||||
<HighlightInlineType v-if="slot.type" :type="slot.type" />
|
||||
|
||||
<MDC v-if="slot.description" :value="slot.description" class="text-(--ui-text-toned) mt-1" />
|
||||
<MDC v-if="slot.description" :value="slot.description" class="text-(--ui-text-toned) mt-1" :cache-key="`${kebabCase(route.path)}-${slot.name}-description`" />
|
||||
</ProseTd>
|
||||
</ProseTr>
|
||||
</ProseTbody>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { murmurHash } from 'ohash'
|
||||
import { hash } from 'ohash'
|
||||
|
||||
const props = defineProps<{
|
||||
type: string
|
||||
@@ -23,7 +23,7 @@ const type = computed(() => {
|
||||
return type
|
||||
})
|
||||
|
||||
const { data: ast } = await useAsyncData(`hightlight-inline-code-${murmurHash(type.value)}`, () => parseMarkdown(`\`${type.value}\`{lang="ts-type"}`))
|
||||
const { data: ast } = await useAsyncData(`hightlight-inline-code-${hash(type.value).slice(0, 10)}`, () => parseMarkdown(`\`${type.value}\`{lang="ts-type"}`))
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -9,21 +9,25 @@ const props = withDefaults(defineProps<{
|
||||
|
||||
function getEmojiFlag(locale: string): string {
|
||||
const languageToCountry: Record<string, string> = {
|
||||
ar: 'sa',
|
||||
bn: 'bd',
|
||||
cs: 'cz',
|
||||
da: 'dk',
|
||||
el: 'gr',
|
||||
et: 'ee',
|
||||
en: 'gb',
|
||||
hi: 'in',
|
||||
ja: 'jp',
|
||||
km: 'kh',
|
||||
ko: 'kr',
|
||||
nb: 'no',
|
||||
sv: 'se',
|
||||
uk: 'ua',
|
||||
vi: 'vn'
|
||||
ar: 'sa', // Arabic -> Saudi Arabia
|
||||
bn: 'bd', // Bengali -> Bangladesh
|
||||
ca: 'es', // Catalan -> Spain
|
||||
cs: 'cz', // Czech -> Czech Republic (note: modern country code is actually 'cz')
|
||||
ckb: 'iq', // Central Kurdish -> Iraq
|
||||
da: 'dk', // Danish -> Denmark
|
||||
el: 'gr', // Greek -> Greece
|
||||
et: 'ee', // Estonian -> Estonia
|
||||
en: 'gb', // English -> Great Britain
|
||||
he: 'il', // Hebrew -> Israel
|
||||
hi: 'in', // Hindi -> India
|
||||
ja: 'jp', // Japanese -> Japan
|
||||
km: 'kh', // Khmer -> Cambodia
|
||||
ko: 'kr', // Korean -> South Korea
|
||||
nb: 'no', // Norwegian Bokmål -> Norway
|
||||
sv: 'se', // Swedish -> Sweden
|
||||
uk: 'ua', // Ukrainian -> Ukraine
|
||||
ur: 'pk', // Urdu -> Pakistan
|
||||
vi: 'vn' // Vietnamese -> Vietnam
|
||||
}
|
||||
|
||||
const baseLanguage = locale.split('-')[0]?.toLowerCase() || locale
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
<script lang="ts" setup>
|
||||
import { CalendarDate, HebrewCalendar } from '@internationalized/date'
|
||||
|
||||
const hebrewDate = shallowRef(new CalendarDate(new HebrewCalendar(), 5781, 1, 1))
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UCalendar v-model="hebrewDate" />
|
||||
</template>
|
||||
@@ -2,6 +2,7 @@
|
||||
const searchTerm = ref('')
|
||||
|
||||
const { data: users, status } = await useFetch('https://jsonplaceholder.typicode.com/users', {
|
||||
key: 'command-palette-users',
|
||||
transform: (data: { id: number, name: string, email: string }[]) => {
|
||||
return data?.map(user => ({ id: user.id, label: user.name, suffix: user.email, avatar: { src: `https://i.pravatar.cc/120?img=${user.id}` } })) || []
|
||||
},
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
const { data: users } = await useFetch('https://jsonplaceholder.typicode.com/users', {
|
||||
key: 'command-palette-users',
|
||||
transform: (data: { id: number, name: string, email: string }[]) => {
|
||||
return data?.map(user => ({ id: user.id, label: user.name, suffix: user.email, avatar: { src: `https://i.pravatar.cc/120?img=${user.id}` } })) || []
|
||||
},
|
||||
|
||||
@@ -3,6 +3,7 @@ const searchTerm = ref('')
|
||||
const searchTermDebounced = refDebounced(searchTerm, 200)
|
||||
|
||||
const { data: users, status } = await useFetch('https://jsonplaceholder.typicode.com/users', {
|
||||
key: 'command-palette-users',
|
||||
params: { q: searchTermDebounced },
|
||||
transform: (data: { id: number, name: string, email: string }[]) => {
|
||||
return data?.map(user => ({ id: user.id, label: user.name, suffix: user.email, avatar: { src: `https://i.pravatar.cc/120?img=${user.id}` } })) || []
|
||||
|
||||
@@ -11,7 +11,7 @@ const items = [
|
||||
level: 2
|
||||
},
|
||||
{
|
||||
id: '/getting-started#reka-ui-radix-vue',
|
||||
id: '/getting-started#reka-ui',
|
||||
label: 'Reka UI',
|
||||
level: 3
|
||||
},
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
const searchTerm = ref('')
|
||||
|
||||
const { data: users, status } = await useFetch('https://jsonplaceholder.typicode.com/users', {
|
||||
key: 'command-palette-users',
|
||||
params: { q: searchTerm },
|
||||
transform: (data: { id: number, name: string, email: string }[]) => {
|
||||
return data?.map(user => ({ id: user.id, label: user.name, suffix: user.email, avatar: { src: `https://i.pravatar.cc/120?img=${user.id}` } })) || []
|
||||
|
||||
@@ -22,7 +22,7 @@ async function onSubmit(event: FormSubmitEvent<Schema>) {
|
||||
</script>
|
||||
|
||||
<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">
|
||||
<UInput v-model="state.email" />
|
||||
</UFormField>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
const { data: users, status } = await useFetch('https://jsonplaceholder.typicode.com/users', {
|
||||
key: 'typicode-users',
|
||||
transform: (data: { id: number, name: string }[]) => {
|
||||
return data?.map(user => ({
|
||||
label: user.name,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
const { data: users, status } = await useFetch('https://jsonplaceholder.typicode.com/users', {
|
||||
key: 'typicode-users-email',
|
||||
transform: (data: { id: number, name: string, email: string }[]) => {
|
||||
return data?.map(user => ({
|
||||
label: user.name,
|
||||
|
||||
@@ -3,6 +3,7 @@ const searchTerm = ref('')
|
||||
const searchTermDebounced = refDebounced(searchTerm, 200)
|
||||
|
||||
const { data: users, status } = await useFetch('https://jsonplaceholder.typicode.com/users', {
|
||||
key: 'typicode-users',
|
||||
params: { q: searchTermDebounced },
|
||||
transform: (data: { id: number, name: string }[]) => {
|
||||
return data?.map(user => ({
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
const searchTerm = ref('')
|
||||
|
||||
const { data: users, status } = await useFetch('https://jsonplaceholder.typicode.com/users', {
|
||||
key: 'command-palette-users',
|
||||
params: { q: searchTerm },
|
||||
transform: (data: { id: number, name: string, email: string }[]) => {
|
||||
return data?.map(user => ({ id: user.id, label: user.name, suffix: user.email, avatar: { src: `https://i.pravatar.cc/120?img=${user.id}` } })) || []
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
const { data: users, status } = await useFetch('https://jsonplaceholder.typicode.com/users', {
|
||||
key: 'typicode-users',
|
||||
transform: (data: { id: number, name: string }[]) => {
|
||||
return data?.map(user => ({
|
||||
label: user.name,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
const { data: users, status } = await useFetch('https://jsonplaceholder.typicode.com/users', {
|
||||
key: 'typicode-users-email',
|
||||
transform: (data: { id: number, name: string, email: string }[]) => {
|
||||
return data?.map(user => ({
|
||||
label: user.name,
|
||||
|
||||
@@ -3,6 +3,7 @@ const searchTerm = ref('')
|
||||
const searchTermDebounced = refDebounced(searchTerm, 200)
|
||||
|
||||
const { data: users, status } = await useFetch('https://jsonplaceholder.typicode.com/users', {
|
||||
key: 'typicode-users',
|
||||
params: { q: searchTermDebounced },
|
||||
transform: (data: { id: number, name: string }[]) => {
|
||||
return data?.map(user => ({
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
const { data: users, status } = await useFetch('https://jsonplaceholder.typicode.com/users', {
|
||||
key: 'typicode-users',
|
||||
transform: (data: { id: number, name: string }[]) => {
|
||||
return data?.map(user => ({
|
||||
label: user.name,
|
||||
|
||||
@@ -13,6 +13,7 @@ type User = {
|
||||
}
|
||||
|
||||
const { data, status } = await useFetch<User[]>('https://jsonplaceholder.typicode.com/users', {
|
||||
key: 'table-users',
|
||||
transform: (data) => {
|
||||
return data?.map(user => ({
|
||||
...user,
|
||||
|
||||
139
docs/app/components/home/HomeContributors.vue
Normal file
@@ -0,0 +1,139 @@
|
||||
<script setup lang="ts">
|
||||
const props = withDefaults(defineProps<{
|
||||
contributors?: {
|
||||
username: string
|
||||
}[]
|
||||
level?: number
|
||||
max?: number
|
||||
paused?: boolean
|
||||
}>(), {
|
||||
level: 0,
|
||||
max: 4,
|
||||
paused: false
|
||||
})
|
||||
|
||||
const contributors = computed(() => props.contributors?.slice(0, 5) ?? [])
|
||||
|
||||
const el = ref(null)
|
||||
const { width } = useElementSize(el)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="isolate rounded-full relative circle w-full aspect-[1/1] p-8 sm:p-12 md:p-14 lg:p-10 xl:p-16 before:absolute before:inset-px before:bg-(--ui-bg) before:rounded-full z-(--level)"
|
||||
:class="{ 'animation-paused': paused }"
|
||||
:style="{
|
||||
'--duration': `${((level + 1) * 8)}s`,
|
||||
'--level': level + 1
|
||||
}"
|
||||
>
|
||||
<HomeContributors
|
||||
v-if="(level + 1) < max"
|
||||
:max="max"
|
||||
:level="level + 1"
|
||||
:contributors="props.contributors?.slice(5) ?? []"
|
||||
:paused="paused"
|
||||
/>
|
||||
|
||||
<div
|
||||
ref="el"
|
||||
class="avatars absolute inset-0 grid"
|
||||
:style="{
|
||||
'--total': contributors.length,
|
||||
'--offset': `${width / 2}px`
|
||||
}"
|
||||
>
|
||||
<UTooltip
|
||||
v-for="(contributor, index) in contributors"
|
||||
:key="contributor.username"
|
||||
:text="contributor.username"
|
||||
:delay-duration="0"
|
||||
>
|
||||
<NuxtLink
|
||||
:to="`https://github.com/${contributor.username}`"
|
||||
:aria-label="contributor.username"
|
||||
target="_blank"
|
||||
class="avatar flex absolute top-1/2 left-1/2"
|
||||
tabindex="-1"
|
||||
:style="{
|
||||
'--index': index + 1
|
||||
}"
|
||||
>
|
||||
<img
|
||||
width="56"
|
||||
height="56"
|
||||
:src="`https://ipx.nuxt.com/s_56x56/gh_avatar/${contributor.username}`"
|
||||
:srcset="`https://ipx.nuxt.com/s_112x112/gh_avatar/${contributor.username} 2x`"
|
||||
:alt="contributor.username"
|
||||
class="ring-2 ring-(--ui-border) lg:hover:ring-(--ui-border-inverted) transition rounded-full size-7"
|
||||
loading="lazy"
|
||||
>
|
||||
</NuxtLink>
|
||||
</UTooltip>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.circle:after {
|
||||
--start: 0deg;
|
||||
--end: 360deg;
|
||||
--border-color: var(--ui-border);
|
||||
--highlight-color: var(--ui-color-neutral-400);
|
||||
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
margin: -1px;
|
||||
opacity: 1;
|
||||
border-radius: 9999px;
|
||||
z-index: -1;
|
||||
background: var(--border-color);
|
||||
|
||||
@supports (background: paint(houdini)) {
|
||||
background: linear-gradient(var(--angle), var(--border-color), var(--border-color), var(--border-color), var(--border-color), var(--highlight-color));
|
||||
animation: var(--duration) rotate linear infinite;
|
||||
}
|
||||
}
|
||||
|
||||
.dark .circle:after {
|
||||
--highlight-color: var(--color-white);
|
||||
}
|
||||
|
||||
.animation-paused.circle:after,
|
||||
.animation-paused .avatars {
|
||||
animation-play-state: paused;
|
||||
}
|
||||
|
||||
.avatars {
|
||||
--start: calc(var(--level) * 36deg);
|
||||
--end: calc(360deg + (var(--level) * 36deg));
|
||||
transform: rotate(var(--angle));
|
||||
animation: calc(var(--duration) + 60s) rotate linear infinite;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
--deg: calc(var(--index) * (360deg / var(--total)));
|
||||
--transformX: calc(cos(var(--deg)) * var(--offset));
|
||||
--transformY: calc(sin(var(--deg)) * var(--offset));
|
||||
transform: translate(calc(-50% + var(--transformX)), calc(-50% + var(--transformY))) rotate(calc(360deg - var(--angle)));
|
||||
}
|
||||
|
||||
@keyframes rotate {
|
||||
from {
|
||||
--angle: var(--start);
|
||||
}
|
||||
to {
|
||||
--angle: var(--end);
|
||||
}
|
||||
}
|
||||
|
||||
@property --angle {
|
||||
syntax: '<angle>';
|
||||
initial-value: 0deg;
|
||||
inherits: true;
|
||||
}
|
||||
</style>
|
||||
@@ -3,7 +3,7 @@ withDefaults(defineProps<{
|
||||
title: string
|
||||
description: string
|
||||
component: string
|
||||
module: string
|
||||
module?: string
|
||||
}>(), {
|
||||
module: ''
|
||||
})
|
||||
|
||||
@@ -3,8 +3,8 @@ withDefaults(defineProps<{
|
||||
title: string
|
||||
description: string
|
||||
headline: string
|
||||
framework: string
|
||||
module: string
|
||||
framework?: string
|
||||
module?: string
|
||||
}>(), {
|
||||
framework: 'nuxt',
|
||||
module: ''
|
||||
|
||||
@@ -81,7 +81,6 @@ function setBlackAsPrimary(value: boolean) {
|
||||
|
||||
<div class="grid grid-cols-3 gap-1 -mx-2">
|
||||
<ThemePickerButton
|
||||
chip="primary"
|
||||
label="Black"
|
||||
:selected="appConfig.theme.blackAsPrimary"
|
||||
@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" />
|
||||
</template>
|
||||
</ThemePickerButton>
|
||||
|
||||
<ThemePickerButton
|
||||
v-for="color in primaryColors"
|
||||
:key="color"
|
||||
|
||||
@@ -5,6 +5,10 @@ defineProps<{
|
||||
chip?: string
|
||||
selected?: boolean
|
||||
}>()
|
||||
|
||||
const slots = defineSlots<{
|
||||
leading: () => any
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -17,7 +21,7 @@ defineProps<{
|
||||
class="capitalize ring-(--ui-border) rounded-[calc(var(--ui-radius))] text-[11px]"
|
||||
: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">
|
||||
<span
|
||||
class="inline-block size-2 rounded-full"
|
||||
|
||||
@@ -37,6 +37,10 @@ export const useContentNavigation = (navigation: Ref<ContentNavigationItem[] | u
|
||||
return {
|
||||
...item,
|
||||
children: item.children?.filter((child: any) => {
|
||||
if (child.path.startsWith('/components')) {
|
||||
return true
|
||||
}
|
||||
|
||||
if (child.framework && child.framework !== framework.value) {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -12,23 +12,17 @@ export function useLinks() {
|
||||
to: '/components',
|
||||
active: route.path === '/components',
|
||||
children: [{
|
||||
label: 'Layout',
|
||||
to: '/components#layout',
|
||||
description: 'Container, grid, divider and responsive layout.',
|
||||
icon: 'i-lucide-layout',
|
||||
active: route.fullPath === '/components#layout'
|
||||
label: 'Element',
|
||||
to: '/components#element',
|
||||
description: 'Button, badge, icon, alert, and small UI elements.',
|
||||
icon: 'i-lucide-mouse-pointer',
|
||||
active: route.fullPath === '/components#element'
|
||||
}, {
|
||||
label: 'Form',
|
||||
to: '/components#form',
|
||||
description: 'Input, select, checkbox, radio and form validation.',
|
||||
icon: 'i-lucide-text-cursor-input',
|
||||
active: route.fullPath === '/components#form'
|
||||
}, {
|
||||
label: 'Element',
|
||||
to: '/components#element',
|
||||
description: 'Button, badge, icon, alert, and small UI elements.',
|
||||
icon: 'i-lucide-mouse-pointer',
|
||||
active: route.fullPath === '/components#element'
|
||||
}, {
|
||||
label: 'Data',
|
||||
to: '/components#data',
|
||||
@@ -47,6 +41,12 @@ export function useLinks() {
|
||||
description: 'Modal, tooltip, dialog and popover.',
|
||||
icon: 'i-lucide-layers',
|
||||
active: route.fullPath === '/components#overlay'
|
||||
}, {
|
||||
label: 'Layout',
|
||||
to: '/components#layout',
|
||||
description: 'Container, grid, divider and responsive layout.',
|
||||
icon: 'i-lucide-layout',
|
||||
active: route.fullPath === '/components#layout'
|
||||
}]
|
||||
}, {
|
||||
label: 'Pro',
|
||||
@@ -98,7 +98,7 @@ export function useLinks() {
|
||||
label: 'Raycast Extension',
|
||||
description: 'Access Nuxt UI components without leaving your editor.',
|
||||
icon: 'i-simple-icons-raycast',
|
||||
to: 'https://github.com/HugoRCD/nuxt-ui-raycast-extension',
|
||||
to: 'https://www.raycast.com/HugoRCD/nuxt-ui',
|
||||
target: '_blank'
|
||||
}, {
|
||||
label: 'Figma to Code',
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import colors from 'tailwindcss/colors'
|
||||
// import { debounce } from 'perfect-debounce'
|
||||
import type { NuxtError } from '#app'
|
||||
|
||||
const props = defineProps<{
|
||||
@@ -15,16 +14,6 @@ const { data: files } = useLazyAsyncData('search', () => queryCollectionSearchSe
|
||||
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 color = computed(() => colorMode.value === 'dark' ? (colors as any)[appConfig.ui.colors.neutral][900] : 'white')
|
||||
const radius = computed(() => `:root { --ui-radius: ${appConfig.theme.radius}rem; }`)
|
||||
@@ -48,7 +37,7 @@ useHead({
|
||||
})
|
||||
|
||||
useSeoMeta({
|
||||
titleTemplate: '%s - Nuxt UI v3',
|
||||
titleTemplate: '%s - Nuxt UI',
|
||||
title: String(props.error.statusCode)
|
||||
})
|
||||
|
||||
@@ -67,17 +56,16 @@ provide('navigation', mappedNavigation)
|
||||
<UApp>
|
||||
<NuxtLoadingIndicator color="#FFF" />
|
||||
|
||||
<!-- <Banner /> -->
|
||||
<Banner />
|
||||
|
||||
<Header :links="links" />
|
||||
|
||||
<UError :error="error" />
|
||||
|
||||
<!-- <Footer /> -->
|
||||
<Footer />
|
||||
|
||||
<ClientOnly>
|
||||
<LazyUContentSearch
|
||||
v-model:search-term="searchTerm"
|
||||
:files="files"
|
||||
:groups="[{
|
||||
id: 'framework',
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
<template>
|
||||
<div>
|
||||
<slot />
|
||||
</div>
|
||||
<slot />
|
||||
</template>
|
||||
|
||||
182
docs/app/pages/.index.yml
Normal file
@@ -0,0 +1,182 @@
|
||||
title: The Intuitive Vue UI Library
|
||||
description: Create beautiful, responsive & accessible web apps quickly with Vue or Nuxt. Nuxt UI is an open-source UI library of 50+ customizable components built with Tailwind CSS and Reka UI.
|
||||
hero:
|
||||
title: The Intuitive Vue UI Library
|
||||
description: Create beautiful, responsive & accessible web apps quickly with Vue or Nuxt. Nuxt UI is an open-source UI library of 50+ customizable components built with Tailwind CSS and Reka UI.
|
||||
links:
|
||||
- label: Get started
|
||||
to: /getting-started/installation/nuxt
|
||||
class: 'ui-only nuxt-only'
|
||||
- label: Get started
|
||||
to: /getting-started/installation/vue
|
||||
class: 'ui-only vue-only'
|
||||
- label: Get started
|
||||
to: /getting-started/installation/pro/nuxt
|
||||
class: 'ui-pro-only nuxt-only'
|
||||
- label: Get started
|
||||
to: /getting-started/installation/pro/vue
|
||||
class: 'ui-pro-only vue-only'
|
||||
- label: Explore components
|
||||
to: /components
|
||||
variant: outline
|
||||
color: neutral
|
||||
trailingIcon: i-lucide-arrow-right
|
||||
features:
|
||||
- icon: i-logos-tailwindcss-icon
|
||||
title: Styled with Tailwind CSS v4
|
||||
description: Beautifully styled by default, overwrite any style you want.
|
||||
- icon: i-custom-reka-ui
|
||||
title: Accessible with Reka UI
|
||||
description: Robust accessibility out of the box.
|
||||
- icon: i-logos-typescript-icon
|
||||
title: Type-safe with TypeScript
|
||||
description: Auto-complete and type safety for all components.
|
||||
features:
|
||||
- title: Build for the modern web
|
||||
description: Powered by Tailwind CSS v4 and Reka UI for top performance and accessibility.
|
||||
icon: i-lucide-rocket
|
||||
to: /getting-started
|
||||
- title: Flexible design system
|
||||
description: Beautiful by default and easily customizable with design tokens to your brand.
|
||||
icon: i-lucide-swatch-book
|
||||
to: /getting-started/theme#design-system
|
||||
- title: Internationalization (i18n)
|
||||
description: Nuxt UI is translated into 30+ languages, works well with i18n and multi-directional support (LTR/RTL).
|
||||
icon: i-lucide-globe
|
||||
to: /getting-started/i18n/nuxt
|
||||
- title: Easy font customization
|
||||
description: Performance-optimized fonts with first-class @nuxt/fonts integration.
|
||||
icon: i-lucide-a-large-small
|
||||
to: /getting-started/fonts
|
||||
- title: Large icons sets
|
||||
description: Access to over 200,000 customizable icons from Iconify, seamlessly integrated with Iconify.
|
||||
icon: i-lucide-smile
|
||||
to: /getting-started/icons
|
||||
- title: Light & Dark
|
||||
description: Dark mode-ready components, seamless integration with @nuxtjs/color-mode.
|
||||
icon: i-lucide-sun-moon
|
||||
to: /getting-started/color-mode/nuxt
|
||||
design_system:
|
||||
title: Flexible design system
|
||||
description: Build your next project faster with Nuxt UI's comprehensive design system. Featuring semantic color aliases, comprehensive design tokens, and automatic light/dark mode support for accessible components out of the box.
|
||||
links:
|
||||
- label: Customize design system
|
||||
to: /getting-started/theme#design-system
|
||||
variant: outline
|
||||
color: neutral
|
||||
trailingIcon: i-lucide-arrow-right
|
||||
features:
|
||||
- title: Color aliases via AppConfig
|
||||
description: Configure 7 semantic color aliases (primary, secondary, success, info, warning, error, neutral) at runtime through AppConfig without rebuilding your application
|
||||
icon: i-lucide-palette
|
||||
- title: Comprehensive design tokens
|
||||
description: Extensive set of neutral palette tokens for text, backgrounds, and borders with automatic light/dark mode support via CSS variables like --ui-text, --ui-bg, --ui-border
|
||||
icon: i-lucide-component
|
||||
- title: Global style variables
|
||||
description: Customize global styling with --ui-radius for consistent border rounding and --ui-container for layout widths across your entire application
|
||||
icon: i-lucide-ruler
|
||||
code: |
|
||||
::code-group
|
||||
|
||||
```ts [app.config.ts]
|
||||
export default defineAppConfig({
|
||||
ui: {
|
||||
colors: {
|
||||
primary: 'indigo',
|
||||
secondary: 'pink',
|
||||
success: 'green',
|
||||
info: 'blue',
|
||||
warning: 'orange',
|
||||
error: 'red',
|
||||
neutral: 'zinc'
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
```
|
||||
|
||||
```css [main.css]
|
||||
@import "tailwindcss";
|
||||
@import "@nuxt/ui";
|
||||
|
||||
:root {
|
||||
--ui-radius: var(--radius-sm);
|
||||
--ui-container: 90rem;
|
||||
--ui-bg: var(--ui-color-neutral-50);
|
||||
--ui-text: var(--ui-color-neutral-900);
|
||||
}
|
||||
.dark {
|
||||
--ui-bg: var(--ui-color-neutral-950);
|
||||
--ui-border: var(--ui-color-neutral-900);
|
||||
}
|
||||
```
|
||||
|
||||
::
|
||||
component_customization:
|
||||
title: Powerful component customization
|
||||
description: Nuxt UI leverages [Tailwind Variants](https://www.tailwind-variants.org/) to provide a powerful, maintainable system for managing component styles and intelligently merging Tailwind CSS classes without conflicts.
|
||||
links:
|
||||
- label: Customize components
|
||||
to: /getting-started/theme#customize-theme
|
||||
variant: outline
|
||||
color: neutral
|
||||
trailingIcon: i-lucide-arrow-right
|
||||
features:
|
||||
- title: Powerful slot and variant system
|
||||
description: Customize component parts with slots and apply different styles based on props, creating consistent UI patterns with granular control over styling
|
||||
icon: i-lucide-layout-grid
|
||||
- title: Global theme with AppConfig
|
||||
description: Configure component styles project-wide with a centralized AppConfig that maintains consistency across your application without rebuilding
|
||||
icon: i-lucide-settings-2
|
||||
- title: Per-component customization
|
||||
description: Fine-tune individual components with the ui prop for slot-specific styling and class prop for root element overrides, providing maximum flexibility
|
||||
icon: i-lucide-component
|
||||
code: |
|
||||
::code-group
|
||||
|
||||
```ts [app.config.ts]
|
||||
export default defineAppConfig({
|
||||
ui: {
|
||||
button: {
|
||||
slots: {
|
||||
base: 'group font-bold',
|
||||
trailingIcon: 'group-data-[state=open]:rotate-180 transition-transform duration-200'
|
||||
},
|
||||
defaultVariants: {
|
||||
color: 'neutral',
|
||||
variant: 'subtle'
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
```vue [Collapsible.vue]
|
||||
<template>
|
||||
<UCollapsible>
|
||||
<UButton
|
||||
label="Open"
|
||||
color="neutral"
|
||||
variant="subtle"
|
||||
trailing-icon="i-lucide-chevron-down"
|
||||
:ui="{
|
||||
trailingIcon: 'group-data-[state=open]:rotate-180 transition-transform duration-200'
|
||||
}"
|
||||
class="group font-bold"
|
||||
/>
|
||||
</UCollapsible>
|
||||
</template>
|
||||
```
|
||||
|
||||
::
|
||||
community:
|
||||
title: Nuxt UI open-source community
|
||||
description: Join our thriving community to contribute code, report issues, suggest features, or help with documentation. Every contribution makes Nuxt UI better for everyone.
|
||||
links:
|
||||
- label: Star on GitHub
|
||||
color: neutral
|
||||
variant: outline
|
||||
to: https://github.com/nuxt/ui
|
||||
target: _blank
|
||||
icon: i-lucide-star
|
||||
@@ -1,4 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { kebabCase } from 'scule'
|
||||
import type { ContentNavigationItem } from '@nuxt/content'
|
||||
import { findPageBreadcrumb, mapContentNavigation } from '#ui-pro/utils/content'
|
||||
|
||||
@@ -9,7 +10,7 @@ definePageMeta({
|
||||
layout: 'docs'
|
||||
})
|
||||
|
||||
const { data: page } = await useAsyncData(route.path, () => queryCollection('content').path(route.path).first())
|
||||
const { data: page } = await useAsyncData(kebabCase(route.path), () => queryCollection('content').path(route.path).first())
|
||||
if (!page.value) {
|
||||
throw createError({ statusCode: 404, statusMessage: 'Page not found', fatal: true })
|
||||
}
|
||||
@@ -24,7 +25,7 @@ watch(page, () => {
|
||||
}
|
||||
}, { immediate: true })
|
||||
|
||||
const { data: surround } = await useAsyncData(`${route.path}-surround`, () => {
|
||||
const { data: surround } = await useAsyncData(`${kebabCase(route.path)}-surround`, () => {
|
||||
return queryCollectionItemSurroundings('content', route.path, {
|
||||
fields: ['description']
|
||||
}).orWhere(group => group.where('framework', '=', framework.value).where('framework', 'IS NULL'))
|
||||
@@ -81,6 +82,8 @@ if (route.path.startsWith('/components')) {
|
||||
})
|
||||
} else {
|
||||
defineOgImageComponent('Docs', {
|
||||
title: page.value.title,
|
||||
description: page.value.description,
|
||||
headline: breadcrumb.value?.[breadcrumb.value.length - 1]?.label || 'Nuxt UI',
|
||||
framework: page.value?.framework,
|
||||
module: page.value.module
|
||||
@@ -106,23 +109,6 @@ const communityLinks = computed(() => [{
|
||||
icon: 'i-lucide-map',
|
||||
to: '/roadmap'
|
||||
}])
|
||||
|
||||
// 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>
|
||||
|
||||
<template>
|
||||
@@ -137,7 +123,7 @@ const communityLinks = computed(() => [{
|
||||
</template>
|
||||
|
||||
<template #description>
|
||||
<MDC v-if="page.description" :value="page.description" unwrap="p" />
|
||||
<MDC v-if="page.description" :value="page.description" unwrap="p" :cache-key="`${kebabCase(route.path)}-description`" />
|
||||
</template>
|
||||
|
||||
<template v-if="page.links?.length" #links>
|
||||
@@ -171,14 +157,9 @@ const communityLinks = computed(() => [{
|
||||
|
||||
<UPageLinks title="Community" :links="communityLinks" />
|
||||
|
||||
<!-- <USeparator type="dashed" />
|
||||
|
||||
<UPageLinks title="Resources" :links="resourcesLinks" />
|
||||
|
||||
<USeparator type="dashed" />
|
||||
|
||||
<AdsPro />
|
||||
<AdsCarbon /> -->
|
||||
<AdsCarbon />
|
||||
</template>
|
||||
</UContentToc>
|
||||
</template>
|
||||
|
||||
@@ -15,7 +15,7 @@ useSeoMeta({
|
||||
ogImage: joinURL(url, '/og-image.png')
|
||||
})
|
||||
|
||||
const { data: components } = await useAsyncData('components', () => {
|
||||
const { data: components } = await useAsyncData('all-components', () => {
|
||||
return queryCollection('content')
|
||||
.where('path', 'LIKE', '/components/%')
|
||||
.where('extension', '=', 'md')
|
||||
@@ -31,17 +31,13 @@ const componentsPerCategory = computed(() => {
|
||||
})
|
||||
|
||||
const categories = [{
|
||||
id: 'layout',
|
||||
title: 'Layout',
|
||||
description: 'Structural components for organizing content, including containers, grids, dividers, and responsive layout systems.'
|
||||
id: 'element',
|
||||
title: 'Element',
|
||||
description: 'Core UI building blocks like buttons, badges, icons, avatars, and other fundamental interface elements.'
|
||||
}, {
|
||||
id: 'form',
|
||||
title: 'Form',
|
||||
description: 'Interactive form elements including inputs, selects, checkboxes, radio buttons, and advanced form validation components.'
|
||||
}, {
|
||||
id: 'element',
|
||||
title: 'Element',
|
||||
description: 'Core UI building blocks like buttons, badges, icons, avatars, and other fundamental interface elements.'
|
||||
}, {
|
||||
id: 'data',
|
||||
title: 'Data',
|
||||
@@ -54,6 +50,10 @@ const categories = [{
|
||||
id: 'overlay',
|
||||
title: 'Overlay',
|
||||
description: 'Floating UI elements like modals, dialogs, tooltips, popovers, and other components that overlay the main content.'
|
||||
}, {
|
||||
id: 'layout',
|
||||
title: 'Layout',
|
||||
description: 'Structural components for organizing content, including containers, grids, dividers, and responsive layout systems.'
|
||||
}]
|
||||
|
||||
const { y } = useWindowScroll()
|
||||
@@ -81,7 +81,10 @@ onMounted(() => {
|
||||
orientation="vertical"
|
||||
:ui="{ title: 'text-balance', container: 'relative' }"
|
||||
>
|
||||
<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 #top>
|
||||
<div class="absolute z-[-1] rounded-full bg-(--ui-primary) blur-[300px] size-60 sm:size-80 transform -translate-x-1/2 left-1/2 -translate-y-80" />
|
||||
</template>
|
||||
|
||||
<template #headline>
|
||||
<UButton
|
||||
to="https://tailwindcss.com"
|
||||
@@ -96,6 +99,7 @@ onMounted(() => {
|
||||
<template #title>
|
||||
Build beautiful UI with <span class="text-(--ui-primary)">{{ components!.length }}+</span> powerful components
|
||||
</template>
|
||||
|
||||
<template #links>
|
||||
<UButton
|
||||
to="/getting-started/installation/vue"
|
||||
@@ -114,10 +118,10 @@ onMounted(() => {
|
||||
size="xl"
|
||||
/>
|
||||
</template>
|
||||
<template #top>
|
||||
<div class="absolute z-[-1] rounded-full bg-(--ui-primary) blur-[300px] size-60 sm:size-80 transform -translate-x-1/2 left-1/2 -translate-y-80" />
|
||||
<StarsBg />
|
||||
</template>
|
||||
|
||||
<LazyStarsBg />
|
||||
|
||||
<div aria-hidden="true" class="hidden lg:block absolute z-[-1] border-x border-(--ui-border) inset-0 mx-4 sm:mx-6 lg:mx-8" />
|
||||
</UPageHero>
|
||||
|
||||
<div v-for="category in categories" :key="category.id">
|
||||
@@ -148,6 +152,7 @@ onMounted(() => {
|
||||
:description="component.description"
|
||||
:to="component.path"
|
||||
:ui="{ wrapper: 'order-last', container: 'lg:flex' }"
|
||||
class="group"
|
||||
>
|
||||
<template #title>
|
||||
<div class="flex items-center gap-0.5">
|
||||
@@ -156,7 +161,7 @@ onMounted(() => {
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div class="group rounded-[calc(var(--ui-radius)*1.5)] border border-(--ui-border-muted) overflow-hidden aspect-[16/9]">
|
||||
<div class="rounded-[calc(var(--ui-radius)*1.5)] border border-(--ui-border-muted) overflow-hidden aspect-[16/9]">
|
||||
<UColorModeImage
|
||||
:light="`${component.path.replace('/components/', '/components/light/')}.png`"
|
||||
:dark="`${component.path.replace('/components/', '/components/dark/')}.png`"
|
||||
|
||||
@@ -8,7 +8,6 @@ hero:
|
||||
links:
|
||||
- label: Purchase Pro Kit
|
||||
to: 'https://nuxt.lemonsqueezy.com/buy/17213c49-621b-4c2c-9478-3a50a099003d'
|
||||
trailing-icon: i-lucide-arrow-right
|
||||
target: _blank
|
||||
- label: Free Figma Kit
|
||||
to: 'https://go.nuxt.com/figma'
|
||||
@@ -121,7 +120,6 @@ section4:
|
||||
links:
|
||||
- label: Get access now
|
||||
to: 'https://nuxt.lemonsqueezy.com/buy/17213c49-621b-4c2c-9478-3a50a099003d'
|
||||
trailing-icon: i-lucide-arrow-right
|
||||
- label: Preview UI Pro Design Kit
|
||||
to: 'https://go.nuxt.com/figma-pro'
|
||||
icon: i-logos-figma
|
||||
@@ -180,6 +178,7 @@ pricing:
|
||||
- title: Solo License
|
||||
description: Design faster with all Nuxt UI Pro components.
|
||||
price: $149
|
||||
# discount: $119
|
||||
billing_period: one-time payment
|
||||
billing_cycle: plus local taxes
|
||||
class: bg-(--ui-bg-elevated)/50
|
||||
@@ -201,6 +200,7 @@ pricing:
|
||||
- title: Team License
|
||||
description: Everything you need to deliver faster as a team.
|
||||
price: $349
|
||||
# discount: $279
|
||||
billing_period: one-time payment
|
||||
billing_cycle: plus local taxes
|
||||
class: bg-(--ui-bg-elevated)/50
|
||||
@@ -277,16 +277,14 @@ faq:
|
||||
content: As the Figma Pro Kit is a digital product packaged as a zip file, we cannot offer refunds once the purchase is made.
|
||||
- label: Do you have a Figma to Code plugin?
|
||||
content: >
|
||||
We recommend the open source [TeamPad Dev](https://github.com/ecomfe/tempad-dev) inspect panel with the [TeamPad Dev Nuxt UI Plugin](https://github.com/Justineo/tempad-dev-plugin-nuxt-ui):
|
||||
We recommend the open source [TemPad Dev](https://github.com/ecomfe/tempad-dev) inspect panel with the [TemPad Dev Nuxt UI Plugin](https://github.com/Justineo/tempad-dev-plugin-nuxt-ui):
|
||||
|
||||
1. Install the [TeamPad Dev Chrome Extension](https://chromewebstore.google.com/detail/tempad-dev/lgoeakbaikpkihoiphamaeopmliaimpc)
|
||||
1. Install the [TemPad Dev Chrome Extension](https://chromewebstore.google.com/detail/tempad-dev/lgoeakbaikpkihoiphamaeopmliaimpc)
|
||||
|
||||
2. Open your Figma file with Nuxt UI components (reload the page if you don't see the TeamPad Dev panel)
|
||||
2. Open your Figma file with Nuxt UI components (reload the page if you don't see the TemPad Dev panel)
|
||||
|
||||
3. Install the `@nuxt` in TeamPad Dev's plugins section
|
||||
3. Install the `@nuxt` (or `@nuxt/pro` for Nuxt UI Pro) in TemPad Dev's plugins section
|
||||
|
||||
4. Select any Nuxt UI component and inspect the code it generates
|
||||
|
||||
{.w-full .rounded .mb-2 .max-w-[636px]}
|
||||
|
||||
*Right now, only Nuxt UI components are supported, but the code of the plugin is [open source](https://github.com/Justineo/tempad-dev-plugin-nuxt-ui) and anyone can contribute to it.*
|
||||
{.w-full .rounded .mb-2 .max-w-[636px]}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
// @ts-expect-error yaml is not typed
|
||||
import page from '.figma.yml'
|
||||
import { animate } from 'motion'
|
||||
import { animate } from 'motion-v'
|
||||
import { joinURL } from 'ufo'
|
||||
|
||||
const { url } = useSiteConfig()
|
||||
@@ -93,10 +93,10 @@ onMounted(async () => {
|
||||
}"
|
||||
>
|
||||
<template #title>
|
||||
<MDC :value="page.hero.title" unwrap="p" />
|
||||
<MDC :value="page.hero.title" unwrap="p" cache-key="figma-hero-title" />
|
||||
</template>
|
||||
<template #description>
|
||||
<MDC :value="page.hero.description" unwrap="p" />
|
||||
<MDC :value="page.hero.description" unwrap="p" cache-key="figma-hero-description" />
|
||||
</template>
|
||||
<!-- <img src="/pro/figma/nuxt-ui-figma.png" alt="Screnshot of the Nuxt UI Figma design kit" class="w-full h-auto border border-(--ui-border) border-b-0"> -->
|
||||
<div class="relative">
|
||||
@@ -140,10 +140,10 @@ onMounted(async () => {
|
||||
class="rounded-none bg-gradient-to-b from-(--ui-bg-muted) to-(--ui-bg)"
|
||||
>
|
||||
<template #title>
|
||||
<MDC :value="page.cta1.title" unwrap="p" />
|
||||
<MDC :value="page.cta1.title" unwrap="p" cache-key="figma-cta-1-title" />
|
||||
</template>
|
||||
<template #description>
|
||||
<MDC :value="page.cta1.description" unwrap="p" />
|
||||
<MDC :value="page.cta1.description" unwrap="p" cache-key="figma-cta-1-description" />
|
||||
</template>
|
||||
</UPageCTA>
|
||||
<UPageSection v-bind="page.section1" orientation="horizontal" :ui="{ container: 'py-16 sm:py-16 lg:py-16' }">
|
||||
@@ -189,7 +189,7 @@ onMounted(async () => {
|
||||
}"
|
||||
>
|
||||
<template #description>
|
||||
<MDC :value="page.section4.description" unwrap="p" />
|
||||
<MDC :value="page.section4.description" unwrap="p" cache-key="figma-section-4-description" />
|
||||
</template>
|
||||
<div aria-hidden="true" class="absolute z-[-1] border-x border-(--ui-border) inset-0 mx-4 sm:mx-6 lg:mx-8" />
|
||||
<ul class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 items-start justify-center border border-(--ui-border) border-b-0 sm:divide-x divide-y lg:divide-y-0 divide-(--ui-border)">
|
||||
@@ -233,6 +233,7 @@ onMounted(async () => {
|
||||
:title="plan.title"
|
||||
:description="plan.description"
|
||||
:price="plan.price"
|
||||
:discount="plan.discount"
|
||||
:billing-period="plan.billing_period"
|
||||
:billing-cycle="plan.billing_cycle"
|
||||
:highlight="plan.highlight"
|
||||
@@ -245,7 +246,7 @@ onMounted(async () => {
|
||||
<template #features>
|
||||
<li v-for="(feature, i) in plan.features" :key="i" class="flex items-center gap-2 min-w-0">
|
||||
<UIcon name="i-lucide-circle-check" class="size-5 shrink-0 text-(--ui-primary)" />
|
||||
<MDC :value="feature" unwrap="p" tag="span" class="text-sm truncate text-(--ui-text-accented)" />
|
||||
<MDC :value="feature" unwrap="p" tag="span" class="text-sm truncate text-(--ui-text-accented)" :cache-key="`figma-pricing-plan-${index}-feature-${i}`" />
|
||||
</li>
|
||||
</template>
|
||||
<template #button>
|
||||
@@ -281,8 +282,8 @@ onMounted(async () => {
|
||||
:items="(page.faq.items as any[])"
|
||||
class="max-w-4xl mx-auto"
|
||||
>
|
||||
<template #body="{ item }">
|
||||
<MDC :value="item.content" unwrap="p" />
|
||||
<template #body="{ item, index }">
|
||||
<MDC :value="item.content" unwrap="p" :cache-key="`figma-faq-${index}-content`" />
|
||||
</template>
|
||||
</UPageAccordion>
|
||||
</UPageSection>
|
||||
|
||||
307
docs/app/pages/index.vue
Normal file
@@ -0,0 +1,307 @@
|
||||
<script setup lang="ts">
|
||||
import { joinURL } from 'ufo'
|
||||
// @ts-expect-error yaml is not typed
|
||||
import page from '.index.yml'
|
||||
|
||||
const { url } = useSiteConfig()
|
||||
|
||||
useSeoMeta({
|
||||
titleTemplate: `%s - Nuxt UI`,
|
||||
title: page.title,
|
||||
description: page.description,
|
||||
ogTitle: `${page.title} - Nuxt UI`,
|
||||
ogDescription: page.description,
|
||||
ogImage: joinURL(url, '/og-image.png')
|
||||
})
|
||||
|
||||
const { data: components } = await useAsyncData('ui-components', () => {
|
||||
return queryCollection('content')
|
||||
.where('path', 'LIKE', '/components/%')
|
||||
.where('extension', '=', 'md')
|
||||
.where('module', 'IS NULL')
|
||||
.select('path', 'title', 'description', 'category', 'module')
|
||||
.all()
|
||||
})
|
||||
|
||||
const { data: module } = await useFetch<{
|
||||
stats: {
|
||||
downloads: number
|
||||
stars: number
|
||||
}
|
||||
contributors: {
|
||||
username: string
|
||||
}[]
|
||||
}>('https://api.nuxt.com/modules/ui', {
|
||||
key: 'stats',
|
||||
transform: ({ stats, contributors }) => ({ stats, contributors })
|
||||
})
|
||||
|
||||
const { format } = Intl.NumberFormat('en', { notation: 'compact' })
|
||||
|
||||
const contributorsRef = ref(null)
|
||||
const isContributorsInView = ref(false)
|
||||
const isContributorsHovered = useElementHover(contributorsRef)
|
||||
|
||||
useIntersectionObserver(contributorsRef, ([entry]) => {
|
||||
isContributorsInView.value = entry?.isIntersecting || false
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UMain>
|
||||
<UPageHero
|
||||
orientation="horizontal"
|
||||
:ui="{
|
||||
container: 'pb-0 sm:pb-0 lg:py-0',
|
||||
title: 'lg:mt-16',
|
||||
links: 'lg:mb-16',
|
||||
description: 'text-balance'
|
||||
}"
|
||||
>
|
||||
<template #title>
|
||||
The Intuitive <br> <span class="text-(--ui-primary)">Vue UI Library</span>
|
||||
</template>
|
||||
<template #description>
|
||||
{{ page.hero.description }}
|
||||
</template>
|
||||
|
||||
<template #links>
|
||||
<UButton v-for="link of page.hero.links" :key="link.label" v-bind="link" size="xl" />
|
||||
<div class="w-full my-6">
|
||||
<USeparator class="w-1/2" type="dashed" />
|
||||
</div>
|
||||
<div class="flex flex-col gap-4">
|
||||
<Motion
|
||||
v-for="(feature, index) in page.hero.features"
|
||||
:key="feature.title"
|
||||
as-child
|
||||
:initial="{ opacity: 0, transform: 'translateX(-10px)' }"
|
||||
:while-in-view="{ opacity: 1, transform: 'translateX(0)' }"
|
||||
:transition="{ delay: 0.2 + 0.4 * index }"
|
||||
:in-view-options="{ once: true }"
|
||||
>
|
||||
<UPageFeature v-bind="feature" class="opacity-0" />
|
||||
</Motion>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<LazySkyBg />
|
||||
|
||||
<div class="h-[344px] lg:h-full lg:relative w-full lg:min-h-[calc(100vh-var(--ui-header-height)-1px)] overflow-hidden">
|
||||
<UPageMarquee
|
||||
pause-on-hover
|
||||
:overlay="false"
|
||||
: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',
|
||||
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
|
||||
v-for="component of components?.slice(0, 10)"
|
||||
:key="component.path"
|
||||
class="relative group/link aspect-video border-(--ui-border) w-[290px] xl:w-[330px] 2xl:w-[320px] 2xl:p-2 2xl:border-y"
|
||||
:to="component.path"
|
||||
>
|
||||
<UColorModeImage
|
||||
|
||||
:light="`${component.path.replace('/components/', '/components/light/')}.png`"
|
||||
:dark="`${component.path.replace('/components/', '/components/dark/')}.png`"
|
||||
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"
|
||||
/>
|
||||
<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>
|
||||
</UPageMarquee>
|
||||
|
||||
<UPageMarquee
|
||||
pause-on-hover
|
||||
reverse
|
||||
:overlay="false"
|
||||
: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',
|
||||
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
|
||||
v-for="component of components?.slice(10, 20)"
|
||||
:key="component.path"
|
||||
class="relative group/link aspect-video border-(--ui-border) w-[290px] xl:w-[330px] 2xl:w-[320px] 2xl:p-2 2xl:border-y"
|
||||
:to="component.path"
|
||||
>
|
||||
<UColorModeImage
|
||||
:light="`${component.path.replace('/components/', '/components/light/')}.png`"
|
||||
:dark="`${component.path.replace('/components/', '/components/dark/')}.png`"
|
||||
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"
|
||||
/>
|
||||
<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>
|
||||
</UPageMarquee>
|
||||
</div>
|
||||
</UPageHero>
|
||||
|
||||
<USeparator />
|
||||
|
||||
<UPageSection :ui="{ container: 'lg:py-16' }">
|
||||
<ul class="grid grid-cols-1 gap-x-6 sm:grid-cols-2 lg:grid-cols-3 gap-y-6 lg:gap-x-8 lg:gap-y-8 xl:gap-y-10">
|
||||
<Motion
|
||||
v-for="(feature, index) in page?.features"
|
||||
:key="feature.title"
|
||||
as="li"
|
||||
:initial="{ opacity: 0, transform: 'translateY(10px)' }"
|
||||
:while-in-view="{ opacity: 1, transform: 'translateY(0)' }"
|
||||
:transition="{ delay: 0.1 * index }"
|
||||
:in-view-options="{ once: true }"
|
||||
class="flex items-start gap-x-3 relative group"
|
||||
>
|
||||
<NuxtLink v-if="feature.to" :to="feature.to" class="absolute inset-0 z-10" />
|
||||
|
||||
<div class="relative p-3">
|
||||
<svg class="absolute inset-0" viewBox="0 0 44 44" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<line x1="6.5" x2="6.5" y2="44" stroke="var(--ui-border)" />
|
||||
<line x1="38.5" x2="38.5" y2="44" stroke="var(--ui-border)" />
|
||||
<line y1="5.5" x2="44" y2="5.5" stroke="var(--ui-border)" />
|
||||
<line y1="37.5" x2="44" y2="37.5" stroke="var(--ui-border)" />
|
||||
<circle cx="6.53613" cy="5.45508" r="1.5" fill="var(--ui-border-accented)" />
|
||||
<circle cx="38.5957" cy="5.45508" r="1.5" fill="var(--ui-border-accented)" />
|
||||
<circle cx="6.53711" cy="37.4551" r="1.5" fill="var(--ui-border-accented)" />
|
||||
<circle cx="38.5957" cy="37.4551" r="1.5" fill="var(--ui-border-accented)" />
|
||||
</svg>
|
||||
<UIcon :name="feature.icon" class="size-5 flex-shrink-0" />
|
||||
</div>
|
||||
<div class="flex flex-col">
|
||||
<h2 class="font-medium text-(--ui-text-highlighted) inline-flex items-center gap-x-1">
|
||||
{{ feature.title }}
|
||||
<UIcon v-if="feature.to" name="i-lucide-arrow-right" class="size-4 flex-shrink-0 opacity-0 group-hover:opacity-100 transition-all duration-200 -translate-x-1 group-hover:translate-x-0" />
|
||||
</h2>
|
||||
<p class="text-sm text-(--ui-text-muted)">
|
||||
{{ feature.description }}
|
||||
</p>
|
||||
</div>
|
||||
</Motion>
|
||||
</ul>
|
||||
</UPageSection>
|
||||
|
||||
<USeparator />
|
||||
|
||||
<UPageSection
|
||||
:title="page.design_system.title"
|
||||
:description="page.design_system.description"
|
||||
:features="page.design_system.features"
|
||||
:links="page.design_system.links"
|
||||
orientation="horizontal"
|
||||
>
|
||||
<MDC :value="page.design_system.code" cache-key="index-design-system-code" />
|
||||
</UPageSection>
|
||||
|
||||
<USeparator />
|
||||
|
||||
<UPageSection
|
||||
:title="page.component_customization.title"
|
||||
:features="page.component_customization.features"
|
||||
:links="page.component_customization.links"
|
||||
orientation="horizontal"
|
||||
>
|
||||
<template #description>
|
||||
<MDC :value="page.component_customization.description" cache-key="index-component-customization-description" />
|
||||
</template>
|
||||
|
||||
<MDC :value="page.component_customization.code" cache-key="index-component-customization-code" />
|
||||
</UPageSection>
|
||||
|
||||
<USeparator />
|
||||
|
||||
<UPageSection
|
||||
:title="page.community.title"
|
||||
:description="page.community.description"
|
||||
:links="page.community.links"
|
||||
orientation="horizontal"
|
||||
:ui="{ features: 'flex items-center gap-4 lg:gap-8' }"
|
||||
class="border-b border-(--ui-border)"
|
||||
>
|
||||
<template #features>
|
||||
<NuxtLink to="https://npm.chart.dev/@nuxt/ui" target="_blank" class="min-w-0">
|
||||
<p class="text-4xl font-semibold text-(--ui-text-highlighted) truncate">
|
||||
{{ format(module?.stats?.downloads ?? 0) }}+
|
||||
</p>
|
||||
<p class="text-(--ui-text-muted) text-sm truncate">monthly downloads</p>
|
||||
</NuxtLink>
|
||||
|
||||
<NuxtLink to="https://github.com/nuxt/ui" target="_blank" class="min-w-0">
|
||||
<p class="text-4xl font-semibold text-(--ui-text-highlighted) truncate">
|
||||
{{ format(module?.stats?.stars ?? 0) }}+
|
||||
</p>
|
||||
<p class="text-(--ui-text-muted) text-sm truncate">GitHub stars</p>
|
||||
</NuxtLink>
|
||||
|
||||
<NuxtLink to="https://github.com/nuxt/ui/graphs/contributors" target="_blank" class="min-w-0">
|
||||
<p class="text-4xl font-semibold text-(--ui-text-highlighted) truncate">
|
||||
175+
|
||||
</p>
|
||||
<p class="text-(--ui-text-muted) text-sm truncate">Contributors</p>
|
||||
</NuxtLink>
|
||||
</template>
|
||||
|
||||
<div ref="contributorsRef" class="p-4 sm:px-6 md:px-8 lg:px-12 xl:px-14 overflow-hidden flex relative">
|
||||
<LazyHomeContributors :contributors="module?.contributors" :paused="!isContributorsInView || isContributorsHovered" />
|
||||
</div>
|
||||
</UPageSection>
|
||||
|
||||
<UPageSection :ui="{ container: 'relative !pb-0 overflow-hidden' }">
|
||||
<template #title>
|
||||
Build faster with Nuxt UI <span class="text-(--ui-primary)">Pro</span>.
|
||||
</template>
|
||||
<template #description>
|
||||
A collection of premium Vue components, composables and utils built on top of Nuxt UI. <br> Focused on structure and layout, these <span class="text-(--ui-text)">responsive components</span> are designed to be the perfect <span class="text-(--ui-text)">building blocks for your next idea</span>.
|
||||
</template>
|
||||
<template #links>
|
||||
<UButton to="/pro" size="lg">
|
||||
Discover Nuxt UI Pro
|
||||
</UButton>
|
||||
<UButton to="/pro/templates" size="lg" variant="outline" trailing-icon="i-lucide-arrow-right" color="neutral">
|
||||
Explore templates
|
||||
</UButton>
|
||||
</template>
|
||||
|
||||
<LazyStarsBg />
|
||||
|
||||
<div aria-hidden="true" class="hidden lg:block absolute z-[-1] border-x border-(--ui-border) inset-0 mx-4 sm:mx-6 lg:mx-8" />
|
||||
<div class="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">
|
||||
<UPageMarquee reverse orientation="vertical" :overlay="false" :ui="{ root: '[--duration:40s] absolute w-[460px] -left-[100px] -top-[300px] h-[940px] transform-3d rotate-x-55 rotate-y-0 rotate-z-30' }">
|
||||
<img
|
||||
v-for="i in 4"
|
||||
:key="i"
|
||||
:src="`/pro/blocks/image${i}.png`"
|
||||
width="460"
|
||||
height="258"
|
||||
loading="lazy"
|
||||
:alt="`Nuxt UI Pro Screenshot ${i}`"
|
||||
class="aspect-video border border-(--ui-border) rounded-[calc(var(--ui-radius)*2)] bg-white"
|
||||
>
|
||||
</UPageMarquee>
|
||||
<UPageMarquee orientation="vertical" :overlay="false" :ui="{ root: '[--duration:40s] absolute w-[460px] -top-[400px] left-[480px] h-[1160px] transform-3d rotate-x-55 rotate-y-0 rotate-z-30' }">
|
||||
<img
|
||||
v-for="i in [5, 6, 7, 8]"
|
||||
:key="i"
|
||||
:src="`/pro/blocks/image${i}.png`"
|
||||
width="460"
|
||||
height="258"
|
||||
loading="lazy"
|
||||
:alt="`Nuxt UI Pro Screenshot ${i}`"
|
||||
class="aspect-video border border-(--ui-border) rounded-[calc(var(--ui-radius)*2)] bg-white"
|
||||
>
|
||||
</UPageMarquee>
|
||||
<UPageMarquee reverse orientation="vertical" :overlay="false" :ui="{ root: 'hidden md:flex [--duration:40s] absolute w-[460px] -top-[300px] left-[1020px] h-[1060px] transform-3d rotate-x-55 rotate-y-0 rotate-z-30' }">
|
||||
<img
|
||||
v-for="i in [9, 10, 11, 12]"
|
||||
:key="i"
|
||||
:src="`/pro/blocks/image${i}.png`"
|
||||
width="460"
|
||||
height="258"
|
||||
:alt="`Nuxt UI Pro Screenshot ${i}`"
|
||||
loading="lazy"
|
||||
class="aspect-video border border-(--ui-border) rounded-[calc(var(--ui-radius)*2)] bg-white"
|
||||
>
|
||||
</UPageMarquee>
|
||||
</div>
|
||||
</UPageSection>
|
||||
</UMain>
|
||||
</template>
|
||||
@@ -17,7 +17,10 @@ pricing:
|
||||
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.
|
||||
orientation: horizontal
|
||||
price: $149 - $349
|
||||
price: $149
|
||||
# discount: $119
|
||||
billing_period: one-time payment
|
||||
billing_cycle: plus local taxes
|
||||
terms: Solo & Team licenses available.
|
||||
features:
|
||||
- 1700+ components & variants from Nuxt UI & UI Pro
|
||||
@@ -29,13 +32,14 @@ pricing:
|
||||
- Free [preview available](https://www.figma.com/design/mxXR9binOSLU3rYKZZRPXs/PREVIEW---NuxtUIPro-V3-BETA?m=auto&t=c4598Wr0rZwKPs5M-1)
|
||||
- Includes Nuxt UI [Figma Kit](https://www.figma.com/community/file/1288455405058138934)
|
||||
button:
|
||||
label: Explore Figma Kit Pricing
|
||||
label: Buy Figma Kit
|
||||
to: 'https://nuxt.lemonsqueezy.com/buy/17213c49-621b-4c2c-9478-3a50a099003d'
|
||||
color: 'neutral'
|
||||
plans:
|
||||
- title: Solo
|
||||
description: Tailored for indie hackers, freelancers and solo founders.
|
||||
price: $249
|
||||
# discount: $199
|
||||
billing_period: one-time payment
|
||||
billing_cycle: plus local taxes
|
||||
features:
|
||||
@@ -50,6 +54,7 @@ pricing:
|
||||
- title: Startup
|
||||
description: Best suited for small teams, startups and agencies.
|
||||
price: $499
|
||||
# discount: $399
|
||||
billing_period: one-time payment
|
||||
billing_cycle: plus local taxes
|
||||
features:
|
||||
@@ -65,6 +70,7 @@ pricing:
|
||||
- title: Organization
|
||||
description: Ideal for larger teams and organizations.
|
||||
price: $999
|
||||
# discount: $799
|
||||
billing_period: one-time payment
|
||||
billing_cycle: plus local taxes
|
||||
features:
|
||||
@@ -119,12 +125,12 @@ testimonials:
|
||||
to: 'https://www.linkedin.com/in/anthonybettini/'
|
||||
target: _blank
|
||||
avatar:
|
||||
src: 'https://media.licdn.com/dms/image/v2/C4E03AQEY3pmXsH8hDg/profile-displayphoto-shrink_200_200/profile-displayphoto-shrink_200_200/0/1519741249602?e=1743638400&v=beta&t=lw2K6vS0OOCZWGtHY1buJVkRItQCa4OQw0vzAhhpJk8'
|
||||
src: 'https://media.licdn.com/dms/image/v2/C4E03AQEY3pmXsH8hDg/profile-displayphoto-shrink_800_800/profile-displayphoto-shrink_800_800/0/1519741249442?e=1746057600&v=beta&t=dvQfBT9ah03MPNy9cnly30ugreeCdxG4nrxV3lwKAC8'
|
||||
- quote: "Wow, Nuxt UI Pro is a total game-changer! I'm seriously impressed with the quality, attention to detail, and the insane variety of components you get. It's like hitting the jackpot for any developer. I've saved countless hours that I would've spent stressing over making my apps look good, with amazing accessible UX, and instead, I've been able to focus on the real deal – building the app itself. It's an instant buy for me, every single time. No second thoughts!"
|
||||
user:
|
||||
name: 'Yaz Jallad'
|
||||
description: 'Founder Ninjaparade Digital'
|
||||
to: 'https://twitter.com/ninjaparade/'
|
||||
to: 'https://x.com/ninjaparade/'
|
||||
target: _blank
|
||||
avatar:
|
||||
src: 'https://pbs.twimg.com/profile_images/1824690890222485504/lQ7v1AGt_400x400.jpg'
|
||||
@@ -158,8 +164,8 @@ testimonials:
|
||||
- quote: "I jumped at the chance to buy the Nuxt team's new UI kit as soon as I saw it. While I'm already a fan of Nuxt UI, the pro version takes it to a whole new level and lets me paste entire blocks into all my projects, saving me a ton of time."
|
||||
user:
|
||||
name: 'Thomas Sanlis'
|
||||
description: 'Freelance developer and designer'
|
||||
to: 'https://twitter.com/T_Zahil'
|
||||
description: 'Founder of Uneed'
|
||||
to: 'https://x.com/T_Zahil'
|
||||
target: _blank
|
||||
avatar:
|
||||
src: 'https://pbs.twimg.com/profile_images/1374040164180299791/ACw4G3nZ_400x400.jpg'
|
||||
@@ -167,23 +173,31 @@ testimonials:
|
||||
user:
|
||||
name: 'Benjamin Code'
|
||||
description: 'YouTuber and SaaS builder'
|
||||
to: 'https://twitter.com/benjamincode'
|
||||
to: 'https://x.com/benjamincode'
|
||||
target: _blank
|
||||
avatar:
|
||||
src: 'https://pbs.twimg.com/profile_images/1607353032420769793/I8qQSUfQ_400x400.jpg'
|
||||
- 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:
|
||||
name: 'Estéban Soubiran'
|
||||
description: 'Web developer and UnJS member'
|
||||
to: 'https://twitter.com/soubiran_'
|
||||
description: 'Software engineer'
|
||||
to: 'https://x.com/soubiran_'
|
||||
target: _blank
|
||||
avatar:
|
||||
src: 'https://pbs.twimg.com/profile_images/1801649350319218689/aS_X_iTm_400x400.jpg'
|
||||
- quote: "I used to code all my components from scratch, but since I started using Nuxt UI Pro, I just can’t work without it. It has all the components I need: for landing pages, for dashboards and even for blog content! This is a no-brainer investment to ship faster, and I’ve already made my money back 10x in time saved!"
|
||||
user:
|
||||
name: 'Nico Jeannen'
|
||||
description: 'Founder of Ads Template'
|
||||
to: 'https://x.com/nico_jeannen'
|
||||
target: _blank
|
||||
avatar:
|
||||
src: 'https://pbs.twimg.com/profile_images/1754025659180187649/AAG78n19_400x400.jpg'
|
||||
- quote: "As someone who builds a lot of projects, Nuxt UI Pro has been a game-changer. It's not just about saving time – it's about having components that are thoughtfully designed and just work. The developer experience is exceptional, and I can focus on building features instead of tweaking UI components."
|
||||
user:
|
||||
name: 'Hugo Richard'
|
||||
description: 'Frontend Engineer at NuxtLabs'
|
||||
to: 'https://twitter.com/hugorcd__'
|
||||
description: 'Founder of Shelve'
|
||||
to: 'https://x.com/hugorcd__'
|
||||
target: _blank
|
||||
avatar:
|
||||
src: 'https://ipx.nuxt.com/f_auto,s_40x40/gh_avatar/hugorcd'
|
||||
|
||||
@@ -7,13 +7,13 @@ hero:
|
||||
- label: Buy a license
|
||||
size: xl
|
||||
to: /pro/pricing
|
||||
trailing-icon: i-lucide-arrow-right
|
||||
- label: Get started
|
||||
- label: Try for free
|
||||
trailing: true
|
||||
color: neutral
|
||||
variant: ghost
|
||||
variant: outline
|
||||
to: /getting-started/installation/pro/nuxt
|
||||
size: xl
|
||||
trailingIcon: i-lucide-arrow-right
|
||||
features:
|
||||
title: Create stunning Vue applications faster.
|
||||
description: Nuxt UI Pro comes packed with powerful features to help you build modern, performant, accessible and responsive Nuxt applications at record speed. From pre-built UI sections to Figma design kits, every detail is crafted to speed up your development and deliver a polished user experience.
|
||||
@@ -157,8 +157,8 @@ cta:
|
||||
links:
|
||||
- label: Buy a license
|
||||
to: '/pro/pricing'
|
||||
trailing-icon: i-lucide-arrow-right
|
||||
- label: Get started
|
||||
to: '/getting-started/license'
|
||||
variant: ghost
|
||||
- label: Try for free
|
||||
to: /getting-started/installation/pro/nuxt
|
||||
variant: outline
|
||||
color: neutral
|
||||
trailingIcon: i-lucide-arrow-right
|
||||
|
||||
@@ -5,16 +5,16 @@ hero:
|
||||
description: 'Ready to use templates powered by our premium Vue components and Nuxt Content.<br class="hidden lg:block"> The templates are responsive, accessible and easy to customize so you can get started in no time.'
|
||||
navigation: false
|
||||
links:
|
||||
- label: Get started
|
||||
to: /getting-started/installation/pro/nuxt#use-an-official-template
|
||||
color: neutral
|
||||
- label: Buy a license
|
||||
color: primary
|
||||
size: xl
|
||||
trailingIcon: i-lucide-arrow-right
|
||||
- label: Purchase a license
|
||||
to: /pro/pricing
|
||||
- label: Try for free
|
||||
to: /getting-started/installation/pro/nuxt#use-an-official-template
|
||||
size: xl
|
||||
color: neutral
|
||||
variant: outline
|
||||
to: /pro/pricing
|
||||
trailingIcon: i-lucide-arrow-right
|
||||
templates:
|
||||
- title: 'Dashboard'
|
||||
description: "A template to illustrate how to build your own dashboard with the 15+ latest Nuxt UI Pro components, designed specifically to create a consistent look and feel."
|
||||
@@ -30,13 +30,26 @@ templates:
|
||||
- title: Resizable multi-column layout
|
||||
icon: i-lucide-columns-3
|
||||
links:
|
||||
- label: Live preview
|
||||
- label: Preview
|
||||
to: https://dashboard-template.nuxt.dev
|
||||
target: _blank
|
||||
leadingIcon: i-logos-nuxt-icon
|
||||
trailingIcon: i-lucide-arrow-up-right
|
||||
color: neutral
|
||||
- label: Use this template
|
||||
to: https://github.com/nuxt-ui-pro/dashboard/tree/v3
|
||||
- label: Nuxt Template
|
||||
to: https://github.com/nuxt-ui-pro/dashboard
|
||||
target: _blank
|
||||
icon: i-simple-icons-github
|
||||
color: neutral
|
||||
variant: outline
|
||||
- label: Preview
|
||||
to: https://vue-dashboard-template.nuxt.dev
|
||||
target: _blank
|
||||
leadingIcon: i-logos-vue
|
||||
trailingIcon: i-lucide-arrow-up-right
|
||||
color: neutral
|
||||
- label: Vue Template
|
||||
to: https://github.com/nuxt-ui-pro/dashboard-vue
|
||||
target: _blank
|
||||
icon: i-simple-icons-github
|
||||
color: neutral
|
||||
@@ -55,13 +68,14 @@ templates:
|
||||
- title: Authentication pages (login, register)
|
||||
icon: i-lucide-user-round-check
|
||||
links:
|
||||
- label: Live preview
|
||||
- label: Preview
|
||||
to: https://saas-template.nuxt.dev
|
||||
target: _blank
|
||||
leadingIcon: i-logos-nuxt-icon
|
||||
trailingIcon: i-lucide-arrow-up-right
|
||||
color: neutral
|
||||
- label: Use this template
|
||||
to: https://github.com/nuxt-ui-pro/saas/tree/v3
|
||||
- label: Nuxt Template
|
||||
to: https://github.com/nuxt-ui-pro/saas
|
||||
target: _blank
|
||||
variant: outline
|
||||
icon: i-simple-icons-github
|
||||
@@ -80,13 +94,14 @@ templates:
|
||||
- title: Write content in YAML
|
||||
icon: i-simple-icons-yaml
|
||||
links:
|
||||
- label: Live preview
|
||||
- label: Preview
|
||||
to: https://landing-template.nuxt.dev
|
||||
target: _blank
|
||||
leadingIcon: i-logos-nuxt-icon
|
||||
trailingIcon: i-lucide-arrow-up-right
|
||||
color: neutral
|
||||
- label: Use this template
|
||||
to: https://github.com/nuxt-ui-pro/landing/tree/v3
|
||||
- label: Nuxt Template
|
||||
to: https://github.com/nuxt-ui-pro/landing
|
||||
target: _blank
|
||||
icon: i-simple-icons-github
|
||||
color: neutral
|
||||
@@ -105,14 +120,51 @@ templates:
|
||||
- title: Full-text search out of the box
|
||||
icon: i-lucide-search
|
||||
links:
|
||||
- label: Live preview
|
||||
- label: Preview
|
||||
to: https://docs-template.nuxt.dev
|
||||
target: _blank
|
||||
leadingIcon: i-logos-nuxt-icon
|
||||
trailingIcon: i-lucide-arrow-up-right
|
||||
color: neutral
|
||||
- label: Use this template
|
||||
- label: Nuxt Template
|
||||
to: https://github.com/nuxt-ui-pro/docs/tree/v3
|
||||
target: _blank
|
||||
variant: outline
|
||||
icon: i-simple-icons-github
|
||||
color: neutral
|
||||
- title: 'Starter'
|
||||
description: "A minimal starter template to build your own project with Nuxt UI Pro components."
|
||||
icon: i-lucide-flower
|
||||
thumbnail:
|
||||
dark: https://assets.hub.nuxt.com/eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1cmwiOiJodHRwczovL3VpLXByby1zdGFydGVyLm51eHQuZGV2IiwiaWF0IjoxNzM5NDYzMzk4fQ.XLzPkSW6nRbPW07QO1RkMwz_RAPA4KfeyrWrK3li9YI.jpg?theme=dark
|
||||
light: https://assets.hub.nuxt.com/eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1cmwiOiJodHRwczovL3VpLXByby1zdGFydGVyLm51eHQuZGV2IiwiaWF0IjoxNzM5NDYzMzk4fQ.XLzPkSW6nRbPW07QO1RkMwz_RAPA4KfeyrWrK3li9YI.jpg?theme=light
|
||||
features:
|
||||
- title: ESLint Configured
|
||||
icon: i-simple-icons-eslint
|
||||
- title: Nuxt 4 Compatibility Enabled
|
||||
icon: i-simple-icons-nuxtdotjs
|
||||
links:
|
||||
- label: Preview
|
||||
to: https://ui-pro-starter.nuxt.dev
|
||||
target: _blank
|
||||
leadingIcon: i-logos-nuxt-icon
|
||||
trailingIcon: i-lucide-arrow-up-right
|
||||
color: neutral
|
||||
- label: Nuxt Template
|
||||
to: https://github.com/nuxt-ui-pro/starter
|
||||
target: _blank
|
||||
variant: outline
|
||||
icon: i-simple-icons-github
|
||||
color: neutral
|
||||
- label: Preview
|
||||
to: https://ui-pro-starter-vue.nuxt.dev
|
||||
target: _blank
|
||||
leadingIcon: i-logos-vue
|
||||
trailingIcon: i-lucide-arrow-up-right
|
||||
color: neutral
|
||||
- label: Vue Template
|
||||
to: https://github.com/nuxt-ui-pro/starter-vue
|
||||
target: _blank
|
||||
variant: outline
|
||||
icon: i-simple-icons-github
|
||||
color: neutral
|
||||
|
||||
@@ -70,14 +70,13 @@ onMounted(() => {
|
||||
|
||||
<template>
|
||||
<UMain>
|
||||
<UPageHero headline="License Activation" :title="title" :description="description" :ui="{ container: 'relative' }">
|
||||
<template #top>
|
||||
<StarsBg />
|
||||
</template>
|
||||
<UPageHero headline="License Activation" :title="title" :description="description" :ui="{ container: 'relative overflow-hidden', wrapper: 'lg:px-12', description: 'text-pretty' }">
|
||||
<LazyStarsBg />
|
||||
|
||||
<div aria-hidden="true" class="hidden lg:block absolute z-[-1] border-x border-(--ui-border) inset-0 mx-4 sm:mx-6 lg:mx-8" />
|
||||
|
||||
<div class="lg:border-y border-(--ui-border)">
|
||||
<UCard class="lg:w-1/2 m-auto lg:rounded-none overflow-hidden" variant="outline" :ui="{ footer: 'bg-(--ui-bg-muted)' }">
|
||||
<div class="px-4 py-10 lg:border border-(--ui-border) bg-(--ui-bg)">
|
||||
<div class="max-w-xl mx-auto">
|
||||
<UForm
|
||||
:schema="schema"
|
||||
:validate-on="['blur']"
|
||||
@@ -107,12 +106,13 @@ onMounted(() => {
|
||||
</UAlert>
|
||||
<UAlert v-else-if="errorMessage" color="error" variant="subtle" :title="errorMessage" />
|
||||
</UForm>
|
||||
<template #footer>
|
||||
<p class="text-sm text-center text-neutral-500 dark:text-neutral-400">
|
||||
If you purchased a license with multiple seats, activate the license key for each member of your team.
|
||||
</p>
|
||||
</template>
|
||||
</UCard>
|
||||
|
||||
<ProseHr />
|
||||
|
||||
<ProseNote>
|
||||
If you purchased a license with multiple seats, activate the license key for each member of your team.
|
||||
</ProseNote>
|
||||
</div>
|
||||
</div>
|
||||
</UPageHero>
|
||||
</UMain>
|
||||
|
||||
@@ -26,21 +26,52 @@ useSeoMeta({
|
||||
}"
|
||||
>
|
||||
<template #title>
|
||||
<MDC :value="page.hero.title" unwrap="p" />
|
||||
<MDC :value="page.hero.title" tag="span" unwrap="p" cache-key="pro-hero-title" />
|
||||
</template>
|
||||
<template #description>
|
||||
<MDC :value="page.hero.description" unwrap="p" />
|
||||
</template>
|
||||
<template #top>
|
||||
<StarsBg />
|
||||
<MDC :value="page.hero.description" tag="span" unwrap="p" cache-key="pro-hero-description" />
|
||||
</template>
|
||||
|
||||
<LazyStarsBg />
|
||||
|
||||
<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" />
|
||||
</Motion>
|
||||
<Motion as-child :initial="{ opacity: 0 }" :animate="{ opacity: 1 }" :transition="{ delay: 0.6, duration: 0.6 }">
|
||||
<NuxtImg src="/pro/hero.png" width="1374" height="439" alt="Nuxt UI Pro" class="w-full border-t border-x border-(--ui-border) bg-(--ui-bg-muted)" />
|
||||
</Motion>
|
||||
<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">
|
||||
<UPageMarquee reverse orientation="vertical" :overlay="false" :ui="{ root: '[--duration:40s] absolute w-[460px] -left-[100px] -top-[300px] h-[940px] transform-3d rotate-x-55 rotate-y-0 rotate-z-30' }">
|
||||
<img
|
||||
v-for="i in 4"
|
||||
:key="i"
|
||||
:src="`/pro/blocks/image${i}.png`"
|
||||
width="460"
|
||||
height="258"
|
||||
:alt="`Nuxt UI Pro Screenshot ${i}`"
|
||||
class="aspect-video border border-(--ui-border) rounded-[calc(var(--ui-radius)*2)] bg-white"
|
||||
>
|
||||
</UPageMarquee>
|
||||
<UPageMarquee orientation="vertical" :overlay="false" :ui="{ root: '[--duration:40s] absolute w-[460px] -top-[400px] left-[480px] h-[1160px] transform-3d rotate-x-55 rotate-y-0 rotate-z-30' }">
|
||||
<img
|
||||
v-for="i in [5, 6, 7, 8]"
|
||||
:key="i"
|
||||
:src="`/pro/blocks/image${i}.png`"
|
||||
width="460"
|
||||
height="258"
|
||||
:alt="`Nuxt UI Pro Screenshot ${i}`"
|
||||
class="aspect-video border border-(--ui-border) rounded-[calc(var(--ui-radius)*2)] bg-white"
|
||||
>
|
||||
</UPageMarquee>
|
||||
<UPageMarquee reverse orientation="vertical" :overlay="false" :ui="{ root: 'hidden md:flex [--duration:40s] absolute w-[460px] -top-[300px] left-[1020px] h-[1060px] transform-3d rotate-x-55 rotate-y-0 rotate-z-30' }">
|
||||
<img
|
||||
v-for="i in [9, 10, 11, 12]"
|
||||
:key="i"
|
||||
:src="`/pro/blocks/image${i}.png`"
|
||||
width="460"
|
||||
height="258"
|
||||
:alt="`Nuxt UI Pro Screenshot ${i}`"
|
||||
class="aspect-video border border-(--ui-border) rounded-[calc(var(--ui-radius)*2)] bg-white"
|
||||
>
|
||||
</UPageMarquee>
|
||||
</div>
|
||||
</UPageHero>
|
||||
<UPageCTA
|
||||
variant="outline"
|
||||
@@ -51,11 +82,11 @@ useSeoMeta({
|
||||
}"
|
||||
>
|
||||
<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 }">
|
||||
<MDC :value="page.testimonial.quote" unwrap="p" class="before:content-[open-quote] after:content-[close-quote] " />
|
||||
<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" />
|
||||
</Motion>
|
||||
</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
|
||||
v-bind="page.testimonial.user"
|
||||
class="justify-center"
|
||||
@@ -72,7 +103,7 @@ useSeoMeta({
|
||||
}"
|
||||
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" />
|
||||
</Motion>
|
||||
</UPageSection>
|
||||
@@ -85,13 +116,13 @@ useSeoMeta({
|
||||
wrapper: 'grid grid-cols-1 lg:grid-cols-2',
|
||||
description: 'lg:mt-0' }"
|
||||
orientation="horizontal"
|
||||
class="rounded-none border-t border-(--ui-border) bg-gradient-to-b from-(--ui-bg-muted) to-(--ui-bg)"
|
||||
class="rounded-none border-t border-(--ui-border) bg-gradient-to-b from-(--ui-bg-elevated)/50 to-(--ui-bg)"
|
||||
>
|
||||
<template #title>
|
||||
<MDC :value="page.mainSection.title" unwrap="p" />
|
||||
<MDC :value="page.mainSection.title" tag="span" unwrap="p" cache-key="pro-main-section-title" />
|
||||
</template>
|
||||
<template #description>
|
||||
<MDC :value="page.mainSection.description" unwrap="p" />
|
||||
<MDC :value="page.mainSection.description" tag="span" unwrap="p" cache-key="pro-main-section-description" />
|
||||
</template>
|
||||
</UPageCTA>
|
||||
<UPageSection
|
||||
@@ -108,7 +139,7 @@ useSeoMeta({
|
||||
container: index === 0 ? 'pb-0 sm:pb-0 lg:pb-0 py-16 sm:py-16 lg:py-16' : ''
|
||||
}"
|
||||
>
|
||||
<MDC :value="section.code" />
|
||||
<MDC :value="section.code" :cache-key="`pro-section-${index}-code`" />
|
||||
</UPageSection>
|
||||
|
||||
<UPageSection
|
||||
@@ -165,7 +196,8 @@ useSeoMeta({
|
||||
class="overflow-hidden"
|
||||
orientation="horizontal"
|
||||
>
|
||||
<StarsBg />
|
||||
<LazyStarsBg />
|
||||
|
||||
<video
|
||||
class="rounded-[var(--ui-radius)] z-10"
|
||||
preload="none"
|
||||
|
||||
@@ -24,12 +24,13 @@ useSeoMeta({
|
||||
}"
|
||||
>
|
||||
<template #title>
|
||||
<MDC :value="page.pricing.title" unwrap="p" />
|
||||
</template>
|
||||
<template #top>
|
||||
<StarsBg />
|
||||
<MDC :value="page.pricing.title" unwrap="p" cache-key="pro-pricing-title" />
|
||||
</template>
|
||||
|
||||
<LazyStarsBg />
|
||||
|
||||
<div aria-hidden="true" class="hidden lg:block absolute z-[-1] border-x border-(--ui-border) inset-0 mx-4 sm:mx-6 lg:mx-8" />
|
||||
|
||||
<div class="flex flex-col bg-(--ui-bg) gap-8 lg:gap-0">
|
||||
<UPricingPlan
|
||||
v-bind="page.pricing.freePlan"
|
||||
@@ -43,6 +44,7 @@ useSeoMeta({
|
||||
:title="plan.title"
|
||||
:description="plan.description"
|
||||
:price="plan.price"
|
||||
:discount="plan.discount"
|
||||
:billing-period="plan.billing_period"
|
||||
:billing-cycle="plan.billing_cycle"
|
||||
:variant="plan.highlight ? 'soft' : 'outline'"
|
||||
@@ -54,12 +56,14 @@ useSeoMeta({
|
||||
<UPricingPlan
|
||||
v-bind="page.pricing.figma"
|
||||
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)"
|
||||
>
|
||||
<template #features>
|
||||
<li v-for="(feature, index) in page.pricing.figma.features" :key="index" class="flex items-center gap-2 min-w-0">
|
||||
<UIcon name="i-lucide-circle-check" class="size-5 text-(--ui-primary) shrink-0" />
|
||||
<MDC :value="feature" unwrap="p" class="text-sm truncate text-(--ui-text-toned)" />
|
||||
<MDC :value="feature" unwrap="p" class="text-sm truncate text-(--ui-text-toned)" :cache-key="`pro-pricing-figma-feature-${index}`" />
|
||||
</li>
|
||||
</template>
|
||||
</UPricingPlan>
|
||||
@@ -111,8 +115,8 @@ useSeoMeta({
|
||||
:items="(page.faq.items as any[])"
|
||||
class="max-w-4xl mx-auto"
|
||||
>
|
||||
<template #body="{ item }">
|
||||
<MDC :value="item.content" unwrap="p" />
|
||||
<template #body="{ item, index }">
|
||||
<MDC :value="item.content" unwrap="p" :cache-key="`pro-pricing-faq-${index}-content`" />
|
||||
</template>
|
||||
</UPageAccordion>
|
||||
</UPageSection>
|
||||
|
||||
@@ -16,59 +16,61 @@ useSeoMeta({
|
||||
|
||||
<!-- eslint-disable vue/no-v-html -->
|
||||
<template>
|
||||
<UPageHero :links="page.links" :ui="{ container: 'relative' }">
|
||||
<template #top>
|
||||
<StarsBg />
|
||||
</template>
|
||||
<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">
|
||||
<UPageHero :links="page.links" :ui="{ container: 'relative' }">
|
||||
<LazyStarsBg />
|
||||
|
||||
<template #title>
|
||||
<MDC :value="page.hero.title" unwrap="p" />
|
||||
</template>
|
||||
<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 #description>
|
||||
<MDC :value="page.hero.description" unwrap="p" />
|
||||
</template>
|
||||
</UPageHero>
|
||||
<template #title>
|
||||
<MDC :value="page.hero.title" unwrap="p" cache-key="pro-templates-hero-title" />
|
||||
</template>
|
||||
|
||||
<UPageSection
|
||||
v-for="(template, index) in page.templates"
|
||||
:key="index"
|
||||
:title="template.title"
|
||||
:links="template.links"
|
||||
:features="template.features"
|
||||
orientation="horizontal"
|
||||
class="lg:border-t border-(--ui-border)"
|
||||
:ui="{
|
||||
title: 'lg:text-4xl',
|
||||
wrapper: 'lg:py-16 lg:border-r border-(--ui-border) order-last lg:pr-16',
|
||||
container: 'lg:py-0'
|
||||
}"
|
||||
>
|
||||
<template #description>
|
||||
<MDC :value="template.description" unwrap="p" />
|
||||
</template>
|
||||
<template #description>
|
||||
<MDC :value="page.hero.description" unwrap="p" cache-key="pro-templates-hero-description" />
|
||||
</template>
|
||||
</UPageHero>
|
||||
|
||||
<div class="lg:border-x border-(--ui-border) h-full flex items-center lg:bg-(--ui-bg-muted)/20">
|
||||
<Motion :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 }">
|
||||
<UColorModeImage
|
||||
v-if="template.thumbnail"
|
||||
v-bind="template.thumbnail"
|
||||
class="w-full h-auto border lg:border-y lg:border-x-0 border-(--ui-border) rounded-(--ui-radius) lg:rounded-none"
|
||||
width="656"
|
||||
height="369"
|
||||
loading="lazy"
|
||||
/>
|
||||
<UCarousel
|
||||
v-else-if="template.images"
|
||||
v-slot="{ item }"
|
||||
:items="(template.images as any[])"
|
||||
dots
|
||||
>
|
||||
<NuxtImg v-bind="item" class="w-full h-full object-cover" width="576" height="360" />
|
||||
</UCarousel>
|
||||
<Placeholder v-else class="w-full h-full aspect-video" />
|
||||
</Motion>
|
||||
</div>
|
||||
</UPageSection>
|
||||
<UPageSection
|
||||
v-for="(template, index) in page.templates"
|
||||
:key="index"
|
||||
:title="template.title"
|
||||
:links="template.links"
|
||||
:features="template.features"
|
||||
orientation="horizontal"
|
||||
class="lg:border-t border-(--ui-border)"
|
||||
:ui="{
|
||||
title: 'lg:text-4xl',
|
||||
wrapper: 'lg:py-16 lg:border-r border-(--ui-border) order-last lg:pr-16',
|
||||
container: 'lg:py-0',
|
||||
links: 'gap-x-3'
|
||||
}"
|
||||
>
|
||||
<template #description>
|
||||
<MDC :value="template.description" unwrap="p" :cache-key="`pro-templates-${index}-description`" />
|
||||
</template>
|
||||
|
||||
<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)' }" :while-in-view="{ opacity: 1, transform: 'translateY(0px)' }" :in-view-options="{ once: true }" :transition="{ duration: 0.5, delay: 0.2 }">
|
||||
<UColorModeImage
|
||||
v-if="template.thumbnail"
|
||||
v-bind="template.thumbnail"
|
||||
class="w-full h-auto border lg:border-y lg:border-x-0 border-(--ui-border) rounded-(--ui-radius) lg:rounded-none"
|
||||
width="656"
|
||||
height="369"
|
||||
loading="lazy"
|
||||
/>
|
||||
<UCarousel
|
||||
v-else-if="template.images"
|
||||
v-slot="{ item }"
|
||||
:items="(template.images as any[])"
|
||||
dots
|
||||
>
|
||||
<NuxtImg v-bind="item" class="w-full h-full object-cover" width="576" height="360" />
|
||||
</UCarousel>
|
||||
<Placeholder v-else class="w-full h-full aspect-video" />
|
||||
</Motion>
|
||||
</div>
|
||||
</UPageSection>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -3,7 +3,7 @@ const title = 'Roadmap'
|
||||
const description = 'Discover our Volta board for @nuxt/ui development status.'
|
||||
|
||||
useSeoMeta({
|
||||
titleTemplate: '%s - Nuxt UI v3',
|
||||
titleTemplate: '%s - Nuxt UI',
|
||||
title,
|
||||
ogTitle: 'Nuxt UI Roadmap',
|
||||
description
|
||||
|
||||
@@ -41,16 +41,16 @@ export default defineNuxtPlugin({
|
||||
const primaryColor = localStorage.getItem('nuxt-ui-primary');
|
||||
if (primaryColor !== 'black') {
|
||||
html = html.replace(
|
||||
/(--ui-color-primary-\\d{2,3}:\\s*var\\()--color-${appConfig.ui.colors.primary}-(\\d{2,3}\\))/g,
|
||||
\`$1--color-\${primaryColor}-$2\`
|
||||
/(--ui-color-primary-\\d{2,3}:\\s*var\\(--color-)${appConfig.ui.colors.primary}(-\\d{2,3}.*?\\))/g,
|
||||
\`$1\${primaryColor}$2\`
|
||||
);
|
||||
}
|
||||
}
|
||||
if (localStorage.getItem('nuxt-ui-neutral')) {
|
||||
let neutralColor = localStorage.getItem('nuxt-ui-neutral');
|
||||
html = html.replace(
|
||||
/(--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\`
|
||||
/(--ui-color-neutral-\\d{2,3}:\\s*var\\(--color-)${appConfig.ui.colors.neutral}(-\\d{2,3}.*?\\))/g,
|
||||
\`$1\${neutralColor === 'neutral' ? 'old-neutral' : neutralColor}$2\`
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,17 +1,12 @@
|
||||
---
|
||||
navigation.title: Introduction
|
||||
title: Nuxt UI v3
|
||||
description: 'A comprehensive, Nuxt-integrated UI library providing a rich set of fully-styled, accessible and highly customizable components for building modern web applications.'
|
||||
title: Introduction
|
||||
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.'
|
||||
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>
|
||||
|
||||
### Reka UI (Radix Vue)
|
||||
### 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:
|
||||
|
||||
@@ -24,15 +19,15 @@ This transition empowers Nuxt UI to become a more comprehensive and flexible UI
|
||||
|
||||
### 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.
|
||||
- **Unified toolchain**: Built-in import handling, vendor prefixing, and syntax transforms, with no additional tooling required.
|
||||
- **CSS-first configuration**: A reimagined developer experience where you customize and extend the framework directly in CSS instead of a JavaScript configuration file.
|
||||
- **Designed for the modern web**: Built on native cascade layers, wide-gamut colors, and including first-class support for modern CSS features like container queries, @starting-style, popovers, and more.
|
||||
|
||||
::note{to="https://tailwindcss.com/docs/upgrade-guide" target="_blank" aria-label="Tailwind CSS v4 upgrade guide"}
|
||||
Learn how to upgrade your project from Tailwind CSS v3 to v4.
|
||||
::note{to="https://tailwindcss.com/docs/upgrade-guide#changes-from-v3" target="_blank" aria-label="Tailwind CSS v4 upgrade guide"}
|
||||
Learn about all the breaking changes in Tailwind CSS v4.
|
||||
::
|
||||
|
||||
### Tailwind Variants
|
||||
@@ -47,7 +42,7 @@ This integration unifies the styling of components, ensuring consistency and cod
|
||||
|
||||
### 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**:
|
||||
- Full auto-completion for component props based on your theme
|
||||
@@ -105,42 +100,34 @@ We want to be transparent: migrating from Nuxt UI v2 to v3 will require signific
|
||||
|
||||
Key points to consider:
|
||||
|
||||
- A comprehensive migration guide will be available in the coming weeks.
|
||||
- Read our [migration guide](/getting-started/migration) to upgrade your project from v2 to v3.
|
||||
- Review the new documentation and components carefully before attempting to upgrade.
|
||||
- If you encounter any issues, please report them on our [GitHub repository](https://github.com/nuxt/ui/issues).
|
||||
|
||||
## FAQ
|
||||
|
||||
::accordion
|
||||
::accordion-item{label="What are the main considerations when upgrading to Nuxt UI v3?"}
|
||||
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?"}
|
||||
::accordion-item{label="Is Nuxt UI 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.
|
||||
::
|
||||
|
||||
::accordion-item{label="What about Nuxt UI Pro?"}
|
||||
We've also rebuilt Nuxt UI Pro from scratch and released a `v3.0.0-alpha.x` package with almost all components ready. This is a free update, so the license you buy now is valid for all UI Pro versions. We're actively working to finish the rewrite of all Nuxt UI Pro components.
|
||||
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?"}
|
||||
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.
|
||||
::accordion-item{label="Will Nuxt UI work with other CSS frameworks like UnoCSS?"}
|
||||
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?"}
|
||||
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).
|
||||
::accordion-item{label="How does Nuxt UI handle 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?"}
|
||||
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.
|
||||
::
|
||||
|
||||
::accordion-item{label="Is this version stable and suitable for production use?"}
|
||||
As Nuxt UI v3 is currently in alpha, we recommend thorough testing before using it in production environments. We're actively working on stabilization and welcome feedback from early adopters to improve the library. Feel free to report any issues you encounter on our [GitHub repository](https://github.com/nuxt/ui/issues).
|
||||
::accordion-item{label="What is the testing approach for Nuxt UI?"}
|
||||
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.
|
||||
::
|
||||
::
|
||||
|
||||
: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.
|
||||
|
||||
@@ -20,24 +20,24 @@ Looking for the **Vue** version?
|
||||
|
||||
::steps{level="4"}
|
||||
|
||||
#### Install the Nuxt UI v3 alpha package
|
||||
#### Install the Nuxt UI package
|
||||
|
||||
::code-group{sync="pm"}
|
||||
|
||||
```bash [pnpm]
|
||||
pnpm add @nuxt/ui@next
|
||||
pnpm add @nuxt/ui
|
||||
```
|
||||
|
||||
```bash [yarn]
|
||||
yarn add @nuxt/ui@next
|
||||
yarn add @nuxt/ui
|
||||
```
|
||||
|
||||
```bash [npm]
|
||||
npm install @nuxt/ui@next
|
||||
npm install @nuxt/ui
|
||||
```
|
||||
|
||||
```bash [bun]
|
||||
bun add @nuxt/ui@next
|
||||
bun add @nuxt/ui
|
||||
```
|
||||
|
||||
::
|
||||
@@ -56,19 +56,14 @@ export default defineNuxtConfig({
|
||||
|
||||
#### Import Tailwind CSS and Nuxt UI in your CSS
|
||||
|
||||
```css [assets/css/main.css]
|
||||
@import "tailwindcss" theme(static);
|
||||
::code-group
|
||||
|
||||
```css [app/assets/css/main.css]
|
||||
@import "tailwindcss";
|
||||
@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
|
||||
Use the `css` property in your `nuxt.config.ts` to import your CSS file.
|
||||
|
||||
```ts [nuxt.config.ts]
|
||||
```ts [nuxt.config.ts] {3}
|
||||
export default defineNuxtConfig({
|
||||
modules: ['@nuxt/ui'],
|
||||
css: ['~/assets/css/main.css']
|
||||
@@ -86,7 +81,11 @@ It's recommended to install the [Tailwind CSS IntelliSense](https://marketplace.
|
||||
},
|
||||
"editor.quickSuggestions": {
|
||||
"strings": "on"
|
||||
}
|
||||
},
|
||||
"tailwindCSS.classAttributes": ["class", "ui"],
|
||||
"tailwindCSS.experimental.classRegex": [
|
||||
["ui:\\s*{([^)]*)\\s*}", "(?:'|\"|`)([^']*)(?:'|\"|`)"]
|
||||
]
|
||||
```
|
||||
|
||||
::
|
||||
@@ -109,12 +108,12 @@ The `App` component provides global configurations and is required for **Toast**
|
||||
|
||||
### 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:
|
||||
|
||||
```bash [Terminal]
|
||||
npx nuxi init -t ui3 <my-app>
|
||||
npx nuxi init -t ui <my-app>
|
||||
```
|
||||
|
||||
::note
|
||||
@@ -141,6 +140,7 @@ Use the `prefix` option to change the prefix of the components.
|
||||
```ts [nuxt.config.ts]
|
||||
export default defineNuxtConfig({
|
||||
modules: ['@nuxt/ui'],
|
||||
css: ['~/assets/css/main.css'],
|
||||
ui: {
|
||||
prefix: 'Nuxt'
|
||||
}
|
||||
@@ -156,6 +156,7 @@ Use the `fonts` option to enable or disable the [`@nuxt/fonts`](https://github.c
|
||||
```ts [nuxt.config.ts]
|
||||
export default defineNuxtConfig({
|
||||
modules: ['@nuxt/ui'],
|
||||
css: ['~/assets/css/main.css'],
|
||||
ui: {
|
||||
fonts: false
|
||||
}
|
||||
@@ -171,6 +172,7 @@ Use the `colorMode` option to enable or disable the [`@nuxt/color-mode`](https:/
|
||||
```ts [nuxt.config.ts]
|
||||
export default defineNuxtConfig({
|
||||
modules: ['@nuxt/ui'],
|
||||
css: ['~/assets/css/main.css'],
|
||||
ui: {
|
||||
colorMode: false
|
||||
}
|
||||
@@ -186,6 +188,7 @@ Use the `theme.colors` option to define the dynamic color aliases used to genera
|
||||
```ts [nuxt.config.ts]
|
||||
export default defineNuxtConfig({
|
||||
modules: ['@nuxt/ui'],
|
||||
css: ['~/assets/css/main.css'],
|
||||
ui: {
|
||||
theme: {
|
||||
colors: ['primary', 'error']
|
||||
@@ -207,6 +210,7 @@ Use the `theme.transitions` option to enable or disable transitions on component
|
||||
```ts [nuxt.config.ts]
|
||||
export default defineNuxtConfig({
|
||||
modules: ['@nuxt/ui'],
|
||||
css: ['~/assets/css/main.css'],
|
||||
ui: {
|
||||
theme: {
|
||||
transitions: false
|
||||
@@ -221,30 +225,19 @@ This option adds the `transition-colors` class on components with hover or activ
|
||||
|
||||
## 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.
|
||||
|
||||
Preview releases are automatically generated for every commit to the `v3` branch and pull requests targeting the `v3` branch. To use it into your project, use the installation command below by replacing `5385f84` with any commit hash or pull request 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.
|
||||
|
||||
::code-group{sync="pm"}
|
||||
|
||||
```bash [pnpm]
|
||||
pnpm add https://pkg.pr.new/@nuxt/ui@5385f84
|
||||
```diff [package.json]
|
||||
{
|
||||
"dependencies": {
|
||||
- "@nuxt/ui": "^3.0.0",
|
||||
+ "@nuxt/ui": "https://pkg.pr.new/@nuxt/ui@4c96909",
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```bash [yarn]
|
||||
yarn add https://pkg.pr.new/@nuxt/ui@5385f84
|
||||
```
|
||||
|
||||
```bash [npm]
|
||||
npm install https://pkg.pr.new/@nuxt/ui@5385f84
|
||||
```
|
||||
|
||||
```bash [bun]
|
||||
bun add https://pkg.pr.new/@nuxt/ui@5385f84
|
||||
```
|
||||
|
||||
::
|
||||
|
||||
::note
|
||||
**pkg.pr.new** will automatically comment on PRs with the installation URL, making it easy to test changes.
|
||||
::
|
||||
|
||||
@@ -20,24 +20,24 @@ Looking for the **Nuxt** version?
|
||||
|
||||
::steps{level="4"}
|
||||
|
||||
#### Install the Nuxt UI v3 alpha package
|
||||
#### Install the Nuxt UI package
|
||||
|
||||
::code-group{sync="pm"}
|
||||
|
||||
```bash [pnpm]
|
||||
pnpm add @nuxt/ui@next
|
||||
pnpm add @nuxt/ui
|
||||
```
|
||||
|
||||
```bash [yarn]
|
||||
yarn add @nuxt/ui@next
|
||||
yarn add @nuxt/ui
|
||||
```
|
||||
|
||||
```bash [npm]
|
||||
npm install @nuxt/ui@next
|
||||
npm install @nuxt/ui
|
||||
```
|
||||
|
||||
```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
|
||||
|
||||
```css [assets/main.css]
|
||||
@import "tailwindcss" theme(static);
|
||||
@import "tailwindcss";
|
||||
@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
|
||||
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": {
|
||||
"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
|
||||
|
||||
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:
|
||||
|
||||
@@ -313,30 +313,19 @@ This option adds the `transition-colors` class on components with hover or activ
|
||||
|
||||
## 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.
|
||||
|
||||
Preview releases are automatically generated for every commit to the `v3` branch and pull requests targeting the `v3` branch. To use it into your project, use the installation command below by replacing `5385f84` with any commit hash or pull request 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.
|
||||
|
||||
::code-group{sync="pm"}
|
||||
|
||||
```bash [pnpm]
|
||||
pnpm add https://pkg.pr.new/@nuxt/ui@5385f84
|
||||
```diff [package.json]
|
||||
{
|
||||
"dependencies": {
|
||||
- "@nuxt/ui": "^3.0.0",
|
||||
+ "@nuxt/ui": "https://pkg.pr.new/@nuxt/ui@4c96909",
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```bash [yarn]
|
||||
yarn add https://pkg.pr.new/@nuxt/ui@5385f84
|
||||
```
|
||||
|
||||
```bash [npm]
|
||||
npm install https://pkg.pr.new/@nuxt/ui@5385f84
|
||||
```
|
||||
|
||||
```bash [bun]
|
||||
bun add https://pkg.pr.new/@nuxt/ui@5385f84
|
||||
```
|
||||
|
||||
::
|
||||
|
||||
::note
|
||||
**pkg.pr.new** will automatically comment on PRs with the installation URL, making it easy to test changes.
|
||||
::
|
||||
|
||||
533
docs/content/1.getting-started/2.migration.md
Normal file
@@ -0,0 +1,533 @@
|
||||
---
|
||||
title: Migration
|
||||
description: 'A comprehensive guide to migrate your application from Nuxt UI v2 to Nuxt UI v3.'
|
||||
---
|
||||
|
||||
Nuxt UI v3.0 is a new major version rebuilt from the ground up, introducing a modern architecture with significant performance improvements and an enhanced developer experience. This major release includes several breaking changes alongside powerful new features and capabilities:
|
||||
|
||||
- **Tailwind CSS v4**: Migration from JavaScript to CSS-based configuration
|
||||
- **Reka UI**: Replacing Headless UI as the underlying component library
|
||||
- **Tailwind Variants**: New styling API for component variants
|
||||
|
||||
This guide provides step by step instructions to migrate your application from v2 to v3.
|
||||
|
||||
## Migrate your project
|
||||
|
||||
::steps
|
||||
|
||||
### Update Tailwind CSS
|
||||
|
||||
Tailwind CSS v4 introduces significant changes to its configuration approach. The official Tailwind upgrade tool will help automate most of the migration process.
|
||||
|
||||
::note{to="https://tailwindcss.com/docs/upgrade-guide#changes-from-v3" target="_blank"}
|
||||
For a detailed walkthrough of all changes, refer to the official **Tailwind CSS v4 upgrade guide**.
|
||||
::
|
||||
|
||||
1. Create a `main.css` file and import it in your `nuxt.config.ts` file:
|
||||
|
||||
::code-group
|
||||
|
||||
```css [app/assets/css/main.css]
|
||||
@import "tailwindcss";
|
||||
```
|
||||
|
||||
```ts [nuxt.config.ts]
|
||||
export default defineNuxtConfig({
|
||||
css: ['~/assets/css/main.css']
|
||||
})
|
||||
```
|
||||
|
||||
::
|
||||
|
||||
2. Run the Tailwind CSS upgrade tool:
|
||||
|
||||
```bash
|
||||
npx @tailwindcss/upgrade
|
||||
```
|
||||
|
||||
### Update Nuxt UI
|
||||
|
||||
3. Install the latest version of the package:
|
||||
|
||||
::module-only
|
||||
#ui
|
||||
:::div
|
||||
|
||||
::::code-group{sync="pm"}
|
||||
|
||||
```bash [pnpm]
|
||||
pnpm add @nuxt/ui
|
||||
```
|
||||
|
||||
```bash [yarn]
|
||||
yarn add @nuxt/ui
|
||||
```
|
||||
|
||||
```bash [npm]
|
||||
npm install @nuxt/ui
|
||||
```
|
||||
|
||||
```bash [bun]
|
||||
bun add @nuxt/ui
|
||||
```
|
||||
|
||||
::::
|
||||
|
||||
:::
|
||||
|
||||
#ui-pro
|
||||
:::div
|
||||
|
||||
::::code-group{sync="pm"}
|
||||
|
||||
```bash [pnpm]
|
||||
pnpm add @nuxt/ui-pro
|
||||
```
|
||||
|
||||
```bash [yarn]
|
||||
yarn add @nuxt/ui-pro
|
||||
```
|
||||
|
||||
```bash [npm]
|
||||
npm install @nuxt/ui-pro
|
||||
```
|
||||
|
||||
```bash [bun]
|
||||
bun add @nuxt/ui-pro
|
||||
```
|
||||
|
||||
::::
|
||||
|
||||
:::
|
||||
|
||||
::
|
||||
|
||||
4. Import it in your CSS:
|
||||
|
||||
::module-only
|
||||
#ui
|
||||
:::div
|
||||
|
||||
```css [app/assets/css/main.css]{2}
|
||||
@import "tailwindcss";
|
||||
@import "@nuxt/ui";
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
#ui-pro
|
||||
:::div
|
||||
|
||||
```css [app/assets/css/main.css]{2}
|
||||
@import "tailwindcss";
|
||||
@import "@nuxt/ui-pro";
|
||||
```
|
||||
|
||||
:::
|
||||
::
|
||||
|
||||
::module-only
|
||||
#ui
|
||||
|
||||
:::div
|
||||
5. Wrap your app with the [App](/components/app) component:
|
||||
:::
|
||||
|
||||
#ui-pro
|
||||
:::div
|
||||
5. Add the `@nuxt/ui-pro` module in your `nuxt.config.ts` file as it's no longer a layer:
|
||||
|
||||
```diff [nuxt.config.ts]
|
||||
export default defineNuxtConfig({
|
||||
- extends: ['@nuxt/ui-pro'],
|
||||
- modules: ['@nuxt/ui']
|
||||
+ modules: ['@nuxt/ui-pro']
|
||||
})
|
||||
```
|
||||
|
||||
6. Wrap your app with the [App](/components/app) component:
|
||||
:::
|
||||
|
||||
::
|
||||
|
||||
```vue [app.vue] {2,4}
|
||||
<template>
|
||||
<UApp>
|
||||
<NuxtPage />
|
||||
</UApp>
|
||||
</template>
|
||||
```
|
||||
|
||||
::
|
||||
|
||||
## Changes from v2
|
||||
|
||||
Now that you have updated your project, you can start migrating your code. Here's a comprehensive list of all the breaking changes in Nuxt UI v3.
|
||||
|
||||
### Updated design system
|
||||
|
||||
In Nuxt UI v2, we had a mix between a design system with `primary`, `gray`, `error` aliases and all the colors from Tailwind CSS. We've replaced it with a proper [design system](/getting-started/theme#design-system) with 7 color aliases:
|
||||
|
||||
| Color | Default | Description |
|
||||
| --- | --- | --- |
|
||||
| `primary`{color="primary"} | `green` | Main brand color, used as the default color for components. |
|
||||
| `secondary`{color="secondary"} | `blue` | Secondary color to complement the primary color. |
|
||||
| `success`{color="success"} | `green` | Used for success states. |
|
||||
| `info`{color="info"} | `blue` | Used for informational states. |
|
||||
| `warning`{color="warning"} | `yellow` | Used for warning states. |
|
||||
| `error`{color="error"} | `red` | Used for form error validation states. |
|
||||
| `neutral` | `slate` | Neutral color for backgrounds, text, etc. |
|
||||
|
||||
This change introduces several breaking changes that you need to be aware of:
|
||||
|
||||
1. The `gray` color has been renamed to `neutral`
|
||||
|
||||
```diff
|
||||
<template>
|
||||
- <p class="text-gray-500 dark:text-gray-400" />
|
||||
+ <p class="text-neutral-500 dark:text-neutral-400" />
|
||||
</template>
|
||||
```
|
||||
|
||||
::note
|
||||
You can also use the new [design tokens](/getting-started/theme#neutral-palette) to handle light and dark mode:
|
||||
|
||||
```diff
|
||||
<template>
|
||||
- <p class="text-gray-500 dark:text-gray-400" />
|
||||
+ <p class="text-(--ui-text-muted)" />
|
||||
|
||||
- <p class="text-gray-900 dark:text-white" />
|
||||
+ <p class="text-(--ui-text-highlighted)" />
|
||||
</template>
|
||||
```
|
||||
::
|
||||
|
||||
2. The `DEFAULT` shade that let you write `text-primary` no longer exists, you can use [color shades](/getting-started/theme#color-shades) instead:
|
||||
|
||||
```diff
|
||||
<template>
|
||||
- <p class="text-primary">Hello</p>
|
||||
+ <p class="text-(--ui-primary)">Hello</p>
|
||||
</template>
|
||||
```
|
||||
|
||||
3. The `gray`, `black` and `white` in the `color` props have been removed in favor of `neutral`:
|
||||
|
||||
```diff
|
||||
- <UButton color="black" />
|
||||
+ <UButton color="neutral" />
|
||||
|
||||
- <UButton color="gray" />
|
||||
+ <UButton color="neutral" variant="subtle" />
|
||||
|
||||
- <UButton color="white" />
|
||||
+ <UButton color="neutral" variant="outline" />
|
||||
```
|
||||
|
||||
4. You can no longer use Tailwind CSS colors in the `color` props, use the new aliases instead:
|
||||
|
||||
```diff
|
||||
- <UButton color="red" />
|
||||
+ <UButton color="error" />
|
||||
```
|
||||
|
||||
::note{to="/getting-started/theme#colors"}
|
||||
Learn how to extend the design system to add new color aliases.
|
||||
::
|
||||
|
||||
5. The color configuration in `app.config.ts` has been moved into a `colors` object:
|
||||
|
||||
```diff
|
||||
export default defineAppConfig({
|
||||
ui: {
|
||||
- primary: 'green',
|
||||
- gray: 'cool'
|
||||
+ colors: {
|
||||
+ primary: 'green',
|
||||
+ neutral: 'slate'
|
||||
+ }
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
### Updated theming system
|
||||
|
||||
Nuxt UI components are now styled using the [Tailwind Variants API](/getting-started/theme#components-theme), which makes all the overrides you made using the `app.config.ts` and the `ui` prop obsolete.
|
||||
|
||||
1. Update your [`app.config.ts`](/getting-started/theme#config) to override components with their new theme:
|
||||
|
||||
```diff
|
||||
export default defineAppConfig({
|
||||
ui: {
|
||||
button: {
|
||||
- font: 'font-bold',
|
||||
- default: {
|
||||
- size: 'md',
|
||||
- color: 'primary'
|
||||
- }
|
||||
+ slots: {
|
||||
+ base: 'font-medium'
|
||||
+ },
|
||||
+ defaultVariants: {
|
||||
+ size: 'md',
|
||||
+ color: 'primary'
|
||||
+ }
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
2. Update your [`ui` props](/getting-started/theme#props) to override each component's slots using their new theme:
|
||||
|
||||
```diff
|
||||
<template>
|
||||
- <UButton :ui="{ font: 'font-bold' }" />
|
||||
+ <UButton :ui="{ base: 'font-bold' }" />
|
||||
</template>
|
||||
```
|
||||
|
||||
::tip{to="/components/button#theme"}
|
||||
We can't detail all the changes here but you can check each component's theme in the **Theme** section.
|
||||
::
|
||||
|
||||
### Renamed components
|
||||
|
||||
We've renamed some Nuxt UI components to align with the Reka UI naming convention:
|
||||
|
||||
| v2 | v3 |
|
||||
| --- | --- |
|
||||
| `Divider` | [`Separator`](/components/separator) |
|
||||
| `Dropdown` | [`DropdownMenu`](/components/dropdown-menu) |
|
||||
| `FormGroup` | [`FormField`](/components/form-field) |
|
||||
| `Range` | [`Slider`](/components/slider) |
|
||||
| `Toggle` | [`Switch`](/components/switch) |
|
||||
| `Notification` | [`Toast`](/components/toast) |
|
||||
| `VerticalNavigation` | [`NavigationMenu`](/components/navigation-menu) with `orientation="vertical"` |
|
||||
| `HorizontalNavigation` | [`NavigationMenu`](/components/navigation-menu) with `orientation="horizontal"` |
|
||||
|
||||
::module-only
|
||||
#ui-pro
|
||||
:::div
|
||||
Here are the Nuxt UI Pro components that have been renamed or removed:
|
||||
|
||||
| v1 | v3 |
|
||||
| --- | --- |
|
||||
| `BlogList` | [`BlogPosts`](/components/blog-posts) |
|
||||
| `ColorModeToggle` | [`ColorModeSwitch`](/components/color-mode-switch) |
|
||||
| `DashboardCard` | Removed (use [`PageCard`](/components/page-card) instead) |
|
||||
| `DashboardLayout` | [`DashboardGroup`](/components/dashboard-group) |
|
||||
| `DashboardModal` | Removed (use [`Modal`](/components/modal) instead) |
|
||||
| `DashboardNavbarToggle` | [`DashboardSidebarToggle`](/components/dashboard-sidebar-toggle) |
|
||||
| `DashboardPage` | Removed |
|
||||
| `DashboardPanelContent` | Removed (use `#body` slot instead) |
|
||||
| `DashboardPanelHandle` | [`DashboardResizeHandle`](/components/dashboard-resize-handle) |
|
||||
| `DashboardSection` | Removed (use [`PageCard`](/components/page-card) instead) |
|
||||
| `DashboardSidebarLinks` | Removed (use [`NavigationMenu`](/components/navigation-menu) instead) |
|
||||
| `DashboardSlideover` | Removed (use [`Slideover`](/components/slideover) instead) |
|
||||
| `FooterLinks` | Removed (use [`NavigationMenu`](/components/navigation-menu) instead) |
|
||||
| `HeaderLinks` | Removed (use [`NavigationMenu`](/components/navigation-menu) instead) |
|
||||
| `LandingCard` | Removed (use [`PageCard`](/components/page-card) instead) |
|
||||
| `LandingCTA` | [`PageCTA`](/components/page-cta) |
|
||||
| `LandingFAQ` | Removed (use [`PageAccordion`](/components/page-accordion) instead) |
|
||||
| `LandingGrid` | Removed (use [`PageGrid`](/components/page-grid) instead) |
|
||||
| `LandingHero` | Removed (use [`PageHero`](/components/page-hero) instead) |
|
||||
| `LandingLogos` | [`PageLogos`](/components/page-logos) |
|
||||
| `LandingSection` | [`PageSection`](/components/page-section) |
|
||||
| `LandingTestimonial` | Removed (use [`PageCard`](/components/page-card#as-a-testimonial) instead) |
|
||||
| `NavigationAccordion` | [`ContentNavigation`](/components/content-navigation) |
|
||||
| `NavigationLinks` | [`ContentNavigation`](/components/content-navigation) |
|
||||
| `NavigationTree` | [`ContentNavigation`](/components/content-navigation) |
|
||||
| `PageError` | [`Error`](/components/error) |
|
||||
| `PricingCard` | [`PricingPlan`](/components/pricing-plan) |
|
||||
| `PricingGrid` | [`PricingPlans`](/components/pricing-plans) |
|
||||
| `PricingSwitch` | Removed (use [`Switch`](/components/switch) or [`Tabs`](/components/tabs) instead) |
|
||||
|
||||
:::
|
||||
|
||||
::
|
||||
|
||||
### Changed components
|
||||
|
||||
In addition to the renamed components, there are lots of changes to the components API. Let's detail the most important ones:
|
||||
|
||||
1. The `links` and `options` props have been renamed to `items` for consistency:
|
||||
|
||||
```diff
|
||||
<template>
|
||||
- <USelect :options="countries" />
|
||||
+ <USelect :items="countries" />
|
||||
|
||||
- <UHorizontalNavigation :links="links" />
|
||||
+ <UNavigationMenu :items="links" />
|
||||
</template>
|
||||
```
|
||||
|
||||
::note
|
||||
This change affects the following components: `Breadcrumb`, `HorizontalNavigation`, `InputMenu`, `RadioGroup`, `Select`, `SelectMenu`, `VerticalNavigation`.
|
||||
::
|
||||
|
||||
2. The global `Modals`, `Slideovers` and `Notifications` components have been removed in favor the [App](/components/app) component:
|
||||
|
||||
```diff [app.vue]
|
||||
<template>
|
||||
+ <UApp>
|
||||
+ <NuxtPage />
|
||||
+ </UApp>
|
||||
- <UModals />
|
||||
- <USlideovers />
|
||||
- <UNotifications />
|
||||
</template>
|
||||
```
|
||||
|
||||
3. The `v-model:open` directive and `default-open` prop are now used to control visibility:
|
||||
|
||||
```diff
|
||||
<template>
|
||||
- <UModal v-model="open" />
|
||||
+ <UModal v-model:open="open" />
|
||||
</template>
|
||||
```
|
||||
|
||||
::note
|
||||
This change affects the following components: `ContextMenu`, `Modal` and `Slideover` and enables controlling visibility for `InputMenu`, `Select`, `SelectMenu` and `Tooltip`.
|
||||
::
|
||||
|
||||
4. The default slot is now used for the trigger and the content goes inside the `#content` slot (you don't need to use a `v-model:open` directive with this method):
|
||||
|
||||
```diff
|
||||
<script setup lang="ts">
|
||||
- const open = ref(false)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
- <UButton label="Open" @click="open = true" />
|
||||
|
||||
- <UModal v-model="open">
|
||||
+ <UModal>
|
||||
+ <UButton label="Open" />
|
||||
|
||||
+ <template #content>
|
||||
<div class="p-4">
|
||||
<Placeholder class="h-48" />
|
||||
</div>
|
||||
+ </template>
|
||||
</UModal>
|
||||
</template>
|
||||
```
|
||||
|
||||
::note
|
||||
This change affects the following components: `Modal`, `Popover`, `Slideover`, `Tooltip`.
|
||||
::
|
||||
|
||||
5. A `#header`, `#body` and `#footer` slots have been added inside the `#content` slot like the `Card` component:
|
||||
|
||||
```diff
|
||||
<template>
|
||||
- <UModal>
|
||||
+ <UModal title="Title" description="Description">
|
||||
- <div class="p-4">
|
||||
+ <template #body>
|
||||
<Placeholder class="h-48" />
|
||||
+ </template>
|
||||
- </div>
|
||||
</UModal>
|
||||
</template>
|
||||
```
|
||||
|
||||
::note
|
||||
This change affects the following components: `Modal`, `Slideover`.
|
||||
::
|
||||
|
||||
|
||||
### Changed composables
|
||||
|
||||
1. The `useToast()` composable `timeout` prop has been renamed to `duration`:
|
||||
|
||||
```diff
|
||||
<script setup lang="ts">
|
||||
const toast = useToast()
|
||||
|
||||
- toast.add({ title: 'Invitation sent', timeout: 0 })
|
||||
+ toast.add({ title: 'Invitation sent', duration: 0 })
|
||||
</script>
|
||||
```
|
||||
|
||||
2. The `useModal` and `useSlideover` composables have been removed in favor of a more generic `useOverlay` composable:
|
||||
|
||||
Some important differences:
|
||||
- The `useOverlay` composable is now used to create overlay instances
|
||||
- Overlays that are opened, can be awaited for their result
|
||||
- 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 `close` event with the desired value
|
||||
|
||||
|
||||
```diff
|
||||
<script setup lang="ts">
|
||||
import { ModalExampleComponent } from '#components'
|
||||
|
||||
- const modal = useModal()
|
||||
+ const overlay = useOverlay()
|
||||
|
||||
- modal.open(ModalExampleComponent)
|
||||
+ const modal = overlay.create(ModalExampleComponent)
|
||||
</script>
|
||||
```
|
||||
|
||||
Props are now passed through a props attribute:
|
||||
|
||||
```diff
|
||||
<script setup lang="ts">
|
||||
import { ModalExampleComponent } from '#components'
|
||||
|
||||
- const modal = useModal()
|
||||
+ const overlay = useOverlay()
|
||||
|
||||
const count = ref(0)
|
||||
|
||||
- modal.open(ModalExampleComponent, {
|
||||
- count: count.value
|
||||
- })
|
||||
+ const modal = overlay.create(ModalExampleComponent, {
|
||||
+ props: {
|
||||
+ count: count.value
|
||||
+ }
|
||||
+ })
|
||||
</script>
|
||||
```
|
||||
|
||||
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
|
||||
<script setup lang="ts">
|
||||
import { ModalExampleComponent } from '#components'
|
||||
|
||||
- const modal = useModal()
|
||||
+ const overlay = useOverlay()
|
||||
|
||||
+ const modal = overlay.create(ModalExampleComponent)
|
||||
|
||||
- function openModal() {
|
||||
- modal.open(ModalExampleComponent, {
|
||||
- onSuccess() {
|
||||
- toast.add({ title: 'Success!' })
|
||||
- }
|
||||
- })
|
||||
- }
|
||||
+ async function openModal() {
|
||||
+ const result = await modal.open(ModalExampleComponent, {
|
||||
+ count: count.value
|
||||
+ })
|
||||
+
|
||||
+ if (result) {
|
||||
+ toast.add({ title: 'Success!' })
|
||||
+ }
|
||||
+ }
|
||||
</script>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
::warning
|
||||
This page is a work in progress, we'll improve it regularly.
|
||||
::
|
||||
@@ -6,7 +6,7 @@ navigation.icon: i-lucide-swatch-book
|
||||
|
||||
## Tailwind CSS
|
||||
|
||||
Nuxt UI v3 uses Tailwind CSS v4, you can read the [upgrade guide](https://tailwindcss.com/docs/upgrade-guide) to learn how to upgrade your project from v3 to v4.
|
||||
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`
|
||||
|
||||
@@ -16,8 +16,8 @@ Tailwind CSS v4 takes a CSS-first configuration approach, you now customize your
|
||||
#ui
|
||||
:::div
|
||||
|
||||
```css [assets/css/main.css]
|
||||
@import "tailwindcss" theme(static);
|
||||
```css [app/assets/css/main.css]
|
||||
@import "tailwindcss";
|
||||
@import "@nuxt/ui";
|
||||
|
||||
@theme static {
|
||||
@@ -44,8 +44,8 @@ Tailwind CSS v4 takes a CSS-first configuration approach, you now customize your
|
||||
#ui-pro
|
||||
:::div
|
||||
|
||||
```css [assets/css/main.css]
|
||||
@import "tailwindcss" theme(static);
|
||||
```css [app/assets/css/main.css]
|
||||
@import "tailwindcss";
|
||||
@import "@nuxt/ui-pro";
|
||||
|
||||
@theme static {
|
||||
@@ -86,13 +86,13 @@ This can be useful when writing Tailwind CSS classes in markdown files with [`@n
|
||||
#ui
|
||||
:::div
|
||||
|
||||
```css [assets/css/main.css]
|
||||
@import "tailwindcss" theme(static);
|
||||
```css [app/assets/css/main.css]
|
||||
@import "tailwindcss";
|
||||
@import "@nuxt/ui";
|
||||
|
||||
@source "../../content";
|
||||
/* Use this if using compatibilityVersion: 4: https://nuxt.com/docs/getting-started/upgrade#opting-in-to-nuxt-4 */
|
||||
@source "../../../content";
|
||||
/* Use this if you're not using compatibilityVersion: 4: https://nuxt.com/docs/getting-started/upgrade#opting-in-to-nuxt-4 */
|
||||
@source "../../content";
|
||||
```
|
||||
|
||||
:::
|
||||
@@ -100,13 +100,13 @@ This can be useful when writing Tailwind CSS classes in markdown files with [`@n
|
||||
#ui-pro
|
||||
:::div
|
||||
|
||||
```css [assets/css/main.css]
|
||||
@import "tailwindcss" theme(static);
|
||||
```css [app/assets/css/main.css]
|
||||
@import "tailwindcss";
|
||||
@import "@nuxt/ui-pro";
|
||||
|
||||
@source "../../content";
|
||||
/* Use this if using compatibilityVersion: 4: https://nuxt.com/docs/getting-started/upgrade#opting-in-to-nuxt-4 */
|
||||
@source "../../../content";
|
||||
/* Use this if you're not using compatibilityVersion: 4: https://nuxt.com/docs/getting-started/upgrade#opting-in-to-nuxt-4 */
|
||||
@source "../../content";
|
||||
```
|
||||
|
||||
:::
|
||||
@@ -142,7 +142,7 @@ Nuxt UI leverages Vite config to provide customizable color aliases based on [Ta
|
||||
|
||||
::framework-only
|
||||
#nuxt
|
||||
::div
|
||||
:::div
|
||||
You can configure these color aliases at runtime in your `app.config.ts` file under the `ui.colors` key, allowing for dynamic theme customization without requiring an application rebuild:
|
||||
|
||||
```ts [app.config.ts]
|
||||
@@ -156,14 +156,19 @@ export default defineAppConfig({
|
||||
})
|
||||
```
|
||||
|
||||
::
|
||||
:::
|
||||
|
||||
#vue
|
||||
::module-only
|
||||
#ui
|
||||
|
||||
:::div
|
||||
You can configure these color aliases at runtime in your `vite.config.ts` file under the `ui.colors` key:
|
||||
|
||||
::::module-only
|
||||
|
||||
#ui
|
||||
|
||||
:::::div
|
||||
|
||||
```ts [vite.config.ts]
|
||||
import { defineConfig } from 'vite'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
@@ -183,11 +188,12 @@ export default defineConfig({
|
||||
]
|
||||
})
|
||||
```
|
||||
:::
|
||||
:::::
|
||||
|
||||
#ui-pro
|
||||
:::div
|
||||
You can configure these color aliases at runtime in your `vite.config.ts` file under the `uiPro.colors` key:
|
||||
|
||||
:::::div
|
||||
|
||||
```ts [vite.config.ts]
|
||||
import { defineConfig } from 'vite'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
@@ -207,9 +213,12 @@ export default defineConfig({
|
||||
]
|
||||
})
|
||||
```
|
||||
:::
|
||||
|
||||
::
|
||||
:::::
|
||||
|
||||
::::
|
||||
|
||||
:::
|
||||
|
||||
::
|
||||
|
||||
@@ -256,11 +265,17 @@ export default defineNuxtConfig({
|
||||
:::
|
||||
|
||||
#vue
|
||||
::module-only
|
||||
#ui
|
||||
|
||||
:::tip
|
||||
|
||||
You can add you own dynamic color aliases in your `vite.config.ts`, you just have to make sure to also define them in the [`theme.colors`](/getting-started/installation/vue#themecolors) option of the `ui` plugin.
|
||||
|
||||
::::module-only
|
||||
|
||||
#ui
|
||||
|
||||
:::::div
|
||||
|
||||
```ts [vite.config.ts]
|
||||
import { defineConfig } from 'vite'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
@@ -283,11 +298,11 @@ export default defineConfig({
|
||||
})
|
||||
```
|
||||
|
||||
:::
|
||||
:::::
|
||||
|
||||
#ui-pro
|
||||
:::tip
|
||||
You can add you own dynamic color aliases in your `vite.config.ts`, you just have to make sure to also define them in the [`theme.colors`](/getting-started/installation/vue#themecolors) option of the `uiPro` plugin.
|
||||
|
||||
:::::div
|
||||
|
||||
```ts [vite.config.ts]
|
||||
import { defineConfig } from 'vite'
|
||||
@@ -311,9 +326,12 @@ export default defineConfig({
|
||||
})
|
||||
```
|
||||
|
||||
:::::
|
||||
|
||||
::::
|
||||
|
||||
:::
|
||||
|
||||
::
|
||||
::
|
||||
|
||||
### Tokens
|
||||
@@ -361,8 +379,8 @@ You can change which shade is used for each color on light and dark mode:
|
||||
#ui
|
||||
:::div{class="*:!mb-0 *:!mt-2.5"}
|
||||
|
||||
```css [assets/css/main.css]
|
||||
@import "tailwindcss" theme(static);
|
||||
```css [app/assets/css/main.css]
|
||||
@import "tailwindcss";
|
||||
@import "@nuxt/ui";
|
||||
|
||||
:root {
|
||||
@@ -379,8 +397,8 @@ You can change which shade is used for each color on light and dark mode:
|
||||
#ui-pro
|
||||
:::div{class="*:!mb-0 *:!mt-2.5"}
|
||||
|
||||
```css [assets/css/main.css]
|
||||
@import "tailwindcss" theme(static);
|
||||
```css [app/assets/css/main.css]
|
||||
@import "tailwindcss";
|
||||
@import "@nuxt/ui-pro";
|
||||
|
||||
:root {
|
||||
@@ -415,8 +433,8 @@ You cannot set `primary: 'black'`{lang="ts-type"} in your [`vite.config.ts`](#co
|
||||
#ui
|
||||
:::div{class="*:!mb-0 *:!mt-2.5"}
|
||||
|
||||
```css [assets/css/main.css]
|
||||
@import "tailwindcss" theme(static);
|
||||
```css [app/assets/css/main.css]
|
||||
@import "tailwindcss";
|
||||
@import "@nuxt/ui";
|
||||
|
||||
:root {
|
||||
@@ -433,8 +451,8 @@ You cannot set `primary: 'black'`{lang="ts-type"} in your [`vite.config.ts`](#co
|
||||
#ui-pro
|
||||
:::div{class="*:!mb-0 *:!mt-2.5"}
|
||||
|
||||
```css [assets/css/main.css]
|
||||
@import "tailwindcss" theme(static);
|
||||
```css [app/assets/css/main.css]
|
||||
@import "tailwindcss";
|
||||
@import "@nuxt/ui-pro";
|
||||
|
||||
:root {
|
||||
@@ -545,8 +563,8 @@ You can customize these CSS variables to tailor the appearance of your applicati
|
||||
#ui
|
||||
:::div{class="*:!mb-0 *:!mt-2.5"}
|
||||
|
||||
```css [assets/css/main.css]
|
||||
@import "tailwindcss" theme(static);
|
||||
```css [app/assets/css/main.css]
|
||||
@import "tailwindcss";
|
||||
@import "@nuxt/ui";
|
||||
|
||||
:root {
|
||||
@@ -565,8 +583,8 @@ You can customize these CSS variables to tailor the appearance of your applicati
|
||||
#ui-pro
|
||||
:::div{class="*:!mb-0 *:!mt-2.5"}
|
||||
|
||||
```css [assets/css/main.css]
|
||||
@import "tailwindcss" theme(static);
|
||||
```css [app/assets/css/main.css]
|
||||
@import "tailwindcss";
|
||||
@import "@nuxt/ui-pro";
|
||||
|
||||
:root {
|
||||
@@ -606,8 +624,8 @@ You can customize the default radius value using the default Tailwind CSS variab
|
||||
#ui
|
||||
:::div{class="*:!mb-0 *:!mt-2.5"}
|
||||
|
||||
```css [assets/css/main.css]
|
||||
@import "tailwindcss" theme(static);
|
||||
```css [app/assets/css/main.css]
|
||||
@import "tailwindcss";
|
||||
@import "@nuxt/ui";
|
||||
|
||||
:root {
|
||||
@@ -620,8 +638,8 @@ You can customize the default radius value using the default Tailwind CSS variab
|
||||
#ui-pro
|
||||
:::div{class="*:!mb-0 *:!mt-2.5"}
|
||||
|
||||
```css [assets/css/main.css]
|
||||
@import "tailwindcss" theme(static);
|
||||
```css [app/assets/css/main.css]
|
||||
@import "tailwindcss";
|
||||
@import "@nuxt/ui-pro";
|
||||
|
||||
:root {
|
||||
@@ -651,8 +669,8 @@ You can customize the default container width using the default Tailwind CSS var
|
||||
#ui
|
||||
:::div{class="*:!mb-0 *:!mt-2.5"}
|
||||
|
||||
```css [assets/css/main.css]
|
||||
@import "tailwindcss" theme(static);
|
||||
```css [app/assets/css/main.css]
|
||||
@import "tailwindcss";
|
||||
@import "@nuxt/ui";
|
||||
|
||||
@theme {
|
||||
@@ -669,8 +687,8 @@ You can customize the default container width using the default Tailwind CSS var
|
||||
#ui-pro
|
||||
:::div{class="*:!mb-0 *:!mt-2.5"}
|
||||
|
||||
```css [assets/css/main.css]
|
||||
@import "tailwindcss" theme(static);
|
||||
```css [app/assets/css/main.css]
|
||||
@import "tailwindcss";
|
||||
@import "@nuxt/ui-pro";
|
||||
|
||||
@theme {
|
||||
@@ -820,14 +838,14 @@ You can explore the theme for each component in two ways:
|
||||
|
||||
- Check the `Theme` section in the documentation of each individual component.
|
||||
- Browse the source code directly in the GitHub repository at [`v3/src/theme`](https://github.com/nuxt/ui/tree/v3/src/theme).
|
||||
|
||||
::
|
||||
|
||||
### Config
|
||||
|
||||
::framework-only
|
||||
#nuxt
|
||||
::div
|
||||
|
||||
:::div
|
||||
You can override the theme of components globally inside your `app.config.ts` by using the exact same structure as the theme object.
|
||||
|
||||
Let's say you want to change the font weight of all your buttons, you can do it like this:
|
||||
@@ -844,17 +862,21 @@ export default defineAppConfig({
|
||||
})
|
||||
```
|
||||
|
||||
::
|
||||
:::
|
||||
|
||||
#vue
|
||||
|
||||
::module-only
|
||||
#ui
|
||||
:::div
|
||||
You can override the theme of components globally inside your `vite.config.ts` by using the exact same structure as the theme object.
|
||||
|
||||
Let's say you want to change the font weight of all your buttons, you can do it like this:
|
||||
|
||||
::::module-only
|
||||
|
||||
#ui
|
||||
|
||||
:::::div
|
||||
|
||||
```ts [vite.config.ts]
|
||||
import { defineConfig } from 'vite'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
@@ -875,13 +897,12 @@ export default defineConfig({
|
||||
]
|
||||
})
|
||||
```
|
||||
:::
|
||||
|
||||
:::::
|
||||
|
||||
#ui-pro
|
||||
:::div
|
||||
You can override the theme of components globally inside your `vite.config.ts` by using the exact same structure as the theme object.
|
||||
|
||||
Let's say you want to change the font weight of all your buttons, you can do it like this:
|
||||
:::::div
|
||||
|
||||
```ts [vite.config.ts]
|
||||
import { defineConfig } from 'vite'
|
||||
@@ -903,8 +924,12 @@ export default defineConfig({
|
||||
]
|
||||
})
|
||||
```
|
||||
|
||||
:::::
|
||||
|
||||
::::
|
||||
|
||||
:::
|
||||
::
|
||||
|
||||
::
|
||||
|
||||
|
||||
@@ -99,9 +99,8 @@ In your `nuxt.config.ts`, add an item in `icon.customCollections`:
|
||||
|
||||
```ts
|
||||
export default defineNuxtConfig({
|
||||
modules: [
|
||||
'@nuxt/ui'
|
||||
],
|
||||
modules: ['@nuxt/ui'],
|
||||
css: ['~/assets/css/main.css'],
|
||||
icon: {
|
||||
customCollections: [{
|
||||
prefix: 'custom',
|
||||
|
||||
@@ -18,8 +18,8 @@ Nuxt UI automatically registers the [`@nuxt/fonts`](https://github.com/nuxt/font
|
||||
#ui
|
||||
:::div
|
||||
|
||||
```css [assets/css/main.css]
|
||||
@import "tailwindcss" theme(static);
|
||||
```css [app/assets/css/main.css]
|
||||
@import "tailwindcss";
|
||||
@import "@nuxt/ui";
|
||||
|
||||
@theme {
|
||||
@@ -32,8 +32,8 @@ Nuxt UI automatically registers the [`@nuxt/fonts`](https://github.com/nuxt/font
|
||||
#ui-pro
|
||||
:::div
|
||||
|
||||
```css [assets/css/main.css]
|
||||
@import "tailwindcss" theme(static);
|
||||
```css [app/assets/css/main.css]
|
||||
@import "tailwindcss";
|
||||
@import "@nuxt/ui-pro";
|
||||
|
||||
@theme {
|
||||
|
||||
@@ -52,6 +52,8 @@ You can disable the `@nuxtjs/color-mode` module with the `ui.colorMode` option i
|
||||
|
||||
```ts [nuxt.config.ts]
|
||||
export default defineNuxtConfig({
|
||||
modules: ['@nuxt/ui'],
|
||||
css: ['~/assets/css/main.css'],
|
||||
ui: {
|
||||
colorMode: false
|
||||
}
|
||||
|
||||
@@ -17,6 +17,11 @@ Nuxt UI provides an **App** component that wraps your app to provide global conf
|
||||
|
||||
### Locale
|
||||
|
||||
::module-only
|
||||
|
||||
#ui
|
||||
:::div
|
||||
|
||||
Use the `locale` prop with the locale you want to use from `@nuxt/ui/locale`:
|
||||
|
||||
```vue [app.vue]
|
||||
@@ -31,13 +36,42 @@ import { fr } from '@nuxt/ui/locale'
|
||||
</template>
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
#ui-pro
|
||||
:::div
|
||||
|
||||
Use the `locale` prop with the locale you want to use from `@nuxt/ui-pro/locale`:
|
||||
|
||||
```vue [app.vue]
|
||||
<script setup lang="ts">
|
||||
import { fr } from '@nuxt/ui-pro/locale'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UApp :locale="fr">
|
||||
<NuxtPage />
|
||||
</UApp>
|
||||
</template>
|
||||
```
|
||||
|
||||
:::
|
||||
::
|
||||
|
||||
### Custom locale
|
||||
|
||||
You also have the option to add your own locale using `defineLocale`:
|
||||
|
||||
::module-only
|
||||
|
||||
#ui
|
||||
:::div
|
||||
|
||||
```vue [app.vue]
|
||||
<script setup lang="ts">
|
||||
const locale = defineLocale({
|
||||
import type { Messages } from '@nuxt/ui'
|
||||
|
||||
const locale = defineLocale<Messages>({
|
||||
name: 'My custom locale',
|
||||
code: 'en',
|
||||
dir: 'ltr',
|
||||
@@ -54,6 +88,35 @@ const locale = defineLocale({
|
||||
</template>
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
#ui-pro
|
||||
:::div
|
||||
|
||||
```vue [app.vue]
|
||||
<script setup lang="ts">
|
||||
import type { Messages } from '@nuxt/ui-pro'
|
||||
|
||||
const locale = defineLocale<Messages>({
|
||||
name: 'My custom locale',
|
||||
code: 'en',
|
||||
dir: 'ltr',
|
||||
messages: {
|
||||
// implement pairs
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UApp :locale="locale">
|
||||
<NuxtPage />
|
||||
</UApp>
|
||||
</template>
|
||||
```
|
||||
|
||||
:::
|
||||
::
|
||||
|
||||
::tip
|
||||
Look at the `code` parameter, there you need to pass the iso code of the language. Example:
|
||||
|
||||
@@ -98,6 +161,7 @@ export default defineNuxtConfig({
|
||||
'@nuxt/ui',
|
||||
'@nuxtjs/i18n'
|
||||
],
|
||||
css: ['~/assets/css/main.css'],
|
||||
i18n: {
|
||||
locales: [{
|
||||
code: 'de',
|
||||
@@ -115,6 +179,11 @@ export default defineNuxtConfig({
|
||||
|
||||
#### Set the `locale` prop using `useI18n`
|
||||
|
||||
::module-only
|
||||
|
||||
#ui
|
||||
:::div
|
||||
|
||||
```vue [app.vue]
|
||||
<script setup lang="ts">
|
||||
import * as locales from '@nuxt/ui/locale'
|
||||
@@ -129,6 +198,28 @@ const { locale } = useI18n()
|
||||
</template>
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
#ui-pro
|
||||
:::div
|
||||
|
||||
```vue [app.vue]
|
||||
<script setup lang="ts">
|
||||
import * as locales from '@nuxt/ui-pro/locale'
|
||||
|
||||
const { locale } = useI18n()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UApp :locale="locales[locale]">
|
||||
<NuxtPage />
|
||||
</UApp>
|
||||
</template>
|
||||
```
|
||||
|
||||
:::
|
||||
::
|
||||
|
||||
::
|
||||
|
||||
### Dynamic direction
|
||||
@@ -137,6 +228,11 @@ Each locale has a `dir` property which will be used by the `App` component to se
|
||||
|
||||
In a multilingual application, you might want to set the `lang` and `dir` attributes on the `<html>` element dynamically based on the user's locale, which you can do with the [useHead](https://nuxt.com/docs/api/composables/use-head) composable:
|
||||
|
||||
::module-only
|
||||
|
||||
#ui
|
||||
:::div
|
||||
|
||||
```vue [app.vue]
|
||||
<script setup lang="ts">
|
||||
import * as locales from '@nuxt/ui/locale'
|
||||
@@ -161,6 +257,38 @@ useHead({
|
||||
</template>
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
#ui-pro
|
||||
:::div
|
||||
|
||||
```vue [app.vue]
|
||||
<script setup lang="ts">
|
||||
import * as locales from '@nuxt/ui-pro/locale'
|
||||
|
||||
const { locale } = useI18n()
|
||||
|
||||
const lang = computed(() => locales[locale.value].code)
|
||||
const dir = computed(() => locales[locale.value].dir)
|
||||
|
||||
useHead({
|
||||
htmlAttrs: {
|
||||
lang,
|
||||
dir
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UApp :locale="locales[locale]">
|
||||
<NuxtPage />
|
||||
</UApp>
|
||||
</template>
|
||||
```
|
||||
|
||||
:::
|
||||
::
|
||||
|
||||
## Supported languages
|
||||
|
||||
:supported-languages
|
||||
|
||||
@@ -17,6 +17,11 @@ Nuxt UI provides an **App** component that wraps your app to provide global conf
|
||||
|
||||
### Locale
|
||||
|
||||
::module-only
|
||||
|
||||
#ui
|
||||
:::div
|
||||
|
||||
Use the `locale` prop with the locale you want to use from `@nuxt/ui/locale`:
|
||||
|
||||
```vue [App.vue]
|
||||
@@ -31,15 +36,43 @@ import { fr } from '@nuxt/ui/locale'
|
||||
</template>
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
#ui-pro
|
||||
:::div
|
||||
|
||||
Use the `locale` prop with the locale you want to use from `@nuxt/ui-pro/locale`:
|
||||
|
||||
```vue [App.vue]
|
||||
<script setup lang="ts">
|
||||
import { fr } from '@nuxt/ui-pro/locale'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UApp :locale="fr">
|
||||
<RouterView />
|
||||
</UApp>
|
||||
</template>
|
||||
```
|
||||
|
||||
:::
|
||||
::
|
||||
|
||||
### Custom locale
|
||||
|
||||
You also have the option to add your locale using `defineLocale`:
|
||||
|
||||
::module-only
|
||||
|
||||
#ui
|
||||
:::div
|
||||
|
||||
```vue [App.vue]
|
||||
<script setup lang="ts">
|
||||
import { defineLocale } from '@nuxt/ui/composables/defineLocale'
|
||||
import type { Messages } from '@nuxt/ui'
|
||||
import { defineLocale } from '@nuxt/ui/composables/defineLocale.js'
|
||||
|
||||
const locale = defineLocale({
|
||||
const locale = defineLocale<Messages>({
|
||||
name: 'My custom locale',
|
||||
code: 'en',
|
||||
dir: 'ltr',
|
||||
@@ -56,6 +89,36 @@ const locale = defineLocale({
|
||||
</template>
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
#ui-pro
|
||||
:::div
|
||||
|
||||
```vue [App.vue]
|
||||
<script setup lang="ts">
|
||||
import type { Messages } from '@nuxt/ui-pro'
|
||||
import { defineLocale } from '@nuxt/ui/composables/defineLocale.js'
|
||||
|
||||
const locale = defineLocale<Messages>({
|
||||
name: 'My custom locale',
|
||||
code: 'en',
|
||||
dir: 'ltr',
|
||||
messages: {
|
||||
// implement pairs
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UApp :locale="locale">
|
||||
<RouterView />
|
||||
</UApp>
|
||||
</template>
|
||||
```
|
||||
|
||||
:::
|
||||
::
|
||||
|
||||
::tip
|
||||
Look at the `code` parameter, there you need to pass the iso code of the language. Example:
|
||||
|
||||
@@ -131,6 +194,11 @@ app.mount('#app')
|
||||
|
||||
#### Set the `locale` prop using `useI18n`
|
||||
|
||||
::module-only
|
||||
|
||||
#ui
|
||||
:::div
|
||||
|
||||
```vue [App.vue]
|
||||
<script setup lang="ts">
|
||||
import { useI18n } from 'vue-i18n'
|
||||
@@ -146,6 +214,29 @@ const { locale } = useI18n()
|
||||
</template>
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
#ui-pro
|
||||
:::div
|
||||
|
||||
```vue [App.vue]
|
||||
<script setup lang="ts">
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import * as locales from '@nuxt/ui-pro/locale'
|
||||
|
||||
const { locale } = useI18n()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UApp :locale="locales[locale]">
|
||||
<RouterView />
|
||||
</UApp>
|
||||
</template>
|
||||
```
|
||||
|
||||
:::
|
||||
::
|
||||
|
||||
::
|
||||
|
||||
### Dynamic direction
|
||||
@@ -154,6 +245,11 @@ Each locale has a `dir` property which will be used by the `App` component to se
|
||||
|
||||
In a multilingual application, you might want to set the `lang` and `dir` attributes on the `<html>` element dynamically based on the user's locale, which you can do with the [useHead](https://unhead.unjs.io/usage/composables/use-head) composable:
|
||||
|
||||
::module-only
|
||||
|
||||
#ui
|
||||
:::div
|
||||
|
||||
```vue [App.vue]
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
@@ -181,6 +277,41 @@ useHead({
|
||||
</template>
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
#ui-pro
|
||||
:::div
|
||||
|
||||
```vue [App.vue]
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useHead } from '@unhead/vue'
|
||||
import * as locales from '@nuxt/ui-pro/locale'
|
||||
|
||||
const { locale } = useI18n()
|
||||
|
||||
const lang = computed(() => locales[locale.value].code)
|
||||
const dir = computed(() => locales[locale.value].dir)
|
||||
|
||||
useHead({
|
||||
htmlAttrs: {
|
||||
lang,
|
||||
dir
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UApp :locale="locales[locale]">
|
||||
<RouterView />
|
||||
</UApp>
|
||||
</template>
|
||||
```
|
||||
|
||||
:::
|
||||
::
|
||||
|
||||
## Supported languages
|
||||
|
||||
:supported-languages
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
---
|
||||
title: Contribution Guide
|
||||
description: 'A comprehensive guide on contributing to Nuxt UI v3, including project structure, development workflow, and best practices.'
|
||||
description: 'A comprehensive guide on contributing to Nuxt UI, including project structure, development workflow, and best practices.'
|
||||
navigation: false
|
||||
---
|
||||
|
||||
Nuxt UI thrives thanks to its incredible community ❤️. We welcome all contributions through bug reports, pull requests, and feedback to help make this library even better.
|
||||
|
||||
::caution
|
||||
Before reporting a bug or requesting a feature, make sure that you have read through our [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 or requesting a feature, 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%20is%3Aopen%20sort%3Aupdated-desc%20label%3Av3).
|
||||
::
|
||||
|
||||
## Project Structure
|
||||
|
||||
@@ -29,23 +29,6 @@ props:
|
||||
---
|
||||
::
|
||||
|
||||
### Link
|
||||
|
||||
You can pass any property from the [Link](/components/link#props) component such as `to`, `target`, etc.
|
||||
|
||||
::component-code
|
||||
---
|
||||
ignore:
|
||||
- label
|
||||
- target
|
||||
props:
|
||||
to: https://github.com/nuxt/ui
|
||||
target: _blank
|
||||
slots:
|
||||
default: Button
|
||||
---
|
||||
::
|
||||
|
||||
### Color
|
||||
|
||||
Use the `color` prop to change the color of the Button.
|
||||
@@ -160,6 +143,96 @@ props:
|
||||
---
|
||||
::
|
||||
|
||||
### Link
|
||||
|
||||
You can pass any property from the [Link](/components/link#props) component such as `to`, `target`, etc.
|
||||
|
||||
::component-code
|
||||
---
|
||||
ignore:
|
||||
- target
|
||||
props:
|
||||
to: https://github.com/nuxt/ui
|
||||
target: _blank
|
||||
slots:
|
||||
default: Button
|
||||
---
|
||||
::
|
||||
|
||||
When the Button is a link or when using the `active` prop, you can use the `active-color` and `active-variant` props to customize the active state.
|
||||
|
||||
::component-code
|
||||
---
|
||||
prettier: true
|
||||
ignore:
|
||||
- color
|
||||
- variant
|
||||
items:
|
||||
activeColor:
|
||||
- primary
|
||||
- secondary
|
||||
- success
|
||||
- info
|
||||
- warning
|
||||
- error
|
||||
- neutral
|
||||
activeVariant:
|
||||
- solid
|
||||
- outline
|
||||
- soft
|
||||
- subtle
|
||||
- ghost
|
||||
- link
|
||||
props:
|
||||
active: true
|
||||
color: neutral
|
||||
variant: outline
|
||||
activeColor: primary
|
||||
activeVariant: solid
|
||||
slots:
|
||||
default: |
|
||||
|
||||
Button
|
||||
---
|
||||
|
||||
Button
|
||||
::
|
||||
|
||||
You can also use the `active-class` and `inactive-class` props to customize the active state.
|
||||
|
||||
::component-code
|
||||
---
|
||||
props:
|
||||
active: true
|
||||
activeClass: 'font-bold'
|
||||
inactiveClass: 'font-light'
|
||||
slots:
|
||||
default: Button
|
||||
---
|
||||
|
||||
Button
|
||||
::
|
||||
|
||||
::tip
|
||||
You can configure these styles globally in your `app.config.ts` file under the `ui.button.variants.active` key.
|
||||
|
||||
```ts
|
||||
export default defineAppConfig({
|
||||
ui: {
|
||||
button: {
|
||||
variants: {
|
||||
active: {
|
||||
true: {
|
||||
base: 'font-bold'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
||||
::
|
||||
|
||||
### Loading
|
||||
|
||||
Use the `loading` prop to show a loading icon and disable the Button.
|
||||
|
||||
@@ -209,6 +209,20 @@ name: 'calendar-min-max-dates-example'
|
||||
---
|
||||
::
|
||||
|
||||
### With other calendar systems
|
||||
|
||||
You can use other calenders from `@internationalized/date` to implement a different calendar system.
|
||||
|
||||
::component-example
|
||||
---
|
||||
name: 'calendar-other-system-example'
|
||||
---
|
||||
::
|
||||
|
||||
::note{to="https://react-spectrum.adobe.com/internationalized/date/Calendar.html#implementations"}
|
||||
You can check all the available calendars on `@internationalized/date` docs.
|
||||
::
|
||||
|
||||
### As a DatePicker
|
||||
|
||||
Use a [Button](/components/button) and a [Popover](/components/popover) component to create a date picker.
|
||||
|
||||
@@ -166,6 +166,31 @@ slots:
|
||||
:placeholder{class="h-48 m-4"}
|
||||
::
|
||||
|
||||
### Handle Only
|
||||
|
||||
Use the `handle-only` prop to only allow the Drawer to be dragged by the handle.
|
||||
|
||||
::component-code
|
||||
---
|
||||
prettier: true
|
||||
props:
|
||||
handleOnly: true
|
||||
slots:
|
||||
default: |
|
||||
|
||||
<UButton label="Open" color="neutral" variant="subtle" trailing-icon="i-lucide-chevron-up" />
|
||||
|
||||
content: |
|
||||
|
||||
<Placeholder class="h-48 m-4" />
|
||||
---
|
||||
|
||||
:u-button{label="Open" color="neutral" variant="subtle" trailing-icon="i-lucide-chevron-up"}
|
||||
|
||||
#content
|
||||
:placeholder{class="h-48 m-4"}
|
||||
::
|
||||
|
||||
### Overlay
|
||||
|
||||
Use the `overlay` prop to control whether the Drawer has an overlay or not. Defaults to `true`.
|
||||
@@ -193,13 +218,14 @@ slots:
|
||||
|
||||
### Scale background
|
||||
|
||||
Use the `should-scale-background` prop to scale the background when the Drawer is open, creating a visual depth effect.
|
||||
Use the `should-scale-background` prop to scale the background when the Drawer is open, creating a visual depth effect. You can set the `set-background-color-on-scale` prop to `false` to prevent changing the background color.
|
||||
|
||||
::component-code
|
||||
---
|
||||
prettier: true
|
||||
props:
|
||||
shouldScaleBackground: true
|
||||
setBackgroundColorOnScale: true
|
||||
slots:
|
||||
default: |
|
||||
|
||||
@@ -217,12 +243,12 @@ slots:
|
||||
::
|
||||
|
||||
::warning
|
||||
Make sure to add the `vaul-drawer-wrapper` directive to a parent element of your app to make this work.
|
||||
Make sure to add the `data-vaul-drawer-wrapper` directive to a parent element of your app to make this work.
|
||||
|
||||
```vue [app.vue]
|
||||
<template>
|
||||
<UApp>
|
||||
<div class="bg-(--ui-bg)" vaul-drawer-wrapper>
|
||||
<div class="bg-(--ui-bg)" data-vaul-drawer-wrapper>
|
||||
<NuxtLayout>
|
||||
<NuxtPage />
|
||||
</NuxtLayout>
|
||||
@@ -235,7 +261,7 @@ Make sure to add the `vaul-drawer-wrapper` directive to a parent element of your
|
||||
export default defineNuxtConfig({
|
||||
app: {
|
||||
rootAttrs: {
|
||||
'vaul-drawer-wrapper': '',
|
||||
'data-vaul-drawer-wrapper': '',
|
||||
'class': 'bg-(--ui-bg)'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ links:
|
||||
|
||||
## Usage
|
||||
|
||||
Use the Form component to validate form data using schema libraries such as [Valibot](https://github.com/fabian-hiller/valibot), [Zod](https://github.com/colinhacks/zod), [Yup](https://github.com/jquense/yup), [Joi](https://github.com/hapijs/joi), [Superstruct](https://github.com/ianstormtaylor/superstruct) or your own validation logic.
|
||||
Use the Form component to validate form data using validation libraries such as [Valibot](https://github.com/fabian-hiller/valibot), [Zod](https://github.com/colinhacks/zod), [Yup](https://github.com/jquense/yup), [Joi](https://github.com/hapijs/joi), [Superstruct](https://github.com/ianstormtaylor/superstruct) or your own validation logic.
|
||||
|
||||
It works with the [FormField](/components/form-field) component to display error messages around form elements automatically.
|
||||
|
||||
@@ -18,7 +18,7 @@ It works with the [FormField](/components/form-field) component to display error
|
||||
It requires two props:
|
||||
|
||||
- `state` - a reactive object holding the form's state.
|
||||
- `schema` - a schema object from a validation library like [Valibot](https://github.com/fabian-hiller/valibot), [Zod](https://github.com/colinhacks/zod), [Yup](https://github.com/jquense/yup), [Joi](https://github.com/hapijs/joi) or [Superstruct](https://github.com/ianstormtaylor/superstruct).
|
||||
- `schema` - any [Standard Schema](https://standardschema.dev/) or a schema from [Yup](https://github.com/jquense/yup), [Joi](https://github.com/hapijs/joi) or [Superstruct](https://github.com/ianstormtaylor/superstruct).
|
||||
|
||||
::warning
|
||||
**No validation library is included** by default, ensure you **install the one you need**.
|
||||
|
||||
@@ -334,7 +334,7 @@ name: 'modal-programmatic-example'
|
||||
::
|
||||
|
||||
::tip
|
||||
You can close the modal within the modal component by calling `modal.close()`.
|
||||
You can close the modal within the modal component by emitting `"emit('close')`.
|
||||
::
|
||||
|
||||
### Nested modals
|
||||
|
||||
@@ -333,7 +333,7 @@ name: 'slideover-programmatic-example'
|
||||
::
|
||||
|
||||
::tip
|
||||
You can close the slideover within the slideover component by calling `slideover.close()`.
|
||||
You can close the slideover within the slideover component by emitting `emit('close')`.
|
||||
::
|
||||
|
||||
### Nested slideovers
|
||||
|
||||
@@ -4,11 +4,10 @@ category: data
|
||||
links:
|
||||
- label: Tree
|
||||
icon: i-custom-reka-ui
|
||||
to: https://www.reka-ui.com/components/tree.html
|
||||
to: https://reka-ui.com/docs/components/tree
|
||||
- label: GitHub
|
||||
icon: i-simple-icons-github
|
||||
to: https://github.com/nuxt/ui/tree/v3/src/runtime/components/Tree.vue
|
||||
navigation.badge: Soon
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -34,7 +34,7 @@ export default defineNuxtConfig({
|
||||
},
|
||||
$production: {
|
||||
site: {
|
||||
url: 'https://ui3.nuxt.dev'
|
||||
url: 'https://ui.nuxt.com'
|
||||
}
|
||||
},
|
||||
|
||||
@@ -55,7 +55,7 @@ export default defineNuxtConfig({
|
||||
}]
|
||||
},
|
||||
rootAttrs: {
|
||||
'vaul-drawer-wrapper': '',
|
||||
'data-vaul-drawer-wrapper': '',
|
||||
'class': 'bg-(--ui-bg)'
|
||||
}
|
||||
},
|
||||
@@ -85,12 +85,61 @@ export default defineNuxtConfig({
|
||||
},
|
||||
|
||||
routeRules: {
|
||||
'/': { redirect: '/getting-started', prerender: false },
|
||||
'/getting-started/installation': { redirect: '/getting-started/installation/nuxt', prerender: false },
|
||||
'/getting-started/installation/pro': { redirect: '/getting-started/installation/pro/nuxt', prerender: false },
|
||||
'/getting-started/icons': { redirect: '/getting-started/icons/nuxt', prerender: false },
|
||||
'/getting-started/color-mode': { redirect: '/getting-started/color-mode/nuxt', prerender: false },
|
||||
'/getting-started/i18n': { redirect: '/getting-started/i18n/nuxt', prerender: false },
|
||||
'/composables': { redirect: '/composables/define-shortcuts', prerender: false }
|
||||
'/composables': { redirect: '/composables/define-shortcuts', prerender: false },
|
||||
// v2 redirects
|
||||
'/getting-started/theming': { redirect: { to: '/getting-started/theme', statusCode: 301 }, prerender: false },
|
||||
'/pro/getting-started/**': { redirect: { to: '/getting-started/installation/pro/nuxt', statusCode: 301 }, prerender: false },
|
||||
'/playground': { redirect: { to: '/getting-started/installation/nuxt', statusCode: 301 }, prerender: false },
|
||||
'/pro/guide/**': { redirect: { to: '/getting-started/installation/pro/nuxt', statusCode: 301 }, prerender: false },
|
||||
'/pro/prose/**': { redirect: { to: '/getting-started/typography#vue-components', statusCode: 301 }, prerender: false },
|
||||
'/components/range': { redirect: { to: '/components/slider', statusCode: 301 }, prerender: false },
|
||||
'/components/date-picker': { redirect: { to: '/components/calendar#as-a-datepicker', statusCode: 301 }, prerender: false },
|
||||
'/components/dropdown': { redirect: { to: '/components/dropdown-menu', statusCode: 301 }, prerender: false },
|
||||
'/components/notification': { redirect: { to: '/components/toast', statusCode: 301 }, prerender: false },
|
||||
'/components/vertical-navigation': { redirect: { to: '/components/navigation-menu', statusCode: 301 }, prerender: false },
|
||||
'/components/horizontal-navigation': { redirect: { to: '/components/navigation-menu', statusCode: 301 }, prerender: false },
|
||||
'/components/divider': { redirect: { to: '/components/separator', statusCode: 301 }, prerender: false },
|
||||
'/components/toggle': { redirect: { to: '/components/switch', statusCode: 301 }, prerender: false },
|
||||
'/components/form-group': { redirect: { to: '/components/form-field', statusCode: 301 }, prerender: false },
|
||||
'/pro/components': { redirect: { to: '/components', statusCode: 301 }, prerender: false },
|
||||
'/pro/components/docs/docs-search': { redirect: { to: '/components/content-search', statusCode: 301 }, prerender: false },
|
||||
'/pro/components/docs-search': { redirect: { to: '/components/content-search', statusCode: 301 }, prerender: false },
|
||||
'/pro/components/landing-hero': { redirect: { to: '/components/page-hero', statusCode: 301 }, prerender: false },
|
||||
'/pro/components/landing-cta': { redirect: { to: '/components/page-cta', statusCode: 301 }, prerender: false },
|
||||
'/pro/components/landing-card': { redirect: { to: '/components/page-card', statusCode: 301 }, prerender: false },
|
||||
'/pro/components/landing-section': { redirect: { to: '/components/page-section', statusCode: 301 }, prerender: false },
|
||||
'/pro/components/landing-faq': { redirect: { to: '/components/page-accordion', statusCode: 301 }, prerender: false },
|
||||
'/pro/components/landing-grid': { redirect: { to: '/components/page-grid', statusCode: 301 }, prerender: false },
|
||||
'/pro/components/landing-logos': { redirect: { to: '/components/page-logos', statusCode: 301 }, prerender: false },
|
||||
'/pro/components/landing-testimonial': { redirect: { to: '/components/page-card#as-a-testimonial', statusCode: 301 }, prerender: false },
|
||||
'/pro/components/blog-list': { redirect: { to: '/components/blog-posts', statusCode: 301 }, prerender: false },
|
||||
'/pro/components/color-mode-toggle': { redirect: { to: '/components/color-mode-switch', statusCode: 301 }, prerender: false },
|
||||
'/pro/components/dashboard-card': { redirect: { to: '/components/page-card', statusCode: 301 }, prerender: false },
|
||||
'/pro/components/dashboard-layout': { redirect: { to: '/components/dashboard-group', statusCode: 301 }, prerender: false },
|
||||
'/pro/components/dashboard-modal': { redirect: { to: '/components/modal', statusCode: 301 }, prerender: false },
|
||||
'/pro/components/dashboard-navbar-toggle': { redirect: { to: '/components/dashboard-sidebar-toggle', statusCode: 301 }, prerender: false },
|
||||
'/pro/components/dashboard-page': { redirect: { to: '/components/dashboard-panel', statusCode: 301 }, prerender: false },
|
||||
'/pro/components/dashboard-panel-content': { redirect: { to: '/components/dashboard-panel', statusCode: 301 }, prerender: false },
|
||||
'/pro/components/dashboard-panel-handle': { redirect: { to: '/components/dashboard-resize-handle', statusCode: 301 }, prerender: false },
|
||||
'/pro/components/dashboard-section': { redirect: { to: '/components/page-card', statusCode: 301 }, prerender: false },
|
||||
'/pro/components/dashboard-sidebar-links': { redirect: { to: '/components/navigation-menu', statusCode: 301 }, prerender: false },
|
||||
'/pro/components/dashboard-slideover': { redirect: { to: '/components/slideover', statusCode: 301 }, prerender: false },
|
||||
'/pro/components/navigation-accordion': { redirect: { to: '/components/content-navigation', statusCode: 301 }, prerender: false },
|
||||
'/pro/components/navigation-links': { redirect: { to: '/components/content-navigation', statusCode: 301 }, prerender: false },
|
||||
'/pro/components/navigation-tree': { redirect: { to: '/components/content-navigation', statusCode: 301 }, prerender: false },
|
||||
'/pro/components/page-error': { redirect: { to: '/components/error', statusCode: 301 }, prerender: false },
|
||||
'/pro/components/footer-links': { redirect: { to: '/components/navigation-menu', statusCode: 301 }, prerender: false },
|
||||
'/pro/components/header-links': { redirect: { to: '/components/navigation-menu', statusCode: 301 }, prerender: false },
|
||||
'/pro/components/pricing-card': { redirect: { to: '/components/pricing-plan', statusCode: 301 }, prerender: false },
|
||||
'/pro/components/pricing-grid': { redirect: { to: '/components/pricing-plans', statusCode: 301 }, prerender: false },
|
||||
'/pro/components/pricing-switch': { redirect: { to: '/components/switch', statusCode: 301 }, prerender: false },
|
||||
'/pro/components/**': { redirect: { to: '/components/**', statusCode: 301 }, prerender: false },
|
||||
'/releases': { redirect: 'https://github.com/nuxt/ui/releases', prerender: false }
|
||||
},
|
||||
|
||||
future: {
|
||||
@@ -104,9 +153,10 @@ export default defineNuxtConfig({
|
||||
routes: [
|
||||
'/getting-started',
|
||||
'/api/countries.json',
|
||||
'/api/locales.json'
|
||||
'/api/locales.json',
|
||||
// '/api/releases.json',
|
||||
// '/api/pulls.json'
|
||||
'/404.html'
|
||||
],
|
||||
crawlLinks: true,
|
||||
autoSubfolderIndex: false
|
||||
@@ -127,7 +177,12 @@ export default defineNuxtConfig({
|
||||
vite: {
|
||||
plugins: [
|
||||
yaml()
|
||||
]
|
||||
],
|
||||
server: {
|
||||
fs: {
|
||||
allow: process.env.NUXT_UI_PRO_PATH ? [resolve(process.env.NUXT_UI_PRO_PATH)] : undefined
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
componentMeta: {
|
||||
@@ -169,12 +224,12 @@ export default defineNuxtConfig({
|
||||
},
|
||||
|
||||
llms: {
|
||||
domain: 'https://ui3.nuxt.dev',
|
||||
title: 'Nuxt UI v3',
|
||||
domain: 'https://ui.nuxt.com',
|
||||
title: 'Nuxt UI',
|
||||
description: 'A comprehensive, Nuxt-integrated UI library providing a rich set of fully-styled, accessible and highly customizable components for building modern web applications.',
|
||||
full: {
|
||||
title: 'Nuxt UI v3 Full Documentation',
|
||||
description: 'This is the full documentation for Nuxt UI v3. It includes all the Markdown files written with the MDC syntax.'
|
||||
title: 'Nuxt UI Full Documentation',
|
||||
description: 'This is the full documentation for Nuxt UI. It includes all the Markdown files written with the MDC syntax.'
|
||||
},
|
||||
sections: [
|
||||
{
|
||||
|
||||
@@ -4,34 +4,33 @@
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"@iconify-json/logos": "^1.2.4",
|
||||
"@iconify-json/lucide": "^1.2.27",
|
||||
"@iconify-json/simple-icons": "^1.2.26",
|
||||
"@iconify-json/lucide": "^1.2.31",
|
||||
"@iconify-json/simple-icons": "^1.2.29",
|
||||
"@iconify-json/vscode-icons": "^1.2.16",
|
||||
"@nuxt/content": "^3.2.2",
|
||||
"@nuxt/image": "^1.9.0",
|
||||
"@nuxt/content": "^3.4.0",
|
||||
"@nuxt/image": "^1.10.0",
|
||||
"@nuxt/ui": "latest",
|
||||
"@nuxt/ui-pro": "https://pkg.pr.new/@nuxt/ui-pro@c02527f",
|
||||
"@nuxthub/core": "^0.8.17",
|
||||
"@nuxt/ui-pro": "https://pkg.pr.new/@nuxt/ui-pro@d96a086",
|
||||
"@nuxthub/core": "^0.8.18",
|
||||
"@nuxtjs/plausible": "^1.2.0",
|
||||
"@octokit/rest": "^21.1.1",
|
||||
"@rollup/plugin-yaml": "^4.1.2",
|
||||
"@vueuse/nuxt": "^12.7.0",
|
||||
"@vueuse/nuxt": "^13.0.0",
|
||||
"joi": "^17.13.3",
|
||||
"motion": "^12.4.7",
|
||||
"motion-v": "0.11.0-beta.4",
|
||||
"nuxt": "^3.15.4",
|
||||
"motion-v": "0.13.1",
|
||||
"nuxt": "^3.16.1",
|
||||
"nuxt-component-meta": "^0.10.0",
|
||||
"nuxt-llms": "^0.1.0",
|
||||
"nuxt-og-image": "^4.1.4",
|
||||
"prettier": "^3.5.2",
|
||||
"shiki-transformer-color-highlight": "^0.2.0",
|
||||
"nuxt-og-image": "^5.0.5",
|
||||
"prettier": "^3.5.3",
|
||||
"shiki-transformer-color-highlight": "^1.0.0",
|
||||
"superstruct": "^2.0.2",
|
||||
"ufo": "^1.5.4",
|
||||
"valibot": "^0.42.1",
|
||||
"valibot": "^1.0.0",
|
||||
"yup": "^1.6.1",
|
||||
"zod": "^3.24.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"wrangler": "^3.111.0"
|
||||
"wrangler": "^3.114.2"
|
||||
}
|
||||
}
|
||||
|
||||
BIN
docs/public/pro/ad.png
Normal file
|
After Width: | Height: | Size: 86 KiB |
BIN
docs/public/pro/blocks/image1.png
Normal file
|
After Width: | Height: | Size: 74 KiB |
BIN
docs/public/pro/blocks/image10.png
Normal file
|
After Width: | Height: | Size: 79 KiB |
BIN
docs/public/pro/blocks/image11.png
Normal file
|
After Width: | Height: | Size: 34 KiB |
BIN
docs/public/pro/blocks/image12.png
Normal file
|
After Width: | Height: | Size: 91 KiB |
BIN
docs/public/pro/blocks/image13.png
Normal file
|
After Width: | Height: | Size: 129 KiB |
BIN
docs/public/pro/blocks/image14.png
Normal file
|
After Width: | Height: | Size: 55 KiB |
BIN
docs/public/pro/blocks/image15.png
Normal file
|
After Width: | Height: | Size: 354 KiB |
BIN
docs/public/pro/blocks/image16.png
Normal file
|
After Width: | Height: | Size: 118 KiB |
BIN
docs/public/pro/blocks/image17.png
Normal file
|
After Width: | Height: | Size: 85 KiB |
BIN
docs/public/pro/blocks/image2.png
Normal file
|
After Width: | Height: | Size: 93 KiB |
BIN
docs/public/pro/blocks/image3.png
Normal file
|
After Width: | Height: | Size: 182 KiB |
BIN
docs/public/pro/blocks/image4.png
Normal file
|
After Width: | Height: | Size: 116 KiB |
BIN
docs/public/pro/blocks/image5.png
Normal file
|
After Width: | Height: | Size: 122 KiB |
BIN
docs/public/pro/blocks/image6.png
Normal file
|
After Width: | Height: | Size: 95 KiB |