Skip to content

Commit

Permalink
chore: implement a results table for the search view
Browse files Browse the repository at this point in the history
  • Loading branch information
oliviareichl committed May 27, 2024
1 parent 3ca8e0f commit fa3735a
Show file tree
Hide file tree
Showing 22 changed files with 450 additions and 7 deletions.
79 changes: 79 additions & 0 deletions components/search-data-table/data-table.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
<script setup lang="ts">
import { type ColumnDef, FlexRender, getCoreRowModel, useVueTable } from "@tanstack/vue-table";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
import type { SearchResults } from "@/types/api.ts";
const props = defineProps<{
data: SearchResults["results"];
}>();
const columns: Array<ColumnDef<SearchResults["results"][number]>> = [
{
accessorKey: "title",
header: () => h("div", "Titel"),
cell: ({ row }) => {
return h("div", row.getValue("title"));
},
},
];
const table = useVueTable({
get data() {
return props.data;
},
get columns() {
return columns;
},
getCoreRowModel: getCoreRowModel(),
});
</script>

<template>
<div class="font-semibold text-frisch-indigo">Suchergebnisse ({{ table.getRowCount() }})</div>
<div class="rounded-md border">
<Table>
<TableHeader>
<TableCaption class="sr-only">
<span>Suchergebnisse</span>
</TableCaption>
<TableRow v-for="headerGroup in table.getHeaderGroups()" :key="headerGroup.id">
<TableHead v-for="header in headerGroup.headers" :key="header.id">
<FlexRender
v-if="!header.isPlaceholder"
:render="header.column.columnDef.header"
:props="header.getContext()"
/>
</TableHead>
</TableRow>
</TableHeader>
<TableBody>
<template v-if="table.getRowModel().rows?.length">
<TableRow
v-for="row in table.getRowModel().rows"
:key="row.id"
:data-state="row.getIsSelected() ? 'selected' : undefined"
>
<TableCell v-for="cell in row.getVisibleCells()" :key="cell.id">
<FlexRender :render="cell.column.columnDef.cell" :props="cell.getContext()" />
</TableCell>
</TableRow>
</template>
<template v-else>
<TableRow>
<TableCell :col-span="columns.length" class="h-24 text-center">
Keine Einträge zu dieser Suche.
</TableCell>
</TableRow>
</template>
</TableBody>
</Table>
</div>
</template>
26 changes: 26 additions & 0 deletions components/ui/pagination/PaginationEllipsis.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<script setup lang="ts">
import { DotsHorizontalIcon } from "@radix-icons/vue";
import { PaginationEllipsis, type PaginationEllipsisProps } from "radix-vue";
import { computed, type HTMLAttributes } from "vue";
import { cn } from "@/utils/styles";
const props = defineProps<PaginationEllipsisProps & { class?: HTMLAttributes["class"] }>();
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props;
return delegated;
});
</script>

<template>
<PaginationEllipsis
v-bind="delegatedProps"
:class="cn('w-9 h-9 flex items-center justify-center', props.class)"
>
<slot>
<DotsHorizontalIcon />
</slot>
</PaginationEllipsis>
</template>
31 changes: 31 additions & 0 deletions components/ui/pagination/PaginationFirst.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<script setup lang="ts">
import { DoubleArrowLeftIcon } from "@radix-icons/vue";
import { PaginationFirst, type PaginationFirstProps } from "radix-vue";
import { computed, type HTMLAttributes } from "vue";
import { Button } from "@/components/ui/button";
import { cn } from "@/utils/styles";
const props = withDefaults(
defineProps<PaginationFirstProps & { class?: HTMLAttributes["class"] }>(),
{
asChild: true,
},
);
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props;
return delegated;
});
</script>

<template>
<PaginationFirst v-bind="delegatedProps">
<Button :class="cn('w-9 h-9 p-0', props.class)" variant="outline">
<slot>
<DoubleArrowLeftIcon />
</slot>
</Button>
</PaginationFirst>
</template>
31 changes: 31 additions & 0 deletions components/ui/pagination/PaginationLast.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<script setup lang="ts">
import { DoubleArrowRightIcon } from "@radix-icons/vue";
import { PaginationLast, type PaginationLastProps } from "radix-vue";
import { computed, type HTMLAttributes } from "vue";
import { Button } from "@/components/ui/button";
import { cn } from "@/utils/styles";
const props = withDefaults(
defineProps<PaginationLastProps & { class?: HTMLAttributes["class"] }>(),
{
asChild: true,
},
);
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props;
return delegated;
});
</script>

<template>
<PaginationLast v-bind="delegatedProps">
<Button :class="cn('w-9 h-9 p-0', props.class)" variant="outline">
<slot>
<DoubleArrowRightIcon />
</slot>
</Button>
</PaginationLast>
</template>
31 changes: 31 additions & 0 deletions components/ui/pagination/PaginationNext.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<script setup lang="ts">
import { ChevronRightIcon } from "@radix-icons/vue";
import { PaginationNext, type PaginationNextProps } from "radix-vue";
import { computed, type HTMLAttributes } from "vue";
import { Button } from "@/components/ui/button";
import { cn } from "@/utils/styles";
const props = withDefaults(
defineProps<PaginationNextProps & { class?: HTMLAttributes["class"] }>(),
{
asChild: true,
},
);
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props;
return delegated;
});
</script>

