diff --git a/src/components/Table.tsx b/src/components/Table.tsx index 1fb046a..c0e82cb 100644 --- a/src/components/Table.tsx +++ b/src/components/Table.tsx @@ -1,11 +1,12 @@ import React from 'react'; +import usePagination, { Offset } from 'src/hooks/usePagination'; -type DataItem = Record; +export type DataItem = Record; export interface Header { key: string; header: string; - formatter?: (data: DataItem) => JSX.ElementType; + formatter?: (data: DataItem) => string; } interface Props { @@ -14,33 +15,74 @@ interface Props { } export default function Table({ data, headers }: Props): JSX.Element { - function getProperty(data: DataItem, header: Header): any { - if (header.key === 'index') { - return 'index'; + const { items, changeOffset } = usePagination({ items: data }); + + function formatCell(data: DataItem, header: Header): JSX.Element { + // This formatting is only used because the source is trusted (private markdown files manage only by me) + // and because Astro don't allow me to pass JSX from an Astro file to a TSX file, + // so I have to pass the formatted row as a string. + // DON'T use this method on a public API + if (header.formatter != null) { + return ( +
+ ); } return data[header.key]; } return ( - - - - {headers.map((item, idx) => ( - - ))} - - - - - {data.map((item, idx) => ( - - {headers.map((header, hidx) => ( - + <> +
{item.header}
{getProperty(item.data, header)}
+ + + {headers.map((item, idx) => ( + ))} - ))} - -
{item.header}
+ + + + {items.map((item, idx) => ( + + {headers.map((header, hidx) => ( + {formatCell(item, header)} + ))} + + ))} + + + +
+ + + + +
+ ); } diff --git a/src/content b/src/content index efff561..65edd2d 160000 --- a/src/content +++ b/src/content @@ -1 +1 @@ -Subproject commit efff561a802a40e93493d01a50ef228bfe0c485e +Subproject commit 65edd2d35506ff4169b2ab6db1e48c167f64d73e diff --git a/src/hooks/usePagination.tsx b/src/hooks/usePagination.tsx new file mode 100644 index 0000000..56c0821 --- /dev/null +++ b/src/hooks/usePagination.tsx @@ -0,0 +1,90 @@ +import { useReducer } from 'react'; + +export interface IUsePagination { + items: T[]; + changeOffset: (offset: Offset) => void; +} + +interface Props { + items: T[]; +} + +interface State { + offset: number; + total: number; + limit: number; +} + +type ActionType = + | { type: 'update'; value: any; name: string } + | { type: 'update'; value: any; name: string }; + +export enum Offset { + Next, + Prev, + First, + Last, +} + +export default function usePagination({ + items, +}: Props): IUsePagination { + const reducer = (state: State, action: ActionType): State => { + switch (action.type) { + case 'update': + return { + ...state, + [action.name]: action.value, + }; + default: + return state; + } + }; + + const [state, dispatch] = useReducer(reducer, { + offset: 0, + total: 0, + limit: 30, + }); + + const changeOffset = (offset: Offset): void => { + switch (offset) { + case Offset.Next: + dispatch({ + type: 'update', + name: 'offset', + value: state.offset + state.limit, + }); + break; + case Offset.Prev: + dispatch({ + type: 'update', + name: 'offset', + value: state.offset - state.limit, + }); + break; + case Offset.First: + dispatch({ + type: 'update', + name: 'offset', + value: 0, + }); + break; + case Offset.Last: + dispatch({ + type: 'update', + name: 'offset', + value: items.length - state.limit, + }); + break; + + default: + break; + } + }; + + return { + changeOffset, + items: items.slice(state.offset, state.offset + state.limit), + }; +} diff --git a/src/pages/games/index.astro b/src/pages/games/index.astro index 370b8d0..79f8822 100644 --- a/src/pages/games/index.astro +++ b/src/pages/games/index.astro @@ -3,16 +3,23 @@ import { getCollection } from 'astro:content'; import Layout from '@layouts/Layout.astro'; import Table, { type Header } from '@components/Table.jsx'; -const games = await getCollection('games'); +const rawGames = await getCollection('games'); + +const games = rawGames.map((item, idx) => ({ + ...item.data, + id: idx, + slug: item.slug, +})); const headers: Header[] = [ { - key: 'index', + key: 'id', header: 'index', }, { key: 'title', header: 'Title', + formatter: (data) => `${data.title}`, }, { key: 'status', @@ -29,11 +36,11 @@ const headers: Header[] = [ ]; --- - +

Games

- +
@@ -41,7 +48,7 @@ const headers: Header[] = [ { games.map((item) => (
  • - {item.data.title} + {item.title}
  • )) }