mirror of
https://github.com/sysadminsmedia/homebox.git
synced 2025-12-21 21:33:02 +01:00
feat: add eslint-plugin-tailwindcss (#199)
This commit is contained in:
@@ -11,6 +11,7 @@ module.exports = {
|
||||
"@nuxtjs/eslint-config-typescript",
|
||||
"plugin:vue/vue3-recommended",
|
||||
"plugin:prettier/recommended",
|
||||
"plugin:tailwindcss/recommended",
|
||||
],
|
||||
parserOptions: {
|
||||
ecmaVersion: "latest",
|
||||
|
||||
@@ -68,23 +68,23 @@
|
||||
<LabelCreateModal v-model="modals.label" />
|
||||
<LocationCreateModal v-model="modals.location" />
|
||||
|
||||
<div class="bg-neutral absolute shadow-xl top-0 h-[20rem] max-h-96 -z-10 w-full"></div>
|
||||
<div class="absolute top-0 -z-10 h-80 max-h-96 w-full bg-neutral shadow-xl"></div>
|
||||
|
||||
<BaseContainer cmp="header" class="py-6 max-w-none">
|
||||
<BaseContainer cmp="header" class="max-w-none py-6">
|
||||
<BaseContainer>
|
||||
<NuxtLink to="/home">
|
||||
<h2 class="mt-1 text-4xl font-bold tracking-tight text-neutral-content sm:text-5xl lg:text-6xl flex">
|
||||
<h2 class="mt-1 flex text-4xl font-bold tracking-tight text-neutral-content sm:text-5xl lg:text-6xl">
|
||||
HomeB
|
||||
<AppLogo class="w-12 -mb-4" />
|
||||
<AppLogo class="-mb-4 w-12" />
|
||||
x
|
||||
</h2>
|
||||
</NuxtLink>
|
||||
<div class="ml-1 mt-2 text-lg text-neutral-content/75 space-x-2">
|
||||
<div class="ml-1 mt-2 space-x-2 text-lg text-neutral-content/75">
|
||||
<template v-for="link in links">
|
||||
<NuxtLink
|
||||
v-if="!link.action"
|
||||
:key="link.name"
|
||||
class="hover:text-base-content transition-color duration-200 italic"
|
||||
class="italic transition-colors duration-200 hover:text-base-content"
|
||||
:to="link.href"
|
||||
>
|
||||
{{ link.name }}
|
||||
@@ -93,7 +93,7 @@
|
||||
v-else
|
||||
:key="link.name + 'link'"
|
||||
for="location-form-modal"
|
||||
class="hover:text-base-content transition-color duration-200 italic"
|
||||
class="italic transition-colors duration-200 hover:text-base-content"
|
||||
@click="link.action"
|
||||
>
|
||||
{{ link.name }}
|
||||
@@ -101,15 +101,15 @@
|
||||
<span v-if="!link.last" :key="link.name"> / </span>
|
||||
</template>
|
||||
</div>
|
||||
<div class="flex mt-6">
|
||||
<div class="mt-6 flex">
|
||||
<div class="dropdown">
|
||||
<label tabindex="0" class="btn btn-primary btn-sm">
|
||||
<span>
|
||||
<MdiPlus class="mr-1 -ml-1" />
|
||||
<MdiPlus class="-ml-1 mr-1" />
|
||||
</span>
|
||||
Create
|
||||
</label>
|
||||
<ul tabindex="0" class="dropdown-content menu p-2 shadow bg-base-100 rounded-box w-52">
|
||||
<ul tabindex="0" class="dropdown-content menu rounded-box w-52 bg-base-100 p-2 shadow">
|
||||
<li v-for="btn in dropdown" :key="btn.name">
|
||||
<button @click="btn.action">
|
||||
{{ btn.name }}
|
||||
|
||||
@@ -4,11 +4,11 @@
|
||||
<p>
|
||||
{{ $t("components.app.import_dialog.description") }}
|
||||
</p>
|
||||
<div class="alert alert-warning shadow-lg mt-4">
|
||||
<div class="alert alert-warning mt-4 shadow-lg">
|
||||
<div>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="stroke-current flex-shrink-0 h-6 w-6 mb-auto"
|
||||
class="mb-auto size-6 shrink-0 stroke-current"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
@@ -30,10 +30,10 @@
|
||||
<input ref="importRef" type="file" class="hidden" accept=".csv,.tsv" @change="setFile" />
|
||||
|
||||
<BaseButton type="button" @click="uploadCsv">
|
||||
<MdiUpload class="h-5 w-5 mr-2" />
|
||||
<MdiUpload class="mr-2 size-5" />
|
||||
{{ $t("components.app.import_dialog.upload") }}
|
||||
</BaseButton>
|
||||
<p class="text-center pt-4 -mb-5">
|
||||
<p class="-mb-5 pt-4 text-center">
|
||||
{{ importCsv?.name }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="force-above fixed top-2 right-2 w-[300px]">
|
||||
<div class="fixed right-2 top-2 z-[9999] w-[300px]">
|
||||
<TransitionGroup name="notify" tag="div">
|
||||
<div
|
||||
v-for="(notify, index) in notifications.slice(0, 4)"
|
||||
@@ -14,14 +14,14 @@
|
||||
>
|
||||
<div class="flex gap-1">
|
||||
<template v-if="notify.type == 'success'">
|
||||
<MdiCheckboxMarkedCircle class="h-5 w-5" />
|
||||
<MdiCheckboxMarkedCircle class="size-5" />
|
||||
</template>
|
||||
<template v-if="notify.type == 'info'">
|
||||
<MdiInformationSlabCircle class="h-5 w-5" />
|
||||
<MdiInformationSlabCircle class="size-5" />
|
||||
</template>
|
||||
|
||||
<template v-if="notify.type == 'error'">
|
||||
<MdiAlert class="h-5 w-5" />
|
||||
<MdiAlert class="size-5" />
|
||||
</template>
|
||||
{{ notify.message }}
|
||||
</div>
|
||||
@@ -41,10 +41,6 @@
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.force-above {
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
.notify-move,
|
||||
.notify-enter-active,
|
||||
.notify-leave-active {
|
||||
|
||||
@@ -2,12 +2,12 @@
|
||||
<div class="card bg-base-100 shadow-xl sm:rounded-lg">
|
||||
<div v-if="$slots.title" class="px-4 py-5 sm:px-6">
|
||||
<component :is="collapsable ? 'button' : 'div'" v-on="collapsable ? { click: toggle } : {}">
|
||||
<h3 class="text-lg font-medium leading-6 flex items-center">
|
||||
<h3 class="flex items-center text-lg font-medium leading-6">
|
||||
<slot name="title"></slot>
|
||||
<template v-if="collapsable">
|
||||
<span class="ml-2 swap swap-rotate" :class="`${collapsed ? 'swap-active' : ''}`">
|
||||
<MdiChevronRight class="h-6 w-6 swap-on" />
|
||||
<MdiChevronDown class="h-6 w-6 swap-off" />
|
||||
<span class="swap swap-rotate ml-2" :class="`${collapsed ? 'swap-active' : ''}`">
|
||||
<MdiChevronRight class="swap-on size-6" />
|
||||
<MdiChevronDown class="swap-off size-6" />
|
||||
</span>
|
||||
</template>
|
||||
</h3>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<component :is="cmp" class="container max-w-6xl mx-auto px-3">
|
||||
<component :is="cmp" class="container mx-auto max-w-6xl px-3">
|
||||
<slot />
|
||||
</component>
|
||||
</template>
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<template>
|
||||
<div class="z-[999]">
|
||||
<input :id="modalId" v-model="modal" type="checkbox" class="modal-toggle" />
|
||||
<div class="modal modal-bottom sm:modal-middle overflow-visible">
|
||||
<div class="modal-box overflow-visible relative">
|
||||
<button :for="modalId" class="btn btn-sm btn-circle absolute right-2 top-2" @click="close">✕</button>
|
||||
<div class="modal modal-bottom overflow-visible sm:modal-middle">
|
||||
<div class="modal-box relative overflow-visible">
|
||||
<button :for="modalId" class="btn btn-circle btn-sm absolute right-2 top-2" @click="close">✕</button>
|
||||
|
||||
<h3 class="font-bold text-lg">
|
||||
<h3 class="text-lg font-bold">
|
||||
<slot name="title"></slot>
|
||||
</h3>
|
||||
<slot> </slot>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="pb-3">
|
||||
<h3
|
||||
class="text-3xl font-bold tracking-tight flex items-center"
|
||||
class="flex items-center text-3xl font-bold tracking-tight"
|
||||
:class="{
|
||||
'text-neutral-content': dark,
|
||||
'text-content': !dark,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="grid grid-cols-1 md:grid-cols-4 gap-10 py-6">
|
||||
<div class="grid grid-cols-1 gap-10 py-6 md:grid-cols-4">
|
||||
<div class="col-span-3">
|
||||
<h4 class="mb-1 text-lg font-semibold">
|
||||
<slot name="title"></slot>
|
||||
|
||||
@@ -8,13 +8,13 @@
|
||||
<input
|
||||
v-model="internalSearch"
|
||||
tabindex="0"
|
||||
class="input w-full items-center flex flex-wrap border border-gray-400 rounded-lg"
|
||||
class="input flex w-full flex-wrap items-center rounded-lg border border-gray-400"
|
||||
@keyup.enter="selectFirst"
|
||||
/>
|
||||
<button
|
||||
v-if="!!modelValue && Object.keys(modelValue).length !== 0"
|
||||
style="transform: translateY(-50%)"
|
||||
class="top-1/2 absolute right-2 btn btn-xs btn-circle no-animation"
|
||||
class="btn btn-circle btn-xs no-animation absolute right-2 top-1/2"
|
||||
@click="clear"
|
||||
>
|
||||
x
|
||||
@@ -23,7 +23,7 @@
|
||||
<ul
|
||||
tabindex="0"
|
||||
style="display: inline"
|
||||
class="dropdown-content mb-1 menu shadow border border-gray-400 rounded bg-base-100 w-full z-[9999] max-h-60 overflow-y-scroll"
|
||||
class="dropdown-content menu z-[9999] mb-1 max-h-60 w-full overflow-y-scroll rounded border border-gray-400 bg-base-100 shadow"
|
||||
>
|
||||
<li v-for="(obj, idx) in filtered" :key="idx">
|
||||
<div type="button" @click="select(obj)">
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<div class="relative">
|
||||
<ComboboxInput
|
||||
:display-value="i => extractDisplay(i as SupportValues)"
|
||||
class="w-full input input-bordered"
|
||||
class="input input-bordered w-full"
|
||||
@change="search = $event.target.value"
|
||||
/>
|
||||
<button
|
||||
@@ -16,14 +16,14 @@
|
||||
class="absolute inset-y-0 right-6 flex items-center rounded-r-md px-2 focus:outline-none"
|
||||
@click="clear"
|
||||
>
|
||||
<MdiClose class="w-5 h-5" />
|
||||
<MdiClose class="size-5" />
|
||||
</button>
|
||||
<ComboboxButton class="absolute inset-y-0 right-0 flex items-center rounded-r-md px-2 focus:outline-none">
|
||||
<MdiChevronDown class="w-5 h-5" />
|
||||
<MdiChevronDown class="size-5" />
|
||||
</ComboboxButton>
|
||||
<ComboboxOptions
|
||||
v-if="computedItems.length > 0"
|
||||
class="absolute dropdown-content z-10 mt-2 max-h-60 w-full overflow-auto rounded-md card bg-base-100 border border-gray-400"
|
||||
class="card dropdown-content absolute z-10 mt-2 max-h-60 w-full overflow-auto rounded-md border border-gray-400 bg-base-100"
|
||||
>
|
||||
<ComboboxOption
|
||||
v-for="item in computedItems"
|
||||
@@ -34,7 +34,7 @@
|
||||
>
|
||||
<li
|
||||
:class="[
|
||||
'relative cursor-default select-none py-2 pl-3 pr-9 duration-75 ease-in-out transition-colors',
|
||||
'relative cursor-default select-none py-2 pl-3 pr-9 transition-colors duration-75 ease-in-out',
|
||||
active ? 'bg-primary text-primary-content' : 'text-base-content',
|
||||
]"
|
||||
>
|
||||
@@ -45,11 +45,11 @@
|
||||
<span
|
||||
v-if="selected"
|
||||
:class="[
|
||||
'absolute inset-y-0 right-0 flex text-primary items-center pr-4',
|
||||
'absolute inset-y-0 right-0 flex items-center pr-4 text-primary',
|
||||
active ? 'text-primary-content' : 'bg-primary',
|
||||
]"
|
||||
>
|
||||
<MdiCheck class="h-5 w-5" aria-hidden="true" />
|
||||
<MdiCheck class="size-5" aria-hidden="true" />
|
||||
</span>
|
||||
</slot>
|
||||
</li>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<span class="label-text">{{ label }}</span>
|
||||
</label>
|
||||
<div class="dropdown dropdown-top sm:dropdown-end">
|
||||
<div tabindex="0" class="w-full min-h-[48px] flex gap-2 p-4 flex-wrap border border-gray-400 rounded-lg">
|
||||
<div tabindex="0" class="flex min-h-[48px] w-full flex-wrap gap-2 rounded-lg border border-gray-400 p-4">
|
||||
<span v-for="itm in value" :key="name != '' ? itm[name] : itm" class="badge">
|
||||
{{ name != "" ? itm[name] : itm }}
|
||||
</span>
|
||||
@@ -12,12 +12,12 @@
|
||||
<div
|
||||
tabindex="0"
|
||||
style="display: inline"
|
||||
class="dropdown-content mb-1 menu w-full z-[9999] shadow border border-gray-400 rounded bg-base-100"
|
||||
class="dropdown-content menu z-[9999] mb-1 w-full rounded border border-gray-400 bg-base-100 shadow"
|
||||
>
|
||||
<div class="m-2">
|
||||
<input v-model="search" placeholder="Search…" class="input input-sm input-bordered w-full" />
|
||||
<input v-model="search" placeholder="Search…" class="input input-bordered input-sm w-full" />
|
||||
</div>
|
||||
<ul class="overflow-y-scroll max-h-60">
|
||||
<ul class="max-h-60 overflow-y-scroll">
|
||||
<li
|
||||
v-for="(obj, idx) in filteredItems"
|
||||
:key="idx"
|
||||
|
||||
@@ -3,11 +3,11 @@
|
||||
<FormTextField v-model="value" placeholder="Password" :label="label" :type="inputType"> </FormTextField>
|
||||
<button
|
||||
type="button"
|
||||
class="inline-flex p-1 ml-1 justify-center mt-auto mb-3 tooltip absolute top-11 right-3"
|
||||
class="tooltip absolute right-3 top-11 mb-3 ml-1 mt-auto inline-flex justify-center p-1"
|
||||
data-tip="Toggle Password Show"
|
||||
@click="toggle()"
|
||||
>
|
||||
<MdiEye name="mdi-eye" class="h-5 w-5" />
|
||||
<MdiEye name="mdi-eye" class="size-5" />
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<label class="label">
|
||||
<span class="label-text">{{ label }}</span>
|
||||
</label>
|
||||
<textarea ref="el" v-model="value" class="textarea w-full textarea-bordered h-28" :placeholder="placeholder" />
|
||||
<textarea ref="el" v-model="value" class="textarea textarea-bordered h-28 w-full" :placeholder="placeholder" />
|
||||
<label v-if="limit" class="label">
|
||||
<span class="label-text-alt"></span>
|
||||
<span class="label-text-alt"> {{ valueLen }}/{{ limit }}</span>
|
||||
@@ -16,7 +16,7 @@
|
||||
<textarea
|
||||
ref="el"
|
||||
v-model="value"
|
||||
class="textarea textarea-bordered w-full col-span-3 mt-3 h-28"
|
||||
class="textarea textarea-bordered col-span-3 mt-3 h-28 w-full"
|
||||
auto-grow
|
||||
:placeholder="placeholder"
|
||||
auto-height
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<label class="label">
|
||||
<span class="label-text">{{ label }}</span>
|
||||
</label>
|
||||
<input v-model="value" :placeholder="placeholder" class="input input-bordered col-span-3 w-full mt-2" />
|
||||
<input v-model="value" :placeholder="placeholder" class="input input-bordered col-span-3 mt-2 w-full" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -6,15 +6,15 @@
|
||||
class="flex items-center justify-between py-3 pl-3 pr-4 text-sm"
|
||||
>
|
||||
<div class="flex w-0 flex-1 items-center">
|
||||
<MdiPaperclip class="h-5 w-5 flex-shrink-0 text-gray-400" aria-hidden="true" />
|
||||
<MdiPaperclip class="size-5 shrink-0 text-gray-400" aria-hidden="true" />
|
||||
<span class="ml-2 w-0 flex-1 truncate"> {{ attachment.document.title }}</span>
|
||||
</div>
|
||||
<div class="ml-4 flex-shrink-0">
|
||||
<div class="ml-4 shrink-0">
|
||||
<a class="tooltip mr-2" data-tip="Download" :href="attachmentURL(attachment.id)" target="_blank">
|
||||
<MdiDownload class="h-5 w-5" />
|
||||
<MdiDownload class="size-5" />
|
||||
</a>
|
||||
<a class="tooltip" data-tip="Open" :href="attachmentURL(attachment.id)" target="_blank">
|
||||
<MdiOpenInNew class="h-5 w-5" />
|
||||
<MdiOpenInNew class="size-5" />
|
||||
</a>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
@@ -1,32 +1,32 @@
|
||||
<template>
|
||||
<NuxtLink class="group card rounded-md border border-gray-300" :to="`/item/${item.id}`">
|
||||
<div class="relative h-[200px]">
|
||||
<img v-if="imageUrl" class="h-[200px] w-full object-cover rounded-t shadow-sm border-gray-300" :src="imageUrl" />
|
||||
<img v-if="imageUrl" class="h-[200px] w-full rounded-t border-gray-300 object-cover shadow-sm" :src="imageUrl" />
|
||||
<div class="absolute bottom-1 left-1">
|
||||
<NuxtLink
|
||||
v-if="item.location"
|
||||
class="text-sm hover:link badge shadow-md rounded-md"
|
||||
class="badge rounded-md text-sm shadow-md hover:link"
|
||||
:to="`/location/${item.location.id}`"
|
||||
>
|
||||
{{ item.location.name }}
|
||||
</NuxtLink>
|
||||
</div>
|
||||
</div>
|
||||
<div class="rounded-b p-4 pt-2 flex-grow col-span-4 flex flex-col gap-y-1 bg-base-100">
|
||||
<h2 class="text-lg font-bold two-line">{{ item.name }}</h2>
|
||||
<div class="col-span-4 flex grow flex-col gap-y-1 rounded-b bg-base-100 p-4 pt-2">
|
||||
<h2 class="line-clamp-2 text-ellipsis text-lg font-bold">{{ item.name }}</h2>
|
||||
<div class="divider my-0"></div>
|
||||
<div class="flex justify-between gap-2">
|
||||
<div v-if="item.insured" class="tooltip z-10" data-tip="Insured">
|
||||
<MdiShieldCheck class="h-5 w-5 text-primary" />
|
||||
<MdiShieldCheck class="size-5 text-primary" />
|
||||
</div>
|
||||
<div class="tooltip" data-tip="Quantity">
|
||||
<span class="badge h-5 w-5 badge-primary badge-sm text-xs">
|
||||
<span class="badge badge-primary badge-sm size-5 text-xs">
|
||||
{{ item.quantity }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<Markdown class="mb-2 text-clip three-line" :source="item.description" />
|
||||
<div class="flex gap-2 flex-wrap -mr-1 mt-auto justify-end">
|
||||
<Markdown class="mb-2 line-clamp-3 text-ellipsis" :source="item.description" />
|
||||
<div class="-mr-1 mt-auto flex flex-wrap justify-end gap-2">
|
||||
<LabelChip v-for="label in top3" :key="label.id" :label="label" size="sm" />
|
||||
</div>
|
||||
</div>
|
||||
@@ -59,22 +59,4 @@
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="css">
|
||||
.three-line {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 3;
|
||||
line-clamp: 3;
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
|
||||
.two-line {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
</style>
|
||||
<style lang="css"></style>
|
||||
|
||||
@@ -15,16 +15,16 @@
|
||||
</div>
|
||||
<BaseButton class="rounded-r-none" :loading="loading" type="submit">
|
||||
<template #icon>
|
||||
<MdiPackageVariant class="swap-off h-5 w-5" />
|
||||
<MdiPackageVariantClosed class="swap-on h-5 w-5" />
|
||||
<MdiPackageVariant class="swap-off size-5" />
|
||||
<MdiPackageVariantClosed class="swap-on size-5" />
|
||||
</template>
|
||||
{{ $t("global.create") }}
|
||||
</BaseButton>
|
||||
<div class="dropdown dropdown-top">
|
||||
<label tabindex="0" class="btn rounded-l-none rounded-r-xl">
|
||||
<MdiChevronDown class="h-5 w-5" name="mdi-chevron-down" />
|
||||
<MdiChevronDown class="size-5" name="mdi-chevron-down" />
|
||||
</label>
|
||||
<ul tabindex="0" class="dropdown-content menu p-2 shadow bg-base-100 rounded-box w-64 right-0">
|
||||
<ul tabindex="0" class="dropdown-content menu rounded-box right-0 w-64 bg-base-100 p-2 shadow">
|
||||
<li>
|
||||
<button type="button" @click="create(false)">{{ $t("global.create_and_add") }}</button>
|
||||
</li>
|
||||
@@ -39,13 +39,13 @@
|
||||
<p class="mb-0">File name: {{ form.photo?.name }}</p>
|
||||
<img
|
||||
:src="form.preview"
|
||||
class="h-[100px] w-full object-cover rounded-t shadow-sm border-gray-300"
|
||||
class="h-[100px] w-full rounded-t border-gray-300 object-cover shadow-sm"
|
||||
alt="Uploaded Photo"
|
||||
/>
|
||||
</template>
|
||||
</div>
|
||||
</form>
|
||||
<p class="text-sm text-center mt-4">
|
||||
<p class="mt-4 text-center text-sm">
|
||||
use <kbd class="kbd kbd-xs">Shift</kbd> + <kbd class="kbd kbd-xs"> Enter </kbd> to create and add another
|
||||
</p>
|
||||
</BaseModal>
|
||||
|
||||
@@ -28,23 +28,23 @@
|
||||
|
||||
<template>
|
||||
<section>
|
||||
<BaseSectionHeader class="mb-2 flex justify-between items-center">
|
||||
<BaseSectionHeader class="mb-2 flex items-center justify-between">
|
||||
{{ $t("components.item.view.selectable.items") }}
|
||||
<template #description>
|
||||
<div v-if="!viewSet" class="dropdown dropdown-hover dropdown-left">
|
||||
<div v-if="!viewSet" class="dropdown dropdown-left dropdown-hover">
|
||||
<label tabindex="0" class="btn btn-ghost m-1">
|
||||
<MdiDotsVertical class="h-7 w-7" />
|
||||
<MdiDotsVertical class="size-7" />
|
||||
</label>
|
||||
<ul tabindex="0" class="dropdown-content menu p-2 shadow bg-base-100 rounded-box w-32">
|
||||
<ul tabindex="0" class="dropdown-content menu rounded-box w-32 bg-base-100 p-2 shadow">
|
||||
<li>
|
||||
<button @click="setViewPreference('card')">
|
||||
<MdiCardTextOutline class="h-5 w-5" />
|
||||
<MdiCardTextOutline class="size-5" />
|
||||
{{ $t("components.item.view.selectable.card") }}
|
||||
</button>
|
||||
</li>
|
||||
<li>
|
||||
<button @click="setViewPreference('table')">
|
||||
<MdiTable class="h-5 w-5" />
|
||||
<MdiTable class="size-5" />
|
||||
{{ $t("components.item.view.selectable.table") }}
|
||||
</button>
|
||||
</li>
|
||||
@@ -57,9 +57,9 @@
|
||||
<ItemViewTable :items="items" />
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-4">
|
||||
<div class="grid grid-cols-1 gap-4 sm:grid-cols-2 md:grid-cols-3">
|
||||
<ItemCard v-for="item in items" :key="item.id" :item="item" />
|
||||
<div class="first:block hidden text-lg">{{ $t("components.item.view.selectable.no_items") }}</div>
|
||||
<div class="hidden text-lg first:block">{{ $t("components.item.view.selectable.no_items") }}</div>
|
||||
</div>
|
||||
</template>
|
||||
</section>
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
<template>
|
||||
<BaseCard class="overflow-clip">
|
||||
<BaseCard class="overflow-hidden">
|
||||
<table class="table w-full">
|
||||
<thead>
|
||||
<tr>
|
||||
<th
|
||||
v-for="h in headers"
|
||||
:key="h.value"
|
||||
class="text-no-transform text-sm bg-neutral text-neutral-content cursor-pointer"
|
||||
class="text-no-transform cursor-pointer bg-neutral text-sm text-neutral-content"
|
||||
@click="sortBy(h.value)"
|
||||
>
|
||||
<div
|
||||
@@ -24,8 +24,8 @@
|
||||
:class="`inline-flex ${sortByProperty === h.value ? '' : 'opacity-0'}`"
|
||||
>
|
||||
<span class="swap swap-rotate" :class="{ 'swap-active': pagination.descending }">
|
||||
<MdiArrowDown class="swap-on h-5 w-5" />
|
||||
<MdiArrowUp class="swap-off h-5 w-5" />
|
||||
<MdiArrowDown class="swap-on size-5" />
|
||||
<MdiArrowUp class="swap-off size-5" />
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -53,8 +53,8 @@
|
||||
<Currency :amount="d.purchasePrice" />
|
||||
</template>
|
||||
<template v-else-if="cell(h) === 'cell-insured'">
|
||||
<MdiCheck v-if="d.insured" class="text-green-500 h-5 w-5 inline" />
|
||||
<MdiClose v-else class="text-red-500 h-5 w-5 inline" />
|
||||
<MdiCheck v-if="d.insured" class="inline size-5 text-green-500" />
|
||||
<MdiClose v-else class="inline size-5 text-red-500" />
|
||||
</template>
|
||||
<slot v-else :name="cell(h)" v-bind="{ item: d }">
|
||||
{{ extractValue(d, h.value) }}
|
||||
@@ -63,9 +63,9 @@
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div v-if="items.length > 10" class="border-t p-3 justify-end flex gap-3">
|
||||
<div v-if="items.length > 10" class="flex justify-end gap-3 border-t p-3">
|
||||
<div class="flex items-center">Rows per page</div>
|
||||
<select v-model.number="pagination.rowsPerPage" class="select select-sm select-primary">
|
||||
<select v-model.number="pagination.rowsPerPage" class="select select-primary select-sm">
|
||||
<option :value="10">10</option>
|
||||
<option :value="25">25</option>
|
||||
<option :value="50">50</option>
|
||||
|
||||
@@ -29,13 +29,13 @@
|
||||
:class="{
|
||||
'badge-lg p-4': size === 'lg',
|
||||
'p-3': size !== 'sm' && size !== 'lg',
|
||||
'p-2 badge-sm': size === 'sm',
|
||||
'badge-sm p-2': size === 'sm',
|
||||
}"
|
||||
:to="`/label/${label.id}`"
|
||||
>
|
||||
<label class="swap swap-rotate" :class="isActive ? 'swap-active' : ''">
|
||||
<MdiArrowRight class="mr-2 swap-on" />
|
||||
<MdiTagOutline class="mr-2 swap-off" />
|
||||
<MdiArrowRight class="swap-on mr-2" />
|
||||
<MdiTagOutline class="swap-off mr-2" />
|
||||
</label>
|
||||
{{ label.name }}
|
||||
</NuxtLink>
|
||||
|
||||
@@ -15,9 +15,9 @@
|
||||
<BaseButton class="rounded-r-none" :loading="loading" type="submit"> {{ $t("global.create") }} </BaseButton>
|
||||
<div class="dropdown dropdown-top">
|
||||
<label tabindex="0" class="btn rounded-l-none rounded-r-xl">
|
||||
<MdiChevronDown class="h-5 w-5" />
|
||||
<MdiChevronDown class="size-5" />
|
||||
</label>
|
||||
<ul tabindex="0" class="dropdown-content menu p-2 shadow bg-base-100 rounded-box w-64 right-0">
|
||||
<ul tabindex="0" class="dropdown-content menu rounded-box right-0 w-64 bg-base-100 p-2 shadow">
|
||||
<li>
|
||||
<button type="button" @click="create(false)">{{ $t("global.create_and_add") }}</button>
|
||||
</li>
|
||||
@@ -26,7 +26,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<p class="text-sm text-center mt-4">
|
||||
<p class="mt-4 text-center text-sm">
|
||||
use <kbd class="kbd kbd-xs">Shift</kbd> + <kbd class="kbd kbd-xs"> Enter </kbd> to create and add another
|
||||
</p>
|
||||
</BaseModal>
|
||||
|
||||
@@ -2,24 +2,24 @@
|
||||
<NuxtLink
|
||||
ref="card"
|
||||
:to="`/location/${location.id}`"
|
||||
class="card bg-base-100 text-base-content rounded-md transition duration-300 shadow-md"
|
||||
class="card rounded-md bg-base-100 text-base-content shadow-md transition duration-300"
|
||||
>
|
||||
<div
|
||||
class="card-body"
|
||||
:class="{
|
||||
'p-4': !dense,
|
||||
'py-2 px-3': dense,
|
||||
'px-3 py-2': dense,
|
||||
}"
|
||||
>
|
||||
<h2 class="flex items-center justify-between gap-2">
|
||||
<label class="swap swap-rotate" :class="isActive ? 'swap-active' : ''">
|
||||
<MdiArrowRight class="swap-on h-6 w-6" />
|
||||
<MdiMapMarkerOutline class="swap-off h-6 w-6" />
|
||||
<MdiArrowRight class="swap-on size-6" />
|
||||
<MdiMapMarkerOutline class="swap-off size-6" />
|
||||
</label>
|
||||
<span class="mx-auto">
|
||||
{{ location.name }}
|
||||
</span>
|
||||
<span class="badge badge-primary h-6 badge-lg" :class="{ 'opacity-0': !hasCount }">
|
||||
<span class="badge badge-primary badge-lg h-6" :class="{ 'opacity-0': !hasCount }">
|
||||
{{ count }}
|
||||
</span>
|
||||
</h2>
|
||||
|
||||
@@ -16,9 +16,9 @@
|
||||
<BaseButton class="rounded-r-none" type="submit" :loading="loading">{{ $t("global.create") }}</BaseButton>
|
||||
<div class="dropdown dropdown-top">
|
||||
<label tabindex="0" class="btn rounded-l-none rounded-r-xl">
|
||||
<MdiChevronDown class="h-5 w-5" />
|
||||
<MdiChevronDown class="size-5" />
|
||||
</label>
|
||||
<ul tabindex="0" class="dropdown-content menu p-2 shadow bg-base-100 rounded-box w-64 right-0">
|
||||
<ul tabindex="0" class="dropdown-content menu rounded-box right-0 w-64 bg-base-100 p-2 shadow">
|
||||
<li>
|
||||
<button type="button" @click="create(false)">{{ $t("global.create_and_add") }}</button>
|
||||
</li>
|
||||
@@ -27,7 +27,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<p class="text-sm text-center mt-4">
|
||||
<p class="mt-4 text-center text-sm">
|
||||
use <kbd class="kbd kbd-xs">Shift</kbd> + <kbd class="kbd kbd-xs"> Enter </kbd> to create and add another
|
||||
</p>
|
||||
</BaseModal>
|
||||
|
||||
@@ -8,10 +8,10 @@
|
||||
v-if="selected"
|
||||
:class="['absolute inset-y-0 right-0 flex items-center pr-4', active ? 'text-white' : 'text-primary']"
|
||||
>
|
||||
<MdiCheck class="h-5 w-5" aria-hidden="true" />
|
||||
<MdiCheck class="size-5" aria-hidden="true" />
|
||||
</span>
|
||||
</div>
|
||||
<div v-if="cast(item.value).name != cast(item.value).treeString" class="text-xs mt-1">
|
||||
<div v-if="cast(item.value).name != cast(item.value).treeString" class="mt-1 text-xs">
|
||||
{{ cast(item.value).treeString }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -40,19 +40,19 @@
|
||||
<template>
|
||||
<div>
|
||||
<div
|
||||
class="node flex items-center gap-1 rounded p-1"
|
||||
class="flex items-center gap-1 rounded p-1"
|
||||
:class="{
|
||||
'cursor-pointer hover:bg-base-200': hasChildren,
|
||||
}"
|
||||
@click="openRef = !openRef"
|
||||
>
|
||||
<div
|
||||
class="p-1/2 rounded mr-1 flex items-center justify-center"
|
||||
class="mr-1 flex items-center justify-center rounded p-0.5"
|
||||
:class="{
|
||||
'hover:bg-base-200': hasChildren,
|
||||
}"
|
||||
>
|
||||
<div v-if="!hasChildren" class="h-6 w-6"></div>
|
||||
<div v-if="!hasChildren" class="size-6"></div>
|
||||
<label
|
||||
v-else
|
||||
class="swap swap-rotate"
|
||||
@@ -60,13 +60,13 @@
|
||||
'swap-active': openRef,
|
||||
}"
|
||||
>
|
||||
<MdiChevronRight name="mdi-chevron-right" class="h-6 w-6 swap-off" />
|
||||
<MdiChevronDown name="mdi-chevron-down" class="h-6 w-6 swap-on" />
|
||||
<MdiChevronRight name="mdi-chevron-right" class="swap-off size-6" />
|
||||
<MdiChevronDown name="mdi-chevron-down" class="swap-on size-6" />
|
||||
</label>
|
||||
</div>
|
||||
<MdiMapMarker v-if="item.type === 'location'" class="h-4 w-4" />
|
||||
<MdiPackageVariant v-else class="h-4 w-4" />
|
||||
<NuxtLink class="hover:link text-lg" :to="link" @click.stop>{{ item.name }} </NuxtLink>
|
||||
<MdiMapMarker v-if="item.type === 'location'" class="size-4" />
|
||||
<MdiPackageVariant v-else class="size-4" />
|
||||
<NuxtLink class="text-lg hover:link" :to="link" @click.stop>{{ item.name }} </NuxtLink>
|
||||
</div>
|
||||
<div v-if="openRef" class="ml-4">
|
||||
<LocationTreeNode v-for="child in item.children" :key="child.id" :item="child" :tree-id="treeId" />
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="p-4 border-2 root">
|
||||
<div class="root border-2 p-4">
|
||||
<LocationTreeNode v-for="item in locs" :key="item.id" :item="item" :tree-id="treeId" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -1,37 +1,37 @@
|
||||
<template>
|
||||
<div ref="el" class="dropdown" :class="{ 'dropdown-open': dropdownOpen }">
|
||||
<button ref="btn" tabindex="0" class="btn btn-xs" @click="toggle">
|
||||
{{ label }} {{ len }} <MdiChevronDown class="h-4 w-4" />
|
||||
{{ label }} {{ len }} <MdiChevronDown class="size-4" />
|
||||
</button>
|
||||
<div tabindex="0" class="dropdown-content mt-1 w-64 shadow bg-base-100 rounded-md">
|
||||
<div class="pt-4 px-4 shadow-sm mb-1">
|
||||
<input v-model="search" type="text" placeholder="Search…" class="input input-sm input-bordered w-full mb-2" />
|
||||
<div tabindex="0" class="dropdown-content mt-1 w-64 rounded-md bg-base-100 shadow">
|
||||
<div class="mb-1 px-4 pt-4 shadow-sm">
|
||||
<input v-model="search" type="text" placeholder="Search…" class="input input-bordered input-sm mb-2 w-full" />
|
||||
</div>
|
||||
<div class="overflow-y-auto max-h-72 divide-y">
|
||||
<div class="max-h-72 divide-y overflow-y-auto">
|
||||
<label
|
||||
v-for="v in selectedView"
|
||||
:key="v"
|
||||
class="cursor-pointer px-4 label flex justify-between hover:bg-base-200"
|
||||
class="label flex cursor-pointer justify-between px-4 hover:bg-base-200"
|
||||
>
|
||||
<span class="label-text mr-2">
|
||||
<slot name="display" v-bind="{ item: v }">
|
||||
{{ v[display] }}
|
||||
</slot>
|
||||
</span>
|
||||
<input v-model="selected" type="checkbox" :value="v" class="checkbox checkbox-sm checkbox-primary" />
|
||||
<input v-model="selected" type="checkbox" :value="v" class="checkbox checkbox-primary checkbox-sm" />
|
||||
</label>
|
||||
<hr v-if="selected.length > 0" />
|
||||
<label
|
||||
v-for="v in unselected"
|
||||
:key="v"
|
||||
class="cursor-pointer px-4 label flex justify-between hover:bg-base-200"
|
||||
class="label flex cursor-pointer justify-between px-4 hover:bg-base-200"
|
||||
>
|
||||
<span class="label-text mr-2">
|
||||
<slot name="display" v-bind="{ item: v }">
|
||||
{{ v[display] }}
|
||||
</slot>
|
||||
</span>
|
||||
<input v-model="selected" type="checkbox" :value="v" class="checkbox checkbox-sm checkbox-primary" />
|
||||
<input v-model="selected" type="checkbox" :value="v" class="checkbox checkbox-primary checkbox-sm" />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
@@ -97,7 +97,10 @@
|
||||
const unselected = computed(() => {
|
||||
return props.options.filter(o => {
|
||||
if (searchFold.value.length > 0) {
|
||||
return o[props.display].toLowerCase().includes(searchFold.value) && selected.value.every(s => s[props.uniqueField] !== o[props.uniqueField]);
|
||||
return (
|
||||
o[props.display].toLowerCase().includes(searchFold.value) &&
|
||||
selected.value.every(s => s[props.uniqueField] !== o[props.uniqueField])
|
||||
);
|
||||
}
|
||||
return selected.value.every(s => s[props.uniqueField] !== o[props.uniqueField]);
|
||||
});
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<template>
|
||||
<div class="border-t border-gray-300 px-4 py-5 sm:p-0">
|
||||
<dl class="sm:divide-y sm:divide-gray-300">
|
||||
<div v-for="(detail, i) in details" :key="i" class="py-4 sm:grid group sm:grid-cols-3 sm:gap-4 sm:px-6">
|
||||
<div v-for="(detail, i) in details" :key="i" class="group py-4 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
|
||||
<dt class="text-sm font-medium text-base-content">
|
||||
{{ detail.name }}
|
||||
</dt>
|
||||
<dd class="text-sm text-base-content text-start sm:col-span-2">
|
||||
<dd class="text-start text-sm text-base-content sm:col-span-2">
|
||||
<slot :name="detail.slot || detail.name" v-bind="{ detail }">
|
||||
<DateTime
|
||||
v-if="detail.type == 'date'"
|
||||
@@ -14,9 +14,9 @@
|
||||
/>
|
||||
<Currency v-else-if="detail.type == 'currency'" :amount="detail.text" />
|
||||
<template v-else-if="detail.type === 'link'">
|
||||
<div class="tooltip tooltip-primary tooltip-top" :data-tip="detail.href">
|
||||
<div class="tooltip tooltip-top tooltip-primary" :data-tip="detail.href">
|
||||
<a class="btn btn-primary btn-xs" :href="detail.href" target="_blank">
|
||||
<MdiOpenInNew class="mr-2 swap-on" />
|
||||
<MdiOpenInNew class="swap-on mr-2" />
|
||||
{{ detail.text }}
|
||||
</a>
|
||||
</div>
|
||||
@@ -31,13 +31,13 @@
|
||||
{{ detail.text }}
|
||||
<span
|
||||
v-if="detail.copyable"
|
||||
class="opacity-0 group-hover:opacity-100 ml-4 my-0 duration-75 transition-opacity"
|
||||
class="my-0 ml-4 opacity-0 transition-opacity duration-75 group-hover:opacity-100"
|
||||
>
|
||||
<CopyText
|
||||
v-if="detail.text.toString()"
|
||||
:text="detail.text.toString()"
|
||||
:icon-size="16"
|
||||
class="btn btn-xs btn-ghost btn-circle"
|
||||
class="btn btn-circle btn-ghost btn-xs"
|
||||
/>
|
||||
</span>
|
||||
</span>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div
|
||||
ref="el"
|
||||
class="h-24 w-full border-2 border-primary border-dashed grid place-content-center"
|
||||
class="grid h-24 w-full place-content-center border-2 border-dashed border-primary"
|
||||
:class="isOverDropZone ? 'bg-primary bg-opacity-10' : ''"
|
||||
>
|
||||
<slot />
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<MdiQrcode />
|
||||
</label>
|
||||
</slot>
|
||||
<div tabindex="0" class="card compact dropdown-content shadow-lg bg-base-100 rounded-box w-64">
|
||||
<div tabindex="0" class="card dropdown-content compact rounded-box w-64 bg-base-100 shadow-lg">
|
||||
<div class="card-body">
|
||||
<h2 class="text-center">{{ $t("components.global.page_qr_code.page_url") }}</h2>
|
||||
<img :src="getQRCodeUrl()" />
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<div class="py-4">
|
||||
<p class="text-sm">{{ $t("components.global.password_score.password_strength") }}: {{ message }}</p>
|
||||
<progress
|
||||
class="progress w-full progress-bar"
|
||||
class="progress w-full"
|
||||
:value="score"
|
||||
max="100"
|
||||
:class="{
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
<template>
|
||||
<div class="grow-1 max-w-full"></div>
|
||||
<div class="max-w-full"></div>
|
||||
</template>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="stats bg-neutral shadow rounded-md">
|
||||
<div class="stat text-neutral-content text-center space-y-1 p-3">
|
||||
<div class="stats rounded-md bg-neutral shadow">
|
||||
<div class="stat space-y-1 p-3 text-center text-neutral-content">
|
||||
<div class="stat-title text-neutral-content">{{ title }}</div>
|
||||
<div class="stat-value text-2xl">
|
||||
<Currency v-if="type === 'currency'" :amount="value" />
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<h3 class="flex gap-2 items-center mb-3 pl-1 text-lg">
|
||||
<h3 class="mb-3 flex items-center gap-2 pl-1 text-lg">
|
||||
<slot />
|
||||
</h3>
|
||||
</template>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<th
|
||||
v-for="h in headers"
|
||||
:key="h.value"
|
||||
class="text-no-transform text-sm bg-neutral text-neutral-content"
|
||||
class="text-no-transform bg-neutral text-sm text-neutral-content"
|
||||
:class="{
|
||||
'text-center': h.align === 'center',
|
||||
'text-right': h.align === 'right',
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<main class="w-full min-h-screen bg-blue-100 grid place-items-center">
|
||||
<main class="grid min-h-screen w-full place-items-center bg-blue-100">
|
||||
<slot></slot>
|
||||
</main>
|
||||
</template>
|
||||
|
||||
@@ -15,21 +15,21 @@
|
||||
<div class="drawer-content justify-center bg-base-300 pt-20 lg:pt-0">
|
||||
<AppHeaderDecor class="-mt-10 hidden lg:block" />
|
||||
<!-- Button -->
|
||||
<div class="navbar z-[99] lg:hidden top-0 fixed bg-primary shadow-md drawer-button">
|
||||
<label for="my-drawer-2" class="btn btn-square btn-ghost text-base-100 drawer-button lg:hidden">
|
||||
<MdiMenu class="h-6 w-6" />
|
||||
<div class="navbar drawer-button fixed top-0 z-[99] bg-primary shadow-md lg:hidden">
|
||||
<label for="my-drawer-2" class="btn btn-square btn-ghost drawer-button text-base-100 lg:hidden">
|
||||
<MdiMenu class="size-6" />
|
||||
</label>
|
||||
<NuxtLink to="/home">
|
||||
<h2 class="text-3xl font-bold tracking-tight text-base-100 flex">
|
||||
<h2 class="flex text-3xl font-bold tracking-tight text-base-100">
|
||||
HomeB
|
||||
<AppLogo class="w-8 -mb-3" />
|
||||
<AppLogo class="-mb-3 w-8" />
|
||||
x
|
||||
</h2>
|
||||
</NuxtLink>
|
||||
</div>
|
||||
|
||||
<slot></slot>
|
||||
<footer v-if="status" class="text-center w-full bottom-0 pb-4 bg-base-300 text-secondary-content">
|
||||
<footer v-if="status" class="bottom-0 w-full bg-base-300 pb-4 text-center text-secondary-content">
|
||||
<p class="text-center text-sm">
|
||||
{{ $t("global.version", { version: status.build.version }) }} ~
|
||||
{{ $t("global.build", { build: status.build.commit }) }}
|
||||
@@ -42,26 +42,26 @@
|
||||
<label for="my-drawer-2" class="drawer-overlay"></label>
|
||||
|
||||
<!-- Top Section -->
|
||||
<div class="w-60 py-5 md:py-10 bg-base-200 flex flex-grow-1 flex-col">
|
||||
<div class="flex w-60 flex-col bg-base-200 py-5 md:py-10">
|
||||
<div class="space-y-8">
|
||||
<div class="flex flex-col items-center gap-4">
|
||||
<p>{{ $t("global.welcome", { username: username }) }}</p>
|
||||
<NuxtLink class="avatar placeholder" to="/home">
|
||||
<div class="bg-base-300 text-neutral-content rounded-full w-24 p-4">
|
||||
<div class="w-24 rounded-full bg-base-300 p-4 text-neutral-content">
|
||||
<AppLogo />
|
||||
</div>
|
||||
</NuxtLink>
|
||||
</div>
|
||||
<div class="flex flex-col bg-base-200">
|
||||
<div class="mx-auto w-40 mb-6">
|
||||
<div class="dropdown overflow visible w-40">
|
||||
<label tabindex="0" class="btn btn-primary btn-block text-lg text-no-transform">
|
||||
<div class="mx-auto mb-6 w-40">
|
||||
<div class="dropdown visible w-40">
|
||||
<label tabindex="0" class="text-no-transform btn btn-primary btn-block text-lg">
|
||||
<span>
|
||||
<MdiPlus class="mr-1 -ml-1" />
|
||||
<MdiPlus class="-ml-1 mr-1" />
|
||||
</span>
|
||||
{{ $t("global.create") }}
|
||||
</label>
|
||||
<ul tabindex="0" class="dropdown-content menu p-2 shadow bg-base-100 rounded-box w-40">
|
||||
<ul tabindex="0" class="dropdown-content menu rounded-box w-40 bg-base-100 p-2 shadow">
|
||||
<li v-for="btn in dropdown" :key="btn.name">
|
||||
<button @click="btn.action">
|
||||
{{ btn.name }}
|
||||
@@ -70,7 +70,7 @@
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<ul class="flex flex-col mx-auto gap-2 w-40 menu">
|
||||
<ul class="menu mx-auto flex w-40 flex-col gap-2">
|
||||
<li v-for="n in nav" :key="n.id" class="text-xl" @click="unfocus">
|
||||
<NuxtLink
|
||||
v-if="n.to"
|
||||
@@ -80,7 +80,7 @@
|
||||
'bg-secondary text-secondary-content': n.active?.value,
|
||||
}"
|
||||
>
|
||||
<component :is="n.icon" class="h-6 w-6 mr-4" />
|
||||
<component :is="n.icon" class="mr-4 size-6" />
|
||||
{{ n.name }}
|
||||
</NuxtLink>
|
||||
</li>
|
||||
@@ -89,7 +89,7 @@
|
||||
</div>
|
||||
|
||||
<!-- Bottom -->
|
||||
<button class="mt-auto mx-2 hover:bg-base-300 p-3 rounded-btn" @click="logout">
|
||||
<button class="rounded-btn mx-2 mt-auto p-3 hover:bg-base-300" @click="logout">
|
||||
{{ $t("global.sign_out") }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
"eslint": "^8.23.0",
|
||||
"eslint-config-prettier": "^9.0.0",
|
||||
"eslint-plugin-prettier": "^5.1.3",
|
||||
"eslint-plugin-tailwindcss": "^3.17.4",
|
||||
"eslint-plugin-vue": "^9.4.0",
|
||||
"h3": "^1.7.1",
|
||||
"intl-messageformat": "^10.5.14",
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<h1 class="text-blue-500 font-extrabold flex flex-col text-center">
|
||||
<h1 class="flex flex-col text-center font-extrabold text-blue-500">
|
||||
<span class="text-7xl">404.</span>
|
||||
<span class="text-5xl mt-5"> Page Not Found </span>
|
||||
<span class="mt-5 text-5xl"> Page Not Found </span>
|
||||
</h1>
|
||||
</template>
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
<BaseContainer>
|
||||
<section v-if="!pending">
|
||||
<BaseSectionHeader class="mb-5"> This Asset Id is associated with multiple items</BaseSectionHeader>
|
||||
<div class="grid gap-2 grid-cols-1 sm:grid-cols-2">
|
||||
<div class="grid grid-cols-1 gap-2 sm:grid-cols-2">
|
||||
<ItemCard v-for="item in items" :key="item.id" :item="item" />
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -40,21 +40,21 @@
|
||||
<BaseCard v-if="breakpoints.lg">
|
||||
<ItemViewTable :items="itemTable.items" />
|
||||
</BaseCard>
|
||||
<div v-else class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div v-else class="grid grid-cols-1 gap-4 md:grid-cols-2">
|
||||
<ItemCard v-for="item in itemTable.items" :key="item.id" :item="item" />
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<Subtitle> Storage Locations </Subtitle>
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 card md:grid-cols-3 gap-4">
|
||||
<div class="card grid grid-cols-1 gap-4 sm:grid-cols-2 md:grid-cols-3">
|
||||
<LocationCard v-for="location in locations" :key="location.id" :location="location" />
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<Subtitle> Labels </Subtitle>
|
||||
<div class="flex gap-4 flex-wrap">
|
||||
<div class="flex flex-wrap gap-4">
|
||||
<LabelChip v-for="label in labels" :key="label.id" size="lg" :label="label" class="shadow-md" />
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
import MdiLogin from "~icons/mdi/login";
|
||||
import MdiArrowRight from "~icons/mdi/arrow-right";
|
||||
import MdiLock from "~icons/mdi/lock";
|
||||
import MdiMastodon from '~icons/mdi/mastodon';
|
||||
import MdiMastodon from "~icons/mdi/mastodon";
|
||||
|
||||
useHead({
|
||||
title: "Homebox | Organize and Tag Your Stuff",
|
||||
@@ -135,9 +135,9 @@
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex flex-col min-h-screen">
|
||||
<div class="fill-primary min-w-full absolute top-0 z-[-1]">
|
||||
<div class="bg-primary flex-col flex min-h-[20vh]" />
|
||||
<div class="flex min-h-screen flex-col">
|
||||
<div class="absolute top-0 z-[-1] min-w-full fill-primary">
|
||||
<div class="flex min-h-[20vh] flex-col bg-primary" />
|
||||
<svg
|
||||
class="fill-primary drop-shadow-xl"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
@@ -151,43 +151,58 @@
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<header class="p-4 sm:px-6 lg:p-14 sm:py-6 sm:flex sm:items-end mx-auto">
|
||||
<header class="mx-auto p-4 sm:flex sm:items-end sm:p-6 lg:p-14">
|
||||
<div>
|
||||
<h2 class="mt-1 text-4xl font-bold tracking-tight text-neutral-content sm:text-5xl lg:text-6xl flex">
|
||||
<h2 class="mt-1 flex text-4xl font-bold tracking-tight text-neutral-content sm:text-5xl lg:text-6xl">
|
||||
HomeB
|
||||
<AppLogo class="w-12 -mb-4" />
|
||||
<AppLogo class="-mb-4 w-12" />
|
||||
x
|
||||
</h2>
|
||||
<p class="ml-1 text-lg text-base-content/50">{{ $t("index.tagline") }}</p>
|
||||
</div>
|
||||
<div class="flex mt-6 sm:mt-0 gap-4 ml-auto text-neutral-content">
|
||||
<a class="tooltip" :data-tip="$t('global.github')" href="https://github.com/sysadminsmedia/homebox" target="_blank">
|
||||
<MdiGithub class="h-8 w-8" />
|
||||
<div class="ml-auto mt-6 flex gap-4 text-neutral-content sm:mt-0">
|
||||
<a
|
||||
class="tooltip"
|
||||
:data-tip="$t('global.github')"
|
||||
href="https://github.com/sysadminsmedia/homebox"
|
||||
target="_blank"
|
||||
>
|
||||
<MdiGithub class="size-8" />
|
||||
</a>
|
||||
<a href="https://noc.social/@sysadminsmedia" class="tooltip" :data-tip="$t('global.follow_dev')" target="_blank">
|
||||
<MdiMastodon class="h-8 w-8" />
|
||||
<a
|
||||
href="https://noc.social/@sysadminsmedia"
|
||||
class="tooltip"
|
||||
:data-tip="$t('global.follow_dev')"
|
||||
target="_blank"
|
||||
>
|
||||
<MdiMastodon class="size-8" />
|
||||
</a>
|
||||
<a href="https://discord.gg/aY4DCkpNA9" class="tooltip" :data-tip="$t('global.join_discord')" target="_blank">
|
||||
<MdiDiscord class="h-8 w-8" />
|
||||
<MdiDiscord class="size-8" />
|
||||
</a>
|
||||
<a href="https://homebox.sysadminsmedia.com/en/" class="tooltip" :data-tip="$t('global.read_docs')" target="_blank">
|
||||
<MdiFolder class="h-8 w-8" />
|
||||
<a
|
||||
href="https://homebox.sysadminsmedia.com/en/"
|
||||
class="tooltip"
|
||||
:data-tip="$t('global.read_docs')"
|
||||
target="_blank"
|
||||
>
|
||||
<MdiFolder class="size-8" />
|
||||
</a>
|
||||
</div>
|
||||
</header>
|
||||
<div class="grid p-6 sm:place-items-center min-h-[50vh]">
|
||||
<div class="grid min-h-[50vh] p-6 sm:place-items-center">
|
||||
<div>
|
||||
<Transition name="slide-fade">
|
||||
<form v-if="registerForm" @submit.prevent="registerUser">
|
||||
<div class="card w-max-[500px] md:w-[500px] bg-base-100 shadow-xl">
|
||||
<div class="card bg-base-100 shadow-xl md:w-[500px]">
|
||||
<div class="card-body">
|
||||
<h2 class="card-title text-2xl align-center">
|
||||
<MdiAccount class="mr-1 w-7 h-7" />
|
||||
<h2 class="card-title text-2xl">
|
||||
<MdiAccount class="mr-1 size-7" />
|
||||
{{ $t("index.register") }}
|
||||
</h2>
|
||||
<FormTextField v-model="email" :label="$t('index.set_email')" />
|
||||
<FormTextField v-model="username" :label="$t('index.set_name')" />
|
||||
<div v-if="!(groupToken == '')" class="pt-4 pb-1 text-center">
|
||||
<div v-if="!(groupToken == '')" class="pb-1 pt-4 text-center">
|
||||
<p>{{ $t("index.joining_group") }}</p>
|
||||
<button type="button" class="text-xs underline" @click="groupToken = ''">
|
||||
{{ $t("index.dont_join_group") }}
|
||||
@@ -209,16 +224,20 @@
|
||||
</div>
|
||||
</form>
|
||||
<form v-else @submit.prevent="login">
|
||||
<div class="card w-max-[500px] md:w-[500px] bg-base-100 shadow-xl">
|
||||
<div class="card bg-base-100 shadow-xl md:w-[500px]">
|
||||
<div class="card-body">
|
||||
<h2 class="card-title text-2xl align-center">
|
||||
<MdiAccount class="mr-1 w-7 h-7" />
|
||||
<h2 class="card-title text-2xl">
|
||||
<MdiAccount class="mr-1 size-7" />
|
||||
{{ $t("index.login") }}
|
||||
</h2>
|
||||
<template v-if="status && status.demo">
|
||||
<p class="text-xs italic text-center">This is a demo instance</p>
|
||||
<p class="text-xs text-center"><b>{{ $t("global.email") }}</b> demo@example.com</p>
|
||||
<p class="text-xs text-center"><b>{{ $t("global.password") }}</b> demo</p>
|
||||
<p class="text-center text-xs italic">This is a demo instance</p>
|
||||
<p class="text-center text-xs">
|
||||
<b>{{ $t("global.email") }}</b> demo@example.com
|
||||
</p>
|
||||
<p class="text-center text-xs">
|
||||
<b>{{ $t("global.password") }}</b> demo
|
||||
</p>
|
||||
</template>
|
||||
<FormTextField v-model="email" :label="$t('global.email')" />
|
||||
<FormPassword v-model="loginPassword" :label="$t('global.password')" />
|
||||
@@ -239,28 +258,28 @@
|
||||
</div>
|
||||
</form>
|
||||
</Transition>
|
||||
<div class="text-center mt-6">
|
||||
<div class="mt-6 text-center">
|
||||
<BaseButton
|
||||
v-if="status && status.allowRegistration"
|
||||
class="btn-primary btn-wide"
|
||||
@click="() => toggleLogin()"
|
||||
>
|
||||
<template #icon>
|
||||
<MdiAccountPlus v-if="!registerForm" class="w-5 h-5 swap-off" />
|
||||
<MdiLogin v-else class="w-5 h-5 swap-off" />
|
||||
<MdiArrowRight class="w-5 h-5 swap-on" />
|
||||
<MdiAccountPlus v-if="!registerForm" class="swap-off size-5" />
|
||||
<MdiLogin v-else class="swap-off size-5" />
|
||||
<MdiArrowRight class="swap-on size-5" />
|
||||
</template>
|
||||
{{ registerForm ? $t("index.login") : $t("index.register") }}
|
||||
</BaseButton>
|
||||
<p v-else class="text-base-content italic text-sm inline-flex items-center gap-2">
|
||||
<MdiLock class="w-4 h-4 inline-block" />
|
||||
<p v-else class="inline-flex items-center gap-2 text-sm italic text-base-content">
|
||||
<MdiLock class="inline-block size-4" />
|
||||
{{ $t("disabled_registration") }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<footer v-if="status" class="mt-auto text-center w-full bottom-0 pb-4">
|
||||
<footer v-if="status" class="bottom-0 mt-auto w-full pb-4 text-center">
|
||||
<p class="text-center text-sm">
|
||||
{{ $t("global.version", { version: status.build.version }) }} ~
|
||||
{{ $t("global.build", { build: status.build.commit }) }}
|
||||
|
||||
@@ -441,42 +441,42 @@
|
||||
<template>
|
||||
<BaseContainer v-if="item" class="pb-8">
|
||||
<Title>{{ item.name }}</Title>
|
||||
<dialog ref="refDialog" class="z-[999] fixed bg-transparent">
|
||||
<dialog ref="refDialog" class="fixed z-[999] bg-transparent">
|
||||
<div ref="refDialogBody" class="relative">
|
||||
<div class="absolute right-0 -mt-3 -mr-3 sm:-mt-4 sm:-mr-4 space-x-1">
|
||||
<a class="btn btn-sm sm:btn-md btn-primary btn-circle" :href="dialoged.src" download>
|
||||
<MdiDownload class="h-5 w-5" />
|
||||
<div class="absolute right-0 -mr-3 -mt-3 space-x-1 sm:-mr-4 sm:-mt-4">
|
||||
<a class="btn btn-circle btn-primary btn-sm sm:btn-md" :href="dialoged.src" download>
|
||||
<MdiDownload class="size-5" />
|
||||
</a>
|
||||
<button class="btn btn-sm sm:btn-md btn-primary btn-circle" @click="closeDialog()">
|
||||
<MdiClose class="h-5 w-5" />
|
||||
<button class="btn btn-circle btn-primary btn-sm sm:btn-md" @click="closeDialog()">
|
||||
<MdiClose class="size-5" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<img class="max-w-[80vw] max-h-[80vh]" :src="dialoged.src" />
|
||||
<img class="max-h-[80vh] max-w-[80vw]" :src="dialoged.src" />
|
||||
</div>
|
||||
</dialog>
|
||||
|
||||
<section>
|
||||
<div class="bg-base-100 rounded p-3">
|
||||
<div class="rounded bg-base-100 p-3">
|
||||
<header class="mb-2">
|
||||
<div class="flex flex-wrap items-end gap-2">
|
||||
<div class="avatar placeholder mb-auto">
|
||||
<div class="bg-neutral-focus text-neutral-content rounded-full w-12">
|
||||
<MdiPackageVariant class="h-7 w-7" />
|
||||
<div class="w-12 rounded-full bg-neutral-focus text-neutral-content">
|
||||
<MdiPackageVariant class="size-7" />
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div v-if="fullpath && fullpath.length > 0" class="text-sm breadcrumbs pt-0 pb-0">
|
||||
<div v-if="fullpath && fullpath.length > 0" class="breadcrumbs py-0 text-sm">
|
||||
<ul class="text-base-content/70">
|
||||
<li v-for="part in fullpath" :key="part.id">
|
||||
<NuxtLink :to="`/${part.type}/${part.id}`"> {{ part.name }}</NuxtLink>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<h1 class="text-2xl pb-1">
|
||||
<h1 class="pb-1 text-2xl">
|
||||
{{ item ? item.name : "" }}
|
||||
</h1>
|
||||
<div class="flex gap-1 flex-wrap text-xs">
|
||||
<div class="flex flex-wrap gap-1 text-xs">
|
||||
<div>
|
||||
Created
|
||||
<DateTime :date="item?.createdAt" />
|
||||
@@ -491,12 +491,12 @@
|
||||
</div>
|
||||
</header>
|
||||
<div class="divider my-0 mb-1"></div>
|
||||
<div class="p-1 prose max-w-[100%]">
|
||||
<div class="prose max-w-full p-1">
|
||||
<Markdown v-if="item && item.description" class="text-base" :source="item.description"> </Markdown>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-wrap items-center justify-between mb-6 mt-3">
|
||||
<div class="mb-6 mt-3 flex flex-wrap items-center justify-between">
|
||||
<div class="btn-group">
|
||||
<NuxtLink
|
||||
v-for="t in tabs"
|
||||
@@ -516,7 +516,7 @@
|
||||
<BaseCard v-if="!hasNested" collapsable>
|
||||
<template #title> Details </template>
|
||||
<template #title-actions>
|
||||
<div class="flex flex-wrap justify-between items-center mt-2 gap-4">
|
||||
<div class="mt-2 flex flex-wrap items-center justify-between gap-4">
|
||||
<label class="label cursor-pointer">
|
||||
<input v-model="preferences.showEmpty" type="checkbox" class="toggle toggle-primary" />
|
||||
<span class="label-text ml-4"> Show Empty </span>
|
||||
@@ -528,13 +528,13 @@
|
||||
<template #quantity="{ detail }">
|
||||
{{ detail.text }}
|
||||
<span
|
||||
class="opacity-0 group-hover:opacity-100 ml-4 my-0 duration-75 transition-opacity inline-flex gap-2"
|
||||
class="my-0 ml-4 inline-flex gap-2 opacity-0 transition-opacity duration-75 group-hover:opacity-100"
|
||||
>
|
||||
<button class="btn btn-circle btn-xs" @click="adjustQuantity(-1)">
|
||||
<MdiMinus class="h-3 w-3" />
|
||||
<MdiMinus class="size-3" />
|
||||
</button>
|
||||
<button class="btn btn-circle btn-xs" @click="adjustQuantity(1)">
|
||||
<MdiPlus class="h-3 w-3" />
|
||||
<MdiPlus class="size-3" />
|
||||
</button>
|
||||
</span>
|
||||
</template>
|
||||
@@ -546,10 +546,10 @@
|
||||
<BaseCard v-if="photos && photos.length > 0">
|
||||
<template #title> Photos </template>
|
||||
<div
|
||||
class="container border-t border-gray-300 p-4 flex flex-wrap gap-2 mx-auto max-h-[500px] overflow-y-scroll scroll-bg"
|
||||
class="scroll-bg container mx-auto flex max-h-[500px] flex-wrap gap-2 overflow-y-scroll border-t border-gray-300 p-4"
|
||||
>
|
||||
<button v-for="(img, i) in photos" :key="i" @click="openDialog(img)">
|
||||
<img class="rounded max-h-[200px]" :src="img.src" />
|
||||
<img class="max-h-[200px] rounded" :src="img.src" />
|
||||
</button>
|
||||
</div>
|
||||
</BaseCard>
|
||||
@@ -587,7 +587,7 @@
|
||||
</template>
|
||||
</DetailsSection>
|
||||
<div v-else>
|
||||
<p class="text-base-content/70 px-6 pb-4">No attachments found</p>
|
||||
<p class="px-6 pb-4 text-base-content/70">No attachments found</p>
|
||||
</div>
|
||||
</BaseCard>
|
||||
|
||||
|
||||
@@ -425,7 +425,7 @@
|
||||
name="text"
|
||||
:items="attachmentOpts"
|
||||
/>
|
||||
<div v-if="editState.type == 'photo'" class="flex gap-2 mt-3">
|
||||
<div v-if="editState.type == 'photo'" class="mt-3 flex gap-2">
|
||||
<input v-model="editState.primary" type="checkbox" class="checkbox" />
|
||||
<p class="text-sm">
|
||||
<span class="font-semibold">Primary Photo</span>
|
||||
@@ -439,9 +439,9 @@
|
||||
</BaseModal>
|
||||
|
||||
<section class="relative">
|
||||
<div class="my-4 justify-end flex gap-2 items-center sticky z-10 top-1">
|
||||
<div class="mr-auto tooltip tooltip-right" data-tip="Show Advanced View Options">
|
||||
<label class="label cursor-pointer mr-auto">
|
||||
<div class="sticky top-1 z-10 my-4 flex items-center justify-end gap-2">
|
||||
<div class="tooltip tooltip-right mr-auto" data-tip="Show Advanced View Options">
|
||||
<label class="label mr-auto cursor-pointer">
|
||||
<input v-model="preferences.editorAdvancedView" type="checkbox" class="toggle toggle-primary" />
|
||||
<span class="label-text ml-4"> Advanced </span>
|
||||
</label>
|
||||
@@ -452,7 +452,7 @@
|
||||
</template>
|
||||
Save
|
||||
</BaseButton>
|
||||
<BaseButton class="btn btn-sm btn-error" @click="deleteItem()">
|
||||
<BaseButton class="btn btn-error btn-sm" @click="deleteItem()">
|
||||
<MdiDelete class="mr-2" />
|
||||
Delete
|
||||
</BaseButton>
|
||||
@@ -461,9 +461,9 @@
|
||||
<BaseCard class="overflow-visible">
|
||||
<template #title> Edit Details </template>
|
||||
<template #title-actions>
|
||||
<div class="flex flex-wrap justify-between items-center mt-2 gap-4"></div>
|
||||
<div class="mt-2 flex flex-wrap items-center justify-between gap-4"></div>
|
||||
</template>
|
||||
<div class="px-5 pt-2 border-t mb-6 grid md:grid-cols-2 gap-4">
|
||||
<div class="mb-6 grid gap-4 border-t px-5 pt-2 md:grid-cols-2">
|
||||
<LocationSelector v-model="item.location" />
|
||||
<FormMultiselect v-model="item.labels" label="Labels" :items="labels ?? []" />
|
||||
<Autocomplete
|
||||
@@ -478,8 +478,8 @@
|
||||
</div>
|
||||
|
||||
<div class="border-t border-gray-300 sm:p-0">
|
||||
<div v-for="field in mainFields" :key="field.ref" class="sm:divide-y sm:divide-gray-300 grid grid-cols-1">
|
||||
<div class="pt-2 px-4 pb-4 sm:px-6 border-b border-gray-300">
|
||||
<div v-for="field in mainFields" :key="field.ref" class="grid grid-cols-1 sm:divide-y sm:divide-gray-300">
|
||||
<div class="border-b border-gray-300 px-4 pb-4 pt-2 sm:px-6">
|
||||
<FormTextArea v-if="field.type === 'textarea'" v-model="item[field.ref]" :label="field.label" inline />
|
||||
<FormTextField
|
||||
v-else-if="field.type === 'text'"
|
||||
@@ -513,25 +513,25 @@
|
||||
|
||||
<BaseCard>
|
||||
<template #title> Custom Fields </template>
|
||||
<div class="px-5 border-t divide-y divide-gray-300 space-y-4">
|
||||
<div class="space-y-4 divide-y divide-gray-300 border-t px-5">
|
||||
<div
|
||||
v-for="(field, idx) in item.fields"
|
||||
:key="`field-${idx}`"
|
||||
class="grid grid-cols-2 md:grid-cols-4 gap-2"
|
||||
class="grid grid-cols-2 gap-2 md:grid-cols-4"
|
||||
>
|
||||
<!-- <FormSelect v-model:value="field.type" label="Field Type" :items="fieldTypes" value-key="value" /> -->
|
||||
<FormTextField v-model="field.name" label="Name" />
|
||||
<div class="flex items-end col-span-3">
|
||||
<div class="col-span-3 flex items-end">
|
||||
<FormTextField v-model="field.textValue" label="Value" />
|
||||
<div class="tooltip" data-tip="Delete">
|
||||
<button class="btn btn-sm btn-square mb-2 ml-2" @click="item.fields.splice(idx, 1)">
|
||||
<button class="btn btn-square btn-sm mb-2 ml-2" @click="item.fields.splice(idx, 1)">
|
||||
<MdiDelete />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="px-5 pb-4 mt-4 flex justify-end">
|
||||
<div class="mt-4 flex justify-end px-5 pb-4">
|
||||
<BaseButton size="sm" @click="addField"> Add </BaseButton>
|
||||
</div>
|
||||
</BaseCard>
|
||||
@@ -539,7 +539,7 @@
|
||||
<div
|
||||
v-if="preferences.editorAdvancedView"
|
||||
ref="attDropZone"
|
||||
class="overflow-visible card bg-base-100 shadow-xl sm:rounded-lg"
|
||||
class="card overflow-visible bg-base-100 shadow-xl sm:rounded-lg"
|
||||
>
|
||||
<div class="px-4 py-5 sm:px-6">
|
||||
<h3 class="text-lg font-medium leading-6">Attachments</h3>
|
||||
@@ -555,7 +555,7 @@
|
||||
</div>
|
||||
<button
|
||||
v-else
|
||||
class="h-24 w-full border-2 border-primary border-dashed grid place-content-center"
|
||||
class="grid h-24 w-full place-content-center border-2 border-dashed border-primary"
|
||||
@click="clickUpload"
|
||||
>
|
||||
<input ref="refAttachmentInput" hidden type="file" @change="uploadImage" />
|
||||
@@ -570,20 +570,20 @@
|
||||
:key="attachment.id"
|
||||
class="grid grid-cols-6 justify-between py-3 pl-3 pr-4 text-sm"
|
||||
>
|
||||
<p class="my-auto col-span-4">
|
||||
<p class="col-span-4 my-auto">
|
||||
{{ attachment.document.title }}
|
||||
</p>
|
||||
<p class="my-auto">
|
||||
{{ capitalize(attachment.type) }}
|
||||
</p>
|
||||
<div class="flex gap-2 justify-end">
|
||||
<div class="flex justify-end gap-2">
|
||||
<div class="tooltip" data-tip="Delete">
|
||||
<button class="btn btn-sm btn-square" @click="deleteAttachment(attachment.id)">
|
||||
<button class="btn btn-square btn-sm" @click="deleteAttachment(attachment.id)">
|
||||
<MdiDelete />
|
||||
</button>
|
||||
</div>
|
||||
<div class="tooltip" data-tip="Edit">
|
||||
<button class="btn btn-sm btn-square" @click="openAttachmentEditDialog(attachment)">
|
||||
<button class="btn btn-square btn-sm" @click="openAttachmentEditDialog(attachment)">
|
||||
<MdiPencil />
|
||||
</button>
|
||||
</div>
|
||||
@@ -593,7 +593,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="preferences.editorAdvancedView" class="overflow-visible card bg-base-100 shadow-xl sm:rounded-lg">
|
||||
<div v-if="preferences.editorAdvancedView" class="card overflow-visible bg-base-100 shadow-xl sm:rounded-lg">
|
||||
<div class="px-4 py-5 sm:px-6">
|
||||
<h3 class="text-lg font-medium leading-6">Purchase Details</h3>
|
||||
</div>
|
||||
@@ -601,9 +601,9 @@
|
||||
<div
|
||||
v-for="field in purchaseFields"
|
||||
:key="field.ref"
|
||||
class="sm:divide-y sm:divide-gray-300 grid grid-cols-1"
|
||||
class="grid grid-cols-1 sm:divide-y sm:divide-gray-300"
|
||||
>
|
||||
<div class="pt-2 px-4 pb-4 sm:px-6 border-b border-gray-300">
|
||||
<div class="border-b border-gray-300 px-4 pb-4 pt-2 sm:px-6">
|
||||
<FormTextArea v-if="field.type === 'textarea'" v-model="item[field.ref]" :label="field.label" inline />
|
||||
<FormTextField
|
||||
v-else-if="field.type === 'text'"
|
||||
@@ -635,7 +635,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="preferences.editorAdvancedView" class="overflow-visible card bg-base-100 shadow-xl sm:rounded-lg">
|
||||
<div v-if="preferences.editorAdvancedView" class="card overflow-visible bg-base-100 shadow-xl sm:rounded-lg">
|
||||
<div class="px-4 py-5 sm:px-6">
|
||||
<h3 class="text-lg font-medium leading-6">Warranty Details</h3>
|
||||
</div>
|
||||
@@ -643,9 +643,9 @@
|
||||
<div
|
||||
v-for="field in warrantyFields"
|
||||
:key="field.ref"
|
||||
class="sm:divide-y sm:divide-gray-300 grid grid-cols-1"
|
||||
class="grid grid-cols-1 sm:divide-y sm:divide-gray-300"
|
||||
>
|
||||
<div class="pt-2 px-4 pb-4 sm:px-6 border-b border-gray-300">
|
||||
<div class="border-b border-gray-300 px-4 pb-4 pt-2 sm:px-6">
|
||||
<FormTextArea v-if="field.type === 'textarea'" v-model="item[field.ref]" :label="field.label" inline />
|
||||
<FormTextField
|
||||
v-else-if="field.type === 'text'"
|
||||
@@ -677,13 +677,13 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="preferences.editorAdvancedView" class="overflow-visible card bg-base-100 shadow-xl sm:rounded-lg">
|
||||
<div v-if="preferences.editorAdvancedView" class="card overflow-visible bg-base-100 shadow-xl sm:rounded-lg">
|
||||
<div class="px-4 py-5 sm:px-6">
|
||||
<h3 class="text-lg font-medium leading-6">Sold Details</h3>
|
||||
</div>
|
||||
<div class="border-t border-gray-300 sm:p-0">
|
||||
<div v-for="field in soldFields" :key="field.ref" class="sm:divide-y sm:divide-gray-300 grid grid-cols-1">
|
||||
<div class="pt-2 pb-4 px-4 sm:px-6 border-b border-gray-300">
|
||||
<div v-for="field in soldFields" :key="field.ref" class="grid grid-cols-1 sm:divide-y sm:divide-gray-300">
|
||||
<div class="border-b border-gray-300 px-4 pb-4 pt-2 sm:px-6">
|
||||
<FormTextArea v-if="field.type === 'textarea'" v-model="item[field.ref]" :label="field.label" inline />
|
||||
<FormTextField
|
||||
v-else-if="field.type === 'text'"
|
||||
|
||||
@@ -188,7 +188,7 @@
|
||||
<DatePicker v-model="entry.scheduledDate" label="Scheduled Date" />
|
||||
<FormTextArea v-model="entry.description" label="Notes" />
|
||||
<FormTextField v-model="entry.cost" autofocus label="Cost" />
|
||||
<div class="py-2 flex justify-end">
|
||||
<div class="flex justify-end py-2">
|
||||
<BaseButton type="submit" class="ml-2 mt-2">
|
||||
<template #icon>
|
||||
<MdiPost />
|
||||
@@ -200,11 +200,11 @@
|
||||
</BaseModal>
|
||||
|
||||
<section class="space-y-6">
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
|
||||
<div class="grid grid-cols-1 gap-6 md:grid-cols-3">
|
||||
<StatCard
|
||||
v-for="stat in stats"
|
||||
:key="stat.id"
|
||||
class="stats block shadow-xl border-l-primary"
|
||||
class="stats block border-l-primary shadow-xl"
|
||||
:title="stat.title"
|
||||
:value="stat.value"
|
||||
:type="stat.type"
|
||||
@@ -228,7 +228,7 @@
|
||||
</div>
|
||||
<div class="container space-y-6">
|
||||
<BaseCard v-for="e in log.entries" :key="e.id">
|
||||
<BaseSectionHeader class="p-6 border-b border-b-gray-300">
|
||||
<BaseSectionHeader class="border-b border-b-gray-300 p-6">
|
||||
<span class="text-base-content">
|
||||
{{ e.name }}
|
||||
</span>
|
||||
@@ -253,7 +253,7 @@
|
||||
<div class="p-6">
|
||||
<Markdown :source="e.description" />
|
||||
</div>
|
||||
<div class="flex justify-end p-4 gap-1">
|
||||
<div class="flex justify-end gap-1 p-4">
|
||||
<BaseButton size="sm" @click="openEditDialog(e)">
|
||||
<template #icon>
|
||||
<MdiEdit />
|
||||
@@ -274,7 +274,7 @@
|
||||
class="relative block w-full rounded-lg border-2 border-dashed border-base-content p-12 text-center"
|
||||
@click="newEntry()"
|
||||
>
|
||||
<MdiWrenchClock class="h-16 w-16 inline" />
|
||||
<MdiWrenchClock class="inline size-16" />
|
||||
<span class="mt-2 block text-sm font-medium text-gray-900"> Create Your First Entry </span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -40,9 +40,9 @@
|
||||
<template>
|
||||
<BaseContainer cmp="section">
|
||||
<BaseSectionHeader> Add an Item To Your Inventory </BaseSectionHeader>
|
||||
<form class="max-w-3xl mx-auto my-5 space-y-6" @submit.prevent="submit">
|
||||
<div class="divider collapse-title px-0 cursor-pointer">Required Information</div>
|
||||
<div class="bg-base-200 card">
|
||||
<form class="mx-auto my-5 max-w-3xl space-y-6" @submit.prevent="submit">
|
||||
<div class="collapse-title divider cursor-pointer px-0">Required Information</div>
|
||||
<div class="card bg-base-200">
|
||||
<div class="card-body">
|
||||
<FormTextField v-model="form.name" label="Name" />
|
||||
<FormTextArea v-model="form.description" label="Description" limit="1000" />
|
||||
@@ -76,7 +76,7 @@
|
||||
</div>
|
||||
<div v-if="show.sold" class="card bg-base-200">
|
||||
<div class="card-body">
|
||||
<div class="grid md:grid-cols-2 gap-2">
|
||||
<div class="grid gap-2 md:grid-cols-2">
|
||||
<FormTextField v-model="form.soldTime" label="Sold Time" />
|
||||
<FormTextField v-model="form.soldPrice" label="Sold Price" />
|
||||
<FormTextField v-model="form.soldTo" label="Sold To" />
|
||||
|
||||
@@ -336,10 +336,10 @@
|
||||
<template>
|
||||
<BaseContainer class="mb-16">
|
||||
<div v-if="locations && labels">
|
||||
<div class="flex flex-wrap md:flex-nowrap gap-4 items-end">
|
||||
<div class="flex flex-wrap items-end gap-4 md:flex-nowrap">
|
||||
<div class="w-full">
|
||||
<FormTextField v-model="query" :placeholder="$t('global.search')" />
|
||||
<div v-if="byAssetId" class="text-sm pl-2 pt-2">
|
||||
<div v-if="byAssetId" class="pl-2 pt-2 text-sm">
|
||||
<p>{{ $t("items.query_id", { id: parsedAssetId }) }}</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -352,14 +352,14 @@
|
||||
</BaseButton>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-wrap md:flex-nowrap gap-2 w-full py-2">
|
||||
<div class="flex w-full flex-wrap gap-2 py-2 md:flex-nowrap">
|
||||
<SearchFilter v-model="selectedLocations" :label="$t('global.locations')" :options="locationFlatTree">
|
||||
<template #display="{ item }">
|
||||
<div>
|
||||
<div class="flex w-full">
|
||||
{{ item.name }}
|
||||
</div>
|
||||
<div v-if="item.name != item.treeString" class="text-xs mt-1">
|
||||
<div v-if="item.name != item.treeString" class="mt-1 text-xs">
|
||||
{{ item.treeString }}
|
||||
</div>
|
||||
</div>
|
||||
@@ -370,21 +370,21 @@
|
||||
<label tabindex="0" class="btn btn-xs">{{ $t("items.options") }}</label>
|
||||
<div
|
||||
tabindex="0"
|
||||
class="dropdown-content mt-1 max-h-72 p-4 w-64 overflow-auto shadow bg-base-100 rounded-md -translate-x-24"
|
||||
class="dropdown-content mt-1 max-h-72 w-64 -translate-x-24 overflow-auto rounded-md bg-base-100 p-4 shadow"
|
||||
>
|
||||
<label class="label cursor-pointer mr-auto">
|
||||
<input v-model="includeArchived" type="checkbox" class="toggle toggle-sm toggle-primary" />
|
||||
<label class="label mr-auto cursor-pointer">
|
||||
<input v-model="includeArchived" type="checkbox" class="toggle toggle-primary toggle-sm" />
|
||||
<span class="label-text ml-4"> {{ $t("items.include_archive") }} </span>
|
||||
</label>
|
||||
<label class="label cursor-pointer mr-auto">
|
||||
<input v-model="fieldSelector" type="checkbox" class="toggle toggle-sm toggle-primary" />
|
||||
<label class="label mr-auto cursor-pointer">
|
||||
<input v-model="fieldSelector" type="checkbox" class="toggle toggle-primary toggle-sm" />
|
||||
<span class="label-text ml-4"> {{ $t("items.field_selector") }} </span>
|
||||
</label>
|
||||
<label class="label cursor-pointer mr-auto">
|
||||
<input v-model="negateLabels" type="checkbox" class="toggle toggle-sm toggle-primary" />
|
||||
<label class="label mr-auto cursor-pointer">
|
||||
<input v-model="negateLabels" type="checkbox" class="toggle toggle-primary toggle-sm" />
|
||||
<span class="label-text ml-4"> {{ $t("items.negate_labels") }} </span>
|
||||
</label>
|
||||
<label class="label cursor-pointer mr-auto">
|
||||
<label class="label mr-auto cursor-pointer">
|
||||
<select v-model="orderBy" class="select select-bordered select-sm">
|
||||
<option value="name" selected>{{ $t("global.name") }}</option>
|
||||
<option value="createdAt">{{ $t("items.created_at") }}</option>
|
||||
@@ -393,14 +393,14 @@
|
||||
<span class="label-text ml-4"> {{ $t("items.order_by") }} </span>
|
||||
</label>
|
||||
<hr class="my-2" />
|
||||
<BaseButton class="btn-block btn-sm" @click="reset"> {{ $t("items.reset_search") }} </BaseButton>
|
||||
<BaseButton class="btn-sm btn-block" @click="reset"> {{ $t("items.reset_search") }} </BaseButton>
|
||||
</div>
|
||||
</div>
|
||||
<div class="dropdown ml-auto dropdown-end">
|
||||
<div class="dropdown dropdown-end ml-auto">
|
||||
<label tabindex="0" class="btn btn-xs">{{ $t("items.tips") }}</label>
|
||||
<div
|
||||
tabindex="0"
|
||||
class="dropdown-content mt-1 p-4 w-[325px] text-sm overflow-auto shadow bg-base-100 rounded-md"
|
||||
class="dropdown-content mt-1 w-[325px] overflow-auto rounded-md bg-base-100 p-4 text-sm shadow"
|
||||
>
|
||||
<p class="text-base">{{ $t("items.tips_sub") }}</p>
|
||||
<ul class="mt-1 list-disc pl-6">
|
||||
@@ -417,7 +417,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="fieldSelector" class="py-4 space-y-2">
|
||||
<div v-if="fieldSelector" class="space-y-2 py-4">
|
||||
<p>{{ $t("items.custom_fields") }}</p>
|
||||
<div v-for="(f, idx) in fieldTuples" :key="idx" class="flex flex-wrap gap-2">
|
||||
<div class="form-control w-full max-w-xs">
|
||||
@@ -426,7 +426,7 @@
|
||||
</label>
|
||||
<select
|
||||
v-model="fieldTuples[idx][0]"
|
||||
class="select-bordered select"
|
||||
class="select select-bordered"
|
||||
:items="allFields ?? []"
|
||||
@change="fetchValues(f[0])"
|
||||
>
|
||||
@@ -437,16 +437,16 @@
|
||||
<label class="label">
|
||||
<span class="label-text">{{ $t("items.field_value") }}</span>
|
||||
</label>
|
||||
<select v-model="fieldTuples[idx][1]" class="select-bordered select" :items="fieldValuesCache[f[0]]">
|
||||
<select v-model="fieldTuples[idx][1]" class="select select-bordered" :items="fieldValuesCache[f[0]]">
|
||||
<option v-for="v in fieldValuesCache[f[0]]" :key="v" :value="v">{{ v }}</option>
|
||||
</select>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-square btn-sm md:ml-0 ml-auto mt-auto mb-2"
|
||||
class="btn btn-square btn-sm mb-2 ml-auto mt-auto md:ml-0"
|
||||
@click="fieldTuples.splice(idx, 1)"
|
||||
>
|
||||
<MdiDelete class="w-5 h-5" />
|
||||
<MdiDelete class="size-5" />
|
||||
</button>
|
||||
</div>
|
||||
<BaseButton type="button" class="btn-sm mt-2" @click="() => fieldTuples.push(['', ''])">
|
||||
@@ -457,30 +457,30 @@
|
||||
|
||||
<section class="mt-10">
|
||||
<BaseSectionHeader ref="itemsTitle"> {{ $t("global.items") }} </BaseSectionHeader>
|
||||
<p class="text-base font-medium flex items-center">
|
||||
<p class="flex items-center text-base font-medium">
|
||||
{{ $t("items.results", { total: total }) }}
|
||||
<span class="text-base ml-auto"> {{ $t("items.pages", { page: page, totalPages: totalPages }) }} </span>
|
||||
<span class="ml-auto text-base"> {{ $t("items.pages", { page: page, totalPages: totalPages }) }} </span>
|
||||
</p>
|
||||
|
||||
<div ref="cardgrid" class="grid mt-4 grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-4">
|
||||
<div ref="cardgrid" class="mt-4 grid grid-cols-1 gap-4 sm:grid-cols-2 md:grid-cols-3">
|
||||
<ItemCard v-for="item in items" :key="item.id" :item="item" />
|
||||
|
||||
<div class="hidden first:inline text-xl">{{ $t("items.no_results") }}</div>
|
||||
<div class="hidden text-xl first:inline">{{ $t("items.no_results") }}</div>
|
||||
</div>
|
||||
<div v-if="items.length > 0 && (hasNext || hasPrev)" class="mt-10 flex gap-2 flex-col items-center">
|
||||
<div v-if="items.length > 0 && (hasNext || hasPrev)" class="mt-10 flex flex-col items-center gap-2">
|
||||
<div class="flex">
|
||||
<div class="btn-group">
|
||||
<button :disabled="!hasPrev" class="btn text-no-transform" @click="prev">
|
||||
<MdiChevronLeft class="mr-1 h-6 w-6" name="mdi-chevron-left" />
|
||||
<button :disabled="!hasPrev" class="text-no-transform btn" @click="prev">
|
||||
<MdiChevronLeft class="mr-1 size-6" name="mdi-chevron-left" />
|
||||
{{ $t("items.prev_page") }}
|
||||
</button>
|
||||
<button v-if="hasPrev" class="btn text-no-transform" @click="page = 1">{{ $t("items.first") }}</button>
|
||||
<button v-if="hasNext" class="btn text-no-transform" @click="page = totalPages">
|
||||
<button v-if="hasPrev" class="text-no-transform btn" @click="page = 1">{{ $t("items.first") }}</button>
|
||||
<button v-if="hasNext" class="text-no-transform btn" @click="page = totalPages">
|
||||
{{ $t("items.last") }}
|
||||
</button>
|
||||
<button :disabled="!hasNext" class="btn text-no-transform" @click="next">
|
||||
<button :disabled="!hasNext" class="text-no-transform btn" @click="next">
|
||||
{{ $t("items.next_page") }}
|
||||
<MdiChevronRight class="ml-1 h-6 w-6" name="mdi-chevron-right" />
|
||||
<MdiChevronRight class="ml-1 size-6" name="mdi-chevron-right" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -106,28 +106,28 @@
|
||||
</BaseModal>
|
||||
|
||||
<BaseContainer v-if="label">
|
||||
<div class="bg-base-100 rounded p-3">
|
||||
<div class="rounded bg-base-100 p-3">
|
||||
<header class="mb-2">
|
||||
<div class="flex flex-wrap items-end gap-2">
|
||||
<div class="avatar placeholder mb-auto">
|
||||
<div class="bg-neutral-focus text-neutral-content rounded-full w-12">
|
||||
<MdiPackageVariant class="h-7 w-7" />
|
||||
<div class="w-12 rounded-full bg-neutral-focus text-neutral-content">
|
||||
<MdiPackageVariant class="size-7" />
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h1 class="text-2xl pb-1 flex items-center gap-3">
|
||||
<h1 class="flex items-center gap-3 pb-1 text-2xl">
|
||||
{{ label ? label.name : "" }}
|
||||
|
||||
<div
|
||||
v-if="items && items.totalPrice"
|
||||
class="text-xs bg-secondary text-secondary-content rounded-full px-2 py-1"
|
||||
class="rounded-full bg-secondary px-2 py-1 text-xs text-secondary-content"
|
||||
>
|
||||
<div>
|
||||
<Currency :amount="items.totalPrice" />
|
||||
</div>
|
||||
</div>
|
||||
</h1>
|
||||
<div class="flex gap-1 flex-wrap text-xs">
|
||||
<div class="flex flex-wrap gap-1 text-xs">
|
||||
<div>
|
||||
Created
|
||||
<DateTime :date="label?.createdAt" />
|
||||
|
||||
@@ -121,16 +121,16 @@
|
||||
</BaseModal>
|
||||
|
||||
<BaseContainer v-if="location">
|
||||
<div class="bg-base-100 rounded p-3">
|
||||
<div class="rounded bg-base-100 p-3">
|
||||
<header class="mb-2">
|
||||
<div class="flex flex-wrap items-end gap-2">
|
||||
<div class="avatar placeholder mb-auto">
|
||||
<div class="bg-neutral-focus text-neutral-content rounded-full w-12">
|
||||
<MdiPackageVariant name="mdi-package-variant" class="h-7 w-7" />
|
||||
<div class="w-12 rounded-full bg-neutral-focus text-neutral-content">
|
||||
<MdiPackageVariant name="mdi-package-variant" class="size-7" />
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div v-if="location?.parent" class="text-sm breadcrumbs pt-0 pb-0">
|
||||
<div v-if="location?.parent" class="breadcrumbs py-0 text-sm">
|
||||
<ul class="text-base-content/70">
|
||||
<li>
|
||||
<NuxtLink :to="`/location/${location.parent.id}`"> {{ location.parent.name }}</NuxtLink>
|
||||
@@ -138,19 +138,19 @@
|
||||
<li>{{ location.name }}</li>
|
||||
</ul>
|
||||
</div>
|
||||
<h1 class="text-2xl pb-1 flex items-center gap-3">
|
||||
<h1 class="flex items-center gap-3 pb-1 text-2xl">
|
||||
{{ location ? location.name : "" }}
|
||||
|
||||
<div
|
||||
v-if="location && location.totalPrice"
|
||||
class="text-xs bg-secondary text-secondary-content rounded-full px-2 py-1"
|
||||
class="rounded-full bg-secondary px-2 py-1 text-xs text-secondary-content"
|
||||
>
|
||||
<div>
|
||||
<Currency :amount="location.totalPrice" />
|
||||
</div>
|
||||
</div>
|
||||
</h1>
|
||||
<div class="flex gap-1 flex-wrap text-xs">
|
||||
<div class="flex flex-wrap gap-1 text-xs">
|
||||
<div>
|
||||
Created
|
||||
<DateTime :date="location?.createdAt" />
|
||||
@@ -181,7 +181,7 @@
|
||||
|
||||
<section v-if="location && location.children.length > 0" class="mt-6">
|
||||
<BaseSectionHeader class="mb-5"> Child Locations </BaseSectionHeader>
|
||||
<div class="grid gap-2 grid-cols-1 sm:grid-cols-3">
|
||||
<div class="grid grid-cols-1 gap-2 sm:grid-cols-3">
|
||||
<LocationCard v-for="item in location.children" :key="item.id" :location="item" />
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -65,9 +65,9 @@
|
||||
<BaseSectionHeader> Locations </BaseSectionHeader>
|
||||
<BaseCard>
|
||||
<div class="p-4">
|
||||
<div class="flex justify-end mb-2">
|
||||
<div class="mb-2 flex justify-end">
|
||||
<div class="btn-group">
|
||||
<button class="btn btn-sm tooltip tooltip-top" data-tip="Collapse Tree" @click="closeAll">
|
||||
<button class="btn tooltip tooltip-top btn-sm" data-tip="Collapse Tree" @click="closeAll">
|
||||
<MdiCollapseAllOutline />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -319,7 +319,7 @@
|
||||
</BaseModal>
|
||||
|
||||
<BaseModal v-model="notifierDialog">
|
||||
<template #title> {{ $t("profile.notifier_modal", {type: (notifier != null)}) }} </template>
|
||||
<template #title> {{ $t("profile.notifier_modal", { type: notifier != null }) }} </template>
|
||||
|
||||
<form @submit.prevent="createNotifier">
|
||||
<template v-if="notifier">
|
||||
@@ -329,19 +329,21 @@
|
||||
<FormCheckbox v-model="notifier.isActive" :label="$t('profile.enabled')" />
|
||||
</div>
|
||||
</template>
|
||||
<div class="flex gap-2 justify-between mt-4">
|
||||
<BaseButton :disabled="!(notifier && notifier.url)" type="button" @click="testNotifier"> {{ $t("profile.test") }} </BaseButton>
|
||||
<div class="mt-4 flex justify-between gap-2">
|
||||
<BaseButton :disabled="!(notifier && notifier.url)" type="button" @click="testNotifier">
|
||||
{{ $t("profile.test") }}
|
||||
</BaseButton>
|
||||
<BaseButton type="submit"> {{ $t("global.submit") }} </BaseButton>
|
||||
</div>
|
||||
</form>
|
||||
</BaseModal>
|
||||
|
||||
<BaseContainer class="flex flex-col gap-4 mb-6">
|
||||
<BaseContainer class="mb-6 flex flex-col gap-4">
|
||||
<BaseCard>
|
||||
<template #title>
|
||||
<BaseSectionHeader>
|
||||
<MdiAccount class="mr-2 -mt-1 text-base-600" />
|
||||
<span class="text-base-600"> {{ $t("profile.user_profile") }} </span>
|
||||
<MdiAccount class="-mt-1 mr-2" />
|
||||
<span> {{ $t("profile.user_profile") }} </span>
|
||||
<template #description> {{ $t("profile.user_profile_sub") }} </template>
|
||||
</BaseSectionHeader>
|
||||
</template>
|
||||
@@ -353,12 +355,12 @@
|
||||
<BaseButton size="sm" @click="openPassChange"> {{ $t("profile.change_password") }} </BaseButton>
|
||||
<BaseButton size="sm" @click="generateToken"> {{ $t("profile.gen_invite") }} </BaseButton>
|
||||
</div>
|
||||
<div v-if="token" class="pt-4 flex items-center pl-1">
|
||||
<CopyText class="mr-2 btn-primary btn btn-outline btn-square btn-sm" :text="tokenUrl" />
|
||||
<div v-if="token" class="flex items-center pl-1 pt-4">
|
||||
<CopyText class="btn btn-square btn-outline btn-primary btn-sm mr-2" :text="tokenUrl" />
|
||||
{{ tokenUrl }}
|
||||
</div>
|
||||
<div v-if="token" class="pt-4 flex items-center pl-1">
|
||||
<CopyText class="mr-2 btn-primary btn btn-outline btn-square btn-sm" :text="token" />
|
||||
<div v-if="token" class="flex items-center pl-1 pt-4">
|
||||
<CopyText class="btn btn-square btn-outline btn-primary btn-sm mr-2" :text="token" />
|
||||
{{ token }}
|
||||
</div>
|
||||
</div>
|
||||
@@ -367,8 +369,8 @@
|
||||
<BaseCard>
|
||||
<template #title>
|
||||
<BaseSectionHeader>
|
||||
<MdiMegaphone class="mr-2 -mt-1 text-base-600" />
|
||||
<span class="text-base-600"> {{ $t("profile.notifiers") }} </span>
|
||||
<MdiMegaphone class="-mt-1 mr-2" />
|
||||
<span class=""> {{ $t("profile.notifiers") }} </span>
|
||||
<template #description> {{ $t("profile.notifiers_sub") }} </template>
|
||||
</BaseSectionHeader>
|
||||
</template>
|
||||
@@ -377,20 +379,20 @@
|
||||
<article v-for="n in notifiers.data.value" :key="n.id" class="p-2">
|
||||
<div class="flex flex-wrap items-center gap-2">
|
||||
<p class="mr-auto text-lg">{{ n.name }}</p>
|
||||
<div class="flex gap-2 justify-end">
|
||||
<div class="flex justify-end gap-2">
|
||||
<div class="tooltip" data-tip="Delete">
|
||||
<button class="btn btn-sm btn-square" @click="deleteNotifier(n.id)">
|
||||
<button class="btn btn-square btn-sm" @click="deleteNotifier(n.id)">
|
||||
<MdiDelete />
|
||||
</button>
|
||||
</div>
|
||||
<div class="tooltip" data-tip="Edit">
|
||||
<button class="btn btn-sm btn-square" @click="openNotifierDialog(n)">
|
||||
<button class="btn btn-square btn-sm" @click="openNotifierDialog(n)">
|
||||
<MdiPencil />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-between py-1 flex-wrap text-sm">
|
||||
<div class="flex flex-wrap justify-between py-1 text-sm">
|
||||
<p>
|
||||
<span v-if="n.isActive" class="badge badge-success"> {{ $t("profile.active") }} </span>
|
||||
<span v-else class="badge badge-error"> {{ $t("profile.inactive") }} </span>
|
||||
@@ -411,8 +413,8 @@
|
||||
<BaseCard>
|
||||
<template #title>
|
||||
<BaseSectionHeader class="pb-0">
|
||||
<MdiAccountMultiple class="mr-2 -mt-1 text-base-600" />
|
||||
<span class="text-base-600"> {{ $t("profile.group_settings") }} </span>
|
||||
<MdiAccountMultiple class="-mt-1 mr-2" />
|
||||
<span class=""> {{ $t("profile.group_settings") }} </span>
|
||||
<template #description>
|
||||
{{ $t("profile.group_settings_sub") }}
|
||||
</template>
|
||||
@@ -432,8 +434,8 @@
|
||||
<BaseCard>
|
||||
<template #title>
|
||||
<BaseSectionHeader>
|
||||
<MdiFill class="mr-2 text-base-600" />
|
||||
<span class="text-base-600"> {{ $t("profile.theme_settings") }} </span>
|
||||
<MdiFill class="mr-2" />
|
||||
<span class=""> {{ $t("profile.theme_settings") }} </span>
|
||||
<template #description>
|
||||
{{ $t("profile.theme_settings_sub") }}
|
||||
</template>
|
||||
@@ -445,30 +447,30 @@
|
||||
<div
|
||||
v-for="theme in themes"
|
||||
:key="theme.value"
|
||||
class="border-base-content/20 hover:border-base-content/40 outline-base-content overflow-hidden rounded-lg border outline-2 outline-offset-2"
|
||||
class="overflow-hidden rounded-lg border border-base-content/20 outline-2 outline-offset-2 outline-base-content hover:border-base-content/40"
|
||||
:data-theme="theme.value"
|
||||
:data-set-theme="theme.value"
|
||||
data-act-class="outline"
|
||||
@click="setTheme(theme.value)"
|
||||
>
|
||||
<div :data-theme="theme.value" class="bg-base-100 text-base-content w-full cursor-pointer font-sans">
|
||||
<div :data-theme="theme.value" class="w-full cursor-pointer bg-base-100 font-sans text-base-content">
|
||||
<div class="grid grid-cols-5 grid-rows-3">
|
||||
<div class="bg-base-200 col-start-1 row-span-2 row-start-1"></div>
|
||||
<div class="bg-base-300 col-start-1 row-start-3"></div>
|
||||
<div class="bg-base-100 col-span-4 col-start-2 row-span-3 row-start-1 flex flex-col gap-1 p-2">
|
||||
<div class="col-start-1 row-span-2 row-start-1 bg-base-200"></div>
|
||||
<div class="col-start-1 row-start-3 bg-base-300"></div>
|
||||
<div class="col-span-4 col-start-2 row-span-3 row-start-1 flex flex-col gap-1 bg-base-100 p-2">
|
||||
<div class="font-bold">{{ theme.label }}</div>
|
||||
<div class="flex flex-wrap gap-1">
|
||||
<div class="bg-primary flex aspect-square w-5 items-center justify-center rounded lg:w-6">
|
||||
<div class="text-primary-content text-sm font-bold">A</div>
|
||||
<div class="flex aspect-1 w-5 items-center justify-center rounded bg-primary lg:w-6">
|
||||
<div class="text-sm font-bold text-primary-content">A</div>
|
||||
</div>
|
||||
<div class="bg-secondary flex aspect-square w-5 items-center justify-center rounded lg:w-6">
|
||||
<div class="text-secondary-content text-sm font-bold">A</div>
|
||||
<div class="flex aspect-1 w-5 items-center justify-center rounded bg-secondary lg:w-6">
|
||||
<div class="text-sm font-bold text-secondary-content">A</div>
|
||||
</div>
|
||||
<div class="bg-accent flex aspect-square w-5 items-center justify-center rounded lg:w-6">
|
||||
<div class="text-accent-content text-sm font-bold">A</div>
|
||||
<div class="flex aspect-1 w-5 items-center justify-center rounded bg-accent lg:w-6">
|
||||
<div class="text-sm font-bold text-accent-content">A</div>
|
||||
</div>
|
||||
<div class="bg-neutral flex aspect-square w-5 items-center justify-center rounded lg:w-6">
|
||||
<div class="text-neutral-content text-sm font-bold">A</div>
|
||||
<div class="flex aspect-1 w-5 items-center justify-center rounded bg-neutral lg:w-6">
|
||||
<div class="text-sm font-bold text-neutral-content">A</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -482,13 +484,15 @@
|
||||
<BaseCard>
|
||||
<template #title>
|
||||
<BaseSectionHeader>
|
||||
<MdiDelete class="mr-2 -mt-1 text-base-600" />
|
||||
<span class="text-base-600"> {{ $t("profile.delete_account") }} </span>
|
||||
<MdiDelete class="-mt-1 mr-2" />
|
||||
<span class=""> {{ $t("profile.delete_account") }} </span>
|
||||
<template #description> {{ $t("profile.delete_account_sub") }} </template>
|
||||
</BaseSectionHeader>
|
||||
</template>
|
||||
<div class="p-4 px-6 border-t-2 border-gray-300">
|
||||
<BaseButton size="sm" class="btn-error" @click="deleteProfile"> {{ $t("profile.delete_account") }} </BaseButton>
|
||||
<div class="border-t-2 border-gray-300 p-4 px-6">
|
||||
<BaseButton size="sm" class="btn-error" @click="deleteProfile">
|
||||
{{ $t("profile.delete_account") }}
|
||||
</BaseButton>
|
||||
</div>
|
||||
</BaseCard>
|
||||
</BaseContainer>
|
||||
|
||||
@@ -296,7 +296,7 @@
|
||||
<template>
|
||||
<div class="print:hidden">
|
||||
<AppToast />
|
||||
<div class="container max-w-4xl mx-auto p-4 pt-6 prose">
|
||||
<div class="container prose mx-auto max-w-4xl p-4 pt-6">
|
||||
<h1>Homebox Label Generator</h1>
|
||||
<p>
|
||||
The Homebox Label Generator is a tool to help you print labels for your Homebox inventory. These are intended to
|
||||
@@ -332,14 +332,14 @@
|
||||
</ol>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="flex gap-2 flex-wrap">
|
||||
<div class="flex flex-wrap gap-2">
|
||||
<NuxtLink href="/tools">Tools</NuxtLink>
|
||||
<NuxtLink href="/home">Home</NuxtLink>
|
||||
</div>
|
||||
</div>
|
||||
<div class="divider max-w-4xl mx-auto"></div>
|
||||
<div class="container max-w-4xl mx-auto p-4">
|
||||
<div class="grid grid-cols-2 mx-auto gap-3">
|
||||
<div class="divider mx-auto max-w-4xl"></div>
|
||||
<div class="container mx-auto max-w-4xl p-4">
|
||||
<div class="mx-auto grid grid-cols-2 gap-3">
|
||||
<div v-for="(prop, i) in propertyInputs" :key="i" class="form-control w-full max-w-xs">
|
||||
<label class="label">
|
||||
<span class="label-text">{{ prop.label }}</span>
|
||||
@@ -355,7 +355,7 @@
|
||||
</div>
|
||||
<div class="max-w-xs">
|
||||
<div class="form-control">
|
||||
<label class="cursor-pointer label">
|
||||
<label class="label cursor-pointer">
|
||||
<input v-model="bordered" type="checkbox" class="checkbox checkbox-secondary" />
|
||||
<span class="label-text">Bordered Labels</span>
|
||||
</label>
|
||||
@@ -368,7 +368,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col items-center print-show">
|
||||
<div class="flex flex-col items-center">
|
||||
<section
|
||||
v-for="(page, pi) in pages"
|
||||
:key="pi"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div>
|
||||
<AppImportDialog v-model="modals.import" />
|
||||
<BaseContainer class="flex flex-col gap-4 mb-6">
|
||||
<BaseContainer class="mb-6 flex flex-col gap-4">
|
||||
<BaseCard>
|
||||
<template #title>
|
||||
<BaseSectionHeader>
|
||||
@@ -10,7 +10,7 @@
|
||||
<template #description> Generate different reports for your inventory. </template>
|
||||
</BaseSectionHeader>
|
||||
</template>
|
||||
<div class="border-t px-6 pb-3 border-gray-300 divide-gray-300 divide-y">
|
||||
<div class="divide-y divide-gray-300 border-t border-gray-300 px-6 pb-3">
|
||||
<DetailAction @action="navigateTo('/reports/label-generator')">
|
||||
<template #title>Asset ID Labels</template>
|
||||
Generates a printable PDF of labels for a range of Asset ID. These are not specific to your inventory so you
|
||||
@@ -39,7 +39,7 @@
|
||||
</template>
|
||||
</BaseSectionHeader>
|
||||
</template>
|
||||
<div class="border-t px-6 pb-3 border-gray-300 divide-gray-300 divide-y">
|
||||
<div class="divide-y divide-gray-300 border-t border-gray-300 px-6 pb-3">
|
||||
<DetailAction @action="modals.import = true">
|
||||
<template #title>Import Inventory</template>
|
||||
Imports the standard CSV format for Homebox. Without an <code>HB.import_ref</code> column, this will
|
||||
@@ -62,7 +62,7 @@
|
||||
</template>
|
||||
</BaseSectionHeader>
|
||||
</template>
|
||||
<div class="border-t px-6 pb-3 border-gray-300 divide-gray-300 divide-y">
|
||||
<div class="divide-y divide-gray-300 border-t border-gray-300 px-6 pb-3">
|
||||
<DetailAction @action="ensureAssetIDs">
|
||||
<template #title>Ensure Asset IDs</template>
|
||||
Ensures that all items in your inventory have a valid asset_id field. This is done by finding the highest
|
||||
|
||||
@@ -5,15 +5,15 @@ import { IntlMessageFormat } from "intl-messageformat";
|
||||
export default defineNuxtPlugin(({ vueApp }) => {
|
||||
function checkDefaultLanguage() {
|
||||
let matched = null;
|
||||
const languages = Object.getOwnPropertyNames(messages())
|
||||
const languages = Object.getOwnPropertyNames(messages());
|
||||
languages.forEach(lang => {
|
||||
if (lang === navigator.language.replace('-', '_')) {
|
||||
if (lang === navigator.language.replace("-", "_")) {
|
||||
matched = lang;
|
||||
}
|
||||
});
|
||||
if (!matched) {
|
||||
languages.forEach(lang => {
|
||||
const languagePartials = navigator.language.split('-')[0]
|
||||
const languagePartials = navigator.language.split("-")[0];
|
||||
if (lang === languagePartials) {
|
||||
matched = lang;
|
||||
}
|
||||
@@ -53,8 +53,8 @@ export const messageCompiler: MessageCompiler = (message, { locale, key, onError
|
||||
};
|
||||
|
||||
export const messages: Object = () => {
|
||||
let messages = {};
|
||||
const modules = import.meta.glob('~//locales/**.json', { eager: true });
|
||||
const messages = {};
|
||||
const modules = import.meta.glob("~//locales/**.json", { eager: true });
|
||||
for (const path in modules) {
|
||||
const key = path.slice(9, -5);
|
||||
messages[key] = modules[path];
|
||||
|
||||
15
frontend/pnpm-lock.yaml
generated
15
frontend/pnpm-lock.yaml
generated
@@ -114,6 +114,9 @@ importers:
|
||||
eslint-plugin-prettier:
|
||||
specifier: ^5.1.3
|
||||
version: 5.1.3(@types/eslint@8.4.10)(eslint-config-prettier@9.1.0(eslint@8.29.0))(eslint@8.29.0)(prettier@3.2.5)
|
||||
eslint-plugin-tailwindcss:
|
||||
specifier: ^3.17.4
|
||||
version: 3.17.4(tailwindcss@3.4.1)
|
||||
eslint-plugin-vue:
|
||||
specifier: ^9.4.0
|
||||
version: 9.22.0(eslint@8.29.0)
|
||||
@@ -2959,6 +2962,12 @@ packages:
|
||||
peerDependencies:
|
||||
eslint: ^7.0.0 || ^8.0.0
|
||||
|
||||
eslint-plugin-tailwindcss@3.17.4:
|
||||
resolution: {integrity: sha512-gJAEHmCq2XFfUP/+vwEfEJ9igrPeZFg+skeMtsxquSQdxba9XRk5bn0Bp9jxG1VV9/wwPKi1g3ZjItu6MIjhNg==}
|
||||
engines: {node: '>=18.12.0'}
|
||||
peerDependencies:
|
||||
tailwindcss: ^3.4.0
|
||||
|
||||
eslint-plugin-unicorn@44.0.2:
|
||||
resolution: {integrity: sha512-GLIDX1wmeEqpGaKcnMcqRvMVsoabeF0Ton0EX4Th5u6Kmf7RM9WBl705AXFEsns56ESkEs0uyelLuUTvz9Tr0w==}
|
||||
engines: {node: '>=14.18'}
|
||||
@@ -9073,6 +9082,12 @@ snapshots:
|
||||
dependencies:
|
||||
eslint: 8.29.0
|
||||
|
||||
eslint-plugin-tailwindcss@3.17.4(tailwindcss@3.4.1):
|
||||
dependencies:
|
||||
fast-glob: 3.3.2
|
||||
postcss: 8.4.38
|
||||
tailwindcss: 3.4.1
|
||||
|
||||
eslint-plugin-unicorn@44.0.2(eslint@8.29.0):
|
||||
dependencies:
|
||||
'@babel/helper-validator-identifier': 7.24.7
|
||||
|
||||
Reference in New Issue
Block a user