Remove embedded admin from site

This commit is contained in:
dcconstructions 2026-07-06 00:31:15 +03:00
parent bb7c54e9ca
commit 0e13de36cf
8 changed files with 5 additions and 10389 deletions

View File

@ -6,18 +6,17 @@ Static promo site for NODE.DC: an enterprise platform for processes, data, AI ag
- `content/pages/home.json` - structured content model for the homepage.
- `templates/pages/home/shell.html` - homepage shell and shared head/runtime includes.
- `templates/pages/home/blocks` - block templates used by the renderer and admin.
- `content/block-templates/home.json` - sanitized admin block presets.
- `templates/pages/home/blocks` - block templates used by the renderer.
- `content/block-templates/home.json` - sanitized block presets consumed by the external CMS.
- `assets/site` - local runtime CSS, JS, fonts, and base UI images.
- `assets/custom` - NODE.DC custom runtime and overrides.
- `assets/uploads` - product media managed by the site/admin flow.
- `admin` and `tools/admin-server.mjs` - local content admin.
- `assets/uploads` - product media managed by the external CMS flow.
## Commands
```bash
npm run render:home
npm run admin
npm run render:knowledge
```
For a static preview:

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,344 +0,0 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>NODE.DC Admin</title>
<link rel="stylesheet" href="./admin.css" />
</head>
<body>
<div class="admin-backdrop" aria-hidden="true"></div>
<header class="nodedc-expanded-toolbar-shell">
<div class="nodedc-expanded-toolbar">
<div class="nodedc-expanded-toolbar-top">
<div class="nodedc-expanded-toolbar-left">
<a href="/" class="nodedc-expanded-brand-link" target="_blank" aria-label="NODE.DC">
<img src="./nodedc-logo.svg" alt="NODE.DC" class="nodedc-expanded-brand-logo" />
</a>
</div>
<div class="nodedc-expanded-toolbar-center">
<span class="nodedc-expanded-workspace-button" aria-hidden="true">
<img src="../assets/uploads/images/Logo/dclogo_white_alpha-mqus5if2.png" alt="" class="nodedc-expanded-workspace-avatar" />
</span>
<nav class="nodedc-expanded-nav-group" aria-label="Навигация админки">
<button id="admin-mode-content" class="nodedc-expanded-nav-button" type="button" data-active="true">
<span>Администрирование</span>
</button>
<button id="admin-mode-seo" class="nodedc-expanded-nav-button" type="button" data-active="false">
<span>SEO</span>
</button>
<button id="admin-mode-knowledge" class="nodedc-expanded-nav-button" type="button" data-active="false">
<span>База знаний</span>
</button>
</nav>
</div>
<div class="nodedc-expanded-toolbar-right">
<div class="nodedc-expanded-user-group">
<span class="nodedc-toolbar-icon-button" aria-hidden="true"></span>
<span class="nodedc-expanded-profile-trigger">
<span class="nodedc-expanded-nav-button" data-active="false">
<span>Профиль</span>
</span>
<span class="nodedc-expanded-user-avatar-button" aria-hidden="true">
<span class="nodedc-expanded-user-avatar">DC</span>
</span>
</span>
</div>
</div>
</div>
</div>
</header>
<main class="admin-shell">
<aside class="sidebar">
<div class="sidebar-head">
<div>
<div class="section-kicker">NODE.DC</div>
<h1 id="sidebar-title">Администрирование</h1>
</div>
<button id="add-block" class="admin-panel-close add-block-button" type="button" aria-label="Добавить блок">+</button>
<div class="workspace-card admin-panel-client-select">
<div class="workspace-logo admin-panel-client-select__icon">DC</div>
<div>
<div class="workspace-name">NODE.DC</div>
<div id="workspace-role" class="workspace-role">Администратор сайта</div>
</div>
</div>
</div>
<div id="regions" class="regions"></div>
</aside>
<section class="editor">
<header class="editor-head">
<div>
<h1 id="editor-heading">Настройки сайта</h1>
<div id="selected-region" class="breadcrumb">NODE.DC / Выберите блок</div>
<h2 id="selected-title">Контентный слой</h2>
</div>
<div class="actions">
<span id="dirty-state" class="dirty-state" data-dirty="false">Синхронизировано</span>
<button id="reload" class="icon-btn" type="button" title="Перезагрузить данные"></button>
<button id="save" class="primary-btn" type="button" title="Записать текущую модель в content/pages/home.json">Сохранить модель</button>
<button id="render" class="ghost-btn" type="button" title="Сохранить модель и пересобрать публичный index.html">Обновить index.html</button>
</div>
</header>
<div id="empty-state" class="empty-state">
<div class="empty-icon">ND</div>
<div>
<h3>Выберите блок слева</h3>
<p>Статика, hero, форма и секции страницы разделены на рабочие группы. Сначала редактируем typed-поля, сырой JSON оставлен как технический fallback.</p>
</div>
</div>
<form id="block-form" class="block-form hidden">
<section class="settings-card block-meta-card">
<div class="card-head">
<div>
<div class="section-kicker">Идентификатор</div>
<h3>Служебные параметры</h3>
</div>
<label class="toggle-row">
<input id="block-enabled" name="enabled" type="checkbox" />
<span>Отображение</span>
</label>
</div>
<div class="field-grid">
<label class="field-control">
<span>ID блока</span>
<input id="block-id" name="id" type="text" autocomplete="off" />
</label>
<label class="field-control">
<span>Название в админке</span>
<input id="block-label" name="adminLabel" type="text" autocomplete="off" />
</label>
<label class="field-control">
<span>Шаблон / тип</span>
<input id="block-template" name="template" type="text" autocomplete="off" readonly />
</label>
<label class="field-control">
<span>Target</span>
<input id="block-anchor" name="target" type="text" autocomplete="off" list="block-target-options" />
<datalist id="block-target-options"></datalist>
</label>
</div>
</section>
<section class="settings-card structure-card">
<div class="card-head structure-head">
<div>
<div class="section-kicker">Порядок блока</div>
<h3>Операции с блоком</h3>
</div>
<div class="button-row icon-action-row">
<button id="move-up" class="icon-action-btn" type="button" title="Поднять блок" aria-label="Поднять блок">
<span aria-hidden="true"></span>
</button>
<button id="move-down" class="icon-action-btn" type="button" title="Опустить блок" aria-label="Опустить блок">
<span aria-hidden="true"></span>
</button>
<button id="duplicate" class="icon-action-btn" type="button" title="Дублировать блок" aria-label="Дублировать блок">
<span aria-hidden="true"></span>
</button>
<button id="copy" class="icon-action-btn operation-extra" type="button" title="Копировать блок" aria-label="Копировать блок">
<span aria-hidden="true"></span>
</button>
<button id="paste-after" class="icon-action-btn operation-extra" type="button" title="Вставить после" aria-label="Вставить после">
<span aria-hidden="true"></span>
</button>
<button id="delete-block" class="icon-action-btn danger-action-btn" type="button" title="Удалить блок" aria-label="Удалить блок">
<svg class="trash-can-icon" viewBox="0 0 24 24" aria-hidden="true" focusable="false">
<path d="M3.75 6.75h16.5" />
<path d="M8.25 6.75V4.9c0-.64.51-1.15 1.15-1.15h5.2c.64 0 1.15.51 1.15 1.15v1.85" />
<path d="M6.25 6.75l.7 12.15c.06.78.7 1.35 1.47 1.35h7.16c.77 0 1.41-.57 1.47-1.35l.7-12.15" />
<path d="M10 10.75v5.5" />
<path d="M14 10.75v5.5" />
</svg>
</button>
</div>
</div>
</section>
<section class="content-panel">
<div class="panel-head">
<div>
<div id="content-panel-kicker" class="section-kicker">Контент</div>
<h3 id="content-panel-title">Редактируемые поля</h3>
</div>
<span id="content-panel-note" class="panel-note">Поля сгруппированы по смысловым подблокам верстки.</span>
</div>
<div id="content-fields" class="content-fields"></div>
</section>
<details class="json-details">
<summary>JSON выбранного блока</summary>
<label class="json-field">
<span>Техническое представление</span>
<textarea id="block-json" spellcheck="false"></textarea>
</label>
</details>
</form>
<div id="knowledge-form" class="knowledge-editor hidden"></div>
<pre id="status" class="status"></pre>
</section>
</main>
<div id="template-modal" class="template-modal-layer hidden" role="dialog" aria-modal="true" aria-labelledby="template-modal-title">
<article class="template-modal">
<header class="template-modal-head">
<div>
<div class="section-kicker">Библиотека блоков</div>
<h2 id="template-modal-title">Добавить блок</h2>
<p>Выберите шаблон. Новый блок появится в конце соответствующего списка.</p>
</div>
<button id="template-modal-close" class="admin-panel-close modal-close-button" type="button" aria-label="Закрыть">×</button>
</header>
<div id="template-list" class="template-list"></div>
<footer class="template-modal-foot">
<button id="template-modal-cancel" class="ghost-btn" type="button">Отмена</button>
</footer>
</article>
</div>
<div id="delete-modal" class="template-modal-layer delete-modal-layer hidden" role="dialog" aria-modal="true" aria-labelledby="delete-modal-title" aria-describedby="delete-modal-body">
<article class="template-modal delete-modal">
<header class="template-modal-head delete-modal-head">
<div>
<div class="section-kicker">Удаление</div>
<h2 id="delete-modal-title">Подтвердите действие</h2>
<p id="delete-modal-body">Вы действительно подтвердить удаление элемента?</p>
</div>
</header>
<footer class="template-modal-foot delete-modal-foot">
<button id="delete-modal-cancel" class="ghost-btn" type="button">Отмена</button>
<button id="delete-modal-confirm" class="danger-btn delete-confirm-btn" type="button">Да</button>
</footer>
</article>
</div>
<div id="media-modal" class="template-modal-layer media-modal-layer hidden" role="dialog" aria-modal="true" aria-labelledby="media-modal-title">
<article class="template-modal media-modal">
<header class="template-modal-head media-modal-head">
<div>
<div class="section-kicker">Медиатека</div>
<h2 id="media-modal-title">Выбрать файл</h2>
<p id="media-modal-subtitle">Существующие файлы на сервере и загрузки для текущего поля.</p>
</div>
<div class="media-modal-actions">
<span id="media-site-size" class="media-site-size">Сайт: считаем...</span>
<button id="media-trash-toggle" class="admin-panel-close media-header-action media-trash-toggle" type="button" aria-label="Недавно удалённые" title="Недавно удалённые">
<svg viewBox="0 0 24 24" aria-hidden="true">
<path d="M3.75 6.75h16.5" />
<path d="M8.25 6.75V4.9c0-.64.51-1.15 1.15-1.15h5.2c.64 0 1.15.51 1.15 1.15v1.85" />
<path d="M6.25 6.75l.7 12.15c.06.78.7 1.35 1.47 1.35h7.16c.77 0 1.41-.57 1.47-1.35l.7-12.15" />
<path d="M10 10.75v5.5" />
<path d="M14 10.75v5.5" />
</svg>
</button>
<button id="media-modal-close" class="admin-panel-close modal-close-button media-header-action" type="button" aria-label="Закрыть">×</button>
</div>
</header>
<div class="media-toolbar">
<label class="media-search">
<span>Поиск</span>
<input id="media-search" type="search" autocomplete="off" placeholder="Имя, папка, путь" />
</label>
<div id="media-kind-filters" class="media-filter-row media-kind-row" aria-label="Тип файла"></div>
<div id="media-root-filters" class="media-filter-row media-root-row" aria-label="Корень файлов"></div>
<button id="media-upload" class="primary-btn media-upload-btn" type="button">+ Загрузить</button>
</div>
<div id="media-drop-zone" class="media-browser media-browser-columns">
<section class="media-main">
<div id="media-breadcrumbs" class="media-breadcrumbs"></div>
<div id="media-list" class="media-columns"></div>
<div id="media-empty" class="media-empty hidden">Папка пуста.</div>
</section>
<aside class="media-preview-panel">
<div id="media-preview" class="media-preview">
<span>FILE</span>
</div>
<div class="media-preview-copy">
<div id="media-preview-name" class="media-preview-name">Выберите файл</div>
<div id="media-preview-path" class="media-preview-path"></div>
<div id="media-preview-meta" class="media-preview-meta"></div>
</div>
<div id="media-preview-usage" class="media-usage-pill" data-status="idle">
<span class="media-usage-dot"></span>
<span>Нет выбора</span>
</div>
<div class="media-preview-actions">
<button id="media-select" class="primary-btn" type="button" disabled>Выбрать</button>
<button id="media-delete" class="danger-btn media-delete-btn" type="button" aria-label="Удалить файл" title="Удалить файл" disabled>
<svg viewBox="0 0 24 24" aria-hidden="true">
<path d="M3.75 6.75h16.5" />
<path d="M8.25 6.75V4.9c0-.64.51-1.15 1.15-1.15h5.2c.64 0 1.15.51 1.15 1.15v1.85" />
<path d="M6.25 6.75l.7 12.15c.06.78.7 1.35 1.47 1.35h7.16c.77 0 1.41-.57 1.47-1.35l.7-12.15" />
<path d="M10 10.75v5.5" />
<path d="M14 10.75v5.5" />
</svg>
</button>
</div>
</aside>
</div>
<footer class="template-modal-foot media-modal-foot">
<button id="media-refresh" class="ghost-btn" type="button">Обновить список</button>
<button id="media-modal-cancel" class="ghost-btn" type="button">Отмена</button>
</footer>
</article>
</div>
<div id="media-context-menu" class="media-context-menu hidden" role="menu"></div>
<div id="media-action-modal" class="template-modal-layer media-action-modal-layer hidden" role="dialog" aria-modal="true" aria-labelledby="media-action-title">
<article class="template-modal media-action-modal">
<header class="template-modal-head media-action-head">
<div>
<div class="section-kicker">Файл-менеджер</div>
<h2 id="media-action-title">Действие</h2>
<p id="media-action-body">Введите имя.</p>
</div>
</header>
<div class="media-action-body">
<label class="field-control">
<span id="media-action-label">Имя</span>
<input id="media-action-input" type="text" autocomplete="off" />
</label>
</div>
<footer class="template-modal-foot media-action-foot">
<button id="media-action-cancel" class="ghost-btn" type="button">Отмена</button>
<button id="media-action-confirm" class="primary-btn" type="button">Подтвердить</button>
</footer>
</article>
</div>
<div id="knowledge-button-modal" class="template-modal-layer knowledge-button-modal-layer hidden" role="dialog" aria-modal="true" aria-labelledby="knowledge-button-title">
<article class="template-modal knowledge-button-modal">
<header class="template-modal-head knowledge-button-head">
<div>
<div class="section-kicker">База знаний</div>
<h2 id="knowledge-button-title">Кнопка в статье</h2>
<p>Ссылка ведёт на лендинг или внешний адрес. Target открывает нужный блок лендинга.</p>
</div>
<button id="knowledge-button-close" class="admin-panel-close modal-close-button" type="button" aria-label="Закрыть">×</button>
</header>
<div class="knowledge-button-body">
<label class="field-control">
<span>Название</span>
<input id="knowledge-button-name" type="text" autocomplete="off" placeholder="Посмотреть демо" />
</label>
<label class="field-control">
<span>Ссылка</span>
<input id="knowledge-button-link" type="text" autocomplete="off" placeholder="/" />
</label>
<label class="field-control">
<span>Target / блок лендинга</span>
<input id="knowledge-button-target" type="text" autocomplete="off" list="knowledge-button-target-options" placeholder="hub-video" />
<datalist id="knowledge-button-target-options"></datalist>
</label>
<p class="knowledge-button-hint">Можно выбрать target из списка или ввести ID блока лендинга. Если target пустой, ссылка откроет первый экран.</p>
<p id="knowledge-button-error" class="knowledge-button-error" aria-live="polite"></p>
</div>
<footer class="template-modal-foot knowledge-button-foot">
<button id="knowledge-button-cancel" class="ghost-btn" type="button">Отмена</button>
<button id="knowledge-button-confirm" class="primary-btn" type="button">Добавить кнопку</button>
</footer>
</article>
</div>
<script src="./admin.js" type="module"></script>
</body>
</html>

