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 0000000..e265457
Binary files /dev/null and b/assets/uploads/images/static-elements/dclogo_white_alpha-mqus5if2.png differ
diff --git a/content/block-templates/home.json b/content/block-templates/home.json
index ca493f9..9cd26ae 100644
--- a/content/block-templates/home.json
+++ b/content/block-templates/home.json
@@ -35,13 +35,6 @@
"bodyHtml": "Деплой в один клик, непрерывный пайплайн, мгновенный откат и быстрая доставка через 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;
Как и любой кастомный код, это добавляет только ту нагрузку, которую несёт сам код.
Все файлы собираются, минифицируются и сжимаются, чтобы минимально влиять на проект и не плодить внешние библиотеки и CDN-скрипты.
После сборки файлы загружаются в Cloudflare R2 и отдаются через CDN-ссылку на выделенном домене проекта, чтобы получить быстрый и совместимый с Webflow результат.
В панели деплоя есть мгновенный откат.
Нажмите откат, верните предыдущую рабочую версию, исправьте локально и опубликуйте заново.
Помимо @plan, @build и @explore стандартных режимов агентов мы готовим @webflow режим, специально заточенный под Webflow: структуру проекта, взаимодействие с ним и эффективную разработку.
Основано на многолетнем опыте написания кастомного кода для Webflow-анимаций.
WebGL, Three.js, GSAP и кастомная функциональность собраны в набор практик, пайплайнов и модульную систему, чтобы всё работало согласованно.
Также доступна библиотека компонентов: выберите компонент, добавьте в проект и попросите ИИ адаптировать его под задачу.
При запуске NODE.DC доступна отдельная вкладка для встраивания.
В зависимости от задачи можно получить скрипты для конкретной страницы или единый app.js для всего проекта.
Сгенерированная ссылка содержит и продакшен-версию, следующую за URL деплоя, и локальную версию для предпросмотра без влияния на посетителей сайта.
Мы используем основные доступные модели: OpenAI до Claude до Gemini.
Оркестратор выбирает модель под задачу автоматически, но вы можете вручную переключиться на нужную модель.
Во время работы NODE.DC выполняет две задачи параллельно.
Поднимает локальную среду разработки на Bun, синхронизирует JavaScript и TypeScript, включает HMR и держит webhook для автоматического обновления сайта при изменениях.
Одновременно работает оркестратор ИИ-агентов: обрабатывает запросы, меняет код, проверяет состояние сборки и при необходимости обновляет проект Webflow.
Процесс многоэтапный: сначала Bun собирает, сжимает, минифицирует и подготавливает проект вместе с библиотеками.
Затем файлы отправляются в CDN: cdn.node.dc/{USERNAME}/{PROJECT-NAME}. Ссылка уже содержит нужную структуру: вы видите локальную версию, а пользователи получают опубликованный скрипт.
Система изначально рассчитана на работу с Webflow MCP.
Подключите проект и авторизацию, чтобы ИИ-агенты получили доступ к Webflow-сборке. Подключение приложения в Webflow Designer даёт агентам доступ к контенту, элементам, стилям и CSS, а кастомный код получает полный контекст проекта.






































































