mirror of
https://github.com/ChenQihan666/MyBlog-Next.git
synced 2026-08-14 07:33:07 +08:00
feat: add global and per-post timezone support (#491)
* refactor: replace embedded svg with svg icon * feat: add global and per-post timezone support - add `SITE.timezone` in config to define a global default timezone. - allow per-post timezone overrides via `timezone` in frontmatter. - update date formatting logic to use the correct timezone when rendering timestamps. - ensure that posts without a timezone fallback to `SITE.timezone`. - improve consistency between local and deployed timezones. * refactor: replace `LOCALE` constant with `SITE.lang` * docs: update guides * fix: update code word-break inside markdown table Closes #466
This commit is contained in:
@@ -10,7 +10,7 @@ export interface Props extends CollectionEntry<"blog"> {
|
||||
|
||||
const { variant = "h2", data, id, filePath } = Astro.props;
|
||||
|
||||
const { title, pubDatetime, modDatetime, description } = data;
|
||||
const { title, description, pubDatetime, modDatetime, timezone } = data;
|
||||
|
||||
const headerProps = {
|
||||
style: { viewTransitionName: slugifyStr(title) },
|
||||
@@ -31,6 +31,6 @@ const headerProps = {
|
||||
)
|
||||
}
|
||||
</a>
|
||||
<Datetime {pubDatetime} {modDatetime} />
|
||||
<Datetime {pubDatetime} {modDatetime} {timezone} />
|
||||
<p>{description}</p>
|
||||
</li>
|
||||
|
||||
@@ -1,11 +1,19 @@
|
||||
---
|
||||
import { LOCALE } from "@/constants";
|
||||
import dayjs from "dayjs";
|
||||
import utc from "dayjs/plugin/utc";
|
||||
import timezone from "dayjs/plugin/timezone";
|
||||
import IconCalendar from "@/assets/icons/IconCalendar.svg";
|
||||
import { SITE } from "@/config";
|
||||
|
||||
dayjs.extend(utc);
|
||||
dayjs.extend(timezone);
|
||||
|
||||
export interface Props {
|
||||
class?: string;
|
||||
size?: "sm" | "lg";
|
||||
timezone: string | undefined;
|
||||
pubDatetime: string | Date;
|
||||
modDatetime: string | Date | undefined | null;
|
||||
size?: "sm" | "lg";
|
||||
class?: string;
|
||||
}
|
||||
|
||||
const {
|
||||
@@ -13,52 +21,36 @@ const {
|
||||
modDatetime,
|
||||
size = "sm",
|
||||
class: className = "",
|
||||
timezone: postTimezone,
|
||||
} = Astro.props;
|
||||
|
||||
/* ========== Formatted Datetime ========== */
|
||||
const myDatetime = new Date(
|
||||
modDatetime && modDatetime > pubDatetime ? modDatetime : pubDatetime
|
||||
);
|
||||
const date = myDatetime.toLocaleDateString(LOCALE.langTag, {
|
||||
year: "numeric",
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
});
|
||||
const latestDatetime =
|
||||
modDatetime && modDatetime > pubDatetime ? modDatetime : pubDatetime;
|
||||
const datetime = dayjs(latestDatetime).tz(postTimezone || SITE.timezone);
|
||||
|
||||
const time = myDatetime.toLocaleTimeString(LOCALE.langTag, {
|
||||
hour: "2-digit",
|
||||
minute: "2-digit",
|
||||
});
|
||||
const date = datetime.format("D MMM, YYYY"); // e.g., '22 Mar, 2025'
|
||||
const time = datetime.format("hh:mm A"); // e.g., '08:30 PM'
|
||||
---
|
||||
|
||||
<div class={`flex items-end space-x-2 opacity-80 ${className}`.trim()}>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class={`${
|
||||
size === "sm" ? "scale-90" : "scale-100"
|
||||
} inline-block h-6 w-6 min-w-[1.375rem] fill-foreground`}
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path
|
||||
d="M7 11h2v2H7zm0 4h2v2H7zm4-4h2v2h-2zm0 4h2v2h-2zm4-4h2v2h-2zm0 4h2v2h-2z"
|
||||
></path>
|
||||
<path
|
||||
d="M5 22h14c1.103 0 2-.897 2-2V6c0-1.103-.897-2-2-2h-2V2h-2v2H9V2H7v2H5c-1.103 0-2 .897-2 2v14c0 1.103.897 2 2 2zM19 8l.001 12H5V8h14z"
|
||||
></path>
|
||||
</svg>
|
||||
<div class:list={["flex items-end space-x-2 opacity-80", className]}>
|
||||
<IconCalendar
|
||||
class:list={[
|
||||
"inline-block size-6 min-w-[1.375rem]",
|
||||
{ "scale-90": size === "sm" },
|
||||
]}
|
||||
/>
|
||||
{
|
||||
modDatetime && modDatetime > pubDatetime ? (
|
||||
<span
|
||||
class={`italic ${size === "sm" ? "text-sm" : "text-sm sm:text-base"}`}
|
||||
>
|
||||
<span class:list={["text-sm italic", { "sm:text-base": size === "lg" }]}>
|
||||
Updated:
|
||||
</span>
|
||||
) : (
|
||||
<span class="sr-only">Published:</span>
|
||||
)
|
||||
}
|
||||
<span class={`italic ${size === "sm" ? "text-sm" : "text-sm sm:text-base"}`}>
|
||||
<time datetime={myDatetime.toISOString()}>{date}</time>
|
||||
<span class:list={["text-sm italic", { "sm:text-base": size === "lg" }]}>
|
||||
<time datetime={datetime.toISOString()}>{date}</time>
|
||||
<span aria-hidden="true"> | </span>
|
||||
<span class="sr-only"> at </span>
|
||||
<span class="text-nowrap">{time}</span>
|
||||
|
||||
Reference in New Issue
Block a user