Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add pagination #73

Open
wants to merge 16 commits into
base: main
Choose a base branch
from
56 changes: 54 additions & 2 deletions blog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ import type {
export { Fragment, h };

const IS_DEV = Deno.args.includes("--dev") && "watchFs" in Deno;
const POSTS = new Map<string, Post>();
let POSTS = new Map<string, Post>();
const HMR_SOCKETS: Set<WebSocket> = new Set();

const HMR_CLIENT = `let socket;
Expand Down Expand Up @@ -199,6 +199,12 @@ async function loadContent(blogDirectory: string, isDev: boolean) {
}
}

POSTS = new Map(
Array.from(POSTS).sort(([, a], [, b]) =>
b.publishDate.getTime() - a.publishDate.getTime()
),
);

if (isDev) {
watchForChanges(postsDirectory).catch(() => {});
}
Expand Down Expand Up @@ -344,7 +350,39 @@ export async function handler(
}
}

if (pathname === "/" && searchParams.get("page")?.match(/^[0-9]+$/)) {
const index = Number(searchParams.get("page"));
const tagPosts = filterPosts(POSTS, searchParams);
return html({
...sharedHtmlOptions,
ij5 marked this conversation as resolved.
Show resolved Hide resolved
title: blogState.title ?? "My Blog",
meta: {
"description": blogState.description,
"og:title": blogState.title,
"og:description": blogState.description,
"og:image": ogImage ?? blogState.cover,
"twitter:title": blogState.title,
"twitter:description": blogState.description,
"twitter:image": ogImage ?? blogState.cover,
"twitter:card": ogImage ? twitterCard : undefined,
},
styles: [
...(blogState.style ? [blogState.style] : []),
],
body: (
<Index
state={blogState}
index={index}
postsLength={tagPosts.size}
posts={getPostsPage(tagPosts, index)}
searchParams={searchParams}
/>
),
});
}

if (pathname === "/") {
const tagPosts = filterPosts(POSTS, searchParams);
return html({
...sharedHtmlOptions,
title: blogState.title ?? "My Blog",
Expand All @@ -364,7 +402,10 @@ export async function handler(
body: (
<Index
state={blogState}
posts={filterPosts(POSTS, searchParams)}
postsLength={tagPosts.size}
posts={getPostsPage(tagPosts, 0)}
index={0}
searchParams={searchParams}
/>
),
});
Expand Down Expand Up @@ -523,6 +564,17 @@ export function redirects(redirectMap: Record<string, string>): BlogMiddleware {
};
}

function getPostsPage(
ij5 marked this conversation as resolved.
Show resolved Hide resolved
posts: Map<string, Post>,
index: number,
) {
const i = Math.round(index);
if (i < 0) return new Map();
return new Map(
Array.from(posts.entries()).slice(i * 10, i * 10 + 10),
);
}

function filterPosts(
posts: Map<string, Post>,
searchParams: URLSearchParams,
Expand Down
87 changes: 86 additions & 1 deletion components.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,71 @@ const socialAppIcons = new Map([
["linkedin.com", IconLinkedin],
]);

interface PaginationProps {
index: number;
type: "forward" | "backward" | "both";
tag: string | null;
}
function Pagination({ index, type, tag }: PaginationProps) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the UI is not good, i will add a mockup later

let t;
if (tag) t = "&tag=" + tag;
else t = "";
const page = (
<div class="mt-3 flex gap-2 items-center justify-center">
{(type === "backward" || type === "both")
? (
<a
href={`/?page=${index - 1}${t}`}
class="relative flex items-center justify-center w-8 h-8 rounded-full bg-gray-600/10 dark:bg-gray-400/10 text-gray-700 dark:text-gray-400 hover:bg-gray-600/15 dark:hover:bg-gray-400/15 hover:text-black dark:hover:text-white transition-colors group"
>
<IconPrevious />
</a>
)
: ""}
{(type === "forward" || type === "both")
? (
<a
href={`/?page=${index + 1}${t}`}
class="relative flex items-center justify-center w-8 h-8 rounded-full bg-gray-600/10 dark:bg-gray-400/10 text-gray-700 dark:text-gray-400 hover:bg-gray-600/15 dark:hover:bg-gray-400/15 hover:text-black dark:hover:text-white transition-colors group"
>
<IconNext />
</a>
)
: ""}
</div>
);
return page;
}

interface IndexProps {
state: BlogState;
posts: Map<string, Post>;
index: number;
postsLength: number;
searchParams: URLSearchParams;
ij5 marked this conversation as resolved.
Show resolved Hide resolved
}

export function Index({ state, posts }: IndexProps) {
export function Index(
{ state, posts, index, postsLength, searchParams }: IndexProps,
) {
const postIndex = [];
for (const [_key, post] of posts.entries()) {
postIndex.push(post);
}
postIndex.sort(
(a, b) => (b.publishDate?.getTime() ?? 0) - (a.publishDate?.getTime() ?? 0),
);
let page;
const tag = searchParams.get("tag");
if ((index + 1) * 10 >= postsLength && index !== 0) {
page = <Pagination tag={tag} index={index} type={"backward"} />;
} else if (index === 0 && (index + 1) * 10 >= postsLength) {
page = "";
} else if (index === 0) {
page = <Pagination tag={tag} index={index} type={"forward"} />;
} else {
page = <Pagination tag={tag} index={index} type={"both"} />;
}

return (
<div class="home">
Expand Down Expand Up @@ -114,6 +166,7 @@ export function Index({ state, posts }: IndexProps) {
/>
))}
</div>
{page}

{state.footer || <Footer author={state.author} />}
</div>
Expand Down Expand Up @@ -354,6 +407,38 @@ function IconExternalLink() {
);
}

function IconPrevious() {
return (
<svg
className="inline-block w-5 h-5"
viewBox="0 0 512 512"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fill="currentColor"
d="M257.5 445.1l-22.2 22.2c-9.4 9.4-24.6 9.4-33.9 0L7 273c-9.4-9.4-9.4-24.6 0-33.9L201.4 44.7c9.4-9.4 24.6-9.4 33.9 0l22.2 22.2c9.5 9.5 9.3 25-.4 34.3L136.6 216H424c13.3 0 24 10.7 24 24v32c0 13.3-10.7 24-24 24H136.6l120.5 114.8c9.8 9.3 10 24.8.4 34.3z"
/>
</svg>
);
}

function IconNext() {
return (
<svg
className="inline-block w-5 h-5"
viewBox="0 0 512 512"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fill="currentColor"
d="M190.5 66.9l22.2-22.2c9.4-9.4 24.6-9.4 33.9 0L441 239c9.4 9.4 9.4 24.6 0 33.9L246.6 467.3c-9.4 9.4-24.6 9.4-33.9 0l-22.2-22.2c-9.5-9.5-9.3-25 .4-34.3L311.4 296H24c-13.3 0-24-10.7-24-24v-32c0-13.3 10.7-24 24-24h287.4L190.9 101.2c-9.8-9.3-10-24.8-.4-34.3z"
/>
</svg>
);
}

function IconGithub() {
return (
<svg
Expand Down