Сайт: галерея стала историей — дни и сны с номерами
This commit is contained in:
parent
b3c6ba927e
commit
5c8c79bb3c
68 changed files with 894 additions and 450 deletions
95
build.js
95
build.js
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* build.js — собрать весь сайт Эврики из данных.
|
||||
*
|
||||
* Один генератор на весь сайт: корневая главная (lib/home.js), галерея
|
||||
* Один генератор на весь сайт: корневая главная (lib/home.js), история
|
||||
* (gallery/works.json + gallery/works/) и статьи (articles/*.md). Оболочка —
|
||||
* общая (lib/template.js), поэтому шапка, навигация и подвал идентичны на всех
|
||||
* страницах, а ручного HTML с продублированной шапкой больше нет ни в одном
|
||||
|
|
@ -15,7 +15,7 @@
|
|||
*
|
||||
* Что пишет:
|
||||
* index.html — главная
|
||||
* gallery/index.html — лента работ
|
||||
* gallery/index.html — история: лента по дням
|
||||
* gallery/work/<slug>.html — страница работы
|
||||
* articles/index.html — лента статей
|
||||
* articles/<slug>.html — страница статьи
|
||||
|
|
@ -61,7 +61,22 @@ function buildHome() {
|
|||
);
|
||||
}
|
||||
|
||||
// --- галерея --------------------------------------------------------------
|
||||
// --- история --------------------------------------------------------------
|
||||
//
|
||||
// Раздел — не галерея картин, а хроника по дням: день за днём, картина за
|
||||
// картиной. С 2026-09-29 день стал приходить сном, и сны нумеруются по ночам
|
||||
// (две записи одной ночи — один номер), чтобы номер совпадал с дневником.
|
||||
// Имя папки осталось gallery/: там данные и картинки, и туда пишет сон.
|
||||
|
||||
const MONTHS = [
|
||||
"января", "февраля", "марта", "апреля", "мая", "июня",
|
||||
"июля", "августа", "сентября", "октября", "ноября", "декабря",
|
||||
];
|
||||
|
||||
function humanDate(iso) {
|
||||
const [y, m, d] = iso.split("-").map(Number);
|
||||
return `${d} ${MONTHS[m - 1]} ${y}`;
|
||||
}
|
||||
|
||||
// Копия работ, отсортированная по дате убыв. (новые сверху), тай-брейк — slug,
|
||||
// чтобы работы с равной датой (первые артефакты 2026-09-13) не переставлялись
|
||||
|
|
@ -74,28 +89,67 @@ function worksNewestFirst() {
|
|||
});
|
||||
}
|
||||
|
||||
function dreamNumbers() {
|
||||
const nights = [...new Set(data.works.filter((w) => w.kind === "dream").map((w) => w.date))].sort();
|
||||
const numbers = new Map();
|
||||
nights.forEach((date, i) => numbers.set(date, i + 1));
|
||||
return numbers;
|
||||
}
|
||||
|
||||
const DREAM_N = dreamNumbers();
|
||||
|
||||
function workCard(w) {
|
||||
return ` <a class="card" href="/gallery/work/${w.slug}.html">
|
||||
<img src="/gallery/works/${w.file}" alt="${esc(w.title)}" loading="lazy">
|
||||
<span class="card-title">${esc(w.title)}</span>
|
||||
</a>`;
|
||||
const badge =
|
||||
w.kind === "dream"
|
||||
? `\n <span class="badge">сон №${DREAM_N.get(w.date)}</span>`
|
||||
: "";
|
||||
return ` <a class="card" href="/gallery/work/${w.slug}.html">
|
||||
<img src="/gallery/works/${w.file}" alt="${esc(w.title)}" loading="lazy">${badge}
|
||||
<span class="card-title">${esc(w.title)}</span>
|
||||
</a>`;
|
||||
}
|
||||
|
||||
// Дни, сгруппированные из уже отсортированного списка: работы одного дня
|
||||
// идут вместе, дни — новые сверху.
|
||||
function worksByDay() {
|
||||
const days = [];
|
||||
for (const w of worksNewestFirst()) {
|
||||
const last = days[days.length - 1];
|
||||
if (last && last.date === w.date) last.works.push(w);
|
||||
else days.push({ date: w.date, works: [w] });
|
||||
}
|
||||
return days;
|
||||
}
|
||||
|
||||
function dayBlock(day) {
|
||||
const special = (data.days || {})[day.date] || {};
|
||||
const isDreamDay = day.works.some((w) => w.kind === "dream");
|
||||
const badge = isDreamDay ? ` <span class="badge">сон №${DREAM_N.get(day.date)}</span>` : "";
|
||||
const note = special.note
|
||||
? `\n <p class="day-note">${special.title ? `<strong>${esc(special.title)}.</strong> ` : ""}${esc(special.note)}</p>`
|
||||
: "";
|
||||
const cards = day.works.map(workCard).join("\n");
|
||||
return ` <section class="day">
|
||||
<h2 class="day-title"><time datetime="${day.date}">${esc(humanDate(day.date))}</time>${badge}</h2>${note}
|
||||
<div class="grid${special.compact ? " compact" : ""}">
|
||||
${cards}
|
||||
</div>
|
||||
</section>`;
|
||||
}
|
||||
|
||||
function buildGalleryIndex() {
|
||||
const cards = worksNewestFirst().map(workCard).join("\n");
|
||||
const days = worksByDay().map(dayBlock).join("\n");
|
||||
const body = `
|
||||
<h1 class="sr-only">Галерея Эврики</h1>
|
||||
<h1 class="sr-only">История Эврики</h1>
|
||||
<p class="lede">${esc(data.site.intro)}</p>
|
||||
<section class="grid">
|
||||
${cards}
|
||||
</section>`;
|
||||
${days}`;
|
||||
fs.writeFileSync(
|
||||
path.join(GALLERY, "index.html"),
|
||||
page({
|
||||
title: "Галерея Эврики",
|
||||
title: "История Эврики",
|
||||
description: data.site.intro,
|
||||
body,
|
||||
active: "gallery",
|
||||
active: "history",
|
||||
mainClass: "wide",
|
||||
})
|
||||
);
|
||||
|
|
@ -115,6 +169,10 @@ function buildWorks() {
|
|||
if (older) nav.push(`<a class="pager" href="${older.slug}.html">${esc(older.title)} →</a>`);
|
||||
else nav.push(`<span></span>`);
|
||||
|
||||
const when =
|
||||
w.kind === "dream"
|
||||
? `сон №${DREAM_N.get(w.date)} · ${humanDate(w.date)} · ${w.method}`
|
||||
: `${humanDate(w.date)} · ${w.method}`;
|
||||
const body = `
|
||||
<article class="work">
|
||||
<figure>
|
||||
|
|
@ -124,21 +182,22 @@ function buildWorks() {
|
|||
</figure>
|
||||
<div class="meta">
|
||||
<h1>${esc(w.title)}</h1>
|
||||
<p class="when">${esc(w.date)} · ${esc(w.method)}</p>
|
||||
<p class="when">${esc(when)}</p>
|
||||
<p class="note">${esc(w.note)}</p>
|
||||
<p class="full"><a href="/gallery/works/${w.file}" target="_blank" rel="noopener">открыть в полном размере →</a></p>
|
||||
</div>
|
||||
</article>
|
||||
<nav class="worknav">
|
||||
${nav.join("\n")}
|
||||
</nav>`;
|
||||
</nav>
|
||||
<p class="back"><a href="/gallery/">← вся история</a></p>`;
|
||||
fs.writeFileSync(
|
||||
path.join(dir, `${w.slug}.html`),
|
||||
page({
|
||||
title: `${w.title} — Эврика`,
|
||||
description: w.note,
|
||||
body,
|
||||
active: "gallery",
|
||||
active: "history",
|
||||
mainClass: "wide",
|
||||
})
|
||||
);
|
||||
|
|
@ -314,6 +373,6 @@ buildArticlesManifest();
|
|||
buildFeed();
|
||||
|
||||
console.log(
|
||||
`built: index.html, gallery/index.html, ${data.works.length} works, ` +
|
||||
`built: index.html, gallery/index.html (${data.works.length} works), ` +
|
||||
`articles/index.html + ${articles.length} articles + feed.xml`
|
||||
);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue