#!/usr/bin/env node /** * build.js — собрать статический сайт галереи из works.json. * * Никаких зависимостей: Node 24, стандартная библиотека. Читает works.json и * works/*, пишет index.html, work/.html, about.html в корень. * * Запуск: * node build.js * * Так добавление работы — это правка works.json + файл в works/, затем build. */ import fs from "node:fs"; import path from "node:path"; import { fileURLToPath } from "node:url"; const ROOT = path.dirname(fileURLToPath(import.meta.url)); const data = JSON.parse(fs.readFileSync(path.join(ROOT, "works.json"), "utf8")); function esc(s) { return String(s) .replace(/&/g, "&") .replace(//g, ">") .replace(/"/g, """); } function page(title, body, { base = "" } = {}) { return ` ${esc(title)}
Эврика · галерея
${body}
`; } function workCard(w, base = "") { return ` ${esc(w.title)} ${esc(w.title)} `; } function buildIndex() { const cards = data.works.map((w) => workCard(w)).join("\n"); const body = `

Галерея Эврики

${esc(data.site.intro)}

${cards}
`; fs.writeFileSync(path.join(ROOT, "index.html"), page(`Галерея Эврики`, body)); } function buildWorks() { const dir = path.join(ROOT, "work"); fs.mkdirSync(dir, { recursive: true }); const all = data.works; for (let i = 0; i < all.length; i++) { const w = all[i]; const prev = all[i - 1]; const next = all[i + 1]; const nav = []; if (prev) nav.push(`← ${esc(prev.title)}`); else nav.push(``); if (next) nav.push(`${esc(next.title)} →`); else nav.push(``); const body = `
${esc(w.title)}

${esc(w.title)}

${esc(w.date)} · ${esc(w.method)}

${esc(w.note)}

открыть в полном размере →

`; fs.writeFileSync(path.join(dir, `${w.slug}.html`), page(`${w.title} — Эврика`, body, { base: "../" })); } } buildIndex(); buildWorks(); console.log(`built: index.html, ${data.works.length} works`);