wip: more UI fixes for consistency across themes

This commit is contained in:
Hayden 2022-12-11 12:14:41 -09:00
parent b66bc407fc
commit b6c73733dc
No known key found for this signature in database
GPG key ID: 17CF79474E257545
12 changed files with 278 additions and 129 deletions

View file

@ -29,7 +29,7 @@ func (ctrl *V1Controller) HandleItemsGetAll() server.HandlerFunc {
return repo.ItemQuery{
Page: queryIntOrNegativeOne(params.Get("page")),
PageSize: queryIntOrNegativeOne(params.Get("perPage")),
PageSize: queryIntOrNegativeOne(params.Get("pageSize")),
Search: params.Get("q"),
LocationIDs: queryUUIDList(params, "locations"),
LabelIDs: queryUUIDList(params, "labels"),

View file

@ -1,26 +1,64 @@
<script lang="ts" setup>
// https://stackoverflow.com/questions/36721830/convert-hsl-to-rgb-and-hex
function hslToHex(h: number, s: number, l: number) {
l /= 100;
const a = (s * Math.min(l, 1 - l)) / 100;
const f = (n: number) => {
const k = (n + h / 30) % 12;
const color = l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1);
return Math.round(255 * color)
.toString(16)
.padStart(2, "0"); // convert to Hex and prefix "0" if needed
};
return `#${f(0)}${f(8)}${f(4)}`;
}
function unstring(value: string): [number, number, number] {
const [h, s, l] = value
.replace("hsla(", "")
.replace(")", "")
.replace(/%/g, "")
.split(",")
.map(v => v.trim());
return [Number(h), Number(s), Number(l)];
}
const primary = useCssVar("--p");
const primaryHex = computed(() => hslToHex(...unstring(primary.value)));
const accent = useCssVar("--a");
const accentHex = computed(() => hslToHex(...unstring(accent.value)));
const neutral = useCssVar("--n");
const neutralHex = computed(() => hslToHex(...unstring(neutral.value)));
const base100 = useCssVar("--b1");
const base100Hex = computed(() => hslToHex(...unstring(base100.value)));
</script>
<template>
<svg viewBox="0 0 1440 237" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#a)" filter="url(#b)">
<path fill="#fff" d="M0-103h1440v310H0z" />
<path fill="#2C2E27" d="M0-103h1440v310H0z" />
<path :fill="neutralHex" d="M0-103h1440v310H0z" />
<g clip-path="url(#c)">
<path
d="M1344.93 230.569h-75.81v-45.486h30.32c5.98 0 11.89 1.177 17.41 3.463s10.53 5.636 14.76 9.86c8.53 8.53 13.32 20.099 13.32 32.163Z"
fill="#507B5D"
:fill="primaryHex"
/>
<path
d="M1297.89 170.07c0-3.395-2.75-6.147-6.14-6.147-3.4 0-6.15 2.752-6.15 6.147 0 3.395 2.75 6.148 6.15 6.148 3.39 0 6.14-2.753 6.14-6.148ZM1328.45 170.07c0-3.395-2.75-6.147-6.15-6.147-3.39 0-6.15 2.752-6.15 6.147 0 3.395 2.76 6.148 6.15 6.148 3.4 0 6.15-2.753 6.15-6.148Z"
fill="#F6FAFB"
:fill="base100Hex"
/>
</g>
<g clip-path="url(#d)">
<path
d="M1401.78 60c7.5 0 14.83 2.2231 21.06 6.388 6.24 4.165 11.09 10.0848 13.96 17.0109 2.87 6.9261 3.62 14.5474 2.16 21.9001-1.46 7.353-5.07 14.107-10.37 19.408-5.3 5.301-12.06 8.911-19.41 10.373-7.35 1.463-14.98.712-21.9-2.157-6.93-2.869-12.85-7.727-17.01-13.96-4.17-6.234-6.39-13.562-6.39-21.0587V60h37.9Z"
fill="#F6FAFB"
:fill="base100Hex"
/>
</g>
<g clip-path="url(#e)">
<path d="M1269.12 135.809h75.81V60h-75.81v75.809Z" fill="#FFDA56" />
<path d="M1269.12 135.809h75.81V60h-75.81v75.809Z" :fill="accentHex" />
</g>
<g clip-path="url(#f)">
<path
@ -29,35 +67,35 @@
/>
</g>
<g clip-path="url(#g)">
<path d="M1079.6 135.809h75.81V60h-75.81v75.809Z" fill="#FFDA56" />
<path d="M1079.6 135.809h75.81V60h-75.81v75.809Z" :fill="accentHex" />
</g>
<g clip-path="url(#h)">
<path
d="M890.08 60h75.808v45.485h-30.323c-5.973 0-11.888-1.176-17.406-3.462-5.519-2.2861-10.533-5.6365-14.757-9.8602C894.872 83.6327 890.08 72.0634 890.08 60Z"
fill="#507B5D"
:fill="primaryHex"
/>
<path
d="M937.114 120.498c0 3.395 2.752 6.148 6.147 6.148 3.395 0 6.147-2.753 6.147-6.148 0-3.395-2.752-6.147-6.147-6.147-3.395 0-6.147 2.752-6.147 6.147ZM906.56 120.498c0 3.395 2.752 6.148 6.147 6.148 3.395 0 6.148-2.753 6.148-6.148 0-3.395-2.753-6.147-6.148-6.147-3.395 0-6.147 2.752-6.147 6.147Z"
fill="#F6FAFB"
:fill="base100Hex"
/>
</g>
<g clip-path="url(#i)">
<path d="M795.32 154.76v75.809h75.808V154.76H795.32Z" fill="#FFDA56" />
<path d="M795.32 154.76v75.809h75.808V154.76H795.32Z" :fill="accentHex" />
</g>
<g clip-path="url(#j)">
<path
d="M776.368 154.76v75.809h-45.485v-30.324c0-5.973 1.177-11.888 3.463-17.406 2.286-5.519 5.636-10.533 9.86-14.757 8.53-8.53 20.099-13.322 32.162-13.322Z"
fill="#507B5D"
:fill="primaryHex"
/>
<path
d="M715.87 201.794c-3.395 0-6.147 2.752-6.147 6.147 0 3.395 2.752 6.148 6.147 6.148 3.395 0 6.148-2.753 6.148-6.148 0-3.395-2.753-6.147-6.148-6.147ZM715.87 171.24c-3.395 0-6.147 2.752-6.147 6.147 0 3.395 2.752 6.148 6.147 6.148 3.395 0 6.148-2.753 6.148-6.148 0-3.395-2.753-6.147-6.148-6.147Z"
fill="#F6FAFB"
:fill="base100Hex"
/>
</g>
<g clip-path="url(#k)">
<path
d="M871.128 97.9043c0 7.4967-2.223 14.8247-6.388 21.0587-4.165 6.233-10.084 11.091-17.01 13.96-6.927 2.869-14.548 3.62-21.901 2.157-7.352-1.462-14.106-5.072-19.407-10.373-5.301-5.301-8.911-12.055-10.374-19.408-1.462-7.3527-.712-14.974 2.157-21.9001 2.869-6.9261 7.727-12.8459 13.961-17.0109C818.399 62.2231 825.727 60 833.224 60h37.904v37.9043Z"
fill="#F6FAFB"
:fill="base100Hex"
/>
</g>
<g clip-path="url(#l)">
@ -72,17 +110,17 @@
<g clip-path="url(#m)">
<path
d="M605.8 97.9043c0-7.4968 2.223-14.8252 6.388-21.0585 4.165-6.2333 10.085-11.0916 17.011-13.9605 6.926-2.8689 14.547-3.6195 21.9-2.157 7.353 1.4626 14.107 5.0726 19.408 10.3736 5.301 5.301 8.911 12.0549 10.373 19.4076 1.463 7.3527.712 14.9735-2.157 21.9005-2.869 6.926-7.727 12.846-13.96 17.01-6.234 4.165-13.562 6.389-21.059 6.389H605.8V97.9043Z"
fill="#F6FAFB"
:fill="base100Hex"
/>
</g>
<g clip-path="url(#n)">
<path
d="M511.04 135.809V60h45.485v30.3234c0 5.9732-1.176 11.8876-3.462 17.4066-2.286 5.518-5.637 10.533-9.86 14.756-8.53 8.53-20.1 13.323-32.163 13.323Z"
fill="#507B5D"
:fill="primaryHex"
/>
<path
d="M571.538 88.7746c3.395 0 6.147-2.7522 6.147-6.1473 0-3.395-2.752-6.1473-6.147-6.1473-3.395 0-6.147 2.7523-6.147 6.1473 0 3.3951 2.752 6.1473 6.147 6.1473ZM571.538 119.328c3.395 0 6.147-2.752 6.147-6.147 0-3.395-2.752-6.147-6.147-6.147-3.395 0-6.147 2.752-6.147 6.147 0 3.395 2.752 6.147 6.147 6.147Z"
fill="#F6FAFB"
:fill="base100Hex"
/>
</g>
<g clip-path="url(#o)">
@ -103,28 +141,28 @@
<g clip-path="url(#q)">
<path
d="M132 230.569V154.76h45.485v30.323c0 5.974-1.176 11.888-3.462 17.407-2.286 5.518-5.636 10.533-9.86 14.756-8.53 8.53-20.1 13.323-32.163 13.323Z"
fill="#507B5D"
:fill="primaryHex"
/>
<path
d="M192.498 183.535c3.395 0 6.148-2.753 6.148-6.148 0-3.395-2.753-6.147-6.148-6.147-3.395 0-6.147 2.752-6.147 6.147 0 3.395 2.752 6.148 6.147 6.148ZM192.498 214.089c3.395 0 6.148-2.753 6.148-6.148 0-3.395-2.753-6.147-6.148-6.147-3.395 0-6.147 2.752-6.147 6.147 0 3.395 2.752 6.148 6.147 6.148Z"
fill="#F6FAFB"
:fill="base100Hex"
/>
</g>
<g clip-path="url(#r)">
<path
d="M302.569 135.809H226.76V90.3234h30.323c5.974 0 11.888 1.1765 17.407 3.4624 5.518 2.2858 10.533 5.6362 14.756 9.8602 8.53 8.53 13.323 20.099 13.323 32.163Z"
fill="#507B5D"
:fill="primaryHex"
/>
<path
d="M255.535 75.3103c0-3.3951-2.753-6.1473-6.148-6.1473-3.395 0-6.147 2.7522-6.147 6.1473 0 3.3951 2.752 6.1473 6.147 6.1473 3.395 0 6.148-2.7522 6.148-6.1473ZM286.089 75.3103c0-3.3951-2.753-6.1473-6.148-6.1473-3.395 0-6.147 2.7522-6.147 6.1473 0 3.3951 2.752 6.1473 6.147 6.1473 3.395 0 6.148-2.7522 6.148-6.1473Z"
fill="#F6FAFB"
:fill="base100Hex"
/>
</g>
<g clip-path="url(#s)">
<path d="M207.809 60H132v75.809h75.809V60Z" fill="#FFDA56" />
<path d="M207.809 60H132v75.809h75.809V60Z" :fill="accentHex" />
</g>
<g clip-path="url(#t)">
<path d="M502-31v75.8085h75.809V-31H502Z" fill="#FFDA56" />
<path d="M502-31v75.8085h75.809V-31H502Z" :fill="accentHex" />
</g>
<g clip-path="url(#u)">
<path
@ -141,7 +179,7 @@
<g clip-path="url(#w)">
<path
d="M388.089 6.66425c0 7.49675-2.224 14.82515-6.388 21.05845-4.165 6.2333-10.085 11.0916-17.011 13.9605-6.926 2.8689-14.548 3.6195-21.9 2.157-7.353-1.4626-14.107-5.0726-19.408-10.3736-5.301-5.301-8.911-12.0549-10.374-19.4076-1.462-7.3527-.712-14.973986 2.157-21.90008 2.869-6.92612 7.728-12.84592 13.961-17.01092 6.233-4.165 13.562-6.388 21.058-6.388h37.905V6.66425Z"
fill="#F6FAFB"
:fill="base100Hex"
/>
</g>
<g clip-path="url(#x)">
@ -165,7 +203,7 @@
<g clip-path="url(#A)">
<path
d="M956.648-31.24v75.8085h-45.485V14.2451c0-5.97318 1.177-11.88788 3.463-17.40639 2.286-5.5185 5.636-10.53271 9.86-14.75641 8.53-8.5301 20.099-13.3223 32.162-13.3223Z"
fill="#507B5D"
:fill="primaryHex"
/>
<path
d="M896.15 15.7939c-3.395 0-6.147 2.7522-6.147 6.1473 0 3.3951 2.752 6.1473 6.147 6.1473 3.395 0 6.148-2.7522 6.148-6.1473 0-3.3951-2.753-6.1473-6.148-6.1473Z"
@ -181,7 +219,7 @@
<g clip-path="url(#C)">
<path
d="M1070.36 44.5685V-31.24h45.49V-.916588c0 5.973188-1.18 11.887888-3.47 17.406388-2.28 5.5185-5.63 10.5328-9.86 14.7564-8.53 8.5302-20.1 13.3223-32.16 13.3223Z"
fill="#507B5D"
:fill="primaryHex"
/>
<path
d="M1130.86 28.0885c3.39 0 6.15-2.7522 6.15-6.1473 0-3.3951-2.76-6.1473-6.15-6.1473-3.4 0-6.15 2.7522-6.15 6.1473 0 3.3951 2.75 6.1473 6.15 6.1473Z"
@ -191,13 +229,13 @@
<g clip-path="url(#D)">
<path
d="M1203.02 44.5685c-7.49 0-14.82-2.223-21.05-6.388-6.24-4.165-11.1-10.0848-13.96-17.0109-2.87-6.9261-3.62-14.54737-2.16-21.900078 1.46-7.352702 5.07-14.106622 10.37-19.407622 5.3-5.301 12.06-8.911 19.41-10.3736 7.35-1.4625 14.97-.7119 21.9 2.157 6.93 2.8689 12.85 7.7272 17.01 13.9605 4.17 6.23332 6.39 13.561722 6.39 21.05848V44.5685h-37.91Z"
fill="#F6FAFB"
:fill="base100Hex"
/>
</g>
<g clip-path="url(#E)">
<path
d="M1335.69-31.24v75.8085h-45.49V14.2451c0-5.97318 1.18-11.88788 3.47-17.40639 2.28-5.5185 5.63-10.53271 9.86-14.75641 8.53-8.5301 20.1-13.3223 32.16-13.3223Z"
fill="#507B5D"
:fill="primaryHex"
/>
<path
d="M1275.19 15.7939c-3.39 0-6.15 2.7522-6.15 6.1473 0 3.3951 2.76 6.1473 6.15 6.1473 3.4 0 6.15-2.7522 6.15-6.1473 0-3.3951-2.75-6.1473-6.15-6.1473Z"
@ -207,7 +245,7 @@
<g clip-path="url(#F)">
<path
d="M292.808-31v75.8085h-45.485V14.4851c0-5.97316 1.177-11.88786 3.463-17.40636 2.286-5.51851 5.636-10.53274 9.86-14.75644C269.176-26.2078 280.745-31 292.808-31Z"
fill="#507B5D"
:fill="primaryHex"
/>
<path
d="M232.31 16.0339c-3.395 0-6.147 2.7522-6.147 6.1473 0 3.3951 2.752 6.1473 6.147 6.1473 3.395 0 6.148-2.7522 6.148-6.1473 0-3.3951-2.753-6.1473-6.148-6.1473Z"

View file

@ -0,0 +1,90 @@
<template>
<BaseModal v-model="dialog">
<template #title> Import CSV File </template>
<p>
Import a CSV file containing your items, labels, and locations. See documentation for more information on the
required format.
</p>
<form @submit.prevent="submitCsvFile">
<div class="flex flex-col gap-2 py-6">
<input ref="importRef" type="file" class="hidden" accept=".csv,.tsv" @change="setFile" />
<BaseButton type="button" @click="uploadCsv">
<Icon class="h-5 w-5 mr-2" name="mdi-upload" />
Upload
</BaseButton>
<p class="text-center pt-4 -mb-5">
{{ importCsv?.name }}
</p>
</div>
<div class="modal-action">
<BaseButton type="submit" :disabled="!importCsv"> Submit </BaseButton>
</div>
</form>
</BaseModal>
</template>
<script setup lang="ts">
type Props = {
modelValue: boolean;
};
const props = withDefaults(defineProps<Props>(), {
modelValue: false,
});
const emit = defineEmits(["update:modelValue"]);
const dialog = useVModel(props, "modelValue", emit);
const api = useUserApi();
const toast = useNotifier();
const importCsv = ref<File | null>(null);
const importLoading = ref(false);
const importRef = ref<HTMLInputElement>();
whenever(
() => !dialog.value,
() => {
importCsv.value = null;
}
);
function setFile(e: Event) {
importCsv.value = e.target.files[0];
}
function uploadCsv() {
importRef.value.click();
}
const eventBus = useEventBus();
async function submitCsvFile() {
if (!importCsv.value) {
toast.error("Please select a file to import.");
return;
}
importLoading.value = true;
const { error } = await api.items.import(importCsv.value);
if (error) {
toast.error("Import failed. Please try again later.");
}
// Reset
dialog.value = false;
importLoading.value = false;
importCsv.value = null;
if (importRef.value) {
importRef.value.value = "";
}
eventBus.emit(EventTypes.ClearStores);
}
</script>

View file

@ -1,5 +1,5 @@
<template>
<div class="card bg-white shadow-xl sm:rounded-lg">
<div class="card bg-base-100 shadow-xl sm:rounded-lg">
<div v-if="$slots.title" class="px-4 py-5 sm:px-6">
<h3 class="text-lg font-medium leading-6">
<slot name="title"></slot>

View file

@ -23,7 +23,7 @@
<template>
<NuxtLink
ref="badge"
class="badge badge-secondary"
class="badge badge-secondary text-secondary-content"
:class="{
'badge-lg p-4': size === 'lg',
'p-3': size !== 'sm' && size !== 'lg',

View file

@ -2,7 +2,7 @@
<NuxtLink
ref="card"
:to="`/location/${location.id}`"
class="card bg-white text-neutral rounded-md transition duration-300 shadow-md"
class="card bg-base-100 text-base-content rounded-md transition duration-300 shadow-md"
>
<div
class="card-body"
@ -19,7 +19,7 @@
<span class="mx-auto">
{{ location.name }}
</span>
<span v-if="hasCount" class="badge badge-primary h-6 w-6 badge-lg"> {{ count }}</span>
<span v-if="hasCount" class="badge badge-primary h-6 badge-lg"> {{ count }}</span>
</h2>
</div>
</NuxtLink>

View file

@ -24,7 +24,7 @@
<td
v-for="h in headers"
:key="`${h.value}-${i}`"
class="bg-white"
class="bg-base-100"
:class="{
'text-center': h.align === 'center',
'text-right': h.align === 'right',

View file

@ -1,9 +1,19 @@
<template>
<div>
<!--
Confirmation Modal is a singleton used by all components so we render
it here to ensure it's always available. Possibly could move this further
up the tree
-->
<ModalConfirm />
<AppImportDialog v-model="modals.import" />
<ItemCreateModal v-model="modals.item" />
<LabelCreateModal v-model="modals.label" />
<LocationCreateModal v-model="modals.location" />
<AppToast />
<div class="drawer drawer-mobile">
<input id="my-drawer-2" type="checkbox" class="drawer-toggle" />
<div class="drawer-content justify-center">
<div class="drawer-content justify-center bg-base-300">
<AppHeaderDecor class="-mt-10" />
<slot></slot>
@ -12,7 +22,7 @@
</div>
<!-- Sidebar -->
<div class="drawer-side shadow-lg w-60 flex flex-col justify-center py-10" style="background: white">
<div class="drawer-side overflow-visible shadow-lg w-60 flex flex-col justify-center bg-base-200 py-10">
<label for="my-drawer-2" class="drawer-overlay"></label>
<!-- Top Section -->
<div class="space-y-8">
@ -26,25 +36,37 @@
</div>
<div class="flex flex-col">
<div class="mx-auto w-40 mb-6">
<BaseButton class="btn-block btn-primary text-xl">
<template #icon>
<Icon name="mdi-plus-circle" class="h-6 w-6" />
</template>
Create
</BaseButton>
</div>
<ul class="flex flex-col mx-auto gap-y-8">
<li v-for="n in nav" :key="n.id" class="text-xl">
<NuxtLink v-if="n.to" :to="n.to">
<span class="mr-4">
<Icon :name="n.icon" class="h-5 w-5" />
<div class="dropdown overflow visible w-40">
<label tabindex="0" class="btn btn-primary btn-block text-lg text-no-transform">
<span>
<Icon name="mdi-plus" class="mr-1 -ml-1" />
</span>
Create
</label>
<ul tabindex="0" class="dropdown-content menu p-2 shadow bg-base-100 rounded-box w-40">
<li v-for="btn in dropdown" :key="btn.name">
<button @click="btn.action">
{{ btn.name }}
</button>
</li>
</ul>
</div>
</div>
<ul class="flex flex-col mx-auto gap-2 w-40 menu">
<li v-for="n in nav" :key="n.id" class="text-xl">
<NuxtLink
v-if="n.to"
class="rounded-btn"
:to="n.to"
:class="{
'bg-secondary text-secondary-content': n.active?.value,
}"
>
<Icon :name="n.icon" class="h-6 w-6 mr-4" />
{{ n.name }}
</NuxtLink>
<button v-else @click="n.action">
<span class="mr-4">
<Icon :name="n.icon" class="h-5 w-5" />
</span>
<button v-else class="rounded-btn" @click="n.action">
<Icon :name="n.icon" class="h-6 w-6 mr-4" />
{{ n.name }}
</button>
</li>
@ -52,32 +74,67 @@
</div>
</div>
<!-- Bottom -->
<button class="mt-auto mb-6">Sign Out</button>
<button class="mt-auto mb-6" @click="logout">Sign Out</button>
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import { useAuthStore } from "~~/stores/auth";
import { useLabelStore } from "~~/stores/labels";
import { useLocationStore } from "~~/stores/locations";
/**
* Store Provider Initialization
*/
const modals = reactive({
item: false,
location: false,
label: false,
import: false,
});
const dropdown = [
{
name: "Item / Asset",
action: () => {
modals.item = true;
},
},
{
name: "Location",
action: () => {
modals.location = true;
},
},
{
name: "Label",
action: () => {
modals.label = true;
},
},
];
const route = useRoute();
const nav = [
{
icon: "mdi-home",
active: computed(() => route.path === "/home"),
id: 0,
name: "Home",
to: "/home",
},
{
icon: "mdi-account",
id: 1,
active: computed(() => route.path === "/profile"),
name: "Profile",
to: "/profile",
},
{
icon: "mdi-document",
id: 3,
active: computed(() => route.path === "/items"),
name: "Items",
to: "/items",
},
@ -85,14 +142,18 @@
icon: "mdi-database",
id: 2,
name: "Import",
action: () => {},
},
{
icon: "mdi-database-export",
id: 5,
name: "Export",
action: () => {},
action: () => {
modals.import = true;
},
},
// {
// icon: "mdi-database-export",
// id: 5,
// name: "Export",
// action: () => {
// console.log("Export");
// },
// },
];
const labelStore = useLabelStore();
@ -134,4 +195,16 @@
rmLocationStoreObserver();
eventBus.off(EventTypes.ClearStores, "stores");
});
const authStore = useAuthStore();
const api = useUserApi();
async function logout() {
const { error } = await authStore.logout(api);
if (error) {
return;
}
navigateTo("/");
}
</script>

