Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 3 additions & 11 deletions app/components/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,26 +8,18 @@ import { Github as GithubIcon } from "./icons/Github";
import { AuthNav } from "./AuthNav";
import { BrandMark } from "./BrandMark";
import { LiveEditionLabel } from "./LiveEditionLabel";
import { LiveDate } from "./LiveDate";

export async function Header() {
const t = await getTranslations("header");
const now = new Date();
const editionTimestampMs = now.getTime();
const formattedDate = now.toLocaleDateString("en-US", {
month: "long",
day: "numeric",
year: "numeric",
timeZone: "Australia/Sydney",
});
const editionTimestampMs = new Date().getTime();
return (
<header className="fixed top-0 w-full z-50 bg-[var(--background)] border-b border-[var(--foreground)] py-2 transition-colors duration-300">
<div className="container mx-auto px-6">
<div className="flex items-center justify-between border-b border-[var(--foreground)] pb-2 mb-2 transition-colors duration-300">
<LiveEditionLabel initialTimestamp={editionTimestampMs} />
<BrandMark priority />
<div className="font-mono text-[10px] uppercase tracking-widest text-neutral-500">
{formattedDate}
</div>
<LiveDate initialTimestamp={editionTimestampMs} />
</div>

<div className="flex items-center justify-end md:justify-between h-10">
Expand Down
40 changes: 40 additions & 0 deletions app/components/LiveDate.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
"use client";

import { useEffect, useState } from "react";

type LiveDateProps = {
// milliseconds since epoch
initialTimestamp: number;
};

// 固定时区(悉尼)保证服务端/客户端首帧一致,避免 hydration mismatch;
// 挂载后每秒刷新,避免 SSG/ISR 把 build 时刻的日期冻住。
const TIMEZONE = "Australia/Sydney";

function formatDate(ms: number) {
return new Date(ms).toLocaleDateString("en-US", {
month: "long",
day: "numeric",
year: "numeric",
timeZone: TIMEZONE,
});
}

export function LiveDate({ initialTimestamp }: LiveDateProps) {
const [formattedDate, setFormattedDate] = useState(() =>
formatDate(initialTimestamp),
);

useEffect(() => {
const update = () => setFormattedDate(formatDate(Date.now()));
update();
const intervalId = setInterval(update, 1000);
return () => clearInterval(intervalId);
}, []);

return (
<div className="font-mono text-[10px] uppercase tracking-widest text-neutral-500">
{formattedDate}
</div>
);
}
Loading