feat: add entry links to Tag template

This commit is contained in:
Thomas Bishop 2025-07-29 17:56:00 +01:00
parent 8ab2aa77a6
commit c098bfc044
2 changed files with 142 additions and 102 deletions

View file

@ -1,113 +1,112 @@
import {
flexRender,
getCoreRowModel,
useReactTable,
getPaginationRowModel,
SortingState,
getSortedRowModel,
flexRender,
getCoreRowModel,
useReactTable,
getPaginationRowModel,
getSortedRowModel,
} from "@tanstack/react-table"
import { Button } from "./ui/button"
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table"
import { useState } from "react"
export function DataTable({ columns, data, loading }) {
const [sorting, setSorting] = useState([])
const table = useReactTable({
data,
columns,
getCoreRowModel: getCoreRowModel(),
getPaginationRowModel: getPaginationRowModel(),
onSortingChange: setSorting,
getSortedRowModel: getSortedRowModel(),
state: {
sorting,
},
})
const [sorting, setSorting] = useState([])
const table = useReactTable({
data,
columns,
getCoreRowModel: getCoreRowModel(),
getPaginationRowModel: getPaginationRowModel(),
onSortingChange: setSorting,
getSortedRowModel: getSortedRowModel(),
state: {
sorting,
},
})
const pageCount = table.getPageCount()
const currentPage = table.getState().pagination?.pageIndex
return (
<div>
<div className="rounded-none border">
<Table>
<TableHeader>
{table.getHeaderGroups().map((headerGroup) => (
<TableRow key={headerGroup.id}>
{headerGroup.headers.map((header) => {
return (
<TableHead key={header.id}>
{header.isPlaceholder
? null
: flexRender(
header.column.columnDef.header,
header.getContext(),
)}
</TableHead>
)
})}
</TableRow>
))}
</TableHeader>
<TableBody>
{table.getRowModel().rows?.length ? (
table.getRowModel().rows.map((row) => (
<TableRow key={row.id} data-state={row.getIsSelected() && "selected"}>
{row.getVisibleCells().map((cell) => (
<TableCell key={cell.id}>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</TableCell>
))}
</TableRow>
))
) : loading ? (
<TableRow>
<TableCell colSpan={columns.length} className="h-24 text-center">
Loading...
</TableCell>
</TableRow>
) : (
<TableRow>
<TableCell colSpan={columns.length} className="h-24 text-center">
No results.
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
</div>
<div className="flex items-center justify-end space-x-2 py-4 gap-2">
<div>
<span className="text-sm text-muted-foreground">{`${currentPage + 1} of ${pageCount}`}</span>
</div>
<div>
<Button
className="rounded-none"
variant="outline"
size="sm"
onClick={() => table.previousPage()}
disabled={!table.getCanPreviousPage()}
>
Previous
</Button>
<Button
variant="outline"
className="rounded-none"
size="sm"
onClick={() => table.nextPage()}
disabled={!table.getCanNextPage()}
>
Next
</Button>
</div>
</div>
</div>
)
const pageCount = table.getPageCount()
const currentPage = table.getState().pagination?.pageIndex
return (
<div>
<div className="rounded-none border">
<Table>
<TableHeader>
{table.getHeaderGroups().map((headerGroup) => (
<TableRow key={headerGroup.id}>
{headerGroup.headers.map((header) => {
return (
<TableHead key={header.id}>
{header.isPlaceholder
? null
: flexRender(
header.column.columnDef.header,
header.getContext(),
)}
</TableHead>
)
})}
</TableRow>
))}
</TableHeader>
<TableBody>
{table.getRowModel().rows?.length ? (
table.getRowModel().rows.map((row) => (
<TableRow key={row.id} data-state={row.getIsSelected() && "selected"}>
{row.getVisibleCells().map((cell) => (
<TableCell key={cell.id}>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</TableCell>
))}
</TableRow>
))
) : loading ? (
<TableRow>
<TableCell colSpan={columns.length} className="h-24 text-center">
Loading...
</TableCell>
</TableRow>
) : (
<TableRow>
<TableCell colSpan={columns.length} className="h-24 text-center">
No results.
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
</div>
<div className="flex items-center justify-end space-x-2 py-4 gap-2">
<div>
<span className="text-sm text-muted-foreground">{`${currentPage + 1} of ${pageCount}`}</span>
</div>
<div>
<Button
className="rounded-none"
variant="outline"
size="sm"
onClick={() => table.previousPage()}
disabled={!table.getCanPreviousPage()}
>
Previous
</Button>
<Button
variant="outline"
className="rounded-none"
size="sm"
onClick={() => table.nextPage()}
disabled={!table.getCanNextPage()}
>
Next
</Button>
</div>
</div>
</div>
)
}

View file

@ -1,7 +1,47 @@
import { useParams } from "react-router"
import Page from "./Page"
import { useQuery } from "@tanstack/react-query"
import api from "@/api/eolas-api"
import { DataTable } from "@/components/DataTable"
import { ArrowUpDown } from "lucide-react"
import { Button } from "@/components/ui/button"
import { Link } from "react-router"
const columns = [
{
accessorKey: "entry_title",
header: ({ column }) => {
return (
<Button
variant="ghost"
className="rounded-none"
onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
>
Title
<ArrowUpDown className="ml-2 h-4 w-4" />
</Button>
)
},
cell: ({ cell, row }) => {
return (
<Link to={`/entries/${row.original.entry_title}`}>
<span className="text-foreground underline-offset-3 underline hover:text-gray-700 dark:hover:text-green-300">
{row.original.entry_title.replace(/_/g, " ")}
</span>
</Link>
)
},
},
]
export default function Tag() {
const { tag } = useParams()
const { data, isLoading } = useQuery({
queryKey: [`entries_for_tag_${tag}`],
queryFn: () => api.get(`/entries/tag/${tag}`).then((res) => res.data),
})
return (
<Page
titleComponent={
@ -10,6 +50,7 @@ export default function Tag() {
<span>{tag}</span>
</>
}
pageBody={<DataTable columns={columns} data={data?.data || []} loading={isLoading} />}
/>
)
}