mirror of
https://github.com/sysadminsmedia/homebox.git
synced 2025-12-21 13:23:14 +01:00
* feat: implement example of data table * feat: load item data into table * chore: begin switching dialogs * feat: implement old dialog for controlling headers and page size * feat: get table into relatively usable state * feat: enhance dropdown actions for multi-selection and CSV download * feat: enhance table cell and dropdown button styles for better usability * feat: json download for table * feat: add expanded row component for item details in data table * chore: add translation support * feat: restore table on home page * fix: oops need ids * feat: move card view to use tanstack to allow for pagination * feat: switch the items search to use ItemViewSelectable * fix: update pagination handling and improve button click logic * feat: improve selectable table * feat: add indeterminate to checkbox * feat: overhaul maintenance dialog to use new system and add maintenance options to table * feat: add label ids and location id to item patch api * feat: change location and labels in table view * feat: add quick actions preference and enable toggle in table settings * fix: lint * fix: remove sized 1 pages * fix: attempt to fix type error * fix: various issues * fix: remove * fix: refactor item fetching logic to use useAsyncData for improved reactivity and improve use confirm * fix: sort backend issues * fix: enhance CSV export functionality by escaping fields to prevent formula injection * fix: put aria sort on th not button * chore: update api types
78 lines
2.8 KiB
Vue
78 lines
2.8 KiB
Vue
<script setup lang="ts">
|
|
import { useI18n } from "vue-i18n";
|
|
import { statCardData } from "./statistics";
|
|
import { itemsTable } from "./table";
|
|
import { useLabelStore } from "~~/stores/labels";
|
|
import { useLocationStore } from "~~/stores/locations";
|
|
import BaseContainer from "@/components/Base/Container.vue";
|
|
import BaseCard from "@/components/Base/Card.vue";
|
|
import Subtitle from "~/components/global/Subtitle.vue";
|
|
import StatCard from "~/components/global/StatCard/StatCard.vue";
|
|
import ItemCard from "~/components/Item/Card.vue";
|
|
import LocationCard from "~/components/Location/Card.vue";
|
|
import LabelChip from "~/components/Label/Chip.vue";
|
|
import Table from "~/components/Item/View/Table.vue";
|
|
|
|
const { t } = useI18n();
|
|
|
|
definePageMeta({
|
|
middleware: ["auth"],
|
|
});
|
|
useHead({
|
|
title: "HomeBox | " + t("menu.home"),
|
|
});
|
|
|
|
const api = useUserApi();
|
|
const breakpoints = useBreakpoints();
|
|
|
|
const locationStore = useLocationStore();
|
|
const locations = computed(() => locationStore.parentLocations);
|
|
|
|
const labelsStore = useLabelStore();
|
|
const labels = computed(() => labelsStore.labels);
|
|
|
|
const itemTable = itemsTable(api);
|
|
const stats = statCardData(api);
|
|
</script>
|
|
|
|
<template>
|
|
<div>
|
|
<BaseContainer class="flex flex-col gap-4">
|
|
<section>
|
|
<Subtitle> {{ $t("home.quick_statistics") }} </Subtitle>
|
|
<div class="grid grid-cols-2 gap-2 md:grid-cols-4 md:gap-6">
|
|
<StatCard v-for="(stat, i) in stats" :key="i" :title="stat.label" :value="stat.value" :type="stat.type" />
|
|
</div>
|
|
</section>
|
|
|
|
<section>
|
|
<Subtitle> {{ $t("home.recently_added") }} </Subtitle>
|
|
|
|
<p v-if="itemTable.items.length === 0" class="ml-2 text-sm">{{ $t("items.no_results") }}</p>
|
|
<BaseCard v-else-if="breakpoints.lg">
|
|
<Table :items="itemTable.items" />
|
|
</BaseCard>
|
|
<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> {{ $t("home.storage_locations") }} </Subtitle>
|
|
<p v-if="locations.length === 0" class="ml-2 text-sm">{{ $t("locations.no_results") }}</p>
|
|
<div v-else class="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> {{ $t("home.labels") }} </Subtitle>
|
|
<p v-if="labels.length === 0" class="ml-2 text-sm">{{ $t("labels.no_results") }}</p>
|
|
<div v-else class="flex flex-wrap gap-4">
|
|
<LabelChip v-for="label in labels" :key="label.id" size="lg" :label="label" class="shadow-md" />
|
|
</div>
|
|
</section>
|
|
</BaseContainer>
|
|
</div>
|
|
</template>
|