mirror of
https://github.com/ArthurDanjou/ui.git
synced 2026-01-29 03:10:42 +01:00
feat(InputMenu): new component (#86)
This commit is contained in:
@@ -27,6 +27,7 @@ const components = [
|
||||
'form',
|
||||
'form-field',
|
||||
'input',
|
||||
'input-menu',
|
||||
'kbd',
|
||||
'link',
|
||||
'modal',
|
||||
|
||||
@@ -62,6 +62,16 @@ const variants = Object.keys(theme.variants.variant)
|
||||
<div class="flex items-center gap-2 ml-[-171px]">
|
||||
<UButton v-for="size in sizes" :key="size" icon="i-heroicons-rocket-launch" label="Button" :size="(size as any)" />
|
||||
</div>
|
||||
<div class="flex items-center gap-2 ml-[-171px]">
|
||||
<UButton
|
||||
v-for="size in sizes"
|
||||
:key="size"
|
||||
:avatar="{ src: 'https://avatars.githubusercontent.com/u/739984?v=4' }"
|
||||
label="Button"
|
||||
color="white"
|
||||
:size="(size as any)"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex items-center gap-2 ml-[-159px]">
|
||||
<UButton
|
||||
v-for="size in sizes"
|
||||
@@ -72,9 +82,12 @@ const variants = Object.keys(theme.variants.variant)
|
||||
:size="(size as any)"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex items-center gap-2 ml-[-67px]">
|
||||
<div class="flex items-center gap-2 ml-[-68px]">
|
||||
<UButton v-for="size in sizes" :key="size" icon="i-heroicons-rocket-launch" :size="(size as any)" />
|
||||
</div>
|
||||
<div class="flex items-center gap-2 ml-[-68px]">
|
||||
<UButton v-for="size in sizes" :key="size" :avatar="{ src: 'https://avatars.githubusercontent.com/u/739984?v=4' }" color="white" :size="(size as any)" />
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<UButton icon="i-heroicons-rocket-launch" trailing-icon="i-heroicons-chevron-down-20-solid" label="Block" block />
|
||||
</div>
|
||||
|
||||
@@ -1,13 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
// import { createReusableTemplate, refDebounced } from '@vueuse/core'
|
||||
import { createReusableTemplate } from '@vueuse/core'
|
||||
|
||||
type User = {
|
||||
id: number
|
||||
name: string
|
||||
email: string
|
||||
phone: string
|
||||
}
|
||||
import type { User } from '~/types'
|
||||
|
||||
const [DefineTemplate, ReuseTemplate] = createReusableTemplate()
|
||||
const toast = useToast()
|
||||
@@ -28,7 +22,7 @@ const { data: users, pending } = await useFetch('https://jsonplaceholder.typicod
|
||||
const groups = computed(() => [{
|
||||
id: 'users',
|
||||
label: searchTerm.value ? `Users matching “${searchTerm.value}”...` : 'Users',
|
||||
items: users.value!
|
||||
items: users.value || []
|
||||
}, {
|
||||
id: 'actions',
|
||||
items: [{
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
<script setup lang="ts">
|
||||
const appConfig = useAppConfig()
|
||||
|
||||
const items = [
|
||||
[{
|
||||
label: 'My account',
|
||||
@@ -122,12 +120,8 @@ defineShortcuts(extractShortcuts(items))
|
||||
<UDropdownMenu :items="items" arrow :content="{ side: 'bottom', align: 'start' }" class="min-w-48">
|
||||
<UButton label="Open" color="white" icon="i-heroicons-user" />
|
||||
|
||||
<template #custom="{ item }">
|
||||
<UIcon :name="item.icon" class="shrink-0 size-5" />
|
||||
|
||||
<span class="truncate">{{ item.label }}</span>
|
||||
|
||||
<UIcon name="i-heroicons-check-badge" class="shrink-0 size-5 text-primary-500 dark:text-primary-400 ms-auto" />
|
||||
<template #custom-trailing>
|
||||
<UIcon name="i-heroicons-check-badge" class="shrink-0 size-5 text-primary-500 dark:text-primary-400" />
|
||||
</template>
|
||||
</UDropdownMenu>
|
||||
</div>
|
||||
|
||||
63
playground/pages/input-menu.vue
Normal file
63
playground/pages/input-menu.vue
Normal file
@@ -0,0 +1,63 @@
|
||||
<script setup lang="ts">
|
||||
import { refDebounced } from '@vueuse/core'
|
||||
|
||||
import type { User } from '~/types'
|
||||
|
||||
const fruits = ['Apple', 'Banana', 'Blueberry', 'Grapes', 'Pineapple']
|
||||
const vegetables = ['Aubergine', 'Broccoli', 'Carrot', 'Courgette', 'Leek']
|
||||
|
||||
const { data: users2 } = await useFetch('https://jsonplaceholder.typicode.com/users', {
|
||||
transform: (data: User[]) => {
|
||||
return data?.map(user => ({ id: user.id, label: user.name, avatar: { src: `https://i.pravatar.cc/120?img=${user.id}` } })) || []
|
||||
}
|
||||
})
|
||||
|
||||
const searchTerm = ref('')
|
||||
const searchTermDebounced = refDebounced(searchTerm, 200)
|
||||
|
||||
const { data: users3, pending } = await useFetch('https://jsonplaceholder.typicode.com/users', {
|
||||
params: { q: searchTermDebounced },
|
||||
transform: (data: User[]) => {
|
||||
return data?.map(user => ({ id: user.id, label: user.name, avatar: { src: `https://i.pravatar.cc/120?img=${user.id}` } })) || []
|
||||
}
|
||||
})
|
||||
|
||||
const statuses = [{
|
||||
label: 'Backlog',
|
||||
icon: 'i-heroicons-question-mark-circle'
|
||||
}, {
|
||||
label: 'To Do',
|
||||
icon: 'i-heroicons-plus-circle'
|
||||
}, {
|
||||
label: 'In Progress',
|
||||
icon: 'i-heroicons-arrow-up-circle'
|
||||
}, {
|
||||
label: 'Done',
|
||||
icon: 'i-heroicons-check-circle'
|
||||
}, {
|
||||
label: 'Canceled',
|
||||
icon: 'i-heroicons-x-circle'
|
||||
}]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex flex-col gap-4">
|
||||
<div class="flex gap-4">
|
||||
<UInputMenu :items="[[{ label: 'Fruits', type: 'label' }, ...fruits], [{ label: 'Vegetables', type: 'label' }, ...vegetables]]" placeholder="Search..." />
|
||||
|
||||
<UInputMenu :items="statuses" placeholder="Search status..." icon="i-heroicons-magnifying-glass" trailing-icon="i-heroicons-chevron-up-down-20-solid" />
|
||||
|
||||
<UInputMenu :items="users2 || []" icon="i-heroicons-user" placeholder="Search users..." />
|
||||
|
||||
<UInputMenu
|
||||
v-model:search-term="searchTerm"
|
||||
:items="users3 || []"
|
||||
:loading="pending"
|
||||
:filter="false"
|
||||
icon="i-heroicons-user"
|
||||
placeholder="Search users async..."
|
||||
@update:open="searchTerm = ''"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -6,7 +6,7 @@ const sizes = Object.keys(theme.variants.size)
|
||||
|
||||
<template>
|
||||
<div class="flex flex-col items-center gap-4">
|
||||
<div class="flex flex-col gap-4 ml-[86px]">
|
||||
<div class="flex flex-col gap-4 ml-[46px]">
|
||||
<UInput placeholder="Search..." autofocus />
|
||||
<UInput placeholder="Search..." color="gray" />
|
||||
<UInput placeholder="Search..." color="primary" />
|
||||
@@ -20,7 +20,7 @@ const sizes = Object.keys(theme.variants.size)
|
||||
<UInput loading trailing placeholder="Search..." />
|
||||
<UInput loading trailing-icon="i-heroicons-magnifying-glass" placeholder="Search..." />
|
||||
</div>
|
||||
<div class="flex items-center gap-4 -ml-[42px]">
|
||||
<div class="flex items-center gap-4 ml-[-44px]">
|
||||
<UInput
|
||||
v-for="size in sizes"
|
||||
:key="size"
|
||||
@@ -37,6 +37,15 @@ const sizes = Object.keys(theme.variants.size)
|
||||
:size="(size as any)"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex items-center gap-4">
|
||||
<UInput
|
||||
v-for="size in sizes"
|
||||
:key="size"
|
||||
:avatar="{ src: 'https://avatars.githubusercontent.com/u/739984?v=4' }"
|
||||
placeholder="Search..."
|
||||
:size="(size as any)"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex items-center gap-4">
|
||||
<UInput
|
||||
v-for="size in sizes"
|
||||
|
||||
@@ -17,10 +17,10 @@ const kbdKeys = Object.keys(kbdKeysMap)
|
||||
<div class="flex items-center gap-1">
|
||||
<UKbd value="meta" color="black" />
|
||||
</div>
|
||||
<div class="flex items-center gap-1 -ml-[216px]">
|
||||
<div class="flex items-center gap-1 ml-[-216px]">
|
||||
<UKbd v-for="(kdbKey, index) in kbdKeys" :key="index" :value="kdbKey" />
|
||||
</div>
|
||||
<div class="flex items-center gap-1 -ml-[22px]">
|
||||
<div class="flex items-center gap-1 ml-[-22px]">
|
||||
<UKbd v-for="size in sizes" :key="size" value="meta" :size="(size as any)" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
6
playground/types/index.d.ts
vendored
Normal file
6
playground/types/index.d.ts
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
export interface User {
|
||||
id: number
|
||||
name: string
|
||||
email: string
|
||||
phone: string
|
||||
}
|
||||
Reference in New Issue
Block a user