summaryrefslogtreecommitdiff
path: root/src/pages/blog
diff options
context:
space:
mode:
Diffstat (limited to 'src/pages/blog')
-rw-r--r--src/pages/blog/[...date].astro259
1 files changed, 181 insertions, 78 deletions
diff --git a/src/pages/blog/[...date].astro b/src/pages/blog/[...date].astro
index d66ac8e..a0764be 100644
--- a/src/pages/blog/[...date].astro
+++ b/src/pages/blog/[...date].astro
@@ -1,14 +1,176 @@
---
import type {
+ GetStaticPaths,
+ GetStaticPathsItem,
InferGetStaticParamsType,
InferGetStaticPropsType,
} from "astro";
import Base from "@layouts/Base.astro";
+import PrevNext from "@layouts/PrevNext.astro";
import DateSelector from "@components/DateSelector.astro";
import SimplePostList from "@components/templates/SimplePostList.astro";
-import { datePaths, sortLastCreated } from "@lib/collection/helpers";
+import { fromPosts, isEntry, sortLastCreated } from "@lib/collection/helpers";
+import type { Entry } from "@lib/collection/schemas";
+import { identity } from "@utils/anonymous";
-export const getStaticPaths = datePaths;
+export const getStaticPaths = (async (): Promise<
+ {
+ params: { date?: string };
+ props: {
+ posts: Entry[];
+ next?: string;
+ previous?: string;
+ years: number[];
+ months: number[];
+ days?: number[];
+ };
+ }[]
+> => {
+ const posts = await fromPosts(isEntry, identity);
+
+ const archive = {
+ years: new Set<number>(),
+ monthsByYear: new Map<string, Set<number>>(),
+ daysByMonth: new Map<string, Set<number>>(),
+ postsByDate: new Map<string, typeof posts>(),
+ sortedDates: [] as string[],
+ };
+
+ const getYMD = (date: Date) => {
+ const y = date.getFullYear();
+ const m = date.getMonth() + 1;
+ const d = date.getDate();
+ return { y, m, d };
+ };
+
+ for (const post of posts) {
+ const { y, m, d } = getYMD(post.data.dateCreated);
+
+ archive.years.add(y);
+
+ const months = archive.monthsByYear.get(y.toString());
+ if (months === undefined) {
+ archive.monthsByYear.set(y.toString(), new Set([m]));
+ } else {
+ months.add(m);
+ }
+
+ const ym = `${y}/${String(m).padStart(2, "0")}`;
+ const days = archive.daysByMonth.get(ym);
+ if (days === undefined) {
+ archive.daysByMonth.set(ym, new Set([d]));
+ } else {
+ days.add(d);
+ }
+
+ const ymd = `${ym}/${String(d).padStart(2, "0")}`;
+ const posts = archive.postsByDate.get(ymd);
+ if (posts === undefined) {
+ archive.postsByDate.set(ymd, [post]);
+ } else {
+ posts.push(post);
+ }
+ }
+
+ archive.sortedDates = Array.from(archive.postsByDate.keys()).sort();
+
+ const paths: {
+ params: { date?: string };
+ props: {
+ posts: Entry[];
+ next?: string;
+ previous?: string;
+ years: number[];
+ months: number[];
+ days?: number[];
+ };
+ }[] = [] satisfies GetStaticPathsItem[];
+
+ const sortedYears = Array.from(archive.years).sort();
+
+ const lastYear = Math.max(...sortedYears.map(Number));
+ paths.push({
+ params: { date: undefined },
+ props: {
+ posts: posts.filter((p) =>
+ p.data.dateCreated.getFullYear() === lastYear
+ ),
+ next: undefined,
+ previous: sortedYears?.[sortedYears.length - 2]?.toString(),
+ years: sortedYears,
+ months: Array.from(archive.monthsByYear.get(lastYear.toString()) ?? []),
+ },
+ });
+
+ for (const y of sortedYears) {
+ const yearPosts = posts.filter((p) =>
+ p.data.dateCreated.getFullYear() === Number(y)
+ );
+ const idx = sortedYears.indexOf(y);
+ paths.push({
+ params: { date: y.toString() },
+ props: {
+ posts: yearPosts,
+ next: sortedYears?.[idx + 1]?.toString(),
+ previous: sortedYears?.[idx - 1]?.toString(),
+ years: sortedYears,
+ months: Array.from(archive.monthsByYear.get(y.toString()) ?? []),
+ },
+ });
+ }
+
+ const allMonths = Array.from(archive.monthsByYear.entries())
+ .flatMap(([year, mset]) =>
+ Array.from(mset).map((m) => `${year}/${String(m).padStart(2, "0")}`)
+ )
+ .sort();
+
+ for (const [y, months] of archive.monthsByYear) {
+ const sortedMonths = Array.from(months).sort();
+ for (const m of sortedMonths) {
+ const monthPosts = posts.filter((p) => {
+ const d = p.data.dateCreated;
+ return (
+ d.getFullYear() === Number(y) &&
+ d.getMonth() + 1 === m
+ );
+ });
+
+ const ym = `${y}/${String(m).padStart(2, "0")}`;
+ const idx = allMonths.indexOf(ym);
+
+ paths.push({
+ params: { date: ym },
+ props: {
+ posts: monthPosts,
+ next: allMonths?.[idx + 1],
+ previous: allMonths?.[idx - 1],
+ years: sortedYears,
+ months: Array.from(months).sort(),
+ days: Array.from(archive.daysByMonth.get(ym) ?? []).sort(),
+ },
+ });
+ }
+ }
+
+ for (let i = 0; i < archive.sortedDates.length; i++) {
+ const ymd = archive.sortedDates[i];
+ const [y, m] = ymd.split("/");
+ paths.push({
+ params: { date: ymd },
+ props: {
+ posts: archive.postsByDate.get(ymd) ?? [],
+ next: archive.sortedDates?.[i + 1],
+ previous: archive.sortedDates?.[i - 1],
+ years: sortedYears,
+ months: Array.from(archive.monthsByYear.get(y) ?? []).sort(),
+ days: Array.from(archive.daysByMonth.get(`${y}/${m}`) ?? []).sort(),
+ },
+ });
+ }
+
+ return paths;
+}) satisfies GetStaticPaths;
export type Params = InferGetStaticParamsType<typeof getStaticPaths>;
export type Props = InferGetStaticPropsType<typeof getStaticPaths>;
@@ -29,7 +191,8 @@ const format = date === undefined
month: dateParts?.[1] === undefined ? undefined : "long",
day: dateParts?.[2] === undefined ? undefined : "numeric",
}).format(date);
-const title = "Publicações" + (format !== undefined ? ` -- ${format}` : "");
+const title = "Publicações" +
+ (format !== undefined ? ` &ndash; ${format}` : "");
const description = "Ultímas publicações" +
(format !== undefined ? ` do dia ${format}` : "") + ".";
---
@@ -46,83 +209,23 @@ const description = "Ultímas publicações" +
itemscope
itemtype="http://schema.org/Blog"
>
- <h2 itemprop="name description">{title}</h2>
+ <h2 itemprop="name description" set:html={title} />
<DateSelector {date} {years} {months} {days} />
- {
- (next || previous) && (
- <nav>
- {
- previous && (
- <p>
- &lt; <a href={`/blog/${Astro.props.previous}`}>Anterior</a>
- </p>
- )
- }
- <span class="small">{format}</span>
- {
- next && (
- <p><a href={`/blog/${Astro.props.next}`}>Próximo</a> &gt;</p>
- )
- }
- </nav>
- )
- }
- <SimplePostList
- {posts}
- dateOptions={{
- weekday: "long",
- year: "numeric",
- month: "long",
- day: "numeric",
- hour: "2-digit",
- minute: "2-digit",
- timeZoneName: "long",
- }}
- />
- {
- (next || previous) && (
- <nav>
- {
- previous && (
- <p>
- &lt; <a href={`/blog/${Astro.props.previous}`}>Anterior</a>
- </p>
- )
- }
- <span class="small">{format}</span>
- {
- next && (
- <p><a href={`/blog/${Astro.props.next}`}>Próximo</a> &gt;</p>
- )
- }
- </nav>
- )
- }
+ <PrevNext {previous} {next} label={format}>
+ <SimplePostList
+ {posts}
+ dateOptions={{
+ weekday: "long",
+ year: "numeric",
+ month: "long",
+ day: "numeric",
+ hour: "2-digit",
+ minute: "2-digit",
+ timeZoneName: "long",
+ }}
+ />
+ </PrevNext>
<DateSelector {date} {years} {months} {days} />
</section>
</main>
</Base>
-
-<style>
- nav {
- display: flex;
- align-items: center;
- padding-block: calc(var(--size-2) * 1em);
- gap: calc(var(--size-2) * 1em);
- justify-content: center;
- & > p {
- border-radius: calc(var(--size-0) * 1em);
- border-width: 1px;
- box-shadow: 0 1px 2px var(--color-light);
- font-size: calc(var(--size-3) * 1rem);
- font-weight: 500;
- padding-inline: calc(var(--size-3) * 1em);
- padding-block: calc(var(--size-2) * 1em);
- display: inline-flex;
- gap: calc(var(--size-2) * 1em);
- align-items: center;
- justify-content: center;
- height: 2ch;
- }
- }
-</style>