Skip to content

Commit 3f242e8

Browse files
committed
feat: add auto-generated last-updated dates to all pages
1 parent e9dbb52 commit 3f242e8

6 files changed

Lines changed: 131 additions & 6 deletions

File tree

components/Layout.js

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { useRouter } from 'next/router';
55
import { Sidebar } from './Sidebar';
66
import { TableOfContents } from './TableOfContents';
77
import { getPrevNext } from '../lib/navigation';
8+
import lastUpdated from '../lib/lastUpdated.json';
89
import { Breadcrumbs } from './Breadcrumbs';
910
import { ThemeToggle } from './ThemeToggle';
1011
import { SearchDialog } from './SearchDialog';
@@ -147,7 +148,20 @@ export default function Layout({ children, frontmatter }) {
147148

148149
<main className="layout-content" id="main-content">
149150
<Breadcrumbs />
150-
<article>{children}</article>
151+
<article>
152+
{children}
153+
{lastUpdated[currentPath] && (
154+
<p className="last-updated">
155+
Last updated{' '}
156+
{new Date(lastUpdated[currentPath]).toLocaleDateString('en-US', {
157+
year: 'numeric',
158+
month: 'long',
159+
day: 'numeric',
160+
})}
161+
</p>
162+
)}
163+
</article>
164+
151165

152166
{(prev || next) && (
153167
<nav className="pagination" aria-label="Page navigation">

lib/generate-last-updated.js

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
const { execSync } = require("child_process");
2+
const { readdirSync, statSync, writeFileSync } = require("fs");
3+
const { join, relative } = require("path");
4+
5+
const PAGES_DIR = join(__dirname, "..", "pages");
6+
const OUTPUT = join(__dirname, "lastUpdated.json");
7+
8+
function walkDir(dir) {
9+
const results = [];
10+
for (const entry of readdirSync(dir)) {
11+
const full = join(dir, entry);
12+
if (statSync(full).isDirectory()) {
13+
results.push(...walkDir(full));
14+
} else if (full.endsWith(".md")) {
15+
results.push(full);
16+
}
17+
}
18+
return results;
19+
}
20+
21+
function getLastUpdated(filePath) {
22+
try {
23+
const date = execSync(`git log -1 --format="%aI" -- "${filePath}"`, {
24+
encoding: "utf-8",
25+
}).trim();
26+
return date || null;
27+
} catch {
28+
return null;
29+
}
30+
}
31+
32+
const files = walkDir(PAGES_DIR);
33+
const map = {};
34+
35+
for (const file of files) {
36+
const rel = "/" + relative(PAGES_DIR, file).replace(/\.md$/, "");
37+
const route = rel === "/index" ? "/" : rel;
38+
const date = getLastUpdated(file);
39+
if (date) {
40+
map[route] = date;
41+
}
42+
}
43+
44+
writeFileSync(OUTPUT, JSON.stringify(map, null, 2) + "\n");
45+
console.log(`Generated last-updated dates for ${Object.keys(map).length} pages`);

lib/lastUpdated.json

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
{
2+
"/architecture/account-and-identity": "2026-03-05T14:44:33+06:00",
3+
"/architecture/data-flow-and-lifecycle": "2026-02-20T13:15:20+01:00",
4+
"/architecture/indexers-and-discovery": "2026-03-05T04:01:13+08:00",
5+
"/architecture/overview": "2026-03-03T14:42:32+06:00",
6+
"/architecture/portability-and-scaling": "2026-03-05T13:01:42+08:00",
7+
"/core-concepts/cel-work-scopes": "2026-02-26T16:26:35+01:00",
8+
"/core-concepts/certified-identity": "2026-03-05T14:47:53+06:00",
9+
"/core-concepts/common-use-cases": "2026-03-05T12:52:26+08:00",
10+
"/core-concepts/funding-and-value-flow": "2026-03-05T15:35:21+08:00",
11+
"/core-concepts/hypercerts-core-data-model": "2026-03-05T02:45:35+08:00",
12+
"/core-concepts/what-is-hypercerts": "2026-03-05T03:40:14+08:00",
13+
"/core-concepts/why-at-protocol": "2026-02-20T12:49:43+01:00",
14+
"/ecosystem/why-we-need-hypercerts": "2026-02-20T12:49:43+01:00",
15+
"/getting-started/building-on-hypercerts": "2026-03-03T16:31:31+08:00",
16+
"/getting-started/creating-your-first-hypercert": "2026-03-05T02:45:35+08:00",
17+
"/getting-started/quickstart": "2026-03-05T12:57:05+06:00",
18+
"/getting-started/testing-and-deployment": "2026-03-05T14:36:55+06:00",
19+
"/getting-started/working-with-evaluations": "2026-03-03T14:45:57+08:00",
20+
"/": "2026-03-05T13:01:42+08:00",
21+
"/lexicons/certified-lexicons/badge-award": "2026-02-20T12:49:43+01:00",
22+
"/lexicons/certified-lexicons/badge-definition": "2026-02-20T12:49:43+01:00",
23+
"/lexicons/certified-lexicons/badge-response": "2026-02-20T12:49:43+01:00",
24+
"/lexicons/certified-lexicons/index": "2026-02-20T12:49:43+01:00",
25+
"/lexicons/certified-lexicons/location": "2026-02-20T12:49:43+01:00",
26+
"/lexicons/certified-lexicons/profile": "2026-02-20T12:49:43+01:00",
27+
"/lexicons/certified-lexicons/shared-defs": "2026-02-20T12:49:43+01:00",
28+
"/lexicons/hypercerts-lexicons/acknowledgement": "2026-03-03T14:45:57+08:00",
29+
"/lexicons/hypercerts-lexicons/activity-claim": "2026-03-03T14:45:57+08:00",
30+
"/lexicons/hypercerts-lexicons/attachment": "2026-03-03T14:45:57+08:00",
31+
"/lexicons/hypercerts-lexicons/collection": "2026-03-03T14:45:57+08:00",
32+
"/lexicons/hypercerts-lexicons/contribution": "2026-03-03T14:45:57+08:00",
33+
"/lexicons/hypercerts-lexicons/evaluation": "2026-03-03T14:45:57+08:00",
34+
"/lexicons/hypercerts-lexicons/funding-receipt": "2026-03-03T14:45:57+08:00",
35+
"/lexicons/hypercerts-lexicons/index": "2026-02-20T19:42:03+08:00",
36+
"/lexicons/hypercerts-lexicons/measurement": "2026-03-03T14:45:57+08:00",
37+
"/lexicons/hypercerts-lexicons/rights": "2026-03-03T14:45:57+08:00",
38+
"/lexicons/introduction-to-lexicons": "2026-02-20T12:49:43+01:00",
39+
"/reference/faq": "2026-03-05T12:57:05+06:00",
40+
"/reference/glossary": "2026-03-05T12:57:05+06:00",
41+
"/roadmap": "2026-03-03T14:45:57+08:00",
42+
"/tools/hyperboards": "2026-03-03T14:45:57+08:00",
43+
"/tools/hypercerts-cli": "2026-03-05T12:30:00+06:00",
44+
"/tools/hyperindex": "2026-02-20T19:42:03+08:00",
45+
"/tools/scaffold": "2026-03-05T15:58:36+06:00"
46+
}

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
"private": true,
55
"description": "Hypercerts Protocol Documentation",
66
"scripts": {
7-
"dev": "next dev --webpack",
8-
"build": "next build --webpack",
7+
"dev": "node lib/generate-last-updated.js && next dev --webpack",
8+
"build": "node lib/generate-last-updated.js && next build --webpack",
99
"start": "next start"
1010
},
1111
"dependencies": {

pages/core-concepts/hypercerts-core-data-model.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@ description: The data model behind hypercerts — record types, dimensions, and
55

66
# Core Data Model
77

8-
*Last updated: March 5, 2026*
9-
108
A hypercert is an [activity claim](/lexicons/hypercerts-lexicons/activity-claim) with linked records that describe work done. The activity claim is the anchor — contributions, attachments, measurements, and evaluations reference it to add context.
119

1210
This page explains what records exist, what they contain, and how they connect.

styles/globals.css

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -939,11 +939,33 @@ a.sidebar-link-active:hover {
939939
font-size: 13px;
940940
}
941941

942+
/* ===== Last Updated ===== */
943+
article:has(.last-updated) {
944+
display: flex;
945+
flex-direction: column;
946+
}
947+
948+
article:has(.last-updated) > article {
949+
display: contents;
950+
}
951+
952+
article:has(.last-updated) > article > h1:first-child {
953+
order: -2;
954+
}
955+
956+
.last-updated {
957+
order: -1;
958+
margin-bottom: var(--space-6);
959+
padding-bottom: var(--space-2);
960+
border-bottom: 1px solid var(--color-border);
961+
font-size: 0.8125rem;
962+
color: var(--color-text-secondary);
963+
}
942964
/* ===== Pagination ===== */
943965
.pagination {
944966
display: flex;
945967
justify-content: space-between;
946-
margin-top: var(--space-12);
968+
margin-top: var(--space-6);
947969
padding-top: var(--space-6);
948970
border-top: 1px solid var(--color-border);
949971
gap: var(--space-4);

0 commit comments

Comments
 (0)