mirror of
https://github.com/ArthurDanjou/arthome.git
synced 2026-01-27 18:00:26 +01:00
Working on arthome
This commit is contained in:
123
app/components/App/Header.vue
Normal file
123
app/components/App/Header.vue
Normal file
@@ -0,0 +1,123 @@
|
||||
<script setup lang="ts">
|
||||
const colorMode = useColorMode()
|
||||
const { user, loggedIn, clear } = useUserSession()
|
||||
|
||||
const isSettingsOpen = ref(false)
|
||||
|
||||
const items = [
|
||||
[{
|
||||
slot: 'account',
|
||||
disabled: true,
|
||||
}],
|
||||
[{
|
||||
label: 'Home',
|
||||
icon: 'i-ph:house-line-duotone',
|
||||
action: () => navigateTo('/'),
|
||||
}, {
|
||||
label: 'Settings',
|
||||
icon: 'i-ph:gear-six-duotone',
|
||||
action: () => {
|
||||
console.log('Settings')
|
||||
isSettingsOpen.value = true
|
||||
},
|
||||
}, {
|
||||
label: 'Profile',
|
||||
icon: 'i-ph:person-arms-spread-duotone',
|
||||
action: () => navigateTo('/profile'),
|
||||
}],
|
||||
[{
|
||||
slot: 'logout',
|
||||
label: 'Sign out',
|
||||
icon: 'i-ph:sign-out-bold',
|
||||
}],
|
||||
]
|
||||
|
||||
function toggleColorMode() {
|
||||
colorMode.preference = colorMode.preference === 'dark' ? 'light' : 'dark'
|
||||
}
|
||||
|
||||
async function logout() {
|
||||
await clear()
|
||||
navigateTo('/login')
|
||||
window.location.reload()
|
||||
}
|
||||
|
||||
defineShortcuts({
|
||||
t: () => toggleColorMode(),
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<header
|
||||
class="fixed top-0 w-full py-4 z-50 bg-white/30 dark:bg-zinc-900/30 duration-300 backdrop-blur"
|
||||
>
|
||||
<UContainer>
|
||||
<div class="flex justify-between w-full items-center">
|
||||
<h1 class="tracking-wide text-lg font-bold text-black dark:text-white">
|
||||
ArtHome
|
||||
</h1>
|
||||
<div class="flex items-center gap-2">
|
||||
<ClientOnly>
|
||||
<UDropdown v-if="loggedIn" :items="items" mode="hover" :ui="{ item: { disabled: 'cursor-text select-text' } }" :popper="{ placement: 'bottom-start' }">
|
||||
<UAvatar :src="user.avatar" />
|
||||
|
||||
<template #account>
|
||||
<div class="text-left">
|
||||
<p>
|
||||
Signed in as
|
||||
</p>
|
||||
<p class="truncate font-medium text-gray-900 dark:text-white">
|
||||
{{ user.name }}
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #item="{ item }">
|
||||
<div class="w-full flex justify-between items-center" @click.prevent="item.action()">
|
||||
<span class="truncate">{{ item.label }}</span>
|
||||
<UIcon :name="item.icon" class="flex-shrink-0 h-4 w-4 text-gray-400 dark:text-gray-500 ms-auto" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #logout="{ item }">
|
||||
<div class="w-full flex justify-between items-center" @click="logout()">
|
||||
<span class="truncate">{{ item.label }}</span>
|
||||
<UIcon :name="item.icon" class="flex-shrink-0 h-4 w-4 text-gray-400 dark:text-gray-500 ms-auto" />
|
||||
</div>
|
||||
</template>
|
||||
</UDropdown>
|
||||
<UButton
|
||||
:icon="$colorMode.preference === 'dark' ? 'i-ph:moon-duotone' : 'i-ph:sun-duotone'"
|
||||
color="gray"
|
||||
square
|
||||
size="md"
|
||||
variant="ghost"
|
||||
@click="toggleColorMode"
|
||||
/>
|
||||
</clientonly>
|
||||
</div>
|
||||
</div>
|
||||
</UContainer>
|
||||
</header>
|
||||
<USlideover v-model="isSettingsOpen">
|
||||
<UCard class="flex flex-col flex-1" :ui="{ body: { base: 'flex-1' }, ring: '', divide: 'divide-y divide-gray-100 dark:divide-gray-800' }">
|
||||
<template #header>
|
||||
<div class="flex items-center justify-between">
|
||||
<h3 class="text-base font-semibold leading-6 text-gray-900 dark:text-white">
|
||||
Settings
|
||||
</h3>
|
||||
<UButton color="gray" variant="ghost" icon="i-heroicons-x-mark-20-solid" class="-my-1" @click="isSettingsOpen = false" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #default>
|
||||
Hey
|
||||
Delete account
|
||||
Change user details
|
||||
{{ user }}
|
||||
</template>
|
||||
</UCard>
|
||||
</USlideover>
|
||||
</div>
|
||||
</template>
|
||||
109
app/components/App/Tab.vue
Normal file
109
app/components/App/Tab.vue
Normal file
@@ -0,0 +1,109 @@
|
||||
<script setup lang="ts">
|
||||
import type { TabType } from '~~/types/types'
|
||||
|
||||
defineProps<{
|
||||
tab: TabType
|
||||
}>()
|
||||
|
||||
// DropDown Items
|
||||
const items = [[
|
||||
{
|
||||
label: 'Edit',
|
||||
icon: 'i-ph:pencil-duotone',
|
||||
color: 'green',
|
||||
click: tab => openUpdateTabModal(tab),
|
||||
},
|
||||
{
|
||||
label: 'Delete',
|
||||
icon: 'i-ph:trash-duotone',
|
||||
color: 'red',
|
||||
click: tab => openDeleteTabModal(tab),
|
||||
},
|
||||
]]
|
||||
|
||||
// Modals
|
||||
const updateTabModal = ref(false)
|
||||
const deleteTabModal = ref(false)
|
||||
|
||||
// Update Category
|
||||
const currentUpdateTab = ref<TabType | null>(null)
|
||||
function openUpdateTabModal(tab: TabType) {
|
||||
currentUpdateTab.value = tab
|
||||
updateTabModal.value = true
|
||||
}
|
||||
|
||||
// Delete Category
|
||||
const currentDeleteTab = ref<TabType | null>(null)
|
||||
function openDeleteTabModal(tab: TabType) {
|
||||
currentDeleteTab.value = tab
|
||||
deleteTabModal.value = true
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ULink
|
||||
:to="tab.link"
|
||||
class="relative"
|
||||
target="_blank"
|
||||
>
|
||||
<div v-show="tab.primary" class="absolute flex h-3 w-3 -left-1 -top-1">
|
||||
<span class="animate-ping absolute inline-flex h-full w-full rounded-full opacity-75" :class="`bg-${tab.color}-400`" />
|
||||
<span class="relative inline-flex rounded-full h-3 w-3" :class="`bg-${tab.color}-400`" />
|
||||
</div>
|
||||
<UCard
|
||||
:ui="{ body: { base: 'h-full' }, background: 'h-full duration-300 bg-white hover:bg-gray-100 dark:bg-gray-900 dark:hover:bg-gray-800' }"
|
||||
>
|
||||
<div class="flex items-center justify-between h-full">
|
||||
<div class="flex gap-4 items-center h-full">
|
||||
<UBadge :color="tab.color" class="p-2" variant="soft">
|
||||
<UIcon :name="`i-ph:${tab.icon}`" size="32" />
|
||||
</UBadge>
|
||||
<div class="flex flex-col gap-1">
|
||||
<div :class="`text-${tab.color}-400`" class="text-xl font-medium">
|
||||
<p>{{ tab.name }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<UDropdown
|
||||
:items="items"
|
||||
:popper="{ placement: 'bottom-end', arrow: true }"
|
||||
:ui="{ container: 'z-50 group', width: 'w-40', shadow: 'shadow-2xl' }"
|
||||
>
|
||||
<UButton
|
||||
color="gray"
|
||||
variant="soft"
|
||||
icon="i-ph:dots-three-outline-vertical-duotone"
|
||||
/>
|
||||
|
||||
<template #item="{ item }">
|
||||
<div class="w-full flex items-center justify-between" @click.prevent="item.click(tab)">
|
||||
<span
|
||||
class="truncate"
|
||||
:class="`text-${item.color}-500`"
|
||||
>
|
||||
{{ item.label }}
|
||||
</span>
|
||||
<UIcon
|
||||
:name="item.icon"
|
||||
class="flex-shrink-0 h-4 w-4 ms-auto"
|
||||
:class="`text-${item.color}-500`"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</UDropdown>
|
||||
</div>
|
||||
</UCard>
|
||||
<ModalUpdateTab
|
||||
v-if="currentUpdateTab"
|
||||
v-model="updateTabModal"
|
||||
:tab="currentUpdateTab"
|
||||
@close-modal="updateTabModal = false"
|
||||
/>
|
||||
<ModalDeleteTab
|
||||
v-if="currentDeleteTab"
|
||||
v-model="deleteTabModal"
|
||||
:tab="currentDeleteTab"
|
||||
@close-modal="deleteTabModal = false"
|
||||
/>
|
||||
</ULink>
|
||||
</template>
|
||||
@@ -1,13 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
56
app/components/CategoryHeader.vue
Normal file
56
app/components/CategoryHeader.vue
Normal file
@@ -0,0 +1,56 @@
|
||||
<script setup lang="ts">
|
||||
import type { CategoryType } from '~~/types/types'
|
||||
|
||||
defineProps<{
|
||||
category: CategoryType
|
||||
dropdownItems: { label: string, icon: string, color: string, click: (category: CategoryType) => void }[]
|
||||
}>()
|
||||
defineEmits(['createTab'])
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-if="category" class="flex items-center mb-4" :class="category.nameVisible ? 'justify-between' : 'justify-end'">
|
||||
<div v-if="category.nameVisible" class="flex items-center gap-2 mb-4" :class="`text-${category.color}-500`">
|
||||
<UIcon :name="`i-ph:${category.icon}`" size="28" />
|
||||
<h1 class="font-bold text-2xl">
|
||||
{{ category.name }}
|
||||
</h1>
|
||||
</div>
|
||||
<div class="flex gap-4">
|
||||
<UButton
|
||||
color="gray"
|
||||
variant="solid"
|
||||
label="New tab"
|
||||
icon="i-ph:plus-circle-duotone"
|
||||
@click.prevent="$emit('createTab')"
|
||||
/>
|
||||
<UDropdown
|
||||
:items="dropdownItems"
|
||||
:popper="{ placement: 'bottom-end', arrow: true }"
|
||||
:ui="{ width: 'w-40', shadow: 'shadow-xl' }"
|
||||
>
|
||||
<UButton
|
||||
color="white"
|
||||
variant="solid"
|
||||
icon="i-ph:dots-three-outline-vertical-duotone"
|
||||
/>
|
||||
|
||||
<template #item="{ item }">
|
||||
<div class="w-full flex items-center justify-between" @click.prevent="item.click(category)">
|
||||
<span
|
||||
class="truncate"
|
||||
:class="`text-${item.color}-500`"
|
||||
>
|
||||
{{ item.label }}
|
||||
</span>
|
||||
<UIcon
|
||||
:name="item.icon"
|
||||
class="flex-shrink-0 h-4 w-4 ms-auto"
|
||||
:class="`text-${item.color}-500`"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</UDropdown>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
70
app/components/Modal/CreateCategory.vue
Normal file
70
app/components/Modal/CreateCategory.vue
Normal file
@@ -0,0 +1,70 @@
|
||||
<script setup lang="ts">
|
||||
import type { FormSubmitEvent } from '#ui/types'
|
||||
import type { CreateCategorySchemaType } from '~~/types/types'
|
||||
import { COLORS, CreateCategorySchema } from '~~/types/types'
|
||||
|
||||
const emit = defineEmits(['closeModal'])
|
||||
const { createCategory } = await useCategories()
|
||||
const state = reactive({
|
||||
name: undefined,
|
||||
icon: undefined,
|
||||
color: COLORS[0],
|
||||
nameVisible: true,
|
||||
})
|
||||
|
||||
async function handleCreate(event: FormSubmitEvent<CreateCategorySchemaType>) {
|
||||
await createCategory(event.data)
|
||||
emit('closeModal')
|
||||
state.color = COLORS[0]
|
||||
state.nameVisible = true
|
||||
state.icon = undefined
|
||||
state.name = undefined
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UModal :ui="{ width: 'w-full sm:max-w-md' }">
|
||||
<UCard>
|
||||
<template #header>
|
||||
<div class="flex items-center justify-between">
|
||||
<h3 class="text-base font-semibold leading-6 text-gray-900 dark:text-white">
|
||||
Create a new category
|
||||
</h3>
|
||||
<UButton
|
||||
color="gray"
|
||||
variant="soft"
|
||||
icon="i-heroicons-x-mark-20-solid"
|
||||
class="p-1"
|
||||
@click="$emit('closeModal')"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<template #default>
|
||||
<UForm :schema="CreateCategorySchema" :state="state" class="space-y-4" @submit="handleCreate">
|
||||
<UFormGroup label="Name" name="name">
|
||||
<UInput v-model="state.name" type="text" variant="outline" />
|
||||
</UFormGroup>
|
||||
|
||||
<UFormGroup label="Icon " name="icon" help="Get icon from the Phosphor Collection">
|
||||
<UInput v-model="state.icon" type="text" variant="outline" />
|
||||
</UFormGroup>
|
||||
|
||||
<UFormGroup label="Color " name="color">
|
||||
<USelect v-model="state.color" :options="COLORS" variant="outline" />
|
||||
</UFormGroup>
|
||||
|
||||
<UFormGroup>
|
||||
<UCheckbox v-model="state.nameVisible" :color="state.color" label="Is the category name visible?" />
|
||||
</UFormGroup>
|
||||
|
||||
<UButton
|
||||
type="submit"
|
||||
:color="state.color"
|
||||
block
|
||||
label="Create category"
|
||||
/>
|
||||
</UForm>
|
||||
</template>
|
||||
</UCard>
|
||||
</UModal>
|
||||
</template>
|
||||
91
app/components/Modal/CreateTab.vue
Normal file
91
app/components/Modal/CreateTab.vue
Normal file
@@ -0,0 +1,91 @@
|
||||
<script setup lang="ts">
|
||||
import type { FormSubmitEvent } from '#ui/types'
|
||||
import { COLORS, type CategoryType, CreateTabSchema, type CreateTabSchemaType } from '~~/types/types'
|
||||
|
||||
const props = defineProps<{
|
||||
category: CategoryType | undefined
|
||||
}>()
|
||||
|
||||
const emit = defineEmits(['closeModal'])
|
||||
const { createTab } = await useTabs()
|
||||
const { categories } = await useCategories()
|
||||
|
||||
const state = reactive({
|
||||
name: undefined,
|
||||
icon: undefined,
|
||||
link: undefined,
|
||||
color: COLORS[0],
|
||||
primary: false,
|
||||
categoryId: props.category?.id,
|
||||
})
|
||||
|
||||
watchEffect(() => {
|
||||
state.categoryId = props.category?.id
|
||||
})
|
||||
|
||||
async function handleCreate(event: FormSubmitEvent<CreateTabSchemaType>) {
|
||||
await createTab(event.data)
|
||||
emit('closeModal')
|
||||
state.name = undefined
|
||||
state.icon = undefined
|
||||
state.link = undefined
|
||||
state.color = COLORS[0]
|
||||
state.primary = false
|
||||
state.categoryId = props.category?.id
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UModal :ui="{ width: 'w-full sm:max-w-md' }">
|
||||
<UCard>
|
||||
<template #header>
|
||||
<div class="flex items-center justify-between">
|
||||
<h3 class="text-base font-semibold leading-6 text-gray-900 dark:text-white">
|
||||
Create a new tab
|
||||
</h3>
|
||||
<UButton
|
||||
color="gray"
|
||||
variant="soft"
|
||||
icon="i-heroicons-x-mark-20-solid"
|
||||
class="p-1"
|
||||
@click="$emit('closeModal')"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<template #default>
|
||||
<UForm :schema="CreateTabSchema" :state="state" class="space-y-4" @submit="handleCreate">
|
||||
<UFormGroup label="Name" name="name">
|
||||
<UInput v-model="state.name" type="text" />
|
||||
</UFormGroup>
|
||||
|
||||
<UFormGroup label="Icon " name="icon">
|
||||
<UInput v-model="state.icon" type="text" />
|
||||
</UFormGroup>
|
||||
|
||||
<UFormGroup label="Color " name="color">
|
||||
<USelect v-model="state.color" :options="COLORS" />
|
||||
</UFormGroup>
|
||||
|
||||
<UFormGroup label="Category " name="category">
|
||||
<USelect v-model="state.categoryId" :options="categories" option-attribute="name" value-attribute="id" />
|
||||
</UFormGroup>
|
||||
|
||||
<UFormGroup label="Link " name="link">
|
||||
<UInput v-model="state.link" type="text" />
|
||||
</UFormGroup>
|
||||
|
||||
<UFormGroup>
|
||||
<UCheckbox v-model="state.primary" :color="state.color" label="Is the tab primary?" />
|
||||
</UFormGroup>
|
||||
|
||||
<UButton
|
||||
type="submit"
|
||||
:color="state.color"
|
||||
block
|
||||
label="Create tab"
|
||||
/>
|
||||
</UForm>
|
||||
</template>
|
||||
</UCard>
|
||||
</UModal>
|
||||
</template>
|
||||
58
app/components/Modal/DeleteCategory.vue
Normal file
58
app/components/Modal/DeleteCategory.vue
Normal file
@@ -0,0 +1,58 @@
|
||||
<script setup lang="ts">
|
||||
import type { CategoryType } from '~~/types/types'
|
||||
|
||||
const props = defineProps<{
|
||||
category: CategoryType | null
|
||||
}>()
|
||||
|
||||
const emit = defineEmits(['closeModal'])
|
||||
const { deleteCategory } = await useCategories()
|
||||
|
||||
async function handleDelete() {
|
||||
await deleteCategory(props.category.id)
|
||||
emit('closeModal')
|
||||
}
|
||||
|
||||
defineShortcuts({
|
||||
enter: async () => await handleDelete(),
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UModal :ui="{ width: 'w-full sm:max-w-md' }">
|
||||
<UCard>
|
||||
<template #header>
|
||||
<div class="flex items-center justify-between">
|
||||
<h3 class="text-base font-semibold leading-6 text-gray-900 dark:text-white">
|
||||
Confirm deletion of '{{ category.name }}'
|
||||
</h3>
|
||||
<UButton
|
||||
color="gray"
|
||||
variant="soft"
|
||||
icon="i-heroicons-x-mark-20-solid"
|
||||
class="p-1"
|
||||
@click="$emit('closeModal')"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<template #default>
|
||||
<div class="space-y-4">
|
||||
<UButton
|
||||
color="red"
|
||||
variant="solid"
|
||||
label="Delete"
|
||||
block
|
||||
@click.prevent="handleDelete"
|
||||
/>
|
||||
<UButton
|
||||
color="gray"
|
||||
variant="solid"
|
||||
label="Cancel"
|
||||
block
|
||||
@click.prevent="$emit('closeModal')"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</UCard>
|
||||
</UModal>
|
||||
</template>
|
||||
58
app/components/Modal/DeleteTab.vue
Normal file
58
app/components/Modal/DeleteTab.vue
Normal file
@@ -0,0 +1,58 @@
|
||||
<script setup lang="ts">
|
||||
import type { TabType } from '~~/types/types'
|
||||
|
||||
const props = defineProps<{
|
||||
tab: TabType | null
|
||||
}>()
|
||||
|
||||
const emit = defineEmits(['closeModal'])
|
||||
const { deleteTab } = await useTabs()
|
||||
|
||||
async function handleDelete() {
|
||||
await deleteTab(props.tab.id)
|
||||
emit('closeModal')
|
||||
}
|
||||
|
||||
defineShortcuts({
|
||||
enter: async () => await handleDelete(),
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UModal :ui="{ width: 'w-full sm:max-w-md' }">
|
||||
<UCard>
|
||||
<template #header>
|
||||
<div class="flex items-center justify-between">
|
||||
<h3 class="text-base font-semibold leading-6 text-gray-900 dark:text-white">
|
||||
Confirm deletion of '{{ tab.name }}'
|
||||
</h3>
|
||||
<UButton
|
||||
color="gray"
|
||||
variant="soft"
|
||||
icon="i-heroicons-x-mark-20-solid"
|
||||
class="p-1"
|
||||
@click="$emit('closeModal')"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<template #default>
|
||||
<div class="space-y-4">
|
||||
<UButton
|
||||
color="red"
|
||||
variant="solid"
|
||||
label="Delete"
|
||||
block
|
||||
@click.prevent="handleDelete"
|
||||
/>
|
||||
<UButton
|
||||
color="gray"
|
||||
variant="solid"
|
||||
label="Cancel"
|
||||
block
|
||||
@click.prevent="$emit('closeModal')"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</UCard>
|
||||
</UModal>
|
||||
</template>
|
||||
80
app/components/Modal/UpdateCategory.vue
Normal file
80
app/components/Modal/UpdateCategory.vue
Normal file
@@ -0,0 +1,80 @@
|
||||
<script setup lang="ts">
|
||||
import { COLORS, type CategoryType, UpdateCategorySchema } from '~~/types/types'
|
||||
import type { FormSubmitEvent } from '#ui/types'
|
||||
|
||||
const props = defineProps<{
|
||||
category: CategoryType | null
|
||||
}>()
|
||||
|
||||
const emit = defineEmits(['closeModal'])
|
||||
const { updateCategory } = await useCategories()
|
||||
|
||||
const state = reactive({
|
||||
name: props.category?.name,
|
||||
icon: props.category?.icon,
|
||||
color: props.category?.color,
|
||||
nameVisible: props.category?.nameVisible,
|
||||
})
|
||||
|
||||
watchEffect(() => {
|
||||
state.name = props.category?.name
|
||||
state.icon = props.category?.icon
|
||||
state.color = props.category?.color
|
||||
state.nameVisible = props.category?.nameVisible
|
||||
})
|
||||
|
||||
async function handleUpdate(event: FormSubmitEvent<UpdateCategorySchema>) {
|
||||
await updateCategory({
|
||||
id: props.category!.id,
|
||||
...event.data,
|
||||
})
|
||||
emit('closeModal')
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UModal :ui="{ width: 'w-full sm:max-w-md' }">
|
||||
<UCard>
|
||||
<template #header>
|
||||
<div class="flex items-center justify-between">
|
||||
<h3 class="text-base font-semibold leading-6 text-gray-900 dark:text-white">
|
||||
Update category '{{ category.name }}'
|
||||
</h3>
|
||||
<UButton
|
||||
color="gray"
|
||||
variant="soft"
|
||||
icon="i-heroicons-x-mark-20-solid"
|
||||
class="p-1"
|
||||
@click="$emit('closeModal')"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<template #default>
|
||||
<UForm :schema="UpdateCategorySchema" :state="state" class="space-y-4" @submit="handleUpdate">
|
||||
<UFormGroup label="Name" name="name">
|
||||
<UInput v-model="state.name" type="text" />
|
||||
</UFormGroup>
|
||||
|
||||
<UFormGroup label="Color " name="color">
|
||||
<USelect v-model="state.color" :options="COLORS" />
|
||||
</UFormGroup>
|
||||
|
||||
<UFormGroup label="Icon " name="icon">
|
||||
<UInput v-model="state.icon" type="text" />
|
||||
</UFormGroup>
|
||||
|
||||
<UFormGroup>
|
||||
<UCheckbox v-model="state.nameVisible" :color="state.color" label="Is the category name visible?" />
|
||||
</UFormGroup>
|
||||
|
||||
<UButton
|
||||
type="submit"
|
||||
:color="state.color"
|
||||
block
|
||||
label="Update category"
|
||||
/>
|
||||
</UForm>
|
||||
</template>
|
||||
</UCard>
|
||||
</UModal>
|
||||
</template>
|
||||
89
app/components/Modal/UpdateTab.vue
Normal file
89
app/components/Modal/UpdateTab.vue
Normal file
@@ -0,0 +1,89 @@
|
||||
<script setup lang="ts">
|
||||
import type { FormSubmitEvent } from '#ui/types'
|
||||
import type { COLORS, TabType, UpdateTabSchemaType } from '~~/types/types'
|
||||
import { UpdateTabSchema } from '~~/types/types'
|
||||
|
||||
const props = defineProps<{
|
||||
tab: TabType | null
|
||||
}>()
|
||||
|
||||
const emit = defineEmits(['closeModal'])
|
||||
const { categories } = await useCategories()
|
||||
const { updateTab } = await useTabs()
|
||||
|
||||
const state = reactive({
|
||||
name: props.tab?.name,
|
||||
icon: props.tab?.icon,
|
||||
color: props.tab?.color,
|
||||
primary: props.tab?.primary,
|
||||
categoryId: props.tab?.categoryId,
|
||||
})
|
||||
|
||||
watchEffect(() => {
|
||||
state.name = props.tab?.name
|
||||
state.icon = props.tab?.icon
|
||||
state.color = props.tab?.color
|
||||
state.primary = props.tab?.primary
|
||||
state.categoryId = props.tab?.categoryId
|
||||
})
|
||||
|
||||
async function handleUpdate(event: FormSubmitEvent<UpdateTabSchemaType>) {
|
||||
await updateTab({
|
||||
id: props.tab!.id,
|
||||
...event.data,
|
||||
categoryId: Number(event.data.categoryId),
|
||||
})
|
||||
emit('closeModal')
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UModal :ui="{ width: 'w-full sm:max-w-md' }">
|
||||
<UCard>
|
||||
<template #header>
|
||||
<div class="flex items-center justify-between">
|
||||
<h3 class="text-base font-semibold leading-6 text-gray-900 dark:text-white">
|
||||
Update category '{{ tab.name }}'
|
||||
</h3>
|
||||
<UButton
|
||||
color="gray"
|
||||
variant="soft"
|
||||
icon="i-heroicons-x-mark-20-solid"
|
||||
class="p-1"
|
||||
@click="$emit('closeModal')"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<template #default>
|
||||
<UForm :schema="UpdateTabSchema" :state="state" class="space-y-4" @submit="handleUpdate">
|
||||
<UFormGroup label="Name" name="name">
|
||||
<UInput v-model="state.name" type="text" />
|
||||
</UFormGroup>
|
||||
|
||||
<UFormGroup label="Color " name="color">
|
||||
<USelect v-model="state.color" :options="COLORS" />
|
||||
</UFormGroup>
|
||||
|
||||
<UFormGroup label="Icon " name="icon">
|
||||
<UInput v-model="state.icon" type="text" />
|
||||
</UFormGroup>
|
||||
|
||||
<UFormGroup label="Category " name="category">
|
||||
<USelect v-model="state.categoryId" :options="categories" option-attribute="name" value-attribute="id" />
|
||||
</UFormGroup>
|
||||
|
||||
<UFormGroup>
|
||||
<UCheckbox v-model="state.primary" :color="state.color" label="Is the category primary?" />
|
||||
</UFormGroup>
|
||||
|
||||
<UButton
|
||||
type="submit"
|
||||
:color="state.color"
|
||||
block
|
||||
label="Update tab"
|
||||
/>
|
||||
</UForm>
|
||||
</template>
|
||||
</UCard>
|
||||
</UModal>
|
||||
</template>
|
||||
@@ -1,18 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import type { Tab } from '~~/server/utils/db'
|
||||
|
||||
defineProps<{
|
||||
tab: PropType<Tab>
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
Tab
|
||||
{{ tab }}
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
Reference in New Issue
Block a user