Commit 0a90c97

HPCesia <me@hpcesia.com>
2026-08-10 05:14:08
Add publish datetime to content schema
1 parent 52df230
Changed files (5)
src/contents/posts/test.typ
@@ -3,6 +3,11 @@
     title: "Test page",
     author: "HPCesia",
     desc: "Test Page",
+    date: datetime(
+      year: 2025,
+      month: 3,
+      day: 12,
+    ),
   )
 )<frontmatter>
 
src/pages/posts/index.astro
@@ -7,9 +7,13 @@ import BaseLayout from "@/layouts/BaseLayout.astro";
 const posts = await getCollection("posts");
 ---
 <BaseLayout title="Posts">
-
-    <h1>Posts</h1>
-    {
-        posts.map(post => (<li><a href={url("/posts/" + post.id)}>{post.data.title}</a></li>))
-    }
+  <h1>Posts</h1>
+  {
+    posts.map((post) => (
+      <li>
+        <a href={url("/posts/" + post.id)}>{post.data.title}</a>
+        <time>{Temporal.ZonedDateTime.from(post.data.date).toPlainDateTime().toLocaleString("en-US")}</time>
+      </li>)
+    )
+  }
 </BaseLayout>
src/types/config.d.ts
@@ -15,4 +15,10 @@ export type SiteConfig = {
    * Description of this website.
    */
   description: string;
+  /**
+   * Time zone of typst posts' date.
+   * It should be a valid IANA time zone name,
+   * e.g. `"Etc/UTC"`, `"America/New_York"`, `"Asia/Shanghai"`.
+   */
+  timeZone: string;
 };
src/config.ts
@@ -5,4 +5,5 @@ export const SITE_CONFIG: SiteConfig = {
   title: "Kerplunk",
   author: "John Doe",
   description: "A static blog template.",
+  timeZone: "Etc/UTC",
 };
src/content.config.ts
@@ -2,6 +2,8 @@ import { defineCollection } from "astro:content";
 import { glob } from "astro/loaders";
 import { z } from "astro/zod";
 
+import { SITE_CONFIG } from "@/config.ts";
+
 const typCollection = defineCollection({
   loader: glob({
     pattern: "**/[^_]*.{typ,typst}",
@@ -11,6 +13,30 @@ const typCollection = defineCollection({
     title: z.string(),
     author: z.string().optional(),
     desc: z.any().optional(),
+    date: z.string().transform((str) => {
+      const match = str.match(
+        /datetime\(\s*year:\s*(\d+),?\s*month:\s*(\d+),?\s*day:\s*(\d+)(?:,?\s*hour:\s*(\d+))?(?:,?\s*minute:\s*(\d+))?(?:,?\s*second:\s*(\d+))?,?\s*\)/,
+      );
+      if (match) {
+        const year = parseInt(match[1], 10);
+        const month = parseInt(match[2], 10);
+        const day = parseInt(match[3], 10);
+        const hour = match[4] ? parseInt(match[4], 10) : 0;
+        const minute = match[5] ? parseInt(match[5], 10) : 0;
+        const second = match[6] ? parseInt(match[6], 10) : 0;
+
+        return Temporal.ZonedDateTime.from({
+          year,
+          month,
+          day,
+          hour,
+          minute,
+          second,
+          timeZone: SITE_CONFIG.timeZone,
+        }).toString();
+      }
+      return z.NEVER;
+    }),
   }),
 });