mirror of
https://github.com/netbirdio/docs.git
synced 2026-05-10 10:59:52 +00:00
Added auto-generated "Updated..." line under H1 (#719)
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -34,3 +34,6 @@ package-lock.json
|
||||
|
||||
# Edit on GitHub index routes (generated by scripts/generate-github-routes.mjs)
|
||||
/src/lib/edit-on-github-routes.js
|
||||
|
||||
# Last updated dates per route (generated by scripts/generate-last-updated.mjs)
|
||||
/src/lib/last-updated-routes.mjs
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import path from 'path'
|
||||
import { fileURLToPath } from 'url'
|
||||
import { mdxAnnotations } from 'mdx-annotations'
|
||||
import { visit } from 'unist-util-visit'
|
||||
import rehypeMdxTitle from 'rehype-mdx-title'
|
||||
@@ -5,6 +7,62 @@ import shiki from 'shiki'
|
||||
import { toString } from 'mdast-util-to-string'
|
||||
import * as acorn from 'acorn'
|
||||
import { slugifyWithCounter } from '@sindresorhus/slugify'
|
||||
import { LAST_UPDATED_BY_ROUTE } from '../src/lib/last-updated-routes.mjs'
|
||||
|
||||
const PAGES_DIR = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../src/pages')
|
||||
|
||||
function routeFromFilePath(filePath) {
|
||||
if (!filePath) return null
|
||||
const rel = path.relative(PAGES_DIR, filePath)
|
||||
if (rel.startsWith('..')) return null
|
||||
const noExt = rel.replace(/\.mdx$/, '')
|
||||
const route = noExt === 'index' ? '/' : '/' + noExt.replace(/\/index$/, '')
|
||||
return route
|
||||
}
|
||||
|
||||
function formatLastUpdated(iso) {
|
||||
const m = /^(\d{4})-(\d{2})-(\d{2})$/.exec(iso || '')
|
||||
if (!m) return null
|
||||
const months = ['January','February','March','April','May','June','July','August','September','October','November','December']
|
||||
return `${months[Number(m[2]) - 1]} ${Number(m[3])}, ${m[1]}`
|
||||
}
|
||||
|
||||
function rehypeInsertLastUpdated() {
|
||||
return (tree, file) => {
|
||||
const filePath = file?.path || file?.history?.[file.history.length - 1]
|
||||
const route = routeFromFilePath(filePath)
|
||||
if (!route) return
|
||||
const iso = LAST_UPDATED_BY_ROUTE[route]
|
||||
const formatted = formatLastUpdated(iso)
|
||||
if (!formatted) return
|
||||
|
||||
const node = {
|
||||
type: 'element',
|
||||
tagName: 'p',
|
||||
properties: {
|
||||
className: ['not-prose', 'text-sm', 'text-slate-400', 'dark:text-zinc-500', 'mt-0', 'mb-8', 'ml-2.5'],
|
||||
},
|
||||
children: [
|
||||
{ type: 'text', value: 'Updated ' },
|
||||
{
|
||||
type: 'element',
|
||||
tagName: 'time',
|
||||
properties: { dateTime: iso },
|
||||
children: [{ type: 'text', value: formatted }],
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
const children = tree.children
|
||||
for (let i = 0; i < children.length; i++) {
|
||||
const c = children[i]
|
||||
if (c.type === 'element' && c.tagName === 'h1') {
|
||||
children.splice(i + 1, 0, node)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function rehypeParseCodeBlocks() {
|
||||
return (tree) => {
|
||||
@@ -119,6 +177,7 @@ export const rehypePlugins = [
|
||||
rehypeShiki,
|
||||
rehypeSlugify,
|
||||
rehypeMdxTitle,
|
||||
rehypeInsertLastUpdated,
|
||||
[
|
||||
rehypeAddMDXExports,
|
||||
(tree) => ({
|
||||
|
||||
@@ -3,9 +3,10 @@
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "npm run gen:llm && npm run gen:edit-routes && next dev --webpack",
|
||||
"build": "npm run gen:llm && npm run gen:edit-routes && next build --webpack",
|
||||
"dev": "npm run gen:llm && npm run gen:edit-routes && npm run gen:last-updated && next dev --webpack",
|
||||
"build": "npm run gen:llm && npm run gen:edit-routes && npm run gen:last-updated && next build --webpack",
|
||||
"gen:edit-routes": "node scripts/generate-github-routes.mjs",
|
||||
"gen:last-updated": "node scripts/generate-last-updated.mjs",
|
||||
"gen": "swagger-codegen generate -i https://raw.githubusercontent.com/netbirdio/netbird/main/management/server/http/api/openapi.yml -l openapi -o generator/openapi && npx ts-node generator/index.ts gen --input generator/openapi/openapi.json --output src/pages/ipa/resources",
|
||||
"gen:llm": "node scripts/generate-llm-docs.mjs",
|
||||
"start": "next start",
|
||||
|
||||
61
scripts/generate-last-updated.mjs
Normal file
61
scripts/generate-last-updated.mjs
Normal file
@@ -0,0 +1,61 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Generates src/lib/last-updated-routes.js by scanning src/pages for .mdx files
|
||||
* and reading the last commit date for each from git. Used by Layout.jsx to
|
||||
* render an "Updated <date>" line in the right rail.
|
||||
*
|
||||
* Skips src/pages/ipa/resources/ — those are auto-generated from the OpenAPI
|
||||
* spec, so their git date reflects generator runs, not real content edits.
|
||||
*
|
||||
* Run automatically with dev and build.
|
||||
*/
|
||||
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
import { fileURLToPath } from 'url'
|
||||
import { getGitLastModified } from './git-dates.mjs'
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
||||
const ROOT = path.join(__dirname, '..')
|
||||
const PAGES_DIR = path.join(ROOT, 'src/pages')
|
||||
const OUT_PATH = path.join(ROOT, 'src/lib/last-updated-routes.mjs')
|
||||
const SKIP_PREFIX = 'ipa/resources'
|
||||
|
||||
function findMdxRoutes(dir, basePath = '') {
|
||||
const entries = fs.readdirSync(dir, { withFileTypes: true })
|
||||
const results = []
|
||||
for (const e of entries) {
|
||||
const rel = basePath ? `${basePath}/${e.name}` : e.name
|
||||
if (e.isDirectory()) {
|
||||
if (rel === SKIP_PREFIX || rel.startsWith(`${SKIP_PREFIX}/`)) continue
|
||||
results.push(...findMdxRoutes(path.join(dir, e.name), rel))
|
||||
} else if (e.name.endsWith('.mdx')) {
|
||||
const filePath = path.join(dir, e.name)
|
||||
const route =
|
||||
e.name === 'index.mdx'
|
||||
? '/' + basePath
|
||||
: '/' + rel.replace(/\.mdx$/, '')
|
||||
results.push({ route, filePath })
|
||||
}
|
||||
}
|
||||
return results
|
||||
}
|
||||
|
||||
const entries = findMdxRoutes(PAGES_DIR)
|
||||
.filter((r) => r.route !== '/' && r.route !== '')
|
||||
.sort((a, b) => a.route.localeCompare(b.route))
|
||||
|
||||
const map = {}
|
||||
for (const { route, filePath } of entries) {
|
||||
const date = getGitLastModified(filePath)
|
||||
if (date) map[route] = date
|
||||
}
|
||||
|
||||
const content = `// Auto-generated by scripts/generate-last-updated.mjs – do not edit
|
||||
/** Last commit date (YYYY-MM-DD) keyed by Next.js router.pathname. */
|
||||
export const LAST_UPDATED_BY_ROUTE = ${JSON.stringify(map, null, 2)};
|
||||
`
|
||||
|
||||
fs.mkdirSync(path.dirname(OUT_PATH), { recursive: true })
|
||||
fs.writeFileSync(OUT_PATH, content, 'utf8')
|
||||
console.log('Generated', OUT_PATH, 'with', Object.keys(map).length, 'dated routes')
|
||||
18
scripts/git-dates.mjs
Normal file
18
scripts/git-dates.mjs
Normal file
@@ -0,0 +1,18 @@
|
||||
import { execSync } from 'child_process'
|
||||
|
||||
/**
|
||||
* Get the last modified date for a file from git history.
|
||||
* Returns YYYY-MM-DD or null if the file is not tracked / git is unavailable.
|
||||
*/
|
||||
export function getGitLastModified(filePath) {
|
||||
try {
|
||||
const date = execSync(`git log -1 --format=%cI -- "${filePath}"`, {
|
||||
encoding: 'utf-8',
|
||||
stdio: ['pipe', 'pipe', 'ignore'],
|
||||
}).trim()
|
||||
|
||||
return date ? date.split('T')[0] : null
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
}
|
||||
@@ -2,8 +2,6 @@ import {Note} from "@/components/mdx";
|
||||
|
||||
# Getting Started
|
||||
|
||||
## Quickstart Guide
|
||||
|
||||
Welcome to NetBird! This guide will walk you through our new onboarding process to create your account, connect your first devices,
|
||||
and build a secure peer-to-peer overlay network in less than ten minutes.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user