From 54af3eb68f85c33beced189e42903cd5be261915 Mon Sep 17 00:00:00 2001 From: DefectingCat Date: Tue, 21 Jun 2022 15:51:03 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20Pagination=20for=20gists?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/RUA/Button.tsx | 33 +++++++++ components/gists/FileContent.tsx | 2 +- ...styles.module.css => GistsCode.module.css} | 0 components/gists/GistsCode.tsx | 2 +- components/gists/Pagination.tsx | 48 +++++++++++++ lib/fetcher.ts | 71 +++++++++++++++---- pages/g/[id].tsx | 24 +++---- pages/gists/[p].tsx | 13 ++-- pages/gists/index.tsx | 7 +- 9 files changed, 166 insertions(+), 34 deletions(-) create mode 100644 components/RUA/Button.tsx rename components/gists/{styles.module.css => GistsCode.module.css} (100%) create mode 100644 components/gists/Pagination.tsx diff --git a/components/RUA/Button.tsx b/components/RUA/Button.tsx new file mode 100644 index 0000000..b8594e1 --- /dev/null +++ b/components/RUA/Button.tsx @@ -0,0 +1,33 @@ +import classNames from 'classnames'; + +export type ButtonProps = { + children: React.ReactNode; + disabled?: boolean; +}; + +const Button = ({ children, disabled }: ButtonProps) => { + return ( + <> + + + ); +}; + +export default Button; diff --git a/components/gists/FileContent.tsx b/components/gists/FileContent.tsx index 72ab569..c81b96b 100644 --- a/components/gists/FileContent.tsx +++ b/components/gists/FileContent.tsx @@ -16,7 +16,7 @@ type Props = { const FileContent = ({ gists }: Props) => { return ( <> -
+
{gists.map((g) => (
{Object.keys(g.files).map((f) => ( diff --git a/components/gists/styles.module.css b/components/gists/GistsCode.module.css similarity index 100% rename from components/gists/styles.module.css rename to components/gists/GistsCode.module.css diff --git a/components/gists/GistsCode.tsx b/components/gists/GistsCode.tsx index 215d0d6..7fe44c1 100644 --- a/components/gists/GistsCode.tsx +++ b/components/gists/GistsCode.tsx @@ -7,7 +7,7 @@ import remarkParse from 'remark-parse'; import remarkRehype from 'remark-rehype'; import { GistsFile } from 'types'; import { unified } from 'unified'; -import styles from './styles.module.css'; +import styles from './GistsCode.module.css'; interface Props { file: GistsFile; diff --git a/components/gists/Pagination.tsx b/components/gists/Pagination.tsx new file mode 100644 index 0000000..f0eac06 --- /dev/null +++ b/components/gists/Pagination.tsx @@ -0,0 +1,48 @@ +import { pageSize } from 'lib/fetcher'; +import dynamic from 'next/dynamic'; +import Link from 'next/link'; + +const Button = dynamic(() => import('components/RUA/Button')); + +type Props = { + pageSize: pageSize; +}; + +const Pagination = ({ pageSize }: Props) => { + const prev = Number(pageSize.prev); + const next = Number(pageSize.next); + + return ( + <> + + + ); +}; + +export default Pagination; diff --git a/lib/fetcher.ts b/lib/fetcher.ts index d5ed515..9e446c0 100644 --- a/lib/fetcher.ts +++ b/lib/fetcher.ts @@ -7,7 +7,7 @@ const octokit = new Octokit({ }); const linkMatch = /<(.*?)>/; -// const relMatch = /"(.*?)"/; +const relMatch = /"(.*?)"/; export type GistData = { id: string; @@ -17,10 +17,11 @@ export type GistData = { description: string | null; }; export type GetGists = { - next: string | null; - total: string | null; + pageSize: pageSize; gists: GistData[]; }; +export type pageSize = { [key in PageKeys]: string | null }; +export type PageKeys = 'prev' | 'next' | 'last' | 'first'; /** * Get all gists. @@ -31,15 +32,30 @@ export const getGists = async (page = 1, perPage = 10) => { page, per_page: perPage, }); + /** + * + * ; rel="prev", + * ; rel="next", + * ; rel="last", + * ; rel="first" + */ const link = result.headers.link?.split(','); if (!link) return null; - const next = new URLSearchParams( - link[0].match(linkMatch)?.[1].split('?')[1] - ).get('page'); - const total = new URLSearchParams( - link[1].match(linkMatch)?.[1].split('?')[1] - ).get('page'); + + const pageSize: pageSize = { + prev: null, + next: null, + last: null, + first: null, + }; + link.map((l) => { + const text = l.match(relMatch)?.[1] as PageKeys; + if (!text) return; + pageSize[text] = new URLSearchParams( + l.match(linkMatch)?.[1].split('?')[1] + ).get('page'); + }); const data: GistData[] = result.data.map((item) => ({ id: item.id, @@ -62,8 +78,7 @@ export const getGists = async (page = 1, perPage = 10) => { ); return { - next, - total, + pageSize, gists: data, }; }; @@ -77,15 +92,47 @@ export const getUser = async () => { return (await octokit.rest.users.getAuthenticated()).data; }; +export type GetSignalGist = Awaited>; +export type SingalGist = { + login: string | undefined; + files: { [key: string]: GistsFile }; + updated_at: string | undefined; + description: string | undefined | null; +}; /** * Get one gist. * @param id * @returns */ export const getSignalGist = async (id: string) => { - return ( + const result = ( await octokit.rest.gists.get({ gist_id: id, }) ).data; + + if (result.files == null) return; + + const data: SingalGist = { + login: result.owner?.login, + updated_at: result.updated_at, + description: result.description, + files: result.files as SingalGist['files'], + }; + + await Promise.all( + Object.keys(data.files).map(async (f) => { + const url = data.files?.[f]?.raw_url; + if (!url) return; + let target = data.files[f]; + if (!target?.content) + target = { + ...target, + content: '', + }; + target.content = await fetch(url).then((res) => res.text()); + }) + ); + + return data; }; diff --git a/pages/g/[id].tsx b/pages/g/[id].tsx index f57f41b..f4e0fcd 100644 --- a/pages/g/[id].tsx +++ b/pages/g/[id].tsx @@ -1,14 +1,13 @@ import Anchor from 'components/mdx/Anchor'; import dayjs from 'dayjs'; import relativeTime from 'dayjs/plugin/relativeTime'; -import { getSignalGist } from 'lib/fetcher'; +import { getSignalGist, SingalGist } from 'lib/fetcher'; import { GetStaticPaths, GetStaticProps, InferGetStaticPropsType } from 'next'; import dynamic from 'next/dynamic'; import Image from 'next/image'; import Link from 'next/link'; import avatar from 'public/images/img/avatar.svg'; import { ReactElement } from 'react'; -import { SignalGist } from 'types'; const MainLayout = dynamic(() => import('layouts/MainLayout')); const GistsCode = dynamic(() => import('components/gists/GistsCode')); @@ -31,7 +30,7 @@ const Gist = ({ gist }: InferGetStaticPropsType) => { />

- {gist.owner.login} + {gist.login} /{Object.keys(gist.files)[0]}

@@ -67,23 +66,18 @@ export const getStaticPaths: GetStaticPaths = async () => { export const getStaticProps: GetStaticProps<{ id: string | undefined; - gist: SignalGist; + gist: SingalGist; }> = async ({ params }) => { - if (typeof params?.id !== 'string') { + if (typeof params?.id !== 'string') return { notFound: true, }; - } - const gist = await getSignalGist(params?.id); - - await Promise.all( - Object.keys(gist.files).map(async (f) => { - gist.files[f].content = await fetch(gist.files[f].raw_url).then((res) => - res.text() - ); - }) - ); + const gist = await getSignalGist(params.id); + if (!gist || !gist.files) + return { + notFound: true, + }; return { props: { diff --git a/pages/gists/[p].tsx b/pages/gists/[p].tsx index 124a521..3e3441a 100644 --- a/pages/gists/[p].tsx +++ b/pages/gists/[p].tsx @@ -9,6 +9,7 @@ import { ReactElement } from 'react'; const MainLayout = dynamic(() => import('layouts/MainLayout')); const UserInfo = dynamic(() => import('components/gists/UserInfo')); const FileContent = dynamic(() => import('components/gists/FileContent')); +const Pagination = dynamic(() => import('components/gists/Pagination')); dayjs.extend(relativeTime); @@ -21,7 +22,11 @@ const Gists = ({
- + +
+ + +
@@ -30,8 +35,8 @@ const Gists = ({ export const getStaticPaths: GetStaticPaths = async () => { const result = await getGists(); - const next = Number(result?.next); - const total = Number(result?.total); + const next = Number(result?.pageSize.next); + const last = Number(result?.pageSize.last); const paths: ( | string | { @@ -39,7 +44,7 @@ export const getStaticPaths: GetStaticPaths = async () => { locale?: string | undefined; } )[] = []; - for (let i = next; i <= total; i++) { + for (let i = next; i <= last; i++) { paths.push({ params: { p: i.toString(), diff --git a/pages/gists/index.tsx b/pages/gists/index.tsx index 5ecb694..21858f3 100644 --- a/pages/gists/index.tsx +++ b/pages/gists/index.tsx @@ -8,6 +8,7 @@ import { ReactElement } from 'react'; const MainLayout = dynamic(() => import('layouts/MainLayout')); const UserInfo = dynamic(() => import('components/gists/UserInfo')); const FileContent = dynamic(() => import('components/gists/FileContent')); +const Pagination = dynamic(() => import('components/gists/Pagination')); dayjs.extend(relativeTime); @@ -20,7 +21,11 @@ const Gists = ({
- + +
+ + +