mirror of
https://github.com/ArthurDanjou/ui.git
synced 2026-01-15 20:48:12 +01:00
Compare commits
46 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
531a89cdb8 | ||
|
|
6970c2d665 | ||
|
|
9719ea3858 | ||
|
|
a4af6b3805 | ||
|
|
3493c138d9 | ||
|
|
d08e64d53f | ||
|
|
6aecb082d2 | ||
|
|
63e27f8b4b | ||
|
|
7970aefcb0 | ||
|
|
a893d7fa2e | ||
|
|
8ace629ff8 | ||
|
|
0d35b82ecb | ||
|
|
5f37077835 | ||
|
|
948f4b89b1 | ||
|
|
e6d0dd5898 | ||
|
|
4702a4f103 | ||
|
|
efa9674815 | ||
|
|
97d40395d3 | ||
|
|
a2fb22d835 | ||
|
|
d14a1a82c2 | ||
|
|
a566627a23 | ||
|
|
ee3352278c | ||
|
|
b1d9e01818 | ||
|
|
ca171f3095 | ||
|
|
c0e493d96a | ||
|
|
d0d3235860 | ||
|
|
18915975be | ||
|
|
f5d068be9d | ||
|
|
6018f009a8 | ||
|
|
2b78b5d7dc | ||
|
|
87f3f0b4c0 | ||
|
|
41bf56f2ae | ||
|
|
b7795f4ef6 | ||
|
|
57f8145a8d | ||
|
|
70fbcb6b24 | ||
|
|
bea47b5906 | ||
|
|
fc1b3b2f17 | ||
|
|
5bf5a314c4 | ||
|
|
3558eb1a4f | ||
|
|
1c4d46e056 | ||
|
|
1b0ed9e732 | ||
|
|
b72037a777 | ||
|
|
a7644860b8 | ||
|
|
c90cd9c4f3 | ||
|
|
7805168685 | ||
|
|
27717a55b3 |
79
CHANGELOG.md
79
CHANGELOG.md
@@ -2,6 +2,85 @@
|
||||
|
||||
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
||||
|
||||
### [1.1.3](https://github.com/nuxtlabs/ui/compare/v1.1.2...v1.1.3) (2023-03-02)
|
||||
|
||||
### [1.1.2](https://github.com/nuxtlabs/ui/compare/v1.1.1...v1.1.2) (2023-02-28)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **Tooltip:** truncate ([d08e64d](https://github.com/nuxtlabs/ui/commit/d08e64d53fa439f34d51909bcb6812f1bcd95d83))
|
||||
* **VerticalNavigation:** links `to` type ([7970aef](https://github.com/nuxtlabs/ui/commit/7970aefcb032ce01fcb11e9285fa61ce87f59519))
|
||||
|
||||
### [1.1.1](https://github.com/nuxtlabs/ui/compare/v1.1.0...v1.1.1) (2023-02-20)
|
||||
|
||||
## [1.1.0](https://github.com/nuxtlabs/ui/compare/v1.0.0...v1.1.0) (2023-02-17)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **CommandPalette:** handle async search for specific groups ([efa9674](https://github.com/nuxtlabs/ui/commit/efa9674815ab4de756079690da0a381c3703d564))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **CommandPalette:** types ([4702a4f](https://github.com/nuxtlabs/ui/commit/4702a4f10379201c167cc52099519778756a5780))
|
||||
|
||||
## [1.0.0](https://github.com/nuxtlabs/ui/compare/v0.2.1...v1.0.0) (2023-02-17)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* migrate to `@egoist/tailwindcss-icons` ([ee33522](https://github.com/nuxtlabs/ui/commit/ee3352278cf03fdd12f2a4663b403052de3f089a))
|
||||
|
||||
### [0.2.1](https://github.com/nuxtlabs/ui/compare/v0.2.0...v0.2.1) (2023-02-16)
|
||||
|
||||
## [0.2.0](https://github.com/nuxtlabs/ui/compare/v0.1.39...v0.2.0) (2023-02-16)
|
||||
|
||||
### [0.1.39](https://github.com/nuxtlabs/ui/compare/v0.1.38...v0.1.39) (2023-02-16)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* use `nuxt-icon` ([f5d068b](https://github.com/nuxtlabs/ui/commit/f5d068be9d5778b3d4fcdc11d06d9d765e62075d))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **SelectCustom:** handle search on string arrays ([6018f00](https://github.com/nuxtlabs/ui/commit/6018f009a86cca196d15e4e72dd5eb41aaeb4bad))
|
||||
|
||||
### [0.1.38](https://github.com/nuxtlabs/ui/compare/v0.1.37...v0.1.38) (2023-02-03)
|
||||
|
||||
### [0.1.37](https://github.com/nuxtlabs/ui/compare/v0.1.36...v0.1.37) (2023-02-03)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **CommandPalette:** improve accessibility ([#129](https://github.com/nuxtlabs/ui/issues/129)) ([bea47b5](https://github.com/nuxtlabs/ui/commit/bea47b5906d1bc665717830d6dc2f3ff2a0374f3))
|
||||
|
||||
### [0.1.36](https://github.com/nuxtlabs/ui/compare/v0.1.35...v0.1.36) (2023-02-02)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **CommandPalette:** put back cursor on top only when query changes ([5bf5a31](https://github.com/nuxtlabs/ui/commit/5bf5a314c414b96c656190719bd56acca10676f5))
|
||||
|
||||
### [0.1.35](https://github.com/nuxtlabs/ui/compare/v0.1.34...v0.1.35) (2023-02-01)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **AvatarGroup:** preset size prop ([c90cd9c](https://github.com/nuxtlabs/ui/commit/c90cd9c4f37bc3ce5f6e13f3279dc2c574c76524))
|
||||
* **Dropdown:** lint ([1c4d46e](https://github.com/nuxtlabs/ui/commit/1c4d46e056adf84d69462a12af8ac29f93cbf87a))
|
||||
* **Dropdown:** prevent panel display when no items ([a764486](https://github.com/nuxtlabs/ui/commit/a7644860b8c22a0163e01ca2c0eab2c48b09745a))
|
||||
|
||||
### [0.1.34](https://github.com/nuxtlabs/ui/compare/v0.1.33...v0.1.34) (2023-01-27)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **CommandPalette:** typecheck ([27717a5](https://github.com/nuxtlabs/ui/commit/27717a55b3e5120f32fba2bcea30f5a91262f1c5))
|
||||
|
||||
### [0.1.33](https://github.com/nuxtlabs/ui/compare/v0.1.32...v0.1.33) (2023-01-27)
|
||||
|
||||
### [0.1.32](https://github.com/nuxtlabs/ui/compare/v0.1.31...v0.1.32) (2023-01-23)
|
||||
|
||||
10
docs/app.vue
10
docs/app.vue
@@ -9,11 +9,11 @@
|
||||
</NuxtLink>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="flex items-center">
|
||||
<ColorScheme placeholder="" tag="span">
|
||||
<UButton variant="transparent" :icon="colorMode.value === 'dark' ? 'heroicons-outline:moon' : 'heroicons-outline:sun'" @click="toggleDark" />
|
||||
<UButton variant="transparent" :icon="colorMode.value === 'dark' ? 'i-heroicons-moon' : 'i-heroicons-sun'" @click="toggleDark" />
|
||||
</ColorScheme>
|
||||
<UButton to="https://github.com/nuxtlabs/ui" target="_blank" variant="transparent" icon="fa-brands:github" />
|
||||
<UButton to="https://github.com/nuxtlabs/ui" target="_blank" variant="transparent" icon="i-mdi-github" />
|
||||
</div>
|
||||
</div>
|
||||
</UContainer>
|
||||
@@ -79,12 +79,12 @@ const toggleDark = () => {
|
||||
|
||||
const sections = [
|
||||
{ label: 'Getting Started', links: [{ label: 'Usage', to: '/' }, { label: 'Examples', to: '/examples' }, { label: 'Migration', to: '/migration' }, { label: 'Dark mode', to: '/dark' }] },
|
||||
{ label: 'Elements', links: [{ label: 'Avatar', to: '/components/Avatar' }, { label: 'AvatarGroup', to: '/components/AvatarGroup' }, { label: 'Badge', to: '/components/Badge' }, { label: 'Button', to: '/components/Button' }, { label: 'Dropdown', to: '/components/Dropdown' }, { label: 'Icon', to: '/components/Icon' }] },
|
||||
{ label: 'Elements', links: [{ label: 'Avatar', to: '/components/Avatar' }, { label: 'AvatarGroup', to: '/components/AvatarGroup' }, { label: 'Badge', to: '/components/Badge' }, { label: 'Button', to: '/components/Button' }, { label: 'Dropdown', to: '/components/Dropdown' }] },
|
||||
{ label: 'Feedback', links: [{ label: 'Alert', to: '/components/Alert' }, { label: 'AlertDialog', to: '/components/AlertDialog' }] },
|
||||
{ label: 'Forms', links: [{ label: 'Checkbox', to: '/components/Checkbox' }, { label: 'Input', to: '/components/Input' }, { label: 'FormGroup', to: '/components/FormGroup' }, { label: 'Radio', to: '/components/Radio' }, { label: 'Select', to: '/components/Select' }, { label: 'SelectCustom', to: '/components/SelectCustom' }, { label: 'Textarea', to: '/components/Textarea' }, { label: 'Toggle', to: '/components/Toggle' }] },
|
||||
{ label: 'Layout', links: [{ label: 'Card', to: '/components/Card' }, { label: 'Container', to: '/components/Container' }] },
|
||||
{ label: 'Navigation', links: [{ label: 'Pills', to: '/components/Pills' }, { label: 'Tabs', to: '/components/Tabs' }, { label: 'VerticalNavigation', to: '/components/VerticalNavigation' }, { label: 'CommandPalette', to: '/components/CommandPalette' }] },
|
||||
{ label: 'Overlays', links: [{ label: 'Modal', to: '/components/Modal' }, { label: 'Notification', to: '/components/Notification' }, { label: 'Popover', to: '/components/Popover' }, { label: 'Slideover', to: '/components/Slideover' }, { label: 'Tooltip', to: '/components/Tooltip' }] }
|
||||
{ label: 'Overlays', links: [{ label: 'ContextMenu', to: '/components/ContextMenu' }, { label: 'Modal', to: '/components/Modal' }, { label: 'Notification', to: '/components/Notification' }, { label: 'Popover', to: '/components/Popover' }, { label: 'Slideover', to: '/components/Slideover' }, { label: 'Tooltip', to: '/components/Tooltip' }] }
|
||||
]
|
||||
</script>
|
||||
|
||||
|
||||
@@ -3,7 +3,15 @@ import nuxtUI from '../src/module'
|
||||
|
||||
// https://v3.nuxtjs.org/docs/directory-structure/nuxt.config
|
||||
export default defineNuxtConfig({
|
||||
app: {
|
||||
head: {
|
||||
htmlAttrs: {
|
||||
lang: 'en'
|
||||
}
|
||||
}
|
||||
},
|
||||
modules: [
|
||||
// @ts-ignore
|
||||
nuxtUI
|
||||
],
|
||||
components: {
|
||||
@@ -16,6 +24,7 @@ export default defineNuxtConfig({
|
||||
},
|
||||
preset: {
|
||||
},
|
||||
icons: ['heroicons', 'mdi'],
|
||||
tailwindcss: {
|
||||
theme: {
|
||||
extend: {
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
|
||||
<UButton
|
||||
class="absolute top-0 right-0"
|
||||
:icon="copied ? 'heroicons-outline:clipboard-check' : 'heroicons-outline:clipboard-copy'"
|
||||
:icon="copied ? 'i-heroicons-clipboard-document-check' : 'i-heroicons-clipboard-document'"
|
||||
variant="transparent"
|
||||
size="sm"
|
||||
:custom-class="copied ? '!text-green-500' : ''"
|
||||
@@ -56,7 +56,6 @@
|
||||
v-if="prop.type === 'Boolean'"
|
||||
v-model="prop.value"
|
||||
:name="prop.key"
|
||||
:label="prop.key"
|
||||
/>
|
||||
<USelect
|
||||
v-else-if="prop.values"
|
||||
@@ -121,6 +120,31 @@ const toggle = ref(false)
|
||||
const modal = ref(false)
|
||||
const slideover = ref(false)
|
||||
|
||||
const x = ref(0)
|
||||
const y = ref(0)
|
||||
const isContextMenuOpen = ref(false)
|
||||
const virtualElement = ref({ getBoundingClientRect: () => ({}) })
|
||||
|
||||
onMounted(() => {
|
||||
document.addEventListener('mousemove', ({ clientX, clientY }) => {
|
||||
x.value = clientX
|
||||
y.value = clientY
|
||||
})
|
||||
})
|
||||
|
||||
function openContextMenu () {
|
||||
const top = unref(y)
|
||||
const left = unref(x)
|
||||
|
||||
virtualElement.value.getBoundingClientRect = () => ({
|
||||
width: 0,
|
||||
height: 0,
|
||||
top,
|
||||
left
|
||||
})
|
||||
isContextMenuOpen.value = true
|
||||
}
|
||||
|
||||
const defaultProps = {
|
||||
Button: {
|
||||
label: 'Button text'
|
||||
@@ -132,7 +156,9 @@ const defaultProps = {
|
||||
title: 'A new software update is available. See what’s new in version 2.0.4.'
|
||||
},
|
||||
AlertDialog: {
|
||||
title: 'Are you sure you want to close this modal?',
|
||||
icon: 'i-heroicons-exclamation-triangle',
|
||||
title: 'Deactivate account',
|
||||
description: 'Are you sure you want to deactivate your account? All of your data will be permanently removed from our servers forever. This action cannot be undone.',
|
||||
modelValue: alertDialog,
|
||||
'onUpdate:modelValue': (v) => { alertDialog.value = v },
|
||||
component: {
|
||||
@@ -154,21 +180,21 @@ const defaultProps = {
|
||||
items: [
|
||||
[{
|
||||
label: 'Edit',
|
||||
icon: 'heroicons-solid:pencil'
|
||||
icon: 'i-heroicons-pencil-square-20-solid'
|
||||
}, {
|
||||
label: 'Duplicate',
|
||||
icon: 'heroicons-solid:duplicate'
|
||||
icon: 'i-heroicons-document-duplicate-20-solid'
|
||||
}],
|
||||
[{
|
||||
label: 'Archive',
|
||||
icon: 'heroicons-solid:archive'
|
||||
icon: 'i-heroicons-archive-box-20-solid'
|
||||
}, {
|
||||
label: 'Move',
|
||||
icon: 'heroicons-solid:external-link'
|
||||
icon: 'i-heroicons-arrow-right-circle-20-solid'
|
||||
}],
|
||||
[{
|
||||
label: 'Delete',
|
||||
icon: 'heroicons-solid:trash'
|
||||
icon: 'i-heroicons-trash-20-solid'
|
||||
}]
|
||||
]
|
||||
},
|
||||
@@ -176,22 +202,22 @@ const defaultProps = {
|
||||
links: [
|
||||
{
|
||||
label: 'Home',
|
||||
icon: 'heroicons-outline:home',
|
||||
icon: 'i-heroicons-home',
|
||||
to: '/'
|
||||
},
|
||||
{
|
||||
label: 'Examples',
|
||||
icon: 'heroicons-outline:book-open',
|
||||
icon: 'i-heroicons-book-open',
|
||||
to: '/examples'
|
||||
},
|
||||
{
|
||||
label: 'Migration',
|
||||
icon: 'heroicons-outline:refresh',
|
||||
icon: 'i-heroicons-arrow-path',
|
||||
to: '/migration'
|
||||
},
|
||||
{
|
||||
label: 'External link',
|
||||
icon: 'heroicons-outline:external-link',
|
||||
icon: 'i-heroicons-link',
|
||||
to: 'https://google.fr',
|
||||
target: '_blank'
|
||||
}
|
||||
@@ -207,7 +233,7 @@ const defaultProps = {
|
||||
}]
|
||||
},
|
||||
Icon: {
|
||||
name: 'heroicons-outline:bell'
|
||||
name: 'i-heroicons-bell'
|
||||
},
|
||||
Input: {
|
||||
name: 'input',
|
||||
@@ -259,6 +285,31 @@ const defaultProps = {
|
||||
title: 'Notification title',
|
||||
callback: 'console.log(\'Timer expired\')'
|
||||
},
|
||||
ContextMenu: {
|
||||
modelValue: isContextMenuOpen,
|
||||
'onUpdate:modelValue': (v) => { isContextMenuOpen.value = v },
|
||||
virtualElement,
|
||||
component: {
|
||||
name: 'Card',
|
||||
props: {
|
||||
variant: 'secondary',
|
||||
label: 'Open context menu',
|
||||
onClick: () => { isContextMenuOpen.value = false },
|
||||
onContextmenu: (e) => {
|
||||
e?.preventDefault()
|
||||
openContextMenu()
|
||||
},
|
||||
class: 'relative w-[300px] h-[100px]'
|
||||
}
|
||||
},
|
||||
slots: {
|
||||
default: {
|
||||
tag: 'div',
|
||||
html: 'Context menu content',
|
||||
class: 'rounded border u-border-gray-200 p-2'
|
||||
}
|
||||
}
|
||||
},
|
||||
Modal: {
|
||||
modelValue: modal,
|
||||
'onUpdate:modelValue': (v) => { modal.value = v },
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
Button:
|
||||
</div>
|
||||
|
||||
<UButton variant="primary" icon="heroicons-outline:mail">
|
||||
<UButton variant="primary" icon="i-heroicons-envelope">
|
||||
Button text
|
||||
</UButton>
|
||||
</div>
|
||||
@@ -43,7 +43,7 @@
|
||||
<UModal v-model="isModalOpen" @submit.prevent="onSubmit">
|
||||
<div class="sm:flex sm:items-start">
|
||||
<div class="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-red-100 sm:mx-0 sm:h-10 sm:w-10">
|
||||
<UIcon name="heroicons-outline:exclamation" class="h-6 w-6 text-red-600" aria-hidden="true" />
|
||||
<UIcon name="i-heroicons-exclamation" class="h-6 w-6 text-red-600" aria-hidden="true" />
|
||||
</div>
|
||||
<div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left">
|
||||
<h3 class="text-lg leading-6 font-medium u-text-gray-900">
|
||||
@@ -73,7 +73,7 @@
|
||||
</div>
|
||||
|
||||
<UDropdown v-slot="{ open }" :items="dropdownItems" placement="bottom-start">
|
||||
<UButton variant="white" :icon="open ? 'heroicons-solid:chevron-up' : 'heroicons-solid:chevron-down'" trailing icon-class="transition">
|
||||
<UButton variant="white" :icon="open ? 'i-heroicons-chevron-up-20-solid' : 'i-heroicons-chevron-down-20-solid'" trailing icon-class="transition">
|
||||
Open menu!
|
||||
</UButton>
|
||||
</UDropdown>
|
||||
@@ -96,54 +96,16 @@
|
||||
Popover:
|
||||
</div>
|
||||
|
||||
<UPopover mode="hover" wrapper-class="inline-block relative">
|
||||
<UPopover wrapper-class="inline-block relative">
|
||||
<template #default="{ open }">
|
||||
<UButton variant="secondary" :icon="open ? 'heroicons-solid:chevron-up' : 'heroicons-solid:chevron-down'" trailing icon-class="transition">
|
||||
<UButton variant="secondary" :icon="open ? 'i-heroicons-chevron-up-20-solid-20' : 'i-heroicons-chevron-down-20-solid'" trailing icon-class="transition">
|
||||
Open popover!
|
||||
</UButton>
|
||||
</template>
|
||||
|
||||
<template #panel>
|
||||
<div
|
||||
class="overflow-hidden rounded-lg shadow-lg ring-1 ring-black ring-opacity-5"
|
||||
>
|
||||
<div class="relative grid gap-8 bg-white p-7">
|
||||
<a
|
||||
v-for="item in solutions"
|
||||
:key="item.name"
|
||||
:href="item.href"
|
||||
class="flex items-center p-2 -m-3 transition duration-150 ease-in-out rounded-lg hover:bg-gray-50 focus:outline-none focus-visible:ring focus-visible:ring-orange-500 focus-visible:ring-opacity-50"
|
||||
>
|
||||
<div
|
||||
class="flex items-center justify-center flex-shrink-0 w-10 h-10 text-white sm:h-12 sm:w-12"
|
||||
>
|
||||
<div v-html="item.icon" />
|
||||
</div>
|
||||
<div class="ml-4">
|
||||
<p class="text-sm font-medium u-text-gray-900">
|
||||
{{ item.name }}
|
||||
</p>
|
||||
<p class="text-sm u-text-gray-500">
|
||||
{{ item.description }}
|
||||
</p>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="p-4 bg-gray-50">
|
||||
<a
|
||||
href="##"
|
||||
class="flow-root px-2 py-2 transition duration-150 ease-in-out rounded-md hover:bg-gray-100 focus:outline-none focus-visible:ring focus-visible:ring-orange-500 focus-visible:ring-opacity-50"
|
||||
>
|
||||
<span class="flex items-center">
|
||||
<span class="text-sm font-medium u-text-gray-900">
|
||||
Documentation
|
||||
</span>
|
||||
</span>
|
||||
<span class="block text-sm u-text-gray-500">
|
||||
Start integrating products and tools
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="p-2">
|
||||
Panel
|
||||
</div>
|
||||
</template>
|
||||
</UPopover>
|
||||
@@ -155,7 +117,7 @@
|
||||
</div>
|
||||
|
||||
<UTooltip text="Hello tooltip!" :shortcuts="['⌘', 'G']">
|
||||
<UIcon name="heroicons-outline:information-circle" class="w-6 h-6 u-text-gray-900 cursor-pointer" />
|
||||
<UIcon name="i-heroicons-information-circle" class="w-6 h-6 u-text-gray-900 cursor-pointer" />
|
||||
</UTooltip>
|
||||
</div>
|
||||
|
||||
@@ -163,7 +125,7 @@
|
||||
<div class="font-medium text-sm mb-1 u-text-gray-700">
|
||||
Notifications:
|
||||
</div>
|
||||
<UButton icon="heroicons-outline:bell" variant="red" label="Trigger an error" @click="onNotificationClick" />
|
||||
<UButton icon="i-heroicons-bell" variant="red" label="Trigger an error" @click="onNotificationClick" />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
@@ -171,11 +133,11 @@
|
||||
Context menu:
|
||||
</div>
|
||||
|
||||
<UCard ref="contextMenuRef" class="relative" body-class="h-64" @click="isContextMenuOpen = false" @contextmenu.prevent="openContextMenu">
|
||||
<UCard class="relative" body-class="h-64" @click="isContextMenuOpen = false" @contextmenu.prevent="openContextMenu">
|
||||
<UContextMenu v-model="isContextMenuOpen" :virtual-element="virtualElement" width-class="w-48">
|
||||
<UCard @click.stop>
|
||||
<div class="p-2">
|
||||
Menu
|
||||
</UCard>
|
||||
</div>
|
||||
</UContextMenu>
|
||||
</UCard>
|
||||
</div>
|
||||
@@ -187,18 +149,13 @@
|
||||
|
||||
<UCard body-class="">
|
||||
<UCommandPalette
|
||||
v-model="form.persons"
|
||||
multiple
|
||||
:placeholder="false"
|
||||
:options="{
|
||||
fuseOptions: {
|
||||
includeMatches: true
|
||||
}
|
||||
}"
|
||||
:groups="[{
|
||||
key: 'persons',
|
||||
commands: people
|
||||
}]"
|
||||
:groups="commandPaletteGroups"
|
||||
command-attribute="name"
|
||||
/>
|
||||
</UCard>
|
||||
@@ -212,7 +169,7 @@
|
||||
<UCard body-class="flex">
|
||||
<div class="flex-1 px-4 py-5 sm:p-6 space-y-3">
|
||||
<UFormGroup label="Email" name="email" required>
|
||||
<UInput v-model="form.email" type="email" name="email" required icon="heroicons-outline:mail" />
|
||||
<UInput v-model="form.email" type="email" name="email" required icon="i-heroicons-mail" />
|
||||
</UFormGroup>
|
||||
|
||||
<UFormGroup label="Description" name="description">
|
||||
@@ -227,7 +184,7 @@
|
||||
placeholder="Select a person"
|
||||
text-attribute="name"
|
||||
value-attribute="id"
|
||||
icon="heroicons-outline:user"
|
||||
icon="i-heroicons-user"
|
||||
/>
|
||||
</UFormGroup>
|
||||
|
||||
@@ -236,7 +193,7 @@
|
||||
</UFormGroup>
|
||||
|
||||
<UFormGroup label="Toggle" name="toggle">
|
||||
<UToggle v-model="form.toggle" name="toggle" icon-off="heroicons-solid:x" icon-on="heroicons-solid:check" />
|
||||
<UToggle v-model="form.toggle" name="toggle" icon-off="i-heroicons-x-mark-20-solid" icon-on="i-heroicons-check-20-solid" />
|
||||
</UFormGroup>
|
||||
|
||||
<UFormGroup label="Notifications" label-class="text-base font-medium u-text-gray-900" description="How do you prefer to receive notifications?">
|
||||
@@ -299,7 +256,19 @@ const { $toast } = useNuxtApp()
|
||||
const x = ref(0)
|
||||
const y = ref(0)
|
||||
const isContextMenuOpen = ref(false)
|
||||
const contextMenuRef = ref(null)
|
||||
const virtualElement = ref({ getBoundingClientRect: () => ({}) })
|
||||
|
||||
const commandPaletteGroups = computed(() => ([{
|
||||
key: 'people',
|
||||
commands: people.value
|
||||
}, {
|
||||
key: 'search',
|
||||
label: q => q && `Search results for "${q}"...`,
|
||||
search: async (q) => {
|
||||
if (!q) { return [] }
|
||||
return await $fetch(`https://jsonplaceholder.typicode.com/users?q=${q}`)
|
||||
}
|
||||
}]))
|
||||
|
||||
onMounted(() => {
|
||||
document.addEventListener('mousemove', ({ clientX, clientY }) => {
|
||||
@@ -308,8 +277,6 @@ onMounted(() => {
|
||||
})
|
||||
})
|
||||
|
||||
const virtualElement = ref({ getBoundingClientRect: () => ({}) })
|
||||
|
||||
function openContextMenu () {
|
||||
const top = unref(y)
|
||||
const left = unref(x)
|
||||
@@ -340,27 +307,27 @@ function onSubmit () {
|
||||
const dropdownItems = [
|
||||
[{
|
||||
label: 'Edit',
|
||||
icon: 'heroicons-solid:pencil',
|
||||
icon: 'i-heroicons-pencil-square-20-solid',
|
||||
click: (e) => {
|
||||
e.preventDefault()
|
||||
onClick()
|
||||
}
|
||||
}, {
|
||||
label: 'Duplicate',
|
||||
icon: 'heroicons-solid:duplicate'
|
||||
icon: 'i-heroicons-document-duplicate-20-solid'
|
||||
}],
|
||||
[{
|
||||
label: 'Archive',
|
||||
icon: 'heroicons-solid:archive'
|
||||
icon: 'i-heroicons-archive-box-20-solid'
|
||||
}, {
|
||||
label: 'Move',
|
||||
icon: 'heroicons-solid:external-link',
|
||||
icon: 'i-heroicons-arrow-right-circle-20-solid',
|
||||
to: 'https://www.google.fr',
|
||||
target: '_blank'
|
||||
}],
|
||||
[{
|
||||
label: 'Delete',
|
||||
icon: 'heroicons-solid:trash'
|
||||
icon: 'i-heroicons-trash-20-solid'
|
||||
}]
|
||||
]
|
||||
|
||||
@@ -373,100 +340,11 @@ const customDropdownItems = [
|
||||
}],
|
||||
[{
|
||||
label: 'About',
|
||||
icon: 'heroicons-solid:plus',
|
||||
icon: 'i-heroicons-plus-20-solid',
|
||||
to: '/about'
|
||||
}]
|
||||
]
|
||||
|
||||
const solutions = [
|
||||
{
|
||||
name: 'Insights',
|
||||
description: 'Measure actions your users take',
|
||||
href: '##',
|
||||
icon: `
|
||||
<svg
|
||||
width="48"
|
||||
height="48"
|
||||
viewBox="0 0 48 48"
|
||||
fill="none"
|
||||
aria-hidden='true'
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<rect width="48" height="48" rx="8" fill="#FFEDD5" />
|
||||
<path
|
||||
d="M24 11L35.2583 17.5V30.5L24 37L12.7417 30.5V17.5L24 11Z"
|
||||
stroke="#FB923C"
|
||||
stroke-width="2"
|
||||
/>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M16.7417 19.8094V28.1906L24 32.3812L31.2584 28.1906V19.8094L24 15.6188L16.7417 19.8094Z"
|
||||
stroke="#FDBA74"
|
||||
stroke-width="2"
|
||||
/>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M20.7417 22.1196V25.882L24 27.7632L27.2584 25.882V22.1196L24 20.2384L20.7417 22.1196Z"
|
||||
stroke="#FDBA74"
|
||||
stroke-width="2"
|
||||
/>
|
||||
</svg>
|
||||
`
|
||||
},
|
||||
{
|
||||
name: 'Automations',
|
||||
description: 'Create your own targeted content',
|
||||
href: '##',
|
||||
icon: `
|
||||
<svg
|
||||
width="48"
|
||||
height="48"
|
||||
viewBox="0 0 48 48"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<rect width="48" height="48" rx="8" fill="#FFEDD5" />
|
||||
<path
|
||||
d="M28.0413 20L23.9998 13L19.9585 20M32.0828 27.0001L36.1242 34H28.0415M19.9585 34H11.8755L15.9171 27"
|
||||
stroke="#FB923C"
|
||||
stroke-width="2"
|
||||
/>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M18.804 30H29.1963L24.0001 21L18.804 30Z"
|
||||
stroke="#FDBA74"
|
||||
stroke-width="2"
|
||||
/>
|
||||
</svg>
|
||||
`
|
||||
},
|
||||
{
|
||||
name: 'Reports',
|
||||
description: 'Keep track of your growth',
|
||||
href: '##',
|
||||
icon: `
|
||||
<svg
|
||||
width="48"
|
||||
height="48"
|
||||
viewBox="0 0 48 48"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<rect width="48" height="48" rx="8" fill="#FFEDD5" />
|
||||
<rect x="13" y="32" width="2" height="4" fill="#FDBA74" />
|
||||
<rect x="17" y="28" width="2" height="8" fill="#FDBA74" />
|
||||
<rect x="21" y="24" width="2" height="12" fill="#FDBA74" />
|
||||
<rect x="25" y="20" width="2" height="16" fill="#FDBA74" />
|
||||
<rect x="29" y="16" width="2" height="20" fill="#FB923C" />
|
||||
<rect x="33" y="12" width="2" height="24" fill="#FB923C" />
|
||||
</svg>
|
||||
`
|
||||
}
|
||||
]
|
||||
|
||||
const onNotificationClick = () => {
|
||||
$toast.error({ title: 'Error', description: 'This is an error message' })
|
||||
}
|
||||
|
||||
@@ -105,13 +105,6 @@ const components = [
|
||||
preset: true,
|
||||
typescript: true
|
||||
},
|
||||
{
|
||||
label: 'Icon',
|
||||
to: '/components/Icon',
|
||||
nuxt3: true,
|
||||
capi: true,
|
||||
typescript: true
|
||||
},
|
||||
{
|
||||
label: 'Link',
|
||||
to: '/components/Link',
|
||||
|
||||
35
package.json
35
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nuxthq/ui",
|
||||
"version": "0.1.33",
|
||||
"version": "1.1.3",
|
||||
"repository": "https://github.com/nuxtlabs/ui",
|
||||
"license": "MIT",
|
||||
"exports": {
|
||||
@@ -25,37 +25,34 @@
|
||||
"release": "yarn lint && standard-version && git push --follow-tags"
|
||||
},
|
||||
"dependencies": {
|
||||
"@headlessui/vue": "1.7.4",
|
||||
"@iconify/vue": "^4.0.2",
|
||||
"@nuxt/kit": "^3.0.0",
|
||||
"@egoist/tailwindcss-icons": "^1.0.7",
|
||||
"@headlessui/vue": "^1.7.11",
|
||||
"@iconify-json/heroicons": "^1.1.10",
|
||||
"@nuxt/kit": "^3.2.2",
|
||||
"@nuxtjs/color-mode": "^3.2.0",
|
||||
"@nuxtjs/tailwindcss": "^6.2.0",
|
||||
"@nuxtjs/tailwindcss": "^6.4.1",
|
||||
"@popperjs/core": "^2.11.6",
|
||||
"@tailwindcss/aspect-ratio": "^0.4.2",
|
||||
"@tailwindcss/forms": "^0.5.3",
|
||||
"@tailwindcss/line-clamp": "^0.4.2",
|
||||
"@tailwindcss/typography": "^0.5.9",
|
||||
"@vueuse/core": "^9.11.1",
|
||||
"@vueuse/integrations": "^9.11.1",
|
||||
"defu": "^6.1.1",
|
||||
"@vueuse/core": "^9.13.0",
|
||||
"@vueuse/integrations": "^9.13.0",
|
||||
"defu": "^6.1.2",
|
||||
"fuse.js": "^6.6.2",
|
||||
"lodash-es": "^4.17.21",
|
||||
"tailwindcss": "^3.2.4"
|
||||
"tailwindcss": "^3.2.7"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@iconify-json/mdi": "^1.1.47",
|
||||
"@nuxt/module-builder": "^0.2.1",
|
||||
"@nuxtjs/eslint-config-typescript": "^12.0.0",
|
||||
"@types/lodash-es": "^4.17.6",
|
||||
"eslint": "^8.32.0",
|
||||
"nuxt": "^3.0.0",
|
||||
"@types/node": "^18.14.2",
|
||||
"eslint": "^8.35.0",
|
||||
"nuxt": "^3.2.2",
|
||||
"standard-version": "^9.5.0",
|
||||
"unbuild": "^1.1.1",
|
||||
"vue-tsc": "^1.0.24"
|
||||
},
|
||||
"build": {
|
||||
"externals": [
|
||||
"tailwindcss",
|
||||
"tailwindcss/colors.js"
|
||||
]
|
||||
"unbuild": "^1.1.2",
|
||||
"vue-tsc": "^1.2.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ import { defineNuxtModule, installModule, addComponentsDir, addImportsDir, addTe
|
||||
import { defu } from 'defu'
|
||||
import colors from 'tailwindcss/colors.js'
|
||||
import type { Config } from 'tailwindcss'
|
||||
import { iconsPlugin, getIconCollections } from '@egoist/tailwindcss-icons'
|
||||
import { name, version } from '../package.json'
|
||||
import { colorsAsRegex, excludeColors } from './runtime/utils/colors'
|
||||
import defaultPreset from './runtime/presets/default'
|
||||
@@ -39,6 +40,8 @@ export interface ModuleOptions {
|
||||
|
||||
colors?: ColorsOptions
|
||||
|
||||
icons: string[]
|
||||
|
||||
tailwindcss?: Partial<Config>
|
||||
}
|
||||
|
||||
@@ -49,6 +52,7 @@ const defaults = {
|
||||
primary: 'indigo',
|
||||
gray: 'gray'
|
||||
},
|
||||
icons: ['heroicons'],
|
||||
tailwindcss: {
|
||||
theme: {}
|
||||
}
|
||||
@@ -72,7 +76,7 @@ export default defineNuxtModule<ModuleOptions>({
|
||||
// Transpile runtime
|
||||
const runtimeDir = resolve('./runtime')
|
||||
nuxt.options.build.transpile.push(runtimeDir)
|
||||
nuxt.options.build.transpile.push('@popperjs/core', '@headlessui/vue', '@iconify/vue')
|
||||
nuxt.options.build.transpile.push('@popperjs/core', '@headlessui/vue')
|
||||
|
||||
// @ts-ignore
|
||||
nuxt.hook('tailwindcss:config', function (tailwindConfig: TailwindConfig) {
|
||||
@@ -108,6 +112,9 @@ export default defineNuxtModule<ModuleOptions>({
|
||||
variants: ['focus']
|
||||
}])
|
||||
|
||||
tailwindConfig.plugins = tailwindConfig.plugins || []
|
||||
tailwindConfig.plugins.push(iconsPlugin({ collections: getIconCollections(options.icons as any[]) }))
|
||||
|
||||
const ui: object = defu(preset, defaultPreset(variantColors))
|
||||
|
||||
addTemplate({
|
||||
|
||||
@@ -31,7 +31,7 @@ const props = defineProps({
|
||||
type: String,
|
||||
default: 'md',
|
||||
validator (value: string) {
|
||||
return ['xxxs', 'xxs', 'xs', 'sm', 'md', 'lg', 'xl'].includes(value)
|
||||
return Object.keys($ui.avatar.size).includes(value)
|
||||
}
|
||||
},
|
||||
max: {
|
||||
|
||||
@@ -3,24 +3,27 @@
|
||||
<MenuButton
|
||||
ref="trigger"
|
||||
as="div"
|
||||
:disabled="disabled"
|
||||
class="inline-flex w-full"
|
||||
role="button"
|
||||
@mouseover="onMouseOver"
|
||||
>
|
||||
<slot :open="open">
|
||||
<button>Open</button>
|
||||
<button :disabled="disabled">
|
||||
Open
|
||||
</button>
|
||||
</slot>
|
||||
</MenuButton>
|
||||
|
||||
<div v-if="open" ref="container" :class="[containerClass, widthClass]" @mouseover="onMouseOver">
|
||||
<div v-if="open && items.length" ref="container" :class="[containerClass, widthClass]" @mouseover="onMouseOver">
|
||||
<transition appear v-bind="transitionClass">
|
||||
<MenuItems :class="baseClass" static>
|
||||
<MenuItems :class="[baseClass, divideClass, ringClass, roundedClass, shadowClass, backgroundClass]" static>
|
||||
<div v-for="(subItems, index) of items" :key="index" :class="groupClass">
|
||||
<MenuItem v-for="(item, subIndex) of subItems" :key="subIndex" v-slot="{ active, disabled }" :disabled="item.disabled">
|
||||
<MenuItem v-for="(item, subIndex) of subItems" :key="subIndex" v-slot="{ active, disabled: itemDisabled }" :disabled="item.disabled">
|
||||
<Component
|
||||
v-bind="omit(item, ['click'])"
|
||||
:is="(item.to && NuxtLink) || (item.click && 'button') || 'div'"
|
||||
:class="resolveItemClass({ active, disabled })"
|
||||
:class="resolveItemClass({ active, disabled: itemDisabled })"
|
||||
@click="item.click"
|
||||
>
|
||||
<slot :name="item.slot" :item="item">
|
||||
@@ -85,6 +88,10 @@ const props = defineProps({
|
||||
return ['click', 'hover'].includes(value)
|
||||
}
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
wrapperClass: {
|
||||
type: String,
|
||||
default: () => $ui.dropdown.wrapper
|
||||
@@ -97,6 +104,26 @@ const props = defineProps({
|
||||
type: String,
|
||||
default: () => $ui.dropdown.width
|
||||
},
|
||||
backgroundClass: {
|
||||
type: String,
|
||||
default: () => $ui.dropdown.background
|
||||
},
|
||||
shadowClass: {
|
||||
type: String,
|
||||
default: () => $ui.dropdown.shadow
|
||||
},
|
||||
roundedClass: {
|
||||
type: String,
|
||||
default: () => $ui.dropdown.rounded
|
||||
},
|
||||
ringClass: {
|
||||
type: String,
|
||||
default: () => $ui.dropdown.ring
|
||||
},
|
||||
divideClass: {
|
||||
type: String,
|
||||
default: () => $ui.dropdown.divide
|
||||
},
|
||||
baseClass: {
|
||||
type: String,
|
||||
default: () => $ui.dropdown.base
|
||||
|
||||
@@ -1,54 +1,14 @@
|
||||
<template>
|
||||
<span v-if="isFetching" />
|
||||
<Iconify v-else-if="icon" :icon="icon" />
|
||||
<Component :is="component" v-else-if="component" />
|
||||
<span v-else>{{ name }}</span>
|
||||
<span :class="name" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { IconifyIcon } from '@iconify/vue'
|
||||
import { Icon as Iconify } from '@iconify/vue/dist/offline'
|
||||
import { loadIcon } from '@iconify/vue'
|
||||
import { useNuxtApp, useState, computed, watch, onMounted } from '#imports'
|
||||
|
||||
const props = defineProps({
|
||||
defineProps({
|
||||
name: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
})
|
||||
const nuxtApp = useNuxtApp()
|
||||
const state = useState<Record<string, Required<IconifyIcon> | Promise<void> | null>>('u-icons', () => ({}))
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-asserted-optional-chain
|
||||
const isFetching = computed(() => state.value?.[props.name] && ('then' in state.value?.[props.name]!))
|
||||
const icon = computed<Required<IconifyIcon> | null>(() =>
|
||||
!state.value?.[props.name] || 'then' in state.value[props.name]!
|
||||
? null
|
||||
: state.value[props.name] as Required<IconifyIcon>
|
||||
)
|
||||
const component = computed(() => nuxtApp.vueApp.component(props.name))
|
||||
|
||||
const loadIconComponent = (name: string) => {
|
||||
state.value = state.value || {}
|
||||
if (nuxtApp.vueApp.component(props.name) || state.value[name] || state.value[name] === null) { return state.value[name] }
|
||||
|
||||
state.value[name] = loadIcon(name)
|
||||
.then((res) => { state.value[name] = res })
|
||||
// We won't try to load this icon again if it fails
|
||||
.catch(() => { state.value[name] = null })
|
||||
|
||||
// return an awaitable promise
|
||||
return state.value[name]
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
watch(() => props.name, loadIconComponent, { immediate: true })
|
||||
})
|
||||
|
||||
if (process.server) {
|
||||
await loadIconComponent(props.name)
|
||||
}
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="rounded-md p-4" :class="variantClass">
|
||||
<div class="flex">
|
||||
<div class="flex-shrink-0">
|
||||
<div class="inline-flex flex-shrink-0">
|
||||
<Icon v-if="iconName" :name="iconName" :class="iconClass" class="h-5 w-5" />
|
||||
</div>
|
||||
<div class="ml-3 flex-1 md:flex md:justify-between">
|
||||
@@ -57,10 +57,10 @@ const props = defineProps({
|
||||
|
||||
const iconName = computed(() => {
|
||||
return ({
|
||||
info: 'heroicons-solid:information-circle',
|
||||
warning: 'heroicons-solid:exclamation',
|
||||
error: 'heroicons-solid:x-circle',
|
||||
success: 'heroicons-solid:check-circle'
|
||||
info: 'i-heroicons-information-circle',
|
||||
warning: 'i-heroicons-exclamation',
|
||||
error: 'i-heroicons-x-circle',
|
||||
success: 'i-heroicons-check-circle'
|
||||
})[props.variant]
|
||||
})
|
||||
|
||||
|
||||
@@ -23,9 +23,9 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import { DialogTitle, DialogDescription } from '@headlessui/vue'
|
||||
import Icon from '../elements/Icon.vue'
|
||||
import Modal from '../overlays/Modal.vue'
|
||||
import Button from '../elements/Button.vue'
|
||||
import Icon from '../elements/Icon.vue'
|
||||
import $ui from '#build/ui'
|
||||
|
||||
const props = defineProps({
|
||||
@@ -55,7 +55,7 @@ const props = defineProps({
|
||||
},
|
||||
titleClass: {
|
||||
type: String,
|
||||
default: () => $ui.alertDialog.icon.title
|
||||
default: () => $ui.alertDialog.title
|
||||
},
|
||||
description: {
|
||||
type: String,
|
||||
|
||||
@@ -45,8 +45,8 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import { get } from 'lodash-es'
|
||||
import Icon from '../elements/Icon.vue'
|
||||
import { classNames } from '../../utils'
|
||||
import Icon from '../elements/Icon.vue'
|
||||
import $ui from '#build/ui'
|
||||
|
||||
const props = defineProps({
|
||||
|
||||
@@ -110,7 +110,7 @@ const props = defineProps({
|
||||
default: undefined
|
||||
},
|
||||
options: {
|
||||
type: Array as PropType<{ [key: string]: any, disabled?: boolean }[]>,
|
||||
type: Array as PropType<{ [key: string]: any, disabled?: boolean }[] | string[]>,
|
||||
default: () => []
|
||||
},
|
||||
required: {
|
||||
@@ -292,11 +292,11 @@ const iconClass = computed(() => {
|
||||
const filteredOptions = computed(() =>
|
||||
query.value === ''
|
||||
? props.options
|
||||
: props.options.filter((option: any) => {
|
||||
return (props.searchAttributes?.length ? props.searchAttributes : [props.textAttribute]).some((searchAttribute: any) => {
|
||||
return option[searchAttribute] && option[searchAttribute].search(new RegExp(query.value, 'i')) !== -1
|
||||
: (props.options as any[]).filter((option: any) => {
|
||||
return (props.searchAttributes?.length ? props.searchAttributes : [props.textAttribute]).some((searchAttribute: any) => {
|
||||
return typeof option === 'string' ? option.search(new RegExp(query.value, 'i')) !== -1 : (option[searchAttribute] && option[searchAttribute].search(new RegExp(query.value, 'i')) !== -1)
|
||||
})
|
||||
})
|
||||
})
|
||||
)
|
||||
|
||||
const queryOption = computed(() => {
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
>
|
||||
<div :class="$ui.commandPalette.wrapper">
|
||||
<div v-show="searchable" class="relative flex items-center">
|
||||
<Icon :name="inputIcon" :class="$ui.commandPalette.input.icon.base" aria-hidden="true" />
|
||||
<Icon v-if="inputIcon" :name="inputIcon" :class="$ui.commandPalette.input.icon.base" aria-hidden="true" />
|
||||
<ComboboxInput
|
||||
ref="comboboxInput"
|
||||
:value="query"
|
||||
@@ -25,13 +25,27 @@
|
||||
:class="$ui.commandPalette.input.close.base"
|
||||
:size="$ui.commandPalette.input.close.size"
|
||||
:variant="$ui.commandPalette.input.close.variant"
|
||||
aria-label="close"
|
||||
aria-label="Close"
|
||||
@click="onClear"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<ComboboxOptions v-if="groups.length" static hold class="relative flex-1 overflow-y-auto divide-y divide-gray-100 dark:divide-gray-800 scroll-py-2">
|
||||
<CommandPaletteGroup v-for="group of groups" :key="group.key" :group="group" :group-attribute="groupAttribute" :command-attribute="commandAttribute">
|
||||
<ComboboxOptions
|
||||
v-if="groups.length"
|
||||
static
|
||||
hold
|
||||
as="div"
|
||||
aria-label="Commands"
|
||||
class="relative flex-1 overflow-y-auto divide-y divide-gray-100 dark:divide-gray-800 scroll-py-2"
|
||||
>
|
||||
<CommandPaletteGroup
|
||||
v-for="group of groups"
|
||||
:key="group.key"
|
||||
:query="query"
|
||||
:group="group"
|
||||
:group-attribute="groupAttribute"
|
||||
:command-attribute="commandAttribute"
|
||||
>
|
||||
<template v-for="(_, name) in $slots" #[name]="slotData">
|
||||
<slot :name="name" v-bind="slotData" />
|
||||
</template>
|
||||
@@ -39,8 +53,8 @@
|
||||
</ComboboxOptions>
|
||||
|
||||
<div v-else-if="placeholder" class="flex flex-col items-center justify-center flex-1 px-6 py-14 sm:px-14">
|
||||
<Icon :name="emptyIcon" class="w-6 h-6 mx-auto u-text-gray-400" aria-hidden="true" />
|
||||
<p class="mt-4 text-sm text-center u-text-gray-900">
|
||||
<Icon v-if="emptyIcon" :name="emptyIcon" class="w-6 h-6 mx-auto u-text-gray-400 mb-4" aria-hidden="true" />
|
||||
<p class="text-sm text-center u-text-gray-900">
|
||||
{{ query ? "We couldn't find any items with that term. Please try again." : "We couldn't find any items." }}
|
||||
</p>
|
||||
</div>
|
||||
@@ -52,6 +66,7 @@
|
||||
import { ref, computed, watch, onMounted } from 'vue'
|
||||
import { Combobox, ComboboxInput, ComboboxOptions } from '@headlessui/vue'
|
||||
import type { ComputedRef, PropType, ComponentPublicInstance } from 'vue'
|
||||
import { useDebounceFn } from '@vueuse/core'
|
||||
import { useFuse } from '@vueuse/integrations/useFuse'
|
||||
import { groupBy, map } from 'lodash-es'
|
||||
import { defu } from 'defu'
|
||||
@@ -126,6 +141,10 @@ const props = defineProps({
|
||||
placeholder: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
debounce: {
|
||||
type: Number,
|
||||
default: 200
|
||||
}
|
||||
})
|
||||
|
||||
@@ -161,29 +180,44 @@ const options: ComputedRef<Partial<UseFuseOptions<Command>>> = computed(() => de
|
||||
matchAllWhenSearchEmpty: true
|
||||
}))
|
||||
|
||||
const commands = computed(() => props.groups.reduce((acc, group) => {
|
||||
const commands = computed(() => props.groups.filter(group => !group.search).reduce((acc, group) => {
|
||||
return acc.concat(group.commands.map(command => ({ ...command, group: group.key })))
|
||||
}, [] as Command[]))
|
||||
|
||||
const searchResults = ref<{ [key: string]: any }>({})
|
||||
|
||||
const { results } = useFuse(query, commands, options)
|
||||
|
||||
const groups = computed(() => map(groupBy(results.value, command => command.item.group), (results, key) => {
|
||||
const commands = results.map((result) => {
|
||||
const { item, ...data } = result
|
||||
const groups = computed(() => ([
|
||||
...map(groupBy(results.value, command => command.item.group), (results, key) => {
|
||||
const commands = results.map((result) => {
|
||||
const { item, ...data } = result
|
||||
|
||||
return {
|
||||
...item,
|
||||
...data
|
||||
}
|
||||
})
|
||||
|
||||
return {
|
||||
...item,
|
||||
...data
|
||||
}
|
||||
})
|
||||
...props.groups.find(group => group.key === key),
|
||||
commands: commands.slice(0, options.value.resultLimit)
|
||||
} as Group
|
||||
}),
|
||||
...props.groups.filter(group => !!group.search).map(group => ({ ...group, commands: (searchResults.value[group.key] || []).slice(0, options.value.resultLimit) })).filter(group => group.commands.length)
|
||||
]))
|
||||
|
||||
return {
|
||||
...props.groups.find(group => group.key === key),
|
||||
commands: commands.slice(0, options.value.resultLimit)
|
||||
} as Group
|
||||
}))
|
||||
const debouncedSearch = useDebounceFn(async () => {
|
||||
const searchableGroups = props.groups.filter(group => !!group.search)
|
||||
|
||||
await Promise.all(searchableGroups.map(async (group) => {
|
||||
searchResults.value[group.key] = await group.search(query.value)
|
||||
}))
|
||||
}, props.debounce)
|
||||
|
||||
watch(query, () => {
|
||||
debouncedSearch()
|
||||
|
||||
watch(groups, () => {
|
||||
// Select first item on search changes
|
||||
setTimeout(() => {
|
||||
// https://github.com/tailwindlabs/headlessui/blob/6fa6074cd5d3a96f78a2d965392aa44101f5eede/packages/%40headlessui-vue/src/components/combobox/combobox.ts#L804
|
||||
@@ -221,6 +255,7 @@ function onClear () {
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
query,
|
||||
updateQuery: (q: string) => {
|
||||
query.value = q
|
||||
},
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<template>
|
||||
<li class="p-2" role="option">
|
||||
<h2 v-if="group[groupAttribute]" class="px-3 my-2 text-xs font-semibold u-text-gray-900">
|
||||
{{ group[groupAttribute] }}
|
||||
<div class="p-2" role="option">
|
||||
<h2 v-if="label" class="px-3 my-2 text-xs font-semibold u-text-gray-900">
|
||||
{{ label }}
|
||||
</h2>
|
||||
|
||||
<ul class="text-sm u-text-gray-700">
|
||||
<div class="text-sm u-text-gray-700" role="listbox" :aria-label="group[groupAttribute]">
|
||||
<ComboboxOption
|
||||
v-for="(command, index) of group.commands"
|
||||
:key="`${group.key}-${index}`"
|
||||
@@ -13,16 +13,18 @@
|
||||
:disabled="command.disabled"
|
||||
as="template"
|
||||
>
|
||||
<li :class="['flex justify-between select-none items-center rounded-md px-3 py-2 gap-3 relative', active && 'bg-gray-100 dark:bg-gray-800 u-text-gray-900', command.disabled ? 'cursor-not-allowed' : 'cursor-pointer']">
|
||||
<div :class="['flex justify-between select-none items-center rounded-md px-3 py-2 gap-3 relative', active && 'bg-gray-100 dark:bg-gray-800 u-text-gray-900', command.disabled ? 'cursor-not-allowed' : 'cursor-pointer']">
|
||||
<div class="flex items-center gap-2 min-w-0">
|
||||
<Icon v-if="command.icon" :name="command.icon" :class="['h-4 w-4 flex-shrink-0', active ? 'text-opacity-100 dark:text-opacity-100' : 'text-opacity-40 dark:text-opacity-40', command.iconClass || 'text-gray-900 dark:text-gray-50']" aria-hidden="true" />
|
||||
<Avatar
|
||||
v-else-if="command.avatar"
|
||||
v-bind="{ size: 'xxxs', ...command.avatar }"
|
||||
class="flex-shrink-0"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<span v-else-if="command.chip" class="flex-shrink-0 w-2 h-2 mx-1 rounded-full" :style="{ background: `#${command.chip}` }" />
|
||||
<slot :name="`${group.key}-icon`" :group="group" :command="command">
|
||||
<Icon v-if="command.icon" :name="command.icon" :class="['h-4 w-4 flex-shrink-0', active ? 'text-opacity-100 dark:text-opacity-100' : 'text-opacity-40 dark:text-opacity-40', command.iconClass || 'text-gray-900 dark:text-gray-50']" aria-hidden="true" />
|
||||
<Avatar
|
||||
v-else-if="command.avatar"
|
||||
v-bind="{ size: 'xxxs', ...command.avatar }"
|
||||
class="flex-shrink-0"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<span v-else-if="command.chip" class="flex-shrink-0 w-2 h-2 mx-1 rounded-full" :style="{ background: `#${command.chip}` }" />
|
||||
</slot>
|
||||
|
||||
<div class="flex items-center gap-1.5 min-w-0" :class="{ 'opacity-50': command.disabled }">
|
||||
<slot :name="`${group.key}-command`" :group="group" :command="command">
|
||||
@@ -35,7 +37,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Icon v-if="selected" name="heroicons-outline:check" class="h-5 w-5 u-text-gray-900 flex-shrink-0" aria-hidden="true" />
|
||||
<Icon v-if="selected" :name="$ui.commandPalette.option.selected.icon.name" class="h-5 w-5 u-text-gray-900 flex-shrink-0" aria-hidden="true" />
|
||||
<slot v-else-if="active && (group.active || $slots[`${group.key}-active`])" :name="`${group.key}-active`" :group="group" :command="command">
|
||||
<span v-if="group.active" class="flex-shrink-0 u-text-gray-500">{{ group.active }}</span>
|
||||
</slot>
|
||||
@@ -45,24 +47,30 @@
|
||||
</span>
|
||||
<span v-else-if="!command.disabled && group.inactive" class="flex-shrink-0 u-text-gray-500">{{ group.inactive }}</span>
|
||||
</slot>
|
||||
</li>
|
||||
</div>
|
||||
</ComboboxOption>
|
||||
</ul>
|
||||
</li>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import { ComboboxOption } from '@headlessui/vue'
|
||||
import type { PropType } from 'vue'
|
||||
import Icon from '../elements/Icon.vue'
|
||||
import Avatar from '../elements/Avatar.vue'
|
||||
import type { Group } from '../../types/command-palette'
|
||||
import $ui from '#build/ui'
|
||||
|
||||
defineProps({
|
||||
const props = defineProps({
|
||||
group: {
|
||||
type: Object as PropType<Group>,
|
||||
required: true
|
||||
},
|
||||
query: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
groupAttribute: {
|
||||
type: String,
|
||||
required: true
|
||||
@@ -73,6 +81,12 @@ defineProps({
|
||||
}
|
||||
})
|
||||
|
||||
const label = computed(() => {
|
||||
const label = props.group[props.groupAttribute]
|
||||
|
||||
return typeof label === 'function' ? label(props.query) : label
|
||||
})
|
||||
|
||||
function highlight ({ indices, value }: { indices: number[][], value:string }, i = 1): string {
|
||||
const pair = indices[indices.length - i]
|
||||
if (!pair) {
|
||||
|
||||
@@ -49,7 +49,7 @@ import $ui from '#build/ui'
|
||||
defineProps({
|
||||
links: {
|
||||
type: Array as PropType<{
|
||||
to?: RouteLocationNormalized
|
||||
to?: RouteLocationNormalized | string
|
||||
exact?: boolean
|
||||
label: string
|
||||
icon?: string
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div v-if="isOpen" ref="container" :class="[containerClass, widthClass]">
|
||||
<transition appear v-bind="transitionClass">
|
||||
<div :class="baseClass">
|
||||
<div :class="[baseClass, ringClass, roundedClass, shadowClass, backgroundClass]">
|
||||
<slot />
|
||||
</div>
|
||||
</transition>
|
||||
@@ -38,6 +38,22 @@ const props = defineProps({
|
||||
type: String,
|
||||
default: () => $ui.contextMenu.width
|
||||
},
|
||||
backgroundClass: {
|
||||
type: String,
|
||||
default: () => $ui.contextMenu.background
|
||||
},
|
||||
shadowClass: {
|
||||
type: String,
|
||||
default: () => $ui.contextMenu.shadow
|
||||
},
|
||||
roundedClass: {
|
||||
type: String,
|
||||
default: () => $ui.contextMenu.rounded
|
||||
},
|
||||
ringClass: {
|
||||
type: String,
|
||||
default: () => $ui.contextMenu.ring
|
||||
},
|
||||
baseClass: {
|
||||
type: String,
|
||||
default: () => $ui.contextMenu.base
|
||||
|
||||
@@ -33,11 +33,11 @@
|
||||
</div>
|
||||
|
||||
<button
|
||||
class="transition duration-150 ease-in-out u-text-gray-400 focus:outline-none hover:u-text-gray-500 focus:u-text-gray-500"
|
||||
class="inline-flex transition duration-150 ease-in-out u-text-gray-400 focus:outline-none hover:u-text-gray-500 focus:u-text-gray-500"
|
||||
@click.stop="onClose"
|
||||
>
|
||||
<span class="sr-only">Close</span>
|
||||
<Icon name="heroicons-solid:x" class="w-5 h-5" />
|
||||
<Icon :name="$ui.notification.close.icon.name" class="w-5 h-5" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,14 +1,23 @@
|
||||
<template>
|
||||
<Popover v-slot="{ open, close }" :class="wrapperClass" @mouseleave="onMouseLeave">
|
||||
<PopoverButton ref="trigger" as="div" class="inline-flex w-full" role="button" @mouseover="onMouseOver">
|
||||
<PopoverButton
|
||||
ref="trigger"
|
||||
as="div"
|
||||
:disabled="disabled"
|
||||
class="inline-flex w-full"
|
||||
role="button"
|
||||
@mouseover="onMouseOver"
|
||||
>
|
||||
<slot :open="open" :close="close">
|
||||
<button>Open</button>
|
||||
<button :disabled="disabled">
|
||||
Open
|
||||
</button>
|
||||
</slot>
|
||||
</PopoverButton>
|
||||
|
||||
<div v-if="open" ref="container" :class="[containerClass, widthClass]" @mouseover="onMouseOver">
|
||||
<transition appear v-bind="transitionClass">
|
||||
<PopoverPanel :class="baseClass" static>
|
||||
<PopoverPanel :class="[baseClass, ringClass, roundedClass, shadowClass, backgroundClass]" static>
|
||||
<slot name="panel" :open="open" :close="close" />
|
||||
</PopoverPanel>
|
||||
</transition>
|
||||
@@ -33,6 +42,10 @@ const props = defineProps({
|
||||
return ['click', 'hover'].includes(value)
|
||||
}
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
wrapperClass: {
|
||||
type: String,
|
||||
default: () => $ui.popover.wrapper
|
||||
@@ -49,6 +62,22 @@ const props = defineProps({
|
||||
type: String,
|
||||
default: () => $ui.popover.base
|
||||
},
|
||||
backgroundClass: {
|
||||
type: String,
|
||||
default: () => $ui.popover.background
|
||||
},
|
||||
shadowClass: {
|
||||
type: String,
|
||||
default: () => $ui.popover.shadow
|
||||
},
|
||||
roundedClass: {
|
||||
type: String,
|
||||
default: () => $ui.popover.rounded
|
||||
},
|
||||
ringClass: {
|
||||
type: String,
|
||||
default: () => $ui.popover.ring
|
||||
},
|
||||
transitionClass: {
|
||||
type: Object,
|
||||
default: () => $ui.popover.transition
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<transition appear v-bind="transitionClass">
|
||||
<div :class="[baseClass, backgroundClass, roundedClass, shadowClass, ringClass]">
|
||||
<slot name="text">
|
||||
<span class="truncate">{{ text }}</span>
|
||||
{{ text }}
|
||||
</slot>
|
||||
|
||||
<span v-if="shortcuts?.length" class="inline-flex items-center justify-end flex-shrink-0 gap-0.5 ml-1">
|
||||
|
||||
@@ -48,7 +48,7 @@ export default function defaultPreset (variantColors: string[]) {
|
||||
},
|
||||
icon: {
|
||||
base: 'flex-shrink-0',
|
||||
loading: 'heroicons-outline:refresh',
|
||||
loading: 'i-heroicons-arrow-path',
|
||||
size: {
|
||||
xxs: 'h-3.5 w-3.5',
|
||||
xs: 'h-4 w-4',
|
||||
@@ -168,7 +168,7 @@ export default function defaultPreset (variantColors: string[]) {
|
||||
},
|
||||
icon: {
|
||||
base: 'u-text-gray-400',
|
||||
loading: 'heroicons-outline:refresh',
|
||||
loading: 'i-heroicons-arrow-path',
|
||||
size: {
|
||||
xxs: 'h-3 w-3',
|
||||
xs: 'h-4 w-4',
|
||||
@@ -215,7 +215,7 @@ export default function defaultPreset (variantColors: string[]) {
|
||||
wrapper: 'relative',
|
||||
base: `${select.base} text-left cursor-default`,
|
||||
icon: {
|
||||
name: 'heroicons-solid:selector',
|
||||
name: 'i-heroicons-chevron-up-down-20-solid',
|
||||
...select.icon
|
||||
},
|
||||
list: {
|
||||
@@ -233,7 +233,7 @@ export default function defaultPreset (variantColors: string[]) {
|
||||
disabled: 'cursor-not-allowed opacity-50',
|
||||
empty: 'text-sm u-text-gray-400 px-4 py-2',
|
||||
icon: {
|
||||
name: 'heroicons-solid:check',
|
||||
name: 'i-heroicons-check-20-solid',
|
||||
base: 'absolute inset-y-0 right-0 flex items-center pr-4',
|
||||
active: 'text-white',
|
||||
inactive: 'text-primary-600',
|
||||
@@ -355,18 +355,23 @@ export default function defaultPreset (variantColors: string[]) {
|
||||
|
||||
const alertDialog = {
|
||||
icon: {
|
||||
wrapper: 'h-12 w-12 sm:h-10 sm:w-10 bg-primary-100',
|
||||
base: 'text-primary-600'
|
||||
wrapper: 'mx-auto flex h-12 w-12 flex-shrink-0 items-center justify-center rounded-full bg-primary-100 sm:mx-0 sm:h-10 sm:w-10',
|
||||
base: 'h-6 w-6 text-primary-600'
|
||||
},
|
||||
title: 'text-lg leading-6 font-medium text-gray-900',
|
||||
description: 'text-sm text-gray-500'
|
||||
title: 'text-lg leading-6 font-medium u-text-gray-900',
|
||||
description: 'text-sm u-text-gray-500'
|
||||
}
|
||||
|
||||
const dropdown = {
|
||||
wrapper: 'relative inline-flex text-left',
|
||||
container: 'z-20',
|
||||
width: 'w-48',
|
||||
base: 'u-bg-white divide-y u-divide-gray-100 rounded-md ring-1 u-ring-gray-200 shadow-lg focus:outline-none',
|
||||
background: 'u-bg-white',
|
||||
shadow: 'shadow-lg',
|
||||
rounded: 'rounded-md',
|
||||
ring: 'ring-1 u-ring-gray-200',
|
||||
base: 'focus:outline-none',
|
||||
divide: 'divide-y u-divide-gray-100',
|
||||
group: 'py-1',
|
||||
item: {
|
||||
base: 'group flex items-center gap-3 px-4 py-2 text-sm w-full',
|
||||
@@ -483,10 +488,10 @@ export default function defaultPreset (variantColors: string[]) {
|
||||
rounded: 'rounded-lg',
|
||||
ring: 'ring-1 u-ring-gray-200',
|
||||
type: {
|
||||
info: 'heroicons-outline:information-circle',
|
||||
success: 'heroicons-outline:check-circle',
|
||||
warning: 'heroicons-outline:exclamation-circle',
|
||||
error: 'heroicons-outline:x-circle'
|
||||
info: 'i-heroicons-information-circle',
|
||||
success: 'i-heroicons-check-circle',
|
||||
warning: 'i-heroicons-exclamation-circle',
|
||||
error: 'i-heroicons-x-circle'
|
||||
},
|
||||
icon: {
|
||||
base: 'w-6 h-6',
|
||||
@@ -497,6 +502,11 @@ export default function defaultPreset (variantColors: string[]) {
|
||||
error: 'text-red-400'
|
||||
}
|
||||
},
|
||||
close: {
|
||||
icon: {
|
||||
name: 'i-heroicons-x-mark-20-solid'
|
||||
}
|
||||
},
|
||||
transition: {
|
||||
enterActiveClass: 'transform ease-out duration-300 transition',
|
||||
enterFromClass: 'translate-y-2 opacity-0 sm:translate-y-0 sm:translate-x-2',
|
||||
@@ -515,7 +525,7 @@ export default function defaultPreset (variantColors: string[]) {
|
||||
shadow: 'shadow',
|
||||
rounded: 'rounded',
|
||||
ring: 'ring-1 u-ring-gray-200',
|
||||
base: 'invisible lg:visible h-6 px-2 py-1 text-xs font-normal',
|
||||
base: 'invisible lg:visible h-6 px-2 py-1 text-xs font-normal truncate',
|
||||
transition: {
|
||||
enterActiveClass: 'transition ease-out duration-200',
|
||||
enterFromClass: 'opacity-0 translate-y-1',
|
||||
@@ -533,7 +543,11 @@ export default function defaultPreset (variantColors: string[]) {
|
||||
wrapper: 'relative',
|
||||
container: 'z-20',
|
||||
width: '',
|
||||
base: '',
|
||||
background: 'u-bg-white',
|
||||
shadow: 'shadow-lg',
|
||||
rounded: 'rounded-md',
|
||||
ring: 'ring-1 u-ring-gray-200',
|
||||
base: 'overflow-hidden focus:outline-none',
|
||||
transition: {
|
||||
enterActiveClass: 'transition ease-out duration-200',
|
||||
enterFromClass: 'opacity-0 translate-y-1',
|
||||
@@ -551,7 +565,11 @@ export default function defaultPreset (variantColors: string[]) {
|
||||
wrapper: 'relative',
|
||||
container: 'z-20',
|
||||
width: '',
|
||||
base: '',
|
||||
background: 'u-bg-white',
|
||||
shadow: 'shadow-lg',
|
||||
rounded: 'rounded-md',
|
||||
ring: 'ring-1 u-ring-gray-200',
|
||||
base: 'overflow-hidden focus:outline-none',
|
||||
transition: {
|
||||
enterActiveClass: 'transition ease-out duration-200',
|
||||
enterFromClass: 'opacity-0 translate-y-1',
|
||||
@@ -572,7 +590,7 @@ export default function defaultPreset (variantColors: string[]) {
|
||||
base: 'w-full h-12 pr-4 placeholder-gray-400 dark:placeholder-gray-500 bg-transparent border-0 pl-[3.25rem] u-text-gray-900 focus:ring-0 sm:text-sm',
|
||||
icon: {
|
||||
base: 'pointer-events-none absolute top-3.5 left-5 h-5 w-5 u-text-gray-400',
|
||||
name: 'heroicons-outline:search'
|
||||
name: 'i-heroicons-magnifying-glass'
|
||||
},
|
||||
close: {
|
||||
base: 'absolute right-2',
|
||||
@@ -585,7 +603,14 @@ export default function defaultPreset (variantColors: string[]) {
|
||||
},
|
||||
empty: {
|
||||
icon: {
|
||||
name: 'heroicons-outline:search'
|
||||
name: 'i-heroicons-magnifying-glass'
|
||||
}
|
||||
},
|
||||
option: {
|
||||
selected: {
|
||||
icon: {
|
||||
name: 'i-heroicons-check-20-solid'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
2
src/runtime/types/command-palette.d.ts
vendored
2
src/runtime/types/command-palette.d.ts
vendored
@@ -1,6 +1,7 @@
|
||||
import type { UseFuseOptions } from '@vueuse/integrations/useFuse'
|
||||
import type { FuseSortFunctionMatch, FuseSortFunctionMatchList } from 'fuse.js'
|
||||
import type { Avatar } from './avatar'
|
||||
|
||||
export interface Command {
|
||||
id: string | number
|
||||
prefix?: string
|
||||
@@ -22,6 +23,5 @@ export interface Group {
|
||||
active?: string
|
||||
inactive?: string
|
||||
commands: Command[]
|
||||
options?: Partial<UseFuseOptions<Command>>
|
||||
[key: string]: any
|
||||
}
|
||||
|
||||
@@ -1,14 +1,3 @@
|
||||
{
|
||||
"extends": "./docs/.nuxt/tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"module": "esnext"
|
||||
},
|
||||
"include": [
|
||||
"./**/*",
|
||||
"./docs/.nuxt/nuxt.d.ts"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
"dist"
|
||||
]
|
||||
"extends": "./docs/.nuxt/tsconfig.json"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user