From 5b77317b5fc04ab44463391922aebeaa602593bf Mon Sep 17 00:00:00 2001 From: thomasabishop Date: Wed, 23 Jul 2025 14:40:41 +0100 Subject: [PATCH] feat: create Recent Edits component --- package-lock.json | 34 +++++++ package.json | 1 + src/components/EntriesListSidebar.tsx | 3 +- src/components/RecentEditsDataTable.tsx | 104 +++++++++++++++++++++ src/components/TagListSidebar.tsx | 68 +++++++------- src/components/ui/table.tsx | 114 ++++++++++++++++++++++++ src/containers/RecentEdits.tsx | 54 +++++++++++ src/pages/home.tsx | 76 +++++++--------- 8 files changed, 372 insertions(+), 82 deletions(-) create mode 100644 src/components/RecentEditsDataTable.tsx create mode 100644 src/components/ui/table.tsx create mode 100644 src/containers/RecentEdits.tsx diff --git a/package-lock.json b/package-lock.json index 0160a5a..622810d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,6 +16,7 @@ "@tailwindcss/vite": "^4.1.4", "@tanstack/react-query": "^5.83.0", "@tanstack/react-query-devtools": "^5.83.0", + "@tanstack/react-table": "^8.21.3", "axios": "^1.10.0", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", @@ -2112,6 +2113,39 @@ "react": "^18 || ^19" } }, + "node_modules/@tanstack/react-table": { + "version": "8.21.3", + "resolved": "https://registry.npmjs.org/@tanstack/react-table/-/react-table-8.21.3.tgz", + "integrity": "sha512-5nNMTSETP4ykGegmVkhjcS8tTLW6Vl4axfEGQN3v0zdHYbK4UfoqfPChclTrJ4EoK9QynqAu9oUf8VEmrpZ5Ww==", + "license": "MIT", + "dependencies": { + "@tanstack/table-core": "8.21.3" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, + "node_modules/@tanstack/table-core": { + "version": "8.21.3", + "resolved": "https://registry.npmjs.org/@tanstack/table-core/-/table-core-8.21.3.tgz", + "integrity": "sha512-ldZXEhOBb8Is7xLs01fR3YEc3DERiz5silj8tnGkFZytt1abEvl/GhUmCE0PMLaMPTa3Jk4HbKmRlHmu+gCftg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, "node_modules/@types/babel__core": { "version": "7.20.5", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", diff --git a/package.json b/package.json index 6c2202f..3952e32 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "@tailwindcss/vite": "^4.1.4", "@tanstack/react-query": "^5.83.0", "@tanstack/react-query-devtools": "^5.83.0", + "@tanstack/react-table": "^8.21.3", "axios": "^1.10.0", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", diff --git a/src/components/EntriesListSidebar.tsx b/src/components/EntriesListSidebar.tsx index 443f2ab..32f7cdd 100644 --- a/src/components/EntriesListSidebar.tsx +++ b/src/components/EntriesListSidebar.tsx @@ -12,7 +12,6 @@ export default function EntriesListSidebar() { queryFn: () => api.get("/entries").then((res) => res.data), }) - console.log(entries) return ( @@ -30,7 +29,7 @@ export default function EntriesListSidebar() { - {entries?.entries.map((item, i) => ( + {entries?.data.map((item, i) => ( {item.title.replace(/_/g, " ")} diff --git a/src/components/RecentEditsDataTable.tsx b/src/components/RecentEditsDataTable.tsx new file mode 100644 index 0000000..47ce4eb --- /dev/null +++ b/src/components/RecentEditsDataTable.tsx @@ -0,0 +1,104 @@ +import { + flexRender, + getCoreRowModel, + useReactTable, + getPaginationRowModel, +} from "@tanstack/react-table" + +import { Button } from "./ui/button" +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "@/components/ui/table" + +export function RecentEditsDataTable({ columns, data, loading }) { + const table = useReactTable({ + data, + columns, + getCoreRowModel: getCoreRowModel(), + getPaginationRowModel: getPaginationRowModel(), + }) + + const pageCount = table.getPageCount() + const currentPage = table.getState().pagination?.pageIndex + return ( +
+
+ + + {table.getHeaderGroups().map((headerGroup) => ( + + {headerGroup.headers.map((header) => { + return ( + + {header.isPlaceholder + ? null + : flexRender( + header.column.columnDef.header, + header.getContext(), + )} + + ) + })} + + ))} + + + {table.getRowModel().rows?.length ? ( + table.getRowModel().rows.map((row) => ( + + {row.getVisibleCells().map((cell) => ( + + {flexRender(cell.column.columnDef.cell, cell.getContext())} + + ))} + + )) + ) : loading ? ( + + + Loading... + + + ) : ( + + + No results. + + + )} + +
+
+
+
+ {`${currentPage + 1} of ${pageCount}`} +
+
+ + +
+
+
+ ) +} diff --git a/src/components/TagListSidebar.tsx b/src/components/TagListSidebar.tsx index ccc9fda..7c2b297 100644 --- a/src/components/TagListSidebar.tsx +++ b/src/components/TagListSidebar.tsx @@ -8,41 +8,41 @@ import api from "../api/eolas-api" import { Badge } from "./ui/badge" export default function TagListSidebar() { - const { data: tags, isLoading } = useQuery({ - queryKey: ["tag_list"], - queryFn: () => api.get("/tags").then((res) => res.data), - }) + const { data: tags, isLoading } = useQuery({ + queryKey: ["tag_list"], + queryFn: () => api.get("/tags").then((res) => res.data), + }) - console.log(tags) + console.log(tags) - return ( - - - - -
- - Tags - - {tags?.count} - + return ( + + + + + + + Tags + + {tags?.count} + - - - - - - - {tags?.tags.map((item, i) => ( - - - {item} - - - ))} - - -
-
- ) + + + + + + + {tags?.data.map((item, i) => ( + + + {item} + + + ))} + + + + + ) } diff --git a/src/components/ui/table.tsx b/src/components/ui/table.tsx new file mode 100644 index 0000000..5513a5c --- /dev/null +++ b/src/components/ui/table.tsx @@ -0,0 +1,114 @@ +import * as React from "react" + +import { cn } from "@/lib/utils" + +function Table({ className, ...props }: React.ComponentProps<"table">) { + return ( +
+ + + ) +} + +function TableHeader({ className, ...props }: React.ComponentProps<"thead">) { + return ( + + ) +} + +function TableBody({ className, ...props }: React.ComponentProps<"tbody">) { + return ( + + ) +} + +function TableFooter({ className, ...props }: React.ComponentProps<"tfoot">) { + return ( + tr]:last:border-b-0", + className + )} + {...props} + /> + ) +} + +function TableRow({ className, ...props }: React.ComponentProps<"tr">) { + return ( + + ) +} + +function TableHead({ className, ...props }: React.ComponentProps<"th">) { + return ( +
[role=checkbox]]:translate-y-[2px]", + className + )} + {...props} + /> + ) +} + +function TableCell({ className, ...props }: React.ComponentProps<"td">) { + return ( + [role=checkbox]]:translate-y-[2px]", + className + )} + {...props} + /> + ) +} + +function TableCaption({ + className, + ...props +}: React.ComponentProps<"caption">) { + return ( +
+ ) +} + +export { + Table, + TableHeader, + TableBody, + TableFooter, + TableHead, + TableRow, + TableCell, + TableCaption, +} diff --git a/src/containers/RecentEdits.tsx b/src/containers/RecentEdits.tsx new file mode 100644 index 0000000..545d31e --- /dev/null +++ b/src/containers/RecentEdits.tsx @@ -0,0 +1,54 @@ +import { RecentEditsDataTable } from "@/components/RecentEditsDataTable" +import { useQuery } from "@tanstack/react-query" +import api from "../api/eolas-api" + +const columns = [ + { + accessorKey: "title", + header: "Title", + }, + { + accessorKey: "date", + header: "Date", + }, + { + accessorKey: "time", + header: "Time", + }, +] + +export default function RecentEdits() { + const { data, isLoading } = useQuery({ + queryKey: ["entries_recent"], + queryFn: () => api.get("/entries?limit=20&sort=date").then((res) => res.data), + }) + + console.log(data) + const parsed = data?.data?.map((entry) => { + const [date, time] = entry?.last_modified?.split(" ") + return { + title: entry.title.replace(/_/g, " "), + date: new Date(date).toLocaleString("en-GB", { + day: "numeric", + month: "long", + year: "numeric", + }), + time: time, + } + }) + + return ( + <> +
+
+

Recent edits

+
+
+
+ +
+
+
+ + ) +} diff --git a/src/pages/home.tsx b/src/pages/home.tsx index a9e616a..3b60326 100644 --- a/src/pages/home.tsx +++ b/src/pages/home.tsx @@ -1,36 +1,29 @@ -import { Card, CardContent } from "@/components/ui/card" import Main from "@/templates/Main" - -// const scoreData = [ -// { label: "Total Posts", count: "548" }, -// { label: "Tags", count: "68" }, -// { label: "Backlinks", count: "766" }, -// ] +import RecentEdits from "@/containers/RecentEdits" export default function Home() { - return ( - <> -
- {/* -
- {scoreData.map((item, index) => ( - - ))} + return ( + <> +
+
+
+
+
+
+

Welcome

+
+
+

+ I'm Thomas. Eólas is my technical knowledge management system, or + "second-brain", comprising notes from my study of software engineering + and computer science. +

+
+
- */} - -
-
-
- - -

Welcome

-

- I'm Thomas. Eólas is my technical knowledge management system, or - "second-brain", comprising notes from my study of software engineering - and computer science. -

+ {/* +

{" "} @@ -39,22 +32,13 @@ export default function Home() {

-

Recent edits

-
-
-
-
-
-
- - ) + */} +
+ +
+
+ +
+ + ) } - -// const ScoreCard = ({ label, count }) => ( -//
-//
-//

{count}

-//

{label}

-//
-//
-// )