View file

@ -24,57 +24,6 @@
const itemTable = itemsTable(api);
const stats = statCardData(api);
// const importDialog = ref(false);
// const importCsv = ref(null);
// const importLoading = ref(false);
// const importRef = ref<HTMLInputElement>();
// whenever(
// () => !importDialog.value,
// () => {
// importCsv.value = null;
// }
// );
// function setFile(e: Event & { target: HTMLInputElement }) {
// importCsv.value = e.target.files[0];
// }
// function openDialog() {
// importDialog.value = true;
// }
// function uploadCsv() {
// importRef.value.click();
// }
// const eventBus = useEventBus();
// async function submitCsvFile() {
// if (!importCsv.value) {
// toast.error("Please select a file to import.");
// return;
// }
// importLoading.value = true;
// const { error } = await api.items.import(importCsv.value);
// if (error) {
// toast.error("Import failed. Please try again later.");
// }
// // Reset
// importDialog.value = false;
// importLoading.value = false;
// importCsv.value = null;
// if (importRef.value) {
// importRef.value.value = "";
// }
// eventBus.emit(EventTypes.ClearStores);
// }
const purchasePriceOverTime = purchasePriceOverTimeChart(api);
const inventoryByLocation = inventoryByLocationChart(api);

View file

@ -344,7 +344,7 @@
</div>
</dialog>
<section class="px-3">
<div class="space-y-3">
<div class="space-y-6">
<BaseCard>
<template #title>
<BaseSectionHeader>
@ -410,7 +410,7 @@
</BaseCard>
<NuxtPage :item="item" :page-key="itemId" />
<div v-if="!hasNested">
<template v-if="!hasNested">
<BaseCard v-if="photos && photos.length > 0">
<template #title> Photos </template>
<div
@ -470,7 +470,7 @@
<template #title> Sold Details </template>
<DetailsSection :details="soldDetails" />
</BaseCard>
</div>
</template>
</div>
</section>

