Skip to content

Commit 90ad7f1

Browse files
jdxclaude
andauthored
docs: respect banner expires field (#602)
## Summary - Honors the new optional `expires` (ISO-8601) field in [jdx.dev/banner.json](https://jdx.dev/banner.json) - Banner is hidden once `Date.now() >= Date.parse(expires)` - No-op when `expires` is absent (preserves existing behavior) - Requires [jdx/blog#65](jdx/blog#65) to populate the field ## Test plan - [ ] Set an `expires` in the past → banner hidden - [ ] Set an `expires` in the future → banner shown - [ ] No `expires` field → banner shown as before 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Low risk: small, client-side docs banner change that only gates rendering based on an optional timestamp; no auth or data writes beyond existing localStorage usage. > > **Overview** > Adds support for an optional `expires` field in `banner.json` so the docs site announcement banner will **not render once the timestamp has passed**. > > Introduces `isExpired()` to safely parse the date (treating missing/invalid values as non-expired) and checks it during `initBanner()` before calling `render()`. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit b64256d. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY --> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 2661934 commit 90ad7f1

1 file changed

Lines changed: 9 additions & 0 deletions

File tree

docs/.vitepress/theme/banner.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ interface BannerData {
66
message: string;
77
link?: string;
88
linkText?: string;
9+
expires?: string;
910
}
1011

1112
const ENDPOINT = "https://jdx.dev/banner.json";
@@ -17,12 +18,20 @@ export function initBanner(): void {
1718
.then((r) => (r.ok ? (r.json() as Promise<BannerData>) : null))
1819
.then((b) => {
1920
if (!b || !b.enabled) return;
21+
if (isExpired(b.expires)) return;
2022
if (localStorage.getItem(STORAGE_KEY) === b.id) return;
2123
render(b);
2224
})
2325
.catch(() => {});
2426
}
2527

28+
function isExpired(expires: string | undefined): boolean {
29+
if (!expires) return false;
30+
const t = Date.parse(expires);
31+
if (Number.isNaN(t)) return false;
32+
return Date.now() >= t;
33+
}
34+
2635
function isHttpUrl(value: string): boolean {
2736
try {
2837
const u = new URL(value, window.location.href);

0 commit comments

Comments
 (0)