NODEDC_SITE/tools/extract-home-blocks.mjs

156 lines
5.1 KiB
JavaScript

import { mkdir, readFile, writeFile } from "node:fs/promises";
import { dirname, join } from "node:path";
import { fileURLToPath } from "node:url";
const repoRoot = join(dirname(fileURLToPath(import.meta.url)), "..");
const sourcePath = join(repoRoot, "index.html");
const templateRoot = join(repoRoot, "templates", "pages", "home");
const blockRoot = join(templateRoot, "blocks");
const contentPath = join(repoRoot, "content", "pages", "home.json");
const html = await readFile(sourcePath, "utf8");
const marker = {
hero: '<header id="hero" class="s h-screen">',
features: '<section id="features" class="s h-screen py mobile-flip">',
cViz: '<div class="c-viz">',
pricingIntro: '<section id="waitlist" class="s">',
waitlistFiles: '<section id="waitlist" class="s h-screen">',
demoVideoFolder: '<div data-module="folder-wrap" class="folder-w video-w">',
footer: '<footer class="s footer">',
};
function findRequired(needle, from = 0) {
const index = html.indexOf(needle, from);
if (index === -1) {
throw new Error(`Could not find marker: ${needle}`);
}
return index;
}
const heroStart = findRequired(marker.hero);
const featuresStart = findRequired(marker.features, heroStart);
const cVizStart = findRequired(marker.cViz, featuresStart);
const cVizOpenEnd = cVizStart + marker.cViz.length;
const pricingIntroStart = findRequired(marker.pricingIntro, cVizOpenEnd);
const waitlistFilesStart = findRequired(marker.waitlistFiles, pricingIntroStart);
const demoVideoFolderStart = findRequired(marker.demoVideoFolder, waitlistFilesStart);
const footerStart = findRequired(marker.footer, demoVideoFolderStart);
const footerEnd = findRequired("</footer>", footerStart) + "</footer>".length;
const shell = [
html.slice(0, heroStart),
"{{NODEDC_BLOCKS_BEFORE_CVIZ}}",
html.slice(cVizStart, cVizOpenEnd),
"{{NODEDC_BLOCKS_CVIZ}}",
html.slice(footerEnd),
].join("");
const blocks = [
{
region: "beforeCViz",
id: "hero-waitlist",
type: "staticHtml",
template: "hero-waitlist.html",
adminLabel: "Первый экран и заявка",
anchor: "hero",
html: html.slice(heroStart, featuresStart),
},
{
region: "beforeCViz",
id: "feature-video",
type: "staticHtml",
template: "feature-video.html",
adminLabel: "Демо и базовая логика",
anchor: "features",
html: html.slice(featuresStart, cVizStart),
},
{
region: "cViz",
id: "product-system",
type: "staticHtml",
template: "product-system.html",
adminLabel: "Компоненты, режимы, FAQ и тарифная таблица",
anchor: null,
html: html.slice(cVizOpenEnd, pricingIntroStart),
},
{
region: "cViz",
id: "pricing-intro",
type: "staticHtml",
template: "pricing-intro.html",
adminLabel: "Интро тарифов",
anchor: "waitlist",
html: html.slice(pricingIntroStart, waitlistFilesStart),
},
{
region: "cViz",
id: "waitlist-files",
type: "staticHtml",
template: "waitlist-files.html",
adminLabel: "Форма ожидания и txt-файлы",
anchor: "waitlist",
html: html.slice(waitlistFilesStart, demoVideoFolderStart),
},
{
region: "cViz",
id: "demo-video-folder",
type: "staticHtml",
template: "demo-video-folder.html",
adminLabel: "Иконка демо-видео в доке",
anchor: null,
html: html.slice(demoVideoFolderStart, footerStart),
},
{
region: "cViz",
id: "footer",
type: "staticHtml",
template: "footer.html",
adminLabel: "Футер",
anchor: null,
html: html.slice(footerStart, footerEnd),
},
];
const page = {
schemaVersion: 1,
slug: "home",
output: "index.html",
title: "NODE.DC",
seo: {
title: "NODE.DC — ИИ-платформа для Webflow",
description:
"Единая платформа для кастомного кода, MCP и ИИ-агентов в Webflow: контекст проекта, автоматизация, деплой и управляемая разработка.",
},
regions: [
{
id: "beforeCViz",
label: "До c-viz wrapper",
description: "Hero and first product section. These blocks live before the visual wrapper.",
blocks: blocks
.filter((block) => block.region === "beforeCViz")
.map(({ html: _html, ...block }) => ({ ...block, enabled: true })),
},
{
id: "cViz",
label: "Inside c-viz wrapper",
description: "Sections coupled to WebGL/color-flip shell. Keep these in this region for now.",
blocks: blocks
.filter((block) => block.region === "cViz")
.map(({ html: _html, ...block }) => ({ ...block, enabled: true })),
},
],
};
await mkdir(blockRoot, { recursive: true });
await mkdir(dirname(contentPath), { recursive: true });
await writeFile(join(templateRoot, "shell.html"), shell);
for (const block of blocks) {
await writeFile(join(blockRoot, block.template), block.html);
}
await writeFile(contentPath, `${JSON.stringify(page, null, 2)}\n`);
console.log(`Extracted ${blocks.length} blocks from ${sourcePath}`);
console.log(`Wrote ${join(templateRoot, "shell.html")}`);
console.log(`Wrote ${contentPath}`);