View File

@ -1 +0,0 @@
<svg id="nodedc-logo" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 220.82 54.55"><defs><style>.cls-1{fill:#e2e1e1;}.cls-2{fill:#dbdbdb;stroke:#dbdbdb;stroke-miterlimit:10;stroke-width:0.75px;}</style></defs><path class="cls-1" d="M52.8,23.61,46.92,33.76,41.05,23.61H52.8m18-10.39H23.06L46.92,54.55Z"/><polygon class="cls-1" points="31.28 33.13 18.11 10.34 75.73 10.34 62.59 33.13 74.28 33.13 93.22 0 0 0 19.61 33.13 31.28 33.13"/><path class="cls-2" d="M116.35,18.49V1h1.27l10.34,15V1h1.33V18.49H128l-10.34-15v15Z"/><path class="cls-2" d="M140.43,18.64c-4.79,0-8.16-3.72-8.16-8.89S135.64.86,140.43.86s8.17,3.72,8.17,8.89S145.25,18.64,140.43,18.64Zm0-1.25c4,0,6.79-3.17,6.79-7.64s-2.77-7.64-6.79-7.64-6.77,3.17-6.77,7.64S136.44,17.39,140.43,17.39Z"/><path class="cls-2" d="M151.6,18.49V1h5.1c5.54,0,8.79,3.42,8.79,8.74s-3.25,8.74-8.79,8.74ZM153,17.24h3.75c4.77,0,7.42-2.92,7.42-7.49s-2.65-7.49-7.42-7.49H153Z"/><path class="cls-2" d="M168.49,1h10.77V2.26h-9.42V8.93h7.89v1.25h-7.89v7.06h9.74v1.25H168.49Z"/><path class="cls-2" d="M188.88,18.49V1H194c5.54,0,8.79,3.42,8.79,8.74s-3.25,8.74-8.79,8.74Zm1.35-1.25H194c4.77,0,7.41-2.92,7.41-7.49S198.75,2.26,194,2.26h-3.75Z"/><path class="cls-2" d="M205.15,9.75c0-5.24,3.19-8.89,8.11-8.89a6.8,6.8,0,0,1,7.1,5.52h-1.43a5.54,5.54,0,0,0-5.74-4.27c-4.05,0-6.64,3.17-6.64,7.64s2.54,7.64,6.59,7.64a5.46,5.46,0,0,0,5.74-4.29h1.43c-.75,3.52-3.4,5.54-7.15,5.54C208.27,18.64,205.15,15.05,205.15,9.75Z"/></svg>

Before

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -1,5 +0,0 @@
# NODE.DC Admin Notes
The current admin flow edits the structured homepage model and renders `index.html` with `npm run render:home`.
Sanitary rule: admin presets and generated public pages must not contain legacy product names, old external documentation links, or old API origins. Any new SEO/content fields should use the NODE.DC ontology only.

View File

@ -6,7 +6,6 @@
"scripts": {
"extract:home": "node tools/extract-home-blocks.mjs",
"render:home": "node tools/render-home.mjs",
"render:knowledge": "node tools/render-knowledge.mjs",
"admin": "node tools/admin-server.mjs"
"render:knowledge": "node tools/render-knowledge.mjs"
}
}

File diff suppressed because it is too large Load Diff