#!/usr/bin/env node /** * build.js — собрать весь сайт Эврики из данных. * * Один генератор на весь сайт: корневая главная (lib/home.js) и галерея * (gallery/works.json + gallery/works/). Оболочка — общая (lib/template.js), * поэтому шапка, навигация и подвал идентичны на всех страницах, а ручного * HTML с продублированной шапкой больше нет ни в одном файле. * * Никаких зависимостей: Node 24, стандартная библиотека. * * Запуск (из корня eureka-web): * node build.js * * Что пишет: * index.html — главная * gallery/index.html — лента работ * gallery/work/.html — страница работы * * Так добавление работы — это правка gallery/works.json + файл в gallery/works/, * затем build. */ import fs from "node:fs"; import path from "node:path"; import { fileURLToPath } from "node:url"; import { page, esc } from "./lib/template.js"; import { homeTitle, homeDescription, homeBody } from "./lib/home.js"; const ROOT = path.dirname(fileURLToPath(import.meta.url)); const GALLERY = path.join(ROOT, "gallery"); const data = JSON.parse(fs.readFileSync(path.join(GALLERY, "works.json"), "utf8")); // --- главная -------------------------------------------------------------- function buildHome() { fs.writeFileSync( path.join(ROOT, "index.html"), page({ title: homeTitle, description: homeDescription, body: homeBody, active: "home", }) ); } // --- галерея -------------------------------------------------------------- function workCard(w) { return ` ${esc(w.title)} ${esc(w.title)} `; } function buildGalleryIndex() { const cards = data.works.map(workCard).join("\n"); const body = `

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

${esc(data.site.intro)}

${cards}
`; fs.writeFileSync( path.join(GALLERY, "index.html"), page({ title: "Галерея Эврики", description: data.site.intro, body, active: "gallery", mainClass: "wide", }) ); } function buildWorks() { const dir = path.join(GALLERY, "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({ title: `${w.title} — Эврика`, description: w.note, body, active: "gallery", mainClass: "wide", }) ); } } buildHome(); buildGalleryIndex(); buildWorks(); console.log(`built: index.html, gallery/index.html, ${data.works.length} works`);