mirror of
https://github.com/hay-kot/homebox.git
synced 2024-11-22 16:45:43 +00:00
add user profiles and theme selectors
This commit is contained in:
parent
1ca430af21
commit
72324b8439
14 changed files with 466 additions and 186 deletions
|
@ -1,6 +1,10 @@
|
||||||
<template>
|
<template>
|
||||||
<NuxtLayout>
|
<NuxtLayout>
|
||||||
<Html lang="en" data-theme="garden" />
|
<Html lang="en" :data-theme="theme" />
|
||||||
<NuxtPage />
|
<NuxtPage />
|
||||||
</NuxtLayout>
|
</NuxtLayout>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
const { theme } = useTheme();
|
||||||
|
</script>
|
||||||
|
|
|
@ -29,8 +29,9 @@
|
||||||
/>
|
/>
|
||||||
<path d="M5443.74 520.879v4149.79" style="fill: none; stroke: #000; stroke-width: 153.5px" />
|
<path d="M5443.74 520.879v4149.79" style="fill: none; stroke: #000; stroke-width: 153.5px" />
|
||||||
<path
|
<path
|
||||||
|
class="bg-primary"
|
||||||
d="M8951.41 4102.72c0-41.65-22.221-80.136-58.291-100.961-36.069-20.825-80.51-20.825-116.58 0l-2439.92 1408.69c-36.07 20.825-58.29 59.311-58.29 100.961V7058c0 41.65 22.22 80.136 58.29 100.961 36.07 20.825 80.51 20.825 116.58 0l2439.92-1408.69c36.07-20.825 58.291-59.312 58.291-100.962v-1546.59Z"
|
d="M8951.41 4102.72c0-41.65-22.221-80.136-58.291-100.961-36.069-20.825-80.51-20.825-116.58 0l-2439.92 1408.69c-36.07 20.825-58.29 59.311-58.29 100.961V7058c0 41.65 22.22 80.136 58.29 100.961 36.07 20.825 80.51 20.825 116.58 0l2439.92-1408.69c36.07-20.825 58.291-59.312 58.291-100.962v-1546.59Z"
|
||||||
style="fill: #567f67"
|
style="fill: hsl(var(--p) / var(--tw-bg-opacity))"
|
||||||
/>
|
/>
|
||||||
<path
|
<path
|
||||||
d="M8951.41 4102.72c0-41.65-22.221-80.136-58.291-100.961-36.069-20.825-80.51-20.825-116.58 0l-2439.92 1408.69c-36.07 20.825-58.29 59.311-58.29 100.961V7058c0 41.65 22.22 80.136 58.29 100.961 36.07 20.825 80.51 20.825 116.58 0l2439.92-1408.69c36.07-20.825 58.291-59.312 58.291-100.962v-1546.59ZM6463.98 5551.29v1387.06l2301.77-1328.92V4222.37L6463.98 5551.29Z"
|
d="M8951.41 4102.72c0-41.65-22.221-80.136-58.291-100.961-36.069-20.825-80.51-20.825-116.58 0l-2439.92 1408.69c-36.07 20.825-58.29 59.311-58.29 100.961V7058c0 41.65 22.22 80.136 58.29 100.961 36.07 20.825 80.51 20.825 116.58 0l2439.92-1408.69c36.07-20.825 58.291-59.312 58.291-100.962v-1546.59ZM6463.98 5551.29v1387.06l2301.77-1328.92V4222.37L6463.98 5551.29Z"
|
||||||
|
|
|
@ -1,44 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="overflow-hidden card 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">
|
|
||||||
<slot name="title"></slot>
|
|
||||||
</h3>
|
|
||||||
<p v-if="$slots.subtitle" class="mt-1 max-w-2xl text-sm text-gray-500">
|
|
||||||
<slot name="subtitle"></slot>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<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="(dValue, dKey) in details" :key="dKey" class="py-4 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
|
|
||||||
<dt class="text-sm font-medium text-gray-500">
|
|
||||||
{{ dKey }}
|
|
||||||
</dt>
|
|
||||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">
|
|
||||||
<slot :name="rmSpace(dKey)" v-bind="{ key: dKey, value: dValue }">
|
|
||||||
{{ dValue }}
|
|
||||||
</slot>
|
|
||||||
</dd>
|
|
||||||
</div>
|
|
||||||
</dl>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
type StringLike = string | number | boolean;
|
|
||||||
|
|
||||||
function rmSpace(str: string) {
|
|
||||||
return str.replace(" ", "");
|
|
||||||
}
|
|
||||||
|
|
||||||
defineProps({
|
|
||||||
details: {
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
type: Object as () => Record<string, StringLike | any>,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped></style>
|
|
|
@ -9,7 +9,7 @@
|
||||||
>
|
>
|
||||||
<slot />
|
<slot />
|
||||||
</h3>
|
</h3>
|
||||||
<p v-if="$slots.description" class="mt-2 max-w-4xl text-sm text-gray-500">
|
<p v-if="$slots.description" class="mt-2 max-w-4xl text-sm text-base-content">
|
||||||
<slot name="description" />
|
<slot name="description" />
|
||||||
</p>
|
</p>
|
||||||
<div v-if="$slots.after">
|
<div v-if="$slots.after">
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<div ref="label" class="dropdown dropdown-end w-full">
|
<div ref="label" class="dropdown dropdown-end dropdown-top w-full">
|
||||||
<FormTextField v-model="dateText" tabindex="0" label="Date" :inline="inline" readonly />
|
<FormTextField v-model="dateText" tabindex="0" label="Date" :inline="inline" readonly />
|
||||||
<div tabindex="0" class="mt-1 card compact dropdown-content shadow bg-base-100 rounded-box w-64" @blur="resetTime">
|
<div tabindex="0" class="mt-1 card compact dropdown-content shadow bg-base-100 rounded-box w-64" @blur="resetTime">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
|
|
|
@ -2,10 +2,10 @@
|
||||||
<div class="border-t border-gray-300 px-4 py-5 sm:p-0">
|
<div class="border-t border-gray-300 px-4 py-5 sm:p-0">
|
||||||
<dl class="sm:divide-y sm:divide-gray-300">
|
<dl class="sm:divide-y sm:divide-gray-300">
|
||||||
<div v-for="(detail, i) in details" :key="i" class="py-4 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
|
<div v-for="(detail, i) in details" :key="i" class="py-4 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
|
||||||
<dt class="text-sm font-medium text-gray-500">
|
<dt class="text-sm font-medium text-base-content">
|
||||||
{{ detail.name }}
|
{{ detail.name }}
|
||||||
</dt>
|
</dt>
|
||||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">
|
<dd class="mt-1 text-sm text-base-content sm:col-span-2 sm:mt-0">
|
||||||
<slot :name="detail.slot || detail.name" v-bind="{ detail }">
|
<slot :name="detail.slot || detail.name" v-bind="{ detail }">
|
||||||
<template v-if="detail.type == 'date'">
|
<template v-if="detail.type == 'date'">
|
||||||
<DateTime :date="detail.text" />
|
<DateTime :date="detail.text" />
|
||||||
|
|
|
@ -1,9 +1,41 @@
|
||||||
import { Ref } from "vue";
|
import { Ref } from "vue";
|
||||||
|
|
||||||
|
export type DaisyTheme =
|
||||||
|
| "light"
|
||||||
|
| "dark"
|
||||||
|
| "cupcake"
|
||||||
|
| "bumblebee"
|
||||||
|
| "emerald"
|
||||||
|
| "corporate"
|
||||||
|
| "synthwave"
|
||||||
|
| "retro"
|
||||||
|
| "cyberpunk"
|
||||||
|
| "valentine"
|
||||||
|
| "halloween"
|
||||||
|
| "garden"
|
||||||
|
| "forest"
|
||||||
|
| "aqua"
|
||||||
|
| "lofi"
|
||||||
|
| "pastel"
|
||||||
|
| "fantasy"
|
||||||
|
| "wireframe"
|
||||||
|
| "black"
|
||||||
|
| "luxury"
|
||||||
|
| "dracula"
|
||||||
|
| "cmyk"
|
||||||
|
| "autumn"
|
||||||
|
| "business"
|
||||||
|
| "acid"
|
||||||
|
| "lemonade"
|
||||||
|
| "night"
|
||||||
|
| "coffee"
|
||||||
|
| "winter";
|
||||||
|
|
||||||
export type LocationViewPreferences = {
|
export type LocationViewPreferences = {
|
||||||
showDetails: boolean;
|
showDetails: boolean;
|
||||||
showEmpty: boolean;
|
showEmpty: boolean;
|
||||||
editorSimpleView: boolean;
|
editorSimpleView: boolean;
|
||||||
|
theme: DaisyTheme;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -17,6 +49,7 @@ export function useViewPreferences(): Ref<LocationViewPreferences> {
|
||||||
showDetails: true,
|
showDetails: true,
|
||||||
showEmpty: true,
|
showEmpty: true,
|
||||||
editorSimpleView: true,
|
editorSimpleView: true,
|
||||||
|
theme: "garden",
|
||||||
},
|
},
|
||||||
{ mergeDefaults: true }
|
{ mergeDefaults: true }
|
||||||
);
|
);
|
||||||
|
|
42
frontend/composables/use-theme.ts
Normal file
42
frontend/composables/use-theme.ts
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
import { ComputedRef } from "vue";
|
||||||
|
import { DaisyTheme } from "./use-preferences";
|
||||||
|
|
||||||
|
export interface UseTheme {
|
||||||
|
theme: ComputedRef<DaisyTheme>;
|
||||||
|
setTheme: (theme: DaisyTheme) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const themeRef = ref<DaisyTheme>("garden");
|
||||||
|
|
||||||
|
export function useTheme(): UseTheme {
|
||||||
|
const preferences = useViewPreferences();
|
||||||
|
themeRef.value = preferences.value.theme;
|
||||||
|
|
||||||
|
const setTheme = (newTheme: DaisyTheme) => {
|
||||||
|
preferences.value.theme = newTheme;
|
||||||
|
|
||||||
|
if (htmlEl) {
|
||||||
|
htmlEl.value.setAttribute("data-theme", newTheme);
|
||||||
|
}
|
||||||
|
|
||||||
|
themeRef.value = newTheme;
|
||||||
|
};
|
||||||
|
|
||||||
|
const htmlEl = ref<HTMLElement>(null);
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
if (htmlEl.value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
htmlEl.value = document.querySelector("html");
|
||||||
|
console.log(htmlEl.value);
|
||||||
|
});
|
||||||
|
|
||||||
|
const theme = computed(() => {
|
||||||
|
console.log(themeRef.value);
|
||||||
|
return themeRef.value;
|
||||||
|
});
|
||||||
|
|
||||||
|
return { theme, setTheme };
|
||||||
|
}
|
|
@ -140,7 +140,7 @@
|
||||||
Import
|
Import
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<BaseButton type="button" size="sm">
|
<BaseButton type="button" size="sm" to="/profile">
|
||||||
<Icon class="h-5 w-5 mr-2" name="mdi-person" />
|
<Icon class="h-5 w-5 mr-2" name="mdi-person" />
|
||||||
Profile
|
Profile
|
||||||
</BaseButton>
|
</BaseButton>
|
||||||
|
@ -148,12 +148,12 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="grid grid-cols-1 divide-y divide-gray-300 border-t border-gray-300 sm:grid-cols-3 sm:divide-y-0 sm:divide-x"
|
class="grid grid-cols-1 divide-y divide-base-300 border-t border-base-300 sm:grid-cols-3 sm:divide-y-0 sm:divide-x"
|
||||||
>
|
>
|
||||||
<div v-for="stat in stats" :key="stat.label" class="px-6 py-5 text-center text-sm font-medium">
|
<div v-for="stat in stats" :key="stat.label" class="px-6 py-5 text-center text-sm font-medium">
|
||||||
<span class="text-gray-900">{{ stat.value.value }}</span>
|
<span class="text-base-900 font-bold">{{ stat.value.value }}</span>
|
||||||
{{ " " }}
|
{{ " " }}
|
||||||
<span class="text-gray-600">{{ stat.label }}</span>
|
<span class="text-base-600">{{ stat.label }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</BaseCard>
|
</BaseCard>
|
||||||
|
|
|
@ -283,13 +283,13 @@
|
||||||
|
|
||||||
<section class="px-3">
|
<section class="px-3">
|
||||||
<div class="space-y-4">
|
<div class="space-y-4">
|
||||||
<div class="overflow-hidden card bg-base-100 shadow-xl sm:rounded-lg">
|
<div class="card bg-base-100 shadow-xl sm:rounded-lg overflow-visible">
|
||||||
<BaseSectionHeader v-if="item" class="p-5">
|
<BaseSectionHeader v-if="item" class="p-5">
|
||||||
<Icon name="mdi-package-variant" class="-mt-1 mr-2 text-gray-600" />
|
<Icon name="mdi-package-variant" class="-mt-1 mr-2 text-base-content" />
|
||||||
<span class="text-gray-600">
|
<span class="text-base-content">
|
||||||
{{ item.name }}
|
{{ item.name }}
|
||||||
</span>
|
</span>
|
||||||
<p class="text-sm text-gray-600 font-bold pb-0 mb-0">Quantity {{ item.quantity }}</p>
|
<p class="text-sm text-base-content font-bold pb-0 mb-0">Quantity {{ item.quantity }}</p>
|
||||||
<template #after>
|
<template #after>
|
||||||
<div class="modal-action mt-3">
|
<div class="modal-action mt-3">
|
||||||
<div class="mr-auto tooltip" data-tip="Hide the cruft! ">
|
<div class="mr-auto tooltip" data-tip="Hide the cruft! ">
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { DateDetail, Detail } from "~~/components/global/DetailsSection/types";
|
||||||
import { ItemAttachment } from "~~/lib/api/types/data-contracts";
|
import { ItemAttachment } from "~~/lib/api/types/data-contracts";
|
||||||
|
|
||||||
definePageMeta({
|
definePageMeta({
|
||||||
|
@ -64,15 +65,33 @@
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
const itemSummary = computed(() => {
|
const itemDetails = computed(() => {
|
||||||
return {
|
return [
|
||||||
Description: item.value?.description || "",
|
{
|
||||||
"Serial Number": item.value?.serialNumber || "",
|
name: "Description",
|
||||||
"Model Number": item.value?.modelNumber || "",
|
text: item.value?.description,
|
||||||
Manufacturer: item.value?.manufacturer || "",
|
},
|
||||||
Notes: item.value?.notes || "",
|
{
|
||||||
Insured: item.value?.insured ? "Yes" : "No",
|
name: "Serial Number",
|
||||||
};
|
text: item.value?.serialNumber,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Mode Number",
|
||||||
|
text: item.value?.modelNumber,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Manufacturer",
|
||||||
|
text: item.value?.manufacturer,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Insured",
|
||||||
|
text: item.value?.insured ? "Yes" : "No",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Notes",
|
||||||
|
text: item.value?.notes,
|
||||||
|
},
|
||||||
|
];
|
||||||
});
|
});
|
||||||
|
|
||||||
const showAttachments = computed(() => {
|
const showAttachments = computed(() => {
|
||||||
|
@ -88,35 +107,34 @@
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
const itemAttachments = computed(() => {
|
const attachmentDetails = computed(() => {
|
||||||
const val: Record<string, string> = {};
|
const details: Detail[] = [];
|
||||||
|
|
||||||
if (preferences.value.showEmpty) {
|
const push = (name: string) => {
|
||||||
return {
|
details.push({
|
||||||
Photos: "",
|
name,
|
||||||
Manuals: "",
|
text: "",
|
||||||
Warranty: "",
|
slot: name.toLowerCase(),
|
||||||
Attachments: "",
|
});
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
if (attachments.value.photos.length > 0) {
|
if (attachments.value.photos.length > 0) {
|
||||||
val.Photos = "";
|
push("Photos");
|
||||||
}
|
|
||||||
|
|
||||||
if (attachments.value.manuals.length > 0) {
|
|
||||||
val.Manuals = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (attachments.value.warranty.length > 0) {
|
|
||||||
val.Warranty = "";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (attachments.value.attachments.length > 0) {
|
if (attachments.value.attachments.length > 0) {
|
||||||
val.Attachments = "";
|
push("Attachments");
|
||||||
}
|
}
|
||||||
|
|
||||||
return val;
|
if (attachments.value.warranty.length > 0) {
|
||||||
|
push("Warranty");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attachments.value.manuals.length > 0) {
|
||||||
|
push("Manuals");
|
||||||
|
}
|
||||||
|
|
||||||
|
return details;
|
||||||
});
|
});
|
||||||
|
|
||||||
const showWarranty = computed(() => {
|
const showWarranty = computed(() => {
|
||||||
|
@ -127,17 +145,32 @@
|
||||||
});
|
});
|
||||||
|
|
||||||
const warrantyDetails = computed(() => {
|
const warrantyDetails = computed(() => {
|
||||||
const payload = {
|
const details: (Detail | DateDetail)[] = [
|
||||||
"Lifetime Warranty": item.value?.lifetimeWarranty ? "Yes" : "No",
|
{
|
||||||
};
|
name: "Lifetime Warranty",
|
||||||
|
text: item.value?.lifetimeWarranty ? "Yes" : "No",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
if (showWarranty.value) {
|
if (item.value?.lifetimeWarranty) {
|
||||||
payload["Warranty Expires"] = item.value?.warrantyExpires || "";
|
details.push({
|
||||||
|
name: "Warranty Expires",
|
||||||
|
text: "N/A",
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
details.push({
|
||||||
|
name: "Warranty Expires",
|
||||||
|
text: item.value?.warrantyExpires,
|
||||||
|
type: "date",
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
payload["Warranty Details"] = item.value?.warrantyDetails || "";
|
details.push({
|
||||||
|
name: "Warranty Details",
|
||||||
|
text: item.value?.warrantyDetails || "",
|
||||||
|
});
|
||||||
|
|
||||||
return payload;
|
return details;
|
||||||
});
|
});
|
||||||
|
|
||||||
const showPurchase = computed(() => {
|
const showPurchase = computed(() => {
|
||||||
|
@ -147,28 +180,45 @@
|
||||||
return item.value?.purchaseFrom || item.value?.purchasePrice;
|
return item.value?.purchaseFrom || item.value?.purchasePrice;
|
||||||
});
|
});
|
||||||
|
|
||||||
const purchaseDetails = computed(() => {
|
const purchaseDetails = computed<(Detail | DateDetail)[]>(() => {
|
||||||
return {
|
return [
|
||||||
"Purchased From": item.value?.purchaseFrom || "",
|
{
|
||||||
"Purchased Price": item.value?.purchasePrice ? fmtCurrency(item.value.purchasePrice) : "",
|
name: "Purchase From",
|
||||||
"Purchased At": item.value?.purchaseTime || "",
|
label: item.value?.purchaseFrom || "",
|
||||||
};
|
},
|
||||||
|
{
|
||||||
|
name: "Purchase Price",
|
||||||
|
text: item.value?.purchasePrice ? fmtCurrency(item.value.purchasePrice) : "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Purchase Date",
|
||||||
|
text: item.value.purchaseTime,
|
||||||
|
},
|
||||||
|
] as (Detail | DateDetail)[];
|
||||||
});
|
});
|
||||||
|
|
||||||
const showSold = computed(() => {
|
const showSold = computed(() => {
|
||||||
if (preferences.value.showEmpty) {
|
if (preferences.value.showEmpty) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return item.value?.soldTo || item.value?.soldPrice;
|
return item.value?.soldTo || item.value?.soldPrice;
|
||||||
});
|
});
|
||||||
|
|
||||||
const soldDetails = computed(() => {
|
const soldDetails = computed<Array<Detail>>(() => {
|
||||||
return {
|
return [
|
||||||
"Sold To": item.value?.soldTo || "",
|
{
|
||||||
"Sold Price": item.value?.soldPrice ? fmtCurrency(item.value.soldPrice) : "",
|
name: "Sold To",
|
||||||
"Sold At": item.value?.soldTime || "",
|
text: item.value?.soldTo || "",
|
||||||
};
|
},
|
||||||
|
{
|
||||||
|
name: "Sold Price",
|
||||||
|
text: item.value?.soldPrice ? fmtCurrency(item.value.soldPrice) : "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Sold At",
|
||||||
|
text: item.value?.soldTime || "",
|
||||||
|
},
|
||||||
|
] as Detail[];
|
||||||
});
|
});
|
||||||
|
|
||||||
const confirm = useConfirm();
|
const confirm = useConfirm();
|
||||||
|
@ -197,21 +247,25 @@
|
||||||
<div class="form-control"></div>
|
<div class="form-control"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid grid-cols-1 gap-3">
|
<div class="grid grid-cols-1 gap-3">
|
||||||
<BaseDetails :details="itemSummary">
|
<BaseCard>
|
||||||
<template #title>
|
<template #title>
|
||||||
<BaseSectionHeader v-if="item" class="pb-0">
|
<BaseSectionHeader>
|
||||||
<Icon name="mdi-package-variant" class="mr-2 text-gray-600" />
|
<Icon name="mdi-package-variant" class="mr-2 -mt-1 text-base-content" />
|
||||||
<span class="text-gray-600">
|
<span class="text-base-content">
|
||||||
{{ item.name }}
|
{{ item ? item.name : "" }}
|
||||||
</span>
|
</span>
|
||||||
<p class="text-sm text-gray-600 font-bold pb-0 mb-0">
|
<template #description>
|
||||||
|
<p class="text-sm text-base-content font-bold pb-0 mb-0">
|
||||||
{{ item.location.name }} - Quantity {{ item.quantity }}
|
{{ item.location.name }} - Quantity {{ item.quantity }}
|
||||||
</p>
|
</p>
|
||||||
<template #after>
|
|
||||||
<div v-if="item.labels && item.labels.length > 0" class="flex flex-wrap gap-3 mt-3">
|
<div v-if="item.labels && item.labels.length > 0" class="flex flex-wrap gap-3 mt-3">
|
||||||
<LabelChip v-for="label in item.labels" :key="label.id" class="badge-primary" :label="label" />
|
<LabelChip v-for="label in item.labels" :key="label.id" class="badge-primary" :label="label" />
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-action mt-3">
|
</template>
|
||||||
|
</BaseSectionHeader>
|
||||||
|
</template>
|
||||||
|
<template #title-actions>
|
||||||
|
<div class="modal-action mt-0">
|
||||||
<label class="label cursor-pointer mr-auto">
|
<label class="label cursor-pointer mr-auto">
|
||||||
<input v-model="preferences.showEmpty" type="checkbox" class="toggle toggle-primary" />
|
<input v-model="preferences.showEmpty" type="checkbox" class="toggle toggle-primary" />
|
||||||
<span class="label-text ml-4"> Show Empty </span>
|
<span class="label-text ml-4"> Show Empty </span>
|
||||||
|
@ -230,58 +284,58 @@
|
||||||
</BaseButton>
|
</BaseButton>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</BaseSectionHeader>
|
|
||||||
</template>
|
<DetailsSection :details="itemDetails" />
|
||||||
</BaseDetails>
|
</BaseCard>
|
||||||
<BaseDetails v-if="showAttachments" :details="itemAttachments">
|
|
||||||
|
<BaseCard v-if="showAttachments">
|
||||||
<template #title> Attachments </template>
|
<template #title> Attachments </template>
|
||||||
<template #Manuals>
|
<DetailsSection :details="attachmentDetails">
|
||||||
|
<template #manuals>
|
||||||
<ItemAttachmentsList
|
<ItemAttachmentsList
|
||||||
v-if="attachments.manuals.length > 0"
|
v-if="attachments.manuals.length > 0"
|
||||||
:attachments="attachments.manuals"
|
:attachments="attachments.manuals"
|
||||||
:item-id="item.id"
|
:item-id="item.id"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<template #Attachments>
|
<template #attachments>
|
||||||
<ItemAttachmentsList
|
<ItemAttachmentsList
|
||||||
v-if="attachments.attachments.length > 0"
|
v-if="attachments.attachments.length > 0"
|
||||||
:attachments="attachments.attachments"
|
:attachments="attachments.attachments"
|
||||||
:item-id="item.id"
|
:item-id="item.id"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<template #Warranty>
|
<template #warranty>
|
||||||
<ItemAttachmentsList
|
<ItemAttachmentsList
|
||||||
v-if="attachments.warranty.length > 0"
|
v-if="attachments.warranty.length > 0"
|
||||||
:attachments="attachments.warranty"
|
:attachments="attachments.warranty"
|
||||||
:item-id="item.id"
|
:item-id="item.id"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<template #Photos>
|
<template #photos>
|
||||||
<ItemAttachmentsList
|
<ItemAttachmentsList
|
||||||
v-if="attachments.photos.length > 0"
|
v-if="attachments.photos.length > 0"
|
||||||
:attachments="attachments.photos"
|
:attachments="attachments.photos"
|
||||||
:item-id="item.id"
|
:item-id="item.id"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
</BaseDetails>
|
</DetailsSection>
|
||||||
<BaseDetails v-if="showPurchase" :details="purchaseDetails">
|
</BaseCard>
|
||||||
<template #title> Purchase Details </template>
|
|
||||||
<template #PurchasedAt>
|
<BaseCard v-if="showPurchase">
|
||||||
<DateTime :date="item.purchaseTime" />
|
<template #title> Purchase </template>
|
||||||
</template>
|
<DetailsSection :details="purchaseDetails" />
|
||||||
</BaseDetails>
|
</BaseCard>
|
||||||
<BaseDetails v-if="showWarranty" :details="warrantyDetails">
|
|
||||||
|
<BaseCard v-if="showWarranty">
|
||||||
<template #title> Warranty </template>
|
<template #title> Warranty </template>
|
||||||
<template #WarrantyExpires>
|
<DetailsSection :details="warrantyDetails" />
|
||||||
<DateTime :date="item.warrantyExpires" />
|
</BaseCard>
|
||||||
</template>
|
|
||||||
</BaseDetails>
|
<BaseCard v-if="showSold">
|
||||||
<BaseDetails v-if="showSold" :details="soldDetails">
|
|
||||||
<template #title> Sold </template>
|
<template #title> Sold </template>
|
||||||
<template #SoldAt>
|
<DetailsSection :details="soldDetails" />
|
||||||
<DateTime :date="item.soldTime" />
|
</BaseCard>
|
||||||
</template>
|
|
||||||
</BaseDetails>
|
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</BaseContainer>
|
</BaseContainer>
|
||||||
|
|
|
@ -125,8 +125,8 @@
|
||||||
<BaseCard class="mb-16">
|
<BaseCard class="mb-16">
|
||||||
<template #title>
|
<template #title>
|
||||||
<BaseSectionHeader>
|
<BaseSectionHeader>
|
||||||
<Icon name="mdi-tag" class="mr-2 text-gray-600" />
|
<Icon name="mdi-tag" class="mr-2 -mt-1 text-base-content" />
|
||||||
<span class="text-gray-600">
|
<span class="text-base-content">
|
||||||
{{ label ? label.name : "" }}
|
{{ label ? label.name : "" }}
|
||||||
</span>
|
</span>
|
||||||
</BaseSectionHeader>
|
</BaseSectionHeader>
|
||||||
|
|
|
@ -123,8 +123,8 @@
|
||||||
<BaseCard class="mb-16">
|
<BaseCard class="mb-16">
|
||||||
<template #title>
|
<template #title>
|
||||||
<BaseSectionHeader>
|
<BaseSectionHeader>
|
||||||
<Icon name="mdi-map-marker" class="mr-2 text-gray-600" />
|
<Icon name="mdi-map-marker" class="mr-2 -mt-1 text-base-content" />
|
||||||
<span class="text-gray-600">
|
<span class="text-base-content">
|
||||||
{{ location ? location.name : "" }}
|
{{ location ? location.name : "" }}
|
||||||
</span>
|
</span>
|
||||||
</BaseSectionHeader>
|
</BaseSectionHeader>
|
||||||
|
|
190
frontend/pages/profile.vue
Normal file
190
frontend/pages/profile.vue
Normal file
|
@ -0,0 +1,190 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { DaisyTheme } from "~~/composables/use-preferences";
|
||||||
|
|
||||||
|
definePageMeta({
|
||||||
|
layout: "home",
|
||||||
|
});
|
||||||
|
useHead({
|
||||||
|
title: "Homebox | Profile",
|
||||||
|
});
|
||||||
|
|
||||||
|
const { setTheme } = useTheme();
|
||||||
|
|
||||||
|
type ThemeOption = {
|
||||||
|
label: string;
|
||||||
|
value: DaisyTheme;
|
||||||
|
};
|
||||||
|
|
||||||
|
const themes: ThemeOption[] = [
|
||||||
|
{
|
||||||
|
label: "Garden",
|
||||||
|
value: "garden",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Light",
|
||||||
|
value: "light",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Cupcake",
|
||||||
|
value: "cupcake",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Bumblebee",
|
||||||
|
value: "bumblebee",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Emerald",
|
||||||
|
value: "emerald",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Corporate",
|
||||||
|
value: "corporate",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Synthwave",
|
||||||
|
value: "synthwave",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Retro",
|
||||||
|
value: "retro",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Cyberpunk",
|
||||||
|
value: "cyberpunk",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Valentine",
|
||||||
|
value: "valentine",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Halloween",
|
||||||
|
value: "halloween",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Forest",
|
||||||
|
value: "forest",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Aqua",
|
||||||
|
value: "aqua",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Lofi",
|
||||||
|
value: "lofi",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Pastel",
|
||||||
|
value: "pastel",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Fantasy",
|
||||||
|
value: "fantasy",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Wireframe",
|
||||||
|
value: "wireframe",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Black",
|
||||||
|
value: "black",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Luxury",
|
||||||
|
value: "luxury",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Dracula",
|
||||||
|
value: "dracula",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Cmyk",
|
||||||
|
value: "cmyk",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Autumn",
|
||||||
|
value: "autumn",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Business",
|
||||||
|
value: "business",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Acid",
|
||||||
|
value: "acid",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Lemonade",
|
||||||
|
value: "lemonade",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Night",
|
||||||
|
value: "night",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Coffee",
|
||||||
|
value: "coffee",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Winter",
|
||||||
|
value: "winter",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<BaseContainer>
|
||||||
|
<BaseCard>
|
||||||
|
<template #title>
|
||||||
|
<BaseSectionHeader>
|
||||||
|
<Icon name="mdi-fill" class="mr-2 text-base-600" />
|
||||||
|
<span class="text-base-600"> Theme Selector </span>
|
||||||
|
|
||||||
|
<template #description>
|
||||||
|
Theme settings are stored in your browser's local storage. You can change the theme at any time. If you're
|
||||||
|
having trouble setting your theme try refreshing your browser.
|
||||||
|
</template>
|
||||||
|
</BaseSectionHeader>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<div class="px-4 pb-4">
|
||||||
|
<div class="rounded-box grid grid-cols-2 gap-4 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5">
|
||||||
|
<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"
|
||||||
|
: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 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="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>
|
||||||
|
<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>
|
||||||
|
<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>
|
||||||
|
<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>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</BaseCard>
|
||||||
|
</BaseContainer>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped></style>
|
Loading…
Reference in a new issue