View file

@ -21,14 +21,12 @@
{
id: "total",
title: "Total Cost",
subtitle: "Sum over all entries",
value: fmtCurrency(log.value.costTotal),
value: log.value.costTotal,
},
{
id: "average",
title: "Monthly Average",
subtitle: "Average over all entries",
value: fmtCurrency(log.value.costAverage),
value: log.value.costAverage,
},
];
});
@ -138,13 +136,14 @@
</BaseCard>
</div>
<div class="side-slot space-y-6">
<div v-for="stat in stats" :key="stat.id" class="stats block shadow-xl border-l-primary">
<div class="stat">
<div class="stat-title">{{ stat.title }}</div>
<div class="stat-value text-primary">{{ stat.value }}</div>
<div class="stat-desc">{{ stat.subtitle }}</div>
</div>
</div>
<StatCard
v-for="stat in stats"
:key="stat.id"
class="stats block shadow-xl border-l-primary"
:title="stat.title"
:value="stat.value"
type="currency"
/>
</div>
</section>
</div>

View file

@ -12,7 +12,7 @@ module.exports = {
secondary: "#ECF4E7",
accent: "#FFDA56",
neutral: "#2C2E27",
"base-100": "#F6FAFB",
"base-100": "#FFFFFF",
info: "#3ABFF8",
success: "#36D399",
warning: "#FBBD23",