refactor: component dialog, select input, select zone, tree view

This commit is contained in:
puriphatt 2024-10-02 15:06:39 +07:00
parent 5d292c5a5c
commit 51f41abc4b
4 changed files with 109 additions and 23 deletions

View file

@ -45,7 +45,7 @@ const currentTab = defineModel<string>('currentTab');
:model-value="modal"
@update:model-value="(v) => (modal = beforeClose ? beforeClose() : v)"
@before-show="show"
@hide="hideCloseEvent !== undefined && hideCloseEvent ? '' : close"
@hide="hideCloseEvent !== undefined && hideCloseEvent ? '' : close?.()"
>
<div
class="surface-1"

View file

@ -18,14 +18,23 @@ const props = withDefaults(
option: Record<string, unknown>[];
optionLabel?: string;
optionValue?: string;
placeholder?: string;
hideSelected?: boolean;
readonly?: boolean;
clearable?: boolean;
incremental?: boolean;
fillInput?: boolean;
rules?: ((value: string) => string | true)[];
}>(),
{ option: () => [], optionLabel: 'label', optionValue: 'value' },
{
option: () => [],
optionLabel: 'label',
optionValue: 'value',
hideSelected: true,
fillInput: true,
},
);
defineEmits<{
@ -53,14 +62,15 @@ watch(
</script>
<template>
<q-select
:placeholder="placeholder"
outlined
:clearable
use-input
emit-value
map-options
hide-selected
:hideSelected
hide-bottom-space
:fill-input="!!model"
:fill-input="fillInput && !!model"
:hide-dropdown-icon="readonly"
input-debounce="0"
:option-value="optionValue"
@ -70,7 +80,7 @@ watch(
:readonly
:label="label"
:options="incremental ? option : options"
:for="`select-${id}`"
:for="`${id}`"
@filter="
(val, update) => {
incremental ? $emit('filter', val, update) : defaultFilter(val, update);
@ -88,8 +98,8 @@ watch(
</q-item>
</template>
<template v-if="$slots.name" v-slot:selected-item="scope">
<slot name="selected-item" :scope="scope"></slot>
<template v-if="$slots.selectedItem" v-slot:selected-item="scope">
<slot name="selectedItem" :scope="scope"></slot>
</template>
<template v-if="$slots.option" v-slot:option="scope">

View file

@ -7,23 +7,50 @@ const props = withDefaults(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
items: any;
color?: string;
borderSearchSection?: boolean;
itemClass?: string;
noPadding?: boolean;
noItemsIcon?: string;
noItemsLabel?: string;
}>(),
{
items: () => [],
color: 'var(--brand-1)',
noItemsIcon: 'mdi-close',
itemClass: 'col-md-2 col-sm-6 col-12',
},
);
function select(item: unknown) {
if (selectedItem.value.includes(item)) {
let index = selectedItem.value.indexOf(item);
selectedItem.value.splice(index, 1);
} else selectedItem.value.push(item);
defineExpose({ select });
function select(item?: unknown, all?: boolean) {
if (all) {
if (props.items.every((item) => selectedItem.value.includes(item))) {
selectedItem.value = selectedItem.value.filter(
(item) => !props.items.includes(item),
);
} else {
props.items.forEach((i) => {
const productExists = selectedItem.value.some((item) => item === i);
if (!productExists) {
selectedItem.value.push(i);
}
});
}
} else {
if (selectedItem.value.includes(item)) {
const index = selectedItem.value.indexOf(item);
selectedItem.value.splice(index, 1);
} else selectedItem.value.push(item);
}
}
</script>
<template>
<section class="full-width column q-pa-md">
<header class="row items-center no-wrap q-mb-md">
<section class="full-width column">
<header
class="row items-center no-wrap q-px-md q-py-sm"
:class="{ 'bordered surface-3 ': borderSearchSection }"
>
<div class="col"><slot name="top"></slot></div>
<q-input
for="input-search"
@ -40,14 +67,11 @@ function select(item: unknown) {
</template>
</q-input>
</header>
<slot name="tab"></slot>
<section class="col">
<div class="row q-col-gutter-md">
<div
v-for="(item, i) in items"
:key="i"
class="col-md-2 col-sm-6 col-12"
>
<section class="col q-ma-md">
<div v-if="items.length > 0" class="row q-col-gutter-md">
<div v-for="(item, i) in items" :key="i" :class="`${itemClass}`">
<div
class="rounded cursor-pointer relative-position"
:style="`border: 1px solid ${selectedItem.includes(item) ? color : 'transparent'}`"
@ -64,6 +88,14 @@ function select(item: unknown) {
</div>
</div>
</div>
<div v-else class="flex justify-center full-height">
<span class="col column items-center justify-center app-text-muted">
<q-avatar style="background: var(--surface-0)" class="q-mb-md">
<q-icon :name="noItemsIcon" />
</q-avatar>
{{ noItemsLabel || $t('general.noData') }}
</span>
</div>
</section>
</section>
</template>

View file

@ -1,6 +1,7 @@
<script setup lang="ts">
import { Icon } from '@iconify/vue';
import { computed } from 'vue';
import DeleteButton from '../button/DeleteButton.vue';
type Node = {
[key: string]: any;
@ -17,10 +18,14 @@ type Props = {
level?: number;
keyTitle?: string;
keySubtitle?: string;
expandable?: boolean;
hideCheckBox?: boolean;
iconSize?: string;
hideCheckBox?: boolean;
expandable?: boolean;
selectable?: boolean;
deleteable?: boolean;
movable?: boolean;
selectedNode?: Node[];
ancestorNode?: Node[];
decoration?: {
@ -38,6 +43,9 @@ const emits = defineEmits<{
(e: 'checked'): void;
(e: 'select', node: Node, ancestor?: Node[]): void;
(e: 'open', node: Node, ancestor?: Node[]): void;
(e: 'delete', node: Node): void;
(e: 'moveUp', node: Node): void;
(e: 'moveDown', node: Node): void;
}>();
const dec = props.decoration?.find((v) => v.level === (props.level || 0));
@ -90,6 +98,34 @@ function toggleExpand(node: Node, ancestor?: []) {
() => (selectable ? $emit('select', node) : toggleExpand(node))
"
>
<div v-if="!level" style="margin-right: var(--size-1)">
<q-btn
id="btn-up"
for="btn-up"
icon="mdi-arrow-up"
size="sm"
dense
flat
round
:disable="i === 0"
style="color: hsl(var(--text-mute-2))"
@click.stop="$emit('moveUp', node)"
/>
<q-btn
id="btn-down"
for="btn-down"
icon="mdi-arrow-down"
size="sm"
dense
flat
round
class="q-mx-sm"
:disable="i === nodes.length - 1"
style="color: hsl(var(--text-mute-2))"
@click.stop="$emit('moveDown', node)"
/>
</div>
<div style="width: var(--size-6); margin-right: var(--size-1)">
<div
v-if="level !== maxLevel"
@ -154,6 +190,13 @@ function toggleExpand(node: Node, ancestor?: []) {
{{ node[keySubtitle || 'subtitle'] || 'No Subtitle' }}
</span>
</div>
<DeleteButton
v-if="!level"
class="q-ml-auto"
icon-only
@click.stop="$emit('delete', node)"
/>
</div>
</template>
@ -208,6 +251,7 @@ function toggleExpand(node: Node, ancestor?: []) {
/>
</div>
</transition>
<q-separator v-if="!level && i !== nodes.length - 1" class="q-mt-sm" />
</div>
</div>
</template>