mirror of
https://github.com/ArthurDanjou/ui.git
synced 2026-01-20 15:01:46 +01:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
723065afa7 | ||
|
|
e67305e412 | ||
|
|
33ed3935a3 |
4
.github/ISSUE_TEMPLATE/bug-report-v3.yml
vendored
4
.github/ISSUE_TEMPLATE/bug-report-v3.yml
vendored
@@ -5,7 +5,7 @@ body:
|
|||||||
- type: markdown
|
- type: markdown
|
||||||
attributes:
|
attributes:
|
||||||
value: |
|
value: |
|
||||||
Before reporting a bug, please make sure that you have read through our [v3 documentation](https://ui.nuxt.com/) 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://ui3.nuxt.dev/) and existing [issues](https://github.com/nuxt/ui/issues?q=is%3Aissue%20is%3Aopen%20sort%3Aupdated-desc%20label%3Av3).
|
||||||
- type: textarea
|
- type: textarea
|
||||||
id: env
|
id: env
|
||||||
attributes:
|
attributes:
|
||||||
@@ -37,7 +37,7 @@ body:
|
|||||||
id: version
|
id: version
|
||||||
attributes:
|
attributes:
|
||||||
label: Version
|
label: Version
|
||||||
placeholder: v3.0.0
|
placeholder: v3.0.0-alpha.x
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: textarea
|
- type: textarea
|
||||||
|
|||||||
2
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
2
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
@@ -5,7 +5,7 @@ body:
|
|||||||
- type: markdown
|
- type: markdown
|
||||||
attributes:
|
attributes:
|
||||||
value: |
|
value: |
|
||||||
Before reporting a bug, please make sure that you have read through our [documentation](https://ui2.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://ui.nuxt.com) and existing [issues](https://github.com/nuxt/ui/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc).
|
||||||
- type: textarea
|
- type: textarea
|
||||||
id: env
|
id: env
|
||||||
attributes:
|
attributes:
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ body:
|
|||||||
- type: markdown
|
- type: markdown
|
||||||
attributes:
|
attributes:
|
||||||
value: |
|
value: |
|
||||||
Before requesting a feature, please make sure that you have read through our [v3 documentation](https://ui.nuxt.com/) 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://ui3.nuxt.dev/) and existing [issues](https://github.com/nuxt/ui/issues?q=is%3Aissue%20is%3Aopen%20sort%3Aupdated-desc%20label%3Av3).
|
||||||
- type: textarea
|
- type: textarea
|
||||||
id: description
|
id: description
|
||||||
attributes:
|
attributes:
|
||||||
|
|||||||
2
.github/ISSUE_TEMPLATE/feature-request.yml
vendored
2
.github/ISSUE_TEMPLATE/feature-request.yml
vendored
@@ -5,7 +5,7 @@ body:
|
|||||||
- type: markdown
|
- type: markdown
|
||||||
attributes:
|
attributes:
|
||||||
value: |
|
value: |
|
||||||
Before requesting a feature, please make sure that you have read through our [documentation](https://ui2.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://ui.nuxt.com) and existing [issues](https://github.com/nuxt/ui/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc).
|
||||||
- type: textarea
|
- type: textarea
|
||||||
id: description
|
id: description
|
||||||
attributes:
|
attributes:
|
||||||
|
|||||||
2
.github/ISSUE_TEMPLATE/question-v3.yml
vendored
2
.github/ISSUE_TEMPLATE/question-v3.yml
vendored
@@ -5,7 +5,7 @@ body:
|
|||||||
- type: markdown
|
- type: markdown
|
||||||
attributes:
|
attributes:
|
||||||
value: |
|
value: |
|
||||||
Before asking a question, please make sure that you have read through our [v3 documentation](https://ui.nuxt.com/) 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://ui3.nuxt.dev/) and existing [issues](https://github.com/nuxt/ui/issues?q=is%3Aissue%20is%3Aopen%20sort%3Aupdated-desc%20label%3Av3).
|
||||||
- type: textarea
|
- type: textarea
|
||||||
id: description
|
id: description
|
||||||
attributes:
|
attributes:
|
||||||
|
|||||||
2
.github/ISSUE_TEMPLATE/question.yml
vendored
2
.github/ISSUE_TEMPLATE/question.yml
vendored
@@ -5,7 +5,7 @@ body:
|
|||||||
- type: markdown
|
- type: markdown
|
||||||
attributes:
|
attributes:
|
||||||
value: |
|
value: |
|
||||||
Before asking a question, please make sure that you have read through our [documentation](https://ui2.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://ui.nuxt.com) and existing [issues](https://github.com/nuxt/ui/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc).
|
||||||
- type: textarea
|
- type: textarea
|
||||||
id: description
|
id: description
|
||||||
attributes:
|
attributes:
|
||||||
|
|||||||
156
.github/workflows/module.yml
vendored
156
.github/workflows/module.yml
vendored
@@ -50,164 +50,16 @@ jobs:
|
|||||||
run: pnpm run typecheck
|
run: pnpm run typecheck
|
||||||
|
|
||||||
- name: Test
|
- name: Test
|
||||||
run: pnpm run test run
|
run: pnpm run test
|
||||||
|
|
||||||
- name: Test (vue)
|
- name: Test (vue)
|
||||||
run: pnpm run test:vue run
|
run: pnpm run test:vue
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: pnpm run build
|
run: pnpm run build
|
||||||
|
|
||||||
- name: Build playground
|
- name: Build vue fixture
|
||||||
run: pnpm run dev:build
|
run: pnpm run test:vue:build
|
||||||
|
|
||||||
- name: Build playground (vue)
|
|
||||||
run: pnpm run dev:vue:build
|
|
||||||
|
|
||||||
- name: Publish
|
- name: Publish
|
||||||
run: pnpx pkg-pr-new publish --compact --no-template --pnpm
|
run: pnpx pkg-pr-new publish --compact --no-template --pnpm
|
||||||
|
|
||||||
starter-nuxt:
|
|
||||||
needs: build
|
|
||||||
|
|
||||||
runs-on: ${{ matrix.os }}
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
pull-requests: read
|
|
||||||
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
os: [ubuntu-latest] # macos-latest, windows-latest
|
|
||||||
node: [22]
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
repository: nuxtlabs/nuxt-ui-starter
|
|
||||||
|
|
||||||
- name: Store commit SHA
|
|
||||||
run: |
|
|
||||||
echo "COMMIT_SHA=$(echo ${{ github.workflow_sha }} | cut -c1-7)" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Install pnpm
|
|
||||||
uses: pnpm/action-setup@v4
|
|
||||||
|
|
||||||
- name: Install node
|
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: 22
|
|
||||||
cache: pnpm
|
|
||||||
|
|
||||||
- name: Install latest nuxt/ui
|
|
||||||
run: pnpm install https://pkg.pr.new/@nuxt/ui@${{ env.COMMIT_SHA }} --lockfile-only
|
|
||||||
|
|
||||||
- name: Install dependencies
|
|
||||||
run: pnpm install
|
|
||||||
|
|
||||||
- name: Typecheck
|
|
||||||
run: pnpm run typecheck
|
|
||||||
|
|
||||||
- name: Build
|
|
||||||
run: pnpm run build
|
|
||||||
|
|
||||||
starter-vue:
|
|
||||||
needs: build
|
|
||||||
|
|
||||||
runs-on: ${{ matrix.os }}
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
pull-requests: read
|
|
||||||
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
os: [ubuntu-latest] # macos-latest, windows-latest
|
|
||||||
node: [22]
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
repository: nuxtlabs/nuxt-ui-vue-starter
|
|
||||||
|
|
||||||
- name: Store commit SHA
|
|
||||||
run: |
|
|
||||||
echo "COMMIT_SHA=$(echo ${{ github.workflow_sha }} | cut -c1-7)" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Install pnpm
|
|
||||||
uses: pnpm/action-setup@v4
|
|
||||||
|
|
||||||
- name: Install node
|
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: 22
|
|
||||||
cache: pnpm
|
|
||||||
|
|
||||||
- name: Install latest nuxt/ui
|
|
||||||
run: pnpm install https://pkg.pr.new/@nuxt/ui@${{ env.COMMIT_SHA }} --lockfile-only
|
|
||||||
|
|
||||||
- name: Install dependencies
|
|
||||||
run: pnpm install
|
|
||||||
|
|
||||||
- name: Typecheck
|
|
||||||
run: pnpm run typecheck
|
|
||||||
|
|
||||||
- name: Build
|
|
||||||
run: pnpm run build
|
|
||||||
|
|
||||||
nuxt-ui-pro:
|
|
||||||
needs: build
|
|
||||||
|
|
||||||
# Only run this job if not a fork PR (when push event or PR from same repo)
|
|
||||||
if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository
|
|
||||||
|
|
||||||
runs-on: ${{ matrix.os }}
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
pull-requests: read
|
|
||||||
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
os: [ubuntu-latest] # macos-latest, windows-latest
|
|
||||||
node: [22]
|
|
||||||
|
|
||||||
env:
|
|
||||||
NUXT_UI_PRO_LICENSE: ${{ secrets.NUXT_UI_PRO_LICENSE }}
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
repository: nuxt/ui-pro
|
|
||||||
token: ${{ secrets.NUXT_GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Store commit SHA
|
|
||||||
run: |
|
|
||||||
echo "COMMIT_SHA=$(echo ${{ github.workflow_sha }} | cut -c1-7)" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Install pnpm
|
|
||||||
uses: pnpm/action-setup@v4
|
|
||||||
|
|
||||||
- name: Install node
|
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: 22
|
|
||||||
cache: pnpm
|
|
||||||
|
|
||||||
- name: Install latest nuxt/ui
|
|
||||||
run: pnpm install https://pkg.pr.new/@nuxt/ui@${{ env.COMMIT_SHA }} --lockfile-only
|
|
||||||
|
|
||||||
- name: Install dependencies
|
|
||||||
run: pnpm install
|
|
||||||
|
|
||||||
- name: Prepare
|
|
||||||
run: pnpm run dev:prepare
|
|
||||||
|
|
||||||
- name: Typecheck
|
|
||||||
run: pnpm run typecheck
|
|
||||||
|
|
||||||
- name: Build
|
|
||||||
run: pnpm run build
|
|
||||||
|
|||||||
16
.github/workflows/stale.yml
vendored
16
.github/workflows/stale.yml
vendored
@@ -10,16 +10,14 @@ jobs:
|
|||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
issues: write
|
issues: write
|
||||||
|
pull-requests: write
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/stale@v9
|
- uses: actions/stale@v9
|
||||||
with:
|
with:
|
||||||
days-before-stale: -1 # Issues and PR will never be flagged stale automatically.
|
exempt-issue-labels: triage,v3
|
||||||
stale-issue-label: 'needs reproduction' # Label that flags an issue as stale.
|
stale-issue-message: 'This issue is stale because it has been open for 30 days with no activity.'
|
||||||
only-labels: 'needs reproduction' # Only process these issues
|
stale-issue-label: stale
|
||||||
days-before-issue-close: 7
|
stale-pr-label: stale
|
||||||
ignore-updates: true
|
days-before-stale: 30
|
||||||
remove-stale-when-updated: false
|
days-before-close: -1
|
||||||
close-issue-message: This issue was closed because it was open for 7 days without a reproduction.
|
|
||||||
close-issue-label: closed-by-bot
|
|
||||||
operations-per-run: 300 #default 30
|
|
||||||
|
|||||||
97
CHANGELOG.md
97
CHANGELOG.md
@@ -1,102 +1,5 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
## [3.0.2](https://github.com/nuxt/ui/compare/v3.0.1...v3.0.2) (2025-03-28)
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* **Calendar:** allow year and month buttons styling ([#3672](https://github.com/nuxt/ui/issues/3672)) ([4a2b77d](https://github.com/nuxt/ui/commit/4a2b77d86c28806234002340eda39de4dc78cce0))
|
|
||||||
* **locale:** add Armenian language ([#3664](https://github.com/nuxt/ui/issues/3664)) ([c76f590](https://github.com/nuxt/ui/commit/c76f5900970e3f5c451192b1207ccea04771e8b3))
|
|
||||||
* **Table:** add `empty` prop ([afff54f](https://github.com/nuxt/ui/commit/afff54fecd31497238461e0a44abd8668ed734c3))
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **Avatar:** proxy `$attrs` to default slot ([#3712](https://github.com/nuxt/ui/issues/3712)) ([88f349d](https://github.com/nuxt/ui/commit/88f349d0d74eb1c2ce5066818731759c25a9e83e))
|
|
||||||
* **Button:** use `focus:outline-none` instead of `focus:outline-hidden` ([c231fe5](https://github.com/nuxt/ui/commit/c231fe5f26ca7614df46a7ec8a5ce7f4ec8884e7)), closes [#3658](https://github.com/nuxt/ui/issues/3658)
|
|
||||||
* **CommandPalette:** use `group.id` as key ([bc61d29](https://github.com/nuxt/ui/commit/bc61d29cce531715a6279444845f02a002a22af7))
|
|
||||||
* **components:** improve generic types ([#3331](https://github.com/nuxt/ui/issues/3331)) ([b998354](https://github.com/nuxt/ui/commit/b9983549a4b743724ea3ef99cc4a243f5ca41e53))
|
|
||||||
* **Container:** add `w-full` class ([df00149](https://github.com/nuxt/ui/commit/df001495980647cab1e67fd16154f1bc778de5e2))
|
|
||||||
* **defineLocale/defineShortcuts:** remove `@__NO_SIDE_EFFECTS__` ([82e2665](https://github.com/nuxt/ui/commit/82e26655a40782555299516f32a76046fa0dbd3a))
|
|
||||||
* **Drawer:** remove `fadeFromIndex` prop proxy ([f7604e5](https://github.com/nuxt/ui/commit/f7604e565f717001a4d4c2974cf23559a3f01c21))
|
|
||||||
* **Form:** clear dirty state after submit ([#3692](https://github.com/nuxt/ui/issues/3692)) ([3dd88ba](https://github.com/nuxt/ui/commit/3dd88bacecb2945efba8cc3cb4fe59fcbc056e9a))
|
|
||||||
* **FormField:** add `help` to `aria-describedby` attribute ([#3691](https://github.com/nuxt/ui/issues/3691)) ([20c3392](https://github.com/nuxt/ui/commit/20c33920d005332db3c83f33a8c54c7c227ce0a0))
|
|
||||||
* **InputMenu/SelectMenu:** empty search results ([94b6e52](https://github.com/nuxt/ui/commit/94b6e520f5ccf011204e953421fcc5b44b637e51))
|
|
||||||
* **InputMenu:** reset `searchTerm` on `update:open` ([3074632](https://github.com/nuxt/ui/commit/3074632523e67fa6a0ad3d9a71e5692c285bdc3a)), closes [#3620](https://github.com/nuxt/ui/issues/3620)
|
|
||||||
* **Link:** handle `aria-current` like `NuxtLink` / `RouterLink` ([c531d02](https://github.com/nuxt/ui/commit/c531d0248be7863980a1f676643c2dea8301c009))
|
|
||||||
* **Link:** prevent `active="true"` binding on html ([d73768b](https://github.com/nuxt/ui/commit/d73768b70453d60dd4186a996c1cf808b0294bf6))
|
|
||||||
* **Link:** properly pick all `aria-*` & `data-*` attrs ([ade16b7](https://github.com/nuxt/ui/commit/ade16b76cf535924a8d0f402b4d5d65cb67a55eb))
|
|
||||||
* **Link:** proxy `onClick` ([370054b](https://github.com/nuxt/ui/commit/370054b20c0201c9dba84ddfcd1e916594619b93)), closes [#3631](https://github.com/nuxt/ui/issues/3631)
|
|
||||||
* **NavigationMenu:** add `z-index` on viewport ([0095d89](https://github.com/nuxt/ui/commit/0095d8916bf361c0c89972e2f86b79850510c6a9)), closes [#3654](https://github.com/nuxt/ui/issues/3654)
|
|
||||||
* **Switch:** prevent transition on focus outline ([68787b2](https://github.com/nuxt/ui/commit/68787b26fdf2bd5f9d9e812e5bfddb19abe45d1d))
|
|
||||||
* **Table:** wrong condition on `caption` slot ([4ebb94c](https://github.com/nuxt/ui/commit/4ebb94cd7ef909b3547bce0922f75fe3ff74de4c))
|
|
||||||
* **Tabs:** remove `focus:outline-hidden` class ([1769d5e](https://github.com/nuxt/ui/commit/1769d5ed6ea46b1f7eafdc48cb6456512229f98b))
|
|
||||||
* **types:** add missing export for ButtonGroup ([#3709](https://github.com/nuxt/ui/issues/3709)) ([e7e6745](https://github.com/nuxt/ui/commit/e7e674559981177ad08be42418746060d7737df9))
|
|
||||||
* **useOverlay:** refine `open` method type to infer close emit return type ([#3716](https://github.com/nuxt/ui/issues/3716)) ([bd99c2d](https://github.com/nuxt/ui/commit/bd99c2d850d57baccc51e049c0b578a6fc6ab431))
|
|
||||||
* **vue:** mock `nuxtApp.hooks` & `useRuntimeHook` ([23bfeb9](https://github.com/nuxt/ui/commit/23bfeb937004d619187a67fb43e4c76b13d00069))
|
|
||||||
|
|
||||||
## [3.0.1](https://github.com/nuxt/ui/compare/v3.0.0...v3.0.1) (2025-03-21)
|
|
||||||
|
|
||||||
### ⚠ BREAKING CHANGES
|
|
||||||
|
|
||||||
* **Form:** drop explicit support for `zod` and `valibot` (#3617)
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* **components:** handle events in `content` prop ([5dec0e1](https://github.com/nuxt/ui/commit/5dec0e16e28549b8833aaab17a87fada63d6598c))
|
|
||||||
* **locale:** add Catalan language ([#3550](https://github.com/nuxt/ui/issues/3550)) ([53cf1b4](https://github.com/nuxt/ui/commit/53cf1b4c14a2a0e076e1e77688852e6bd0a28a74))
|
|
||||||
* **locale:** add Central Kurdish language ([#3566](https://github.com/nuxt/ui/issues/3566)) ([b2034cc](https://github.com/nuxt/ui/commit/b2034ccc91eec6a2842c6f83d159e5aa6fd5f2fd))
|
|
||||||
* **locale:** add Romanian language ([#3587](https://github.com/nuxt/ui/issues/3587)) ([0229b0f](https://github.com/nuxt/ui/commit/0229b0fd4644a97db7eb3154c3c87a26634dcfbb))
|
|
||||||
* **locale:** add Urdu language ([#3611](https://github.com/nuxt/ui/issues/3611)) ([126ba23](https://github.com/nuxt/ui/commit/126ba2326f8153e155e1013db92c6ee417117610))
|
|
||||||
* **locale:** add Uzbek language ([#3548](https://github.com/nuxt/ui/issues/3548)) ([302e04b](https://github.com/nuxt/ui/commit/302e04bd77ae8b165046b264c8d23626e92f8fb5))
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **Calendar:** grey out days outside of displayed month ([#3639](https://github.com/nuxt/ui/issues/3639)) ([a516866](https://github.com/nuxt/ui/commit/a5168666b7dff08e714d57f497737e7a670f457c))
|
|
||||||
* **ContextMenu/DropdownMenu:** remove `any` from `proxySlots` ([#3623](https://github.com/nuxt/ui/issues/3623)) ([764c41a](https://github.com/nuxt/ui/commit/764c41a0c60dd1c12d39a86af9f5f11b9e6cdc8c))
|
|
||||||
* **Modal/Slideover/Toast:** prevent unnecessary close instantiation ([f4c417d](https://github.com/nuxt/ui/commit/f4c417d9ef5409b52084bdf9d8cbccee3139709f))
|
|
||||||
* **module:** handle tailwindcss import without `theme(static)` ([#3630](https://github.com/nuxt/ui/issues/3630)) ([ecff9ab](https://github.com/nuxt/ui/commit/ecff9abc720bdda3a279d5bcfb7b477ff885f2e4))
|
|
||||||
* **module:** mark functions used in exports as pure ([#3604](https://github.com/nuxt/ui/issues/3604)) ([57efc78](https://github.com/nuxt/ui/commit/57efc78a3b3fa4a54bcd13df47d570a18fba2bc4))
|
|
||||||
* **RadioGroup:** handle `disabled` on items ([fe0bd83](https://github.com/nuxt/ui/commit/fe0bd83d11b0dfa53b58d423bc917f8e21d73444)), closes [nuxt/ui-pro#911](https://github.com/nuxt/ui-pro/issues/911)
|
|
||||||
* **Table:** allow links to be opened when [@select](https://github.com/select) is used ([#3580](https://github.com/nuxt/ui/issues/3580)) ([e80cc15](https://github.com/nuxt/ui/commit/e80cc1592fb244dd7692486a4c1ca5b1c2008112))
|
|
||||||
* **types:** add missing export for Icon ([#3568](https://github.com/nuxt/ui/issues/3568)) ([5e62493](https://github.com/nuxt/ui/commit/5e624933216db95cbfd1b8034b2eb0f13846ae55))
|
|
||||||
* **unplugin:** include `@compodium/examples` in auto-imports paths ([#3585](https://github.com/nuxt/ui/issues/3585)) ([cc504b8](https://github.com/nuxt/ui/commit/cc504b8a4b69dd76b49659d5c206ef23dcb9e475))
|
|
||||||
* **useLocale:** unique symbol to use in `@nuxt/ui-pro` ([#3603](https://github.com/nuxt/ui/issues/3603)) ([dec2730](https://github.com/nuxt/ui/commit/dec2730aaea1327434837cfa022ea04056757cbf))
|
|
||||||
* **vue:** missing unhead context ([#3589](https://github.com/nuxt/ui/issues/3589)) ([0897e9e](https://github.com/nuxt/ui/commit/0897e9ef05fbee4f021f317bb7c2d0b7007f1b75))
|
|
||||||
|
|
||||||
### Code Refactoring
|
|
||||||
|
|
||||||
* **Form:** drop explicit support for `zod` and `valibot` ([#3617](https://github.com/nuxt/ui/issues/3617)) ([9a4bb34](https://github.com/nuxt/ui/commit/9a4bb34d7d14add0a3199103f4b583e8307d1d6d))
|
|
||||||
|
|
||||||
## [3.0.0](https://github.com/nuxt/ui/compare/v3.0.0-beta.4...v3.0.0) (2025-03-12)
|
|
||||||
|
|
||||||
## [3.0.0-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)
|
## [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
|
### Bug Fixes
|
||||||
|
|||||||
35
README.md
35
README.md
@@ -11,31 +11,31 @@
|
|||||||
[![License][license-src]][license-href]
|
[![License][license-src]][license-href]
|
||||||
[![Nuxt][nuxt-src]][nuxt-href]
|
[![Nuxt][nuxt-src]][nuxt-href]
|
||||||
|
|
||||||
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.
|
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.
|
||||||
|
|
||||||
> [!NOTE]
|
> [!NOTE]
|
||||||
> You are on the `v3` development branch, check out the [v2 branch](https://github.com/nuxt/ui/tree/v2) for Nuxt UI v2.
|
> You are on the `v3` development branch, check out the [dev branch](https://github.com/nuxt/ui/tree/dev) for Nuxt UI v2.
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
Visit https://ui.nuxt.com to explore the documentation.
|
Visit https://ui3.nuxt.dev to explore the documentation.
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
```bash [pnpm]
|
```bash [pnpm]
|
||||||
pnpm add @nuxt/ui
|
pnpm add @nuxt/ui@next
|
||||||
```
|
```
|
||||||
|
|
||||||
```bash [yarn]
|
```bash [yarn]
|
||||||
yarn add @nuxt/ui
|
yarn add @nuxt/ui@next
|
||||||
```
|
```
|
||||||
|
|
||||||
```bash [npm]
|
```bash [npm]
|
||||||
npm install @nuxt/ui
|
npm install @nuxt/ui@next
|
||||||
```
|
```
|
||||||
|
|
||||||
```bash [bun]
|
```bash [bun]
|
||||||
bun add @nuxt/ui
|
bun add @nuxt/ui@next
|
||||||
```
|
```
|
||||||
|
|
||||||
### Nuxt
|
### Nuxt
|
||||||
@@ -51,11 +51,11 @@ export default defineNuxtConfig({
|
|||||||
2. Import Tailwind CSS and Nuxt UI in your CSS:
|
2. Import Tailwind CSS and Nuxt UI in your CSS:
|
||||||
|
|
||||||
```css [assets/css/main.css]
|
```css [assets/css/main.css]
|
||||||
@import "tailwindcss";
|
@import "tailwindcss" theme(static);
|
||||||
@import "@nuxt/ui";
|
@import "@nuxt/ui";
|
||||||
```
|
```
|
||||||
|
|
||||||
Learn more in the [installation guide](https://ui.nuxt.com/getting-started/installation/nuxt).
|
Learn more in the [installation guide](https://ui3.nuxt.dev/getting-started/installation/nuxt).
|
||||||
|
|
||||||
### Vue
|
### Vue
|
||||||
|
|
||||||
@@ -98,22 +98,11 @@ app.mount('#app')
|
|||||||
3. Import Tailwind CSS and Nuxt UI in your CSS:
|
3. Import Tailwind CSS and Nuxt UI in your CSS:
|
||||||
|
|
||||||
```css [assets/main.css]
|
```css [assets/main.css]
|
||||||
@import "tailwindcss";
|
@import "tailwindcss" theme(static);
|
||||||
@import "@nuxt/ui";
|
@import "@nuxt/ui";
|
||||||
```
|
```
|
||||||
|
|
||||||
Learn more in the [installation guide](https://ui.nuxt.com/getting-started/installation/vue).
|
Learn more in the [installation guide](https://ui3.nuxt.dev/getting-started/installation/vue).
|
||||||
|
|
||||||
## Contribution
|
|
||||||
|
|
||||||
Thank you for considering contributing to Nuxt UI. Here are a few ways you can get involved:
|
|
||||||
|
|
||||||
- Reporting Bugs: If you come across any bugs or issues, please check out the reporting bugs guide to learn how to submit a bug report.
|
|
||||||
- Suggestions: Have any thoughts to enhance Nuxt UI? We'd love to hear them! Check out the [contribution guide](https://ui.nuxt.com/getting-started/contribution) to share your suggestions.
|
|
||||||
|
|
||||||
## Local Development
|
|
||||||
|
|
||||||
Follow the docs to [set up your local development environment](https://ui.nuxt.com/getting-started/contribution#local-development) and contribute.
|
|
||||||
|
|
||||||
## Credits
|
## Credits
|
||||||
|
|
||||||
@@ -130,7 +119,7 @@ Follow the docs to [set up your local development environment](https://ui.nuxt.c
|
|||||||
Licensed under the [MIT license](https://github.com/nuxt/ui/blob/v3/LICENSE.md).
|
Licensed under the [MIT license](https://github.com/nuxt/ui/blob/v3/LICENSE.md).
|
||||||
|
|
||||||
<!-- Badges -->
|
<!-- Badges -->
|
||||||
[npm-version-src]: https://img.shields.io/npm/v/@nuxt/ui/latest.svg?style=flat&colorA=18181B&colorB=28CF8D
|
[npm-version-src]: https://img.shields.io/npm/v/@nuxt/ui/next.svg?style=flat&colorA=18181B&colorB=28CF8D
|
||||||
[npm-version-href]: https://npmjs.com/package/@nuxt/ui
|
[npm-version-href]: https://npmjs.com/package/@nuxt/ui
|
||||||
|
|
||||||
[npm-downloads-src]: https://img.shields.io/npm/dm/@nuxt/ui.svg?style=flat&colorA=18181B&colorB=28CF8D
|
[npm-downloads-src]: https://img.shields.io/npm/dm/@nuxt/ui.svg?style=flat&colorA=18181B&colorB=28CF8D
|
||||||
|
|||||||
@@ -6,6 +6,9 @@ export default defineBuildConfig({
|
|||||||
'./src/unplugin',
|
'./src/unplugin',
|
||||||
'./src/vite'
|
'./src/vite'
|
||||||
],
|
],
|
||||||
|
rollup: {
|
||||||
|
emitCJS: true
|
||||||
|
},
|
||||||
replace: {
|
replace: {
|
||||||
'process.env.DEV': 'false'
|
'process.env.DEV': 'false'
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"citty": "^0.1.6",
|
"citty": "^0.1.6",
|
||||||
"consola": "^3.4.2",
|
"consola": "^3.4.0",
|
||||||
"pathe": "^2.0.3",
|
"pathe": "^2.0.3",
|
||||||
"scule": "^1.3.0"
|
"scule": "^1.3.0"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ const component = ({ name, primitive, pro, prose, content }) => {
|
|||||||
import type { AppConfig } from '@nuxt/schema'
|
import type { AppConfig } from '@nuxt/schema'
|
||||||
import _appConfig from '#build/app.config'
|
import _appConfig from '#build/app.config'
|
||||||
import theme from '#build/${path}/${prose ? 'prose/' : ''}${content ? 'content/' : ''}${kebabName}'
|
import theme from '#build/${path}/${prose ? 'prose/' : ''}${content ? 'content/' : ''}${kebabName}'
|
||||||
import { tv } from '../utils/tv'
|
import { tv } from '${pro ? '#ui/utils/tv' : '../utils/tv'}'
|
||||||
|
|
||||||
const appConfig${camelName} = _appConfig as AppConfig & { ${key}: { ${prose ? 'prose: { ' : ''}${camelName}: Partial<typeof theme> } }${prose ? ' }' : ''}
|
const appConfig${camelName} = _appConfig as AppConfig & { ${key}: { ${prose ? 'prose: { ' : ''}${camelName}: Partial<typeof theme> } }${prose ? ' }' : ''}
|
||||||
|
|
||||||
@@ -76,7 +76,7 @@ import type { ${upperName}RootProps, ${upperName}RootEmits } from 'reka-ui'
|
|||||||
import type { AppConfig } from '@nuxt/schema'
|
import type { AppConfig } from '@nuxt/schema'
|
||||||
import _appConfig from '#build/app.config'
|
import _appConfig from '#build/app.config'
|
||||||
import theme from '#build/${path}/${prose ? 'prose/' : ''}${content ? 'content/' : ''}${kebabName}'
|
import theme from '#build/${path}/${prose ? 'prose/' : ''}${content ? 'content/' : ''}${kebabName}'
|
||||||
import { tv } from '../utils/tv'
|
import { tv } from '${pro ? '#ui/utils/tv' : '../utils/tv'}'
|
||||||
|
|
||||||
const appConfig${camelName} = _appConfig as AppConfig & { ${key}: { ${prose ? 'prose: { ' : ''}${camelName}: Partial<typeof theme> } }${prose ? ' }' : ''}
|
const appConfig${camelName} = _appConfig as AppConfig & { ${key}: { ${prose ? 'prose: { ' : ''}${camelName}: Partial<typeof theme> } }${prose ? ' }' : ''}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { withoutTrailingSlash } from 'ufo'
|
// import { withoutTrailingSlash } from 'ufo'
|
||||||
import colors from 'tailwindcss/colors'
|
import colors from 'tailwindcss/colors'
|
||||||
|
// import { debounce } from 'perfect-debounce'
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const appConfig = useAppConfig()
|
const appConfig = useAppConfig()
|
||||||
@@ -11,8 +12,17 @@ const { data: files } = useLazyAsyncData('search', () => queryCollectionSearchSe
|
|||||||
server: false
|
server: false
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const searchTerm = ref('')
|
||||||
|
|
||||||
|
// watch(searchTerm, debounce((query: string) => {
|
||||||
|
// if (!query) {
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
|
||||||
|
// useTrackEvent('Search', { props: { query: `${query} - ${searchTerm.value?.commandPaletteRef.results.length} results` } })
|
||||||
|
// }, 500))
|
||||||
|
|
||||||
const links = useLinks()
|
const links = useLinks()
|
||||||
const searchLinks = useSearchLinks()
|
|
||||||
const color = computed(() => colorMode.value === 'dark' ? (colors as any)[appConfig.ui.colors.neutral][900] : 'white')
|
const color = computed(() => colorMode.value === 'dark' ? (colors as any)[appConfig.ui.colors.neutral][900] : 'white')
|
||||||
const radius = computed(() => `:root { --ui-radius: ${appConfig.theme.radius}rem; }`)
|
const radius = computed(() => `:root { --ui-radius: ${appConfig.theme.radius}rem; }`)
|
||||||
const blackAsPrimary = computed(() => appConfig.theme.blackAsPrimary ? `:root { --ui-primary: black; } .dark { --ui-primary: white; }` : ':root {}')
|
const blackAsPrimary = computed(() => appConfig.theme.blackAsPrimary ? `:root { --ui-primary: black; } .dark { --ui-primary: white; }` : ':root {}')
|
||||||
@@ -23,8 +33,8 @@ useHead({
|
|||||||
{ key: 'theme-color', name: 'theme-color', content: color }
|
{ key: 'theme-color', name: 'theme-color', content: color }
|
||||||
],
|
],
|
||||||
link: [
|
link: [
|
||||||
{ rel: 'icon', type: 'image/svg+xml', href: '/icon.svg' },
|
{ rel: 'icon', type: 'image/svg+xml', href: '/icon.svg' }
|
||||||
{ rel: 'canonical', href: `https://ui.nuxt.com${withoutTrailingSlash(route.path)}` }
|
// { rel: 'canonical', href: `https://ui.nuxt.com${withoutTrailingSlash(route.path)}` }
|
||||||
],
|
],
|
||||||
style: [
|
style: [
|
||||||
{ innerHTML: radius, id: 'nuxt-ui-radius', tagPriority: -2 },
|
{ innerHTML: radius, id: 'nuxt-ui-radius', tagPriority: -2 },
|
||||||
@@ -51,7 +61,7 @@ provide('navigation', mappedNavigation)
|
|||||||
<NuxtLoadingIndicator color="var(--ui-primary)" :height="2" />
|
<NuxtLoadingIndicator color="var(--ui-primary)" :height="2" />
|
||||||
|
|
||||||
<template v-if="!route.path.startsWith('/examples')">
|
<template v-if="!route.path.startsWith('/examples')">
|
||||||
<Banner />
|
<!-- <Banner /> -->
|
||||||
|
|
||||||
<Header :links="links" />
|
<Header :links="links" />
|
||||||
</template>
|
</template>
|
||||||
@@ -65,7 +75,7 @@ provide('navigation', mappedNavigation)
|
|||||||
|
|
||||||
<ClientOnly>
|
<ClientOnly>
|
||||||
<LazyUContentSearch
|
<LazyUContentSearch
|
||||||
:links="searchLinks"
|
v-model:search-term="searchTerm"
|
||||||
:files="files"
|
:files="files"
|
||||||
:groups="[{
|
:groups="[{
|
||||||
id: 'framework',
|
id: 'framework',
|
||||||
@@ -85,5 +95,5 @@ provide('navigation', mappedNavigation)
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
/* Safelist (do not remove): [&>div]:*:my-0 [&>div]:*:w-full h-64 !px-0 !py-0 !pt-0 !pb-0 !p-0 !justify-start !justify-end !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 !min-h-96 h-136 */
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,50 +0,0 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
const el = ref<HTMLDivElement | null>(null)
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
if (!el.value) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const script = document.createElement('script')
|
|
||||||
script.setAttribute('type', 'text/javascript')
|
|
||||||
script.setAttribute('src', 'https://cdn.carbonads.com/carbon.js?serve=CWYIVK3E&placement=uinuxtcom')
|
|
||||||
script.setAttribute('id', '_carbonads_js')
|
|
||||||
|
|
||||||
el.value?.appendChild(script)
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div ref="el" class="carbon" />
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
@reference "../assets/css/main.css";
|
|
||||||
|
|
||||||
.carbon :deep(#carbonads) {
|
|
||||||
@apply relative border border-(--ui-border) rounded-[calc(var(--ui-radius)*1.5)] hover:bg-(--ui-bg-elevated)/50 w-full transition-colors min-h-[220px] p-2;
|
|
||||||
|
|
||||||
.carbon-img {
|
|
||||||
@apply flex justify-center w-full;
|
|
||||||
|
|
||||||
& > img {
|
|
||||||
@apply !max-w-full w-full rounded-(--ui-radius);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.carbon-text {
|
|
||||||
@apply text-sm text-(--ui-text-muted) transition-colors text-center text-pretty flex pt-2;
|
|
||||||
}
|
|
||||||
|
|
||||||
.carbon-poweredby {
|
|
||||||
@apply block text-xs text-center text-(--ui-text-muted) pt-2;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
.carbon-text {
|
|
||||||
@apply text-(--ui-text);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,18 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<UBanner
|
<UBanner icon="i-lucide-construction" :actions="[{ label: 'Go to Nuxt UI v2', to: 'https://ui.nuxt.com', trailingIcon: 'i-lucide-arrow-right' }]" :close="false">
|
||||||
id="ui3-launch"
|
|
||||||
icon="i-lucide-rocket"
|
|
||||||
:actions="[
|
|
||||||
{
|
|
||||||
label: 'Discover Nuxt UI Pro',
|
|
||||||
to: '/pro/pricing',
|
|
||||||
trailingIcon: 'i-lucide-arrow-right'
|
|
||||||
}
|
|
||||||
]"
|
|
||||||
close
|
|
||||||
>
|
|
||||||
<template #title>
|
<template #title>
|
||||||
<span class="font-semibold">Nuxt UI v3</span> is officially released.
|
You're looking at the documentation for <span class="font-semibold">Nuxt UI v3</span>!
|
||||||
</template>
|
</template>
|
||||||
</UBanner>
|
</UBanner>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -1,51 +0,0 @@
|
|||||||
<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>
|
|
||||||
@@ -2,8 +2,8 @@
|
|||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
|
|
||||||
const links = [{
|
const links = [{
|
||||||
label: 'Team',
|
label: 'Figma',
|
||||||
to: '/team'
|
to: '/figma'
|
||||||
}, {
|
}, {
|
||||||
label: 'Roadmap',
|
label: 'Roadmap',
|
||||||
to: '/roadmap'
|
to: '/roadmap'
|
||||||
|
|||||||
@@ -22,20 +22,8 @@ onMounted(() => {
|
|||||||
|
|
||||||
const navigation = inject<Ref<ContentNavigationItem[]>>('navigation')
|
const navigation = inject<Ref<ContentNavigationItem[]>>('navigation')
|
||||||
|
|
||||||
const githubLink = computed(() => {
|
|
||||||
return `https://github.com/nuxt/${value.value}`
|
|
||||||
})
|
|
||||||
|
|
||||||
const desktopLinks = computed(() => props.links.map(({ icon, ...link }) => link))
|
const desktopLinks = computed(() => props.links.map(({ icon, ...link }) => link))
|
||||||
const mobileLinks = computed(() => [
|
const mobileLinks = computed(() => props.links.map(link => ({ ...link, defaultOpen: link.children && route.path.startsWith(link.to as string) })))
|
||||||
...props.links.map(link => ({ ...link, defaultOpen: link.children && route.path.startsWith(link.to as string) })),
|
|
||||||
{
|
|
||||||
label: 'Open on GitHub',
|
|
||||||
to: githubLink.value,
|
|
||||||
icon: 'i-simple-icons-github',
|
|
||||||
target: '_blank'
|
|
||||||
}
|
|
||||||
])
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -53,7 +41,7 @@ const mobileLinks = computed(() => [
|
|||||||
<UDropdownMenu
|
<UDropdownMenu
|
||||||
v-slot="{ open }"
|
v-slot="{ open }"
|
||||||
:modal="false"
|
:modal="false"
|
||||||
:items="[{ label: `v${config.version}`, active: true, color: 'primary', checked: true, type: 'checkbox' }, { label: module === 'ui-pro' ? 'v1.7.1' : 'v2.21.1', to: module === 'ui-pro' ? 'https://ui2.nuxt.com/pro' : 'https://ui2.nuxt.com' }]"
|
: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' }]"
|
||||||
:ui="{ content: 'w-(--reka-dropdown-menu-trigger-width) min-w-0' }"
|
:ui="{ content: 'w-(--reka-dropdown-menu-trigger-width) min-w-0' }"
|
||||||
size="xs"
|
size="xs"
|
||||||
>
|
>
|
||||||
@@ -85,7 +73,7 @@ const mobileLinks = computed(() => [
|
|||||||
:key="value"
|
:key="value"
|
||||||
color="neutral"
|
color="neutral"
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
:to="githubLink"
|
:to="`https://github.com/nuxt/${value}`"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
icon="i-simple-icons-github"
|
icon="i-simple-icons-github"
|
||||||
aria-label="GitHub"
|
aria-label="GitHub"
|
||||||
@@ -94,7 +82,7 @@ const mobileLinks = computed(() => [
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #body>
|
<template #body>
|
||||||
<UNavigationMenu orientation="vertical" :items="mobileLinks" class="-mx-2.5" />
|
<UNavigationMenu orientation="vertical" :items="mobileLinks" class="-mx-2.5" default-open />
|
||||||
|
|
||||||
<USeparator type="dashed" class="mt-4 mb-6" />
|
<USeparator type="dashed" class="mt-4 mb-6" />
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { kebabCase } from 'scule'
|
|
||||||
|
|
||||||
interface Star {
|
interface Star {
|
||||||
x: number
|
x: number
|
||||||
y: number
|
y: number
|
||||||
@@ -14,7 +12,6 @@ const props = withDefaults(defineProps<{
|
|||||||
color?: string
|
color?: string
|
||||||
size?: { min: number, max: number }
|
size?: { min: number, max: number }
|
||||||
speed?: 'slow' | 'normal' | 'fast'
|
speed?: 'slow' | 'normal' | 'fast'
|
||||||
isIndex?: boolean
|
|
||||||
}>(), {
|
}>(), {
|
||||||
starCount: 50,
|
starCount: 50,
|
||||||
color: 'var(--ui-primary)',
|
color: 'var(--ui-primary)',
|
||||||
@@ -22,12 +19,9 @@ const props = withDefaults(defineProps<{
|
|||||||
min: 1,
|
min: 1,
|
||||||
max: 3
|
max: 3
|
||||||
}),
|
}),
|
||||||
speed: 'normal',
|
speed: 'normal'
|
||||||
isIndex: false
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const route = useRoute()
|
|
||||||
|
|
||||||
// Generate random stars
|
// Generate random stars
|
||||||
const generateStars = (count: number): Star[] => {
|
const generateStars = (count: number): Star[] => {
|
||||||
return Array.from({ length: count }, () => {
|
return Array.from({ length: count }, () => {
|
||||||
@@ -41,7 +35,7 @@ const generateStars = (count: number): Star[] => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Generate all stars
|
// Generate all stars
|
||||||
const stars = useState<Star[]>(`${kebabCase(route.path)}-sky`, () => generateStars(props.starCount))
|
const stars = ref<Star[]>(generateStars(props.starCount))
|
||||||
|
|
||||||
// Compute twinkle animation duration based on speed
|
// Compute twinkle animation duration based on speed
|
||||||
const twinkleDuration = computed(() => {
|
const twinkleDuration = computed(() => {
|
||||||
@@ -55,21 +49,23 @@ const twinkleDuration = computed(() => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="absolute pointer-events-none z-[-1] overflow-hidden" :class="isIndex ? 'inset-y-0 left-4 right-4 lg:right-[50%]' : 'inset-0'">
|
<div class="absolute pointer-events-none z-[-1] inset-y-0 left-4 right-4 lg:right-[50%] overflow-hidden">
|
||||||
<div
|
<ClientOnly>
|
||||||
v-for="star in stars"
|
<div
|
||||||
:key="star.id"
|
v-for="star in stars"
|
||||||
class="star absolute"
|
:key="star.id"
|
||||||
:style="{
|
class="star absolute"
|
||||||
'left': `${star.x}%`,
|
:style="{
|
||||||
'top': `${star.y}%`,
|
'left': `${star.x}%`,
|
||||||
'transform': 'translate(-50%, -50%)',
|
'top': `${star.y}%`,
|
||||||
'--star-size': `${star.size}px`,
|
'transform': 'translate(-50%, -50%)',
|
||||||
'--star-color': color,
|
'--star-size': `${star.size}px`,
|
||||||
'--twinkle-delay': `${star.twinkleDelay}s`,
|
'--star-color': color,
|
||||||
'--twinkle-duration': twinkleDuration
|
'--twinkle-delay': `${star.twinkleDelay}s`,
|
||||||
}"
|
'--twinkle-duration': twinkleDuration
|
||||||
/>
|
}"
|
||||||
|
/>
|
||||||
|
</ClientOnly>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,4 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { kebabCase } from 'scule'
|
|
||||||
|
|
||||||
interface Star {
|
|
||||||
x: number
|
|
||||||
y: number
|
|
||||||
size: number
|
|
||||||
}
|
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
starCount?: number
|
starCount?: number
|
||||||
color?: string
|
color?: string
|
||||||
@@ -22,10 +14,8 @@ const props = withDefaults(defineProps<{
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
const route = useRoute()
|
|
||||||
|
|
||||||
// Generate random star positions and sizes
|
// Generate random star positions and sizes
|
||||||
const generateStars = (count: number): Star[] => {
|
const generateStars = (count: number) => {
|
||||||
return Array.from({ length: count }, () => ({
|
return Array.from({ length: count }, () => ({
|
||||||
x: Math.floor(Math.random() * 2000),
|
x: Math.floor(Math.random() * 2000),
|
||||||
y: Math.floor(Math.random() * 2000),
|
y: Math.floor(Math.random() * 2000),
|
||||||
@@ -35,58 +25,52 @@ const generateStars = (count: number): Star[] => {
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Define speed configurations once
|
|
||||||
const speedMap = {
|
|
||||||
slow: { duration: 200, opacity: 0.5, ratio: 0.3 },
|
|
||||||
normal: { duration: 150, opacity: 0.75, ratio: 0.3 },
|
|
||||||
fast: { duration: 100, opacity: 1, ratio: 0.4 }
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use a more efficient approach to generate and store stars
|
|
||||||
const stars = useState<{ slow: Star[], normal: Star[], fast: Star[] }>(`${kebabCase(route.path)}-stars`, () => {
|
|
||||||
return {
|
|
||||||
slow: generateStars(Math.floor(props.starCount * speedMap.slow.ratio)),
|
|
||||||
normal: generateStars(Math.floor(props.starCount * speedMap.normal.ratio)),
|
|
||||||
fast: generateStars(Math.floor(props.starCount * speedMap.fast.ratio))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// Compute star layers with different speeds and opacities
|
// Compute star layers with different speeds and opacities
|
||||||
const starLayers = computed(() => [
|
const starLayers = computed(() => {
|
||||||
{ stars: stars.value.fast, ...speedMap.fast },
|
const speedMap = {
|
||||||
{ stars: stars.value.normal, ...speedMap.normal },
|
slow: { duration: 200, opacity: 0.5 },
|
||||||
{ stars: stars.value.slow, ...speedMap.slow }
|
normal: { duration: 150, opacity: 0.75 },
|
||||||
])
|
fast: { duration: 100, opacity: 1 }
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
{ stars: generateStars(props.starCount), ...speedMap.fast },
|
||||||
|
{ stars: generateStars(Math.floor(props.starCount * 0.6)), ...speedMap.normal },
|
||||||
|
{ stars: generateStars(Math.floor(props.starCount * 0.3)), ...speedMap.slow }
|
||||||
|
]
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="absolute pointer-events-none z-[-1] inset-y-0 inset-x-5 sm:inset-x-7 lg:inset-x-9 overflow-hidden">
|
<div class="absolute pointer-events-none z-[-1] inset-y-0 inset-x-5 sm:inset-x-7 lg:inset-x-9 overflow-hidden">
|
||||||
<div class="stars size-full absolute inset-x-0 top-0">
|
<ClientOnly>
|
||||||
<div
|
<div class="stars size-full absolute inset-x-0 top-0">
|
||||||
v-for="(layer, index) in starLayers"
|
|
||||||
:key="index"
|
|
||||||
class="star-layer"
|
|
||||||
:style="{
|
|
||||||
'--star-duration': `${layer.duration}s`,
|
|
||||||
'--star-opacity': layer.opacity,
|
|
||||||
'--star-color': color
|
|
||||||
}"
|
|
||||||
>
|
|
||||||
<div
|
<div
|
||||||
v-for="(star, starIndex) in layer.stars"
|
v-for="(layer, index) in starLayers"
|
||||||
:key="starIndex"
|
:key="index"
|
||||||
class="star absolute rounded-full"
|
class="star-layer"
|
||||||
:style="{
|
:style="{
|
||||||
left: `${star.x}px`,
|
'--star-duration': `${layer.duration}s`,
|
||||||
top: `${star.y}px`,
|
'--star-opacity': layer.opacity,
|
||||||
width: `${star.size}px`,
|
'--star-color': color
|
||||||
height: `${star.size}px`,
|
|
||||||
backgroundColor: 'var(--star-color)',
|
|
||||||
opacity: 'var(--star-opacity)'
|
|
||||||
}"
|
}"
|
||||||
/>
|
>
|
||||||
|
<div
|
||||||
|
v-for="(star, starIndex) in layer.stars"
|
||||||
|
:key="starIndex"
|
||||||
|
class="star absolute rounded-full"
|
||||||
|
:style="{
|
||||||
|
left: `${star.x}px`,
|
||||||
|
top: `${star.y}px`,
|
||||||
|
width: `${star.size}px`,
|
||||||
|
height: `${star.size}px`,
|
||||||
|
backgroundColor: 'var(--star-color)',
|
||||||
|
opacity: 'var(--star-opacity)'
|
||||||
|
}"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</ClientOnly>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
<!-- eslint-disable no-useless-escape -->
|
<!-- eslint-disable no-useless-escape -->
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { ChipProps } from '@nuxt/ui'
|
|
||||||
import json5 from 'json5'
|
import json5 from 'json5'
|
||||||
import { upperFirst, camelCase, kebabCase } from 'scule'
|
import { upperFirst, camelCase, kebabCase } from 'scule'
|
||||||
import { hash } from 'ohash'
|
import { hash } from 'ohash'
|
||||||
@@ -54,8 +53,6 @@ const props = defineProps<{
|
|||||||
hide?: string[]
|
hide?: string[]
|
||||||
/** List of props to externalize in script setup */
|
/** List of props to externalize in script setup */
|
||||||
external?: string[]
|
external?: string[]
|
||||||
/** The types of the externalized props */
|
|
||||||
externalTypes?: string[]
|
|
||||||
/** List of props to use with `v-model` */
|
/** List of props to use with `v-model` */
|
||||||
model?: string[]
|
model?: string[]
|
||||||
/** List of props to cast from code and selection */
|
/** List of props to cast from code and selection */
|
||||||
@@ -212,21 +209,11 @@ ${props.slots?.default}
|
|||||||
code += `
|
code += `
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
`
|
`
|
||||||
if (props.externalTypes?.length) {
|
for (const key of props.external) {
|
||||||
const removeArrayBrackets = (type: string): string => type.endsWith('[]') ? removeArrayBrackets(type.slice(0, -2)) : type
|
|
||||||
|
|
||||||
const types = props.externalTypes.map(type => removeArrayBrackets(type))
|
|
||||||
code += `import type { ${types.join(', ')} } from '@nuxt/ui${props.pro ? '-pro' : ''}'
|
|
||||||
|
|
||||||
`
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const [i, key] of props.external.entries()) {
|
|
||||||
const cast = props.cast?.[key]
|
const cast = props.cast?.[key]
|
||||||
const value = cast ? castMap[cast]!.template(componentProps[key]) : json5.stringify(componentProps[key], null, 2)?.replace(/,([ |\t\n]+[}|\]])/g, '$1')
|
const value = cast ? castMap[cast]!.template(componentProps[key]) : json5.stringify(componentProps[key], null, 2)?.replace(/,([ |\t\n]+[}|\]])/g, '$1')
|
||||||
const type = props.externalTypes?.[i] ? `<${props.externalTypes[i]}>` : ''
|
|
||||||
|
|
||||||
code += `const ${key === 'modelValue' ? 'value' : key} = ref${type}(${value})
|
code += `const ${key === 'modelValue' ? 'value' : key} = ref(${value})
|
||||||
`
|
`
|
||||||
}
|
}
|
||||||
code += `<\/script>
|
code += `<\/script>
|
||||||
@@ -359,7 +346,7 @@ const { data: ast } = await useAsyncData(`component-code-${name}-${hash({ props:
|
|||||||
inset
|
inset
|
||||||
standalone
|
standalone
|
||||||
:color="(modelValue as any)"
|
:color="(modelValue as any)"
|
||||||
:size="(ui.itemLeadingChipSize() as ChipProps['size'])"
|
:size="ui.itemLeadingChipSize()"
|
||||||
class="size-2"
|
class="size-2"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { ChipProps } from '@nuxt/ui'
|
|
||||||
import { camelCase } from 'scule'
|
import { camelCase } from 'scule'
|
||||||
import { useElementSize } from '@vueuse/core'
|
import { useElementSize } from '@vueuse/core'
|
||||||
import { get, set } from '#ui/utils'
|
import { get, set } from '#ui/utils'
|
||||||
@@ -186,7 +185,7 @@ const urlSearchParams = computed(() => {
|
|||||||
inset
|
inset
|
||||||
standalone
|
standalone
|
||||||
:color="(modelValue as any)"
|
:color="(modelValue as any)"
|
||||||
:size="(ui.itemLeadingChipSize() as ChipProps['size'])"
|
:size="ui.itemLeadingChipSize()"
|
||||||
class="size-2"
|
class="size-2"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -11,23 +11,19 @@ function getEmojiFlag(locale: string): string {
|
|||||||
const languageToCountry: Record<string, string> = {
|
const languageToCountry: Record<string, string> = {
|
||||||
ar: 'sa', // Arabic -> Saudi Arabia
|
ar: 'sa', // Arabic -> Saudi Arabia
|
||||||
bn: 'bd', // Bengali -> Bangladesh
|
bn: 'bd', // Bengali -> Bangladesh
|
||||||
ca: 'es', // Catalan -> Spain
|
|
||||||
ckb: 'iq', // Central Kurdish -> Iraq
|
|
||||||
cs: 'cz', // Czech -> Czech Republic (note: modern country code is actually 'cz')
|
cs: 'cz', // Czech -> Czech Republic (note: modern country code is actually 'cz')
|
||||||
da: 'dk', // Danish -> Denmark
|
da: 'dk', // Danish -> Denmark
|
||||||
el: 'gr', // Greek -> Greece
|
el: 'gr', // Greek -> Greece
|
||||||
en: 'gb', // English -> Great Britain
|
|
||||||
et: 'ee', // Estonian -> Estonia
|
et: 'ee', // Estonian -> Estonia
|
||||||
|
en: 'gb', // English -> Great Britain
|
||||||
he: 'il', // Hebrew -> Israel
|
he: 'il', // Hebrew -> Israel
|
||||||
hi: 'in', // Hindi -> India
|
hi: 'in', // Hindi -> India
|
||||||
hy: 'am', // Armenian -> Armenia
|
|
||||||
ja: 'jp', // Japanese -> Japan
|
ja: 'jp', // Japanese -> Japan
|
||||||
km: 'kh', // Khmer -> Cambodia
|
km: 'kh', // Khmer -> Cambodia
|
||||||
ko: 'kr', // Korean -> South Korea
|
ko: 'kr', // Korean -> South Korea
|
||||||
nb: 'no', // Norwegian Bokmål -> Norway
|
nb: 'no', // Norwegian Bokmål -> Norway
|
||||||
sv: 'se', // Swedish -> Sweden
|
sv: 'se', // Swedish -> Sweden
|
||||||
uk: 'ua', // Ukrainian -> Ukraine
|
uk: 'ua', // Ukrainian -> Ukraine
|
||||||
ur: 'pk', // Urdu -> Pakistan
|
|
||||||
vi: 'vn' // Vietnamese -> Vietnam
|
vi: 'vn' // Vietnamese -> Vietnam
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { AccordionItem } from '@nuxt/ui'
|
const items = [
|
||||||
|
|
||||||
const items: AccordionItem[] = [
|
|
||||||
{
|
{
|
||||||
label: 'Icons',
|
label: 'Icons',
|
||||||
icon: 'i-lucide-smile'
|
icon: 'i-lucide-smile'
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { AccordionItem } from '@nuxt/ui'
|
const items = [
|
||||||
|
|
||||||
const items: AccordionItem[] = [
|
|
||||||
{
|
{
|
||||||
label: 'Icons',
|
label: 'Icons',
|
||||||
icon: 'i-lucide-smile'
|
icon: 'i-lucide-smile'
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { AccordionItem } from '@nuxt/ui'
|
|
||||||
|
|
||||||
const items = [
|
const items = [
|
||||||
{
|
{
|
||||||
label: 'Icons',
|
label: 'Icons',
|
||||||
@@ -10,7 +8,7 @@ const items = [
|
|||||||
{
|
{
|
||||||
label: 'Colors',
|
label: 'Colors',
|
||||||
icon: 'i-lucide-swatch-book',
|
icon: 'i-lucide-swatch-book',
|
||||||
slot: 'colors' as const,
|
slot: 'colors',
|
||||||
content: 'Choose a primary and a neutral color from your Tailwind CSS theme.'
|
content: 'Choose a primary and a neutral color from your Tailwind CSS theme.'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -18,7 +16,7 @@ const items = [
|
|||||||
icon: 'i-lucide-box',
|
icon: 'i-lucide-box',
|
||||||
content: 'You can customize components by using the `class` / `ui` props or in your app.config.ts.'
|
content: 'You can customize components by using the `class` / `ui` props or in your app.config.ts.'
|
||||||
}
|
}
|
||||||
] satisfies AccordionItem[]
|
]
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,33 +0,0 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
import type { AccordionItem } from '@nuxt/ui'
|
|
||||||
import { useSortable } from '@vueuse/integrations/useSortable'
|
|
||||||
|
|
||||||
const items = shallowRef<AccordionItem[]>([
|
|
||||||
{
|
|
||||||
label: 'Icons',
|
|
||||||
icon: 'i-lucide-smile',
|
|
||||||
content: 'You have nothing to do, @nuxt/icon will handle it automatically.'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Colors',
|
|
||||||
icon: 'i-lucide-swatch-book',
|
|
||||||
slot: 'colors' as const,
|
|
||||||
content: 'Choose a primary and a neutral color from your Tailwind CSS theme.'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Components',
|
|
||||||
icon: 'i-lucide-box',
|
|
||||||
content: 'You can customize components by using the `class` / `ui` props or in your app.config.ts.'
|
|
||||||
}
|
|
||||||
])
|
|
||||||
|
|
||||||
const accordion = useTemplateRef<HTMLElement>('accordion')
|
|
||||||
|
|
||||||
useSortable(accordion, items, {
|
|
||||||
animation: 150
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<UAccordion ref="accordion" :items="items" />
|
|
||||||
</template>
|
|
||||||
@@ -1,7 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { AccordionItem } from '@nuxt/ui'
|
const items = [
|
||||||
|
|
||||||
const items: AccordionItem[] = [
|
|
||||||
{
|
{
|
||||||
label: 'Icons',
|
label: 'Icons',
|
||||||
icon: 'i-lucide-smile',
|
icon: 'i-lucide-smile',
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { BreadcrumbItem } from '@nuxt/ui'
|
|
||||||
|
|
||||||
const items = [{
|
const items = [{
|
||||||
label: 'Home',
|
label: 'Home',
|
||||||
to: '/'
|
to: '/'
|
||||||
}, {
|
}, {
|
||||||
slot: 'dropdown' as const,
|
slot: 'dropdown',
|
||||||
icon: 'i-lucide-ellipsis',
|
icon: 'i-lucide-ellipsis',
|
||||||
children: [{
|
children: [{
|
||||||
label: 'Documentation'
|
label: 'Documentation'
|
||||||
@@ -20,7 +18,7 @@ const items = [{
|
|||||||
}, {
|
}, {
|
||||||
label: 'Breadcrumb',
|
label: 'Breadcrumb',
|
||||||
to: '/components/breadcrumb'
|
to: '/components/breadcrumb'
|
||||||
}] satisfies BreadcrumbItem[]
|
}]
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { BreadcrumbItem } from '@nuxt/ui'
|
const items = [{
|
||||||
|
|
||||||
const items: BreadcrumbItem[] = [{
|
|
||||||
label: 'Home',
|
label: 'Home',
|
||||||
to: '/'
|
to: '/'
|
||||||
}, {
|
}, {
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { DropdownMenuItem } from '@nuxt/ui'
|
const items = [{
|
||||||
|
|
||||||
const items: DropdownMenuItem[] = [{
|
|
||||||
label: 'Team',
|
label: 'Team',
|
||||||
icon: 'i-lucide-users'
|
icon: 'i-lucide-users'
|
||||||
}, {
|
}, {
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ const groups = [{
|
|||||||
label: 'Billing',
|
label: 'Billing',
|
||||||
icon: 'i-lucide-credit-card',
|
icon: 'i-lucide-credit-card',
|
||||||
kbds: ['meta', 'B'],
|
kbds: ['meta', 'B'],
|
||||||
slot: 'billing' as const
|
slot: 'billing'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Notifications',
|
label: 'Notifications',
|
||||||
@@ -25,7 +25,7 @@ const groups = [{
|
|||||||
}, {
|
}, {
|
||||||
id: 'users',
|
id: 'users',
|
||||||
label: 'Users',
|
label: 'Users',
|
||||||
slot: 'users' as const,
|
slot: 'users',
|
||||||
items: [
|
items: [
|
||||||
{
|
{
|
||||||
label: 'Benjamin Canac',
|
label: 'Benjamin Canac',
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { ContextMenuItem } from '@nuxt/ui'
|
|
||||||
|
|
||||||
const showSidebar = ref(true)
|
const showSidebar = ref(true)
|
||||||
const showToolbar = ref(false)
|
const showToolbar = ref(false)
|
||||||
|
|
||||||
const items = computed<ContextMenuItem[]>(() => [{
|
const items = computed(() => [{
|
||||||
label: 'View',
|
label: 'View',
|
||||||
type: 'label' as const
|
type: 'label' as const
|
||||||
}, {
|
}, {
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { ContextMenuItem } from '@nuxt/ui'
|
const items = [
|
||||||
|
|
||||||
const items: ContextMenuItem[][] = [
|
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
label: 'View',
|
label: 'View',
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { ContextMenuItem } from '@nuxt/ui'
|
|
||||||
|
|
||||||
const loading = ref(true)
|
const loading = ref(true)
|
||||||
|
|
||||||
const items: ContextMenuItem[] = [{
|
const items = [{
|
||||||
label: 'Refresh the Page',
|
label: 'Refresh the Page',
|
||||||
slot: 'refresh'
|
slot: 'refresh'
|
||||||
}, {
|
}, {
|
||||||
|
|||||||
@@ -1,43 +0,0 @@
|
|||||||
<script lang="ts" setup>
|
|
||||||
import { createReusableTemplate, useMediaQuery } from '@vueuse/core'
|
|
||||||
|
|
||||||
const [DefineFormTemplate, ReuseFormTemplate] = createReusableTemplate()
|
|
||||||
const isDesktop = useMediaQuery('(min-width: 768px)')
|
|
||||||
|
|
||||||
const open = ref(false)
|
|
||||||
|
|
||||||
const state = reactive({
|
|
||||||
email: undefined
|
|
||||||
})
|
|
||||||
|
|
||||||
const title = 'Edit profile'
|
|
||||||
const description = 'Make changes to your profile here. Click save when you\'re done.'
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<DefineFormTemplate>
|
|
||||||
<UForm :state="state" class="space-y-4">
|
|
||||||
<UFormField label="Email" name="email" required>
|
|
||||||
<UInput v-model="state.email" placeholder="shadcn@example.com" required />
|
|
||||||
</UFormField>
|
|
||||||
|
|
||||||
<UButton label="Save changes" type="submit" />
|
|
||||||
</UForm>
|
|
||||||
</DefineFormTemplate>
|
|
||||||
|
|
||||||
<UModal v-if="isDesktop" v-model:open="open" :title="title" :description="description">
|
|
||||||
<UButton label="Edit profile" color="neutral" variant="outline" />
|
|
||||||
|
|
||||||
<template #body>
|
|
||||||
<ReuseFormTemplate />
|
|
||||||
</template>
|
|
||||||
</UModal>
|
|
||||||
|
|
||||||
<UDrawer v-else v-model:open="open" :title="title" :description="description">
|
|
||||||
<UButton label="Edit profile" color="neutral" variant="outline" />
|
|
||||||
|
|
||||||
<template #body>
|
|
||||||
<ReuseFormTemplate />
|
|
||||||
</template>
|
|
||||||
</UDrawer>
|
|
||||||
</template>
|
|
||||||
@@ -1,6 +1,4 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { DropdownMenuItem } from '@nuxt/ui'
|
|
||||||
|
|
||||||
const showBookmarks = ref(true)
|
const showBookmarks = ref(true)
|
||||||
const showHistory = ref(false)
|
const showHistory = ref(false)
|
||||||
const showDownloads = ref(false)
|
const showDownloads = ref(false)
|
||||||
@@ -38,7 +36,7 @@ const items = computed(() => [{
|
|||||||
onUpdateChecked(checked: boolean) {
|
onUpdateChecked(checked: boolean) {
|
||||||
showDownloads.value = checked
|
showDownloads.value = checked
|
||||||
}
|
}
|
||||||
}] satisfies DropdownMenuItem[])
|
}])
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { DropdownMenuItem } from '@nuxt/ui'
|
const items = [
|
||||||
|
|
||||||
const items: DropdownMenuItem[][] = [
|
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
label: 'View',
|
label: 'View',
|
||||||
@@ -19,7 +17,7 @@ const items: DropdownMenuItem[][] = [
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
label: 'Delete',
|
label: 'Delete',
|
||||||
color: 'error',
|
color: 'error' as const,
|
||||||
icon: 'i-lucide-trash'
|
icon: 'i-lucide-trash'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -29,5 +27,9 @@ const items: DropdownMenuItem[][] = [
|
|||||||
<template>
|
<template>
|
||||||
<UDropdownMenu :items="items" :ui="{ content: 'w-48' }">
|
<UDropdownMenu :items="items" :ui="{ content: 'w-48' }">
|
||||||
<UButton label="Open" color="neutral" variant="outline" icon="i-lucide-menu" />
|
<UButton label="Open" color="neutral" variant="outline" icon="i-lucide-menu" />
|
||||||
|
|
||||||
|
<template #profile-trailing>
|
||||||
|
<UIcon name="i-lucide-badge-check" class="shrink-0 size-5 text-(--ui-primary)" />
|
||||||
|
</template>
|
||||||
</UDropdownMenu>
|
</UDropdownMenu>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -1,19 +1,15 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { DropdownMenuItem } from '@nuxt/ui'
|
const items = [{
|
||||||
|
label: 'Profile',
|
||||||
const items = [
|
icon: 'i-lucide-user',
|
||||||
{
|
slot: 'profile'
|
||||||
label: 'Profile',
|
}, {
|
||||||
icon: 'i-lucide-user',
|
label: 'Billing',
|
||||||
slot: 'profile' as const
|
icon: 'i-lucide-credit-card'
|
||||||
}, {
|
}, {
|
||||||
label: 'Billing',
|
label: 'Settings',
|
||||||
icon: 'i-lucide-credit-card'
|
icon: 'i-lucide-cog'
|
||||||
}, {
|
}]
|
||||||
label: 'Settings',
|
|
||||||
icon: 'i-lucide-cog'
|
|
||||||
}
|
|
||||||
] satisfies DropdownMenuItem[]
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,24 +1,20 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { DropdownMenuItem } from '@nuxt/ui'
|
|
||||||
|
|
||||||
const open = ref(false)
|
const open = ref(false)
|
||||||
|
|
||||||
defineShortcuts({
|
defineShortcuts({
|
||||||
o: () => open.value = !open.value
|
o: () => open.value = !open.value
|
||||||
})
|
})
|
||||||
|
|
||||||
const items: DropdownMenuItem[] = [
|
const items = [{
|
||||||
{
|
label: 'Profile',
|
||||||
label: 'Profile',
|
icon: 'i-lucide-user'
|
||||||
icon: 'i-lucide-user'
|
}, {
|
||||||
}, {
|
label: 'Billing',
|
||||||
label: 'Billing',
|
icon: 'i-lucide-credit-card'
|
||||||
icon: 'i-lucide-credit-card'
|
}, {
|
||||||
}, {
|
label: 'Settings',
|
||||||
label: 'Settings',
|
icon: 'i-lucide-cog'
|
||||||
icon: 'i-lucide-cog'
|
}]
|
||||||
}
|
|
||||||
]
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ async function onSubmit(event: FormSubmitEvent<Schema>) {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<UForm :schema="schema" :state="state" class="space-y-4" @submit="onSubmit">
|
<UForm :schema="v.safeParser(schema)" :state="state" class="space-y-4" @submit="onSubmit">
|
||||||
<UFormField label="Email" name="email">
|
<UFormField label="Email" name="email">
|
||||||
<UInput v-model="state.email" />
|
<UInput v-model="state.email" />
|
||||||
</UFormField>
|
</UFormField>
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ function onOpen() {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<UInputMenu
|
<UInputMenu
|
||||||
:items="countries"
|
:items="countries || []"
|
||||||
:loading="status === 'pending'"
|
:loading="status === 'pending'"
|
||||||
label-key="name"
|
label-key="name"
|
||||||
:search-input="{ icon: 'i-lucide-search' }"
|
:search-input="{ icon: 'i-lucide-search' }"
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { AvatarProps } from '@nuxt/ui'
|
|
||||||
|
|
||||||
const { data: users, status } = await useFetch('https://jsonplaceholder.typicode.com/users', {
|
const { data: users, status } = await useFetch('https://jsonplaceholder.typicode.com/users', {
|
||||||
key: 'typicode-users',
|
key: 'typicode-users',
|
||||||
transform: (data: { id: number, name: string }[]) => {
|
transform: (data: { id: number, name: string }[]) => {
|
||||||
@@ -8,7 +6,7 @@ const { data: users, status } = await useFetch('https://jsonplaceholder.typicode
|
|||||||
label: user.name,
|
label: user.name,
|
||||||
value: String(user.id),
|
value: String(user.id),
|
||||||
avatar: { src: `https://i.pravatar.cc/120?img=${user.id}` }
|
avatar: { src: `https://i.pravatar.cc/120?img=${user.id}` }
|
||||||
}))
|
})) || []
|
||||||
},
|
},
|
||||||
lazy: true
|
lazy: true
|
||||||
})
|
})
|
||||||
@@ -16,7 +14,7 @@ const { data: users, status } = await useFetch('https://jsonplaceholder.typicode
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<UInputMenu
|
<UInputMenu
|
||||||
:items="users"
|
:items="users || []"
|
||||||
:loading="status === 'pending'"
|
:loading="status === 'pending'"
|
||||||
icon="i-lucide-user"
|
icon="i-lucide-user"
|
||||||
placeholder="Select user"
|
placeholder="Select user"
|
||||||
@@ -25,7 +23,7 @@ const { data: users, status } = await useFetch('https://jsonplaceholder.typicode
|
|||||||
<UAvatar
|
<UAvatar
|
||||||
v-if="modelValue"
|
v-if="modelValue"
|
||||||
v-bind="modelValue.avatar"
|
v-bind="modelValue.avatar"
|
||||||
:size="(ui.leadingAvatarSize() as AvatarProps['size'])"
|
:size="ui.leadingAvatarSize()"
|
||||||
:class="ui.leadingAvatar()"
|
:class="ui.leadingAvatar()"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { AvatarProps } from '@nuxt/ui'
|
|
||||||
|
|
||||||
const { data: users, status } = await useFetch('https://jsonplaceholder.typicode.com/users', {
|
const { data: users, status } = await useFetch('https://jsonplaceholder.typicode.com/users', {
|
||||||
key: 'typicode-users-email',
|
key: 'typicode-users-email',
|
||||||
transform: (data: { id: number, name: string, email: string }[]) => {
|
transform: (data: { id: number, name: string, email: string }[]) => {
|
||||||
@@ -9,7 +7,7 @@ const { data: users, status } = await useFetch('https://jsonplaceholder.typicode
|
|||||||
email: user.email,
|
email: user.email,
|
||||||
value: String(user.id),
|
value: String(user.id),
|
||||||
avatar: { src: `https://i.pravatar.cc/120?img=${user.id}` }
|
avatar: { src: `https://i.pravatar.cc/120?img=${user.id}` }
|
||||||
}))
|
})) || []
|
||||||
},
|
},
|
||||||
lazy: true
|
lazy: true
|
||||||
})
|
})
|
||||||
@@ -17,7 +15,7 @@ const { data: users, status } = await useFetch('https://jsonplaceholder.typicode
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<UInputMenu
|
<UInputMenu
|
||||||
:items="users"
|
:items="users || []"
|
||||||
:loading="status === 'pending'"
|
:loading="status === 'pending'"
|
||||||
:filter-fields="['label', 'email']"
|
:filter-fields="['label', 'email']"
|
||||||
icon="i-lucide-user"
|
icon="i-lucide-user"
|
||||||
@@ -28,7 +26,7 @@ const { data: users, status } = await useFetch('https://jsonplaceholder.typicode
|
|||||||
<UAvatar
|
<UAvatar
|
||||||
v-if="modelValue"
|
v-if="modelValue"
|
||||||
v-bind="modelValue.avatar"
|
v-bind="modelValue.avatar"
|
||||||
:size="(ui.leadingAvatarSize() as AvatarProps['size'])"
|
:size="ui.leadingAvatarSize()"
|
||||||
:class="ui.leadingAvatar()"
|
:class="ui.leadingAvatar()"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { AvatarProps } from '@nuxt/ui'
|
|
||||||
|
|
||||||
const searchTerm = ref('')
|
const searchTerm = ref('')
|
||||||
const searchTermDebounced = refDebounced(searchTerm, 200)
|
const searchTermDebounced = refDebounced(searchTerm, 200)
|
||||||
|
|
||||||
@@ -12,7 +10,7 @@ const { data: users, status } = await useFetch('https://jsonplaceholder.typicode
|
|||||||
label: user.name,
|
label: user.name,
|
||||||
value: String(user.id),
|
value: String(user.id),
|
||||||
avatar: { src: `https://i.pravatar.cc/120?img=${user.id}` }
|
avatar: { src: `https://i.pravatar.cc/120?img=${user.id}` }
|
||||||
}))
|
})) || []
|
||||||
},
|
},
|
||||||
lazy: true
|
lazy: true
|
||||||
})
|
})
|
||||||
@@ -21,7 +19,7 @@ const { data: users, status } = await useFetch('https://jsonplaceholder.typicode
|
|||||||
<template>
|
<template>
|
||||||
<UInputMenu
|
<UInputMenu
|
||||||
v-model:search-term="searchTerm"
|
v-model:search-term="searchTerm"
|
||||||
:items="users"
|
:items="users || []"
|
||||||
:loading="status === 'pending'"
|
:loading="status === 'pending'"
|
||||||
ignore-filter
|
ignore-filter
|
||||||
icon="i-lucide-user"
|
icon="i-lucide-user"
|
||||||
@@ -31,7 +29,7 @@ const { data: users, status } = await useFetch('https://jsonplaceholder.typicode
|
|||||||
<UAvatar
|
<UAvatar
|
||||||
v-if="modelValue"
|
v-if="modelValue"
|
||||||
v-bind="modelValue.avatar"
|
v-bind="modelValue.avatar"
|
||||||
:size="(ui.leadingAvatarSize() as AvatarProps['size'])"
|
:size="ui.leadingAvatarSize()"
|
||||||
:class="ui.leadingAvatar()"
|
:class="ui.leadingAvatar()"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { InputMenuItem } from '@nuxt/ui'
|
|
||||||
|
|
||||||
const items = ref([
|
const items = ref([
|
||||||
{
|
{
|
||||||
label: 'benjamincanac',
|
label: 'benjamincanac',
|
||||||
@@ -25,16 +23,8 @@ const items = ref([
|
|||||||
src: 'https://github.com/noook.png',
|
src: 'https://github.com/noook.png',
|
||||||
alt: 'noook'
|
alt: 'noook'
|
||||||
}
|
}
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'sandros94',
|
|
||||||
value: 'sandros94',
|
|
||||||
avatar: {
|
|
||||||
src: 'https://github.com/sandros94.png',
|
|
||||||
alt: 'sandros94'
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
] satisfies InputMenuItem[])
|
])
|
||||||
const value = ref(items.value[0])
|
const value = ref(items.value[0])
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -1,30 +1,27 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { InputMenuItem, ChipProps } from '@nuxt/ui'
|
|
||||||
|
|
||||||
const items = ref([
|
const items = ref([
|
||||||
{
|
{
|
||||||
label: 'bug',
|
label: 'bug',
|
||||||
value: 'bug',
|
value: 'bug',
|
||||||
chip: {
|
chip: {
|
||||||
color: 'error'
|
color: 'error' as const
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'feature',
|
label: 'feature',
|
||||||
value: 'feature',
|
value: 'feature',
|
||||||
chip: {
|
chip: {
|
||||||
color: 'success'
|
color: 'success' as const
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'enhancement',
|
label: 'enhancement',
|
||||||
value: 'enhancement',
|
value: 'enhancement',
|
||||||
chip: {
|
chip: {
|
||||||
color: 'info'
|
color: 'info' as const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
] satisfies InputMenuItem[])
|
])
|
||||||
|
|
||||||
const value = ref(items.value[0])
|
const value = ref(items.value[0])
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -36,7 +33,7 @@ const value = ref(items.value[0])
|
|||||||
v-bind="modelValue.chip"
|
v-bind="modelValue.chip"
|
||||||
inset
|
inset
|
||||||
standalone
|
standalone
|
||||||
:size="(ui.itemLeadingChipSize() as ChipProps['size'])"
|
:size="ui.itemLeadingChipSize()"
|
||||||
:class="ui.itemLeadingChip()"
|
:class="ui.itemLeadingChip()"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { InputMenuItem } from '@nuxt/ui'
|
|
||||||
|
|
||||||
const items = ref([
|
const items = ref([
|
||||||
{
|
{
|
||||||
label: 'Backlog',
|
label: 'Backlog',
|
||||||
@@ -22,8 +20,7 @@ const items = ref([
|
|||||||
value: 'done',
|
value: 'done',
|
||||||
icon: 'i-lucide-circle-check'
|
icon: 'i-lucide-circle-check'
|
||||||
}
|
}
|
||||||
] satisfies InputMenuItem[])
|
])
|
||||||
|
|
||||||
const value = ref(items.value[0])
|
const value = ref(items.value[0])
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { NavigationMenuItem } from '@nuxt/ui'
|
|
||||||
|
|
||||||
const items = [
|
const items = [
|
||||||
{
|
{
|
||||||
label: 'Docs',
|
label: 'Docs',
|
||||||
icon: 'i-lucide-book-open',
|
icon: 'i-lucide-book-open',
|
||||||
slot: 'docs' as const,
|
slot: 'docs',
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
label: 'Icons',
|
label: 'Icons',
|
||||||
@@ -24,7 +22,7 @@ const items = [
|
|||||||
{
|
{
|
||||||
label: 'Components',
|
label: 'Components',
|
||||||
icon: 'i-lucide-box',
|
icon: 'i-lucide-box',
|
||||||
slot: 'components' as const,
|
slot: 'components',
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
label: 'Link',
|
label: 'Link',
|
||||||
@@ -56,7 +54,7 @@ const items = [
|
|||||||
label: 'GitHub',
|
label: 'GitHub',
|
||||||
icon: 'i-simple-icons-github'
|
icon: 'i-simple-icons-github'
|
||||||
}
|
}
|
||||||
] satisfies NavigationMenuItem[]
|
]
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { NavigationMenuItem } from '@nuxt/ui'
|
const items = [
|
||||||
|
|
||||||
const items: NavigationMenuItem[] = [
|
|
||||||
{
|
{
|
||||||
label: 'Guide',
|
label: 'Guide',
|
||||||
icon: 'i-lucide-book-open'
|
icon: 'i-lucide-book-open'
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { NavigationMenuItem } from '@nuxt/ui'
|
const items = [
|
||||||
|
|
||||||
const items: NavigationMenuItem[] = [
|
|
||||||
{
|
{
|
||||||
label: 'Guide',
|
label: 'Guide',
|
||||||
icon: 'i-lucide-book-open',
|
icon: 'i-lucide-book-open',
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ const label = ref([])
|
|||||||
multiple
|
multiple
|
||||||
placeholder="Search labels..."
|
placeholder="Search labels..."
|
||||||
:groups="[{ id: 'labels', items }]"
|
:groups="[{ id: 'labels', items }]"
|
||||||
:ui="{ input: '[&>input]:h-8 [&>input]:text-sm' }"
|
:ui="{ input: '[&>input]:h-8' }"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
</UPopover>
|
</UPopover>
|
||||||
|
|||||||
@@ -4,7 +4,8 @@ const { data: countries, status, execute } = await useLazyFetch<{
|
|||||||
code: string
|
code: string
|
||||||
emoji: string
|
emoji: string
|
||||||
}[]>('/api/countries.json', {
|
}[]>('/api/countries.json', {
|
||||||
immediate: false
|
immediate: false,
|
||||||
|
default: () => []
|
||||||
})
|
})
|
||||||
|
|
||||||
function onOpen() {
|
function onOpen() {
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { AvatarProps } from '@nuxt/ui'
|
|
||||||
|
|
||||||
const { data: users, status } = await useFetch('https://jsonplaceholder.typicode.com/users', {
|
const { data: users, status } = await useFetch('https://jsonplaceholder.typicode.com/users', {
|
||||||
key: 'typicode-users',
|
key: 'typicode-users',
|
||||||
transform: (data: { id: number, name: string }[]) => {
|
transform: (data: { id: number, name: string }[]) => {
|
||||||
@@ -8,7 +6,7 @@ const { data: users, status } = await useFetch('https://jsonplaceholder.typicode
|
|||||||
label: user.name,
|
label: user.name,
|
||||||
value: String(user.id),
|
value: String(user.id),
|
||||||
avatar: { src: `https://i.pravatar.cc/120?img=${user.id}` }
|
avatar: { src: `https://i.pravatar.cc/120?img=${user.id}` }
|
||||||
}))
|
})) || []
|
||||||
},
|
},
|
||||||
lazy: true
|
lazy: true
|
||||||
})
|
})
|
||||||
@@ -16,7 +14,7 @@ const { data: users, status } = await useFetch('https://jsonplaceholder.typicode
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<USelectMenu
|
<USelectMenu
|
||||||
:items="users"
|
:items="users || []"
|
||||||
:loading="status === 'pending'"
|
:loading="status === 'pending'"
|
||||||
icon="i-lucide-user"
|
icon="i-lucide-user"
|
||||||
placeholder="Select user"
|
placeholder="Select user"
|
||||||
@@ -26,7 +24,7 @@ const { data: users, status } = await useFetch('https://jsonplaceholder.typicode
|
|||||||
<UAvatar
|
<UAvatar
|
||||||
v-if="modelValue"
|
v-if="modelValue"
|
||||||
v-bind="modelValue.avatar"
|
v-bind="modelValue.avatar"
|
||||||
:size="(ui.leadingAvatarSize() as AvatarProps['size'])"
|
:size="ui.leadingAvatarSize()"
|
||||||
:class="ui.leadingAvatar()"
|
:class="ui.leadingAvatar()"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { AvatarProps } from '@nuxt/ui'
|
|
||||||
|
|
||||||
const { data: users, status } = await useFetch('https://jsonplaceholder.typicode.com/users', {
|
const { data: users, status } = await useFetch('https://jsonplaceholder.typicode.com/users', {
|
||||||
key: 'typicode-users-email',
|
key: 'typicode-users-email',
|
||||||
transform: (data: { id: number, name: string, email: string }[]) => {
|
transform: (data: { id: number, name: string, email: string }[]) => {
|
||||||
@@ -9,7 +7,7 @@ const { data: users, status } = await useFetch('https://jsonplaceholder.typicode
|
|||||||
email: user.email,
|
email: user.email,
|
||||||
value: String(user.id),
|
value: String(user.id),
|
||||||
avatar: { src: `https://i.pravatar.cc/120?img=${user.id}` }
|
avatar: { src: `https://i.pravatar.cc/120?img=${user.id}` }
|
||||||
}))
|
})) || []
|
||||||
},
|
},
|
||||||
lazy: true
|
lazy: true
|
||||||
})
|
})
|
||||||
@@ -17,7 +15,7 @@ const { data: users, status } = await useFetch('https://jsonplaceholder.typicode
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<USelectMenu
|
<USelectMenu
|
||||||
:items="users"
|
:items="users || []"
|
||||||
:loading="status === 'pending'"
|
:loading="status === 'pending'"
|
||||||
:filter-fields="['label', 'email']"
|
:filter-fields="['label', 'email']"
|
||||||
icon="i-lucide-user"
|
icon="i-lucide-user"
|
||||||
@@ -28,7 +26,7 @@ const { data: users, status } = await useFetch('https://jsonplaceholder.typicode
|
|||||||
<UAvatar
|
<UAvatar
|
||||||
v-if="modelValue"
|
v-if="modelValue"
|
||||||
v-bind="modelValue.avatar"
|
v-bind="modelValue.avatar"
|
||||||
:size="(ui.leadingAvatarSize() as AvatarProps['size'])"
|
:size="ui.leadingAvatarSize()"
|
||||||
:class="ui.leadingAvatar()"
|
:class="ui.leadingAvatar()"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { AvatarProps } from '@nuxt/ui'
|
|
||||||
|
|
||||||
const searchTerm = ref('')
|
const searchTerm = ref('')
|
||||||
const searchTermDebounced = refDebounced(searchTerm, 200)
|
const searchTermDebounced = refDebounced(searchTerm, 200)
|
||||||
|
|
||||||
@@ -12,7 +10,7 @@ const { data: users, status } = await useFetch('https://jsonplaceholder.typicode
|
|||||||
label: user.name,
|
label: user.name,
|
||||||
value: String(user.id),
|
value: String(user.id),
|
||||||
avatar: { src: `https://i.pravatar.cc/120?img=${user.id}` }
|
avatar: { src: `https://i.pravatar.cc/120?img=${user.id}` }
|
||||||
}))
|
})) || []
|
||||||
},
|
},
|
||||||
lazy: true
|
lazy: true
|
||||||
})
|
})
|
||||||
@@ -21,7 +19,7 @@ const { data: users, status } = await useFetch('https://jsonplaceholder.typicode
|
|||||||
<template>
|
<template>
|
||||||
<USelectMenu
|
<USelectMenu
|
||||||
v-model:search-term="searchTerm"
|
v-model:search-term="searchTerm"
|
||||||
:items="users"
|
:items="users || []"
|
||||||
:loading="status === 'pending'"
|
:loading="status === 'pending'"
|
||||||
ignore-filter
|
ignore-filter
|
||||||
icon="i-lucide-user"
|
icon="i-lucide-user"
|
||||||
@@ -32,7 +30,7 @@ const { data: users, status } = await useFetch('https://jsonplaceholder.typicode
|
|||||||
<UAvatar
|
<UAvatar
|
||||||
v-if="modelValue"
|
v-if="modelValue"
|
||||||
v-bind="modelValue.avatar"
|
v-bind="modelValue.avatar"
|
||||||
:size="(ui.leadingAvatarSize() as AvatarProps['size'])"
|
:size="ui.leadingAvatarSize()"
|
||||||
:class="ui.leadingAvatar()"
|
:class="ui.leadingAvatar()"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { SelectMenuItem } from '@nuxt/ui'
|
|
||||||
|
|
||||||
const items = ref([
|
const items = ref([
|
||||||
{
|
{
|
||||||
label: 'benjamincanac',
|
label: 'benjamincanac',
|
||||||
@@ -25,16 +23,8 @@ const items = ref([
|
|||||||
src: 'https://github.com/noook.png',
|
src: 'https://github.com/noook.png',
|
||||||
alt: 'noook'
|
alt: 'noook'
|
||||||
}
|
}
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'sandros94',
|
|
||||||
value: 'sandros94',
|
|
||||||
avatar: {
|
|
||||||
src: 'https://github.com/sandros94.png',
|
|
||||||
alt: 'sandros94'
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
] satisfies SelectMenuItem[])
|
])
|
||||||
const value = ref(items.value[0])
|
const value = ref(items.value[0])
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -1,29 +1,27 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { SelectMenuItem, ChipProps } from '@nuxt/ui'
|
|
||||||
|
|
||||||
const items = ref([
|
const items = ref([
|
||||||
{
|
{
|
||||||
label: 'bug',
|
label: 'bug',
|
||||||
value: 'bug',
|
value: 'bug',
|
||||||
chip: {
|
chip: {
|
||||||
color: 'error'
|
color: 'error' as const
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'feature',
|
label: 'feature',
|
||||||
value: 'feature',
|
value: 'feature',
|
||||||
chip: {
|
chip: {
|
||||||
color: 'success'
|
color: 'success' as const
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'enhancement',
|
label: 'enhancement',
|
||||||
value: 'enhancement',
|
value: 'enhancement',
|
||||||
chip: {
|
chip: {
|
||||||
color: 'info'
|
color: 'info' as const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
] satisfies SelectMenuItem[])
|
])
|
||||||
const value = ref(items.value[0])
|
const value = ref(items.value[0])
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -35,7 +33,7 @@ const value = ref(items.value[0])
|
|||||||
v-bind="modelValue.chip"
|
v-bind="modelValue.chip"
|
||||||
inset
|
inset
|
||||||
standalone
|
standalone
|
||||||
:size="(ui.itemLeadingChipSize() as ChipProps['size'])"
|
:size="ui.itemLeadingChipSize()"
|
||||||
:class="ui.itemLeadingChip()"
|
:class="ui.itemLeadingChip()"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { SelectMenuItem } from '@nuxt/ui'
|
|
||||||
|
|
||||||
const items = ref([
|
const items = ref([
|
||||||
{
|
{
|
||||||
label: 'Backlog',
|
label: 'Backlog',
|
||||||
@@ -22,7 +20,7 @@ const items = ref([
|
|||||||
value: 'done',
|
value: 'done',
|
||||||
icon: 'i-lucide-circle-check'
|
icon: 'i-lucide-circle-check'
|
||||||
}
|
}
|
||||||
] satisfies SelectMenuItem[])
|
])
|
||||||
const value = ref(items.value[0])
|
const value = ref(items.value[0])
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { AvatarProps } from '@nuxt/ui'
|
|
||||||
|
|
||||||
const { data: users, status } = await useFetch('https://jsonplaceholder.typicode.com/users', {
|
const { data: users, status } = await useFetch('https://jsonplaceholder.typicode.com/users', {
|
||||||
key: 'typicode-users',
|
key: 'typicode-users',
|
||||||
transform: (data: { id: number, name: string }[]) => {
|
transform: (data: { id: number, name: string }[]) => {
|
||||||
@@ -8,7 +6,7 @@ const { data: users, status } = await useFetch('https://jsonplaceholder.typicode
|
|||||||
label: user.name,
|
label: user.name,
|
||||||
value: String(user.id),
|
value: String(user.id),
|
||||||
avatar: { src: `https://i.pravatar.cc/120?img=${user.id}` }
|
avatar: { src: `https://i.pravatar.cc/120?img=${user.id}` }
|
||||||
}))
|
})) || []
|
||||||
},
|
},
|
||||||
lazy: true
|
lazy: true
|
||||||
})
|
})
|
||||||
@@ -20,18 +18,17 @@ function getUserAvatar(value: string) {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<USelect
|
<USelect
|
||||||
:items="users"
|
:items="users || []"
|
||||||
:loading="status === 'pending'"
|
:loading="status === 'pending'"
|
||||||
icon="i-lucide-user"
|
icon="i-lucide-user"
|
||||||
placeholder="Select user"
|
placeholder="Select user"
|
||||||
class="w-48"
|
class="w-48"
|
||||||
value-key="value"
|
|
||||||
>
|
>
|
||||||
<template #leading="{ modelValue, ui }">
|
<template #leading="{ modelValue, ui }">
|
||||||
<UAvatar
|
<UAvatar
|
||||||
v-if="modelValue"
|
v-if="modelValue"
|
||||||
v-bind="getUserAvatar(modelValue)"
|
v-bind="getUserAvatar(modelValue as string)"
|
||||||
:size="(ui.leadingAvatarSize() as AvatarProps['size'])"
|
:size="ui.leadingAvatarSize()"
|
||||||
:class="ui.leadingAvatar()"
|
:class="ui.leadingAvatar()"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { SelectItem } from '@nuxt/ui'
|
|
||||||
|
|
||||||
const items = ref([
|
const items = ref([
|
||||||
{
|
{
|
||||||
label: 'benjamincanac',
|
label: 'benjamincanac',
|
||||||
@@ -25,21 +23,13 @@ const items = ref([
|
|||||||
src: 'https://github.com/noook.png',
|
src: 'https://github.com/noook.png',
|
||||||
alt: 'noook'
|
alt: 'noook'
|
||||||
}
|
}
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'sandros94',
|
|
||||||
value: 'sandros94',
|
|
||||||
avatar: {
|
|
||||||
src: 'https://github.com/sandros94.png',
|
|
||||||
alt: 'sandros94'
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
] satisfies SelectItem[])
|
])
|
||||||
const value = ref(items.value[0]?.value)
|
const value = ref(items.value[0]?.value)
|
||||||
|
|
||||||
const avatar = computed(() => items.value.find(item => item.value === value.value)?.avatar)
|
const avatar = computed(() => items.value.find(item => item.value === value.value)?.avatar)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<USelect v-model="value" :items="items" value-key="value" :avatar="avatar" class="w-48" />
|
<USelect v-model="value" :avatar="avatar" :items="items" class="w-48" />
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -1,30 +1,27 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { SelectItem, ChipProps } from '@nuxt/ui'
|
|
||||||
|
|
||||||
const items = ref([
|
const items = ref([
|
||||||
{
|
{
|
||||||
label: 'bug',
|
label: 'bug',
|
||||||
value: 'bug',
|
value: 'bug',
|
||||||
chip: {
|
chip: {
|
||||||
color: 'error'
|
color: 'error' as const
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'feature',
|
label: 'feature',
|
||||||
value: 'feature',
|
value: 'feature',
|
||||||
chip: {
|
chip: {
|
||||||
color: 'success'
|
color: 'success' as const
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'enhancement',
|
label: 'enhancement',
|
||||||
value: 'enhancement',
|
value: 'enhancement',
|
||||||
chip: {
|
chip: {
|
||||||
color: 'info'
|
color: 'info' as const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
] satisfies SelectItem[])
|
])
|
||||||
|
|
||||||
const value = ref(items.value[0]?.value)
|
const value = ref(items.value[0]?.value)
|
||||||
|
|
||||||
function getChip(value: string) {
|
function getChip(value: string) {
|
||||||
@@ -33,14 +30,14 @@ function getChip(value: string) {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<USelect v-model="value" :items="items" value-key="value" class="w-48">
|
<USelect v-model="value" :items="items" class="w-48">
|
||||||
<template #leading="{ modelValue, ui }">
|
<template #leading="{ modelValue, ui }">
|
||||||
<UChip
|
<UChip
|
||||||
v-if="modelValue"
|
v-if="modelValue"
|
||||||
v-bind="getChip(modelValue)"
|
v-bind="getChip(modelValue as string)"
|
||||||
inset
|
inset
|
||||||
standalone
|
standalone
|
||||||
:size="(ui.itemLeadingChipSize() as ChipProps['size'])"
|
:size="ui.itemLeadingChipSize()"
|
||||||
:class="ui.itemLeadingChip()"
|
:class="ui.itemLeadingChip()"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { SelectItem } from '@nuxt/ui'
|
|
||||||
|
|
||||||
const items = ref([
|
const items = ref([
|
||||||
{
|
{
|
||||||
label: 'Backlog',
|
label: 'Backlog',
|
||||||
@@ -22,12 +20,12 @@ const items = ref([
|
|||||||
value: 'done',
|
value: 'done',
|
||||||
icon: 'i-lucide-circle-check'
|
icon: 'i-lucide-circle-check'
|
||||||
}
|
}
|
||||||
] satisfies SelectItem[])
|
])
|
||||||
const value = ref(items.value[0]?.value)
|
const value = ref(items.value[0]?.value)
|
||||||
|
|
||||||
const icon = computed(() => items.value.find(item => item.value === value.value)?.icon)
|
const icon = computed(() => items.value.find(item => item.value === value.value)?.icon)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<USelect v-model="value" :items="items" value-key="value" :icon="icon" class="w-48" />
|
<USelect v-model="value" :icon="icon" :items="items" class="w-48" />
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { StepperItem } from '@nuxt/ui'
|
const items = [
|
||||||
|
|
||||||
const items: StepperItem[] = [
|
|
||||||
{
|
{
|
||||||
title: 'Address',
|
title: 'Address',
|
||||||
description: 'Add your address here',
|
description: 'Add your address here',
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { StepperItem } from '@nuxt/ui'
|
const items = [
|
||||||
|
|
||||||
const items: StepperItem[] = [
|
|
||||||
{
|
{
|
||||||
slot: 'address',
|
slot: 'address',
|
||||||
title: 'Address',
|
title: 'Address',
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { StepperItem } from '@nuxt/ui'
|
|
||||||
import { onMounted, ref } from 'vue'
|
import { onMounted, ref } from 'vue'
|
||||||
|
|
||||||
const items: StepperItem[] = [
|
const items = [
|
||||||
{
|
{
|
||||||
title: 'Address',
|
title: 'Address',
|
||||||
description: 'Add your address here',
|
description: 'Add your address here',
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { StepperItem } from '@nuxt/ui'
|
const items = [
|
||||||
|
|
||||||
const items: StepperItem[] = [
|
|
||||||
{
|
{
|
||||||
slot: 'address',
|
slot: 'address',
|
||||||
title: 'Address',
|
title: 'Address',
|
||||||
|
|||||||
@@ -97,11 +97,10 @@ function getHeader(column: Column<Payment>, label: string) {
|
|||||||
const isSorted = column.getIsSorted()
|
const isSorted = column.getIsSorted()
|
||||||
|
|
||||||
return h(UDropdownMenu, {
|
return h(UDropdownMenu, {
|
||||||
'content': {
|
content: {
|
||||||
align: 'start'
|
align: 'start'
|
||||||
},
|
},
|
||||||
'aria-label': 'Actions dropdown',
|
items: [{
|
||||||
'items': [{
|
|
||||||
label: 'Asc',
|
label: 'Asc',
|
||||||
type: 'checkbox',
|
type: 'checkbox',
|
||||||
icon: 'i-lucide-arrow-up-narrow-wide',
|
icon: 'i-lucide-arrow-up-narrow-wide',
|
||||||
@@ -127,12 +126,11 @@ function getHeader(column: Column<Payment>, label: string) {
|
|||||||
}
|
}
|
||||||
}]
|
}]
|
||||||
}, () => h(UButton, {
|
}, () => h(UButton, {
|
||||||
'color': 'neutral',
|
color: 'neutral',
|
||||||
'variant': 'ghost',
|
variant: 'ghost',
|
||||||
label,
|
label,
|
||||||
'icon': isSorted ? (isSorted === 'asc' ? 'i-lucide-arrow-up-narrow-wide' : 'i-lucide-arrow-down-wide-narrow') : 'i-lucide-arrow-up-down',
|
icon: isSorted ? (isSorted === 'asc' ? 'i-lucide-arrow-up-narrow-wide' : 'i-lucide-arrow-down-wide-narrow') : 'i-lucide-arrow-up-down',
|
||||||
'class': '-mx-2.5 data-[state=open]:bg-(--ui-bg-elevated)',
|
class: '-mx-2.5 data-[state=open]:bg-(--ui-bg-elevated)'
|
||||||
'aria-label': `Sort by ${isSorted === 'asc' ? 'descending' : 'ascending'}`
|
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -145,12 +145,12 @@ const columns: TableColumn<Payment>[] = [{
|
|||||||
header: ({ table }) => h(UCheckbox, {
|
header: ({ table }) => h(UCheckbox, {
|
||||||
'modelValue': table.getIsSomePageRowsSelected() ? 'indeterminate' : table.getIsAllPageRowsSelected(),
|
'modelValue': table.getIsSomePageRowsSelected() ? 'indeterminate' : table.getIsAllPageRowsSelected(),
|
||||||
'onUpdate:modelValue': (value: boolean | 'indeterminate') => table.toggleAllPageRowsSelected(!!value),
|
'onUpdate:modelValue': (value: boolean | 'indeterminate') => table.toggleAllPageRowsSelected(!!value),
|
||||||
'aria-label': 'Select all'
|
'ariaLabel': 'Select all'
|
||||||
}),
|
}),
|
||||||
cell: ({ row }) => h(UCheckbox, {
|
cell: ({ row }) => h(UCheckbox, {
|
||||||
'modelValue': row.getIsSelected(),
|
'modelValue': row.getIsSelected(),
|
||||||
'onUpdate:modelValue': (value: boolean | 'indeterminate') => row.toggleSelected(!!value),
|
'onUpdate:modelValue': (value: boolean | 'indeterminate') => row.toggleSelected(!!value),
|
||||||
'aria-label': 'Select row'
|
'ariaLabel': 'Select row'
|
||||||
}),
|
}),
|
||||||
enableSorting: false,
|
enableSorting: false,
|
||||||
enableHiding: false
|
enableHiding: false
|
||||||
@@ -242,17 +242,15 @@ const columns: TableColumn<Payment>[] = [{
|
|||||||
}]
|
}]
|
||||||
|
|
||||||
return h('div', { class: 'text-right' }, h(UDropdownMenu, {
|
return h('div', { class: 'text-right' }, h(UDropdownMenu, {
|
||||||
'content': {
|
content: {
|
||||||
align: 'end'
|
align: 'end'
|
||||||
},
|
},
|
||||||
items,
|
items
|
||||||
'aria-label': 'Actions dropdown'
|
|
||||||
}, () => h(UButton, {
|
}, () => h(UButton, {
|
||||||
'icon': 'i-lucide-ellipsis-vertical',
|
icon: 'i-lucide-ellipsis-vertical',
|
||||||
'color': 'neutral',
|
color: 'neutral',
|
||||||
'variant': 'ghost',
|
variant: 'ghost',
|
||||||
'class': 'ml-auto',
|
class: 'ml-auto'
|
||||||
'aria-label': 'Actions dropdown'
|
|
||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
}]
|
}]
|
||||||
@@ -296,7 +294,6 @@ function randomize() {
|
|||||||
variant="outline"
|
variant="outline"
|
||||||
trailing-icon="i-lucide-chevron-down"
|
trailing-icon="i-lucide-chevron-down"
|
||||||
class="ml-auto"
|
class="ml-auto"
|
||||||
aria-label="Columns select dropdown"
|
|
||||||
/>
|
/>
|
||||||
</UDropdownMenu>
|
</UDropdownMenu>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ const { data, status } = await useFetch<User[]>('https://jsonplaceholder.typicod
|
|||||||
transform: (data) => {
|
transform: (data) => {
|
||||||
return data?.map(user => ({
|
return data?.map(user => ({
|
||||||
...user,
|
...user,
|
||||||
avatar: { src: `https://i.pravatar.cc/120?img=${user.id}`, alt: `${user.name} avatar` }
|
avatar: { src: `https://i.pravatar.cc/120?img=${user.id}` }
|
||||||
})) || []
|
})) || []
|
||||||
},
|
},
|
||||||
lazy: true
|
lazy: true
|
||||||
|
|||||||
@@ -97,17 +97,15 @@ const columns: TableColumn<Payment>[] = [{
|
|||||||
id: 'actions',
|
id: 'actions',
|
||||||
cell: ({ row }) => {
|
cell: ({ row }) => {
|
||||||
return h('div', { class: 'text-right' }, h(UDropdownMenu, {
|
return h('div', { class: 'text-right' }, h(UDropdownMenu, {
|
||||||
'content': {
|
content: {
|
||||||
align: 'end'
|
align: 'end'
|
||||||
},
|
},
|
||||||
'items': getRowItems(row),
|
items: getRowItems(row)
|
||||||
'aria-label': 'Actions dropdown'
|
|
||||||
}, () => h(UButton, {
|
}, () => h(UButton, {
|
||||||
'icon': 'i-lucide-ellipsis-vertical',
|
icon: 'i-lucide-ellipsis-vertical',
|
||||||
'color': 'neutral',
|
color: 'neutral',
|
||||||
'variant': 'ghost',
|
variant: 'ghost',
|
||||||
'class': 'ml-auto',
|
class: 'ml-auto'
|
||||||
'aria-label': 'Actions dropdown'
|
|
||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
}]
|
}]
|
||||||
|
|||||||
@@ -48,15 +48,14 @@ const data = ref<Payment[]>([{
|
|||||||
const columns: TableColumn<Payment>[] = [{
|
const columns: TableColumn<Payment>[] = [{
|
||||||
id: 'expand',
|
id: 'expand',
|
||||||
cell: ({ row }) => h(UButton, {
|
cell: ({ row }) => h(UButton, {
|
||||||
'color': 'neutral',
|
color: 'neutral',
|
||||||
'variant': 'ghost',
|
variant: 'ghost',
|
||||||
'icon': 'i-lucide-chevron-down',
|
icon: 'i-lucide-chevron-down',
|
||||||
'square': true,
|
square: true,
|
||||||
'aria-label': 'Expand',
|
ui: {
|
||||||
'ui': {
|
|
||||||
leadingIcon: ['transition-transform', row.getIsExpanded() ? 'duration-200 rotate-180' : '']
|
leadingIcon: ['transition-transform', row.getIsExpanded() ? 'duration-200 rotate-180' : '']
|
||||||
},
|
},
|
||||||
'onClick': () => row.toggleExpanded()
|
onClick: () => row.toggleExpanded()
|
||||||
})
|
})
|
||||||
}, {
|
}, {
|
||||||
accessorKey: 'id',
|
accessorKey: 'id',
|
||||||
|
|||||||
@@ -50,12 +50,12 @@ const columns: TableColumn<Payment>[] = [{
|
|||||||
header: ({ table }) => h(UCheckbox, {
|
header: ({ table }) => h(UCheckbox, {
|
||||||
'modelValue': table.getIsSomePageRowsSelected() ? 'indeterminate' : table.getIsAllPageRowsSelected(),
|
'modelValue': table.getIsSomePageRowsSelected() ? 'indeterminate' : table.getIsAllPageRowsSelected(),
|
||||||
'onUpdate:modelValue': (value: boolean | 'indeterminate') => table.toggleAllPageRowsSelected(!!value),
|
'onUpdate:modelValue': (value: boolean | 'indeterminate') => table.toggleAllPageRowsSelected(!!value),
|
||||||
'aria-label': 'Select all'
|
'ariaLabel': 'Select all'
|
||||||
}),
|
}),
|
||||||
cell: ({ row }) => h(UCheckbox, {
|
cell: ({ row }) => h(UCheckbox, {
|
||||||
'modelValue': row.getIsSelected(),
|
'modelValue': row.getIsSelected(),
|
||||||
'onUpdate:modelValue': (value: boolean | 'indeterminate') => row.toggleSelected(!!value),
|
'onUpdate:modelValue': (value: boolean | 'indeterminate') => row.toggleSelected(!!value),
|
||||||
'aria-label': 'Select row'
|
'ariaLabel': 'Select row'
|
||||||
})
|
})
|
||||||
}, {
|
}, {
|
||||||
accessorKey: 'date',
|
accessorKey: 'date',
|
||||||
|
|||||||
@@ -50,12 +50,12 @@ const columns: TableColumn<Payment>[] = [{
|
|||||||
header: ({ table }) => h(UCheckbox, {
|
header: ({ table }) => h(UCheckbox, {
|
||||||
'modelValue': table.getIsSomePageRowsSelected() ? 'indeterminate' : table.getIsAllPageRowsSelected(),
|
'modelValue': table.getIsSomePageRowsSelected() ? 'indeterminate' : table.getIsAllPageRowsSelected(),
|
||||||
'onUpdate:modelValue': (value: boolean | 'indeterminate') => table.toggleAllPageRowsSelected(!!value),
|
'onUpdate:modelValue': (value: boolean | 'indeterminate') => table.toggleAllPageRowsSelected(!!value),
|
||||||
'aria-label': 'Select all'
|
'ariaLabel': 'Select all'
|
||||||
}),
|
}),
|
||||||
cell: ({ row }) => h(UCheckbox, {
|
cell: ({ row }) => h(UCheckbox, {
|
||||||
'modelValue': row.getIsSelected(),
|
'modelValue': row.getIsSelected(),
|
||||||
'onUpdate:modelValue': (value: boolean | 'indeterminate') => row.toggleSelected(!!value),
|
'onUpdate:modelValue': (value: boolean | 'indeterminate') => row.toggleSelected(!!value),
|
||||||
'aria-label': 'Select row'
|
'ariaLabel': 'Select row'
|
||||||
})
|
})
|
||||||
}, {
|
}, {
|
||||||
accessorKey: 'date',
|
accessorKey: 'date',
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ function getDropdownActions(user: User): DropdownMenuItem[][] {
|
|||||||
<UTable :data="data" :columns="columns" class="flex-1">
|
<UTable :data="data" :columns="columns" class="flex-1">
|
||||||
<template #name-cell="{ row }">
|
<template #name-cell="{ row }">
|
||||||
<div class="flex items-center gap-3">
|
<div class="flex items-center gap-3">
|
||||||
<UAvatar :src="`https://i.pravatar.cc/120?img=${row.original.id}`" size="lg" :alt="`${row.original.name} avatar`" />
|
<UAvatar :src="`https://i.pravatar.cc/120?img=${row.original.id}`" size="lg" />
|
||||||
<div>
|
<div>
|
||||||
<p class="font-medium text-(--ui-text-highlighted)">
|
<p class="font-medium text-(--ui-text-highlighted)">
|
||||||
{{ row.original.name }}
|
{{ row.original.name }}
|
||||||
@@ -108,7 +108,7 @@ function getDropdownActions(user: User): DropdownMenuItem[][] {
|
|||||||
</template>
|
</template>
|
||||||
<template #action-cell="{ row }">
|
<template #action-cell="{ row }">
|
||||||
<UDropdownMenu :items="getDropdownActions(row.original)">
|
<UDropdownMenu :items="getDropdownActions(row.original)">
|
||||||
<UButton icon="i-lucide-ellipsis-vertical" color="neutral" variant="ghost" aria-label="Actions" />
|
<UButton icon="i-lucide-ellipsis-vertical" color="neutral" variant="ghost" />
|
||||||
</UDropdownMenu>
|
</UDropdownMenu>
|
||||||
</template>
|
</template>
|
||||||
</UTable>
|
</UTable>
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { TabsItem } from '@nuxt/ui'
|
const items = [
|
||||||
|
|
||||||
const items: TabsItem[] = [
|
|
||||||
{
|
{
|
||||||
label: 'Account',
|
label: 'Account',
|
||||||
icon: 'i-lucide-user'
|
icon: 'i-lucide-user'
|
||||||
|
|||||||
@@ -1,20 +1,18 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { TabsItem } from '@nuxt/ui'
|
|
||||||
|
|
||||||
const items = [
|
const items = [
|
||||||
{
|
{
|
||||||
label: 'Account',
|
label: 'Account',
|
||||||
description: 'Make changes to your account here. Click save when you\'re done.',
|
description: 'Make changes to your account here. Click save when you\'re done.',
|
||||||
icon: 'i-lucide-user',
|
icon: 'i-lucide-user',
|
||||||
slot: 'account' as const
|
slot: 'account'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Password',
|
label: 'Password',
|
||||||
description: 'Change your password here. After saving, you\'ll be logged out.',
|
description: 'Change your password here. After saving, you\'ll be logged out.',
|
||||||
icon: 'i-lucide-lock',
|
icon: 'i-lucide-lock',
|
||||||
slot: 'password' as const
|
slot: 'password'
|
||||||
}
|
}
|
||||||
] satisfies TabsItem[]
|
]
|
||||||
|
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
name: 'Benjamin Canac',
|
name: 'Benjamin Canac',
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { TabsItem } from '@nuxt/ui'
|
const items = [
|
||||||
|
|
||||||
const items: TabsItem[] = [
|
|
||||||
{
|
{
|
||||||
label: 'Account'
|
label: 'Account'
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { TreeItem } from '@nuxt/ui'
|
import type { TreeItem } from '@nuxt/ui'
|
||||||
|
|
||||||
const items = [
|
const items: TreeItem[] = [
|
||||||
{
|
{
|
||||||
label: 'app/',
|
label: 'app/',
|
||||||
slot: 'app' as const,
|
slot: 'app',
|
||||||
defaultExpanded: true,
|
defaultExpanded: true,
|
||||||
children: [{
|
children: [{
|
||||||
label: 'composables/',
|
label: 'composables/',
|
||||||
@@ -24,7 +24,7 @@ const items = [
|
|||||||
},
|
},
|
||||||
{ label: 'app.vue', icon: 'i-vscode-icons-file-type-vue' },
|
{ label: 'app.vue', icon: 'i-vscode-icons-file-type-vue' },
|
||||||
{ label: 'nuxt.config.ts', icon: 'i-vscode-icons-file-type-nuxt' }
|
{ label: 'nuxt.config.ts', icon: 'i-vscode-icons-file-type-nuxt' }
|
||||||
] satisfies TreeItem[]
|
]
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ const items: TreeItem[] = [
|
|||||||
{ label: 'nuxt.config.ts', icon: 'i-vscode-icons-file-type-nuxt' }
|
{ label: 'nuxt.config.ts', icon: 'i-vscode-icons-file-type-nuxt' }
|
||||||
]
|
]
|
||||||
|
|
||||||
const value = ref()
|
const value = ref(items[items.length - 1])
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ withDefaults(defineProps<{
|
|||||||
title: string
|
title: string
|
||||||
description: string
|
description: string
|
||||||
component: string
|
component: string
|
||||||
module?: string
|
module: string
|
||||||
}>(), {
|
}>(), {
|
||||||
module: ''
|
module: ''
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ withDefaults(defineProps<{
|
|||||||
title: string
|
title: string
|
||||||
description: string
|
description: string
|
||||||
headline: string
|
headline: string
|
||||||
framework?: string
|
framework: string
|
||||||
module?: string
|
module: string
|
||||||
}>(), {
|
}>(), {
|
||||||
framework: 'nuxt',
|
framework: 'nuxt',
|
||||||
module: ''
|
module: ''
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ function setBlackAsPrimary(value: boolean) {
|
|||||||
|
|
||||||
<div class="grid grid-cols-3 gap-1 -mx-2">
|
<div class="grid grid-cols-3 gap-1 -mx-2">
|
||||||
<ThemePickerButton
|
<ThemePickerButton
|
||||||
|
chip="primary"
|
||||||
label="Black"
|
label="Black"
|
||||||
:selected="appConfig.theme.blackAsPrimary"
|
:selected="appConfig.theme.blackAsPrimary"
|
||||||
@click="setBlackAsPrimary(true)"
|
@click="setBlackAsPrimary(true)"
|
||||||
@@ -89,7 +90,6 @@ function setBlackAsPrimary(value: boolean) {
|
|||||||
<span class="inline-block w-2 h-2 rounded-full bg-black dark:bg-white" />
|
<span class="inline-block w-2 h-2 rounded-full bg-black dark:bg-white" />
|
||||||
</template>
|
</template>
|
||||||
</ThemePickerButton>
|
</ThemePickerButton>
|
||||||
|
|
||||||
<ThemePickerButton
|
<ThemePickerButton
|
||||||
v-for="color in primaryColors"
|
v-for="color in primaryColors"
|
||||||
:key="color"
|
:key="color"
|
||||||
@@ -111,7 +111,7 @@ function setBlackAsPrimary(value: boolean) {
|
|||||||
v-for="color in neutralColors"
|
v-for="color in neutralColors"
|
||||||
:key="color"
|
:key="color"
|
||||||
:label="color"
|
:label="color"
|
||||||
:chip="color === 'neutral' ? 'old-neutral' : color"
|
:chip="color"
|
||||||
:selected="neutral === color"
|
:selected="neutral === color"
|
||||||
@click="neutral = color"
|
@click="neutral = color"
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -5,10 +5,6 @@ defineProps<{
|
|||||||
chip?: string
|
chip?: string
|
||||||
selected?: boolean
|
selected?: boolean
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
const slots = defineSlots<{
|
|
||||||
leading: () => any
|
|
||||||
}>()
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -21,7 +17,7 @@ const slots = defineSlots<{
|
|||||||
class="capitalize ring-(--ui-border) rounded-[calc(var(--ui-radius))] text-[11px]"
|
class="capitalize ring-(--ui-border) rounded-[calc(var(--ui-radius))] text-[11px]"
|
||||||
:class="[selected ? 'bg-(--ui-bg-elevated)' : 'hover:bg-(--ui-bg-elevated)/50']"
|
:class="[selected ? 'bg-(--ui-bg-elevated)' : 'hover:bg-(--ui-bg-elevated)/50']"
|
||||||
>
|
>
|
||||||
<template v-if="chip || !!slots.leading" #leading>
|
<template v-if="chip" #leading>
|
||||||
<slot name="leading">
|
<slot name="leading">
|
||||||
<span
|
<span
|
||||||
class="inline-block size-2 rounded-full"
|
class="inline-block size-2 rounded-full"
|
||||||
|
|||||||
@@ -84,10 +84,10 @@ export function useLinks() {
|
|||||||
label: 'Community',
|
label: 'Community',
|
||||||
icon: 'i-lucide-users',
|
icon: 'i-lucide-users',
|
||||||
children: [{
|
children: [{
|
||||||
icon: 'i-lucide-presentation',
|
label: 'Roadmap',
|
||||||
label: 'Showcase',
|
description: 'Track our development progress in real-time.',
|
||||||
description: 'Check out some amazing projects built with Nuxt UI.',
|
icon: 'i-lucide-map',
|
||||||
to: '/showcase'
|
to: '/roadmap'
|
||||||
}, {
|
}, {
|
||||||
label: 'Devtools Integration',
|
label: 'Devtools Integration',
|
||||||
description: 'Integrate Nuxt UI with Nuxt Devtools with Compodium.',
|
description: 'Integrate Nuxt UI with Nuxt Devtools with Compodium.',
|
||||||
@@ -112,5 +112,5 @@ export function useLinks() {
|
|||||||
icon: 'i-lucide-rocket',
|
icon: 'i-lucide-rocket',
|
||||||
to: 'https://github.com/nuxt/ui/releases',
|
to: 'https://github.com/nuxt/ui/releases',
|
||||||
target: '_blank'
|
target: '_blank'
|
||||||
}])
|
}].filter(Boolean))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,66 +0,0 @@
|
|||||||
export function useSearchLinks() {
|
|
||||||
return [{
|
|
||||||
label: 'Docs',
|
|
||||||
icon: 'i-lucide-square-play',
|
|
||||||
to: '/getting-started'
|
|
||||||
}, {
|
|
||||||
label: 'Components',
|
|
||||||
icon: 'i-lucide-square-code',
|
|
||||||
to: '/components'
|
|
||||||
}, {
|
|
||||||
icon: 'i-lucide-sparkles',
|
|
||||||
label: 'Pro > Features',
|
|
||||||
description: 'A collection of premium Vue components.',
|
|
||||||
to: '/pro'
|
|
||||||
}, {
|
|
||||||
icon: 'i-lucide-credit-card',
|
|
||||||
label: 'Pro > Pricing',
|
|
||||||
description: 'Free in development, buy when ready to launch.',
|
|
||||||
to: '/pro/pricing'
|
|
||||||
}, {
|
|
||||||
icon: 'i-lucide-panels-top-left',
|
|
||||||
label: 'Pro > Templates',
|
|
||||||
description: 'Official templates made with Nuxt UI Pro.',
|
|
||||||
to: '/pro/templates'
|
|
||||||
}, {
|
|
||||||
icon: 'i-lucide-circle-check',
|
|
||||||
label: 'Pro > Activate',
|
|
||||||
description: 'Enable Nuxt UI Pro in your production projects.',
|
|
||||||
to: '/pro/activate'
|
|
||||||
}, {
|
|
||||||
label: 'Figma',
|
|
||||||
icon: 'i-simple-icons-figma',
|
|
||||||
to: '/figma'
|
|
||||||
}, {
|
|
||||||
icon: 'i-lucide-presentation',
|
|
||||||
label: 'Community > Showcase',
|
|
||||||
description: 'Check out some of the amazing projects built with Nuxt UI.',
|
|
||||||
to: '/showcase'
|
|
||||||
}, {
|
|
||||||
label: 'Community > Contribution',
|
|
||||||
description: 'A comprehensive guide on contributing to Nuxt UI, including project structure, development workflow, and best practices.',
|
|
||||||
icon: 'i-lucide-git-pull-request-arrow',
|
|
||||||
to: '/getting-started/contribution'
|
|
||||||
}, {
|
|
||||||
label: 'Community > Roadmap',
|
|
||||||
description: 'Track our development progress in real-time.',
|
|
||||||
icon: 'i-lucide-map',
|
|
||||||
to: '/roadmap'
|
|
||||||
}, {
|
|
||||||
label: 'Community > Devtools',
|
|
||||||
description: 'Integrate Nuxt UI with Nuxt Devtools with Compodium.',
|
|
||||||
icon: 'i-lucide-code',
|
|
||||||
to: 'https://github.com/romhml/compodium',
|
|
||||||
target: '_blank'
|
|
||||||
}, {
|
|
||||||
label: 'Community > Team',
|
|
||||||
description: 'Meet the team behind Nuxt UI.',
|
|
||||||
icon: 'i-lucide-users',
|
|
||||||
to: '/team'
|
|
||||||
}, {
|
|
||||||
label: 'Releases',
|
|
||||||
icon: 'i-lucide-rocket',
|
|
||||||
to: 'https://github.com/nuxt/ui/releases',
|
|
||||||
target: '_blank'
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import colors from 'tailwindcss/colors'
|
import colors from 'tailwindcss/colors'
|
||||||
|
// import { debounce } from 'perfect-debounce'
|
||||||
import type { NuxtError } from '#app'
|
import type { NuxtError } from '#app'
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
@@ -14,8 +15,17 @@ const { data: files } = useLazyAsyncData('search', () => queryCollectionSearchSe
|
|||||||
server: false
|
server: false
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const searchTerm = ref('')
|
||||||
|
|
||||||
|
// watch(searchTerm, debounce((query: string) => {
|
||||||
|
// if (!query) {
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
|
||||||
|
// useTrackEvent('Search', { props: { query: `${query} - ${searchTerm.value?.commandPaletteRef.results.length} results` } })
|
||||||
|
// }, 500))
|
||||||
|
|
||||||
const links = useLinks()
|
const links = useLinks()
|
||||||
const searchLinks = useSearchLinks()
|
|
||||||
const color = computed(() => colorMode.value === 'dark' ? (colors as any)[appConfig.ui.colors.neutral][900] : 'white')
|
const color = computed(() => colorMode.value === 'dark' ? (colors as any)[appConfig.ui.colors.neutral][900] : 'white')
|
||||||
const radius = computed(() => `:root { --ui-radius: ${appConfig.theme.radius}rem; }`)
|
const radius = computed(() => `:root { --ui-radius: ${appConfig.theme.radius}rem; }`)
|
||||||
const blackAsPrimary = computed(() => appConfig.theme.blackAsPrimary ? `:root { --ui-primary: black; } .dark { --ui-primary: white; }` : ':root {}')
|
const blackAsPrimary = computed(() => appConfig.theme.blackAsPrimary ? `:root { --ui-primary: black; } .dark { --ui-primary: white; }` : ':root {}')
|
||||||
@@ -38,7 +48,7 @@ useHead({
|
|||||||
})
|
})
|
||||||
|
|
||||||
useSeoMeta({
|
useSeoMeta({
|
||||||
titleTemplate: '%s - Nuxt UI',
|
titleTemplate: '%s - Nuxt UI v3',
|
||||||
title: String(props.error.statusCode)
|
title: String(props.error.statusCode)
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -57,17 +67,17 @@ provide('navigation', mappedNavigation)
|
|||||||
<UApp>
|
<UApp>
|
||||||
<NuxtLoadingIndicator color="#FFF" />
|
<NuxtLoadingIndicator color="#FFF" />
|
||||||
|
|
||||||
<Banner />
|
<!-- <Banner /> -->
|
||||||
|
|
||||||
<Header :links="links" />
|
<Header :links="links" />
|
||||||
|
|
||||||
<UError :error="error" />
|
<UError :error="error" />
|
||||||
|
|
||||||
<Footer />
|
<!-- <Footer /> -->
|
||||||
|
|
||||||
<ClientOnly>
|
<ClientOnly>
|
||||||
<LazyUContentSearch
|
<LazyUContentSearch
|
||||||
:links="searchLinks"
|
v-model:search-term="searchTerm"
|
||||||
:files="files"
|
:files="files"
|
||||||
:groups="[{
|
:groups="[{
|
||||||
id: 'framework',
|
id: 'framework',
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ design_system:
|
|||||||
```
|
```
|
||||||
|
|
||||||
```css [main.css]
|
```css [main.css]
|
||||||
@import "tailwindcss";
|
@import "tailwindcss" theme(static);
|
||||||
@import "@nuxt/ui";
|
@import "@nuxt/ui";
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
@@ -176,11 +176,7 @@ community:
|
|||||||
links:
|
links:
|
||||||
- label: Star on GitHub
|
- label: Star on GitHub
|
||||||
color: neutral
|
color: neutral
|
||||||
|
variant: outline
|
||||||
to: https://github.com/nuxt/ui
|
to: https://github.com/nuxt/ui
|
||||||
target: _blank
|
target: _blank
|
||||||
icon: i-lucide-star
|
icon: i-lucide-star
|
||||||
- label: Meet the team
|
|
||||||
color: neutral
|
|
||||||
variant: outline
|
|
||||||
to: /team
|
|
||||||
trailingIcon: i-lucide-arrow-right
|
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { kebabCase } from 'scule'
|
import { kebabCase } from 'scule'
|
||||||
import type { ContentNavigationItem } from '@nuxt/content'
|
import type { ContentNavigationItem } from '@nuxt/content'
|
||||||
import type { PageLink } from '@nuxt/ui-pro'
|
import { findPageBreadcrumb, mapContentNavigation } from '#ui-pro/utils/content'
|
||||||
import { findPageBreadcrumb, mapContentNavigation } from '@nuxt/ui-pro/utils/content'
|
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const { framework, module } = useSharedData()
|
const { framework, module } = useSharedData()
|
||||||
@@ -67,9 +66,9 @@ if (!import.meta.prerender) {
|
|||||||
|
|
||||||
const type = page.value?.path.includes('components') ? 'Vue Component ' : page.value?.path.includes('composables') ? 'Vue Composable ' : ''
|
const type = page.value?.path.includes('components') ? 'Vue Component ' : page.value?.path.includes('composables') ? 'Vue Composable ' : ''
|
||||||
useSeoMeta({
|
useSeoMeta({
|
||||||
titleTemplate: `%s ${type}- Nuxt UI ${page.value.module === 'ui-pro' ? 'Pro' : ''} ${page.value.framework === 'vue' ? ' for Vue' : ''}`,
|
titleTemplate: `%s ${type}- Nuxt UI ${page.value.module === 'ui-pro' ? 'Pro' : ''} v3${page.value.framework === 'vue' ? ' for Vue' : ''}`,
|
||||||
title: page.value.navigation?.title ? page.value.navigation.title : page.value.title,
|
title: page.value.navigation?.title ? page.value.navigation.title : page.value.title,
|
||||||
ogTitle: `${page.value.navigation?.title ? page.value.navigation.title : page.value.title} ${type}- Nuxt UI ${page.value.module === 'ui-pro' ? 'Pro' : ''} ${page.value.framework === 'vue' ? ' for Vue' : ''}`,
|
ogTitle: `${page.value.navigation?.title ? page.value.navigation.title : page.value.title} ${type}- Nuxt UI ${page.value.module === 'ui-pro' ? 'Pro' : ''} v3${page.value.framework === 'vue' ? ' for Vue' : ''}`,
|
||||||
description: page.value.description,
|
description: page.value.description,
|
||||||
ogDescription: page.value.description
|
ogDescription: page.value.description
|
||||||
})
|
})
|
||||||
@@ -83,8 +82,6 @@ if (route.path.startsWith('/components')) {
|
|||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
defineOgImageComponent('Docs', {
|
defineOgImageComponent('Docs', {
|
||||||
title: page.value.title,
|
|
||||||
description: page.value.description,
|
|
||||||
headline: breadcrumb.value?.[breadcrumb.value.length - 1]?.label || 'Nuxt UI',
|
headline: breadcrumb.value?.[breadcrumb.value.length - 1]?.label || 'Nuxt UI',
|
||||||
framework: page.value?.framework,
|
framework: page.value?.framework,
|
||||||
module: page.value.module
|
module: page.value.module
|
||||||
@@ -101,25 +98,32 @@ const communityLinks = computed(() => [{
|
|||||||
label: 'Star on GitHub',
|
label: 'Star on GitHub',
|
||||||
to: `https://github.com/nuxt/${page.value?.module === 'ui-pro' ? 'ui-pro' : 'ui'}`,
|
to: `https://github.com/nuxt/${page.value?.module === 'ui-pro' ? 'ui-pro' : 'ui'}`,
|
||||||
target: '_blank'
|
target: '_blank'
|
||||||
}, module.value === 'ui-pro' && {
|
|
||||||
icon: 'i-lucide-credit-card',
|
|
||||||
label: 'Purchase a license',
|
|
||||||
to: 'https://nuxt.lemonsqueezy.com/checkout/buy/057dacb2-87ba-4dc1-9256-59ee5b3bd394',
|
|
||||||
target: '_blank'
|
|
||||||
}, module.value === 'ui-pro' && {
|
|
||||||
icon: 'i-lucide-ticket-percent',
|
|
||||||
label: 'Become an affiliate',
|
|
||||||
to: 'https://nuxt.lemonsqueezy.com/affiliates',
|
|
||||||
target: '_blank'
|
|
||||||
}, {
|
}, {
|
||||||
icon: 'i-lucide-git-pull-request-arrow',
|
icon: 'i-lucide-life-buoy',
|
||||||
label: 'Contribution',
|
label: 'Contribution',
|
||||||
to: '/getting-started/contribution'
|
to: '/getting-started/contribution'
|
||||||
}, {
|
}, {
|
||||||
label: 'Roadmap',
|
label: 'Roadmap',
|
||||||
icon: 'i-lucide-map',
|
icon: 'i-lucide-map',
|
||||||
to: '/roadmap'
|
to: '/roadmap'
|
||||||
}].filter(Boolean) as PageLink[])
|
}])
|
||||||
|
|
||||||
|
// const resourcesLinks = [{
|
||||||
|
// icon: 'i-simple-icons-figma',
|
||||||
|
// label: 'Figma Kit',
|
||||||
|
// to: 'https://www.figma.com/community/file/1288455405058138934',
|
||||||
|
// target: '_blank'
|
||||||
|
// }, {
|
||||||
|
// label: 'Playground',
|
||||||
|
// icon: 'i-simple-icons-stackblitz',
|
||||||
|
// to: 'https://stackblitz.com/edit/nuxt-ui',
|
||||||
|
// target: '_blank'
|
||||||
|
// }, {
|
||||||
|
// icon: 'i-simple-icons-nuxtdotjs',
|
||||||
|
// label: 'Nuxt docs',
|
||||||
|
// to: 'https://nuxt.com',
|
||||||
|
// target: '_blank'
|
||||||
|
// }]
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -147,7 +151,7 @@ const communityLinks = computed(() => [{
|
|||||||
v-bind="link"
|
v-bind="link"
|
||||||
>
|
>
|
||||||
<template v-if="link.avatar" #leading>
|
<template v-if="link.avatar" #leading>
|
||||||
<UAvatar v-bind="link.avatar" size="2xs" :alt="`${link.label} avatar`" />
|
<UAvatar v-bind="link.avatar" size="2xs" />
|
||||||
</template>
|
</template>
|
||||||
</UButton>
|
</UButton>
|
||||||
</template>
|
</template>
|
||||||
@@ -168,9 +172,14 @@ const communityLinks = computed(() => [{
|
|||||||
|
|
||||||
<UPageLinks title="Community" :links="communityLinks" />
|
<UPageLinks title="Community" :links="communityLinks" />
|
||||||
|
|
||||||
|
<!-- <USeparator type="dashed" />
|
||||||
|
|
||||||
|
<UPageLinks title="Resources" :links="resourcesLinks" />
|
||||||
|
|
||||||
<USeparator type="dashed" />
|
<USeparator type="dashed" />
|
||||||
|
|
||||||
<AdsCarbon />
|
<AdsPro />
|
||||||
|
<AdsCarbon /> -->
|
||||||
</template>
|
</template>
|
||||||
</UContentToc>
|
</UContentToc>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ const title = 'Vue Components'
|
|||||||
const description = 'Explore 99+ customizable UI components for Vue and Nuxt built with Tailwind CSS and Reka UI.'
|
const description = 'Explore 99+ customizable UI components for Vue and Nuxt built with Tailwind CSS and Reka UI.'
|
||||||
|
|
||||||
useSeoMeta({
|
useSeoMeta({
|
||||||
titleTemplate: '%s - Nuxt UI',
|
titleTemplate: `%s - Nuxt UI`,
|
||||||
title,
|
title,
|
||||||
description,
|
description,
|
||||||
ogTitle: `${title} - Nuxt UI`,
|
ogTitle: `${title} - Nuxt UI`,
|
||||||
@@ -119,8 +119,7 @@ onMounted(() => {
|
|||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<LazyStarsBg />
|
<StarsBg />
|
||||||
|
|
||||||
<div aria-hidden="true" class="hidden lg:block absolute z-[-1] border-x border-(--ui-border) inset-0 mx-4 sm:mx-6 lg:mx-8" />
|
<div aria-hidden="true" class="hidden lg:block absolute z-[-1] border-x border-(--ui-border) inset-0 mx-4 sm:mx-6 lg:mx-8" />
|
||||||
</UPageHero>
|
</UPageHero>
|
||||||
|
|
||||||
@@ -169,7 +168,6 @@ onMounted(() => {
|
|||||||
:loading="index >= 4 ? 'lazy' : 'eager'"
|
:loading="index >= 4 ? 'lazy' : 'eager'"
|
||||||
width="640"
|
width="640"
|
||||||
height="360"
|
height="360"
|
||||||
:alt="`${component.name} preview`"
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</UPageCard>
|
</UPageCard>
|
||||||
|
|||||||
@@ -178,7 +178,6 @@ pricing:
|
|||||||
- title: Solo License
|
- title: Solo License
|
||||||
description: Design faster with all Nuxt UI Pro components.
|
description: Design faster with all Nuxt UI Pro components.
|
||||||
price: $149
|
price: $149
|
||||||
# discount: $119
|
|
||||||
billing_period: one-time payment
|
billing_period: one-time payment
|
||||||
billing_cycle: plus local taxes
|
billing_cycle: plus local taxes
|
||||||
class: bg-(--ui-bg-elevated)/50
|
class: bg-(--ui-bg-elevated)/50
|
||||||
@@ -200,7 +199,6 @@ pricing:
|
|||||||
- title: Team License
|
- title: Team License
|
||||||
description: Everything you need to deliver faster as a team.
|
description: Everything you need to deliver faster as a team.
|
||||||
price: $349
|
price: $349
|
||||||
# discount: $279
|
|
||||||
billing_period: one-time payment
|
billing_period: one-time payment
|
||||||
billing_cycle: plus local taxes
|
billing_cycle: plus local taxes
|
||||||
class: bg-(--ui-bg-elevated)/50
|
class: bg-(--ui-bg-elevated)/50
|
||||||
@@ -277,14 +275,16 @@ 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.
|
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?
|
- label: Do you have a Figma to Code plugin?
|
||||||
content: >
|
content: >
|
||||||
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):
|
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):
|
||||||
|
|
||||||
1. Install the [TemPad Dev Chrome Extension](https://chromewebstore.google.com/detail/tempad-dev/lgoeakbaikpkihoiphamaeopmliaimpc)
|
1. Install the [TeamPad 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 TemPad Dev panel)
|
2. Open your Figma file with Nuxt UI components (reload the page if you don't see the TeamPad Dev panel)
|
||||||
|
|
||||||
3. Install the `@nuxt` (or `@nuxt/pro` for Nuxt UI Pro) in TemPad Dev's plugins section
|
3. Install the `@nuxt` in TeamPad Dev's plugins section
|
||||||
|
|
||||||
4. Select any Nuxt UI component and inspect the code it generates
|
4. Select any Nuxt UI component and inspect the code it generates
|
||||||
|
|
||||||
{.w-full .rounded .mb-2 .max-w-[636px]}
|
{.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.*
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
// @ts-expect-error yaml is not typed
|
// @ts-expect-error yaml is not typed
|
||||||
import page from '.figma.yml'
|
import page from '.figma.yml'
|
||||||
import { animate } from 'motion-v'
|
import { animate } from 'motion'
|
||||||
import { joinURL } from 'ufo'
|
import { joinURL } from 'ufo'
|
||||||
|
|
||||||
const { url } = useSiteConfig()
|
const { url } = useSiteConfig()
|
||||||
|
|
||||||
useSeoMeta({
|
useSeoMeta({
|
||||||
title: page.title,
|
title: page.title,
|
||||||
description: page.description,
|
description: page.description,
|
||||||
@@ -156,7 +155,7 @@ onMounted(async () => {
|
|||||||
:src="item.src"
|
:src="item.src"
|
||||||
:alt="item.alt"
|
:alt="item.alt"
|
||||||
class="w-full h-auto rounded-[calc(var(--ui-radius)*2)]"
|
class="w-full h-auto rounded-[calc(var(--ui-radius)*2)]"
|
||||||
loading="lazy"
|
lazy
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
</UTabs>
|
</UTabs>
|
||||||
@@ -166,7 +165,7 @@ onMounted(async () => {
|
|||||||
v-if="page.section2.image"
|
v-if="page.section2.image"
|
||||||
v-bind="page.section2.image"
|
v-bind="page.section2.image"
|
||||||
class="w-full h-auto rounded-[calc(var(--ui-radius)*2)]"
|
class="w-full h-auto rounded-[calc(var(--ui-radius)*2)]"
|
||||||
loading="lazy"
|
lazy
|
||||||
/>
|
/>
|
||||||
</UPageSection>
|
</UPageSection>
|
||||||
<UPageSection v-bind="page.section3" orientation="horizontal" :ui="{ container: 'py-16 sm:pt-16 lg:pt-16' }">
|
<UPageSection v-bind="page.section3" orientation="horizontal" :ui="{ container: 'py-16 sm:pt-16 lg:pt-16' }">
|
||||||
@@ -174,7 +173,7 @@ onMounted(async () => {
|
|||||||
v-if="page.section3.image"
|
v-if="page.section3.image"
|
||||||
v-bind="page.section3.image"
|
v-bind="page.section3.image"
|
||||||
class="w-full h-auto rounded-[calc(var(--ui-radius)*2)]"
|
class="w-full h-auto rounded-[calc(var(--ui-radius)*2)]"
|
||||||
loading="lazy"
|
lazy
|
||||||
/>
|
/>
|
||||||
</UPageSection>
|
</UPageSection>
|
||||||
<USeparator />
|
<USeparator />
|
||||||
@@ -199,7 +198,7 @@ onMounted(async () => {
|
|||||||
v-if="step.image"
|
v-if="step.image"
|
||||||
v-bind="step.image"
|
v-bind="step.image"
|
||||||
class="rounded-(--ui-radius)"
|
class="rounded-(--ui-radius)"
|
||||||
loading="lazy"
|
lazy
|
||||||
/>
|
/>
|
||||||
<div>
|
<div>
|
||||||
<h2 class="font-semibold inline-flex items-center gap-x-1">
|
<h2 class="font-semibold inline-flex items-center gap-x-1">
|
||||||
@@ -234,7 +233,6 @@ onMounted(async () => {
|
|||||||
:title="plan.title"
|
:title="plan.title"
|
||||||
:description="plan.description"
|
:description="plan.description"
|
||||||
:price="plan.price"
|
:price="plan.price"
|
||||||
:discount="plan.discount"
|
|
||||||
:billing-period="plan.billing_period"
|
:billing-period="plan.billing_period"
|
||||||
:billing-cycle="plan.billing_cycle"
|
:billing-cycle="plan.billing_cycle"
|
||||||
:highlight="plan.highlight"
|
:highlight="plan.highlight"
|
||||||
@@ -273,7 +271,6 @@ onMounted(async () => {
|
|||||||
:key="index"
|
:key="index"
|
||||||
v-bind="logo"
|
v-bind="logo"
|
||||||
class="h-6 shrink-0 max-w-[140px] filter invert dark:invert-0"
|
class="h-6 shrink-0 max-w-[140px] filter invert dark:invert-0"
|
||||||
loading="lazy"
|
|
||||||
>
|
>
|
||||||
</UPageMarquee>
|
</UPageMarquee>
|
||||||
</UPageCTA>
|
</UPageCTA>
|
||||||
|
|||||||
@@ -23,7 +23,18 @@ const { data: components } = await useAsyncData('ui-components', () => {
|
|||||||
.all()
|
.all()
|
||||||
})
|
})
|
||||||
|
|
||||||
const { data: module } = await useFetch('/api/module.json')
|
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 { format } = Intl.NumberFormat('en', { notation: 'compact' })
|
||||||
|
|
||||||
@@ -65,7 +76,7 @@ useIntersectionObserver(contributorsRef, ([entry]) => {
|
|||||||
:key="feature.title"
|
:key="feature.title"
|
||||||
as-child
|
as-child
|
||||||
:initial="{ opacity: 0, transform: 'translateX(-10px)' }"
|
:initial="{ opacity: 0, transform: 'translateX(-10px)' }"
|
||||||
:while-in-view="{ opacity: 1, transform: 'translateX(0)' }"
|
:in-view="{ opacity: 1, transform: 'translateX(0)' }"
|
||||||
:transition="{ delay: 0.2 + 0.4 * index }"
|
:transition="{ delay: 0.2 + 0.4 * index }"
|
||||||
:in-view-options="{ once: true }"
|
:in-view-options="{ once: true }"
|
||||||
>
|
>
|
||||||
@@ -74,7 +85,7 @@ useIntersectionObserver(contributorsRef, ([entry]) => {
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<LazySkyBg is-index />
|
<SkyBg />
|
||||||
|
|
||||||
<div class="h-[344px] lg:h-full lg:relative w-full lg:min-h-[calc(100vh-var(--ui-header-height)-1px)] overflow-hidden">
|
<div class="h-[344px] lg:h-full lg:relative w-full lg:min-h-[calc(100vh-var(--ui-header-height)-1px)] overflow-hidden">
|
||||||
<UPageMarquee
|
<UPageMarquee
|
||||||
@@ -82,7 +93,7 @@ useIntersectionObserver(contributorsRef, ([entry]) => {
|
|||||||
:overlay="false"
|
:overlay="false"
|
||||||
:ui="{
|
:ui="{
|
||||||
root: '[--gap:--spacing(4)] [--duration:40s] border-(--ui-border) absolute w-full left-0 border-y lg:border-x lg:border-y-0 lg:w-[calc(50%-6px)] 2xl:w-[320px] lg:flex-col',
|
root: '[--gap:--spacing(4)] [--duration:40s] border-(--ui-border) absolute w-full left-0 border-y lg:border-x lg:border-y-0 lg:w-[calc(50%-6px)] 2xl:w-[320px] lg:flex-col',
|
||||||
content: 'lg:w-auto lg:flex-col lg:animate-[marquee-vertical_var(--duration)_linear_infinite] lg:rtl:animate-[marquee-vertical-rtl_var(--duration)_linear_infinite] lg:h-[fit-content]'
|
content: 'lg:w-auto lg:h-full lg:flex-col lg:animate-[marquee-vertical_var(--duration)_linear_infinite] lg:rtl:animate-[marquee-vertical-rtl_var(--duration)_linear_infinite] lg:h-[fit-content]'
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<ULink
|
<ULink
|
||||||
@@ -92,14 +103,10 @@ useIntersectionObserver(contributorsRef, ([entry]) => {
|
|||||||
:to="component.path"
|
:to="component.path"
|
||||||
>
|
>
|
||||||
<UColorModeImage
|
<UColorModeImage
|
||||||
|
|
||||||
:light="`${component.path.replace('/components/', '/components/light/')}.png`"
|
:light="`${component.path.replace('/components/', '/components/light/')}.png`"
|
||||||
:dark="`${component.path.replace('/components/', '/components/dark/')}.png`"
|
:dark="`${component.path.replace('/components/', '/components/dark/')}.png`"
|
||||||
:alt="`${component.title} preview`"
|
|
||||||
width="290"
|
|
||||||
height="163"
|
|
||||||
format="webp"
|
|
||||||
class="hover:scale-105 lg:hover:scale-110 transition-transform aspect-video w-full border-x lg:border-x-0 lg:border-y border-(--ui-border) 2xl:border-y-0"
|
class="hover:scale-105 lg:hover:scale-110 transition-transform aspect-video w-full border-x lg:border-x-0 lg:border-y border-(--ui-border) 2xl:border-y-0"
|
||||||
loading="lazy"
|
|
||||||
/>
|
/>
|
||||||
<UBadge color="neutral" variant="outline" size="md" :label="component.title" class="hidden lg:block absolute mx-auto top-4 left-6 xl:left-4 group-hover/link:opacity-100 opacity-0 transition-all duration-300 pointer-events-none -translate-y-2 group-hover/link:translate-y-0" />
|
<UBadge color="neutral" variant="outline" size="md" :label="component.title" class="hidden lg:block absolute mx-auto top-4 left-6 xl:left-4 group-hover/link:opacity-100 opacity-0 transition-all duration-300 pointer-events-none -translate-y-2 group-hover/link:translate-y-0" />
|
||||||
</ULink>
|
</ULink>
|
||||||
@@ -111,7 +118,7 @@ useIntersectionObserver(contributorsRef, ([entry]) => {
|
|||||||
:overlay="false"
|
:overlay="false"
|
||||||
:ui="{
|
:ui="{
|
||||||
root: '[--gap:--spacing(4)] [--duration:40s] border-(--ui-border) absolute w-full mt-[180px] left-0 border-y lg:mt-auto lg:left-auto lg:border-y-0 lg:border-x lg:w-[calc(50%-6px)] 2xl:w-[320px] lg:right-0 lg:flex-col',
|
root: '[--gap:--spacing(4)] [--duration:40s] border-(--ui-border) absolute w-full mt-[180px] left-0 border-y lg:mt-auto lg:left-auto lg:border-y-0 lg:border-x lg:w-[calc(50%-6px)] 2xl:w-[320px] lg:right-0 lg:flex-col',
|
||||||
content: 'lg:w-auto lg:flex-col lg:animate-[marquee-vertical_var(--duration)_linear_infinite] lg:rtl:animate-[marquee-vertical-rtl_var(--duration)_linear_infinite] lg:h-[fit-content] lg:[animation-direction:reverse]'
|
content: 'lg:w-auto lg:h-full lg:flex-col lg:animate-[marquee-vertical_var(--duration)_linear_infinite] lg:rtl:animate-[marquee-vertical-rtl_var(--duration)_linear_infinite] lg:h-[fit-content] lg:[animation-direction:reverse]'
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<ULink
|
<ULink
|
||||||
@@ -123,12 +130,7 @@ useIntersectionObserver(contributorsRef, ([entry]) => {
|
|||||||
<UColorModeImage
|
<UColorModeImage
|
||||||
:light="`${component.path.replace('/components/', '/components/light/')}.png`"
|
:light="`${component.path.replace('/components/', '/components/light/')}.png`"
|
||||||
:dark="`${component.path.replace('/components/', '/components/dark/')}.png`"
|
:dark="`${component.path.replace('/components/', '/components/dark/')}.png`"
|
||||||
:alt="`${component.title} preview`"
|
|
||||||
width="290"
|
|
||||||
height="163"
|
|
||||||
format="webp"
|
|
||||||
class="hover:scale-105 lg:hover:scale-110 transition-transform aspect-video w-full border-x lg:border-x-0 lg:border-y border-(--ui-border) 2xl:border-y-0"
|
class="hover:scale-105 lg:hover:scale-110 transition-transform aspect-video w-full border-x lg:border-x-0 lg:border-y border-(--ui-border) 2xl:border-y-0"
|
||||||
loading="lazy"
|
|
||||||
/>
|
/>
|
||||||
<UBadge color="neutral" variant="outline" size="md" :label="component.title" class="hidden lg:block absolute mx-auto top-4 left-6 xl:left-4 group-hover/link:opacity-100 opacity-0 transition-all duration-300 pointer-events-none -translate-y-2 group-hover/link:translate-y-0" />
|
<UBadge color="neutral" variant="outline" size="md" :label="component.title" class="hidden lg:block absolute mx-auto top-4 left-6 xl:left-4 group-hover/link:opacity-100 opacity-0 transition-all duration-300 pointer-events-none -translate-y-2 group-hover/link:translate-y-0" />
|
||||||
</ULink>
|
</ULink>
|
||||||
@@ -145,14 +147,12 @@ useIntersectionObserver(contributorsRef, ([entry]) => {
|
|||||||
:key="feature.title"
|
:key="feature.title"
|
||||||
as="li"
|
as="li"
|
||||||
:initial="{ opacity: 0, transform: 'translateY(10px)' }"
|
:initial="{ opacity: 0, transform: 'translateY(10px)' }"
|
||||||
:while-in-view="{ opacity: 1, transform: 'translateY(0)' }"
|
:in-view="{ opacity: 1, transform: 'translateY(0)' }"
|
||||||
:transition="{ delay: 0.1 * index }"
|
:transition="{ delay: 0.1 * index }"
|
||||||
:in-view-options="{ once: true }"
|
:in-view-options="{ once: true }"
|
||||||
class="flex items-start gap-x-3 relative group"
|
class="flex items-start gap-x-3 relative group"
|
||||||
>
|
>
|
||||||
<NuxtLink v-if="feature.to" :to="feature.to" class="absolute inset-0 z-10">
|
<NuxtLink v-if="feature.to" :to="feature.to" class="absolute inset-0 z-10" />
|
||||||
<span class="sr-only">Go to {{ feature.title }}</span>
|
|
||||||
</NuxtLink>
|
|
||||||
|
|
||||||
<div class="relative p-3">
|
<div class="relative p-3">
|
||||||
<svg class="absolute inset-0" viewBox="0 0 44 44" fill="none" xmlns="http://www.w3.org/2000/svg">
|
<svg class="absolute inset-0" viewBox="0 0 44 44" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
@@ -165,12 +165,12 @@ useIntersectionObserver(contributorsRef, ([entry]) => {
|
|||||||
<circle cx="6.53711" cy="37.4551" 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)" />
|
<circle cx="38.5957" cy="37.4551" r="1.5" fill="var(--ui-border-accented)" />
|
||||||
</svg>
|
</svg>
|
||||||
<UIcon :name="feature.icon" class="size-5 shrink-0" />
|
<UIcon :name="feature.icon" class="size-5 flex-shrink-0" />
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
<h2 class="font-medium text-(--ui-text-highlighted) inline-flex items-center gap-x-1">
|
<h2 class="font-medium text-(--ui-text-highlighted) inline-flex items-center gap-x-1">
|
||||||
{{ feature.title }}
|
{{ feature.title }}
|
||||||
<UIcon v-if="feature.to" name="i-lucide-arrow-right" class="size-4 shrink-0 opacity-0 group-hover:opacity-100 transition-all duration-200 -translate-x-1 group-hover:translate-x-0" />
|
<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>
|
</h2>
|
||||||
<p class="text-sm text-(--ui-text-muted)">
|
<p class="text-sm text-(--ui-text-muted)">
|
||||||
{{ feature.description }}
|
{{ feature.description }}
|
||||||
@@ -189,7 +189,7 @@ useIntersectionObserver(contributorsRef, ([entry]) => {
|
|||||||
:links="page.design_system.links"
|
:links="page.design_system.links"
|
||||||
orientation="horizontal"
|
orientation="horizontal"
|
||||||
>
|
>
|
||||||
<MDC :value="page.design_system.code" cache-key="index-design-system-code" />
|
<MDC :value="page.design_system.code" />
|
||||||
</UPageSection>
|
</UPageSection>
|
||||||
|
|
||||||
<USeparator />
|
<USeparator />
|
||||||
@@ -201,10 +201,10 @@ useIntersectionObserver(contributorsRef, ([entry]) => {
|
|||||||
orientation="horizontal"
|
orientation="horizontal"
|
||||||
>
|
>
|
||||||
<template #description>
|
<template #description>
|
||||||
<MDC :value="page.component_customization.description" cache-key="index-component-customization-description" />
|
<MDC :value="page.component_customization.description" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<MDC :value="page.component_customization.code" cache-key="index-component-customization-code" />
|
<MDC :value="page.component_customization.code" />
|
||||||
</UPageSection>
|
</UPageSection>
|
||||||
|
|
||||||
<USeparator />
|
<USeparator />
|
||||||
@@ -218,32 +218,26 @@ useIntersectionObserver(contributorsRef, ([entry]) => {
|
|||||||
class="border-b border-(--ui-border)"
|
class="border-b border-(--ui-border)"
|
||||||
>
|
>
|
||||||
<template #features>
|
<template #features>
|
||||||
<li>
|
<NuxtLink to="https://npm.chart.dev/@nuxt/ui" target="_blank" class="min-w-0">
|
||||||
<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">
|
||||||
<p class="text-4xl font-semibold text-(--ui-text-highlighted) truncate">
|
{{ format(module?.stats?.downloads ?? 0) }}+
|
||||||
{{ format(module?.stats?.downloads ?? 0) }}+
|
</p>
|
||||||
</p>
|
<p class="text-(--ui-text-muted) text-sm truncate">monthly downloads</p>
|
||||||
<p class="text-(--ui-text-muted) text-sm truncate">monthly downloads</p>
|
</NuxtLink>
|
||||||
</NuxtLink>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li>
|
<NuxtLink to="https://github.com/nuxt/ui" target="_blank" class="min-w-0">
|
||||||
<NuxtLink to="https://github.com/nuxt/ui" target="_blank" class="min-w-0">
|
<p class="text-4xl font-semibold text-(--ui-text-highlighted) truncate">
|
||||||
<p class="text-4xl font-semibold text-(--ui-text-highlighted) truncate">
|
{{ format(module?.stats?.stars ?? 0) }}+
|
||||||
{{ format(module?.stats?.stars ?? 0) }}+
|
</p>
|
||||||
</p>
|
<p class="text-(--ui-text-muted) text-sm truncate">GitHub stars</p>
|
||||||
<p class="text-(--ui-text-muted) text-sm truncate">GitHub stars</p>
|
</NuxtLink>
|
||||||
</NuxtLink>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li>
|
<NuxtLink to="https://github.com/nuxt/ui/graphs/contributors" target="_blank" class="min-w-0">
|
||||||
<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">
|
||||||
<p class="text-4xl font-semibold text-(--ui-text-highlighted) truncate">
|
175+
|
||||||
175+
|
</p>
|
||||||
</p>
|
<p class="text-(--ui-text-muted) text-sm truncate">Contributors</p>
|
||||||
<p class="text-(--ui-text-muted) text-sm truncate">Contributors</p>
|
</NuxtLink>
|
||||||
</NuxtLink>
|
|
||||||
</li>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<div ref="contributorsRef" class="p-4 sm:px-6 md:px-8 lg:px-12 xl:px-14 overflow-hidden flex relative">
|
<div ref="contributorsRef" class="p-4 sm:px-6 md:px-8 lg:px-12 xl:px-14 overflow-hidden flex relative">
|
||||||
@@ -267,7 +261,7 @@ useIntersectionObserver(contributorsRef, ([entry]) => {
|
|||||||
</UButton>
|
</UButton>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<LazyStarsBg />
|
<StarsBg />
|
||||||
|
|
||||||
<div aria-hidden="true" class="hidden lg:block absolute z-[-1] border-x border-(--ui-border) inset-0 mx-4 sm:mx-6 lg:mx-8" />
|
<div aria-hidden="true" class="hidden lg:block absolute z-[-1] border-x border-(--ui-border) inset-0 mx-4 sm:mx-6 lg:mx-8" />
|
||||||
<div class="relative h-[400px] border border-(--ui-border) bg-(--ui-bg-muted) overflow-hidden border-x-0 -mx-4 sm:-mx-6 lg:mx-0 lg:border-x w-screen lg:w-full">
|
<div class="relative h-[400px] border border-(--ui-border) bg-(--ui-bg-muted) overflow-hidden border-x-0 -mx-4 sm:-mx-6 lg:mx-0 lg:border-x w-screen lg:w-full">
|
||||||
@@ -302,8 +296,8 @@ useIntersectionObserver(contributorsRef, ([entry]) => {
|
|||||||
:src="`/pro/blocks/image${i}.png`"
|
:src="`/pro/blocks/image${i}.png`"
|
||||||
width="460"
|
width="460"
|
||||||
height="258"
|
height="258"
|
||||||
loading="lazy"
|
|
||||||
:alt="`Nuxt UI Pro Screenshot ${i}`"
|
:alt="`Nuxt UI Pro Screenshot ${i}`"
|
||||||
|
loading="lazy"
|
||||||
class="aspect-video border border-(--ui-border) rounded-[calc(var(--ui-radius)*2)] bg-white"
|
class="aspect-video border border-(--ui-border) rounded-[calc(var(--ui-radius)*2)] bg-white"
|
||||||
>
|
>
|
||||||
</UPageMarquee>
|
</UPageMarquee>
|
||||||
|
|||||||
@@ -17,10 +17,7 @@ pricing:
|
|||||||
title: Figma Kit Pro
|
title: Figma Kit Pro
|
||||||
description: Get all Nuxt UI Pro components in a Figma kit to design your next application before coding. Everything you need, from wire-framing to high-fidelity web integration.
|
description: Get all Nuxt UI Pro components in a Figma kit to design your next application before coding. Everything you need, from wire-framing to high-fidelity web integration.
|
||||||
orientation: horizontal
|
orientation: horizontal
|
||||||
price: $149
|
price: $149 - $349
|
||||||
# discount: $119
|
|
||||||
billing_period: one-time payment
|
|
||||||
billing_cycle: plus local taxes
|
|
||||||
terms: Solo & Team licenses available.
|
terms: Solo & Team licenses available.
|
||||||
features:
|
features:
|
||||||
- 1700+ components & variants from Nuxt UI & UI Pro
|
- 1700+ components & variants from Nuxt UI & UI Pro
|
||||||
@@ -39,7 +36,6 @@ pricing:
|
|||||||
- title: Solo
|
- title: Solo
|
||||||
description: Tailored for indie hackers, freelancers and solo founders.
|
description: Tailored for indie hackers, freelancers and solo founders.
|
||||||
price: $249
|
price: $249
|
||||||
# discount: $199
|
|
||||||
billing_period: one-time payment
|
billing_period: one-time payment
|
||||||
billing_cycle: plus local taxes
|
billing_cycle: plus local taxes
|
||||||
features:
|
features:
|
||||||
@@ -54,7 +50,6 @@ pricing:
|
|||||||
- title: Startup
|
- title: Startup
|
||||||
description: Best suited for small teams, startups and agencies.
|
description: Best suited for small teams, startups and agencies.
|
||||||
price: $499
|
price: $499
|
||||||
# discount: $399
|
|
||||||
billing_period: one-time payment
|
billing_period: one-time payment
|
||||||
billing_cycle: plus local taxes
|
billing_cycle: plus local taxes
|
||||||
features:
|
features:
|
||||||
@@ -70,7 +65,6 @@ pricing:
|
|||||||
- title: Organization
|
- title: Organization
|
||||||
description: Ideal for larger teams and organizations.
|
description: Ideal for larger teams and organizations.
|
||||||
price: $999
|
price: $999
|
||||||
# discount: $799
|
|
||||||
billing_period: one-time payment
|
billing_period: one-time payment
|
||||||
billing_cycle: plus local taxes
|
billing_cycle: plus local taxes
|
||||||
features:
|
features:
|
||||||
@@ -180,7 +174,7 @@ testimonials:
|
|||||||
- quote: "Nuxt UI Pro is my preferred choice for everything, from a POC to a web platform. It's ready to use out-of-the-box and assists me in crafting pixel-perfect UIs. It saves me a significant amount of time while remaining highly customizable. Give it a try, and you won't be let down."
|
- quote: "Nuxt UI Pro is my preferred choice for everything, from a POC to a web platform. It's ready to use out-of-the-box and assists me in crafting pixel-perfect UIs. It saves me a significant amount of time while remaining highly customizable. Give it a try, and you won't be let down."
|
||||||
user:
|
user:
|
||||||
name: 'Estéban Soubiran'
|
name: 'Estéban Soubiran'
|
||||||
description: 'Software engineer'
|
description: 'Web developer and UnJS member'
|
||||||
to: 'https://x.com/soubiran_'
|
to: 'https://x.com/soubiran_'
|
||||||
target: _blank
|
target: _blank
|
||||||
avatar:
|
avatar:
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ const { url } = useSiteConfig()
|
|||||||
useSeoMeta({
|
useSeoMeta({
|
||||||
title,
|
title,
|
||||||
description,
|
description,
|
||||||
ogTitle: title,
|
ogTitle: `${title} - Nuxt UI Pro`,
|
||||||
ogDescription: description,
|
ogDescription: description,
|
||||||
ogImage: joinURL(url, '/pro/og-image.png')
|
ogImage: joinURL(url, '/pro/og-image.png')
|
||||||
})
|
})
|
||||||
@@ -71,8 +71,7 @@ onMounted(() => {
|
|||||||
<template>
|
<template>
|
||||||
<UMain>
|
<UMain>
|
||||||
<UPageHero headline="License Activation" :title="title" :description="description" :ui="{ container: 'relative overflow-hidden', wrapper: 'lg:px-12', description: 'text-pretty' }">
|
<UPageHero headline="License Activation" :title="title" :description="description" :ui="{ container: 'relative overflow-hidden', wrapper: 'lg:px-12', description: 'text-pretty' }">
|
||||||
<LazyStarsBg />
|
<StarsBg />
|
||||||
|
|
||||||
<div aria-hidden="true" class="hidden lg:block absolute z-[-1] border-x border-(--ui-border) inset-0 mx-4 sm:mx-6 lg:mx-8" />
|
<div aria-hidden="true" class="hidden lg:block absolute z-[-1] border-x border-(--ui-border) inset-0 mx-4 sm:mx-6 lg:mx-8" />
|
||||||
|
|
||||||
<div class="px-4 py-10 lg:border border-(--ui-border) bg-(--ui-bg)">
|
<div class="px-4 py-10 lg:border border-(--ui-border) bg-(--ui-bg)">
|
||||||
|
|||||||
@@ -9,10 +9,10 @@ const { url } = useSiteConfig()
|
|||||||
|
|
||||||
useSeoMeta({
|
useSeoMeta({
|
||||||
title: page.title,
|
title: page.title,
|
||||||
description: page.description,
|
|
||||||
ogTitle: page.title,
|
ogTitle: page.title,
|
||||||
ogDescription: page.description,
|
ogImage: joinURL(url, '/pro/og-image.png'),
|
||||||
ogImage: joinURL(url, '/pro/og-image.png')
|
description: page.description,
|
||||||
|
ogDescription: page.description
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -32,7 +32,7 @@ useSeoMeta({
|
|||||||
<MDC :value="page.hero.description" tag="span" unwrap="p" cache-key="pro-hero-description" />
|
<MDC :value="page.hero.description" tag="span" unwrap="p" cache-key="pro-hero-description" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<LazyStarsBg />
|
<StarsBg />
|
||||||
|
|
||||||
<Motion as-child :initial="{ height: 0 }" :animate="{ height: 'auto' }" :transition="{ delay: 0.2, duration: 1 }">
|
<Motion as-child :initial="{ height: 0 }" :animate="{ height: 'auto' }" :transition="{ delay: 0.2, duration: 1 }">
|
||||||
<div aria-hidden="true" class="hidden lg:block absolute z-[-1] border-x border-(--ui-border) inset-0 mx-4 sm:mx-6 lg:mx-8" />
|
<div aria-hidden="true" class="hidden lg:block absolute z-[-1] border-x border-(--ui-border) inset-0 mx-4 sm:mx-6 lg:mx-8" />
|
||||||
@@ -82,11 +82,11 @@ useSeoMeta({
|
|||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<template #description>
|
<template #description>
|
||||||
<Motion :initial="{ opacity: 0, transform: 'translateY(10px)' }" :while-in-view="{ opacity: 1, transform: 'translateY(0)' }" :in-view-options="{ once: true }" :transition="{ delay: 0.2 }">
|
<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" tag="span" unwrap="p" class="before:content-[open-quote] after:content-[close-quote]" cache-key="pro-testimonial-quote" />
|
<MDC :value="page.testimonial.quote" tag="span" unwrap="p" class="before:content-[open-quote] after:content-[close-quote]" cache-key="pro-testimonial-quote" />
|
||||||
</Motion>
|
</Motion>
|
||||||
</template>
|
</template>
|
||||||
<Motion :initial="{ opacity: 0, transform: 'translateY(10px)' }" :while-in-view="{ opacity: 1, transform: 'translateY(0)' }" :in-view-options="{ once: true }" :transition="{ delay: 0.3 }">
|
<Motion :initial="{ opacity: 0, transform: 'translateY(10px)' }" :in-view="{ opacity: 1, transform: 'translateY(0)' }" :in-view-options="{ once: true }" :transition="{ delay: 0.3 }">
|
||||||
<UUser
|
<UUser
|
||||||
v-bind="page.testimonial.user"
|
v-bind="page.testimonial.user"
|
||||||
class="justify-center"
|
class="justify-center"
|
||||||
@@ -103,7 +103,7 @@ useSeoMeta({
|
|||||||
}"
|
}"
|
||||||
class="border-t border-(--ui-border)"
|
class="border-t border-(--ui-border)"
|
||||||
>
|
>
|
||||||
<Motion as-child :initial="{ height: 0 }" :while-in-view="{ height: 'auto' }" :transition="{ delay: 0.4, duration: 1 }">
|
<Motion as-child :initial="{ height: 0 }" :in-view="{ height: 'auto' }" :transition="{ delay: 0.4, duration: 1 }">
|
||||||
<div aria-hidden="true" class="hidden lg:block absolute z-[-1] border-x border-(--ui-border) inset-0 mx-4 sm:mx-6 lg:mx-8" />
|
<div aria-hidden="true" class="hidden lg:block absolute z-[-1] border-x border-(--ui-border) inset-0 mx-4 sm:mx-6 lg:mx-8" />
|
||||||
</Motion>
|
</Motion>
|
||||||
</UPageSection>
|
</UPageSection>
|
||||||
@@ -196,7 +196,7 @@ useSeoMeta({
|
|||||||
class="overflow-hidden"
|
class="overflow-hidden"
|
||||||
orientation="horizontal"
|
orientation="horizontal"
|
||||||
>
|
>
|
||||||
<LazyStarsBg />
|
<StarsBg />
|
||||||
|
|
||||||
<video
|
<video
|
||||||
class="rounded-[var(--ui-radius)] z-10"
|
class="rounded-[var(--ui-radius)] z-10"
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ const { url } = useSiteConfig()
|
|||||||
|
|
||||||
useSeoMeta({
|
useSeoMeta({
|
||||||
title: page.title,
|
title: page.title,
|
||||||
description: page.description,
|
|
||||||
ogTitle: page.title,
|
ogTitle: page.title,
|
||||||
|
description: page.description,
|
||||||
ogDescription: page.description,
|
ogDescription: page.description,
|
||||||
ogImage: joinURL(url, '/pro/og-image.png')
|
ogImage: joinURL(url, '/pro/og-image.png')
|
||||||
})
|
})
|
||||||
@@ -27,10 +27,8 @@ useSeoMeta({
|
|||||||
<MDC :value="page.pricing.title" unwrap="p" cache-key="pro-pricing-title" />
|
<MDC :value="page.pricing.title" unwrap="p" cache-key="pro-pricing-title" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<LazyStarsBg />
|
<StarsBg />
|
||||||
|
|
||||||
<div aria-hidden="true" class="hidden lg:block absolute z-[-1] border-x border-(--ui-border) inset-0 mx-4 sm:mx-6 lg:mx-8" />
|
<div aria-hidden="true" class="hidden lg:block absolute z-[-1] border-x border-(--ui-border) inset-0 mx-4 sm:mx-6 lg:mx-8" />
|
||||||
|
|
||||||
<div class="flex flex-col bg-(--ui-bg) gap-8 lg:gap-0">
|
<div class="flex flex-col bg-(--ui-bg) gap-8 lg:gap-0">
|
||||||
<UPricingPlan
|
<UPricingPlan
|
||||||
v-bind="page.pricing.freePlan"
|
v-bind="page.pricing.freePlan"
|
||||||
@@ -44,7 +42,6 @@ useSeoMeta({
|
|||||||
:title="plan.title"
|
:title="plan.title"
|
||||||
:description="plan.description"
|
:description="plan.description"
|
||||||
:price="plan.price"
|
:price="plan.price"
|
||||||
:discount="plan.discount"
|
|
||||||
:billing-period="plan.billing_period"
|
:billing-period="plan.billing_period"
|
||||||
:billing-cycle="plan.billing_cycle"
|
:billing-cycle="plan.billing_cycle"
|
||||||
:variant="plan.highlight ? 'soft' : 'outline'"
|
:variant="plan.highlight ? 'soft' : 'outline'"
|
||||||
@@ -56,8 +53,6 @@ useSeoMeta({
|
|||||||
<UPricingPlan
|
<UPricingPlan
|
||||||
v-bind="page.pricing.figma"
|
v-bind="page.pricing.figma"
|
||||||
variant="naked"
|
variant="naked"
|
||||||
:billing-period="page.pricing.figma.billing_period"
|
|
||||||
:billing-cycle="page.pricing.figma.billing_cycle"
|
|
||||||
class="lg:rounded-none border lg:border-y-0 border-(--ui-border)"
|
class="lg:rounded-none border lg:border-y-0 border-(--ui-border)"
|
||||||
>
|
>
|
||||||
<template #features>
|
<template #features>
|
||||||
@@ -81,7 +76,6 @@ useSeoMeta({
|
|||||||
:key="index"
|
:key="index"
|
||||||
v-bind="logo"
|
v-bind="logo"
|
||||||
class="h-6 shrink-0 max-w-[140px] filter invert dark:invert-0"
|
class="h-6 shrink-0 max-w-[140px] filter invert dark:invert-0"
|
||||||
loading="lazy"
|
|
||||||
>
|
>
|
||||||
</UPageMarquee>
|
</UPageMarquee>
|
||||||
<UContainer>
|
<UContainer>
|
||||||
|
|||||||
@@ -18,8 +18,7 @@ useSeoMeta({
|
|||||||
<template>
|
<template>
|
||||||
<div class="relative">
|
<div class="relative">
|
||||||
<UPageHero :links="page.links" :ui="{ container: 'relative' }">
|
<UPageHero :links="page.links" :ui="{ container: 'relative' }">
|
||||||
<LazyStarsBg />
|
<StarsBg />
|
||||||
|
|
||||||
<div aria-hidden="true" class="hidden lg:block absolute z-[-1] border-x border-(--ui-border) inset-0 mx-4 sm:mx-6 lg:mx-8" />
|
<div aria-hidden="true" class="hidden lg:block absolute z-[-1] border-x border-(--ui-border) inset-0 mx-4 sm:mx-6 lg:mx-8" />
|
||||||
|
|
||||||
<template #title>
|
<template #title>
|
||||||
@@ -51,12 +50,11 @@ useSeoMeta({
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<div class="lg:border-x border-(--ui-border) h-full flex items-center lg:bg-(--ui-bg-muted)/20">
|
<div class="lg:border-x border-(--ui-border) h-full flex items-center lg:bg-(--ui-bg-muted)/20">
|
||||||
<Motion class="flex-1" :initial="{ opacity: 0, transform: 'translateY(10px)' }" :while-in-view="{ opacity: 1, transform: 'translateY(0px)' }" :in-view-options="{ once: true }" :transition="{ duration: 0.5, delay: 0.2 }">
|
<Motion class="flex-1" :initial="{ opacity: 0, transform: 'translateY(10px)' }" :in-view="{ opacity: 1, transform: 'translateY(0px)' }" :in-view-options="{ once: true }" :transition="{ duration: 0.5, delay: 0.2 }">
|
||||||
<UColorModeImage
|
<UColorModeImage
|
||||||
v-if="template.thumbnail"
|
v-if="template.thumbnail"
|
||||||
v-bind="template.thumbnail"
|
v-bind="template.thumbnail"
|
||||||
class="w-full h-auto border lg:border-y lg:border-x-0 border-(--ui-border) rounded-(--ui-radius) lg:rounded-none"
|
class="w-full h-auto border lg:border-y lg:border-x-0 border-(--ui-border) rounded-(--ui-radius) lg:rounded-none"
|
||||||
:alt="`Template ${index} thumbnail`"
|
|
||||||
width="656"
|
width="656"
|
||||||
height="369"
|
height="369"
|
||||||
loading="lazy"
|
loading="lazy"
|
||||||
@@ -67,7 +65,7 @@ useSeoMeta({
|
|||||||
:items="(template.images as any[])"
|
:items="(template.images as any[])"
|
||||||
dots
|
dots
|
||||||
>
|
>
|
||||||
<NuxtImg v-bind="item" class="w-full h-full object-cover" width="576" height="360" loading="lazy" />
|
<NuxtImg v-bind="item" class="w-full h-full object-cover" width="576" height="360" />
|
||||||
</UCarousel>
|
</UCarousel>
|
||||||
<Placeholder v-else class="w-full h-full aspect-video" />
|
<Placeholder v-else class="w-full h-full aspect-video" />
|
||||||
</Motion>
|
</Motion>
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ const description = page.value.description
|
|||||||
useSeoMeta({
|
useSeoMeta({
|
||||||
title,
|
title,
|
||||||
description,
|
description,
|
||||||
ogTitle: title,
|
ogTitle: `${title} - Nuxt UI Pro`,
|
||||||
ogDescription: description,
|
ogDescription: description,
|
||||||
ogImage: joinURL(url, '/pro/og-image.png')
|
ogImage: joinURL(url, '/pro/og-image.png')
|
||||||
})
|
})
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user