Skip to content
1 change: 1 addition & 0 deletions .cache/gatsby-source-git/categories
Submodule categories added at a74c40
8 changes: 6 additions & 2 deletions app/[filename]/ServerRulePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -83,8 +84,11 @@ export default function ServerRulePage({ serverRulePageProps, tinaProps }: Serve
{rule?.title}
</h1>

<div className="flex justify-between my-2 flex-col md:flex-row">
<GitHubMetadata owner="SSWConsulting" repo="SSW.Rules.Content" path={rule?.id} className="mt-2" />
<div className="flex justify-between my-2 flex-col items-center md:flex-row">
<div className="flex gap-2 items-center">
<IsrStatusBadge />
<GitHubMetadata owner="SSWConsulting" repo="SSW.Rules.Content" path={rule?.id} />
</div>
<RuleActionButtons rule={rule} />
</div>
</div>
Expand Down
6 changes: 3 additions & 3 deletions components/last-updated-by/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ export default function GitHubMetadata({ owner = "tinacms", repo = "tina.io", pa
}, [owner, repo, path]);

if (loading) {
return <div className={`text-slate-500 text-sm mb-2 ${className}`}>Loading last updated info...</div>;
return <div className={`text-slate-500 text-sm ${className}`}>Loading last updated info...</div>;
}

// If we have data with historyUrl, show it even if there's an error
Expand Down Expand Up @@ -89,8 +89,8 @@ export default function GitHubMetadata({ owner = "tinacms", repo = "tina.io", pa
) : (
displayAuthorName
)}
</span>
{" "}<Tooltip text={lastUpdateInAbsoluteTime} showDelay={0} hideDelay={0} opaque={true}>
</span>{" "}
<Tooltip text={lastUpdateInAbsoluteTime} showDelay={0} hideDelay={0} opaque={true}>
<span>{` ${lastUpdateInRelativeTime}.`}</span>
</Tooltip>
</span>
Expand Down
61 changes: 61 additions & 0 deletions components/ui/isr-status-badge.tsx
Original file line number Diff line number Diff line change
@@ -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<CacheStatus>("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 <span className="inline-block h-2 w-2 rounded-full bg-zinc-300 animate-pulse" aria-hidden="true" />;
}

const isLive = status === "live";
const tooltip = isLive ? "Live" : "Stale - Refresh for latest";
const style = isLive ? "bg-green-500" : "bg-orange-500";

return (
<Tooltip text={tooltip} showDelay={false} hideDelay={false} opaque={true}>
<span className={cn("inline-block h-2 w-2 rounded-full", style)} aria-label={tooltip} />
</Tooltip>
);
}
Loading