forked from mirrors/homebox
feat: items-editor (#5)
* format readme * update logo * format html * add logo to docs * repository for document and document tokens * add attachments type and repository * autogenerate types via scripts * use autogenerated types * attachment type updates * add insured and quantity fields for items * implement HasID interface for entities * implement label updates for items * implement service update method * WIP item update client side actions * check err on attachment * finish types for basic items editor * remove unused var * house keeping
This commit is contained in:
parent
fbc364dcd2
commit
95ab14b866
125 changed files with 15626 additions and 1791 deletions
|
@ -70,7 +70,7 @@
|
|||
<BaseContainer>
|
||||
<h2 class="mt-1 text-4xl font-bold tracking-tight text-neutral-content sm:text-5xl lg:text-6xl flex">
|
||||
HomeB
|
||||
<AppLogo class="w-12 -mb-4" style="padding-left: 3px; padding-right: 2px" />
|
||||
<AppLogo class="w-12 -mb-4" />
|
||||
x
|
||||
</h2>
|
||||
<div class="ml-1 mt-2 text-lg text-neutral-content/75 space-x-2">
|
||||
|
|
|
@ -1,123 +1,47 @@
|
|||
<template>
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 596.5055138004384 585.369487986598">
|
||||
<g
|
||||
stroke-linecap="round"
|
||||
transform="translate(437.568672588907 210.93877417794465) rotate(332.3235338946895 66.970006481548 27.559467997664797)"
|
||||
>
|
||||
<path
|
||||
d="M-0.3 -0.89 L131.27 -1.27 L131.05 52.32 L-2.89 53.3"
|
||||
stroke="none"
|
||||
stroke-width="0"
|
||||
fill="#15aabf"
|
||||
></path>
|
||||
<path
|
||||
d="M1.61 2.92 C34.39 0.43, 67.49 -3.76, 136.43 -0.16 M-1.81 1.81 C54.26 1.13, 105.28 -0.86, 133.28 -0.04 M132.66 3.06 C133.92 12.97, 132.16 31.97, 132.92 51.2 M134.28 1.16 C131.72 11.69, 133.56 23.47, 134.52 54.65 M133.93 53.09 C103.49 59.22, 80.28 58.51, -1.19 52.09 M133.03 54.88 C92.08 50.88, 53.71 52.46, -0.4 54.88 M-3.64 53.12 C-1.65 33.33, 3.49 15.58, -2.23 -1.93 M-1.08 54.38 C0.63 44.74, -0.42 33.82, 0.29 1.34"
|
||||
stroke="#000"
|
||||
stroke-width="2"
|
||||
fill="none"
|
||||
></path>
|
||||
</g>
|
||||
<g stroke-linecap="round">
|
||||
<g transform="translate(308.4481755172761 281.2115533662909) rotate(0 1.1385609918289674 145.9953857867422)">
|
||||
<path
|
||||
d="M-1.01 -2.17 C-1.07 46.71, 0.3 244.44, -0.46 294.16 M3.63 2.83 C3.44 50.71, -0.72 241.22, -1.36 289.41"
|
||||
stroke="#000000"
|
||||
stroke-width="2"
|
||||
fill="none"
|
||||
></path>
|
||||
</g>
|
||||
</g>
|
||||
<g stroke-linecap="round">
|
||||
<g transform="translate(308.16925883018916 284.66360015581995) rotate(0 135.1525798049602 -68.20042785962323)">
|
||||
<path
|
||||
d="M2.47 0.47 C46.8 -21.36, 220.33 -110.19, 264.96 -133.2 M0.37 -1.74 C45.62 -24.11, 225.01 -114.58, 269.93 -136.88"
|
||||
stroke="#000000"
|
||||
stroke-width="2"
|
||||
fill="none"
|
||||
></path>
|
||||
</g>
|
||||
</g>
|
||||
<g stroke-linecap="round">
|
||||
<g transform="translate(311.39372316987726 570.9674003164946) rotate(0 136.24116036890297 -67.43777376368234)">
|
||||
<path
|
||||
d="M-2.63 2.46 C20.4 -9.48, 94.34 -47.87, 140.63 -71.17 C186.92 -94.47, 252.17 -126.49, 275.11 -137.33 M1.14 1.33 C23.81 -10.35, 94.55 -46.04, 139.83 -68.58 C185.12 -91.11, 249.48 -121.76, 272.86 -133.89"
|
||||
stroke="#000000"
|
||||
stroke-width="2"
|
||||
fill="none"
|
||||
></path>
|
||||
</g>
|
||||
</g>
|
||||
<g stroke-linecap="round">
|
||||
<g transform="translate(580.6092831051336 150.72201134532952) rotate(0 1.5678417062894852 142.75141008423634)">
|
||||
<path
|
||||
d="M2.66 -1.91 C3.6 45.58, 2.41 239.01, 2.99 287.41 M0.67 3.23 C1.39 51.03, -0.51 235.96, 0.31 282.74"
|
||||
stroke="#000000"
|
||||
stroke-width="2"
|
||||
fill="none"
|
||||
></path>
|
||||
</g>
|
||||
</g>
|
||||
<g stroke-linecap="round">
|
||||
<g transform="translate(306.6976102947664 283.14653391715) rotate(0 -140.18354779216435 -59.60806644015338)">
|
||||
<path
|
||||
d="M-0.81 0.62 C-48.48 -18.36, -235.46 -96.23, -283.34 -115.75 M3.94 -1.52 C-44.13 -21.12, -236.56 -99.84, -284.31 -119.83"
|
||||
stroke="#000000"
|
||||
stroke-width="2"
|
||||
fill="none"
|
||||
></path>
|
||||
</g>
|
||||
</g>
|
||||
<g stroke-linecap="round">
|
||||
<g transform="translate(304.3414324224632 572.5226612839633) rotate(0 -144.27019052747903 -64.7761163684645)">
|
||||
<path
|
||||
d="M2.34 1.71 C-46 -19.52, -242.75 -105.04, -290.88 -126.78 M0.17 0.18 C-47.25 -21.98, -237.9 -110.2, -285.78 -131.27"
|
||||
stroke="#000000"
|
||||
stroke-width="2"
|
||||
fill="none"
|
||||
></path>
|
||||
</g>
|
||||
</g>
|
||||
<g stroke-linecap="round">
|
||||
<g
|
||||
transform="translate(15.275892138818847 448.50738095516135) rotate(0 -0.49579063445983707 -143.71703352554232)"
|
||||
>
|
||||
<path
|
||||
d="M-2.4 0.97 C-2.94 -47.38, -0.78 -240.15, -0.9 -288.41 M1.49 -0.97 C0.55 -49.09, -0.95 -237.81, -2.03 -285.33"
|
||||
stroke="#000000"
|
||||
stroke-width="2"
|
||||
fill="none"
|
||||
></path>
|
||||
</g>
|
||||
</g>
|
||||
<g stroke-linecap="round">
|
||||
<g transform="translate(10.301143858432795 164.72182108536072) rotate(0 142.35890827057267 -76.26873721417542)">
|
||||
<path
|
||||
d="M2.04 -1.02 C49.94 -26.43, 238.14 -126.5, 285.02 -151.52 M-0.3 -4.04 C47.43 -29.16, 234.44 -124.45, 282.68 -148.52"
|
||||
stroke="#000000"
|
||||
stroke-width="2"
|
||||
fill="none"
|
||||
></path>
|
||||
</g>
|
||||
</g>
|
||||
<g stroke-linecap="round">
|
||||
<g transform="translate(291.46813332015165 14.258444139957646) rotate(0 143.3244001532809 66.53622476241344)">
|
||||
<path
|
||||
d="M-0.18 -1.16 C46.98 21.36, 236.83 111.22, 284.98 134.14 M-3.72 -4.26 C44.15 18.77, 241.76 114.69, 290.37 137.33"
|
||||
stroke="#000000"
|
||||
stroke-width="2"
|
||||
fill="none"
|
||||
></path>
|
||||
</g>
|
||||
</g>
|
||||
<g stroke-linecap="round">
|
||||
<g transform="translate(175.60844139934756 81.23280016017816) rotate(0 131.7777041676277 66.73388742398038)">
|
||||
<path
|
||||
d="M-1.87 -0.8 C42.4 22.26, 220.78 113.99, 265.42 137.17 M2.32 -3.7 C46.4 18.63, 220.35 109.95, 264.21 132.92"
|
||||
stroke="#000000"
|
||||
stroke-width="2"
|
||||
fill="none"
|
||||
></path>
|
||||
</g>
|
||||
</g>
|
||||
<svg
|
||||
viewBox="0 0 10817 9730"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xml:space="preserve"
|
||||
style="
|
||||
fill-rule: evenodd;
|
||||
clip-rule: evenodd;
|
||||
stroke-linecap: round;
|
||||
stroke-linejoin: round;
|
||||
stroke-miterlimit: 5.42683;
|
||||
"
|
||||
>
|
||||
<path
|
||||
d="M9310.16 2560.9c245.302 249.894 419.711 539.916 565.373 845.231 47.039 98.872 36.229 215.514-28.2 304.05-64.391 88.536-172.099 134.676-280.631 120.28 0 .053-.039.053-.039.053"
|
||||
style="fill: gray; stroke: #000; stroke-width: 206.41px"
|
||||
/>
|
||||
<path
|
||||
d="M5401.56 487.044c-127.958 6.227-254.855 40.77-370.992 103.628-765.271 414.225-2397.45 1297.68-3193.03 1728.32-137.966 74.669-250.327 183.605-328.791 313.046l3963.09 2122.43s-249.048 416.428-470.593 786.926c-189.24 316.445-592.833 429.831-919.198 258.219l-2699.36-1419.32v2215.59c0 226.273 128.751 435.33 337.755 548.466 764.649 413.885 2620.97 1418.66 3385.59 1832.51 209.018 113.137 466.496 113.137 675.514 0 764.623-413.857 2620.94-1418.63 3385.59-1832.51 208.989-113.136 337.743-322.193 337.743-548.466v-3513.48c0-318.684-174.59-611.722-454.853-763.409-795.543-430.632-2427.75-1314.09-3193.02-1728.32-141.693-76.684-299.364-111.227-455.442-103.628"
|
||||
style="fill: #dadada; stroke: #000; stroke-width: 206.42px"
|
||||
/>
|
||||
<path
|
||||
d="M5471.83 4754.46V504.71c-127.958 6.226-325.127 23.1-441.264 85.958-765.271 414.225-2397.45 1297.68-3193.03 1728.32-137.966 74.669-250.327 183.605-328.791 313.046l3963.09 2122.43Z"
|
||||
style="fill: gray; stroke: #000; stroke-width: 206.42px"
|
||||
/>
|
||||
<path
|
||||
d="m1459.34 2725.96-373.791 715.667c-177.166 339.292-46.417 758 292.375 936.167l4.75 2.5m0 0 2699.37 1419.29c326.374 171.625 729.916 58.25 919.165-258.208 221.542-370.5 470.583-786.917 470.583-786.917l-3963.04-2122.42-2.167 3.458-47.25 90.458"
|
||||
style="fill: #dadada; stroke: #000; stroke-width: 206.42px"
|
||||
/>
|
||||
<path d="M5443.74 520.879v4149.79" style="fill: none; stroke: #000; stroke-width: 153.5px" />
|
||||
<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.59Z"
|
||||
style="fill: #567f67"
|
||||
/>
|
||||
<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"
|
||||
/>
|
||||
<path
|
||||
d="M5443.76 9041.74v-4278.4"
|
||||
style="fill: none; stroke: #000; stroke-width: 206.44px; stroke-linejoin: miter"
|
||||
/>
|
||||
<path
|
||||
d="m5471.79 4773.86 3829.35-2188.22"
|
||||
style="fill: none; stroke: #000; stroke-width: 206.43px; stroke-linejoin: miter"
|
||||
/>
|
||||
</svg>
|
||||
</template>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
{{ dKey }}
|
||||
</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">
|
||||
<slot :name="dKey" v-bind="{ key: dKey, value: dValue }">
|
||||
<slot :name="rmSpace(dKey)" v-bind="{ key: dKey, value: dValue }">
|
||||
{{ dValue }}
|
||||
</slot>
|
||||
</dd>
|
||||
|
@ -28,8 +28,13 @@
|
|||
<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,
|
||||
},
|
||||
|
|
35
frontend/components/Form/Checkbox.vue
Normal file
35
frontend/components/Form/Checkbox.vue
Normal file
|
@ -0,0 +1,35 @@
|
|||
<template>
|
||||
<div v-if="!inline" class="form-control w-full">
|
||||
<label class="label cursor-pointer">
|
||||
<span class="label-text"> {{ label }}</span>
|
||||
<input v-model="value" type="checkbox" class="checkbox" />
|
||||
</label>
|
||||
</div>
|
||||
<div v-else class="label cursor-pointer sm:grid sm:grid-cols-4 sm:items-start sm:gap-4">
|
||||
<label>
|
||||
<span class="label-text">
|
||||
{{ label }}
|
||||
</span>
|
||||
</label>
|
||||
<input v-model="value" type="checkbox" class="checkbox" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
inline: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
label: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
});
|
||||
|
||||
const value = useVModel(props, "modelValue");
|
||||
</script>
|
|
@ -52,9 +52,14 @@
|
|||
|
||||
const selected = useVModel(props, "modelValue", emit);
|
||||
const dateText = computed(() => {
|
||||
if (!validDate(selected.value)) {
|
||||
return "";
|
||||
}
|
||||
|
||||
if (selected.value) {
|
||||
return selected.value.toLocaleDateString();
|
||||
}
|
||||
|
||||
return "";
|
||||
});
|
||||
|
||||
|
@ -91,9 +96,7 @@
|
|||
});
|
||||
|
||||
function select(e: MouseEvent, day: Date) {
|
||||
console.log(day);
|
||||
selected.value = day;
|
||||
console.log(selected.value);
|
||||
// @ts-ignore - this is a vue3 bug
|
||||
e.target.blur();
|
||||
resetTime();
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
v-for="(obj, idx) in items"
|
||||
:key="idx"
|
||||
:class="{
|
||||
bordered: selectedIndexes[idx],
|
||||
bordered: selected[idx],
|
||||
}"
|
||||
>
|
||||
<button type="button" @click="toggle(idx)">
|
||||
|
@ -37,10 +37,12 @@
|
|||
default: "",
|
||||
},
|
||||
modelValue: {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
type: Array as () => any[],
|
||||
default: null,
|
||||
},
|
||||
items: {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
type: Array as () => any[],
|
||||
required: true,
|
||||
},
|
||||
|
@ -54,28 +56,23 @@
|
|||
},
|
||||
});
|
||||
|
||||
const selectedIndexes = ref<Record<number, boolean>>({});
|
||||
const value = useVModel(props, "modelValue", emit);
|
||||
|
||||
const selected = computed<Record<number, boolean>>(() => {
|
||||
const obj: Record<number, boolean> = {};
|
||||
value.value.forEach(itm => {
|
||||
const idx = props.items.findIndex(item => item[props.name] === itm.name);
|
||||
obj[idx] = true;
|
||||
});
|
||||
return obj;
|
||||
});
|
||||
|
||||
function toggle(index: number) {
|
||||
selectedIndexes.value[index] = !selectedIndexes.value[index];
|
||||
|
||||
const item = props.items[index];
|
||||
|
||||
if (selectedIndexes.value[index]) {
|
||||
value.value = [...value.value, item];
|
||||
if (selected.value[index]) {
|
||||
value.value = value.value.filter(itm => itm.name !== item.name);
|
||||
} else {
|
||||
value.value = value.value.filter(itm => itm !== item);
|
||||
value.value = [...value.value, item];
|
||||
}
|
||||
}
|
||||
|
||||
watchOnce(
|
||||
() => props.items,
|
||||
() => {
|
||||
if (props.selectFirst && props.items.length > 0) {
|
||||
value.value = props.items[0];
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
const value = useVModel(props, "modelValue", emit);
|
||||
</script>
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
<label class="label">
|
||||
<span class="label-text">{{ label }}</span>
|
||||
</label>
|
||||
<select v-model="value" class="select select-bordered">
|
||||
<select v-model="selectedIdx" class="select select-bordered">
|
||||
<option disabled selected>Pick one</option>
|
||||
<option v-for="obj in items" :key="name != '' ? obj[name] : obj" :value="obj">
|
||||
<option v-for="(obj, idx) in items" :key="name != '' ? obj[name] : obj" :value="idx">
|
||||
{{ name != "" ? obj[name] : obj }}
|
||||
</option>
|
||||
</select>
|
||||
|
@ -24,10 +24,12 @@
|
|||
default: "",
|
||||
},
|
||||
modelValue: {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
type: Object as any,
|
||||
default: null,
|
||||
},
|
||||
items: {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
type: Array as () => any[],
|
||||
required: true,
|
||||
},
|
||||
|
@ -45,10 +47,16 @@
|
|||
() => props.items,
|
||||
() => {
|
||||
if (props.selectFirst && props.items.length > 0) {
|
||||
value.value = props.items[0];
|
||||
selectedIdx.value = 0;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
const value = useVModel(props, "modelValue", emit);
|
||||
const selectedIdx = ref(0);
|
||||
watch(
|
||||
() => selectedIdx.value,
|
||||
() => {
|
||||
emit("update:modelValue", props.items[selectedIdx.value]);
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
<template>
|
||||
<div v-if="!inline" class="form-control">
|
||||
<div v-if="!inline" class="form-control w-full">
|
||||
<label class="label">
|
||||
<span class="label-text">{{ label }}</span>
|
||||
</label>
|
||||
<textarea v-model="value" class="textarea textarea-bordered h-24" :placeholder="placeholder" />
|
||||
<textarea ref="el" v-model="value" class="textarea w-full textarea-bordered h-28" :placeholder="placeholder" />
|
||||
<label v-if="limit" class="label">
|
||||
<span class="label-text-alt"></span>
|
||||
<span class="label-text-alt"> {{ valueLen }}/{{ limit }}</span>
|
||||
|
@ -14,10 +14,12 @@
|
|||
<span class="label-text">{{ label }}</span>
|
||||
</label>
|
||||
<textarea
|
||||
ref="el"
|
||||
v-model="value"
|
||||
class="textarea textarea-bordered col-span-3 mt-3 h-24"
|
||||
class="textarea textarea-bordered w-full col-span-3 mt-3 h-28"
|
||||
auto-grow
|
||||
:placeholder="placeholder"
|
||||
auto-height
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -51,6 +53,19 @@
|
|||
},
|
||||
});
|
||||
|
||||
const el = ref();
|
||||
function setHeight() {
|
||||
el.value.style.height = "auto";
|
||||
el.value.style.height = el.value.scrollHeight + 5 + "px";
|
||||
}
|
||||
|
||||
onUpdated(() => {
|
||||
console.log("updated");
|
||||
if (props.inline) {
|
||||
setHeight();
|
||||
}
|
||||
});
|
||||
|
||||
const value = useVModel(props, "modelValue", emit);
|
||||
const valueLen = computed(() => {
|
||||
return value.value ? value.value.length : 0;
|
||||
|
|
|
@ -22,11 +22,11 @@
|
|||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Item } from "~~/lib/api/classes/items";
|
||||
import { ItemOut, ItemSummary } from "~~/lib/api/types/data-contracts";
|
||||
|
||||
const props = defineProps({
|
||||
item: {
|
||||
type: Object as () => Item,
|
||||
type: Object as () => ItemOut | ItemSummary,
|
||||
required: true,
|
||||
},
|
||||
});
|
||||
|
|
|
@ -26,7 +26,8 @@
|
|||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { type Location } from "~~/lib/api/classes/locations";
|
||||
import { ItemCreate, LocationOut } from "~~/lib/api/types/data-contracts";
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
type: Boolean,
|
||||
|
@ -40,7 +41,7 @@
|
|||
const loading = ref(false);
|
||||
const focused = ref(false);
|
||||
const form = reactive({
|
||||
location: {} as Location,
|
||||
location: {} as LocationOut,
|
||||
name: "",
|
||||
description: "",
|
||||
color: "", // Future!
|
||||
|
@ -80,7 +81,7 @@
|
|||
return;
|
||||
}
|
||||
|
||||
const out = {
|
||||
const out: ItemCreate = {
|
||||
name: form.name,
|
||||
description: form.description,
|
||||
locationId: form.location.id as string,
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
<script setup lang="ts">
|
||||
import { Label } from "~~/lib/api/classes/labels";
|
||||
import { LabelOut, LabelSummary } from "~~/lib/api/types/data-contracts";
|
||||
|
||||
export type sizes = "sm" | "md" | "lg";
|
||||
defineProps({
|
||||
label: {
|
||||
type: Object as () => Label,
|
||||
type: Object as () => LabelOut | LabelSummary,
|
||||
required: true,
|
||||
},
|
||||
size: {
|
||||
|
|
|
@ -26,11 +26,11 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { Location } from "~~/lib/api/classes/locations";
|
||||
import { LocationCount } from "~~/lib/api/types/data-contracts";
|
||||
|
||||
defineProps({
|
||||
location: {
|
||||
type: Object as () => Location,
|
||||
type: Object as () => LocationCount,
|
||||
required: true,
|
||||
},
|
||||
dense: {
|
||||
|
|
52
frontend/components/global/DateTime.vue
Normal file
52
frontend/components/global/DateTime.vue
Normal file
|
@ -0,0 +1,52 @@
|
|||
<template>
|
||||
{{ value }}
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
enum DateTimeFormat {
|
||||
RELATIVE = "relative",
|
||||
LONG = "long",
|
||||
SHORT = "short",
|
||||
}
|
||||
|
||||
const value = computed(() => {
|
||||
if (!props.date) {
|
||||
return "";
|
||||
}
|
||||
|
||||
const dt = typeof props.date === "string" ? new Date(props.date) : props.date;
|
||||
if (!dt) {
|
||||
return "";
|
||||
}
|
||||
|
||||
if (nullDate(dt)) {
|
||||
return "";
|
||||
}
|
||||
|
||||
switch (props.format) {
|
||||
case DateTimeFormat.RELATIVE:
|
||||
return useTimeAgo(dt).value + useDateFormat(dt, " (MM-DD-YYYY)").value;
|
||||
case DateTimeFormat.LONG:
|
||||
return useDateFormat(dt, "YYYY-MM-DD (dddd)").value;
|
||||
case DateTimeFormat.SHORT:
|
||||
return useDateFormat(dt, "YYYY-MM-DD").value;
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
});
|
||||
|
||||
function nullDate(dt: Date) {
|
||||
return dt.getFullYear() === 1;
|
||||
}
|
||||
|
||||
const props = defineProps({
|
||||
date: {
|
||||
type: [Date, String],
|
||||
required: true,
|
||||
},
|
||||
format: {
|
||||
type: String as () => DateTimeFormat,
|
||||
default: "relative",
|
||||
},
|
||||
});
|
||||
</script>
|
Loading…
Add table
Add a link
Reference in a new issue