<template>
<PaginationNext v-bind="delegatedProps">
<Button :class="cn('w-9 h-9 p-0', props.class)" variant="outline">
<slot>
<ChevronRightIcon />
</slot>
</Button>
</PaginationNext>
</template>
31 changes: 31 additions & 0 deletions components/ui/pagination/PaginationPrev.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<script setup lang="ts">
import { ChevronLeftIcon } from "@radix-icons/vue";
import { PaginationPrev, type PaginationPrevProps } from "radix-vue";
import { computed, type HTMLAttributes } from "vue";
import { Button } from "@/components/ui/button";
import { cn } from "@/utils/styles";
const props = withDefaults(
defineProps<PaginationPrevProps & { class?: HTMLAttributes["class"] }>(),
{
asChild: true,
},
);
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props;
return delegated;
});
</script>

<template>
<PaginationPrev v-bind="delegatedProps">
<Button :class="cn('w-9 h-9 p-0', props.class)" variant="outline">
<slot>
<ChevronLeftIcon />
</slot>
</Button>
</PaginationPrev>
</template>
6 changes: 6 additions & 0 deletions components/ui/pagination/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export { default as PaginationEllipsis } from "./PaginationEllipsis.vue";
export { default as PaginationFirst } from "./PaginationFirst.vue";
export { default as PaginationLast } from "./PaginationLast.vue";
export { default as PaginationNext } from "./PaginationNext.vue";
export { default as PaginationPrev } from "./PaginationPrev.vue";
export { PaginationRoot as Pagination, PaginationList, PaginationListItem } from "radix-vue";
17 changes: 17 additions & 0 deletions components/ui/table/Table.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<script setup lang="ts">
import type { HTMLAttributes } from "vue";
import { cn } from "@/utils/styles";
const props = defineProps<{
class?: HTMLAttributes["class"];
}>();
</script>

<template>
<div class="relative w-full overflow-auto">
<table :class="cn('w-full caption-bottom text-sm', props.class)">
<slot />
</table>
</div>
</template>
15 changes: 15 additions & 0 deletions components/ui/table/TableBody.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<script setup lang="ts">
import type { HTMLAttributes } from "vue";
import { cn } from "@/utils/styles";
const props = defineProps<{
class?: HTMLAttributes["class"];
}>();
</script>

<template>
<tbody :class="cn('[&_tr:last-child]:border-0', props.class)">
<slot />
</tbody>
</template>
15 changes: 15 additions & 0 deletions components/ui/table/TableCaption.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<script setup lang="ts">
import type { HTMLAttributes } from "vue";
import { cn } from "@/utils/styles";
const props = defineProps<{
class?: HTMLAttributes["class"];
}>();
</script>

<template>
<caption :class="cn('mt-4 text-sm text-muted-foreground', props.class)">
<slot />
</caption>
</template>
22 changes: 22 additions & 0 deletions components/ui/table/TableCell.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<script setup lang="ts">
import type { HTMLAttributes } from "vue";
import { cn } from "@/utils/styles";
const props = defineProps<{
class?: HTMLAttributes["class"];
}>();
</script>

<template>
<td
:class="
cn(
'p-2 align-middle [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-0.5',
props.class,
)
"
>
<slot />
</td>
</template>
37 changes: 37 additions & 0 deletions components/ui/table/TableEmpty.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<script setup lang="ts">
import { computed, type HTMLAttributes } from "vue";
import { cn } from "@/utils/styles";
import TableCell from "./TableCell.vue";
import TableRow from "./TableRow.vue";
const props = withDefaults(
defineProps<{
class?: HTMLAttributes["class"];
colspan?: number;
}>(),
{
colspan: 1,
},
);
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props;
return delegated;
});
</script>

<template>
<TableRow>
<TableCell
:class="cn('p-4 whitespace-nowrap align-middle text-sm text-foreground', props.class)"
v-bind="delegatedProps"
>
<div class="flex items-center justify-center py-10">
<slot />
</div>
</TableCell>
</TableRow>
</template>
15 changes: 15 additions & 0 deletions components/ui/table/TableFooter.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<script setup lang="ts">
import type { HTMLAttributes } from "vue";
import { cn } from "@/utils/styles";
const props = defineProps<{
class?: HTMLAttributes["class"];
}>();
</script>

<template>
<tfoot :class="cn('border-t bg-muted/50 font-medium [&>tr]:last:border-b-0', props.class)">
<slot />
</tfoot>
</template>
22 changes: 22 additions & 0 deletions components/ui/table/TableHead.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<script setup lang="ts">
import type { HTMLAttributes } from "vue";
import { cn } from "@/utils/styles";
const props = defineProps<{
class?: HTMLAttributes["class"];
}>();
</script>

<template>
<th
:class="
cn(
'h-10 px-2 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-0.5',
props.class,
)
"
>
<slot />
</th>
</template>
Loading

0 comments on commit fa3735a

Please sign in to comment.