From 25e5afedf24d0c7eea1ddd22414da28eeb58dcbe Mon Sep 17 00:00:00 2001 From: dcconstructions Date: Fri, 26 Jun 2026 14:19:14 +0300 Subject: [PATCH] Refine admin dock and access card editing --- admin/admin.css | 48 +++ admin/admin.js | 208 ++++++++++++- .../dclogo_white_alpha-mqus5if2.png | Bin 0 -> 7871 bytes content/block-templates/home.json | 162 ++++++---- content/pages/home.json | 281 +++++++++++++----- index.html | 2 +- .../pages/home/blocks/hero-waitlist.html | 2 +- .../pages/home/blocks/waitlist-files.html | 2 +- templates/pages/home/shell.html | 2 +- tools/render-home.mjs | 33 +- 10 files changed, 573 insertions(+), 167 deletions(-) create mode 100644 assets/uploads/images/static-elements/dclogo_white_alpha-mqus5if2.png diff --git a/admin/admin.css b/admin/admin.css index f6c63f3..9de8ec3 100644 --- a/admin/admin.css +++ b/admin/admin.css @@ -919,6 +919,54 @@ body[data-file-picker-active="true"] .editor { white-space: nowrap; } +.boolean-field { + align-content: start; +} + +.boolean-field input, +.group-head-toggle input { + width: 2.42rem; + height: 1.32rem; + margin: 0; + appearance: none; + border-radius: 999px; + background: rgba(255, 255, 255, 0.16); + padding: 0.16rem; +} + +.boolean-field input::before, +.group-head-toggle input::before { + display: block; + width: 1rem; + aspect-ratio: 1; + border-radius: 50%; + background: rgba(255, 255, 255, 0.82); + content: ""; + transition: transform 0.16s ease; +} + +.boolean-field input:checked, +.group-head-toggle input:checked { + background: rgba(255, 255, 255, 0.9); +} + +.boolean-field input:checked::before, +.group-head-toggle input:checked::before { + background: #050506; + transform: translateX(1.1rem); +} + +.group-head-toggle { + display: inline-flex; + flex: 0 0 auto; + align-items: center; + gap: 0.52rem; + color: var(--text-secondary); + font-size: 0.78rem; + font-weight: 850; + white-space: nowrap; +} + .collection-field { display: grid; grid-column: 1 / -1; diff --git a/admin/admin.js b/admin/admin.js index 3e22554..c1cde1a 100644 --- a/admin/admin.js +++ b/admin/admin.js @@ -80,8 +80,32 @@ const STATIC_FALLBACK = { }, ], dock: { - appTarget: "app-data", - trashAlt: "Белая иконка корзины.", + items: [ + { + enabled: true, + title: "NODE.DC", + href: "#hero", + linkTarget: "", + targetId: "app-data", + iconSrc: "./assets/webflow/images/69ad964d951f9d17cc5a919e_logo-app.svg", + iconAlt: "Иконка NODE.DC", + className: "dock-icon ssscript", + iconClass: "logo", + dividerBefore: false, + }, + { + enabled: true, + title: "Корзина", + href: "", + linkTarget: "", + targetId: "", + iconSrc: "./assets/webflow/images/69a9ae818a76c773dc3cf7bc_trash.avif", + iconAlt: "Белая иконка корзины.", + className: "dock-icon no-bg", + iconClass: "dock-app-img trash", + dividerBefore: true, + }, + ], demoFileLabel: "демо-видео.txt", }, assets: { @@ -126,8 +150,33 @@ const STATIC_FALLBACK = { field("body", "Текст", "textarea", "text", "Уведомления"), ], ), - field("content.dock.appTarget", "Dock: ID приложения", "text", "text", "Dock"), - field("content.dock.trashAlt", "Dock: alt корзины", "text", "text", "Dock"), + collection( + "content.dock.items", + "Иконки dock-панели", + "Dock", + { + enabled: true, + title: "Новое приложение", + href: "#hero", + linkTarget: "", + targetId: "", + iconSrc: "./assets/webflow/images/69ad964d951f9d17cc5a919e_logo-app.svg", + iconAlt: "Иконка приложения", + className: "dock-icon ssscript", + iconClass: "logo", + dividerBefore: false, + }, + [ + field("enabled", "Отображение", "boolean", "boolean", "Dock"), + field("title", "Название", "text", "text", "Dock"), + field("href", "Ссылка / адрес", "url", "attr", "Dock"), + field("linkTarget", "Target ссылки", "text", "attr", "Dock"), + field("targetId", "ID окна / приложения", "text", "attr", "Dock"), + field("iconSrc", "Иконка", "media", "attr", "Dock"), + field("iconAlt", "Alt иконки", "text", "text", "Dock"), + field("dividerBefore", "Разделитель слева", "boolean", "boolean", "Dock"), + ], + ), field("content.dock.demoFileLabel", "Dock: подпись демо-файла", "text", "text", "Dock"), field("content.assets.webglModelSrc", "WebGL-модель логотипа", "media", "attr", "Модель и логотипы"), field("content.assets.logoPng", "PNG-логотип", "media", "attr", "Модель и логотипы"), @@ -143,11 +192,11 @@ const GROUP_COPY = { "Шапка: логотип": "Статичный знак верхней mac-панели: файл логотипа, alt и брендовая подпись.", "Шапка: ссылки": "Пункты навигации верхней mac-панели. Каждый пункт можно добавить, удалить и переставить.", Уведомления: "Карточки уведомлений справа сверху. Порядок в админке соответствует порядку на сайте.", - Dock: "Нижняя системная панель: связь кнопки приложения, корзина и подписи файлов.", + Dock: "Нижняя системная панель: приложения, корзина, ссылки и подписи файлов.", "Модель и логотипы": "Базовые ассеты статичного слоя: GLB-модель, PNG/SVG-логотипы и alt-тексты.", Заголовок: "Главный заголовок и вводный текст выбранной секции.", "Тезисы первого экрана": "Четыре смысловых тезиса вокруг формы раннего доступа.", - "Карточка раннего доступа": "Текст внутри центрального окна приложения.", + "Карточка доступа": "Логотипы, тексты и видимость центрального окна приложения.", Форма: "Плейсхолдеры, кнопки, success/failure состояния формы.", "Юридический блок": "Политики, права и нижний текст формы.", "Видео-окно": "Окно демо-видео и подключенный медиа-файл.", @@ -270,7 +319,7 @@ function inferFieldGroup(path) { if (path.startsWith("content.dock.")) return "Dock"; if (path.startsWith("content.assets.")) return "Модель и логотипы"; if (path.startsWith("content.cards.")) return "Тезисы первого экрана"; - if (path.startsWith("content.app.")) return "Карточка раннего доступа"; + if (path.startsWith("content.app.") || path.startsWith("content.accessCard.")) return "Карточка доступа"; if (path.startsWith("content.form.")) return "Форма"; if (path === "content.legalHtml") return "Юридический блок"; if (path === "content.windowTitle" || path === "content.videoSrc") return "Видео-окно"; @@ -289,6 +338,63 @@ function inferFieldGroup(path) { return "Контент"; } +function createDefaultDockItems(dock = {}, assets = {}) { + return [ + { + enabled: true, + title: "NODE.DC", + href: "#hero", + linkTarget: "", + targetId: dock.appTarget || "app-data", + iconSrc: assets.appIconSrc || STATIC_FALLBACK.content.assets.appIconSrc, + iconAlt: assets.appIconAlt || STATIC_FALLBACK.content.assets.appIconAlt, + className: "dock-icon ssscript", + iconClass: "logo", + dividerBefore: false, + }, + { + enabled: true, + title: "Корзина", + href: "", + linkTarget: "", + targetId: "", + iconSrc: "./assets/webflow/images/69a9ae818a76c773dc3cf7bc_trash.avif", + iconAlt: dock.trashAlt || "Белая иконка корзины.", + className: "dock-icon no-bg", + iconClass: "dock-app-img trash", + dividerBefore: true, + }, + ]; +} + +function normalizeDock(dock, assets = {}) { + const fallbackItems = createDefaultDockItems(dock, assets); + + if (!Array.isArray(dock.items)) { + dock.items = fallbackItems; + } else { + dock.items = dock.items.map((item, index) => { + const fallback = fallbackItems[index] || fallbackItems[0]; + return { + enabled: item.enabled !== false, + title: item.title || fallback.title || `Элемент ${index + 1}`, + href: item.href ?? fallback.href ?? "", + linkTarget: item.linkTarget ?? fallback.linkTarget ?? "", + targetId: item.targetId ?? fallback.targetId ?? "", + iconSrc: item.iconSrc || fallback.iconSrc, + iconAlt: item.iconAlt || item.alt || fallback.iconAlt, + className: item.className || fallback.className || "dock-icon ssscript", + iconClass: item.iconClass || fallback.iconClass || "logo", + dividerBefore: Boolean(item.dividerBefore), + }; + }); + } + + dock.demoFileLabel ||= STATIC_FALLBACK.content.dock.demoFileLabel; + delete dock.appTarget; + delete dock.trashAlt; +} + function ensureStaticElements() { if (!state.page.staticElements) { state.page.staticElements = clone(STATIC_FALLBACK); @@ -307,8 +413,9 @@ function ensureStaticElements() { state.page.staticElements.content.notifications.forEach((notification, index) => { notification.eyebrowClass ||= STATIC_FALLBACK.content.notifications[index]?.eyebrowClass || "red-txt gray"; }); - state.page.staticElements.content.dock ||= clone(STATIC_FALLBACK.content.dock); state.page.staticElements.content.assets ||= clone(STATIC_FALLBACK.content.assets); + state.page.staticElements.content.dock ||= clone(STATIC_FALLBACK.content.dock); + normalizeDock(state.page.staticElements.content.dock, state.page.staticElements.content.assets); state.page.staticElements.editableFields = clone(STATIC_FALLBACK.editableFields); } @@ -1286,7 +1393,71 @@ function prepareCollectionItemForInsert(items, item) { return nextItem; } +function syncFieldValue(block, path, input) { + setByPath(block, path, input.type === "checkbox" ? input.checked : input.value); + el.json.value = JSON.stringify(block, null, 2); + markDirty(); +} + +function renderBooleanField({ block, editableField, grid }) { + const label = document.createElement("label"); + const labelRow = document.createElement("span"); + const labelText = document.createElement("span"); + const kind = document.createElement("span"); + const path = document.createElement("span"); + const input = document.createElement("input"); + + label.className = "field-control boolean-field"; + labelRow.className = "field-label-row"; + labelText.className = "field-label-text"; + labelText.textContent = editableField.label || editableField.path; + kind.className = "field-kind"; + kind.textContent = editableField.kind || "boolean"; + path.className = "field-path"; + path.textContent = editableField.path; + labelRow.append(labelText, kind); + + input.dataset.path = editableField.path; + input.type = "checkbox"; + input.checked = Boolean(getByPath(block, editableField.path)); + + input.addEventListener("change", () => { + const active = activeBlock(); + if (!active) return; + syncFieldValue(active, editableField.path, input); + }); + + label.append(labelRow, input, path); + grid.append(label); +} + +function renderHeaderBooleanToggle({ block, editableField, head }) { + const label = document.createElement("label"); + const input = document.createElement("input"); + const text = document.createElement("span"); + + label.className = "group-head-toggle"; + input.dataset.path = editableField.path; + input.type = "checkbox"; + input.checked = Boolean(getByPath(block, editableField.path)); + text.textContent = "Отображение"; + + input.addEventListener("change", () => { + const active = activeBlock(); + if (!active) return; + syncFieldValue(active, editableField.path, input); + }); + + label.append(input, text); + head.append(label); +} + function renderCollectionScalarField({ block, field, grid }) { + if (field.kind === "boolean") { + renderBooleanField({ block, editableField: field, grid }); + return; + } + const label = document.createElement("label"); const labelRow = document.createElement("span"); const labelText = document.createElement("span"); @@ -1317,9 +1488,7 @@ function renderCollectionScalarField({ block, field, grid }) { input.addEventListener("input", () => { const active = activeBlock(); if (!active) return; - setByPath(active, field.path, input.value); - el.json.value = JSON.stringify(active, null, 2); - markDirty(); + syncFieldValue(active, field.path, input); }); label.append(labelRow, input, path); @@ -1534,7 +1703,11 @@ function renderContentFields(block) { head.append(titleWrap); grid.className = "group-grid"; - for (const editableField of fields) { + const headerFields = fields.filter((field) => field.kind === "boolean" && field.headerToggle); + const bodyFields = fields.filter((field) => !headerFields.includes(field)); + headerFields.forEach((editableField) => renderHeaderBooleanToggle({ block, editableField, head })); + + for (const editableField of bodyFields) { if (editableField.kind === "collection") { renderCollectionField({ block, editableField, grid }); continue; @@ -1545,6 +1718,11 @@ function renderContentFields(block) { continue; } + if (editableField.kind === "boolean") { + renderBooleanField({ block, editableField, grid }); + continue; + } + const label = document.createElement("label"); const labelRow = document.createElement("span"); const labelText = document.createElement("span"); @@ -1575,9 +1753,7 @@ function renderContentFields(block) { input.addEventListener("input", () => { const active = activeBlock(); if (!active) return; - setByPath(active, editableField.path, input.value); - el.json.value = JSON.stringify(active, null, 2); - markDirty(); + syncFieldValue(active, editableField.path, input); }); label.append(labelRow, input, path); @@ -1594,7 +1770,7 @@ function syncContentFields() { if (!block) return; for (const input of el.contentFields.querySelectorAll("[data-path]")) { - setByPath(block, input.dataset.path, input.value); + setByPath(block, input.dataset.path, input.type === "checkbox" ? input.checked : input.value); } } diff --git a/assets/uploads/images/static-elements/dclogo_white_alpha-mqus5if2.png b/assets/uploads/images/static-elements/dclogo_white_alpha-mqus5if2.png new file mode 100644 index 0000000000000000000000000000000000000000..e265457da4f1e36b11ad69ac44688986ee17e947 GIT binary patch literal 7871 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Деплой в один клик, непрерывный пайплайн, мгновенный откат и быстрая доставка через CDN." } ], - "app": { - "iconAlt": "Иконка NODE.DC", - "logoAlt": "Логотип NODE.DC", - "release": "Бета-релиз: июль 2026", - "heading": "Ранний доступ", - "description": "Кастомный код, MCP и ИИ-агенты для Webflow в одном рабочем контуре." - }, "form": { "messagePlaceholder": "Сообщение (необязательно)", "namePlaceholder": "Ваше имя*", @@ -56,7 +49,17 @@ "failureHeading": "Не получилось", "failureTextHtml": "Что-то пошло не так.
Попробуйте ещё раз чуть позже.
" }, - "legalHtml": "Политика конфиденциальностиПолитика cookie
© — Все права защищены
2026" + "legalHtml": "Политика конфиденциальностиПолитика cookie
© — Все права защищены
2026", + "accessCard": { + "enabled": true, + "iconSrc": "./assets/webflow/images/69ad964d951f9d17cc5a919e_logo-app.svg", + "iconAlt": "Иконка NODE.DC", + "wordmarkSrc": "./assets/webflow/images/69ad96a28b06b7552a339137_logtype.svg?v=node-dc", + "wordmarkAlt": "Логотип NODE.DC", + "release": "Бета-релиз: июль 2026", + "heading": "Ранний доступ", + "description": "Кастомный код, MCP и ИИ-агенты для Webflow в одном рабочем контуре." + } }, "editableFields": [ { @@ -144,39 +147,61 @@ "group": "Тезисы первого экрана" }, { - "path": "content.app.iconAlt", - "label": "App: alt иконки", - "kind": "text", + "path": "content.accessCard.enabled", + "label": "Карточка доступа: отображение", + "kind": "boolean", + "renderAs": "boolean", + "group": "Карточка доступа", + "headerToggle": true + }, + { + "path": "content.accessCard.iconSrc", + "label": "Карточка доступа: иконка", + "kind": "media", "renderAs": "attr", - "group": "Карточка раннего доступа" + "group": "Карточка доступа" }, { - "path": "content.app.logoAlt", - "label": "App: alt логотипа", - "kind": "text", + "path": "content.accessCard.wordmarkSrc", + "label": "Карточка доступа: wordmark", + "kind": "media", "renderAs": "attr", - "group": "Карточка раннего доступа" + "group": "Карточка доступа" }, { - "path": "content.app.release", - "label": "App: релиз", + "path": "content.accessCard.iconAlt", + "label": "Карточка доступа: alt иконки", "kind": "text", "renderAs": "text", - "group": "Карточка раннего доступа" + "group": "Карточка доступа" }, { - "path": "content.app.heading", - "label": "App: заголовок", + "path": "content.accessCard.wordmarkAlt", + "label": "Карточка доступа: alt логотипа", "kind": "text", "renderAs": "text", - "group": "Карточка раннего доступа" + "group": "Карточка доступа" }, { - "path": "content.app.description", - "label": "App: описание", + "path": "content.accessCard.release", + "label": "Карточка доступа: релиз", "kind": "text", "renderAs": "text", - "group": "Карточка раннего доступа" + "group": "Карточка доступа" + }, + { + "path": "content.accessCard.heading", + "label": "Карточка доступа: заголовок", + "kind": "text", + "renderAs": "text", + "group": "Карточка доступа" + }, + { + "path": "content.accessCard.description", + "label": "Карточка доступа: описание", + "kind": "textarea", + "renderAs": "text", + "group": "Карточка доступа" }, { "path": "content.form.messagePlaceholder", @@ -2042,15 +2067,6 @@ "anchor": "waitlist", "enabled": true, "content": { - "app": { - "iconSrc": "./assets/webflow/images/69ad964d951f9d17cc5a919e_logo-app.svg", - "iconAlt": "Иконка NODE.DC", - "wordmarkSrc": "./assets/webflow/images/69ad96a28b06b7552a339137_logtype.svg?v=node-dc", - "wordmarkAlt": "Логотип NODE.DC", - "release": "Бета-релиз: июль 2026", - "heading": "Ранний доступ", - "description": "Кастомный код, MCP и ИИ-агенты для Webflow в одном рабочем контуре." - }, "form": { "messagePlaceholder": "Сообщение (необязательно)", "namePlaceholder": "Ваше имя*", @@ -2303,57 +2319,75 @@ "iconSrcset": "./assets/webflow/images/69a9fb87bc56142371745926_txt-file-p-500.avif 500w, ./assets/webflow/images/69a9fb87bc56142371745926_txt-file.avif 1024w", "iconAlt": "Иконка TXT-файла" } - ] + ], + "accessCard": { + "enabled": true, + "iconSrc": "./assets/webflow/images/69ad964d951f9d17cc5a919e_logo-app.svg", + "iconAlt": "Иконка NODE.DC", + "wordmarkSrc": "./assets/webflow/images/69ad96a28b06b7552a339137_logtype.svg?v=node-dc", + "wordmarkAlt": "Логотип NODE.DC", + "release": "Бета-релиз: июль 2026", + "heading": "Ранний доступ", + "description": "Кастомный код, MCP и ИИ-агенты для Webflow в одном рабочем контуре." + } }, "editableFields": [ { - "path": "content.app.iconSrc", - "label": "Иконка приложения", + "path": "content.accessCard.enabled", + "label": "Карточка доступа: отображение", + "kind": "boolean", + "renderAs": "boolean", + "group": "Карточка доступа", + "headerToggle": true + }, + { + "path": "content.accessCard.iconSrc", + "label": "Карточка доступа: иконка", "kind": "media", "renderAs": "attr", - "group": "Карточка раннего доступа" + "group": "Карточка доступа" }, { - "path": "content.app.iconAlt", - "label": "Иконка: alt", - "kind": "text", - "renderAs": "attr", - "group": "Карточка раннего доступа" - }, - { - "path": "content.app.wordmarkSrc", - "label": "Wordmark", + "path": "content.accessCard.wordmarkSrc", + "label": "Карточка доступа: wordmark", "kind": "media", "renderAs": "attr", - "group": "Карточка раннего доступа" + "group": "Карточка доступа" }, { - "path": "content.app.wordmarkAlt", - "label": "Wordmark: alt", - "kind": "text", - "renderAs": "attr", - "group": "Карточка раннего доступа" - }, - { - "path": "content.app.release", - "label": "Релиз", + "path": "content.accessCard.iconAlt", + "label": "Карточка доступа: alt иконки", "kind": "text", "renderAs": "text", - "group": "Карточка раннего доступа" + "group": "Карточка доступа" }, { - "path": "content.app.heading", - "label": "Заголовок", + "path": "content.accessCard.wordmarkAlt", + "label": "Карточка доступа: alt логотипа", "kind": "text", "renderAs": "text", - "group": "Карточка раннего доступа" + "group": "Карточка доступа" }, { - "path": "content.app.description", - "label": "Описание", + "path": "content.accessCard.release", + "label": "Карточка доступа: релиз", + "kind": "text", + "renderAs": "text", + "group": "Карточка доступа" + }, + { + "path": "content.accessCard.heading", + "label": "Карточка доступа: заголовок", + "kind": "text", + "renderAs": "text", + "group": "Карточка доступа" + }, + { + "path": "content.accessCard.description", + "label": "Карточка доступа: описание", "kind": "textarea", "renderAs": "text", - "group": "Карточка раннего доступа" + "group": "Карточка доступа" }, { "path": "content.form.messagePlaceholder", diff --git a/content/pages/home.json b/content/pages/home.json index 2c46b74..140c6ad 100644 --- a/content/pages/home.json +++ b/content/pages/home.json @@ -57,15 +57,39 @@ } ], "dock": { - "appTarget": "app-data", - "trashAlt": "Белая иконка корзины.", - "demoFileLabel": "демо-видео.txt" + "demoFileLabel": "демо-видео.txt", + "items": [ + { + "enabled": true, + "title": "NODE.DC", + "href": "#hero", + "linkTarget": "", + "targetId": "app-data", + "iconSrc": "./assets/uploads/images/static-elements/dclogo_white_alpha-mqus5if2.png", + "iconAlt": "Иконка NODE.DC", + "className": "dock-icon ssscript", + "iconClass": "logo", + "dividerBefore": false + }, + { + "enabled": true, + "title": "Корзина", + "href": "", + "linkTarget": "", + "targetId": "", + "iconSrc": "./assets/webflow/images/69a9ae818a76c773dc3cf7bc_trash.avif", + "iconAlt": "Белая иконка корзины.", + "className": "dock-icon no-bg", + "iconClass": "dock-app-img trash", + "dividerBefore": true + } + ] }, "assets": { "webglModelSrc": "./assets/custom/icon.glb", "logoPng": "./assets/custom/logo.png", "logoPngAlt": "Логотип NODE.DC", - "appIconSrc": "./assets/webflow/images/69ad964d951f9d17cc5a919e_logo-app.svg", + "appIconSrc": "./assets/uploads/images/static-elements/dclogo_white_alpha-mqus5if2.png", "appIconAlt": "Иконка NODE.DC", "appWordmarkSrc": "./assets/webflow/images/69ad96a28b06b7552a339137_logtype.svg?v=node-dc", "appWordmarkAlt": "Логотип NODE.DC" @@ -172,18 +196,81 @@ ] }, { - "path": "content.dock.appTarget", - "label": "Dock: ID приложения", - "kind": "text", - "renderAs": "text", - "group": "Dock" - }, - { - "path": "content.dock.trashAlt", - "label": "Dock: alt корзины", - "kind": "text", - "renderAs": "text", - "group": "Dock" + "path": "content.dock.items", + "label": "Иконки dock-панели", + "kind": "collection", + "renderAs": "collection", + "group": "Dock", + "itemTemplate": { + "enabled": true, + "title": "Новое приложение", + "href": "#hero", + "linkTarget": "", + "targetId": "", + "iconSrc": "./assets/webflow/images/69ad964d951f9d17cc5a919e_logo-app.svg", + "iconAlt": "Иконка приложения", + "className": "dock-icon ssscript", + "iconClass": "logo", + "dividerBefore": false + }, + "itemFields": [ + { + "path": "enabled", + "label": "Отображение", + "kind": "boolean", + "renderAs": "boolean", + "group": "Dock" + }, + { + "path": "title", + "label": "Название", + "kind": "text", + "renderAs": "text", + "group": "Dock" + }, + { + "path": "href", + "label": "Ссылка / адрес", + "kind": "url", + "renderAs": "attr", + "group": "Dock" + }, + { + "path": "linkTarget", + "label": "Target ссылки", + "kind": "text", + "renderAs": "attr", + "group": "Dock" + }, + { + "path": "targetId", + "label": "ID окна / приложения", + "kind": "text", + "renderAs": "attr", + "group": "Dock" + }, + { + "path": "iconSrc", + "label": "Иконка", + "kind": "media", + "renderAs": "attr", + "group": "Dock" + }, + { + "path": "iconAlt", + "label": "Alt иконки", + "kind": "text", + "renderAs": "text", + "group": "Dock" + }, + { + "path": "dividerBefore", + "label": "Разделитель слева", + "kind": "boolean", + "renderAs": "boolean", + "group": "Dock" + } + ] }, { "path": "content.dock.demoFileLabel", @@ -283,13 +370,6 @@ "bodyHtml": "Деплой в один клик, непрерывный пайплайн, мгновенный откат и быстрая доставка через CDN." } ], - "app": { - "iconAlt": "Иконка NODE.DC", - "logoAlt": "Логотип NODE.DC", - "release": "Бета-релиз: июль 2026", - "heading": "Ранний доступ", - "description": "Кастомный код, MCP и ИИ-агенты для Webflow в одном рабочем контуре." - }, "form": { "messagePlaceholder": "Сообщение (необязательно)", "namePlaceholder": "Ваше имя*", @@ -304,7 +384,17 @@ "failureHeading": "Не получилось", "failureTextHtml": "Что-то пошло не так.
Попробуйте ещё раз чуть позже.
" }, - "legalHtml": "Политика конфиденциальностиПолитика cookie
© — Все права защищены
2026" + "legalHtml": "Политика конфиденциальностиПолитика cookie
© — Все права защищены
2026", + "accessCard": { + "enabled": true, + "iconSrc": "./assets/webflow/images/69ad964d951f9d17cc5a919e_logo-app.svg", + "iconAlt": "Иконка NODE.DC", + "wordmarkSrc": "./assets/webflow/images/69ad96a28b06b7552a339137_logtype.svg?v=node-dc", + "wordmarkAlt": "Логотип NODE.DC", + "release": "Бета-релиз: июль 2026", + "heading": "Ранний доступ", + "description": "Кастомный код, MCP и ИИ-агенты для Webflow в одном рабочем контуре." + } }, "editableFields": [ { @@ -392,39 +482,61 @@ "group": "Тезисы первого экрана" }, { - "path": "content.app.iconAlt", - "label": "App: alt иконки", - "kind": "text", + "path": "content.accessCard.enabled", + "label": "Карточка доступа: отображение", + "kind": "boolean", + "renderAs": "boolean", + "group": "Карточка доступа", + "headerToggle": true + }, + { + "path": "content.accessCard.iconSrc", + "label": "Карточка доступа: иконка", + "kind": "media", "renderAs": "attr", - "group": "Карточка раннего доступа" + "group": "Карточка доступа" }, { - "path": "content.app.logoAlt", - "label": "App: alt логотипа", - "kind": "text", + "path": "content.accessCard.wordmarkSrc", + "label": "Карточка доступа: wordmark", + "kind": "media", "renderAs": "attr", - "group": "Карточка раннего доступа" + "group": "Карточка доступа" }, { - "path": "content.app.release", - "label": "App: релиз", + "path": "content.accessCard.iconAlt", + "label": "Карточка доступа: alt иконки", "kind": "text", "renderAs": "text", - "group": "Карточка раннего доступа" + "group": "Карточка доступа" }, { - "path": "content.app.heading", - "label": "App: заголовок", + "path": "content.accessCard.wordmarkAlt", + "label": "Карточка доступа: alt логотипа", "kind": "text", "renderAs": "text", - "group": "Карточка раннего доступа" + "group": "Карточка доступа" }, { - "path": "content.app.description", - "label": "App: описание", + "path": "content.accessCard.release", + "label": "Карточка доступа: релиз", "kind": "text", "renderAs": "text", - "group": "Карточка раннего доступа" + "group": "Карточка доступа" + }, + { + "path": "content.accessCard.heading", + "label": "Карточка доступа: заголовок", + "kind": "text", + "renderAs": "text", + "group": "Карточка доступа" + }, + { + "path": "content.accessCard.description", + "label": "Карточка доступа: описание", + "kind": "textarea", + "renderAs": "text", + "group": "Карточка доступа" }, { "path": "content.form.messagePlaceholder", @@ -2241,15 +2353,6 @@ "anchor": "waitlist", "enabled": true, "content": { - "app": { - "iconSrc": "./assets/webflow/images/69ad964d951f9d17cc5a919e_logo-app.svg", - "iconAlt": "Иконка NODE.DC", - "wordmarkSrc": "./assets/webflow/images/69ad96a28b06b7552a339137_logtype.svg?v=node-dc", - "wordmarkAlt": "Логотип NODE.DC", - "release": "Бета-релиз: июль 2026", - "heading": "Ранний доступ", - "description": "Кастомный код, MCP и ИИ-агенты для Webflow в одном рабочем контуре." - }, "form": { "messagePlaceholder": "Сообщение (необязательно)", "namePlaceholder": "Ваше имя*", @@ -2502,57 +2605,75 @@ "iconSrcset": "./assets/webflow/images/69a9fb87bc56142371745926_txt-file-p-500.avif 500w, ./assets/webflow/images/69a9fb87bc56142371745926_txt-file.avif 1024w", "iconAlt": "Иконка TXT-файла" } - ] + ], + "accessCard": { + "enabled": true, + "iconSrc": "./assets/webflow/images/69ad964d951f9d17cc5a919e_logo-app.svg", + "iconAlt": "Иконка NODE.DC", + "wordmarkSrc": "./assets/webflow/images/69ad96a28b06b7552a339137_logtype.svg?v=node-dc", + "wordmarkAlt": "Логотип NODE.DC", + "release": "Бета-релиз: июль 2026", + "heading": "Ранний доступ", + "description": "Кастомный код, MCP и ИИ-агенты для Webflow в одном рабочем контуре." + } }, "editableFields": [ { - "path": "content.app.iconSrc", - "label": "Иконка приложения", + "path": "content.accessCard.enabled", + "label": "Карточка доступа: отображение", + "kind": "boolean", + "renderAs": "boolean", + "group": "Карточка доступа", + "headerToggle": true + }, + { + "path": "content.accessCard.iconSrc", + "label": "Карточка доступа: иконка", "kind": "media", "renderAs": "attr", - "group": "Карточка раннего доступа" + "group": "Карточка доступа" }, { - "path": "content.app.iconAlt", - "label": "Иконка: alt", - "kind": "text", - "renderAs": "attr", - "group": "Карточка раннего доступа" - }, - { - "path": "content.app.wordmarkSrc", - "label": "Wordmark", + "path": "content.accessCard.wordmarkSrc", + "label": "Карточка доступа: wordmark", "kind": "media", "renderAs": "attr", - "group": "Карточка раннего доступа" + "group": "Карточка доступа" }, { - "path": "content.app.wordmarkAlt", - "label": "Wordmark: alt", - "kind": "text", - "renderAs": "attr", - "group": "Карточка раннего доступа" - }, - { - "path": "content.app.release", - "label": "Релиз", + "path": "content.accessCard.iconAlt", + "label": "Карточка доступа: alt иконки", "kind": "text", "renderAs": "text", - "group": "Карточка раннего доступа" + "group": "Карточка доступа" }, { - "path": "content.app.heading", - "label": "Заголовок", + "path": "content.accessCard.wordmarkAlt", + "label": "Карточка доступа: alt логотипа", "kind": "text", "renderAs": "text", - "group": "Карточка раннего доступа" + "group": "Карточка доступа" }, { - "path": "content.app.description", - "label": "Описание", + "path": "content.accessCard.release", + "label": "Карточка доступа: релиз", + "kind": "text", + "renderAs": "text", + "group": "Карточка доступа" + }, + { + "path": "content.accessCard.heading", + "label": "Карточка доступа: заголовок", + "kind": "text", + "renderAs": "text", + "group": "Карточка доступа" + }, + { + "path": "content.accessCard.description", + "label": "Карточка доступа: описание", "kind": "textarea", "renderAs": "text", - "group": "Карточка раннего доступа" + "group": "Карточка доступа" }, { "path": "content.form.messagePlaceholder", diff --git a/index.html b/index.html index 1d44d30..7a063cc 100644 --- a/index.html +++ b/index.html @@ -120,4 +120,4 @@ visibility: hidden;

Ваш Webflow ИИ-инструменты

Несколько агентов для проекта Webflow: от Designer до кастомного кода.

Полныйагентный контроль

Интеграция с Webflow MCP, мультиагентный режим позволяет работать с несколькими экземплярами параллельно.

Компонентнаябиблиотека

Собирайте с учетом ИИ-агентов разные компонентные заготовки дают основу, а стиль и сложную функциональность можно дорабатывать промптами.

Деплой пайплайн

Деплой в один клик, непрерывный пайплайн, мгновенный откат и быстрая доставка через CDN.
Логотип NODE.DC
Бета-релиз: июль 2026

Ранний доступ

Кастомный код, MCP и ИИ-агенты для Webflow в одном рабочем контуре.

Заявка принята. Спасибо.

Мы скоро свяжемся.

Подать заявку в бету?

Или оформить ранний Founder-доступ

Оформить Founder-доступ 350€
До 200 мест

Не получилось

Что-то пошло не так.
Попробуйте ещё раз чуть позже.

демо-видео.mp4

Всё в одномприложение.

Универсальный инструмент для ИИ-агентов в вашем Webflow-проекте.
Контекст проекта
Подключитесь к MCP чтобы агенты получили полный контекст вашей сборки.
Группы агентов
Используйте несколько агентов параллельно чтобы добавлять кастомный код, анимации и функциональность.
Среда разработки
Используйте быстрые Bun сборки и автообновление для вашего кастомного кода.
Деплой в один клик
Нажмите и публикуйте кастомный код, написанный ИИ, чтобы он стал доступен всем посетителям сайта.

АгентнаяКомпонентнаябиблиотека.

Готовая к работе с агентами компонентная библиотека: добавление в один клик через приложение NODE.DC для Webflow и дальнейшая настройка под проект.

Переключение режимов ИИ

Создание нового проекта

ИИ-док

Аккаунт

Редактирование кода с ИИ

Dev-сервер с ИИ

Webflow MCP

Публикация

Одинкликдобавления.

С помощью расширения NODE.DC для Webflow.
Понимание компонентов
Используйте несколько агентов параллельно чтобы добавлять кастомный код, анимации и функциональность.
Быстрый старт
Используйте быстрые Bun сборки и автообновление для вашего кастомного кода.

Получитеболее сильныйMCP.

Полностью переработанный и более быстрый MCP-сервер.
Понимание Webflow
Используйте несколько агентов параллельно чтобы добавлять кастомный код, анимации и функциональность.

Гибкиережимы ИИ.

Разные режимы и модели для разных задач.

Переключение режимов ИИ

Создание нового проекта

ИИ-док

Аккаунт

Редактирование кода с ИИ

Dev-сервер с ИИ

Webflow MCP

Публикация

Частыевопросыи ответы

Подробный обзор возможностей, логики работы и внутреннего устройства.
FAQ
NODE.DC
Это влияет на производительность?
NODE.DC
Где размещаются мои файлы?
NODE.DC
Что делать, если я опубликовал не те файлы?
NODE.DC
Что такое ИИ-агент Webflow?
NODE.DC
Что такое собственная база знаний?
NODE.DC
Как использовать это с Webflow?
NODE.DC
Какие ИИ-модели доступны?
NODE.DC
Как это работает?
NODE.DC
Как работает публикация?
NODE.DC
Это работает с MCP?
NODE.DC
Ответить
Это влияет на производительность?

Как и любой кастомный код, это добавляет только ту нагрузку, которую несёт сам код.

Все файлы собираются, минифицируются и сжимаются, чтобы минимально влиять на проект и не плодить внешние библиотеки и CDN-скрипты.

Отправлено с iPhone
NODE.DC
Ответить
Где размещаются мои файлы?

После сборки файлы загружаются в Cloudflare R2 и отдаются через CDN-ссылку на выделенном домене проекта, чтобы получить быстрый и совместимый с Webflow результат.

Отправлено с iPhone
NODE.DC
Ответить
Что делать, если я опубликовал не те файлы?

В панели деплоя есть мгновенный откат.

Нажмите откат, верните предыдущую рабочую версию, исправьте локально и опубликуйте заново.

Отправлено с iPhone
NODE.DC
Ответить
Что такое ИИ-агент Webflow?

Помимо @plan, @build и @explore стандартных режимов агентов мы готовим @webflow режим, специально заточенный под Webflow: структуру проекта, взаимодействие с ним и эффективную разработку.

Отправлено с iPhone
NODE.DC
Ответить
Что такое собственная база знаний?

Основано на многолетнем опыте написания кастомного кода для Webflow-анимаций.

WebGL, Three.js, GSAP и кастомная функциональность собраны в набор практик, пайплайнов и модульную систему, чтобы всё работало согласованно.

Также доступна библиотека компонентов: выберите компонент, добавьте в проект и попросите ИИ адаптировать его под задачу.

Отправлено с iPhone
NODE.DC
Ответить
Как использовать это с Webflow?

При запуске NODE.DC доступна отдельная вкладка для встраивания.

В зависимости от задачи можно получить скрипты для конкретной страницы или единый app.js для всего проекта.

Сгенерированная ссылка содержит и продакшен-версию, следующую за URL деплоя, и локальную версию для предпросмотра без влияния на посетителей сайта.

Отправлено с iPhone
NODE.DC
Ответить
Какие ИИ-модели доступны?

Мы используем основные доступные модели: OpenAI до Claude до Gemini.

Оркестратор выбирает модель под задачу автоматически, но вы можете вручную переключиться на нужную модель.

Отправлено с iPhone
NODE.DC
Ответить
Как это работает?

Во время работы NODE.DC выполняет две задачи параллельно.

Поднимает локальную среду разработки на Bun, синхронизирует JavaScript и TypeScript, включает HMR и держит webhook для автоматического обновления сайта при изменениях.

Одновременно работает оркестратор ИИ-агентов: обрабатывает запросы, меняет код, проверяет состояние сборки и при необходимости обновляет проект Webflow.

Отправлено с iPhone
NODE.DC
Ответить
Как работает публикация?

Процесс многоэтапный: сначала Bun собирает, сжимает, минифицирует и подготавливает проект вместе с библиотеками.

Затем файлы отправляются в CDN: cdn.node.dc/{USERNAME}/{PROJECT-NAME}. Ссылка уже содержит нужную структуру: вы видите локальную версию, а пользователи получают опубликованный скрипт.

Отправлено с iPhone
NODE.DC
Ответить
Это работает с MCP?

Система изначально рассчитана на работу с Webflow MCP.

Подключите проект и авторизацию, чтобы ИИ-агенты получили доступ к Webflow-сборке. Подключение приложения в Webflow Designer даёт агентам доступ к контенту, элементам, стилям и CSS, а кастомный код получает полный контекст проекта.

Отправлено с iPhone

Подключить.Поставить задачу.Опубликовать.

Единый путь от разработки до продакшена.
Настройка примерно в 12 кликов: от скачивания приложения до запуска в проекте.
Встать в лист ожидания
Тарифы

Коддля No-Code,усиленный ИИ.

Подписки на приложение с
включённым объёмом в каждом тарифе.
Токенная оплата сверх лимитов.
200 Founder мест с фиксированной ценой на первый год.
Тарифы.app

Бета

Бесплатно
1 месяц

Founder

310
/ год, навсегда
Скидка 50%

Basic

20
/ месяц

Advanced

50
/ месяц
Старт
Старт
Старт
Всего доступно
Расширение (20M)
Расширение (10M)
Глубина рассуждения
Базовый интеллект
Рабочее пространство
Объём токенов
Старт
Объём токенов
Объём токенов
Рабочее пространство
Всего доступно
Расширение (20M)
Расширение (10M)
Глубина рассуждения
Базовый интеллект
Рабочее пространство
Базовый интеллект
Глубина рассуждения
Расширение (10M)
Расширение (20M)
Всего доступно
Июнь 2026
Июнь 2026
Июнь 2026
Июнь 2026
Кредиты тарифа
Без ограничений
40 000 включено
12 000 включено
40 000 включено
Рабочее пространство
Без ограничений
Без ограничений
10 проектов
Без ограничений
Базовый интеллект
Все модели
Все быстрые
Все быстрые
Все быстрые
Глубина рассуждения
Полный
Полный
Ограниченный
Полный
Расширение SM 10€
Обновления без лимита
+ 10 000 кредитов
+ 8 000 кредитов
+ 10 000 кредитов
Расширение MD 20€
Обновления без лимита
+ 26 000 кредитов
+ 20 000 кредитов
+ 26 000 кредитов
Всего доступно
40 тестировщиков
200 мест
--
--
Подать заявку в бету
Оформить Founder-доступ
(*) Условия могут меняться по ходу тестирования, но мы постараемся сохранить заявленные обещания.
Enterprise BYOK-тарифы будут доступны с сентября 2026.
публикация-в-один-клик.png
Иконка MOV-файла.
публикация-в-один-клик.png
полноценный-редактор-кода.webp
Иконка MOV-файла.
полноценный-редактор-кода.webp
ИИ-док-режим.jpg
Иконка MOV-файла.
ИИ-док-режим.jpg
глубокая-интеграция-webflow.webp
Иконка MOV-файла.
глубокая-интеграция-webflow.webp
установка-настройка-запуск.jpg
Иконка MOV-файла.
установка-настройка-запуск.jpg
Логотип NODE.DC
Бета-релиз: июль 2026

Ранний доступ

Кастомный код, MCP и ИИ-агенты для Webflow в одном рабочем контуре.

Заявка принята. Спасибо.

Мы скоро свяжемся.

Подать заявку в бету?
Иконка TXT-файла
fff
fff
Иконка TXT-файла
Ergtrr
Ggg
Иконка TXT-файла
Paul
только что нашёл ваш сайт — выглядит отлично!
Иконка TXT-файла
s
s
Иконка TXT-файла
rkxkr
пока не уверен, но да, интересно
Иконка TXT-файла
Ali Awan
Дайте, пожалуйста, посмотреть продукт!
Иконка TXT-файла
rox del toro
ХОЧУ ДОСТУП
Иконка TXT-файла
Flavio
Привет!
Иконка TXT-файла
Daniel Clydesdale
Мы работаем с Webflow с 2016 года и используем его постоянно. Сейчас внедряем ИИ в процессы, поэтому ваш продукт нам очень интересен. Удачи с запуском!
Иконка TXT-файла
Carter Ogunsola
Для всех разработчиков: я нашёл это очень рано. Уже один из фаворитов.
Иконка TXT-файла
Marin Trajkovski
Здравствуйте, можно получить ранний доступ? Очень хочу протестировать ИИ, это сейчас действительно нужно.
Иконка TXT-файла
Arul
Интересно. Хотелось бы узнать больше.
Иконка TXT-файла
Jeremy
Вау! -Пожалуйста, пустите меня в бету!
Иконка TXT-файла
Safin
С удовольствием протестировал бы продукт. Выглядит очень интересно.
Иконка TXT-файла
Ilja van Eck
Я теперь первый Founder? Берите деньги и запускайте это.
Иконка TXT-файла
Jordan Gilroy
Я ваш главный фанат
Иконка TXT-файла
hyun
привет
Иконка TXT-файла
kris
тестирую
Иконка TXT-файла
Syed Irfan
Интересно
Иконка TXT-файла
ramyar atlasi
Apm pflege schule Düsseldorf
Иконка TXT-файла
Muhammad Ashar
vv
Иконка TXT-файла
:DD
ka tu nx
Иконка TXT-файла
test
test
Иконка TXT-файла
Filip
Я знаю Fed!
Иконка TXT-файла
Arinbjørn
Пустите меня!
Иконка TXT-файла
Janarthanan
жду
Иконка TXT-файла
Jane Smith
Очень хочу ранний доступ к продукту!
Иконка TXT-файла
Daniel Apro
Привет, сайт огонь.
Иконка TXT-файла
Allonelabs
Нам очень нравится ваш дизайн. Спасибо!
Иконка TXT-файла
nicola romei
G.O.A.T. часто используют как сокращение от Greatest of All Time — «лучший за всё время».
Иконка TXT-файла
fff
.txt
Иконка TXT-файла
Ergtrr
.txt
Иконка TXT-файла
Paul
.txt
Иконка TXT-файла
s
.txt
Иконка TXT-файла
rkxkr
.txt
Иконка TXT-файла
Ali Awan
.txt
Иконка TXT-файла
rox del toro
.txt
Иконка TXT-файла
Flavio
.txt
Иконка TXT-файла
Daniel Clydesdale
.txt
Иконка TXT-файла
Carter Ogunsola
.txt
Иконка TXT-файла
Marin Trajkovski
.txt
Иконка TXT-файла
Arul
.txt
Иконка TXT-файла
Jeremy
.txt
Иконка TXT-файла
Safin
.txt
Иконка TXT-файла
Ilja van Eck
.txt
Иконка TXT-файла
Jordan Gilroy
.txt
Иконка TXT-файла
hyun
.txt
Иконка TXT-файла
kris
.txt
Иконка TXT-файла
Syed Irfan
.txt
Иконка TXT-файла
ramyar atlasi
.txt
Иконка TXT-файла
Muhammad Ashar
.txt
Иконка TXT-файла
:DD
.txt
Иконка TXT-файла
test
.txt
Иконка TXT-файла
Filip
.txt
Иконка TXT-файла
Arinbjørn
.txt
Иконка TXT-файла
Janarthanan
.txt
Иконка TXT-файла
Jane Smith
.txt
Иконка TXT-файла
Daniel Apro
.txt
Иконка TXT-файла
Allonelabs
.txt
Иконка TXT-файла
nicola romei
.txt
Иконка MOV-файла.
демо-видео.txt
ДАЛЕЕ — ИЮЛЬ 2026
Открытая бета
Открываем доступ всем. Будем собирать и отлаживать вместе.
ДАЛЕЕ ИЮЛЬ 2026
Альфа для Founder-доступа
На второй фазе тестирования бета открыта для всех подписчиков Founder-тарифа.
СЕЙЧАС
Инвайты в закрытую бету уже отправлены.
Сейчас тестируем базовую функциональность и ИИ-интеграцию.
\ No newline at end of file +Пожалуйста, пустите меня в бету!
Иконка TXT-файла
Safin
С удовольствием протестировал бы продукт. Выглядит очень интересно.
Иконка TXT-файла
Ilja van Eck
Я теперь первый Founder? Берите деньги и запускайте это.
Иконка TXT-файла
Jordan Gilroy
Я ваш главный фанат
Иконка TXT-файла
hyun
привет
Иконка TXT-файла
kris
тестирую
Иконка TXT-файла
Syed Irfan
Интересно
Иконка TXT-файла
ramyar atlasi
Apm pflege schule Düsseldorf
Иконка TXT-файла
Muhammad Ashar
vv
Иконка TXT-файла
:DD
ka tu nx
Иконка TXT-файла
test
test
Иконка TXT-файла
Filip
Я знаю Fed!
Иконка TXT-файла
Arinbjørn
Пустите меня!
Иконка TXT-файла
Janarthanan
жду
Иконка TXT-файла
Jane Smith
Очень хочу ранний доступ к продукту!
Иконка TXT-файла
Daniel Apro
Привет, сайт огонь.
Иконка TXT-файла
Allonelabs
Нам очень нравится ваш дизайн. Спасибо!
Иконка TXT-файла
nicola romei
G.O.A.T. часто используют как сокращение от Greatest of All Time — «лучший за всё время».
Иконка TXT-файла
fff
.txt
Иконка TXT-файла
Ergtrr
.txt
Иконка TXT-файла
Paul
.txt
Иконка TXT-файла
s
.txt
Иконка TXT-файла
rkxkr
.txt
Иконка TXT-файла
Ali Awan
.txt
Иконка TXT-файла
rox del toro
.txt
Иконка TXT-файла
Flavio
.txt
Иконка TXT-файла
Daniel Clydesdale
.txt
Иконка TXT-файла
Carter Ogunsola
.txt
Иконка TXT-файла
Marin Trajkovski
.txt
Иконка TXT-файла
Arul
.txt
Иконка TXT-файла
Jeremy
.txt
Иконка TXT-файла
Safin
.txt
Иконка TXT-файла
Ilja van Eck
.txt
Иконка TXT-файла
Jordan Gilroy
.txt
Иконка TXT-файла
hyun
.txt
Иконка TXT-файла
kris
.txt
Иконка TXT-файла
Syed Irfan
.txt
Иконка TXT-файла
ramyar atlasi
.txt
Иконка TXT-файла
Muhammad Ashar
.txt
Иконка TXT-файла
:DD
.txt
Иконка TXT-файла
test
.txt
Иконка TXT-файла
Filip
.txt
Иконка TXT-файла
Arinbjørn
.txt
Иконка TXT-файла
Janarthanan
.txt
Иконка TXT-файла
Jane Smith
.txt
Иконка TXT-файла
Daniel Apro
.txt
Иконка TXT-файла
Allonelabs
.txt
Иконка TXT-файла
nicola romei
.txt
Иконка MOV-файла.
демо-видео.txt
ДАЛЕЕ — ИЮЛЬ 2026
Открытая бета
Открываем доступ всем. Будем собирать и отлаживать вместе.
ДАЛЕЕ ИЮЛЬ 2026
Альфа для Founder-доступа
На второй фазе тестирования бета открыта для всех подписчиков Founder-тарифа.
СЕЙЧАС
Инвайты в закрытую бету уже отправлены.
Сейчас тестируем базовую функциональность и ИИ-интеграцию.
\ No newline at end of file diff --git a/templates/pages/home/blocks/hero-waitlist.html b/templates/pages/home/blocks/hero-waitlist.html index 3c8e25c..09a3639 100644 --- a/templates/pages/home/blocks/hero-waitlist.html +++ b/templates/pages/home/blocks/hero-waitlist.html @@ -1 +1 @@ -

{{text:content.heading.muted}}{{text:content.heading.main}}

{{html:content.introHtml}}

{{text:content.cards.0.muted}}{{text:content.cards.0.main}}

{{html:content.cards.0.bodyHtml}}

{{text:content.cards.1.muted}}{{text:content.cards.1.main}}

{{html:content.cards.1.bodyHtml}}

{{text:content.cards.2.muted}}{{text:content.cards.2.main}}

{{html:content.cards.2.bodyHtml}}
{{attr:content.app.logoAlt}}
{{text:content.app.release}}

{{text:content.app.heading}}

{{text:content.app.description}}

{{text:content.form.successHeading}}

{{html:content.form.successTextHtml}}

{{text:content.form.betaCtaLabel}}

{{html:content.form.founderIntroHtml}}

{{html:content.form.founderCtaHtml}}
{{text:content.form.spotsLabel}}

{{text:content.form.failureHeading}}

{{html:content.form.failureTextHtml}}

{{html:content.legalHtml}}
\ No newline at end of file +

{{text:content.heading.muted}}{{text:content.heading.main}}

{{html:content.introHtml}}

{{text:content.cards.0.muted}}{{text:content.cards.0.main}}

{{html:content.cards.0.bodyHtml}}

{{text:content.cards.1.muted}}{{text:content.cards.1.main}}

{{html:content.cards.1.bodyHtml}}

{{text:content.cards.2.muted}}{{text:content.cards.2.main}}

{{html:content.cards.2.bodyHtml}}
{{#if content.accessCard.enabled}}
{{attr:content.accessCard.wordmarkAlt}}
{{text:content.accessCard.release}}

{{text:content.accessCard.heading}}

{{text:content.accessCard.description}}

{{text:content.form.successHeading}}

{{html:content.form.successTextHtml}}

{{text:content.form.betaCtaLabel}}

{{html:content.form.founderIntroHtml}}

{{html:content.form.founderCtaHtml}}
{{text:content.form.spotsLabel}}

{{text:content.form.failureHeading}}

{{html:content.form.failureTextHtml}}

{{html:content.legalHtml}}
{{/if}}
\ No newline at end of file diff --git a/templates/pages/home/blocks/waitlist-files.html b/templates/pages/home/blocks/waitlist-files.html index 39d44d5..fe1371f 100644 --- a/templates/pages/home/blocks/waitlist-files.html +++ b/templates/pages/home/blocks/waitlist-files.html @@ -1 +1 @@ -
{{attr:content.app.wordmarkAlt}}
{{text:content.app.release}}

{{text:content.app.heading}}

{{text:content.app.description}}

{{text:content.form.successHeading}}

{{html:content.form.successTextHtml}}

{{text:content.form.betaCtaLabel}}
{{html:content.legalHtml}}
{{#each content.files}}
{{attr:iconAlt}}
{{text:name}}
{{html:bodyHtml}}
{{/each}}
{{#each content.files}}
{{attr:iconAlt}}
{{text:name}}
.txt
{{/each}}
\ No newline at end of file +
{{#if content.accessCard.enabled}}
{{attr:content.accessCard.wordmarkAlt}}
{{text:content.accessCard.release}}

{{text:content.accessCard.heading}}

{{text:content.accessCard.description}}

{{text:content.form.successHeading}}

{{html:content.form.successTextHtml}}

{{text:content.form.betaCtaLabel}}
{{html:content.legalHtml}}
{{/if}}
{{#each content.files}}
{{attr:iconAlt}}
{{text:name}}
{{html:bodyHtml}}
{{/each}}
{{#each content.files}}
{{attr:iconAlt}}
{{text:name}}
.txt
{{/each}}
\ No newline at end of file diff --git a/templates/pages/home/shell.html b/templates/pages/home/shell.html index 1ad8850..3e5817c 100644 --- a/templates/pages/home/shell.html +++ b/templates/pages/home/shell.html @@ -117,4 +117,4 @@ window.__API_ORIGIN__="https://ssscript-website.vercel.app"; [debug] { visibility: hidden; } -
{{NODEDC_BLOCKS_BEFORE_CVIZ}}
{{NODEDC_BLOCKS_CVIZ}}
{{#each staticElements.content.notifications}}
{{html:eyebrowHtml}}
{{text:title}}
{{text:body}}
{{/each}}
{{attr:staticElements.content.dock.trashAlt}}
{{text:staticElements.content.navigation.brandLabel}}
{{#each staticElements.content.navigation.links}}{{/each}}
Сб, 10 июня
09:41
\ No newline at end of file +
{{NODEDC_BLOCKS_BEFORE_CVIZ}}
{{NODEDC_BLOCKS_CVIZ}}
{{#each staticElements.content.notifications}}
{{html:eyebrowHtml}}
{{text:title}}
{{text:body}}
{{/each}}
{{#each staticElements.content.dock.items}}{{#if enabled}}{{#if dividerBefore}}
{{/if}}{{attr:iconAlt}}{{/if}}{{/each}}
{{text:staticElements.content.navigation.brandLabel}}
{{#each staticElements.content.navigation.links}}{{/each}}
Сб, 10 июня
09:41
\ No newline at end of file diff --git a/tools/render-home.mjs b/tools/render-home.mjs index d79f0f3..78770d8 100644 --- a/tools/render-home.mjs +++ b/tools/render-home.mjs @@ -37,6 +37,11 @@ function getByPath(source, path) { return path.split(".").reduce((value, key) => value?.[key], source); } +function isTruthy(value) { + if (Array.isArray(value)) return value.length > 0; + return Boolean(value); +} + function escapeHtml(value) { return String(value) .replaceAll("&", "&") @@ -83,6 +88,24 @@ function renderTemplateTokens(html, block) { }); } +function renderIfBlocks(html, block) { + let rendered = html; + let previous = null; + + while (rendered !== previous) { + previous = rendered; + rendered = rendered.replace( + /\{\{#if\s+([a-zA-Z0-9_.-]+)\s*\}\}((?:(?!\{\{#if|\{\{\/if\}\})[\s\S])*)\{\{\/if\}\}/g, + (_match, path, innerHtml) => { + const value = getByPath(block, path); + return isTruthy(value) ? renderTemplate(innerHtml, block) : ""; + }, + ); + } + + return rendered; +} + function renderEachBlocks(html, block) { return html.replace(/\{\{#each\s+([a-zA-Z0-9_.-]+)\s*\}\}([\s\S]*?)\{\{\/each\}\}/g, (_match, path, innerHtml) => { const items = getByPath(block, path); @@ -91,10 +114,14 @@ function renderEachBlocks(html, block) { throw new Error(`Each token "${path}" in block "${block.id}" must point to an array`); } - return items.map((item) => renderTemplateTokens(innerHtml, item ?? {})).join(""); + return items.map((item) => renderTemplate(innerHtml, item ?? {})).join(""); }); } +function renderTemplate(html, block) { + return renderTemplateTokens(renderIfBlocks(renderEachBlocks(html, block), block), block); +} + function scopeDuplicateIds(html, scope) { const ids = [...html.matchAll(/\sid="([^"]+)"/g)].map((match) => match[1]); if (!ids.length) { @@ -124,7 +151,7 @@ async function renderBlock(block, renderCounts) { const renderCount = renderCounts.get(templateName) ?? 0; renderCounts.set(templateName, renderCount + 1); - const html = renderTemplateTokens(renderEachBlocks(await readTemplate(templateName), block), block); + const html = renderTemplate(await readTemplate(templateName), block); if (renderCount === 0 && block.scopeIds !== true) { return html; @@ -144,7 +171,7 @@ async function renderRegion(region) { return blocks.join(""); } -let output = renderTemplateTokens(renderEachBlocks(shell, { id: page.slug, ...page }), { id: page.slug, ...page }); +let output = renderTemplate(shell, { id: page.slug, ...page }); for (const region of page.regions ?? []) { const token = REGION_TOKEN[region.id]; if (!token) {