Added read only category table
This commit is contained in:
@@ -338,6 +338,81 @@
|
||||
--border-color: color-mix(in srgb, var(--base-color), var(--color-slate-800) 50%);
|
||||
}
|
||||
|
||||
.bgc {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: nowrap;
|
||||
}
|
||||
|
||||
.bgc::before {
|
||||
content: "";
|
||||
display: inline-block;
|
||||
width: .75rem;
|
||||
aspect-ratio: 1;
|
||||
margin-right: 0.5em;
|
||||
border-radius: .25rem;
|
||||
background-color: red;
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
|
||||
.bgc-red::before {
|
||||
@apply bg-red-500;
|
||||
}
|
||||
.bgc-orange::before {
|
||||
@apply bg-orange-500;
|
||||
}
|
||||
.bgc-amber::before {
|
||||
@apply bg-amber-500;
|
||||
}
|
||||
.bgc-yellow::before {
|
||||
@apply bg-yellow-500;
|
||||
}
|
||||
.bgc-lime::before {
|
||||
@apply bg-lime-500;
|
||||
}
|
||||
.bgc-green::before {
|
||||
@apply bg-green-500;
|
||||
}
|
||||
.bgc-emerald::before {
|
||||
@apply bg-emerald-600;
|
||||
}
|
||||
.bgc-teal::before {
|
||||
@apply bg-teal-600;
|
||||
}
|
||||
.bgc-cyan::before {
|
||||
@apply bg-cyan-600;
|
||||
}
|
||||
.bgc-sky::before {
|
||||
@apply bg-sky-600;
|
||||
}
|
||||
.bgc-blue::before {
|
||||
@apply bg-blue-600;
|
||||
}
|
||||
.bgc-indigo::before {
|
||||
@apply bg-indigo-600;
|
||||
}
|
||||
.bgc-violet::before {
|
||||
@apply bg-violet-600;
|
||||
}
|
||||
.bgc-purple::before {
|
||||
@apply bg-purple-600;
|
||||
}
|
||||
.bgc-fuchsia::before {
|
||||
@apply bg-fuchsia-600;
|
||||
}
|
||||
.bgc-pink::before {
|
||||
@apply bg-pink-600;
|
||||
}
|
||||
.bgc-rose::before {
|
||||
@apply bg-rose-600;
|
||||
}
|
||||
.bgc-black::before {
|
||||
@apply bg-black dark:border-[1px] dark:border-slate-300;
|
||||
}
|
||||
.bgc-white::before {
|
||||
@apply bg-white border-[1px] border-slate-700;
|
||||
}
|
||||
|
||||
.fade-enter-active,
|
||||
.fade-leave-active {
|
||||
transition: all .5s ease;
|
||||
|
||||
@@ -9,7 +9,7 @@ defineProps<{
|
||||
<template>
|
||||
<ul>
|
||||
<li v-for="category in categories" :key="category.id">
|
||||
<CalendarCategoryItem :category="category" />
|
||||
<CalendarCategoryListItem :category="category" />
|
||||
</li>
|
||||
</ul>
|
||||
</template>
|
||||
|
||||
@@ -7,7 +7,9 @@ defineProps<{
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UiButton variant="secondary" size="sm" class="w-full text-left">
|
||||
{{ category }}
|
||||
</UiButton>
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="text-sm text-gray-700 dark:text-gray-300">
|
||||
{{ category.name }}
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
42
components/calendar/category/Table.vue
Normal file
42
components/calendar/category/Table.vue
Normal file
@@ -0,0 +1,42 @@
|
||||
<script setup lang="ts">
|
||||
import type { Category } from "~/models/Category";
|
||||
import { ScrollAreaRoot, ScrollAreaViewport, ScrollAreaScrollbar, ScrollAreaThumb } from "radix-vue"
|
||||
|
||||
defineProps<{
|
||||
categories: Category[]
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex flex-col h-full">
|
||||
<header class="grid grid-cols-12 gap-4 px-2 py-4 border-b-[1px] border-b-foreground/10 font-bold">
|
||||
<div class="col-span-6">
|
||||
Nom
|
||||
</div>
|
||||
<div class="col-span-4">
|
||||
Couleur
|
||||
</div>
|
||||
<div class="col-span-2" />
|
||||
</header>
|
||||
|
||||
<ScrollAreaRoot class="h-36 grow overflow-hidden ">
|
||||
<ScrollAreaViewport class="w-full h-full pr-4" as-child>
|
||||
<div class="[&:last-child]:border-0">
|
||||
<CalendarCategoryTableRow
|
||||
v-for="item in categories"
|
||||
:key="item.id"
|
||||
:category="item"
|
||||
/>
|
||||
</div>
|
||||
</ScrollAreaViewport>
|
||||
<ScrollAreaScrollbar
|
||||
class="flex select-none touch-none p-0.5 bg-background transition-colors duration-100 ease-out hover:bg-foreground/5 data-[orientation=vertical]:w-2.5 data-[orientation=horizontal]:flex-col data-[orientation=horizontal]:h-2.5"
|
||||
orientation="vertical"
|
||||
>
|
||||
<ScrollAreaThumb
|
||||
class="flex-1 bg-foreground/20 rounded-[10px] relative before:content-[''] before:absolute before:top-1/2 before:left-1/2 before:-translate-x-1/2 before:-translate-y-1/2 before:w-full before:h-full"
|
||||
/>
|
||||
</ScrollAreaScrollbar>
|
||||
</ScrollAreaRoot>
|
||||
</div>
|
||||
</template>
|
||||
137
components/calendar/category/TableRow.vue
Normal file
137
components/calendar/category/TableRow.vue
Normal file
@@ -0,0 +1,137 @@
|
||||
<script setup lang="ts">
|
||||
import { PhCheck } from "@phosphor-icons/vue";
|
||||
import { cn } from "~/lib/utils";
|
||||
import type { Category } from "~/models/Category";
|
||||
|
||||
const props = defineProps<{
|
||||
category: Category
|
||||
}>()
|
||||
|
||||
type RowMode = "edit" | "view";
|
||||
const currentMode = ref<RowMode>("view");
|
||||
|
||||
const rowRef = ref<HTMLDivElement | null>(null);
|
||||
const inputRef = ref<HTMLInputElement | null>(null);
|
||||
const { focused: inputFocused } = useFocus(inputRef);
|
||||
|
||||
/**
|
||||
* Toggle view mode options
|
||||
*/
|
||||
type ToggleViewOptions = {
|
||||
execution?: "now" | "nextTick"
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle view mode
|
||||
* @param options.execution - When to execute the toggle. "now" or "nextTick"
|
||||
*/
|
||||
function toggleView(options: ToggleViewOptions = { execution: "now" }) {
|
||||
currentMode.value = "view";
|
||||
categorySkeleton.value = structuredClone(toRaw(props.category));
|
||||
|
||||
if (options.execution === "now") {
|
||||
inputFocused.value = false;
|
||||
} else {
|
||||
nextTick(() => {
|
||||
inputFocused.value = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle edit mode
|
||||
*/
|
||||
function toggleEdit() {
|
||||
currentMode.value = "edit";
|
||||
nextTick(() => {
|
||||
inputFocused.value = true;
|
||||
});
|
||||
}
|
||||
|
||||
onClickOutside(rowRef, () => toggleView({ execution: "nextTick" }));
|
||||
onKeyStroke("Escape", () => toggleView({ execution: "now" }));
|
||||
|
||||
const categorySkeleton = ref<Category>(structuredClone(toRaw(props.category)))
|
||||
|
||||
/**
|
||||
* Submit the update
|
||||
* TODO: Implement the update logic
|
||||
*/
|
||||
function submitUpdate() {
|
||||
console.log("oui")
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
ref="rowRef"
|
||||
class="grid grid-cols-12 items-center gap-4 p-1"
|
||||
:class="cn(
|
||||
{ 'bg-slate-100 hover:bg-slate-200 dark:bg-slate-900 dark:hover:bg-slate-800': currentMode === 'edit' },
|
||||
{ 'bg-transparent hover:bg-slate-50 dark:bg-transparent dark:hover:bg-slate-900': currentMode !== 'edit' }
|
||||
)"
|
||||
>
|
||||
<div
|
||||
class="col-span-6"
|
||||
>
|
||||
<template v-if="currentMode === 'view'">
|
||||
<button
|
||||
class="py-2 px-1 h-full w-full text-left underline-offset-4 hover:underline cursor-pointer"
|
||||
@click="toggleEdit"
|
||||
>
|
||||
{{ category.name }}
|
||||
</button>
|
||||
</template>
|
||||
<template v-else-if="currentMode === 'edit'">
|
||||
<input
|
||||
ref="inputRef"
|
||||
type="text"
|
||||
:value="category.name"
|
||||
class="p-1 h-full w-full bg-transparent focus-visible:outline-none italic"
|
||||
>
|
||||
</template>
|
||||
</div>
|
||||
<div class="col-span-4">
|
||||
<template v-if="currentMode === 'view'">
|
||||
<button
|
||||
class="p-1 h-full w-full text-left text-sm cursor-pointer"
|
||||
@click="toggleEdit"
|
||||
>
|
||||
<span
|
||||
class="bgc"
|
||||
:class="cn(`bgc-${category.color}`)"
|
||||
>
|
||||
{{ $t(`ui.colors.${category.color}`) }}
|
||||
</span>
|
||||
</button>
|
||||
</template>
|
||||
<template v-else-if="currentMode === 'edit'">
|
||||
<div class="-mx-2">
|
||||
<InputColor
|
||||
id="category-color"
|
||||
v-model="categorySkeleton.color"
|
||||
position="item-aligned"
|
||||
theme="subtle"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
<div class="col-span-2">
|
||||
<menu class="w-fit ml-auto">
|
||||
<li>
|
||||
<UiButton
|
||||
v-if="currentMode === 'edit'"
|
||||
variant="secondary"
|
||||
size="icon"
|
||||
class="w-6 h-6 rounded-full bg-emerald-500 hover:bg-emerald-600 text-white"
|
||||
:to="{ name: 'calendar.category.edit', params: { id: category.id } }"
|
||||
:title="$t('ui.actions.edit')"
|
||||
@click="submitUpdate"
|
||||
>
|
||||
<PhCheck size="14" weight="bold" />
|
||||
</UiButton>
|
||||
</li>
|
||||
</menu>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -13,10 +13,9 @@ function handleClosing() {
|
||||
<template>
|
||||
<UiAlertDialog :open="isCategoriesModalOpen">
|
||||
<UiAlertDialogContent
|
||||
class="grid grid-rows-[auto_1fr_auto] items-start min-h-[66vh] max-w-4xl gap-6"
|
||||
class="grid grid-rows-[auto_1fr_auto] items-start min-h-[66vh] max-w-4xl"
|
||||
:disable-outside-pointer-events="true"
|
||||
:trap-focus="true"
|
||||
@escape-key-down="handleClosing"
|
||||
@focus-outside="handleClosing"
|
||||
@interact-outside="handleClosing"
|
||||
@close-auto-focus="(e) => e.preventDefault()"
|
||||
|
||||
@@ -3,5 +3,5 @@ const { categories } = storeToRefs(useCalendar())
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<CalendarCategoryList :categories />
|
||||
<CalendarCategoryTable :categories />
|
||||
</template>
|
||||
|
||||
@@ -2,8 +2,10 @@
|
||||
import { cn } from "@/lib/utils";
|
||||
import { type RPGColor, rpgColors } from "~/models/Color";
|
||||
|
||||
defineProps<{
|
||||
const { id, theme = "normal", position = "popper" } = defineProps<{
|
||||
id: string
|
||||
theme?: "normal" | "subtle"
|
||||
position?: "item-aligned" | "popper" | undefined
|
||||
}>();
|
||||
|
||||
const model = defineModel<RPGColor>({ default: "white" });
|
||||
@@ -11,27 +13,23 @@ const model = defineModel<RPGColor>({ default: "white" });
|
||||
|
||||
<template>
|
||||
<UiSelect v-model="model">
|
||||
<UiSelectTrigger :id>
|
||||
<UiSelectTrigger :id :class="cn({ 'h-auto': theme === 'subtle' })">
|
||||
<UiSelectValue
|
||||
:placeholder="$t('ui.colors.selectOne')"
|
||||
class="input-color"
|
||||
:class="
|
||||
cn(
|
||||
`input-color-${model}`,
|
||||
)
|
||||
"
|
||||
class="bgc"
|
||||
:class="cn(`bgc-${model}`)"
|
||||
/>
|
||||
</UiSelectTrigger>
|
||||
<UiSelectContent position="popper">
|
||||
<UiSelectContent :position>
|
||||
<UiSelectGroup>
|
||||
<UiSelectItem
|
||||
v-for="color in rpgColors"
|
||||
:key="color"
|
||||
:value="color"
|
||||
class="input-color"
|
||||
class="bgc"
|
||||
:class="
|
||||
cn(
|
||||
`input-color-${color}`,
|
||||
`bgc-${color}`,
|
||||
)
|
||||
"
|
||||
>
|
||||
@@ -41,76 +39,3 @@ const model = defineModel<RPGColor>({ default: "white" });
|
||||
</UiSelectContent>
|
||||
</UiSelect>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.input-color {
|
||||
&::before {
|
||||
content: "";
|
||||
display: inline-block;
|
||||
width: .75rem;
|
||||
aspect-ratio: 1;
|
||||
margin-right: 0.5em;
|
||||
border-radius: .25rem;
|
||||
background-color: red;
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
|
||||
&.input-color-red::before {
|
||||
@apply bg-red-500;
|
||||
}
|
||||
&.input-color-orange::before {
|
||||
@apply bg-orange-500;
|
||||
}
|
||||
&.input-color-amber::before {
|
||||
@apply bg-amber-500;
|
||||
}
|
||||
&.input-color-yellow::before {
|
||||
@apply bg-yellow-500;
|
||||
}
|
||||
&.input-color-lime::before {
|
||||
@apply bg-lime-500;
|
||||
}
|
||||
&.input-color-green::before {
|
||||
@apply bg-green-500;
|
||||
}
|
||||
&.input-color-emerald::before {
|
||||
@apply bg-emerald-600;
|
||||
}
|
||||
&.input-color-teal::before {
|
||||
@apply bg-teal-600;
|
||||
}
|
||||
&.input-color-cyan::before {
|
||||
@apply bg-cyan-600;
|
||||
}
|
||||
&.input-color-sky::before {
|
||||
@apply bg-sky-600;
|
||||
}
|
||||
&.input-color-blue::before {
|
||||
@apply bg-blue-600;
|
||||
}
|
||||
&.input-color-indigo::before {
|
||||
@apply bg-indigo-600;
|
||||
}
|
||||
&.input-color-violet::before {
|
||||
@apply bg-violet-600;
|
||||
}
|
||||
&.input-color-purple::before {
|
||||
@apply bg-purple-600;
|
||||
}
|
||||
&.input-color-fuchsia::before {
|
||||
@apply bg-fuchsia-600;
|
||||
}
|
||||
&.input-color-pink::before {
|
||||
@apply bg-pink-600;
|
||||
}
|
||||
&.input-color-rose::before {
|
||||
@apply bg-rose-600;
|
||||
}
|
||||
&.input-color-black::before {
|
||||
@apply bg-black dark:border-[1px] dark:border-slate-300;
|
||||
}
|
||||
&.input-color-white::before {
|
||||
@apply bg-white border-[1px] border-slate-700;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -20,7 +20,7 @@ const forwardedProps = useForwardProps(delegatedProps)
|
||||
v-bind="forwardedProps"
|
||||
:class="
|
||||
cn(
|
||||
'flex h-10 w-full items-center justify-between rounded-md border border-input bg-background dark:bg-slate-950 contrast-more:dark:bg-slate-900 px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1',
|
||||
'flex h-10 w-full items-center justify-between rounded-md border border-input bg-background dark:bg-slate-950 contrast-more:dark:bg-slate-900 px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50',
|
||||
props.class
|
||||
)
|
||||
"
|
||||
|
||||
16
components/ui/table/Table.vue
Normal file
16
components/ui/table/Table.vue
Normal file
@@ -0,0 +1,16 @@
|
||||
<script setup lang="ts">
|
||||
import type { HTMLAttributes } from "vue"
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const props = defineProps<{
|
||||
class?: HTMLAttributes["class"]
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="relative w-full overflow-auto">
|
||||
<table :class="cn('w-full caption-bottom text-sm', props.class)">
|
||||
<slot />
|
||||
</table>
|
||||
</div>
|
||||
</template>
|
||||
14
components/ui/table/TableBody.vue
Normal file
14
components/ui/table/TableBody.vue
Normal file
@@ -0,0 +1,14 @@
|
||||
<script setup lang="ts">
|
||||
import type { HTMLAttributes } from "vue"
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const props = defineProps<{
|
||||
class?: HTMLAttributes["class"]
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<tbody :class="cn('[&_tr:last-child]:border-0', props.class)">
|
||||
<slot />
|
||||
</tbody>
|
||||
</template>
|
||||
14
components/ui/table/TableCaption.vue
Normal file
14
components/ui/table/TableCaption.vue
Normal file
@@ -0,0 +1,14 @@
|
||||
<script setup lang="ts">
|
||||
import type { HTMLAttributes } from "vue"
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const props = defineProps<{
|
||||
class?: HTMLAttributes["class"]
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<caption :class="cn('mt-4 text-sm text-muted-foreground', props.class)">
|
||||
<slot />
|
||||
</caption>
|
||||
</template>
|
||||
21
components/ui/table/TableCell.vue
Normal file
21
components/ui/table/TableCell.vue
Normal file
@@ -0,0 +1,21 @@
|
||||
<script setup lang="ts">
|
||||
import type { HTMLAttributes } from "vue"
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const props = defineProps<{
|
||||
class?: HTMLAttributes["class"]
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<td
|
||||
:class="
|
||||
cn(
|
||||
'p-4 align-middle [&:has([role=checkbox])]:pr-0',
|
||||
props.class,
|
||||
)
|
||||
"
|
||||
>
|
||||
<slot />
|
||||
</td>
|
||||
</template>
|
||||
38
components/ui/table/TableEmpty.vue
Normal file
38
components/ui/table/TableEmpty.vue
Normal file
@@ -0,0 +1,38 @@
|
||||
<script setup lang="ts">
|
||||
import type { HTMLAttributes } from "vue"
|
||||
import { cn } from "@/lib/utils"
|
||||
import { computed } from "vue"
|
||||
import TableCell from "./TableCell.vue"
|
||||
import TableRow from "./TableRow.vue"
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
class?: HTMLAttributes["class"]
|
||||
colspan?: number
|
||||
}>(), {
|
||||
colspan: 1,
|
||||
})
|
||||
|
||||
const delegatedProps = computed(() => {
|
||||
const { class: _, ...delegated } = props
|
||||
|
||||
return delegated
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<TableRow>
|
||||
<TableCell
|
||||
:class="
|
||||
cn(
|
||||
'p-4 whitespace-nowrap align-middle text-sm text-foreground',
|
||||
props.class,
|
||||
)
|
||||
"
|
||||
v-bind="delegatedProps"
|
||||
>
|
||||
<div class="flex items-center justify-center py-10">
|
||||
<slot />
|
||||
</div>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</template>
|
||||
14
components/ui/table/TableFooter.vue
Normal file
14
components/ui/table/TableFooter.vue
Normal file
@@ -0,0 +1,14 @@
|
||||
<script setup lang="ts">
|
||||
import type { HTMLAttributes } from "vue"
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const props = defineProps<{
|
||||
class?: HTMLAttributes["class"]
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<tfoot :class="cn('border-t bg-muted/50 font-medium [&>tr]:last:border-b-0', props.class)">
|
||||
<slot />
|
||||
</tfoot>
|
||||
</template>
|
||||
14
components/ui/table/TableHead.vue
Normal file
14
components/ui/table/TableHead.vue
Normal file
@@ -0,0 +1,14 @@
|
||||
<script setup lang="ts">
|
||||
import type { HTMLAttributes } from "vue"
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const props = defineProps<{
|
||||
class?: HTMLAttributes["class"]
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<th :class="cn('h-12 px-4 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0', props.class)">
|
||||
<slot />
|
||||
</th>
|
||||
</template>
|
||||
14
components/ui/table/TableHeader.vue
Normal file
14
components/ui/table/TableHeader.vue
Normal file
@@ -0,0 +1,14 @@
|
||||
<script setup lang="ts">
|
||||
import type { HTMLAttributes } from "vue"
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const props = defineProps<{
|
||||
class?: HTMLAttributes["class"]
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<thead :class="cn('[&_tr]:border-b', props.class)">
|
||||
<slot />
|
||||
</thead>
|
||||
</template>
|
||||
14
components/ui/table/TableRow.vue
Normal file
14
components/ui/table/TableRow.vue
Normal file
@@ -0,0 +1,14 @@
|
||||
<script setup lang="ts">
|
||||
import type { HTMLAttributes } from "vue"
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const props = defineProps<{
|
||||
class?: HTMLAttributes["class"]
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<tr :class="cn('border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted', props.class)">
|
||||
<slot />
|
||||
</tr>
|
||||
</template>
|
||||
9
components/ui/table/index.ts
Normal file
9
components/ui/table/index.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
export { default as Table } from './Table.vue'
|
||||
export { default as TableBody } from './TableBody.vue'
|
||||
export { default as TableCaption } from './TableCaption.vue'
|
||||
export { default as TableCell } from './TableCell.vue'
|
||||
export { default as TableEmpty } from './TableEmpty.vue'
|
||||
export { default as TableFooter } from './TableFooter.vue'
|
||||
export { default as TableHead } from './TableHead.vue'
|
||||
export { default as TableHeader } from './TableHeader.vue'
|
||||
export { default as TableRow } from './TableRow.vue'
|
||||
Reference in New Issue
Block a user