diff --git a/.cache/gatsby-source-git/categories b/.cache/gatsby-source-git/categories
new file mode 160000
index 000000000..a74c4062c
--- /dev/null
+++ b/.cache/gatsby-source-git/categories
@@ -0,0 +1 @@
+Subproject commit a74c4062cc3eb40c01e0e0ad0d0740b453c99f94
diff --git a/app/[filename]/ServerRulePage.tsx b/app/[filename]/ServerRulePage.tsx
index 062dd02d9..7f5418fc1 100644
--- a/app/[filename]/ServerRulePage.tsx
+++ b/app/[filename]/ServerRulePage.tsx
@@ -17,6 +17,7 @@ import RuleActionButtons from "@/components/RuleActionButtons";
import { YouTubeShorts } from "@/components/shared/Youtube";
import { getMarkdownComponentMapping } from "@/components/tina-markdown/markdown-component-mapping";
import { Card } from "@/components/ui/card";
+import IsrStatusBadge from "@/components/ui/isr-status-badge";
export interface ServerRulePageProps {
rule: any;
@@ -83,8 +84,11 @@ export default function ServerRulePage({ serverRulePageProps, tinaProps }: Serve
{rule?.title}
-
diff --git a/components/last-updated-by/index.tsx b/components/last-updated-by/index.tsx
index 419f59467..1eea0817e 100644
--- a/components/last-updated-by/index.tsx
+++ b/components/last-updated-by/index.tsx
@@ -57,7 +57,7 @@ export default function GitHubMetadata({ owner = "tinacms", repo = "tina.io", pa
}, [owner, repo, path]);
if (loading) {
- return Loading last updated info...
;
+ return Loading last updated info...
;
}
// If we have data with historyUrl, show it even if there's an error
@@ -89,8 +89,8 @@ export default function GitHubMetadata({ owner = "tinacms", repo = "tina.io", pa
) : (
displayAuthorName
)}
-
- {" "}
+ {" "}
+
{` ${lastUpdateInRelativeTime}.`}
diff --git a/components/ui/isr-status-badge.tsx b/components/ui/isr-status-badge.tsx
new file mode 100644
index 000000000..a72609198
--- /dev/null
+++ b/components/ui/isr-status-badge.tsx
@@ -0,0 +1,61 @@
+"use client";
+
+import { usePathname } from "next/navigation";
+import React from "react";
+import { cn } from "@/lib/utils";
+import Tooltip from "../tooltip/tooltip";
+
+// x-nextjs-cache header values:
+// - HIT: Served from cache (valid)
+// - MISS: Just generated (fresh)
+// - STALE: Serving old content while rebuilding
+type CacheStatus = "live" | "stale" | "loading";
+
+export default function IsrStatusBadge() {
+ const pathname = usePathname();
+ const [status, setStatus] = React.useState("loading");
+
+ React.useEffect(() => {
+ let cancelled = false;
+ setStatus("loading");
+
+ const checkCache = async () => {
+ try {
+ const res = await fetch(window.location.href, {
+ method: "HEAD",
+ cache: "no-store",
+ });
+
+ const cacheHeader = res.headers.get("x-nextjs-cache")?.toUpperCase();
+
+ if (cancelled) return;
+
+ // HIT or MISS = Live (green), STALE = Stale (orange)
+ if (cacheHeader === "STALE") {
+ setStatus("stale");
+ } else {
+ setStatus("live");
+ }
+ } catch {
+ if (!cancelled) setStatus("live"); // Default to live on error
+ }
+ };
+
+ checkCache();
+ return () => { cancelled = true; };
+ }, [pathname]);
+
+ if (status === "loading") {
+ return ;
+ }
+
+ const isLive = status === "live";
+ const tooltip = isLive ? "Live" : "Stale - Refresh for latest";
+ const style = isLive ? "bg-green-500" : "bg-orange-500";
+
+ return (
+
+
+
+ );
+}