From c354c83a5a737ac814af9136018f4811f53b6dfb Mon Sep 17 00:00:00 2001 From: Rim Zabarov Date: Thu, 5 Nov 2026 13:35:22 +0300 Subject: [PATCH 1/3] Pages use the renamed Smart tags; sf-confirm and sf-editor get their pages Reapplied over ui-e22fefb3c1f8 (#15): / become the R3 names across pages and examples; quoted and backticked names only in smart/, pro/, guide/smart-components, en/ and examples/. CSS classes and examples/home are unchanged. New pages smart/actions/confirm.md and pro/editor/editor.md, with their reference mapping; references regenerated against the bind 6534a3eb. Co-Authored-By: Claude Opus 5.5 --- config/catalog-groups.json | 4 +- config/reference-pages.json | 4 + config/smart-reference.json | 9 +- config/smart-reference.ru.json | 29 ++- .../ru/components/navigation/context-menu.md | 4 +- .../ru/components/overlays-media/tooltip.md | 2 +- content/ru/guide/connection/loader.md | 4 +- content/ru/guide/introduction/levels.md | 4 +- .../ru/guide/layouts/editor/inline-text.md | 2 +- content/ru/guide/layouts/editor/overview.md | 6 +- content/ru/guide/layouts/editor/panels.md | 2 +- content/ru/guide/size-and-type/language.md | 2 +- .../ru/guide/smart-components/assemblies.md | 4 +- .../ru/guide/smart-components/comparison.md | 8 +- content/ru/guide/smart-components/data.md | 8 +- .../guide/smart-components/field-renderers.md | 8 +- .../ru/guide/smart-components/first-paint.md | 22 +- content/ru/guide/smart-components/folder.md | 2 +- content/ru/guide/smart-components/forms.md | 2 +- content/ru/guide/smart-components/language.md | 6 +- content/ru/guide/smart-components/names.md | 12 +- content/ru/guide/smart-components/page.md | 2 +- .../smart-components/view-preferences.md | 4 +- content/ru/pro/admin/change-confirm.md | 77 +------ content/ru/pro/admin/property-view.md | 4 +- content/ru/pro/admin/table.md | 82 +++---- content/ru/pro/chat/chat-window.md | 2 +- content/ru/pro/chat/thread-list.md | 4 +- content/ru/pro/editor/blocks.md | 2 +- content/ru/pro/editor/content-editor.md | 6 +- content/ru/pro/editor/editor.md | 214 ++++++++++++++++++ content/ru/pro/editor/editor.page.json | 6 + content/ru/pro/editor/index.md | 3 +- content/ru/pro/index.md | 1 + content/ru/pro/mail/mail-canvas.md | 10 +- content/ru/pro/mail/mail-inspector.md | 4 +- content/ru/pro/mail/mail-letters.md | 2 +- content/ru/smart/actions/close.md | 10 +- content/ru/smart/actions/confirm.md | 134 +++++++++++ content/ru/smart/actions/confirm.page.json | 6 + content/ru/smart/actions/copy-button.md | 6 +- content/ru/smart/actions/download-file.md | 6 +- content/ru/smart/actions/icon-buttons.md | 10 +- content/ru/smart/actions/index.md | 3 +- content/ru/smart/composite/page-header.md | 16 +- content/ru/smart/composite/search.md | 2 +- content/ru/smart/composite/site-header.md | 8 +- content/ru/smart/content/avatars.md | 8 +- content/ru/smart/content/gallery.md | 2 +- .../ru/smart/editor/composition-overlay.md | 10 +- content/ru/smart/editor/inline-editor.md | 10 +- content/ru/smart/forms/code-input.md | 6 +- content/ru/smart/forms/color.md | 4 +- content/ru/smart/forms/country-code.md | 10 +- content/ru/smart/forms/datepicker.md | 8 +- content/ru/smart/forms/image-field.md | 4 +- content/ru/smart/forms/lookup.md | 4 +- content/ru/smart/forms/quantity.md | 6 +- content/ru/smart/forms/range-slider.md | 12 +- content/ru/smart/forms/rich-text.md | 6 +- content/ru/smart/forms/textarea.md | 12 +- content/ru/smart/forms/theme-generator.md | 2 +- content/ru/smart/index.md | 1 + content/ru/smart/navigation/context-menu.md | 16 +- .../country-code/smart-countries/index.html | 4 +- .../smart-customization/index.html | 4 +- .../country-code/smart-form/index.html | 2 +- .../country-code/smart-modes/index.html | 4 +- .../country-code/smart-sizes/index.html | 6 +- .../components/inputs/with-actions/index.html | 2 +- examples/guide/page-editor/index.html | 4 +- examples/guide/page-editor/index.js | 2 +- .../avatars/overview/index.html | 4 +- .../buttons/loading/index.html | 10 +- .../change-confirm/no-values/index.html | 2 +- .../change-confirm/overview/index.html | 4 +- .../change-confirm/overview/index.js | 2 +- .../change-confirm/state-outcome/index.html | 6 +- .../change-confirm/state-pending/index.html | 4 +- .../close/overview/index.html | 4 +- .../smart-components/close/sizes/index.html | 12 +- .../code-input/appearance/index.html | 4 +- .../code-input/length/index.html | 6 +- .../code-input/mask/index.html | 2 +- .../code-input/mode/index.html | 4 +- .../code-input/overview/index.html | 2 +- .../code-input/sizes/index.html | 6 +- .../code-input/state-disabled/index.html | 2 +- .../code-input/state-error/index.html | 2 +- .../code-input/state-readonly/index.html | 2 +- .../color/appearance/index.html | 6 +- .../color/overview/index.html | 8 +- .../smart-components/color/overview/index.js | 2 +- .../smart-components/color/sizes/index.html | 6 +- .../color/state-disabled/index.html | 2 +- .../color/state-inherited/index.html | 4 +- .../color/swatches/index.html | 4 +- .../smart-components/color/theme/index.html | 2 +- .../composition-overlay/overview/index.html | 2 +- .../composition-overlay/overview/index.js | 2 +- .../smart-components/confirm/card/index.html | 3 + .../confirm/overview/index.html | 1 + .../confirm/states/index.html | 5 + .../content-editor/empty/index.html | 2 +- .../content-editor/overview/index.html | 2 +- .../content-editor/short/index.html | 2 +- .../context-menu/overview/index.html | 4 +- .../context-menu/panel/index.html | 4 +- .../context-menu/panel/index.js | 2 +- .../context-menu/profile/index.html | 2 +- .../context-menu/profile/index.js | 2 +- .../context-menu/settings/index.html | 2 +- .../context-menu/sizes/index.html | 4 +- .../context-menu/standard/index.html | 2 +- .../context-menu/standard/index.js | 2 +- .../context-menu/state-checked/index.html | 2 +- .../context-menu/state-disabled/index.html | 2 +- .../copy-button/appearance/index.html | 8 +- .../copy-button/icons/index.html | 8 +- .../copy-button/overview/index.html | 6 +- .../copy-button/sizes/index.html | 8 +- .../country-code/masks/index.html | 6 +- .../country-code/overview/index.html | 4 +- .../country-code/state-disabled/index.html | 2 +- .../country-code/state-open/index.html | 2 +- .../datepicker/context/index.html | 4 +- .../datepicker/inline/index.html | 2 +- .../datepicker/invalid/index.html | 4 +- .../datepicker/overview/index.html | 4 +- .../datepicker/overview/index.js | 2 +- .../datepicker/presets/index.html | 4 +- .../datepicker/range/index.html | 4 +- .../datepicker/sizes/index.html | 6 +- .../datepicker/state-disabled/index.html | 2 +- .../datepicker/state-readonly/index.html | 2 +- .../download-file/icons/index.html | 6 +- .../download-file/overview/index.html | 6 +- .../download-file/sizes/index.html | 10 +- .../download-file/state-disabled/index.html | 2 +- .../icon-buttons/appearance/index.html | 12 +- .../icon-buttons/badge/index.html | 16 +- .../icon-buttons/content/index.html | 6 +- .../icon-buttons/loading/index.html | 20 +- .../icon-buttons/overview/index.html | 10 +- .../icon-buttons/radius/index.html | 6 +- .../icon-buttons/scheme/index.html | 10 +- .../icon-buttons/segments/index.html | 6 +- .../icon-buttons/sizes/index.html | 10 +- .../icon-buttons/spacing/index.html | 8 +- .../icon-buttons/state-disabled/index.html | 6 +- .../image-field/empty/index.html | 2 +- .../image-field/overview/index.html | 2 +- .../image-field/sizes/index.html | 6 +- .../image-field/state-disabled/index.html | 2 +- .../image-field/state-error/index.html | 2 +- .../image-field/state-readonly/index.html | 2 +- .../inline-editor/overview/index.html | 2 +- .../inline-editor/overview/index.js | 4 +- .../lookup/appearance/index.html | 8 +- .../lookup/overview/index.html | 4 +- .../smart-components/lookup/single/index.html | 4 +- .../smart-components/lookup/sizes/index.html | 12 +- .../lookup/state-disabled/index.html | 4 +- .../lookup/state-error/index.html | 4 +- .../lookup/state-readonly/index.html | 4 +- .../page-header/install/index.html | 4 +- .../page-header/overview/index.html | 4 +- .../page-header/state-star/index.html | 4 +- .../property-view/overview/index.html | 4 +- .../property-view/overview/index.js | 2 +- .../quantity/bounds/index.html | 4 +- .../quantity/decimals/index.html | 4 +- .../quantity/inherited/index.html | 2 +- .../quantity/overview/index.html | 2 +- .../quantity/sizes/index.html | 6 +- .../quantity/state-bound/index.html | 4 +- .../quantity/state-disabled/index.html | 2 +- .../quantity/state-error/index.html | 2 +- .../quantity/state-readonly/index.html | 2 +- .../range-slider/connect/index.html | 6 +- .../range-slider/handles/index.html | 4 +- .../range-slider/label-position/index.html | 4 +- .../range-slider/labels/index.html | 6 +- .../range-slider/overview/index.html | 2 +- .../range-slider/range/index.html | 4 +- .../range-slider/range/index.js | 2 +- .../range-slider/state-disabled/index.html | 2 +- .../range-slider/step/index.html | 6 +- .../rich-text/appearance/index.html | 4 +- .../rich-text/cleaning/index.html | 4 +- .../rich-text/overview/index.html | 4 +- .../rich-text/rows/index.html | 4 +- .../rich-text/sizes/index.html | 6 +- .../rich-text/state-disabled/index.html | 4 +- .../rich-text/state-error/index.html | 4 +- .../rich-text/state-readonly/index.html | 4 +- .../smart-components/search/icon/index.html | 2 +- .../site-header/center/index.html | 4 +- .../site-header/collapse/index.html | 4 +- .../site-header/compact/index.html | 6 +- .../site-header/overview/index.html | 4 +- .../spinner/page-look/index.html | 2 +- .../table/application/index.html | 6 +- .../table/application/index.js | 4 +- .../smart-components/table/list/index.html | 4 +- examples/smart-components/table/list/index.js | 2 +- .../table/overview/index.html | 4 +- .../smart-components/table/overview/index.js | 2 +- .../textarea/appearance/index.html | 4 +- .../textarea/auto-grow/index.html | 8 +- .../textarea/flush/index.html | 6 +- .../textarea/overview/index.html | 4 +- .../smart-components/textarea/rows/index.html | 4 +- .../textarea/sizes/index.html | 6 +- .../textarea/state-disabled/index.html | 2 +- .../textarea/state-error/index.html | 4 +- .../textarea/state-readonly/index.html | 2 +- .../thread-list/overview/index.html | 2 +- .../thread-list/overview/index.js | 2 +- .../thread-list/state-empty/index.html | 2 +- .../thread-list/state-empty/index.js | 2 +- .../thread-list/state-loading/index.html | 2 +- .../thread-list/state-loading/index.js | 2 +- .../thread-list/ungrouped/index.html | 2 +- .../thread-list/ungrouped/index.js | 2 +- 225 files changed, 955 insertions(+), 611 deletions(-) create mode 100644 content/ru/pro/editor/editor.md create mode 100644 content/ru/pro/editor/editor.page.json create mode 100644 content/ru/smart/actions/confirm.md create mode 100644 content/ru/smart/actions/confirm.page.json create mode 100644 examples/smart-components/confirm/card/index.html create mode 100644 examples/smart-components/confirm/overview/index.html create mode 100644 examples/smart-components/confirm/states/index.html diff --git a/config/catalog-groups.json b/config/catalog-groups.json index 7401a319a..f0db037ce 100644 --- a/config/catalog-groups.json +++ b/config/catalog-groups.json @@ -116,7 +116,8 @@ "segmented", "close", "download-file", - "copy-button" + "copy-button", + "confirm" ] }, "forms": { @@ -249,6 +250,7 @@ "editor": { "title": "Редактор страниц", "items": [ + "editor", "content-editor", "blocks" ] diff --git a/config/reference-pages.json b/config/reference-pages.json index 7736f16d9..7e2e8c12b 100644 --- a/config/reference-pages.json +++ b/config/reference-pages.json @@ -1935,6 +1935,10 @@ "kind": "smart", "standard": 3 }, + "smart/actions/confirm.md": { + "kind": "smart", + "standard": 3 + }, "pro/admin/change-confirm.md": { "kind": "smart", "standard": 2 diff --git a/config/smart-reference.json b/config/smart-reference.json index 3f743c6bc..f247e82c8 100644 --- a/config/smart-reference.json +++ b/config/smart-reference.json @@ -7,7 +7,7 @@ "button-copy": "smart/actions/copy-button.md", "button-icon": "smart/actions/icon-buttons.md", "chat-threads": "pro/chat/thread-list.md", - "confirm": "pro/admin/change-confirm.md", + "confirm": "smart/actions/confirm.md", "confirm-change": "pro/admin/change-confirm.md", "editor-content": "pro/editor/content-editor.md", "editor-inline": "smart/editor/inline-editor.md", @@ -28,11 +28,10 @@ "slider-range": "smart/forms/range-slider.md", "view": "pro/admin/table.md", "view-properties": "pro/admin/property-view.md", - "view-table": "pro/admin/table.md" - }, - "skip": { - "editor": "sf-editor (the block editor, simai/ui-pro components/src/smart/editor) has no page yet; its page comes with the editor documentation, not with a repin." + "view-table": "pro/admin/table.md", + "editor": "pro/editor/editor.md" }, + "skip": {}, "suppress": { "popover": { "sections": [ diff --git a/config/smart-reference.ru.json b/config/smart-reference.ru.json index 83714d410..7976c20e7 100644 --- a/config/smart-reference.ru.json +++ b/config/smart-reference.ru.json @@ -2414,6 +2414,33 @@ "The question, said in place: what will happen, as a sentence («Удалить файл «Отчёт.pdf»?»). It names the group; without one the group is named «Подтверждение».": "Вопрос, сказанный на месте: что произойдёт, одним предложением («Удалить файл «Отчёт.pdf»?»). Он же называет группу; без него группа называется «Подтверждение».", "The runtime loader: loads what a page uses, components and utilities, on demand, and the theme. ensure(tags, {timeout}) asks for elements and settles with {ready, missing}, never rejecting; watch(root) marks a box an element renders into as a portal the Loader reads as the page (unwatch unmarks it). Once a theme is set (setTheme, changeTheme), SF.Loader.theme and SF.Loader.themePreference read it.": "Загрузчик: по требованию загружает то, что использует страница, — компоненты и утилиты — и тему. `ensure(tags, {timeout})` запрашивает элементы и завершается значением `{ready, missing}`, никогда не отклоняясь; `watch(root)` отмечает блок, в который элемент рисует содержимое, как портал, который Loader читает как страницу (`unwatch` снимает отметку). Когда тема задана (`setTheme`, `changeTheme`), её читают `SF.Loader.theme` и `SF.Loader.themePreference`.", "Whether this toggle button is on: aria-pressed on the native button and the selected look (the class sheet's active state); pressed=\"false\" says off; absent, the button is not a toggle and nothing is said": "Включена ли эта кнопка-переключатель: `aria-pressed` на нативной кнопке и вид выбранной (активное состояние таблицы стилей классов); `pressed=\"false\"` сообщает «выключено»; без атрибута кнопка не переключатель и ничего не сообщает", - "inline: the question and its answers in the flow of a row, no frame of their own. card: in a framed card with its own inset.": "inline: вопрос и ответы в потоке строки, без своей рамки. card: в карточке с рамкой и собственным отступом." + "inline: the question and its answers in the flow of a row, no frame of their own. card: in a framed card with its own inset.": "inline: вопрос и ответы в потоке строки, без своей рамки. card: в карточке с рамкой и собственным отступом.", + "A short line under the name: where the page lives or its state (the host's words).": "Короткая строка под названием: где живёт страница или её состояние (слова хоста).", + "A site block was saved: {manifest, words, changes}. Keep the manifest in site-blocks.": "Сохранён блок сайта: {manifest, words, changes}. Сохраните манифест в site-blocks.", + "Add a block of a type (and variant) after a block, or where it first fits; the value is the new block's id.": "Добавляет блок типа (и варианта) после блока или туда, где он первым подходит; значение — id нового блока.", + "Choose a block as a press does; with no id the choice is let go.": "Выбирает блок так же, как нажатие; без id выбор снимается.", + "Composition editor manifests of the host's types, or ones that replace the Framework's: the parameter panel is built from them.": "Манифесты редактора композиции для типов хоста или заменяющие манифесты SIMAI Framework: по ним строится панель параметров.", + "One step back, as ⌘Z: typing and structure are one history.": "Шаг назад, как ⌘Z: набор текста и структура — одна история.", + "One step forward, as ⇧⌘Z.": "Шаг вперёд, как ⇧⌘Z.", + "Open the block builder: a new site block, one made from a block, or a site block to change everywhere.": "Открывает конструктор блоков: новый блок сайта, блок из выбранного блока или блок сайта, который нужно изменить везде.", + "Put the caret at the end of a text block.": "Ставит курсор в конец текстового блока.", + "Set a parameter of a block, for a screen when it differs by screen.": "Задаёт параметр блока, для экрана — если значение различается по экранам.", + "Start (or end, on false) editing the site template: the header and footer of every page.": "Начинает (или, при false, заканчивает) правку шаблона сайта: шапки и подвала всех страниц.", + "The accessible name of the page.": "Доступное имя страницы.", + "The host's own block types beside the Framework's; their renderers come in renderers.": "Свои типы блоков хоста рядом с типами SIMAI Framework; их отрисовщики приходят в renderers.", + "The name of the page being edited, shown at the start of the top bar (the host's page name).": "Название редактируемой страницы в начале верхней строки (имя страницы у хоста).", + "The one block editor of the SIMAI page: layout and text in one Composition Document, edited by depth. A click on text types, a click beside it chooses the block, Esc goes up and Enter down. One catalogue (Text and Blocks, groups, variants with pictures, search, favourites, recent) serves the + between blocks, / in text and the library; blocks move by the grip with drop lines or Alt+arrows, and a drop beside a block splits it into columns. The parameter panel says where every value comes from (type, theme, variant, block, screen) and sets values per screen; the Data tab binds a block to a host source through the source port. The block builder makes and changes site blocks everywhere; the site template is a separate, explicit edit. Rights and theme come from the host. One undo history; output as JSON, HTML and Markdown.": "Единый редактор блоков страницы SIMAI: раскладка и текст в одном Composition Document, правка по глубине. Щелчок по тексту — печать, щелчок рядом — выбор блока, Esc — вверх, Enter — вниз. Один каталог («Текст» и «Блоки», группы, варианты с картинками, поиск, избранное, недавние) служит «+» между блоками, «/» в тексте и библиотеке; блоки двигаются за ручку с линиями места или Alt+стрелками, а сброс рядом с блоком делит место на колонки. Панель параметров говорит, откуда каждое значение (тип, тема, вариант, блок, экран), и задаёт значения по экранам; вкладка «Данные» связывает блок с источником хоста через порт источников. Конструктор блоков создаёт и меняет блоки сайта везде; шаблон сайта — отдельная явная правка. Права и тема приходят от хоста. Одна история отмены; результат — JSON, HTML и Markdown.", + "The page as JSON, HTML (utility classes) or Markdown of its text areas; the value is the text.": "Страница как JSON, HTML (классы утилит) или Markdown её текстовых областей; значение — текст.", + "The page changed: {document, reason, scope}. The host saves the document; scope template means the header or footer of every page.": "Страница изменилась: {document, reason, scope}. Хост сохраняет документ; scope template означает шапку или подвал всех страниц.", + "The page is one tab stop; Enter and Esc move by depth, the arrows by siblings; the panels are Framework controls in tab order; changes are said in a status line.": "Страница — одна остановка Tab; Enter и Esc двигают по глубине, стрелки — по соседям; панели — элементы управления SIMAI Framework в порядке Tab; изменения сообщаются в строке состояния.", + "The page: a Composition Document of the profile ui-layout (layout.page, or layout.regions with a banner, main and contentinfo region for a page with a site template). A new one starts editing it; the one the editor sent in change is recognised and kept.": "Страница: Composition Document профиля ui-layout (layout.page или layout.regions с областями banner, main и contentinfo для страницы с шаблоном сайта). Новый документ начинает новую правку; документ, который редактор сам отправил в change, узнаётся и сохраняется.", + "The renderers of the host's types: the page is drawn by them as the site draws it.": "Отрисовщики типов хоста: страница рисуется ими так, как её рисует сайт.", + "The screen the page is drawn and its values are set for: desktop (lg), tablet (md), phone (xs).": "Экран, для которого рисуется страница и задаются значения: desktop (lg), tablet (md), phone (xs).", + "The site's own blocks made in the block builder; the newest version of each is offered in the catalogue.": "Собственные блоки сайта из конструктора блоков; в каталоге предлагается новейшая версия каждого.", + "The site's theme: its defaults are a level of where a value comes from, its attributes are put on the drawn page. The editor never changes it; settings_url links to where it is changed.": "Тема сайта: её значения по умолчанию — один из уровней происхождения значения, её атрибуты ставятся на нарисованную страницу. Редактор её никогда не меняет; settings_url ведёт туда, где её меняют.", + "The words of the host's blocks, by locale.": "Слова блоков хоста по локалям.", + "This block is chosen: {ids}; empty when none is.": "Выбран блок: {ids}; пусто, если не выбран ни один.", + "What the person may change, from the host: layout false lets the author write only inside text areas; template false keeps the site template closed; builder false hides the block builder. There is no role switch in the editor.": "Что человеку можно менять, по данным хоста: layout false позволяет автору писать только внутри текстовых областей; template false держит шаблон сайта закрытым; builder false скрывает конструктор блоков. Переключателя ролей в редакторе нет.", + "Where favourites and recent blocks are kept through SF.Preferences (sf-editor/); empty keeps them for the session only.": "Где хранятся избранные и недавние блоки через SF.Preferences (sf-editor/); пусто — только на время сеанса." } } diff --git a/content/ru/components/navigation/context-menu.md b/content/ru/components/navigation/context-menu.md index 8511b294c..a86cd92e8 100644 --- a/content/ru/components/navigation/context-menu.md +++ b/content/ru/components/navigation/context-menu.md @@ -32,7 +32,7 @@ profile: reference Обычно берут вид `sf-button--link` со схемой `sf-button--on-surface`. - Компонент — только оформление. Открыть меню у объекта, поставить его рядом, закрыть по Escape и вернуть фокус — задача вызывающего кода или - смарт-компонента ``. + смарт-компонента ``. ## Варианты @@ -50,7 +50,7 @@ profile: reference - Статическая разметка `sf-context-menu` не задаёт ролей. Не ставьте ей `role="menu"`, если не реализуете клавиатурную модель меню целиком. -- Для плоского списка действий берите смарт-компонент `` с +- Для плоского списка действий берите смарт-компонент `` с `aria-label`: он даёт прямым кнопкам и ссылкам роль `menuitem`, оставляет в порядке Tab один пункт и переводит фокус клавишами со стрелками вверх и вниз, Home и End. diff --git a/content/ru/components/overlays-media/tooltip.md b/content/ru/components/overlays-media/tooltip.md index bddfe175f..6939a0bf4 100644 --- a/content/ru/components/overlays-media/tooltip.md +++ b/content/ru/components/overlays-media/tooltip.md @@ -27,7 +27,7 @@ profile: reference `sf-tooltip-supporting-text`, затем хвост `sf-tooltip-tail`. - Триггер — нативный фокусируемый элемент: кнопка, ссылка, поле. На теге - смарт-компонента, например ``, описание достаётся самому + смарт-компонента, например ``, описание достаётся самому тегу, а не кнопке внутри него; для подсказки берите классовую кнопку `sf-icon-button`. Атрибут `data-tooltip` на нём хранит `id` поверхности; пустой `data-tooltip` берёт diff --git a/content/ru/guide/connection/loader.md b/content/ru/guide/connection/loader.md index 49032673e..bd576595c 100644 --- a/content/ru/guide/connection/loader.md +++ b/content/ru/guide/connection/loader.md @@ -69,7 +69,7 @@ SF.RuleLoader['cl-datepicker'] = { Имя правила смарт-компонента начинается с `cl-`, папка в поставке — без него: `cl-datepicker` → `smart/datepicker/`. Это внутреннее имя: в разметке и коде -проекта используется только тег ``. +проекта используется только тег ``. Полный список правил выпуска — `distr/rule/rule.json`: имя, теги, вид и связи каждого правила. Ядро несёт те же правила в `distr/core/js/core-rules.js`. @@ -105,7 +105,7 @@ SF.RuleLoader['cl-datepicker'] = { ## Зависимости Поле `relation` перечисляет модули, без которых компонент не работает. Для -`` это обычный компонент календаря, смарт-поле ввода, кнопки, +`` это обычный компонент календаря, смарт-поле ввода, кнопки, кнопки-иконки и иконки. Loader загружает зависимости до самого компонента и ждёт их готовности. Поэтому автор страницы пишет один тег, а не пять. diff --git a/content/ru/guide/introduction/levels.md b/content/ru/guide/introduction/levels.md index 4b2431288..3b4162f08 100644 --- a/content/ru/guide/introduction/levels.md +++ b/content/ru/guide/introduction/levels.md @@ -18,7 +18,7 @@ Framework устроен как лестница уровней. Каждый с | Утилиты | Одно свойство элемента в одном классе | `p-4`, `gap-2`, `bg-surface-container` | Раскладка и точечное оформление | | Компоненты | Готовая структура и оформление повторяемого элемента | `.sf-button` | Элемент без собственного поведения | | Смарт-компоненты | Собственный тег с поведением, состоянием и событиями | ``, `` | Нужны ввод, состояние, события, данные | -| Составные смарт-компоненты | Несколько смарт-компонентов с общей логикой | ``; таблица данных с поиском и фильтрами | Повторяется целый сценарий | +| Составные смарт-компоненты | Несколько смарт-компонентов с общей логикой | ``; таблица данных с поиском и фильтрами | Повторяется целый сценарий | | Макеты | Страница целиком как проверяемые данные | JSON-документ страницы | Структурой страницы нужно управлять | ### Дизайн-токены и Core @@ -140,7 +140,7 @@ Framework устроен как лестница уровней. Каждый с их работу в одной пользовательской задаче. Таблица данных со строкой поиска, фильтрами, сортировкой и постраничным выводом — один такой компонент, а не четыре отдельных, которые проект связывает вручную. Выбор даты -(``) — тоже составной компонент: поле, кнопки и календарь в нём +(``) — тоже составной компонент: поле, кнопки и календарь в нём работают как одно целое. Составной выбор товара может связать варианты, цену, доступность и кнопку diff --git a/content/ru/guide/layouts/editor/inline-text.md b/content/ru/guide/layouts/editor/inline-text.md index 0e4330af3..6a0bfa566 100644 --- a/content/ru/guide/layouts/editor/inline-text.md +++ b/content/ru/guide/layouts/editor/inline-text.md @@ -23,7 +23,7 @@ document.addEventListener('sf-inline-editor-change', (event) => { Правила подключения: -- на странице редактора обязательно должен стоять ``: по +- на странице редактора обязательно должен стоять ``: по этому тегу Loader подключает код правки; - до загрузки `startInlineEdit` выбрасывает ошибку `inline_editor_not_loaded`. diff --git a/content/ru/guide/layouts/editor/overview.md b/content/ru/guide/layouts/editor/overview.md index d3e5af403..0f0c3a63d 100644 --- a/content/ru/guide/layouts/editor/overview.md +++ b/content/ru/guide/layouts/editor/overview.md @@ -27,8 +27,8 @@ HTML**. Страница описана Document. Редактор показы человек видит понятное сообщение. Редактор собирается из смарт-компонентов: оверлея холста -`` ([справочник](/ru/smart/editor/composition-overlay/)), перетаскивания `` -([справочник](/ru/smart/editor/sortable/)), редактора текста `` ([справочник](/ru/smart/editor/inline-editor/)) и закреплённых +`` ([справочник](/ru/smart/editor/composition-overlay/)), перетаскивания `` +([справочник](/ru/smart/editor/sortable/)), редактора текста `` ([справочник](/ru/smart/editor/inline-editor/)) и закреплённых панелей `` ([справочник](/ru/smart/overlays/drawer/)). Их код загружается только на странице редактора, поэтому обычные страницы сайта не получают лишний JavaScript, а опубликованный HTML одинаков с открытым и @@ -41,7 +41,7 @@ HTML**. Страница описана Document. Редактор показы ## Холст и оверлей -`` рисует поверх отрисованного документа +`` рисует поверх отрисованного документа рамки наведения и выбора, панель действий над выбранным блоком и одно место вставки — у стыка блоков под указателем. Блок переносят за ручку на панели или с клавиатуры, а после изменения Document блоки плавно встают на новые diff --git a/content/ru/guide/layouts/editor/panels.md b/content/ru/guide/layouts/editor/panels.md index dca2226ab..f4e53c9ab 100644 --- a/content/ru/guide/layouts/editor/panels.md +++ b/content/ru/guide/layouts/editor/panels.md @@ -18,7 +18,7 @@ description: "Библиотеку блоков и свойства выбран ```html
- +
diff --git a/content/ru/guide/size-and-type/language.md b/content/ru/guide/size-and-type/language.md index 27230b962..348d61838 100644 --- a/content/ru/guide/size-and-type/language.md +++ b/content/ru/guide/size-and-type/language.md @@ -35,7 +35,7 @@ description: "Компоненты Framework сами подставляют ч ```html
- +
``` diff --git a/content/ru/guide/smart-components/assemblies.md b/content/ru/guide/smart-components/assemblies.md index ddc46e5c9..814b7a06e 100644 --- a/content/ru/guide/smart-components/assemblies.md +++ b/content/ru/guide/smart-components/assemblies.md @@ -39,7 +39,7 @@ description: "Сборка — компонент из компонентов: "search": {"part": "sf-search-field", "bind": {"values.query": "query"}}, "source": {"part": "sf-source", "bind": {"settings.collection": "collection", "settings.query": "query", "values.items": "items", "values.total": "total", "values.state": "state"}}, - "list": {"part": "sf-table", "bind": {"settings.items": "items", "settings.state": "state"}} + "list": {"part": "sf-view-table", "bind": {"settings.items": "items", "settings.state": "state"}} }, "layouts": {"default": {"file": "layout.default.html"}}, "rules": [ @@ -205,7 +205,7 @@ flowchart LR ```json "roles": { "inn": {"part": "sf-input", "if": "is-company", "settings": {"name": "inn", "required": true}}, - "note": {"part": "sf-textarea", "hidden": "!has-note"} + "note": {"part": "sf-input-textarea", "hidden": "!has-note"} } ``` diff --git a/content/ru/guide/smart-components/comparison.md b/content/ru/guide/smart-components/comparison.md index 70c274381..452b030d6 100644 --- a/content/ru/guide/smart-components/comparison.md +++ b/content/ru/guide/smart-components/comparison.md @@ -119,11 +119,11 @@ SIMAI Framework; все 59 смарт-компонентов переведен - `sf-tree` рисует записи плоско, строками на классах по ключу, и при более чем 300 видимых записях — только те, что в окне (simai/ui-source#43, `sf-tree` 2.0, выпуск `ui-363de49bdfa8`); -- `sf-property-view` держит одну версию на запись и читает разделы через +- `sf-view-properties` держит одну версию на запись и читает разделы через `group.load` (пункты 25 и 35 переноса, порт 1.15.0 в выпуске `ui-dde3ef154c34`, ui-pro `c6f3cfc`); - деталь под ложным `if`, в закрытом контейнере или с `start` `opened` - или `visible` не загружает код, а редакторы полей `sf-property-view` + или `visible` не загружает код, а редакторы полей `sf-view-properties` загружаются лениво (simai/ui-source#47, выпуск `ui-6d7ee4232223`; ui-pro `41956dc`); - базовое действие `connect-port` есть у каждого смарт-элемента, а @@ -149,7 +149,7 @@ SIMAI Framework; все 59 смарт-компонентов переведен | `sf-modal` копирует содержимое слота через `outerHTML`, обработчики страницы теряются | simai/ui-source#42 | | Идентификаторы из счётчика совпадают у классового и смарт-поля | simai/ui-source#41 | | Три списка слоёв и две основы z-index | simai/ui-source#36, #37 | -| `sf-table` рисует около 108 узлов на строку и не имеет окна | simai/ui-pro#2 | +| `sf-view-table` рисует около 108 узлов на строку и не имеет окна | simai/ui-pro#2 | | Описание `sf-switch` попадает в имя; `Escape` у `sf-menu` объявлен для всех раскладок | simai/ui-source#44 | | `SF.language.use` побеждает `[lang]`; нет множественного числа; пара не поставляет файлы слов | simai/ui-source#45 | | `sf-modal` в `body` теряет язык, тему и переменные хоста; цвет включённого `sf-switch` — только токен роли | simai/ui-source#46 | @@ -166,7 +166,7 @@ SIMAI Framework; все 59 смарт-компонентов переведен | Все теги определяются в одном общем реестре элементов, поэтому две старшие версии тега не уживаются на странице | пункт 34 переноса | | ui-admin передаёт порт каждому компоненту вручную (`setHostPort`) и сам отвечает на `sf-host-port-request`; рантайм сборок доводит порт, повторяет панели, откладывает чтения и говорит слова по коду | пункт 37 переноса | | Порт представления данных 1.12 не пускает `confirm` в массовое `bulk.apply_selected`, хотя хосты просят подтверждения; порт 1.13.0 добавляет поле | simai/ui-source#48, пункт 38 переноса | -| `sf-property-view` не сообщает `saved` и не бывает закрытым, поэтому страница сама создаёт и убирает панель | simai/ui-pro#4, пункт 39 переноса | +| `sf-view-properties` не сообщает `saved` и не бывает закрытым, поэтому страница сама создаёт и убирает панель | simai/ui-pro#4, пункт 39 переноса | | Полигон ui-admin дважды обновляет список при запуске; эталонный хост пишет причины через дефис, а Larena — через подчёркивание; эталонный хост не отвечает на `record.delete` | simai/ui-admin#1, пункт 40 переноса | | Ключ `view` занимает зарезервированное имя, порядок записан как `{field, dir}` | пункт 41 переноса | | `sf-tabs` берёт пункты методом `setItems` и объявляет `items` строкой; `sf-modal` и `sf-toast` не берут `code` и `count` | пункт 42 переноса | diff --git a/content/ru/guide/smart-components/data.md b/content/ru/guide/smart-components/data.md index 3c73062fe..cb76a6d10 100644 --- a/content/ru/guide/smart-components/data.md +++ b/content/ru/guide/smart-components/data.md @@ -63,7 +63,7 @@ orders.connectPort({ port: window.app.dataViewPort }); объявляет порт прямо в элементе — JSON-островом внутри него: ```html - + …начальный вид элемента… - + ``` | Поле | Что задаёт | @@ -135,7 +135,7 @@ simai/ui-source. ### Первый ответ и тихая перепроверка Страница может напечатать первый ответ списка вместе с HTML — остров -`first-answer` у `sf-data-view` в форме ответа порта, — и список работает +`first-answer` у `sf-view` в форме ответа порта, — и список работает ещё до порта. Тогда: - **возможности порта известны до его ответа** — из объявленного порта или @@ -296,7 +296,7 @@ flowchart LR отвечает версией всей записи, `group.save` сравнивается с ней, а своей версии у раздела нет. Сохранение по более старой версии отвечает `conflict` с текущей. Так работает порт `simai.property-view-port` 1.15.0 - (выпуск `ui-dde3ef154c34`) и `sf-property-view` из ui-pro на нём; хост без + (выпуск `ui-dde3ef154c34`) и `sf-view-properties` из ui-pro на нём; хост без возможности `group-load` обслуживается через `record.load` один раз на версию, см. [Один раздел записи](/ru/guide/smart-components/first-paint/#один-раздел-записи). diff --git a/content/ru/guide/smart-components/field-renderers.md b/content/ru/guide/smart-components/field-renderers.md index a8d41b7b2..bfc02fc0d 100644 --- a/content/ru/guide/smart-components/field-renderers.md +++ b/content/ru/guide/smart-components/field-renderers.md @@ -26,8 +26,8 @@ description: "Набор SF.fieldRenderers рисует значение сво - **ячейка** — значение в строке таблицы; - **фильтр** — элемент окна фильтра по этому свойству. -Таблица `` берёт из набора ячейки и фильтры, карточка записи -`` — просмотр и правку. Оба компонента входят в пакет +Таблица `` берёт из набора ячейки и фильтры, карточка записи +`` — просмотр и правку. Оба компонента входят в пакет `pro` ([Представление данных](/ru/pro/admin/table/), [Представление свойств](/ru/pro/admin/property-view/)). Страница вызывает те же функции сама, когда рисует поле без этих компонентов. @@ -47,7 +47,7 @@ description: "Набор SF.fieldRenderers рисует значение сво ## Когда набор доступен У набора нет тега, поэтому разметка страницы его не загружает. Набор -публикуют файлы ``, `` и `` пакета +публикуют файлы ``, `` и `` пакета `pro`, которые несут свою копию, и отдельный файл выпуска `smart/field-renderers/js/field-renderers.js` в базе смарт-компонентов `SF.Loader.smartPath`. @@ -154,7 +154,7 @@ const set = await SF.whenFieldRenderers(); выпадающий список. Дата со временем (`datetime`) правится в одной строке двумя полями: день — -`` (прежнее имя ``), время — `` с маской `чч:мм`. Оба поля того же +`` (прежнее имя ``), время — `` с маской `чч:мм`. Оба поля того же размера, что и остальные, внутри группы с именем поля; у каждого своё доступное имя — «Начало: дата» и «Начало: время». Время можно ввести и без маски: `930`, `9:30` и `9.30` читаются как `09:30`. diff --git a/content/ru/guide/smart-components/first-paint.md b/content/ru/guide/smart-components/first-paint.md index ef66a148e..6d29a975f 100644 --- a/content/ru/guide/smart-components/first-paint.md +++ b/content/ru/guide/smart-components/first-paint.md @@ -49,7 +49,7 @@ description: "Начальный вид у каждого смарт-компо начальный вид не входит. - **Снимок не больше 8 КБ.** Снимок крупнее допускается, только если пример объявляет `"first-paint": {"max-bytes": N, "why": "…"}`; без этого проверка - снимков его не пропускает. Так снимок `sf-country-code` сократился со 107 + снимков его не пропускает. Так снимок `sf-input-country` сократился со 107 до 1,7 КБ. - **Снимок одинаков от прогона к прогону:** два прогона записи дают одни и те же байты (с выпуска `ui-0edd49be08f8`). Для этого: @@ -119,7 +119,7 @@ node scripts/snapshot-first-paint.mjs <папка сборки> --check или карточки с полосками внутри и повторяется столько раз, сколько задаёт настройка, ограничивающая данные: размер страницы, предел строк или объявленное ожидаемое число — например `expected-columns` у -`sf-data-view` и `sf-admin-menu`. Поэтому те же стили, вместе с медиа- и +`sf-view` и `sf-admin-menu`. Поэтому те же стили, вместе с медиа- и контейнерными запросами, дают скелетону и данным одну рамку на любой ширине. - Где размер зависит от данных, которых не знает ни одна настройка @@ -134,7 +134,7 @@ node scripts/snapshot-first-paint.mjs <папка сборки> --check место под компонент, он публикует размеры открытыми CSS-переменными, посчитанными из токенов размера, с формулой в документации. Пример — `--sf-table-row-block-size-<размер>`, `--sf-table-head-block-size-<размер>` -и `--sf-table-toolbar-block-size-<размер>` у `sf-table`. +и `--sf-table-toolbar-block-size-<размер>` у `sf-view-table`. В выпуске `ui-133dc02b833d` данные приходят позже у трёх компонентов из 59: `sf-tree`, `sf-menu` и `sf-profile-picker`. Вручную написан только скелетон @@ -202,8 +202,8 @@ node scripts/snapshot-first-paint.mjs <папка сборки> --check | `none` | заглушки нет: так объявлены элементы в строке текста и то, что открывается поверх страницы, — заглушка сдвинула бы строку, в которой элемент стоит | ```html - - + + ``` Заглушка видна, только пока элемент не определён (`:not(:defined)`) и в нём @@ -280,11 +280,11 @@ flowchart LR рядом с напечатанной разметкой). Сдвиг после прихода кода — не больше 0,0006. -На стенде экрана админки (сборка из выпущенных `sf-data-view`, -`sf-property-view`, `sf-button`, `sf-page-header` и `sf-toast`) первый кадр +На стенде экрана админки (сборка из выпущенных `sf-view`, +`sf-view-properties`, `sf-button`, `sf-header-page` и `sf-toast`) первый кадр стоит неподвижно до кода и после данных на обеих ширинах. Небольшой сдвиг при приходе кода давали две ошибки SIMAI Framework — напечатанная -`sf-button` рисовалась заново, а строка `sf-page-header` меняла высоту со +`sf-button` рисовалась заново, а строка `sf-header-page` меняла высоту со звёздочкой; обе исправлены в выпуске `ui-6d7ee4232223`. ## Когда запускается деталь @@ -395,7 +395,7 @@ stateDiagram-v2 Это уже в поставке: `group.load` появился в порте `simai.property-view-port` 1.15.0 (выпуск `ui-dde3ef154c34`), и -`sf-property-view` из ui-pro читает разделы через него, а у хоста без +`sf-view-properties` из ui-pro читает разделы через него, а у хоста без `group-load` — через `record.load`. На стенде экрана админки открытие записи просит два `group.load` (заголовок с первым разделом и второй раздел «Общее») и ни одного `record.load`; закрытая вкладка ничего не просит, пока @@ -413,10 +413,10 @@ stateDiagram-v2 `visible` не загружает код. На стенде экрана админки первое посещение загружает 24 модуля вместо 41, а когда код подхватывает разметку, сдвиг равен 0 на ширине 1280 и 390 px. -- **Редакторы полей `sf-property-view` загружаются лениво** (ui-pro +- **Редакторы полей `sf-view-properties` загружаются лениво** (ui-pro `41956dc`, 14 связей): пока запись не открыта, их код не приходит. - **У семи компонентов ui-pro свой начальный вид**: проверка 24 — 92 из 92, - сдвиг 0. Скелетон `sf-property-view` — вкладки разделов и карточки групп + сдвиг 0. Скелетон `sf-view-properties` — вкладки разделов и карточки групп полей вместо прежней сетки три на три. Открытых задач по первому кадру и ленивой загрузке сейчас нет. diff --git a/content/ru/guide/smart-components/folder.md b/content/ru/guide/smart-components/folder.md index 13658c930..30a612355 100644 --- a/content/ru/guide/smart-components/folder.md +++ b/content/ru/guide/smart-components/folder.md @@ -122,7 +122,7 @@ flowchart LR **Зачем пять файлов.** Когда справочник, Студия и проба повторяют договор своими файлами, они расходятся с `component.json`: в реестре вида 1.3 у `sf-button` не было события `press`, у `sf-tree` — шести событий версии -2.0, у `sf-table` — тринадцати настроек списка, и эти ошибки видели +2.0, у `sf-view-table` — тринадцати настроек списка, и эти ошибки видели справочник на сайте, каталог Студии и подсказки редактора. По стандарту 1.4 всё это выводится из одного файла. Человек держит меньше: у `sf-button` 5 файлов договора вместо 12 (1189 строк вместо 1728), у `sf-tree` — 5 вместо diff --git a/content/ru/guide/smart-components/forms.md b/content/ru/guide/smart-components/forms.md index e7af84673..c58ef6ad7 100644 --- a/content/ru/guide/smart-components/forms.md +++ b/content/ru/guide/smart-components/forms.md @@ -130,7 +130,7 @@ amount.form.reportValidity(); // false: форма не отправится Поле может показывать значение, унаследованное от уровня выше: от раздела, от шаблона, от общих настроек. Черта используется в `sf-input`, -`sf-textarea`, `sf-dropdown`, `sf-color`, `sf-switch` и `sf-quantity` и +`sf-input-textarea`, `sf-dropdown`, `sf-input-color`, `sf-switch` и `sf-input-quantity` и приносит: | Часть | Имена | diff --git a/content/ru/guide/smart-components/language.md b/content/ru/guide/smart-components/language.md index b0abe9d28..c57ecb665 100644 --- a/content/ru/guide/smart-components/language.md +++ b/content/ru/guide/smart-components/language.md @@ -103,7 +103,7 @@ description: "Слова смарт-компонента в файлах lang/< ```json "roles": { "status": {"part": "sf-dropdown", "settings": {"options": [{"value": "open"}, {"value": "won"}, {"value": "lost"}]}, "bind": {"values.value": "status"}}, - "table": {"part": "sf-table", "settings": {"columns": [{"key": "title"}, {"key": "amount"}]}, "bind": {"settings.items": "deals"}} + "table": {"part": "sf-view-table", "settings": {"columns": [{"key": "title"}, {"key": "amount"}]}, "bind": {"settings.items": "deals"}} } ``` @@ -144,9 +144,9 @@ description: "Слова смарт-компонента в файлах lang/< ```html - +
-
diff --git a/content/ru/guide/smart-components/names.md b/content/ru/guide/smart-components/names.md index 7b8d5a07c..ef7f866a2 100644 --- a/content/ru/guide/smart-components/names.md +++ b/content/ru/guide/smart-components/names.md @@ -14,10 +14,10 @@ description: "Как называются смарт-компоненты, их - Тег — английское словосочетание в kebab-case после приставки: `sf-<уточнение>-<главное слово>`, **главное слово в конце**: - `sf-context-menu`, `sf-admin-menu`, `sf-range-slider`, `sf-page-header`, - `sf-thread-list`, `sf-message-log`. + `sf-menu-context`, `sf-admin-menu`, `sf-slider-range`, `sf-header-page`, + `sf-chat-threads`, `sf-message-log`. - Компонент того же рода сохраняет главное слово и получает уточнение: - `sf-menu`, `sf-context-menu`, `sf-admin-menu`, `sf-site-menu`. В семье + `sf-menu`, `sf-menu-context`, `sf-admin-menu`, `sf-site-menu`. В семье может быть сколько угодно членов. - Сборка из сборок называется так же — по тому, что она есть: `sf-record-screen`, а не по своим частям. @@ -64,13 +64,13 @@ description: "Как называются смарт-компоненты, их | `source` | спрашивает данные у хоста через порт по `collection`, `query`, `filters`, `sort` и `page`; применяет только новейший ответ (`concurrency: latest`); вычисляет состояние данных; сообщает о присланном без запроса и о потоках фактами | порты представления данных и свойств, порт чата | | `search` | текстовый запрос | поиск таблицы и админ-меню | | `filter` | условия на записи | фильтры таблицы | -| `list` | показывает записи; открывает одну, выбирает несколько | `sf-table`, `sf-data-view`, `sf-thread-list` | +| `list` | показывает записи; открывает одну, выбирает несколько | `sf-view-table`, `sf-view`, `sf-chat-threads` | | `pagination` | страница, размер страницы, полоса массовых действий | `sf-pagination` | | `feed` | лента, новое внизу, раннее по запросу | `sf-message-log` | -| `record` | показывает и правит одну запись | `sf-property-view` | +| `record` | показывает и правит одну запись | `sf-view-properties` | | `actions` | команды для выбранного или записи | панель инструментов, действия строки | | `composer` | пишет новую запись | поле ввода UI Chat | -| `confirm` | спрашивает перед изменением, отвечает отпечатком | `sf-change-confirm` | +| `confirm` | спрашивает перед изменением, отвечает отпечатком | `sf-confirm-change` | | `navigation` | где человек; переход между разделами | `sf-admin-menu` | ## Ключи экрана diff --git a/content/ru/guide/smart-components/page.md b/content/ru/guide/smart-components/page.md index 1224cc5c7..5f4a20a9c 100644 --- a/content/ru/guide/smart-components/page.md +++ b/content/ru/guide/smart-components/page.md @@ -39,7 +39,7 @@ description: "Как интерфейс смарт-компонента выгл которая объявила его пакет в `SF_BOOT_CONFIG.packages` до подключения Core. Если пакет не объявлен, загрузчик компонент не загружает и пишет в консоли, какой тег и почему. Так подключаются компоненты пакета `pro`: - ``, ``, ``, `` и + ``, ``, ``, `` и другие — см. [Готовая сборка пакета `pro`](/ru/guide/introduction/structure/#готовая-сборка-пакета-pro) и [Пакеты партнёров и проектов](/ru/guide/smart-components/packages/). diff --git a/content/ru/guide/smart-components/view-preferences.md b/content/ru/guide/smart-components/view-preferences.md index 0cf3cef97..f7bfdc036 100644 --- a/content/ru/guide/smart-components/view-preferences.md +++ b/content/ru/guide/smart-components/view-preferences.md @@ -153,7 +153,7 @@ SF.Preferences.useHost({ ## Раскладка таблицы: предпочтение и слой порта -У `` раскладку колонок помнят два места, и у каждого своя роль: +У `` раскладку колонок помнят два места, и у каждого своя роль: - **Предпочтение** `sf-table/` — значение из таблицы выше. Оно читается до первого запроса: запрос несёт сортировку и размер @@ -193,7 +193,7 @@ SF.Preferences.useHost({ Компонент, который хранит вид, предлагает «Сбросить вид» там, где лежат его настройки. Кнопка «Сбросить» в настройках таблицы убирает из значения раскладку колонок (`columnSettings` и `widths`), а сортировку, размер -страницы и `view` оставляет; в `` она ещё записывает пустую +страницы и `view` оставляет; в `` она ещё записывает пустую раскладку `{}` в личный слой порта против его ревизии. Ширину панели сбрасывает двойной щелчок по ручке. diff --git a/content/ru/pro/admin/change-confirm.md b/content/ru/pro/admin/change-confirm.md index 0f823753c..24c19cebc 100644 --- a/content/ru/pro/admin/change-confirm.md +++ b/content/ru/pro/admin/change-confirm.md @@ -13,7 +13,7 @@ description: "Подготовленное изменение ждёт отве **Теперь в SIMAI Framework.** С выпуска `ui-c3015f76bcc2` карточка входит в выпуск SIMAI Framework под тегом ``, а пакет `pro` её -больше не поставляет. Прежний тег `` работает до +больше не поставляет. Прежний тег `` работает до 2027-01-01. Рядом с ней в Framework — ``: тот же вопрос без «было и станет», например удаление, о котором спрашивают в строке; оба описаны в справочнике ниже. @@ -105,71 +105,10 @@ card.addEventListener('sf-confirm-change-answer', async (event) => { ## Справочник API -Раздел собран из манифеста компонентов выпуска `ui-e22fefb3c1f8` и обновляется вместе с выпуском. Чтобы исправить описание, исправьте манифест. +Раздел собран из манифеста компонента выпуска `ui-e22fefb3c1f8` и обновляется вместе с выпуском. Чтобы исправить описание, исправьте манифест. Каждому атрибуту соответствует свойство элемента с тем же именем в camelCase: `search-placeholder` — `searchPlaceholder`. Свойство атрибута `template` называется `templateName`. -### `` - -| | | -|:---|:---| -| Тег | `` | -| Назначение | Вопрос человеку на месте — удаление, о котором спрашивают в его строке, исключение участника, сброс вида: что произойдёт, два ответа, состояние ожидания, пока ответ применяется, итог и необязательный срок, после которого вопрос истекает. Сам ничего не применяет: нажатие — это событие. | -| Контракт | `smart.confirm`, версия `1.0.0` | -| Поставка | выпуск Framework `ui-e22fefb3c1f8` | -| [Жизненный цикл](/ru/guide/smart-components/quality/#готовность-компонента-к-использованию) | экспериментальный: API может меняться между выпусками | -| [Готовность](/ru/guide/smart-components/quality/#готовность-компонента-к-использованию) | `host-required` | -| Заготовка до прихода кода | нет: атрибут `data-sf-skeleton` не пишется; своего скелетона при загрузке данных нет ([Коробка до кода](/ru/guide/smart-components/first-paint/#коробка-до-кода)) | - -#### Атрибуты - -- `template` — `string`, по умолчанию `default`. Имя варианта шаблона для внешних шаблонов SfBaseElement. -- `root-class` — `string`, по умолчанию пусто. Классы, которые добавляются корневому элементу, нарисованному компонентом. -- `root-style` — `string`, по умолчанию пусто. Объявления стиля, которые ставятся корневому элементу, нарисованному компонентом, в том числе пользовательские свойства. -- `question` — `string`, по умолчанию пусто. Вопрос, сказанный на месте: что произойдёт, одним предложением («Удалить файл «Отчёт.pdf»?»). Он же называет группу; без него группа называется «Подтверждение». -- `state` — `string`, по умолчанию `open`, значения: `open`, `pending`, `accepted`, `declined`, `expired`. open: ответы предложены. pending: ответ отправляется (ставится нажатием). accepted, declined, expired: виден только итог. -- `expires-at` — `string`, по умолчанию пусто. ISO 8601. После этого срока открытый вопрос считается истёкшим и один раз сообщает об этом событием `sf-confirm-expired`. -- `confirm-id` — `string`, по умолчанию пусто. Имя вопроса у хоста (строка, запись); возвращается в каждом событии. -- `disabled` — `boolean`, по умолчанию `false`. Ответы видны, но их нельзя нажать (где-то уже идёт отправка). -- `destructive` — `boolean`, по умолчанию `false`. Согласие что-то уничтожает (удаление): у принимающего ответа статус error. -- `appearance` — `string`, по умолчанию `inline`, значения: `inline`, `card`. inline: вопрос и ответы в потоке строки, без своей рамки. card: в карточке с рамкой и собственным отступом. -- `accept-text` — `string`. Слова ответа «да»; пусто — «Подтвердить» на языке страницы. -- `decline-text` — `string`. Отказывающий ответ; пусто — «Отмена» на языке страницы. - -#### Методы - -- `open()` — возвращает `object`. Задаёт вопрос снова; если его попросила сборка, отвечает `{accepted, reason, value}`, когда человек ответил или время вышло. -- `answer(accepted: boolean)` — возвращает `object`. Отвечает, как ответил бы человек: `accepted` true подтверждает, false отказывается. Отказ: `unknown`, `closed`, `disabled` или `prevented`. -- `confirm()` — возвращает `object`. Согласие; `data-sf-action=".confirm"`. -- `cancel()` — возвращает `object`. Отказывающий ответ; `data-sf-action=".cancel"`. Escape внутри открытого вопроса — тот же ответ. - -#### События - -Все события приходят на сам элемент и всплывают. Что означает глагол в имени события, говорит общий словарь: [Имена и общие слова](/ru/guide/smart-components/names/). Общие события базового элемента перечислены в главе [Модель компонента → Базовый интерфейс](/ru/guide/smart-components/model/#базовый-интерфейс). - -- `sf-confirm-answer` — `detail`: `{ id: any, accepted: boolean }`. Человек ответил (слово словаря answer). Отмените событие, чтобы вопрос остался открытым. -- `sf-confirm-expired` — `detail`: `{ id: any }`. Открытый вопрос дождался `expires-at`; сообщается один раз на каждый срок. - -#### Доступность - -- Роль: группа (`group`). -- Доступное имя: внутренний. -- Клавиши: `Tab`, `Enter`, `Space`, `Escape`. -- Фокус: Группа, названная своим вопросом. Строка состояния — вежливая живая область, которая есть на странице до того, как заговорит; когда нажатие убирает ответы, фокус переходит на неё, а не падает на страницу, и возвращается к первому ответу, если хост отменил. Escape внутри открытого вопроса — отказ. - -#### Минимальная разметка - -```html - -``` - -#### Источник - -- `simai/ui@e22fefb3c1f8bed4c7ad8d8745a408ecedc5029f:distr/smart/confirm` -- `simai/ui@e22fefb3c1f8bed4c7ad8d8745a408ecedc5029f:distr/rule/rule.json#name=cl-confirm` - -### `` - | | | |:---|:---| | Тег | `` | @@ -180,7 +119,7 @@ card.addEventListener('sf-confirm-change-answer', async (event) => { | [Готовность](/ru/guide/smart-components/quality/#готовность-компонента-к-использованию) | `host-required` | | Заготовка до прихода кода | нет: атрибут `data-sf-skeleton` не пишется; своего скелетона при загрузке данных нет ([Коробка до кода](/ru/guide/smart-components/first-paint/#коробка-до-кода)) | -#### Атрибуты +### Атрибуты - `template` — `string`, по умолчанию `default`, значения: `default`. Имя варианта шаблона для внешних шаблонов SfBaseElement. - `root-class` — `string`, по умолчанию пусто. Классы, которые добавляются корневому элементу, нарисованному компонентом. @@ -195,14 +134,14 @@ card.addEventListener('sf-confirm-change-answer', async (event) => { - `decline-text` — `string`. Слова ответа «нет»; пусто — «Отклонить» на языке страницы. - `changes` — `array` из `object`, по умолчанию `[]`. Значения в JSON для разметки; свойство, заданное из скрипта, важнее. -#### Методы +### Методы - `open()` — возвращает `object`. Задаёт вопрос снова; если его попросила сборка, отвечает `{accepted, reason, value}`, когда человек ответил или время вышло. - `answer(accepted: boolean)` — возвращает `object`. Ответить, как ответил бы человек: `accepted` true подтверждает, false отклоняет. Отказ, если карточка закрыта, выключена или ответ отменён. `answer('accept')` и `answer('decline')` читаются до 2026-12-01. - `confirm()` — возвращает `object`. Согласие; `data-sf-action=".confirm"`. - `cancel()` — возвращает `object`. Отказ; `data-sf-action=".cancel"`. -#### События +### События Все события приходят на сам элемент и всплывают. Что означает глагол в имени события, говорит общий словарь: [Имена и общие слова](/ru/guide/smart-components/names/). Общие события базового элемента перечислены в главе [Модель компонента → Базовый интерфейс](/ru/guide/smart-components/model/#базовый-интерфейс). @@ -214,20 +153,20 @@ card.addEventListener('sf-confirm-change-answer', async (event) => { - `sf-change-confirm-answer` — устаревший псевдоним события `sf-confirm-change-answer`: приходит с тем же `detail`, подписывайтесь на `sf-confirm-change-answer`. - `sf-change-confirm-expired` — устаревший псевдоним события `sf-confirm-change-expired`: приходит с тем же `detail`, подписывайтесь на `sf-confirm-change-expired`. -#### Доступность +### Доступность - Роль: область (`region`). - Доступное имя: внутренний. - Клавиши: `Tab`, `Enter`, `Space`. - Фокус: Раздел, названный заголовком (role=heading уровня heading-level). Значения — список описаний. Строка состояния — вежливая живая область, которая есть на странице до того, как заговорит; когда нажатие убирает ответы, фокус переходит на неё, а не падает на страницу, и возвращается на первый ответ, если хост отменил событие. -#### Минимальная разметка +### Минимальная разметка ```html ``` -#### Источник +### Источник - `simai/ui@e22fefb3c1f8bed4c7ad8d8745a408ecedc5029f:distr/smart/confirm-change` - `simai/ui@e22fefb3c1f8bed4c7ad8d8745a408ecedc5029f:distr/rule/rule.json#name=cl-confirm-change` diff --git a/content/ru/pro/admin/property-view.md b/content/ru/pro/admin/property-view.md index 51176eb7c..6ea8d2e31 100644 --- a/content/ru/pro/admin/property-view.md +++ b/content/ru/pro/admin/property-view.md @@ -5,7 +5,7 @@ description: "Показывает и правит поля одного объ # Представление свойств -`` — карточка одного объекта: поля сгруппированы в области, +`` — карточка одного объекта: поля сгруппированы в области, области — в разделы, а каждое поле рисуется отрисовщиком своего типа. Берите его для записи, настроек сайта или профиля; множество записей показывает [представление данных](/ru/pro/admin/table/). @@ -355,7 +355,7 @@ view: { ### Дата и время Поле `datetime` правится в одной строке двумя элементами: день — в -`sf-datepicker`, время — в `sf-input` с маской чч:мм. Оба размера +`sf-input-date`, время — в `sf-input` с маской чч:мм. Оба размера представления, и у каждого своё доступное имя («Начало: дата», «Начало: время»). Значение — текст хоста в часовом поясе сайта в формате ISO 8601 (день, или день и время после `T` или пробела, с секундами, долями и поясом diff --git a/content/ru/pro/admin/table.md b/content/ru/pro/admin/table.md index c5d24a9da..ddf7cfa74 100644 --- a/content/ru/pro/admin/table.md +++ b/content/ru/pro/admin/table.md @@ -5,11 +5,11 @@ description: "Показывает серверную коллекцию таб # Представление данных -`` показывает серверную коллекцию записей: поиск, фильтры, таблицу, +`` показывает серверную коллекцию записей: поиск, фильтры, таблицу, выбор строк, действия, настройки колонок и пагинацию. Данные, права и выполнение действий остаются за приложением: компонент показывает то, что ему передали, и сообщает о намерениях пользователя событиями. -`` оборачивает таблицу и связывает её с приложением через порт +`` оборачивает таблицу и связывает её с приложением через порт хоста. Оба элемента входят в пакет компонентов `pro`. **Компонент Pro.** Входит в [SIMAI Pro](/ru/pro/), а не в выпуск SIMAI @@ -25,12 +25,12 @@ Framework: поставляется пакетом `pro` из репозитор ### Подключение пакета -Элементы `` и `` поставляет Larena, а не выпуск +Элементы `` и `` поставляет Larena, а не выпуск Framework: пакет компонентов Loader с именем `pro` из репозитория `simai/ui-pro` (лицензия PolyForm Small Business 1.0.0 или PolyForm Noncommercial 1.0.0, по запросу — коммерческая лицензия SIMAI; в составе Larena — лицензия Larena). В пакет входят ещё -[``](/ru/pro/admin/property-view/) и +[``](/ru/pro/admin/property-view/) и [``](/ru/pro/admin/admin-menu/). Объявите пакет до подключения Core: `window.SF_BOOT_CONFIG = {packages: {pro: {base: '/assets/pro/<коммит пакета>/smart'}}}`. @@ -85,15 +85,15 @@ Larena — лицензия Larena). В пакет входят ещё `vertical-scroll="page"` отдаёт прокрутку странице вместо самой таблицы, `context-menu-columns` (от 1 до 4) делит меню настроек на колонки. -У `` свои части перечисляет атрибут `chrome`: `toolbar`, +У `` свои части перечисляет атрибут `chrome`: `toolbar`, `pagination`, `select`, `settings`; без атрибута включены все. Часть `toolbar` — запасная строка поиска самого представления. Если в слот -`content` вставлена своя `` со своей панелью инструментов, +`content` вставлена своя `` со своей панелью инструментов, запасная строка не показывается. Без `toolbar` в `chrome` представление ставит таблице `layout="table"`; список на узком экране сохраняет `layout="auto"`, записанный на самой таблице. -Область представления называет `aria-label` самого ``; без +Область представления называет `aria-label` самого ``; без него — общее «Представление данных». Строка страниц с «Всего» появляется после первого ответа приложения и скрыта, пока список не загрузился, при ошибке и при отказе в доступе. @@ -141,7 +141,7 @@ record_ids}` приходит следом до 2026-12-01. Встроенные `sf-table-toolbar-action` с `{action, href}`, и без `preventDefault()` компонент переходит по `href` того же сайта. -В `` кнопку «Создать» показывает возможность `create-record` +В `` кнопку «Создать» показывает возможность `create-record` адаптера. Отдельного права на создание у человека порт не передаёт: хост объявляет `create-record` в адаптере, который строит для этого человека, а на `view.create_record` без права отвечает `refused`. @@ -152,9 +152,9 @@ record_ids}` приходит следом до 2026-12-01. Встроенные `list` — компактным списком, `auto` — таблицей, пока контейнер таблицы не уже порога `list-below`, и списком, когда уже. Решает ширина контейнера, а не окна: таблица рядом с открытой панелью тоже становится списком. -`` с панелью инструментов задаёт своей таблице `auto`; +`` с панелью инструментов задаёт своей таблице `auto`; встроенный список без панели остаётся таблицей, а `layout`, который -приложение написало на `` само, сохраняется. +приложение написало на `` само, сохраняется. В компактном списке каждая запись — блок: флажок выбора (при `selectable`), заголовок, под ним несколько полей с подписями и меню строки. Заголовок — колонка с @@ -175,7 +175,7 @@ record_ids}` приходит следом до 2026-12-01. Встроенные ### Дерево -Адаптер с возможностью `tree` отвечает деревом, и `` +Адаптер с возможностью `tree` отвечает деревом, и `` показывает записи по уровням. Ответ на запрос несёт `tree: {mode: 'tree', parent: null}` и записи одного уровня — корни; каждая запись сообщает `has_children`. Открытие узла поднимает намерение `tree.expand` с `id` узла, и адаптер @@ -202,8 +202,8 @@ record_ids}` приходит следом до 2026-12-01. Встроенные `view.create_record` уходит с `parent`. Оба действия появляются только у записей, которые перечисляют их в `actions`. -`` дерево только рисует: строки с `__tree` пишет -``. Нажатие на кнопку узла отправляет `sf-table-expand` +`` дерево только рисует: строки с `__tree` пишет +``. Нажатие на кнопку узла отправляет `sf-table-expand` с `{id, expanded}`, строка «Показать ещё» — `sf-table-load-more` с `{direction, parent, cursor}`; на оба отвечает представление. Намерения дерева, которые оно поднимает, приходят событием `sf-data-view-tree` с @@ -247,9 +247,9 @@ record_ids}` приходит следом до 2026-12-01. Встроенные перемещённые идентификаторы, строка, перед которой они встали (`null` — в конце), и весь новый порядок. Если порядок не изменился, события нет. Прежнее имя `sf-table-rows-reorder` приходит следом до 2026-12-01. - Порядок сохраняет приложение; в `` — через порт хоста + Порядок сохраняет приложение; в `` — через порт хоста ([Перестановка строк и запись в ячейке](#перестановка-строк-и-запись-в-ячейке)). -- `accept-files` на `` — на представление можно перетащить файлы +- `accept-files` на `` — на представление можно перетащить файлы с компьютера: пока они над ним, видна зона сброса, после отпускания приходит `sf-data-view-files-drop` с `{files}`. Загружает файлы приложение. @@ -274,7 +274,7 @@ table.setRows([ Нажатие флажка отправляет `sf-table-cell-set` с `{id, key, value, revision}`; пока приложение отвечает, флажок выключен. Таблица сама значение не сохраняет: строку перерисовывает то, что ответило приложение. В -`` запись в ячейке идёт через порт хоста +`` запись в ячейке идёт через порт хоста ([Перестановка строк и запись в ячейке](#перестановка-строк-и-запись-в-ячейке)). Кнопки действий строки по умолчанию видны в строке под указателем, в фокусе @@ -295,7 +295,7 @@ table.setRows([ Уже при первой отрисовке таблица вынимает элемент слота из документа, и поиск по `id` после этого вернёт `null` — в том числе после -`customElements.whenDefined('sf-data-view')`. Поэтому ссылку на блок берите на +`customElements.whenDefined('sf-view')`. Поэтому ссылку на блок берите на верхнем уровне скрипта в конце `body`, до того как придёт код пакета, и меняйте блок по событию `sf-data-view-state`. Таблица записывает причину в свойство `emptyContext` до того, как представление отправляет событие: @@ -311,11 +311,11 @@ table.setRows([ или очищает то, что назвал `reset`. Второй запрос из кода страницы не нужен. ```html - - + + - - + + ``` -Отдельная таблица без `` показывает только «нет записей» и +Отдельная таблица без `` показывает только «нет записей» и ошибку. Подробнее — в [Пустое состояние](/ru/guide/smart-components/data/#пустое-состояние). ### Прокрутка на странице списка -`vertical-scroll` у `` выбирает, что прокручивается вверх и вниз: +`vertical-scroll` у `` выбирает, что прокручивается вверх и вниз: `self` — таблица внутри своей рамки, `page` — сама страница. Представление данных по умолчанию ставит своей таблице `page`, если приложение не выбрало иное. Тогда таблица растёт на высоту своих строк, и на странице списка @@ -355,7 +355,7 @@ table.setRows([ ### Персональный вид -С атрибутом `preferences-key` на `` (обычно это имя +С атрибутом `preferences-key` на `` (обычно это имя коллекции) раскладка таблицы, сортировка и размер страницы хранятся как [персональный вид](/ru/guide/smart-components/view-preferences/) под ключом `sf-table/` и применяются до первого запроса: первый @@ -364,7 +364,7 @@ table.setRows([ данных не показывает. Без ключа ничего не запоминается. Поля значения — `columnSettings`, `widths`, `view`, `sort` и `pageSize` — таблица объявляет в манифесте (`persistence.view_preference`); все пять сервер может положить в -страницу для первой отрисовки. Их описание — в справочнике `` ниже +страницу для первой отрисовки. Их описание — в справочнике `` ниже и в [Персональный вид → Поля значения](/ru/guide/smart-components/view-preferences/#поля-значения). ### Шаблоны и настройки колонок @@ -375,7 +375,7 @@ table.setRows([ `sf-table-column-settings-change` без `kind` приходит следом до 2026-12-01. Отдельная таблица отдаёт их приложению, и оно при следующей загрузке применяет их через -`setTableSettings(settings)`. В `` то же изменение всегда +`setTableSettings(settings)`. В `` то же изменение всегда уходит в личный слой человека — намерением `settings.save_personal` с `base_revision` — ревизией слоя `data.column_settings.layers.personal`, а если хост этого слоя ещё не @@ -406,11 +406,11 @@ table.setRows([ `sf-table-template-select` (`{key}`) и `sf-table-template-delete` (`{key}`, по одному на шаблон). `sf-table-template-save` несёт один шаблон из формы или массив шаблонов, если «Применить» на вкладке «Шаблоны» изменило -несколько (порядок, закрепление, выбор по умолчанию); `` +несколько (порядок, закрепление, выбор по умолчанию); `` сохраняет каждый шаблон с `key` отдельным намерением `view.save`. Общее сохранённое представление записывает код страницы: он отправляет на -`` событие `sf-data-view-saved-view-intent` с `{key, label, +`` событие `sf-data-view-saved-view-intent` с `{key, label, revision, roles}` (`revision` и `roles` необязательны), и представление отправляет хосту `view.save_shared` с текущим запросом, колонками и настройками. Нужна возможность `shared-saved-views` и порт версии 1.1.0 или @@ -425,14 +425,14 @@ view.dispatchEvent(new CustomEvent('sf-data-view-saved-view-intent', { ### Порт хоста -`` получает данные методами и сообщает о намерениях событиями; +`` получает данные методами и сообщает о намерениях событиями; метода `setHostPort()` у него нет. Адаптер приложения подключается к -``: `setHostPort(host)` принимает объект с полями `version` и +``: `setHostPort(host)` принимает объект с полями `version` и `capabilities` и методом `raise(intent, payload, {signal})`, который отвечает `{answer: 'applied' | 'conflict' | 'refused' | 'unavailable', …}`. -`` говорит на порте `simai.dataview-port` версии 1.12.0 и -принимает адаптеры версий от 1.0.0 до 1.12.0; манифест `` записывает -версию порта 1.0.0. Если адаптер не передан, `` один раз +`` говорит на порте `simai.dataview-port` версии 1.12.0 и +принимает адаптеры версий от 1.0.0 до 1.12.0; манифест `` записывает +версию порта 1.0.0. Если адаптер не передан, `` один раз запрашивает его событием `sf-host-port-request`. Возможности хост объявляет в `capabilities`: представление предлагает @@ -476,7 +476,7 @@ const host = { return response.json(); // {answer, reason?, message?, sequence?, data?} }, }; -document.querySelector('sf-data-view').setHostPort(host); +document.querySelector('sf-view').setHostPort(host); ``` Транспорт, сессия и защита от подделки запроса (CSRF) — дело приложения: @@ -562,7 +562,7 @@ document.querySelector('sf-data-view').setHostPort(host); 30 и 40; действующий размер страницы представление добавляет в этот список, поэтому 25 тоже есть в выборе. Свои размеры задаёт своя пагинация в слоте: ``; `page-sizes` на -`` внутри представления не действует. +`` внутри представления не действует. Поиск, фильтр и сортировка возвращают `page` к 1. `reason` называет причину запроса: `search`, `filter`, `sort`, `page-change`, @@ -598,7 +598,7 @@ document.querySelector('sf-data-view').setHostPort(host); Поля фильтра порт не передаёт. Кнопку «Фильтр» таблица показывает, только когда есть по чему фильтровать: страница передала поля фильтра, есть сохранённые шаблоны или фильтр уже применён. Поля задаёт страница: она вставляет свою -`` в слот `content` представления и вызывает у неё +`` в слот `content` представления и вызывает у неё `setFilterFields(fields)` (см. [Поиск и фильтр](#поиск-и-фильтр)); применённый фильтр представление отправляет хосту в `query.filters`. @@ -614,7 +614,7 @@ document.querySelector('sf-data-view').setHostPort(host); называет свой `sequence` и тогда, когда он `refused` или `unavailable`; ответ без него представление считает ответом на текущий запрос. -У порта карточки записи (``) свой формат: запись приходит +У порта карточки записи (``) свой формат: запись приходит в самом ответе, без `data`. Порт описывает стык отдельно от компонента: @@ -656,7 +656,7 @@ document.querySelector('sf-data-view').setHostPort(host); ### Пример: связь с приложением -Пример подключает `` к приложению через порт хоста. Приложение +Пример подключает `` к приложению через порт хоста. Приложение здесь — несколько строк JavaScript с массивом записей и задержкой ответа; на своей странице `raise()` отправляет те же намерения на сервер и возвращает его ответ в том же конверте. Переключатель над таблицей меняет ответ приложения: @@ -755,7 +755,7 @@ document.querySelector('sf-data-view').setHostPort(host); проверяет их на сервере. ```js -const table = document.querySelector('sf-table'); +const table = document.querySelector('sf-view-table'); table.setDataState('loading'); const page = await api.listProjects({sort: table.getSort()}); table.setTableData({columns: page.columns, rows: page.rows}); @@ -770,7 +770,7 @@ table.addEventListener('sf-table-apply', async (event) => { ## Доступность - Таблица — именованная область (`role="region"`): задайте `aria-label`, - который называет коллекцию. У `` своё обязательное имя. + который называет коллекцию. У `` своё обязательное имя. - Все действия только с иконкой и все меню имеют доступные имена. Меню, фильтры и окна настроек закрываются по `Escape` и возвращают фокус на кнопку, которая их открыла. diff --git a/content/ru/pro/chat/chat-window.md b/content/ru/pro/chat/chat-window.md index 7bfbe558e..00a3cb655 100644 --- a/content/ru/pro/chat/chat-window.md +++ b/content/ru/pro/chat/chat-window.md @@ -184,7 +184,7 @@ false`), поэтому ответ уходит своим намерением С возможностью `x-conversation-start` в голове списка две команды: «Новый диалог» и «Новая группа». Форма встаёт на место разговора, на телефоне — на весь экран. Людей -ищет `sf-lookup`; окно спрашивает хоста намерением `recipients.search {query}` +ищет `sf-input-lookup`; окно спрашивает хоста намерением `recipients.search {query}` (событие `query`, `kind: recipients`), ответ — `data: {items: [{id, name}]}`. Себя выбрать нельзя. diff --git a/content/ru/pro/chat/thread-list.md b/content/ru/pro/chat/thread-list.md index 0cbbea7d7..0b8837249 100644 --- a/content/ru/pro/chat/thread-list.md +++ b/content/ru/pro/chat/thread-list.md @@ -5,7 +5,7 @@ description: "Разговоры человека, новые сверху: гр # Список разговоров -`` — разговоры человека, новые сверху: с ассистентом или +`` — разговоры человека, новые сверху: с ассистентом или между людьми. Он группирует их по дню последнего изменения, отмечает открытый, даёт переименовать разговор на месте, отправить его в архив и просит следующую страницу, когда показался конец списка. Сам список ничего не @@ -79,7 +79,7 @@ Framework: поставляется пакетом `pro` из репозитор - `sf-thread-list-view` — `{archived}`, переход в архив и обратно. ```js -const list = document.querySelector('sf-thread-list'); +const list = document.querySelector('sf-chat-threads'); list.setThreads(await api.threads(), {hasMore: true}); list.addEventListener('sf-thread-list-select', (event) => { openConversation(event.detail.id); diff --git a/content/ru/pro/editor/blocks.md b/content/ru/pro/editor/blocks.md index b33551e42..53f68e9d8 100644 --- a/content/ru/pro/editor/blocks.md +++ b/content/ru/pro/editor/blocks.md @@ -296,7 +296,7 @@ HTML рендерера — это и предпросмотр блока в р - `validate` сообщает `type_unknown` в этом узле, документ недействителен, и `render` не рисует ничего: страница никогда не рисуется наполовину; -- редактор содержимого `sf-content-editor` ([Редактор содержимого](/ru/pro/editor/content-editor/)) +- редактор содержимого `sf-editor-content` ([Редактор содержимого](/ru/pro/editor/content-editor/)) показывает неизвестный узел заглушкой с именем типа, сохраняет его данные и слоты байт в байт и только перемещает или удаляет его целиком; редактор текста так же поступает с незнакомым встроенным элементом; diff --git a/content/ru/pro/editor/content-editor.md b/content/ru/pro/editor/content-editor.md index d6e4f56e1..e92942d48 100644 --- a/content/ru/pro/editor/content-editor.md +++ b/content/ru/pro/editor/content-editor.md @@ -5,7 +5,7 @@ description: "Страница набирается одним потоком: # Редактор содержимого -`` — режим «Содержимое» редактора страниц SIMAI: страница +`` — режим «Содержимое» редактора страниц SIMAI: страница набирается одним потоком, как в обычном текстовом редакторе. Элемент ничего не хранит: он правит свою копию документа и после каждого изменения отправляет событие `change` с новым документом, а сохраняет приложение. @@ -85,7 +85,7 @@ editor.addEventListener('change', (event) => save(event.detail.document)); (английское имя вида находит его на любом языке: `/div`, `/image`), стрелки выбирают, Enter применяет, Esc закрывает. Строка с «/» сама становится выбранным блоком. -- Выделение текста показывает панель [`sf-inline-editor`](/ru/smart/editor/inline-editor/): +- Выделение текста показывает панель [`sf-editor-inline`](/ru/smart/editor/inline-editor/): жирный, курсив, код, ссылка (⌘B, ⌘I, ⌘E, ⌘K). Пока курсор просто стоит, панели нет. - ↑ и ↓ на первой и последней строке переходят в соседнее поле; ⌥↑ ⌥↓ @@ -156,7 +156,7 @@ Esc в поле выбирает его блок. Стрелки выбираю Блок «Файл» (`content.file`, с 1.2.0) — такая же зона для файла любого типа. Любой файл, кроме картинки, брошенный или вставленный на страницу, становится -блоком файла. Он рисуется строкой `sf-download-file`: значок по типу файла, +блоком файла. Он рисуется строкой `sf-file-download`: значок по типу файла, название и размер. Название набирается прямо в блоке, адрес — в параметрах. Пустой блок файла, как и пустая картинка, не проходит проверку документа: приложение показывает его заглушкой, пока файл не придёт. diff --git a/content/ru/pro/editor/editor.md b/content/ru/pro/editor/editor.md new file mode 100644 index 000000000..4c6a613fb --- /dev/null +++ b/content/ru/pro/editor/editor.md @@ -0,0 +1,214 @@ +--- +title: "Редактор страниц" +description: "Единый редактор блоков страницы: раскладка и текст — один документ, глубина вместо режимов." +--- + +# Редактор страниц + +`` — единый редактор блоков страницы SIMAI: раскладка и текст — +один документ и один редактор. Режимов нет, есть глубина: щелчок по тексту — +печать, щелчок рядом — выбор блока, `Esc` — уровень вверх, `Enter` — вниз. + +Элемент ничего не хранит: после каждого изменения он отправляет `change` с +новым документом, а сохраняет хост. Режим одного потока текста — отдельный +компонент [Редактор содержимого](/ru/pro/editor/content-editor/); свои блоки +для каталога редактора описывает страница [Свои блоки](/ru/pro/editor/blocks/). + +## Данные + +```js +editor.document = doc; // Composition Document, профиль ui-layout +editor.types = [cardsType]; // свои типы блоков хоста +editor.renderers = {'site.cards': renderCards}; +editor.editorManifests = [cardsEditor]; +editor.siteBlocks = savedBlocks; // блоки сайта из конструктора +editor.words = {ru: {...}, en: {...}}; +editor.rights = {layout: true, template: false, builder: true}; +editor.theme = {name: 'brand', label: 'Фирменная', settings_url: '/admin/theme', defaults: {}}; +editor.addEventListener('change', (event) => save(event.detail.document, event.detail.scope)); +editor.addEventListener('sf-editor-block-save', (event) => keepBlock(event.detail.manifest, event.detail.words)); +editor.connectPort({sources, fields, preview, saveBlock}); +``` + +Страница с шаблоном сайта — `layout.regions` с областями `banner`, `main` и +`contentinfo`. Шапка и подвал — шаблон: они приглушены с замком и меняются +только явно, кнопкой «Изменить шаблон» (`edit-template`). `change` с +`scope: 'template'` — изменение шапки или подвала всех страниц. + +## Панель и места хоста + +Сверху одна строка: отмена и повтор, переключатель экранов по центру, +справка, результат и тема — кнопками со значком. Свои элементы хоста +(переключатель списка страниц, языка) ставятся в ту же строку через места +(slots) — второй строки у хоста нет: + +```html + + + + +``` + +- `start` — в начале строки, перед отменой и повтором; +- `actions` — в конце строки, перед справкой, результатом и темой. + +Элементы мест забираются при первом подключении элемента (как у +`sf-header-page`); добавленные позже ставятся через `setSlot(name, element)`. +Размер элементов в строке — `1/2`. + +Название страницы и подпись под ним хост передаёт настройками `heading` и +`caption` — они стоят в начале строки, как в прототипе: + +```html + +``` + +«Изменить шаблон» — тихая текстовая ссылка рядом, без значка. + +Библиотека слева — разделы SIMAI Framework со значком и числом блоков +(`CATALOGUE_GROUPS`, `CATALOGUE_GROUP_TABLE`), избранное (пустое — с короткой подсказкой) и недавние сверху. +Раздел открывается на месте, с «Назад»; найденное поиском подписано +разделом. Варианты блока — карточки с картинкой из дерева варианта. + +Страница — лист с тенью на спокойном фоне. Выбранный блок обведён, над ним — +плавающая панель: путь, ручка, вверх, вниз, копия, «Ещё». Панель справа — +значок, имя и раздел блока, вкладки «Параметры», «JSON», «HTML», поля в +группах «Содержимое», «Расположение», «Дополнительно»; у каждого поля — +точка происхождения значения, «Сбросить» и привязка SIMAI Framework мелким +моноширинным шрифтом. + +## Права и тема + +Права приходят от хоста, переключателя ролей в редакторе нет. +`layout: false` — автор пишет только внутри текстовых областей +(`layout.area`), остальное приглушено с замком и объяснением. +`reasons` заменяют объяснения замка словами хоста. + +Тема только читается: её значения по умолчанию — один из уровней +происхождения значения, её атрибуты ставятся на нарисованную страницу. +`settings_url` ведёт туда, где тему меняют. + +## Вставка, перемещение, колонки + +Один каталог (вкладки «Текст» и «Блоки», группы, варианты с картинками, +поиск, избранное, недавние) открывается тремя путями: «+» между блоками, «/» +в пустой строке и библиотека слева (перетаскиванием или нажатием). Вкладка +выбирается по месту; вкладка, где ничего не подходит, скрыта. + +Блок двигают за ручку с линией места, Alt+↑↓ у выбранного блока и +Alt+Shift+↑↓ во время набора. Сброс к боковому краю соседнего блока делит +место на колонки; «Разделить на колонки» есть в меню ручки и в панели. + +## Параметры и данные + +Панель справа показывает у каждого значения, откуда оно: тип, тема, вариант, +блок, экран. Переключатель экранов (компьютер, планшет, телефон) задаёт, для +какого экрана пишется значение, и показывает страницу на этом экране. +Вкладка «Данные» связывает блок с источником хоста через порт источников: +источник, сопоставление полей, сколько, текст на пустой случай, состояние +предпросмотра (данные, пусто, ошибка, загрузка) и связь с блоком той же +секции. Блок сам ничего не загружает. + +## Конструктор блоков + +«Создать свой блок» или «Сделать блоком сайта» открывает конструктор: блок +собирается из тех же частей, для автора открываются выбранные параметры, +блок сохраняется как блок сайта (`sf-editor-block-save`). Изменение блока +сайта сохраняется новой версией и переносит все его экземпляры на странице +(`upgradeComposed`), сохраняя тексты и значения автора. + +## Результат + +«Результат» показывает страницу как JSON, как HTML с классами утилит и как +Markdown текстовых областей; то же даёт действие `output`. + +## Клавиши + +| Где | Клавиша | Что делает | +|:---|:---|:---| +| страница | Enter / Esc | вниз / вверх по глубине | +| страница | ↑ ↓ | соседний блок | +| страница | Alt+↑↓ | переместить блок | +| страница | ⌫, ⌘D | удалить, дублировать | +| текст | Enter, ⌫ в начале | разделить, соединить | +| текст | / | каталог | +| текст | Alt+Shift+↑↓ | переместить блок, не прерывая набор | +| везде | ⌘Z, ⇧⌘Z | одна история для текста и структуры | + +## Справочник API + +Раздел собран из манифеста компонента выпуска `ui-e22fefb3c1f8` и обновляется вместе с выпуском. Чтобы исправить описание, исправьте манифест. + +Каждому атрибуту соответствует свойство элемента с тем же именем в camelCase: `search-placeholder` — `searchPlaceholder`. Свойство атрибута `template` называется `templateName`. + +| | | +|:---|:---| +| Тег | `` | +| Назначение | Единый редактор блоков страницы SIMAI: раскладка и текст в одном Composition Document, правка по глубине. Щелчок по тексту — печать, щелчок рядом — выбор блока, Esc — вверх, Enter — вниз. Один каталог («Текст» и «Блоки», группы, варианты с картинками, поиск, избранное, недавние) служит «+» между блоками, «/» в тексте и библиотеке; блоки двигаются за ручку с линиями места или Alt+стрелками, а сброс рядом с блоком делит место на колонки. Панель параметров говорит, откуда каждое значение (тип, тема, вариант, блок, экран), и задаёт значения по экранам; вкладка «Данные» связывает блок с источником хоста через порт источников. Конструктор блоков создаёт и меняет блоки сайта везде; шаблон сайта — отдельная явная правка. Права и тема приходят от хоста. Одна история отмены; результат — JSON, HTML и Markdown. | +| Контракт | `smart.editor`, версия `1.1.0` | +| Поставка | пакет `pro` (`SF_BOOT_CONFIG.packages.pro`) | +| [Жизненный цикл](/ru/guide/smart-components/quality/#готовность-компонента-к-использованию) | экспериментальный: API может меняться между выпусками | +| [Готовность](/ru/guide/smart-components/quality/#готовность-компонента-к-использованию) | `host-required` | + +### Атрибуты + +- `template` — `string`, по умолчанию `default`. Имя варианта шаблона для внешних шаблонов SfBaseElement. +- `root-class` — `string`, по умолчанию пусто. Классы, которые добавляются корневому элементу, нарисованному компонентом. +- `root-style` — `string`, по умолчанию пусто. Объявления стиля, которые ставятся корневому элементу, нарисованному компонентом, в том числе пользовательские свойства. +- `screen` — `string`, по умолчанию `desktop`, значения: `desktop`, `tablet`, `phone`. Экран, для которого рисуется страница и задаются значения: desktop (lg), tablet (md), phone (xs). +- `preferences-key` — `string`, по умолчанию пусто. Где хранятся избранные и недавние блоки через SF.Preferences (sf-editor/<key>); пусто — только на время сеанса. +- `heading` — `string`, по умолчанию пусто. Название редактируемой страницы в начале верхней строки (имя страницы у хоста). +- `caption` — `string`, по умолчанию пусто. Короткая строка под названием: где живёт страница или её состояние (слова хоста). +- `label` — `string`. Доступное имя страницы. +- `document` — `object`, по умолчанию `null`. Страница: Composition Document профиля ui-layout (layout.page или layout.regions с областями banner, main и contentinfo для страницы с шаблоном сайта). Новый документ начинает новую правку; документ, который редактор сам отправил в change, узнаётся и сохраняется. +- `types` — `array`, по умолчанию `[]`. Свои типы блоков хоста рядом с типами SIMAI Framework; их отрисовщики приходят в renderers. +- `renderers` — `object`, по умолчанию `null`. Отрисовщики типов хоста: страница рисуется ими так, как её рисует сайт. +- `editor-manifests` — `array` из `object`, по умолчанию `[]`. Манифесты редактора композиции для типов хоста или заменяющие манифесты SIMAI Framework: по ним строится панель параметров. +- `site-blocks` — `array`, по умолчанию `[]`. Собственные блоки сайта из конструктора блоков; в каталоге предлагается новейшая версия каждого. +- `words` — `object`, по умолчанию `null`. Слова блоков хоста по локалям. +- `rights` — `object`, по умолчанию `null`. Что человеку можно менять, по данным хоста: layout false позволяет автору писать только внутри текстовых областей; template false держит шаблон сайта закрытым; builder false скрывает конструктор блоков. Переключателя ролей в редакторе нет. +- `theme` — `object`, по умолчанию `null`. Тема сайта: её значения по умолчанию — один из уровней происхождения значения, её атрибуты ставятся на нарисованную страницу. Редактор её никогда не меняет; settings_url ведёт туда, где её меняют. + +### Методы + +- `select(id: any)` — возвращает `object`. Выбирает блок так же, как нажатие; без id выбор снимается. +- `edit(id: any)` — возвращает `object`. Ставит курсор в конец текстового блока. +- `insert(type: string, variant: any, after: any)` — возвращает `object`. Добавляет блок типа (и варианта) после блока или туда, где он первым подходит; значение — id нового блока. +- `undo()` — возвращает `object`. Шаг назад, как ⌘Z: набор текста и структура — одна история. +- `redo()` — возвращает `object`. Шаг вперёд, как ⇧⌘Z. +- `setParameter(id: any, key: string, value: string, screen: any)` — возвращает `object`. Задаёт параметр блока, для экрана — если значение различается по экранам. +- `editTemplate(on: boolean)` — возвращает `object`. Начинает (или, при false, заканчивает) правку шаблона сайта: шапки и подвала всех страниц. +- `buildBlock(id: any, type: string)` — возвращает `object`. Открывает конструктор блоков: новый блок сайта, блок из выбранного блока или блок сайта, который нужно изменить везде. +- `output(format: any)` — возвращает `object`. Страница как JSON, HTML (классы утилит) или Markdown её текстовых областей; значение — текст. + +### События + +Все события приходят на сам элемент и всплывают. Что означает глагол в имени события, говорит общий словарь: [Имена и общие слова](/ru/guide/smart-components/names/). Общие события базового элемента перечислены в главе [Модель компонента → Базовый интерфейс](/ru/guide/smart-components/model/#базовый-интерфейс). + +- `change` — `detail`: `{ document: object, reason: string, scope: any }`. Страница изменилась: {document, reason, scope}. Хост сохраняет документ; scope template означает шапку или подвал всех страниц. +- `sf-editor-select` — `detail`: `{ ids: array }`. Выбран блок: {ids}; пусто, если не выбран ни один. +- `sf-editor-block-save` — `detail`: `{ manifest: object, words: object, changes: array }`. Сохранён блок сайта: {manifest, words, changes}. Сохраните манифест в site-blocks. + +### Доступность + +- Роль: группа (`group`). +- Доступное имя: внутренний. +- Клавиши: `Tab`, `Enter`, `Escape`, `ArrowUp`, `ArrowDown`, `Alt+ArrowUp`, `Alt+ArrowDown`, `Meta+Z`. +- Фокус: Страница — одна остановка Tab; Enter и Esc двигают по глубине, стрелки — по соседям; панели — элементы управления SIMAI Framework в порядке Tab; изменения сообщаются в строке состояния. + +### Минимальная разметка + +```html + +``` + +### Источник + +- `simai/ui-pro@0516a01732c81983bc88a0db311c876c21666679:components/src/smart/editor` +- `simai/ui-pro@0516a01732c81983bc88a0db311c876c21666679:components/src/smart/editor/rule.js#name=cl-editor` + +## См. также + +- [Редактор содержимого](/ru/pro/editor/content-editor/) — страница одним потоком текста. +- [Свои блоки](/ru/pro/editor/blocks/) — как сделать свой блок для каталога редактора. +- [Редактор раскладки](/ru/guide/layouts/editor/overview/) — части, из которых собран редактор. diff --git a/content/ru/pro/editor/editor.page.json b/content/ru/pro/editor/editor.page.json new file mode 100644 index 000000000..c005d68a2 --- /dev/null +++ b/content/ru/pro/editor/editor.page.json @@ -0,0 +1,6 @@ +{ + "schema": "docara.page.v1", + "navigation": { + "order": 5 + } +} diff --git a/content/ru/pro/editor/index.md b/content/ru/pro/editor/index.md index fcdf6fa96..3152214a4 100644 --- a/content/ru/pro/editor/index.md +++ b/content/ru/pro/editor/index.md @@ -1,10 +1,11 @@ --- title: "Редактор страниц" -description: "Редактор страниц — 1 компонент SIMAI Pro." +description: "Редактор страниц — 2 компонента SIMAI Pro." profile: reference --- # Редактор страниц +- [Редактор страниц](/ru/pro/editor/editor/) — Единый редактор блоков страницы: раскладка и текст — один документ, глубина вместо режимов. - [Редактор содержимого](/ru/pro/editor/content-editor/) — Страница набирается одним потоком: блоки, меню «/» и «+», параметры блока; документ сохраняет приложение. - [Свои блоки](/ru/pro/editor/blocks/) — как сделать свой блок для каталога редактора: шаблон, генератор и проверка. diff --git a/content/ru/pro/index.md b/content/ru/pro/index.md index d1eac4983..468f6b90c 100644 --- a/content/ru/pro/index.md +++ b/content/ru/pro/index.md @@ -70,5 +70,6 @@ SIMAI Framework распространяется по лицензии Apache-2. Редактор содержимого страниц блоками: меню «/», параметры блока, картинки и файлы. +- [Редактор страниц](/ru/pro/editor/editor/) - [Редактор содержимого](/ru/pro/editor/content-editor/) - [Свои блоки](/ru/pro/editor/blocks/) — как сделать свой блок для каталога редактора: шаблон, генератор и проверка. diff --git a/content/ru/pro/mail/mail-canvas.md b/content/ru/pro/mail/mail-canvas.md index b9eb0cece..e193e5525 100644 --- a/content/ru/pro/mail/mail-canvas.md +++ b/content/ru/pro/mail/mail-canvas.md @@ -7,7 +7,7 @@ description: "Готовое письмо в рамке, которая ниче `` — холст редактора писем: готовое письмо в рамке, которая ничего не запускает, переключатель ширины над ним, две заметки о письме («устарел» и -«тяжёлое») и `sf-composition-overlay` сверху — рамки, панель действий и дерево для +«тяжёлое») и `sf-editor-overlay` сверху — рамки, панель действий и дерево для клавиатуры. Элемент не знает письма и рендерера: приложение передаёт отрисованный HTML и данные о нём, а элемент сообщает, что сделал человек. @@ -74,7 +74,7 @@ canvas.html = renderedLetter; | `stale` | заметка «предпросмотр устарел»; картинка остаётся прежней | | `weight` | `{bytes, max}` в килобайтах — предупреждение о весе; пусто — заметки нет | | `items` | что есть в письме для оверлея: `{id, label, kind, parent, editable, rect}` | -| `actions` | панель действий выбранного блока: `{id, label, icon, shortcut, disabled, tone}`, до 16 (см. документацию `sf-composition-overlay`) | +| `actions` | панель действий выбранного блока: `{id, label, icon, shortcut, disabled, tone}`, до 16 (см. документацию `sf-editor-overlay`) | | `accepts` | группы `sf-sortable`, которые можно бросать на письмо, через пробел | | `overlay-target` | `id` оверлея, поставленного хостом в другом месте страницы | @@ -146,7 +146,7 @@ canvas.html = renderedLetter; Свой оверлей элемента лежит внутри прокручиваемой области, перед рамкой: рамки и панель едут вместе с письмом. Над письмом в области есть отступ для панели, поэтому она стоит над блоком и у первого блока. `contain: layout` у предка ему не мешает -(simai/ui-source#58 закрыт в `sf-composition-overlay` 1.2.5). +(simai/ui-source#58 закрыт в `sf-editor-overlay` 1.2.5). Оверлей можно поставить и в другом месте страницы, но вне области он следует за прокруткой скриптом, с задержкой в кадр. Поэтому `overlay-target` нужен, только если @@ -157,7 +157,7 @@ canvas.html = renderedLetter;
- +
``` @@ -169,7 +169,7 @@ canvas.html = renderedLetter; ## Доступность Сначала переключатель ширины, затем дерево оверлея; рамка и ссылки письма в порядок -Tab не входят. Клавиши дерева и панели — у `sf-composition-overlay` (см. его +Tab не входят. Клавиши дерева и панели — у `sf-editor-overlay` (см. его документацию): стрелки, Home и End, Enter к панели или правке, Escape. После щелчка по письму те же клавиши работают и внутри рамки. Заметка о весе — строка состояния. У рамки и слоя есть имена на языке страницы. diff --git a/content/ru/pro/mail/mail-inspector.md b/content/ru/pro/mail/mail-inspector.md index 19c22b41c..33c5ef75b 100644 --- a/content/ru/pro/mail/mail-inspector.md +++ b/content/ru/pro/mail/mail-inspector.md @@ -69,13 +69,13 @@ panel.sections = [ | `kind` | Что это | Своё | |:---|:---|:---| | `text` | `sf-input` | `inputmode`, `inheritedValue`, `ariaLabel` | -| `multiline` | `sf-textarea`, растёт от двух строк до двенадцати | `inheritedValue`, `ariaLabel` | +| `multiline` | `sf-input-textarea`, растёт от двух строк до двенадцати | `inheritedValue`, `ariaLabel` | | `link` | `sf-input` для адреса | как у `text` | | `number` | `sf-input` с цифровой клавиатурой | как у `text`; `inputmode: 'decimal'` для цены | | `select` | `sf-dropdown` | `options: [{value, text}]`; `value: ''` — выбор «ничего» | | `switch` | `sf-switch` | `value` — логическое | | `group` | поля под одним именем, цена например | `rows: [[поле, поле], [поле]]`; ряд из двух стоит парой | -| `image` | `sf-image-field` | `value: {value, label, mime, size, href}` или `null`, `accept`, `emptyText`, `ariaLabel`, `choices: [{value, text}]`, `chooseLabel`, `choosePlaceholder` | +| `image` | `sf-input-image` | `value: {value, label, mime, size, href}` или `null`, `accept`, `emptyText`, `ariaLabel`, `choices: [{value, text}]`, `chooseLabel`, `choosePlaceholder` | | `items` | список на `sf-sortable` | `items: [{label, problem, fields}]`, `open`, `min`, `max` | `hint` — настоящий текст под полем: так значение из бренда слышит и читатель diff --git a/content/ru/pro/mail/mail-letters.md b/content/ru/pro/mail/mail-letters.md index b9b8c63e8..9000f2678 100644 --- a/content/ru/pro/mail/mail-letters.md +++ b/content/ru/pro/mail/mail-letters.md @@ -98,7 +98,7 @@ list.addEventListener('sf-mail-letters-delete', async (event) => { - Порядок `Tab`: сначала панель — поиск, порядок, «Новое письмо», — затем у каждой строки «Открыть» и ⋯. -- Меню строки — `sf-context-menu` со своей клавиатурой. +- Меню строки — `sf-menu-context` со своей клавиатурой. - Имя кнопки ⋯ называет письмо: «Действия с письмом: <название>», поэтому две строки не звучат одинаково. diff --git a/content/ru/smart/actions/close.md b/content/ru/smart/actions/close.md index 2c98f5f56..8f2eabdd9 100644 --- a/content/ru/smart/actions/close.md +++ b/content/ru/smart/actions/close.md @@ -5,13 +5,13 @@ description: "Рисует знак закрытия внутри кнопки, # Закрытие -`` рисует только знак закрытия — крестик нужного размера. Это не +`` рисует только знак закрытия — крестик нужного размера. Это не кнопка: её даёт нативный ` ``` diff --git a/content/ru/smart/actions/confirm.md b/content/ru/smart/actions/confirm.md new file mode 100644 index 000000000..888ef51f1 --- /dev/null +++ b/content/ru/smart/actions/confirm.md @@ -0,0 +1,134 @@ +--- +title: "Подтверждение" +description: "Вопрос человеку прямо на месте: что случится, два ответа, ожидание, итог и срок." +--- + +# Подтверждение + +`` задаёт человеку вопрос там, где он работает: удалить файл в его +строке, убрать участника, вернуть вид раздела. Компонент показывает, что +случится, два ответа, ожидание, пока ответ применяется, и итог. Сам он ничего +не применяет: нажатие — это событие, а действие выполняет страница. + +Окно поверх страницы для такого вопроса не нужно: вопрос стоит в потоке, рядом +с тем, о чём спрашивает. Если нужно показать, каким станет каждое значение, +берите [Подтверждение изменения](/ru/pro/admin/change-confirm/). + +## Пример + +:::example {id="smart-components/confirm/overview" label="Удаление в строке"} +::: + +## Разметка + +```html + +``` + +`question` — вопрос целым предложением: он же имя группы ответов. Без него +группа называется «Подтверждение». `confirm-id` — имя вопроса у страницы +(строка, запись); оно приходит в каждом событии. + +```js +confirm.addEventListener('sf-confirm-answer', (event) => { + if (!event.detail.accepted) return; + removeFile(event.detail.id) + .then(() => { confirm.state = 'accepted'; }) + .catch(() => { event.target.state = 'open'; }); +}); +``` + +Нажатый ответ переводит вопрос в `pending`. Страница ставит итог — +`accepted` или `declined`, а если применить не удалось, возвращает `open`. +Отменённое событие `sf-confirm-answer` оставляет вопрос открытым. + +## Варианты + +### В карточке + +`appearance="card"` ставит вопрос в рамку со своим отступом. Пояснение — +в месте `description`. + +:::example {id="smart-components/confirm/card" label="В карточке, с пояснением"} +::: + +### Ожидание, итог и срок + +`state` показывает, где вопрос: `open` — ответы предложены, `pending` — ответ +отправлен, `accepted`, `declined`, `expired` — виден только итог. +`expires-at` (ISO 8601) задаёт срок: после него открытый вопрос читается как +истёкший и один раз сообщает об этом событием `sf-confirm-expired`. + +:::example {id="smart-components/confirm/states" label="Ожидание, итог, время вышло"} +::: + +## Доступность + +- Вопрос — группа, названная самим вопросом. Строка состояния — вежливая + живая область: она есть на странице до того, как заговорит. +- Когда нажатие убирает ответы, фокус переходит на строку состояния, а не + падает на страницу; если страница вернула вопрос в `open`, фокус + возвращается к первому ответу. +- `Tab` доходит до ответов, `Enter` и `Space` отвечают, `Escape` внутри + открытого вопроса — тот же ответ, что «Отмена». +- `destructive` красит принимающий ответ цветом ошибки: так видно, что + действие что-то уничтожает. + +## Справочник + +Собран из манифеста компонента выпуска `ui-e22fefb3c1f8` и обновляется вместе с выпуском. Чтобы исправить описание, исправьте манифест. + +### Атрибуты + +| Атрибут | Тип | По умолчанию | Значения | Что делает | +|:---|:---|:---|:---|:---| +| `template` | строка | `default` | — | Имя варианта шаблона для внешних шаблонов SfBaseElement. | +| `root-class` | строка | пусто | — | Классы, которые добавляются корневому элементу, нарисованному компонентом. | +| `root-style` | строка | пусто | — | Объявления стиля, которые ставятся корневому элементу, нарисованному компонентом, в том числе пользовательские свойства. | +| `question` | строка | пусто | — | Вопрос, сказанный на месте: что произойдёт, одним предложением («Удалить файл «Отчёт.pdf»?»). Он же называет группу; без него группа называется «Подтверждение». | +| `state` | строка | `open` | `open`, `pending`, `accepted`, `declined`, `expired` | open: ответы предложены. pending: ответ отправляется (ставится нажатием). accepted, declined, expired: виден только итог. | +| `expires-at` | строка | пусто | — | ISO 8601. После этого срока открытый вопрос считается истёкшим и один раз сообщает об этом событием `sf-confirm-expired`. | +| `confirm-id` | строка | пусто | — | Имя вопроса у хоста (строка, запись); возвращается в каждом событии. | +| `disabled` | да/нет | нет | — | Ответы видны, но их нельзя нажать (где-то уже идёт отправка). | +| `destructive` | да/нет | нет | — | Согласие что-то уничтожает (удаление): у принимающего ответа статус error. | +| `appearance` | строка | `inline` | `inline`, `card` | inline: вопрос и ответы в потоке строки, без своей рамки. card: в карточке с рамкой и собственным отступом. | +| `accept-text` | строка | — | — | Слова ответа «да»; пусто — «Подтвердить» на языке страницы. | +| `decline-text` | строка | — | — | Отказывающий ответ; пусто — «Отмена» на языке страницы. | + +Каждому атрибуту соответствует свойство элемента с тем же именем в camelCase: `icon-start` — `iconStart`. Свойство атрибута `template` называется `templateName`. + +### Методы + +| Метод | Возвращает | Что делает | +|:---|:---|:---| +| `open()` | объект | Задаёт вопрос снова; если его попросила сборка, отвечает `{accepted, reason, value}`, когда человек ответил или время вышло. | +| `answer(accepted: boolean)` | объект | Отвечает, как ответил бы человек: `accepted` true подтверждает, false отказывается. Отказ: `unknown`, `closed`, `disabled` или `prevented`. | +| `confirm()` | объект | Согласие; `data-sf-action=".confirm"`. | +| `cancel()` | объект | Отказывающий ответ; `data-sf-action=".cancel"`. Escape внутри открытого вопроса — тот же ответ. | + +### События + +События приходят на сам элемент и всплывают; глаголы в именах — из [общего словаря](/ru/guide/smart-components/names/). Общие события базового элемента — в главе [Модель компонента](/ru/guide/smart-components/model/#базовый-интерфейс). + +| Событие | `detail` | Когда приходит | +|:---|:---|:---| +| `sf-confirm-answer` | `{ id: any, accepted: boolean }` | Человек ответил (слово словаря answer). Отмените событие, чтобы вопрос остался открытым. | +| `sf-confirm-expired` | `{ id: any }` | Открытый вопрос дождался `expires-at`; сообщается один раз на каждый срок. | + +### О компоненте + +| | | +|:---|:---| +| Тег | ``, контракт `smart.confirm` версии `1.0.0` | +| Поставка | выпуск Framework `ui-e22fefb3c1f8` | +| [Готовность](/ru/guide/smart-components/quality/#готовность-компонента-к-использованию) | экспериментальный: API может меняться между выпусками; `host-required` | +| До прихода кода | нет: атрибут `data-sf-skeleton` не пишется; своего скелетона при загрузке данных нет ([Коробка до кода](/ru/guide/smart-components/first-paint/#коробка-до-кода)) | +| Доступность | роль группа (`group`); доступное имя внутренний; клавиши `Tab`, `Enter`, `Space`, `Escape` | +| Источник | `simai/ui@e22fefb3c1f8bed4c7ad8d8745a408ecedc5029f:distr/smart/confirm` | +| Правило классов | `simai/ui@e22fefb3c1f8bed4c7ad8d8745a408ecedc5029f:distr/rule/rule.json#name=cl-confirm` | + +## См. также + +- [Подтверждение изменения](/ru/pro/admin/change-confirm/) — как было и как станет для каждого значения. +- [Модальное окно](/ru/smart/overlays/modal/) — когда вопрос должен остановить всю страницу. diff --git a/content/ru/smart/actions/confirm.page.json b/content/ru/smart/actions/confirm.page.json new file mode 100644 index 000000000..656a0614d --- /dev/null +++ b/content/ru/smart/actions/confirm.page.json @@ -0,0 +1,6 @@ +{ + "schema": "docara.page.v1", + "navigation": { + "order": 35 + } +} diff --git a/content/ru/smart/actions/copy-button.md b/content/ru/smart/actions/copy-button.md index e7825fd4f..b8fffa80f 100644 --- a/content/ru/smart/actions/copy-button.md +++ b/content/ru/smart/actions/copy-button.md @@ -5,7 +5,7 @@ description: "Копирует значение или текст элемент # Кнопка копирования -`` копирует значение и сообщает о результате: значок на миг +`` копирует значение и сообщает о результате: значок на миг становится галочкой, а «Скопировано» вежливо объявляется для чтения с экрана. Берите его, когда копируется содержимое другого элемента (`target`), нужно сообщение о результате и запасной путь там, где буфер обмена недоступен. @@ -24,8 +24,8 @@ description: "Копирует значение или текст элемент ```html sk_test_51H… - - + + ``` Источник задаёт один из двух атрибутов: diff --git a/content/ru/smart/actions/download-file.md b/content/ru/smart/actions/download-file.md index fa6439892..d7c7c5131 100644 --- a/content/ru/smart/actions/download-file.md +++ b/content/ru/smart/actions/download-file.md @@ -5,7 +5,7 @@ description: "Показывает файл для скачивания с им # Скачивание файла -`` показывает файл, который можно скачать: иконку, имя и +`` показывает файл, который можно скачать: иконку, имя и размер. С адресом он становится нативной ссылкой, без адреса — кнопкой, по которой приложение само готовит файл. @@ -22,8 +22,8 @@ description: "Показывает файл для скачивания с им Готовый файл — ссылка с адресом, именем и размером: ```html - + ``` `href` с адресом файла рисует ссылку. С `download` браузер скачивает файл под diff --git a/content/ru/smart/actions/icon-buttons.md b/content/ru/smart/actions/icon-buttons.md index 03e5852f9..09a3ef695 100644 --- a/content/ru/smart/actions/icon-buttons.md +++ b/content/ru/smart/actions/icon-buttons.md @@ -5,7 +5,7 @@ description: "Запускает действие компактной кноп # Кнопки с иконкой -`` — кнопка с одной иконкой вместо подписи: изменить, +`` — кнопка с одной иконкой вместо подписи: изменить, поделиться, закрыть, открыть меню. Берите её в панелях инструментов и строках таблиц, где подпись не помещается, а смысл иконки понятен; если сомневаетесь, берите [кнопку с подписью](/ru/smart/actions/buttons/). @@ -23,7 +23,7 @@ description: "Запускает действие компактной кноп Кнопке нужны иконка и доступное имя: ```html - + ``` `icon` — имя иконки Material Symbols, по умолчанию `add`. Свою разметку @@ -165,15 +165,15 @@ remove.onClick(() => deleteRow(row)); ### Атрибуты `data-*` и фокус Как у [Кнопки](/ru/smart/actions/buttons/#атрибуты-data-и-фокус), -атрибут `data-*` с `` переносится на внутреннюю нативную +атрибут `data-*` с `` переносится на внутреннюю нативную кнопку: у неё есть размеры, она получает фокус и нажатие, поэтому селектор `[data-…]` находит ровно один элемент — её. Хост своей области не имеет -(`display: contents`), к нему ведёт `closest('sf-icon-button')`. +(`display: contents`), к нему ведёт `closest('sf-button-icon')`. ```js const toggle = menu.querySelector('[data-search-toggle]'); // нативная кнопка toggle.focus(); -toggle.closest('sf-icon-button'); // хост +toggle.closest('sf-button-icon'); // хост ``` Записанное на хосте читает свойство `dataAttributes` diff --git a/content/ru/smart/actions/index.md b/content/ru/smart/actions/index.md index 6efb55f22..78f71af44 100644 --- a/content/ru/smart/actions/index.md +++ b/content/ru/smart/actions/index.md @@ -1,6 +1,6 @@ --- title: "Действия" -description: "Действия — 7 смарт-компонентов SIMAI Framework." +description: "Действия — 8 смарт-компонентов SIMAI Framework." profile: reference --- @@ -13,3 +13,4 @@ profile: reference - [Закрытие](/ru/smart/actions/close/) — Рисует знак закрытия внутри кнопки, которую задаёт страница. - [Скачивание файла](/ru/smart/actions/download-file/) — Показывает файл для скачивания с именем и размером и сообщает о нажатии. - [Кнопка копирования](/ru/smart/actions/copy-button/) — Копирует значение или текст элемента, показывает результат галочкой и сообщает о нём экранному диктору. +- [Подтверждение](/ru/smart/actions/confirm/) — Вопрос человеку прямо на месте: что случится, два ответа, ожидание, итог и срок. diff --git a/content/ru/smart/composite/page-header.md b/content/ru/smart/composite/page-header.md index ae0be663d..a9f04c99e 100644 --- a/content/ru/smart/composite/page-header.md +++ b/content/ru/smart/composite/page-header.md @@ -5,7 +5,7 @@ description: "Показывает в начале страницы админи # Шапка страницы -`` — шапка страницы административного приложения: путь к +`` — шапка страницы административного приложения: путь к странице, заголовок, число записей, звезда избранного и главные действия в одной строке. Ставьте её в начало каждой страницы администрирования рядом с [Меню администратора](/ru/pro/admin/admin-menu/): меню показывает, где @@ -21,10 +21,10 @@ description: "Показывает в начале страницы админи Шапке нужен заголовок; путь и действия передаются в слоты: ```html - + - + ``` `heading` — название страницы. Компонент выводит его как `h1` четвёртой @@ -80,7 +80,7 @@ description: "Показывает в начале страницы админи Кнопкам в слоте `actions` берите ступень остальных элементов страницы: рядом с полями `sf-input--size-1` — кнопки размера 1 (`size="1"` у смарт-кнопки, `sf-button--size-1` у классовой). Кнопка только со значком называется -своим атрибутом: `label` у ``, `aria-label` у классовой +своим атрибутом: `label` у ``, `aria-label` у классовой кнопки. Своих отступов по краям у шапки нет: она встаёт в контейнер страницы с @@ -89,10 +89,10 @@ description: "Показывает в начале страницы админи ```html
- + … - - + +
…
``` @@ -107,7 +107,7 @@ description: "Показывает в начале страницы админи состояние, которое не сохранилось. ```js -const header = document.querySelector('sf-page-header'); +const header = document.querySelector('sf-header-page'); header.addEventListener('sf-page-header-toggle', async (event) => { event.preventDefault(); const saved = await saveFavourite(event.detail.on); diff --git a/content/ru/smart/composite/search.md b/content/ru/smart/composite/search.md index 77378a185..67a74db6b 100644 --- a/content/ru/smart/composite/search.md +++ b/content/ru/smart/composite/search.md @@ -39,7 +39,7 @@ description: "Окно поиска по сайту: крупное поле, ф Кнопка-вызов в другом месте страницы: ```html - + ``` diff --git a/content/ru/smart/composite/site-header.md b/content/ru/smart/composite/site-header.md index cc6f670f7..8f136ed3a 100644 --- a/content/ru/smart/composite/site-header.md +++ b/content/ru/smart/composite/site-header.md @@ -5,7 +5,7 @@ description: "Верхняя полоса сайта: бренд, разделы # Шапка сайта -`` — верхняя полоса сайта: бренд, разделы, ссылки и +`` — верхняя полоса сайта: бренд, разделы, ссылки и инструменты в одну строку по ширине контейнера. На узком экране разделы и ссылки уходят в боковую панель, которую открывает кнопка меню. Одна шапка для всех сайтов SIMAI: каталога эффектов, сайтов документации и портала. @@ -26,7 +26,7 @@ description: "Верхняя полоса сайта: бренд, разделы и состояние сохраняются: ```html - + SIMAI GitHub - + ``` | Слот | В широкой строке | На узком экране | @@ -107,7 +107,7 @@ description: "Верхняя полоса сайта: бренд, разделы `outside`, `cancelled` или `api`. ```js -const header = document.querySelector('sf-site-header'); +const header = document.querySelector('sf-header-site'); header.addEventListener('sf-site-header-opened', () => { header.querySelector('[slot="sheet"]')?.replaceChildren(buildDocumentationTree()); }); diff --git a/content/ru/smart/content/avatars.md b/content/ru/smart/content/avatars.md index 9f7d0108e..3fae1adf5 100644 --- a/content/ru/smart/content/avatars.md +++ b/content/ru/smart/content/avatars.md @@ -5,7 +5,7 @@ description: "Выводит готовые сочетания аватаров: # Аватары -`` собирает из аватаров готовые сочетания: человек с источником, +`` собирает из аватаров готовые сочетания: человек с источником, группа с остатком, аватар с двумя строками подписи, аватар профиля. Для одного аватара, аватара с подписью и карточки берите [Аватар](/ru/smart/content/avatar/) — у него есть имя для @@ -24,7 +24,7 @@ description: "Выводит готовые сочетания аватаров: Сочетание выбирает `template`, остальное — атрибуты этого шаблона: ```html - + ``` - `user` — изображение из `image-url`, имя из `name` и источник из `source` @@ -55,9 +55,9 @@ description: "Выводит готовые сочетания аватаров: `tiny`, `small`, `big`, `extra_big`. ```html - + avatars-more="5"> ``` ## Доступность diff --git a/content/ru/smart/content/gallery.md b/content/ru/smart/content/gallery.md index 89beb03c3..10a2391eb 100644 --- a/content/ru/smart/content/gallery.md +++ b/content/ru/smart/content/gallery.md @@ -86,7 +86,7 @@ description: "Показывает набор материалов слайде Смена материала отправляет `change`, открытие и закрытие окна — `sf-gallery-opened` и `sf-gallery-closed` (прежние имена — `sf-change`, -`sf-open` и `sf-close` — приходят с тем же `detail`). Все три всплывают; в +`sf-open` и `sf-button-close` — приходят с тем же `detail`). Все три всплывают; в `event.detail` приходят `current` и `total`, а у `change` ещё `previous` и `from` — откуда пришла смена: `inline`, `lightbox` или `api`. diff --git a/content/ru/smart/editor/composition-overlay.md b/content/ru/smart/editor/composition-overlay.md index 5f72e4718..2dd10a12e 100644 --- a/content/ru/smart/editor/composition-overlay.md +++ b/content/ru/smart/editor/composition-overlay.md @@ -5,7 +5,7 @@ description: "Рисует поверх отрисованной страниц # Оверлей редактора -`` — часть редактора страниц: рисует поверх страницы, +`` — часть редактора страниц: рисует поверх страницы, собранной из Composition Document, рамку при наведении и выборе, подпись и значки узла, панель действий, место вставки у стыка блоков и дерево структуры для клавиатуры. HTML холста оверлей не меняет, поэтому опубликованная страница @@ -22,7 +22,7 @@ description: "Рисует поверх отрисованной страниц Оверлей ставят перед холстом и называют холст атрибутом `for`: ```html - +

О компании

@@ -34,8 +34,8 @@ description: "Рисует поверх отрисованной страниц отмечен в нём атрибутом `data-sf-composition-id`. Атрибут `for` называет `id` холста, метод `attach(canvas)` передаёт его явно. Код оверлея загрузчик SIMAI Framework подключает по требованию — только на странице с тегом -`sf-composition-overlay`, поэтому перед вызовом методов дождитесь -`customElements.whenDefined('sf-composition-overlay')`. +`sf-editor-overlay`, поэтому перед вызовом методов дождитесь +`customElements.whenDefined('sf-editor-overlay')`. Оверлей ставят перед холстом, внутри той же прокручиваемой области: дерево идёт первым в порядке `Tab`, а рамки и панель лежат в прокручиваемом @@ -160,7 +160,7 @@ Document оверлею. или английском). `setMessages(messages)` заменяет их своими. ```js -await customElements.whenDefined('sf-composition-overlay'); +await customElements.whenDefined('sf-editor-overlay'); overlay.attach(canvas); overlay.setDocument(document, { describe: (node) => ({label: titleOf(node), badges: node.shared ? ['Общий'] : []}), diff --git a/content/ru/smart/editor/inline-editor.md b/content/ru/smart/editor/inline-editor.md index 1e1c50191..374541ab0 100644 --- a/content/ru/smart/editor/inline-editor.md +++ b/content/ru/smart/editor/inline-editor.md @@ -5,7 +5,7 @@ description: "Даёт править текст заголовков и абз # Inline-редактор -`` — часть редактора страниц: правка текста +`` — часть редактора страниц: правка текста `content.heading` и `content.paragraph` прямо на холсте. Доступно то, что есть в модели content: полужирный, курсив, код, ссылки и встроенные компоненты (`badge`, `kbd`, `icon`, `button`); списков нет, потому что их нет в модели. События несут нормализованную модель, а не HTML. @@ -18,11 +18,11 @@ description: "Даёт править текст заголовков и абз ## Разметка Элемент ничего не показывает: достаточно поставить на странице -``, и загрузчик SIMAI Framework подключит код редактора по +``, и загрузчик SIMAI Framework подключит код редактора по требованию. ```html - +

Доставка по городу — бесплатно.

``` @@ -30,7 +30,7 @@ description: "Даёт править текст заголовков и абз кода. Правку запускает `SF.Composition.startInlineEdit(element, options)` или метод `edit(element, options)` элемента. До загрузки вызов завершается ошибкой `inline_editor_not_loaded`, поэтому сначала дождитесь -`customElements.whenDefined('sf-inline-editor')`. Повторный запуск на элементе, +`customElements.whenDefined('sf-editor-inline')`. Повторный запуск на элементе, который уже правится, завершается ошибкой `inline_edit_active`. ## Поведение @@ -65,7 +65,7 @@ description: "Даёт править текст заголовков и абз и перерисовывайте страницу. ```js -await customElements.whenDefined('sf-inline-editor'); +await customElements.whenDefined('sf-editor-inline'); SF.Composition.startInlineEdit(element, { content: node.data.content, nodeId: node.id, diff --git a/content/ru/smart/forms/code-input.md b/content/ru/smart/forms/code-input.md index 894454b27..3fbaf3ba9 100644 --- a/content/ru/smart/forms/code-input.md +++ b/content/ru/smart/forms/code-input.md @@ -5,14 +5,14 @@ description: "Поле одноразового кода из сообщения # Код подтверждения -`` — поле одноразового кода из сообщения, приложения-генератора +`` — поле одноразового кода из сообщения, приложения-генератора или письма: код хранит один обычный input, а ячейки его показывают. Берите его для кода, который человек получил и вводит или вставляет. PIN-код или пароль, который человек придумывает сам, вводят в [текстовое поле](/ru/smart/forms/inputs/) с `input-type="password"`. То же на классах — [Код подтверждения](/ru/components/forms/verification/): -`` собирает его разметку из атрибутов. +`` собирает его разметку из атрибутов. ## Пример @@ -24,7 +24,7 @@ description: "Поле одноразового кода из сообщения Минимальная разметка — тег с `label` и `name`: ```html - + ``` - Значение формы — один нативный input с именем `name` и diff --git a/content/ru/smart/forms/color.md b/content/ru/smart/forms/color.md index 74e104226..ebdd253bc 100644 --- a/content/ru/smart/forms/color.md +++ b/content/ru/smart/forms/color.md @@ -5,7 +5,7 @@ description: "Выбирает цвет системной палитрой ил # Цвет -`` — контрол выбора цвета: образец открывает системную палитру, +`` — контрол выбора цвета: образец открывает системную палитру, рядом стоят цвета, которые у продукта уже есть, а кнопка возврата снимает выбор, и снова действует унаследованный цвет. Берите его для цвета темы, внешнего вида сайта, метки или серии графика. @@ -21,7 +21,7 @@ description: "Выбирает цвет системной палитрой ил ```html Основной цвет - + ``` `label` задаёт доступное имя, но видимой подписи не выводит: видимую подпись diff --git a/content/ru/smart/forms/country-code.md b/content/ru/smart/forms/country-code.md index d7a192f2e..235fc8307 100644 --- a/content/ru/smart/forms/country-code.md +++ b/content/ru/smart/forms/country-code.md @@ -5,13 +5,13 @@ description: "Телефонное поле с выбором страны, фл # Код страны -`` — телефонное поле с кнопкой выбора страны: флаг и код +`` — телефонное поле с кнопкой выбора страны: флаг и код страны стоят перед номером, а маска подстраивается под выбранную страну. Для телефона без выбора страны хватит [поля ввода](/ru/smart/forms/inputs/) с маской. То же на классах — [Код страны](/ru/components/forms/country-code/): -`` собирает его разметку из атрибутов. +`` собирает его разметку из атрибутов. ## Пример @@ -23,7 +23,7 @@ description: "Телефонное поле с выбором страны, фл Полю нужна подпись, имя для формы и начальная страна: ```html - + ``` `label` — видимая подпись поля. Без `label` строки подписи нет вовсе, и @@ -71,7 +71,7 @@ description: "Телефонное поле с выбором страны, фл `dialCode`, `label` и необязательным `maskPattern`. Для известных кодов ISO пропущенные поля дополняются встроенным справочником. `max-items` ограничивает число стран в списке. Присваивайте свойство после регистрации элемента — -`await customElements.whenDefined('sf-country-code')`. +`await customElements.whenDefined('sf-input-country')`. :::example {id="components/country-code/smart-countries" label="Список из двух стран"} ::: @@ -124,7 +124,7 @@ description: "Телефонное поле с выбором страны, фл ### Состояние из кода и событие `change` Когда номер или страна зафиксированы, нативное событие `change` внутреннего -поля всплывает через ``; `detail` у него нет. Номер +поля всплывает через ``; `detail` у него нет. Номер читайте из `event.target.value`, а страну и код — из свойства `state`: `value`, `iso2`, `dialCode`, `open` и `disabled`. diff --git a/content/ru/smart/forms/datepicker.md b/content/ru/smart/forms/datepicker.md index e2888ffcd..8e99694e2 100644 --- a/content/ru/smart/forms/datepicker.md +++ b/content/ru/smart/forms/datepicker.md @@ -5,13 +5,13 @@ description: "Выбирает дату или период в календар # Календарь -`` — выбор одной даты или периода в календаре с переходом по +`` — выбор одной даты или периода в календаре с переходом по месяцам и годам. Берите его, когда дату удобнее найти в календаре, чем напечатать; если основной сценарий — ввод с клавиатуры, хватит [поля ввода](/ru/smart/forms/inputs/). То же на классах — [Календарь](/ru/components/forms/datepicker/): оформление -календаря `` берёт из этого компонента. +календаря `` берёт из этого компонента. ## Пример @@ -24,7 +24,7 @@ description: "Выбирает дату или период в календар открывается по щелчку или с клавиатуры: ```html - + ``` `label` выводит подпись над полем. Если подпись выводит сама страница — @@ -202,7 +202,7 @@ ISO принимается тоже: `14.10.2026` и `2026-10-14` дают од календарём: ```html - + - + appearance="bordered"
- + - + appearance="filled"
diff --git a/examples/smart-components/lookup/overview/index.html b/examples/smart-components/lookup/overview/index.html index 2ba189366..a310e5120 100644 --- a/examples/smart-components/lookup/overview/index.html +++ b/examples/smart-components/lookup/overview/index.html @@ -1,4 +1,4 @@ - - + diff --git a/examples/smart-components/lookup/single/index.html b/examples/smart-components/lookup/single/index.html index 5a7a611d5..0c64ab973 100644 --- a/examples/smart-components/lookup/single/index.html +++ b/examples/smart-components/lookup/single/index.html @@ -1,3 +1,3 @@ - + - + diff --git a/examples/smart-components/lookup/sizes/index.html b/examples/smart-components/lookup/sizes/index.html index e22f5f94c..0e9a1d8a9 100644 --- a/examples/smart-components/lookup/sizes/index.html +++ b/examples/smart-components/lookup/sizes/index.html @@ -1,20 +1,20 @@
- + - + size="1/2"
- + - + size="1"
- + - + size="2"
diff --git a/examples/smart-components/lookup/state-disabled/index.html b/examples/smart-components/lookup/state-disabled/index.html index 6df93784c..dfb4a5929 100644 --- a/examples/smart-components/lookup/state-disabled/index.html +++ b/examples/smart-components/lookup/state-disabled/index.html @@ -1,3 +1,3 @@ - + - + diff --git a/examples/smart-components/lookup/state-error/index.html b/examples/smart-components/lookup/state-error/index.html index 3e0726d56..72d66726b 100644 --- a/examples/smart-components/lookup/state-error/index.html +++ b/examples/smart-components/lookup/state-error/index.html @@ -1,3 +1,3 @@ - + - + diff --git a/examples/smart-components/lookup/state-readonly/index.html b/examples/smart-components/lookup/state-readonly/index.html index 62ed1e173..0045eee39 100644 --- a/examples/smart-components/lookup/state-readonly/index.html +++ b/examples/smart-components/lookup/state-readonly/index.html @@ -1,3 +1,3 @@ - + - + diff --git a/examples/smart-components/page-header/install/index.html b/examples/smart-components/page-header/install/index.html index 293b7acdb..16f4b61d3 100644 --- a/examples/smart-components/page-header/install/index.html +++ b/examples/smart-components/page-header/install/index.html @@ -1,4 +1,4 @@ - + - + diff --git a/examples/smart-components/page-header/overview/index.html b/examples/smart-components/page-header/overview/index.html index 8bb0967f7..5c2e998dc 100644 --- a/examples/smart-components/page-header/overview/index.html +++ b/examples/smart-components/page-header/overview/index.html @@ -1,5 +1,5 @@ - + - + diff --git a/examples/smart-components/page-header/state-star/index.html b/examples/smart-components/page-header/state-star/index.html index a1c8f0f89..e99e58af0 100644 --- a/examples/smart-components/page-header/state-star/index.html +++ b/examples/smart-components/page-header/state-star/index.html @@ -1,10 +1,10 @@
- + star="off"
- + star="on"
diff --git a/examples/smart-components/property-view/overview/index.html b/examples/smart-components/property-view/overview/index.html index 0b008e162..7ea6afcc7 100644 --- a/examples/smart-components/property-view/overview/index.html +++ b/examples/smart-components/property-view/overview/index.html @@ -1,5 +1,5 @@ - - +
diff --git a/examples/smart-components/property-view/overview/index.js b/examples/smart-components/property-view/overview/index.js index b6c1a83ed..f73629b14 100644 --- a/examples/smart-components/property-view/overview/index.js +++ b/examples/smart-components/property-view/overview/index.js @@ -74,7 +74,7 @@ const answer = () => { }; const initializeSolutionPropertyView = async () => { - await customElements.whenDefined('sf-property-view'); + await customElements.whenDefined('sf-view-properties'); const panel = document.querySelector('#solution-property-view'); if (!panel || panel.dataset.exampleReady === 'true') return; diff --git a/examples/smart-components/quantity/bounds/index.html b/examples/smart-components/quantity/bounds/index.html index 46519f06d..c04593e40 100644 --- a/examples/smart-components/quantity/bounds/index.html +++ b/examples/smart-components/quantity/bounds/index.html @@ -1,4 +1,4 @@
- - + +
diff --git a/examples/smart-components/quantity/decimals/index.html b/examples/smart-components/quantity/decimals/index.html index 55e6580f3..eff7be3c7 100644 --- a/examples/smart-components/quantity/decimals/index.html +++ b/examples/smart-components/quantity/decimals/index.html @@ -1,4 +1,4 @@
- - + +
diff --git a/examples/smart-components/quantity/inherited/index.html b/examples/smart-components/quantity/inherited/index.html index 107df15ab..de0bb176a 100644 --- a/examples/smart-components/quantity/inherited/index.html +++ b/examples/smart-components/quantity/inherited/index.html @@ -1 +1 @@ - + diff --git a/examples/smart-components/quantity/overview/index.html b/examples/smart-components/quantity/overview/index.html index cbe99cb94..d3d590a29 100644 --- a/examples/smart-components/quantity/overview/index.html +++ b/examples/smart-components/quantity/overview/index.html @@ -1 +1 @@ - + diff --git a/examples/smart-components/quantity/sizes/index.html b/examples/smart-components/quantity/sizes/index.html index bbd81347b..82cd87616 100644 --- a/examples/smart-components/quantity/sizes/index.html +++ b/examples/smart-components/quantity/sizes/index.html @@ -1,5 +1,5 @@
- - - + + +
diff --git a/examples/smart-components/quantity/state-bound/index.html b/examples/smart-components/quantity/state-bound/index.html index 7b7632f69..2698a54db 100644 --- a/examples/smart-components/quantity/state-bound/index.html +++ b/examples/smart-components/quantity/state-bound/index.html @@ -1,10 +1,10 @@
- + value="1" min="1"
- + value="8" max="8"
diff --git a/examples/smart-components/quantity/state-disabled/index.html b/examples/smart-components/quantity/state-disabled/index.html index 2bbed5129..6cd463949 100644 --- a/examples/smart-components/quantity/state-disabled/index.html +++ b/examples/smart-components/quantity/state-disabled/index.html @@ -1 +1 @@ - + diff --git a/examples/smart-components/quantity/state-error/index.html b/examples/smart-components/quantity/state-error/index.html index c645c9a23..82af54ad1 100644 --- a/examples/smart-components/quantity/state-error/index.html +++ b/examples/smart-components/quantity/state-error/index.html @@ -1 +1 @@ - + diff --git a/examples/smart-components/quantity/state-readonly/index.html b/examples/smart-components/quantity/state-readonly/index.html index 28101f49c..91d5d8f4a 100644 --- a/examples/smart-components/quantity/state-readonly/index.html +++ b/examples/smart-components/quantity/state-readonly/index.html @@ -1 +1 @@ - + diff --git a/examples/smart-components/range-slider/connect/index.html b/examples/smart-components/range-slider/connect/index.html index 650682540..c5ec4f80f 100644 --- a/examples/smart-components/range-slider/connect/index.html +++ b/examples/smart-components/range-slider/connect/index.html @@ -1,14 +1,14 @@
- + connect="lower"
- + connect="upper"
- + connect="false"
diff --git a/examples/smart-components/range-slider/handles/index.html b/examples/smart-components/range-slider/handles/index.html index 91988edb4..cc2587625 100644 --- a/examples/smart-components/range-slider/handles/index.html +++ b/examples/smart-components/range-slider/handles/index.html @@ -1,10 +1,10 @@
- + value="20"
- + value="10,30"
diff --git a/examples/smart-components/range-slider/label-position/index.html b/examples/smart-components/range-slider/label-position/index.html index 8a34cbd74..c91356411 100644 --- a/examples/smart-components/range-slider/label-position/index.html +++ b/examples/smart-components/range-slider/label-position/index.html @@ -1,10 +1,10 @@
- + label-position="top"
- + label-position="bottom"
diff --git a/examples/smart-components/range-slider/labels/index.html b/examples/smart-components/range-slider/labels/index.html index 245123d8c..4799d4372 100644 --- a/examples/smart-components/range-slider/labels/index.html +++ b/examples/smart-components/range-slider/labels/index.html @@ -1,14 +1,14 @@
- + label="none"
- + label="text"
- + label="tooltip"
diff --git a/examples/smart-components/range-slider/overview/index.html b/examples/smart-components/range-slider/overview/index.html index d9e2b7534..1bd5bda87 100644 --- a/examples/smart-components/range-slider/overview/index.html +++ b/examples/smart-components/range-slider/overview/index.html @@ -1 +1 @@ - + diff --git a/examples/smart-components/range-slider/range/index.html b/examples/smart-components/range-slider/range/index.html index 7b4d51831..e54e72101 100644 --- a/examples/smart-components/range-slider/range/index.html +++ b/examples/smart-components/range-slider/range/index.html @@ -1,5 +1,5 @@
- - + Цена: 5000–20000 ₽
diff --git a/examples/smart-components/range-slider/range/index.js b/examples/smart-components/range-slider/range/index.js index b1c9edc5a..187da08ef 100644 --- a/examples/smart-components/range-slider/range/index.js +++ b/examples/smart-components/range-slider/range/index.js @@ -6,7 +6,7 @@ const initializePriceRange = async () => { if (!slider || !output || slider.dataset.exampleReady === 'true') return; slider.dataset.exampleReady = 'true'; - await customElements.whenDefined('sf-range-slider'); + await customElements.whenDefined('sf-slider-range'); slider.addEventListener('change', (event) => { const [from, to] = event.detail.values; output.value = `Цена: ${from}–${to} ₽`; diff --git a/examples/smart-components/range-slider/state-disabled/index.html b/examples/smart-components/range-slider/state-disabled/index.html index 561c5f712..cbc5bec8c 100644 --- a/examples/smart-components/range-slider/state-disabled/index.html +++ b/examples/smart-components/range-slider/state-disabled/index.html @@ -1 +1 @@ - + diff --git a/examples/smart-components/range-slider/step/index.html b/examples/smart-components/range-slider/step/index.html index f89d3fd2f..3d650d330 100644 --- a/examples/smart-components/range-slider/step/index.html +++ b/examples/smart-components/range-slider/step/index.html @@ -1,14 +1,14 @@
- + step="5"
- + step="0.5"
- + step="0.5" decimals="2"
diff --git a/examples/smart-components/rich-text/appearance/index.html b/examples/smart-components/rich-text/appearance/index.html index c8dc6a65b..614970d22 100644 --- a/examples/smart-components/rich-text/appearance/index.html +++ b/examples/smart-components/rich-text/appearance/index.html @@ -1,10 +1,10 @@
- + appearance="bordered"
- + appearance="filled"
diff --git a/examples/smart-components/rich-text/cleaning/index.html b/examples/smart-components/rich-text/cleaning/index.html index 0caa6dd3d..c25f10e78 100644 --- a/examples/smart-components/rich-text/cleaning/index.html +++ b/examples/smart-components/rich-text/cleaning/index.html @@ -1,7 +1,7 @@ - - + diff --git a/examples/smart-components/rich-text/overview/index.html b/examples/smart-components/rich-text/overview/index.html index acc812879..fbfa780ad 100644 --- a/examples/smart-components/rich-text/overview/index.html +++ b/examples/smart-components/rich-text/overview/index.html @@ -1,6 +1,6 @@ - - + diff --git a/examples/smart-components/rich-text/rows/index.html b/examples/smart-components/rich-text/rows/index.html index 01f1683c7..d833f83c7 100644 --- a/examples/smart-components/rich-text/rows/index.html +++ b/examples/smart-components/rich-text/rows/index.html @@ -1,10 +1,10 @@
- + rows="2"
- + rows="4" max-rows="8"
diff --git a/examples/smart-components/rich-text/sizes/index.html b/examples/smart-components/rich-text/sizes/index.html index 35fef582e..51183e2b8 100644 --- a/examples/smart-components/rich-text/sizes/index.html +++ b/examples/smart-components/rich-text/sizes/index.html @@ -1,14 +1,14 @@
- + size="1/2"
- + size="1"
- + size="2"
diff --git a/examples/smart-components/rich-text/state-disabled/index.html b/examples/smart-components/rich-text/state-disabled/index.html index 291808cc3..5f90858a2 100644 --- a/examples/smart-components/rich-text/state-disabled/index.html +++ b/examples/smart-components/rich-text/state-disabled/index.html @@ -1,7 +1,7 @@ - - + diff --git a/examples/smart-components/rich-text/state-error/index.html b/examples/smart-components/rich-text/state-error/index.html index f5b33db6f..febb9fb6a 100644 --- a/examples/smart-components/rich-text/state-error/index.html +++ b/examples/smart-components/rich-text/state-error/index.html @@ -1,4 +1,4 @@ - - + diff --git a/examples/smart-components/rich-text/state-readonly/index.html b/examples/smart-components/rich-text/state-readonly/index.html index 32826cec2..f735a3644 100644 --- a/examples/smart-components/rich-text/state-readonly/index.html +++ b/examples/smart-components/rich-text/state-readonly/index.html @@ -1,8 +1,8 @@ - - + diff --git a/examples/smart-components/search/icon/index.html b/examples/smart-components/search/icon/index.html index cc66d3d18..1d90e888a 100644 --- a/examples/smart-components/search/icon/index.html +++ b/examples/smart-components/search/icon/index.html @@ -1,7 +1,7 @@
- +

Нажмите кнопку и наберите «таб» или «тема».

diff --git a/examples/smart-components/site-header/center/index.html b/examples/smart-components/site-header/center/index.html index 6f570c201..f75034a7c 100644 --- a/examples/smart-components/site-header/center/index.html +++ b/examples/smart-components/site-header/center/index.html @@ -1,4 +1,4 @@ - + Эффекты - + diff --git a/examples/smart-components/site-header/collapse/index.html b/examples/smart-components/site-header/collapse/index.html index 0de5972f8..4e6293639 100644 --- a/examples/smart-components/site-header/collapse/index.html +++ b/examples/smart-components/site-header/collapse/index.html @@ -1,4 +1,4 @@ - + SIMAI - + diff --git a/examples/smart-components/site-header/compact/index.html b/examples/smart-components/site-header/compact/index.html index 3ec2fc97b..4ff635383 100644 --- a/examples/smart-components/site-header/compact/index.html +++ b/examples/smart-components/site-header/compact/index.html @@ -1,10 +1,10 @@ - + Эффекты - + - +

Полоса остаётся вверху окна, когда страница прокручивается.

diff --git a/examples/smart-components/site-header/overview/index.html b/examples/smart-components/site-header/overview/index.html index 00f60d5b8..26ba4c711 100644 --- a/examples/smart-components/site-header/overview/index.html +++ b/examples/smart-components/site-header/overview/index.html @@ -1,4 +1,4 @@ - + SIMAI Поставка - + diff --git a/examples/smart-components/spinner/page-look/index.html b/examples/smart-components/spinner/page-look/index.html index a9ddf88f3..025e8f855 100644 --- a/examples/smart-components/spinner/page-look/index.html +++ b/examples/smart-components/spinner/page-look/index.html @@ -9,7 +9,7 @@ - +
diff --git a/examples/smart-components/table/application/index.html b/examples/smart-components/table/application/index.html index f667b4973..9e112ba99 100644 --- a/examples/smart-components/table/application/index.html +++ b/examples/smart-components/table/application/index.html @@ -4,12 +4,12 @@
- - + - +

diff --git a/examples/smart-components/table/application/index.js b/examples/smart-components/table/application/index.js index ccb7a4678..9e8bb88b5 100644 --- a/examples/smart-components/table/application/index.js +++ b/examples/smart-components/table/application/index.js @@ -32,10 +32,10 @@ const dateFormat = new Intl.DateTimeFormat('ru-RU', {dateStyle: 'medium', timeSt const initializeApplicationView = async () => { const root = document.querySelector('[data-application-demo]'); if (!root || root.dataset.exampleReady === 'true') return; - await customElements.whenDefined('sf-data-view'); + await customElements.whenDefined('sf-view'); root.dataset.exampleReady = 'true'; - const view = root.querySelector('sf-data-view'); + const view = root.querySelector('sf-view'); const log = root.querySelector('[data-application-log]'); let scenario = 'normal'; const records = PROJECTS.map((project) => ({...project, revision: '1'})); diff --git a/examples/smart-components/table/list/index.html b/examples/smart-components/table/list/index.html index d6ef8ff61..9fce42831 100644 --- a/examples/smart-components/table/list/index.html +++ b/examples/smart-components/table/list/index.html @@ -1,8 +1,8 @@ - - +
diff --git a/examples/smart-components/table/list/index.js b/examples/smart-components/table/list/index.js index 2bae7dd65..bda089140 100644 --- a/examples/smart-components/table/list/index.js +++ b/examples/smart-components/table/list/index.js @@ -1,5 +1,5 @@ const initializeProjectsList = async () => { - await customElements.whenDefined('sf-table'); + await customElements.whenDefined('sf-view-table'); const table = document.querySelector('#projects-list-view'); if (!table || table.dataset.exampleReady === 'true') return; diff --git a/examples/smart-components/table/overview/index.html b/examples/smart-components/table/overview/index.html index ac18176e1..84dc9ccf5 100644 --- a/examples/smart-components/table/overview/index.html +++ b/examples/smart-components/table/overview/index.html @@ -1,6 +1,6 @@ - - +
diff --git a/examples/smart-components/table/overview/index.js b/examples/smart-components/table/overview/index.js index fe0331748..45641d754 100644 --- a/examples/smart-components/table/overview/index.js +++ b/examples/smart-components/table/overview/index.js @@ -1,5 +1,5 @@ const initializeProjectsDataView = async () => { - await customElements.whenDefined('sf-table'); + await customElements.whenDefined('sf-view-table'); const table = document.querySelector('#projects-data-view'); if (!table || table.dataset.exampleReady === 'true') return; diff --git a/examples/smart-components/textarea/appearance/index.html b/examples/smart-components/textarea/appearance/index.html index 5f51e324f..bae193c17 100644 --- a/examples/smart-components/textarea/appearance/index.html +++ b/examples/smart-components/textarea/appearance/index.html @@ -1,10 +1,10 @@
- + appearance="bordered"
- + appearance="filled"
diff --git a/examples/smart-components/textarea/auto-grow/index.html b/examples/smart-components/textarea/auto-grow/index.html index 1aead3722..5725d18fe 100644 --- a/examples/smart-components/textarea/auto-grow/index.html +++ b/examples/smart-components/textarea/auto-grow/index.html @@ -1,14 +1,14 @@
- - + - - +
diff --git a/examples/smart-components/textarea/flush/index.html b/examples/smart-components/textarea/flush/index.html index c48095bad..fc71e2550 100644 --- a/examples/smart-components/textarea/flush/index.html +++ b/examples/smart-components/textarea/flush/index.html @@ -4,13 +4,13 @@ .composer > sf-textarea { flex: 1 1 auto; min-inline-size: 0; }
- - - + +
diff --git a/examples/smart-components/textarea/overview/index.html b/examples/smart-components/textarea/overview/index.html index d0b4a067c..3a0e98f96 100644 --- a/examples/smart-components/textarea/overview/index.html +++ b/examples/smart-components/textarea/overview/index.html @@ -1,8 +1,8 @@ - - + diff --git a/examples/smart-components/textarea/rows/index.html b/examples/smart-components/textarea/rows/index.html index 07e0bb31e..f16cfba8d 100644 --- a/examples/smart-components/textarea/rows/index.html +++ b/examples/smart-components/textarea/rows/index.html @@ -1,10 +1,10 @@
- + rows="2"
- + rows="6"
diff --git a/examples/smart-components/textarea/sizes/index.html b/examples/smart-components/textarea/sizes/index.html index f7387ecac..76c66736a 100644 --- a/examples/smart-components/textarea/sizes/index.html +++ b/examples/smart-components/textarea/sizes/index.html @@ -1,14 +1,14 @@
- + size="1/2"
- + size="1"
- + size="2"
diff --git a/examples/smart-components/textarea/state-disabled/index.html b/examples/smart-components/textarea/state-disabled/index.html index 0a16952eb..e80cd1d5f 100644 --- a/examples/smart-components/textarea/state-disabled/index.html +++ b/examples/smart-components/textarea/state-disabled/index.html @@ -1 +1 @@ - + diff --git a/examples/smart-components/textarea/state-error/index.html b/examples/smart-components/textarea/state-error/index.html index 9f554a5d5..1d03a2e28 100644 --- a/examples/smart-components/textarea/state-error/index.html +++ b/examples/smart-components/textarea/state-error/index.html @@ -1,8 +1,8 @@ - - + diff --git a/examples/smart-components/textarea/state-readonly/index.html b/examples/smart-components/textarea/state-readonly/index.html index 90ba48dfa..36790cb52 100644 --- a/examples/smart-components/textarea/state-readonly/index.html +++ b/examples/smart-components/textarea/state-readonly/index.html @@ -1 +1 @@ - + diff --git a/examples/smart-components/thread-list/overview/index.html b/examples/smart-components/thread-list/overview/index.html index 932585a4a..bab06beb9 100644 --- a/examples/smart-components/thread-list/overview/index.html +++ b/examples/smart-components/thread-list/overview/index.html @@ -1 +1 @@ -
+
diff --git a/examples/smart-components/thread-list/overview/index.js b/examples/smart-components/thread-list/overview/index.js index 9bc6e3338..f02183946 100644 --- a/examples/smart-components/thread-list/overview/index.js +++ b/examples/smart-components/thread-list/overview/index.js @@ -10,7 +10,7 @@ const threads = [ ]; const initialize = async () => { - await customElements.whenDefined('sf-thread-list'); + await customElements.whenDefined('sf-chat-threads'); const list = document.querySelector('#thread-list-overview'); if (!list || list.dataset.exampleReady === 'true') return; list.dataset.exampleReady = 'true'; diff --git a/examples/smart-components/thread-list/state-empty/index.html b/examples/smart-components/thread-list/state-empty/index.html index 17a0936ef..ccd64681f 100644 --- a/examples/smart-components/thread-list/state-empty/index.html +++ b/examples/smart-components/thread-list/state-empty/index.html @@ -1 +1 @@ -
+
diff --git a/examples/smart-components/thread-list/state-empty/index.js b/examples/smart-components/thread-list/state-empty/index.js index a9bffe2a5..a238e8d0c 100644 --- a/examples/smart-components/thread-list/state-empty/index.js +++ b/examples/smart-components/thread-list/state-empty/index.js @@ -1,6 +1,6 @@ // No conversations yet: the list says so and offers a new one. const initialize = async () => { - await customElements.whenDefined('sf-thread-list'); + await customElements.whenDefined('sf-chat-threads'); const list = document.querySelector('#thread-list-empty'); if (!list || list.dataset.exampleReady === 'true') return; list.dataset.exampleReady = 'true'; diff --git a/examples/smart-components/thread-list/state-loading/index.html b/examples/smart-components/thread-list/state-loading/index.html index e46cf0065..61be6cf06 100644 --- a/examples/smart-components/thread-list/state-loading/index.html +++ b/examples/smart-components/thread-list/state-loading/index.html @@ -1 +1 @@ -
+
diff --git a/examples/smart-components/thread-list/state-loading/index.js b/examples/smart-components/thread-list/state-loading/index.js index 4cac72bd4..8e51ea427 100644 --- a/examples/smart-components/thread-list/state-loading/index.js +++ b/examples/smart-components/thread-list/state-loading/index.js @@ -1,6 +1,6 @@ // While the first page loads the list shows its shape and says it is busy. const initialize = async () => { - await customElements.whenDefined('sf-thread-list'); + await customElements.whenDefined('sf-chat-threads'); const list = document.querySelector('#thread-list-loading'); if (!list || list.dataset.exampleReady === 'true') return; list.dataset.exampleReady = 'true'; diff --git a/examples/smart-components/thread-list/ungrouped/index.html b/examples/smart-components/thread-list/ungrouped/index.html index c90ff07f6..52cfc07e7 100644 --- a/examples/smart-components/thread-list/ungrouped/index.html +++ b/examples/smart-components/thread-list/ungrouped/index.html @@ -1 +1 @@ -
+
diff --git a/examples/smart-components/thread-list/ungrouped/index.js b/examples/smart-components/thread-list/ungrouped/index.js index cc4a210b8..46113b809 100644 --- a/examples/smart-components/thread-list/ungrouped/index.js +++ b/examples/smart-components/thread-list/ungrouped/index.js @@ -10,7 +10,7 @@ const threads = [ ]; const initialize = async () => { - await customElements.whenDefined('sf-thread-list'); + await customElements.whenDefined('sf-chat-threads'); const list = document.querySelector('#thread-list-ungrouped'); if (!list || list.dataset.exampleReady === 'true') return; list.dataset.exampleReady = 'true'; From 7d9268bca9088b9b9eae864f7fcc87a2877d44ec Mon Sep 17 00:00:00 2001 From: Rim Zabarov Date: Mon, 2 Nov 2026 21:34:18 +0300 Subject: [PATCH 2/3] English home shows the demonstrations in English The export writes an English copy of the admin and the showcase under demos/home/en/, its text from examples/home/i18n/en.json, matched whole (a JSON value, a JavaScript literal part, an HTML text or attribute part); a Russian string without a translation stops the export. The person in the admin data speaks English there, so the components draw their own words in English too. Docara keeps the English home's links the same as the Russian one, so a Russian demo page moves to its English copy when the page around it, or the page that opened it, is English. Co-Authored-By: Claude Opus 5.5 --- content/en/index.md | 2 +- examples/home/i18n/en.json | 279 +++++++++++++++++++++++++ scripts/export-live-demonstrations.php | 153 ++++++++++---- translations.lock.json | 2 +- 4 files changed, 389 insertions(+), 47 deletions(-) create mode 100644 examples/home/i18n/en.json diff --git a/content/en/index.md b/content/en/index.md index b385a8cad..e3673910d 100644 --- a/content/en/index.md +++ b/content/en/index.md @@ -16,7 +16,7 @@ an English page. ## What you can build The admin, the chat and the editor are live: click and type in them. A tab -loads when you open it. The demo data is in Russian. +loads when you open it. :::internal_preview {size=tall title="Admin, chat and editor"} [Open the demo](/demos/home/showcase/) diff --git a/examples/home/i18n/en.json b/examples/home/i18n/en.json new file mode 100644 index 000000000..9c700ebc5 --- /dev/null +++ b/examples/home/i18n/en.json @@ -0,0 +1,279 @@ +{ + "schema": "ui-doc.home-demo-translation.v1", + "language": "en", + "note": "English text of the home page demos (examples/home/admin and examples/home/showcase). scripts/export-live-demonstrations.php publishes an English copy under /demos/home/en/ and fails when a Russian string is left without a translation. A string is matched whole: a JSON value, a part of a JavaScript literal between ${…}, an HTML text or attribute part.", + "keep": [ + "Русский", + "Українська", + "Беларуская", + "Қазақ тілі" + ], + "values": { + "admin/assets/data/navigation.json": { + "person.language": "en" + } + }, + "patterns": [ + { + "match": "^SIMAI: (Резервные копии|[^ ]+) №(\\d+)", + "replace": "SIMAI: {1} No. {2}", + "words": { + "Биллинг": "Billing", + "Доставка": "Delivery", + "Импорт": "Import", + "Интеграции": "Integrations", + "Каталог": "Catalogue", + "Корзина": "Cart", + "Медиа": "Media", + "Отчёты": "Reports", + "Платежи": "Payments", + "Поиск": "Search", + "Права": "Permissions", + "Резервные копии": "Backups", + "Склад": "Warehouse", + "Уведомления": "Notifications", + "Формы": "Forms" + } + } + ], + "strings": { + " — расширенная сборка для портала организаций с длинным названием": " — an extended build for the organisations portal with a long name", + "Главная": "Home", + "Данные": "Data", + "Создать хранилище": "Create a storage", + "Сайт": "Site", + "Люди": "People", + "Установка": "Installation", + "Файлы": "Files", + "Все хранилища": "All storages", + "Настройки сайта": "Site settings", + "Страницы": "Pages", + "Меню сайта": "Site menu", + "Открыть сайт": "Open the site", + "Пользователи": "Users", + "Группы": "Groups", + "Роли": "Roles", + "Обновления": "Updates", + "доступно 1.4": "1.4 available", + "Резервные копии": "Backups", + "Журнал": "Log", + "Пакеты": "Packages", + "Сайты": "Sites", + "Разработка": "Development", + "Свойства": "Properties", + "Очереди": "Queues", + "Кеш": "Cache", + "Сайт компании": "Company site", + "Каталог": "Catalogue", + "Каталог решений": "Solutions catalogue", + "Разделы каталога": "Catalogue sections", + "Новости": "News", + "Вопросы и ответы": "Questions and answers", + "Кейсы клиентов": "Customer stories", + "Вакансии": "Vacancies", + "Заявки": "Requests", + "Заявки с сайта": "Site requests", + "4 новых": "4 new", + "Обратные звонки": "Call-backs", + "Интернет-магазин": "Online shop", + "Магазин": "Shop", + "Товары": "Products", + "Заказы": "Orders", + "12 новых": "12 new", + "Покупатели": "Customers", + "Документация": "Documentation", + "Статьи": "Articles", + "Версии": "Versions", + "Сайт клиента": "Client site", + "Материалы": "Materials", + "Магазин клиента": "Client shop", + "Лендинг": "Landing page", + "1 новая": "1 new", + "Обычный": "Standard", + "Экспертный": "Expert", + "Персональный": "Personal", + "Мои заявки": "My requests", + "CRM отдела продаж": "Sales CRM", + "Администратор": "Administrator", + "Профиль": "Profile", + "Безопасность входа": "Sign-in security", + "Активные сеансы": "Active sessions", + "Горячие клавиши": "Keyboard shortcuts", + "Справка": "Help", + "Сегодня": "Today", + "Раньше": "Earlier", + "Доступно обновление 1.4": "Update 1.4 is available", + "Профили меню и сайт в адресе.": "Menu profiles and the site in the address.", + "Вход с нового устройства": "Sign-in from a new device", + "Chrome, macOS, Москва.": "Chrome, macOS, Moscow.", + "Резервная копия готова": "The backup is ready", + "4 новые заявки с сайта": "4 new site requests", + "вчера": "yesterday", + "Пакет storage обновлён до 2.3": "Package storage updated to 2.3", + "8 окт": "Oct 8", + "Создать запись…": "Create a record…", + "в любом хранилище": "in any storage", + "Сменить тему": "Switch theme", + "Светлая / тёмная": "Light / dark", + "Сменить сайт…": "Switch site…", + "Решения": "Solutions", + "Код решения": "Solution code", + "Название": "Name", + "Раздел": "Section", + "Ответственный": "Owner", + "Статус": "Status", + "В работе": "In progress", + "На проверке": "In review", + "Готово": "Done", + "Заморожено": "Frozen", + "Остановлено": "Stopped", + "Метки": "Labels", + "Биллинг": "Billing", + "Инфраструктура": "Infrastructure", + "Уведомления": "Notifications", + "Портал": "Portal", + "Поиск": "Search", + "Описание": "Description", + "Версия": "Version", + "Приоритет": "Priority", + "Бюджет, ₽": "Budget, ₽", + "Выпущено": "Released", + "Проверено": "Reviewed", + "Доступно всем": "Available to everyone", + "Снято с поддержки": "Discontinued", + "Акцентный цвет": "Accent colour", + "Обложка": "Cover", + "Вложения": "Attachments", + "Родительское решение": "Parent solution", + "Зависит от": "Depends on", + "Проверяющий": "Reviewer", + "Скрипт в head": "Script in head", + "Правила темы": "Theme rules", + "Заметки": "Notes", + "Общее": "General", + "Основное": "Main", + "Числа и сроки": "Numbers and dates", + "Оформление": "Appearance", + "Вид": "View", + "Связи": "Relations", + "Интеграция": "Integration", + "Код": "Code", + "Платежи и биллинг": "Payments and billing", + "Коммуникации": "Communications", + "Контент": "Content", + "Администрирование": "Administration", + "Игорь Смирнов": "Igor Smirnov", + "ИС": "IS", + "Анна Петрова": "Anna Petrova", + "АП": "AP", + "Дмитрий Орлов": "Dmitry Orlov", + "ДО": "DO", + "Елена Кузнецова": "Elena Kuznetsova", + "ЕК": "EK", + "Сергей Ильин": "Sergey Ilyin", + "СИ": "SI", + "Мария Волкова": "Maria Volkova", + "МВ": "MV", + "Ядро платформы": "Platform core", + "Авторизация": "Authorisation", + "Хранилище": "Storage", + "Отчётность": "Reporting", + "Техническое задание.pdf": "Specification.pdf", + "Акт приёмки.pdf": "Acceptance certificate.pdf", + "Расчёт тарифов.xlsx": "Tariff calculation.xlsx", + "Протокол встречи.docx": "Meeting minutes.docx", + "Схема обмена.svg": "Exchange diagram.svg", + "Приём платежей, возвраты и сверка с банком.": "Payments, refunds and bank reconciliation.", + "Письма, SMS и push по событиям системы.": "Email, SMS and push on system events.", + "Тарифы, подписки и выставление счетов.": "Tariffs, subscriptions and invoicing.", + "Снимки файлов и базы по расписанию.": "Scheduled snapshots of files and the database.", + "Корзина покупателя и оформление заказа.": "The customer's cart and checkout.", + "Модуль закрывает весь путь обращения: приём, разбор, маршрутизацию ответственному, напоминания по срокам, закрытие с обязательным комментарием и выгрузку в отчётность. Настройки хранятся отдельно для каждой организации портала, а журнал действий пишется целиком и не чистится автоматически.": "The module covers the whole path of a request: intake, triage, routing to an owner, deadline reminders, closing with a required comment and export to reporting. Settings are kept separately for each organisation of the portal, and the action log is written in full and never cleaned automatically.", + "Конструктор форм и обработка заявок.": "Form builder and request handling.", + "Остатки, резервы и движения по складам.": "Stock, reservations and warehouse movements.", + "Службы доставки, зоны и расчёт стоимости.": "Delivery services, zones and cost calculation.", + "Сводки по продажам и обращениям.": "Sales and request summaries.", + "Роли, доступы и журнал действий.": "Roles, access and the action log.", + "Загрузка данных из внешних систем.": "Loading data from external systems.", + "Обмен с 1С, CRM и платёжными шлюзами.": "Exchange with 1C, CRM and payment gateways.", + "Изображения, видео и их варианты.": "Images, video and their variants.", + "Перенесено из SF4, сверить права перед включением.": "Moved from SF4; check permissions before enabling.", + "Товары, разделы и свойства каталога.": "Products, sections and catalogue properties.", + "Индексация и выдача по сайту.": "Site indexing and results.", + "В этой демонстрации данные есть только в разделе «Каталог решений» — откройте его в меню.": "In this demo only the “Solutions catalogue” section has data — open it in the menu.", + "Разделы админки": "Admin sections", + "Где вы находитесь": "Where you are", + "Опубликовать": "Publish", + "Снять с публикации": "Unpublish", + "Удалить": "Delete", + "Общий": "Shared", + "Перейти": "Go to", + "Все результаты": "All results", + "Недавние": "Recent", + "Действия": "Actions", + "в": "in", + "Меню": "Menu", + "Нет прав: эта запись в демо только для чтения": "No permission: this record is read-only in the demo", + "Мои": "Mine", + "Источник данных недоступен": "The data source is unavailable", + "Нет доступа к списку": "No access to the list", + "Записи изменились, обновите список": "The records changed, refresh the list", + "Запись будет удалена.": "The record will be deleted.", + "Будут удалены записи:": "Records to be deleted:", + "Это поле здесь не меняется": "This field cannot be changed here", + "Запись станет видна посетителям сайта.": "The record becomes visible to site visitors.", + "Запись перестанет быть видна посетителям сайта.": "The record stops being visible to site visitors.", + "Новое решение": "New solution", + "Общие настройки здесь не подключены": "Shared settings are not connected here", + "Общие виды здесь не подключены": "Shared views are not connected here", + "Новый вид": "New view", + "Общую раскладку меняет администратор": "The shared layout is changed by an administrator", + "не может быть пустым": "cannot be empty", + "Нужно целое число": "A whole number is needed", + "Запись изменилась, обновите её": "The record changed, refresh it", + "Нет доступа к записи": "No access to the record", + "Запись не найдена": "Record not found", + "Файл больше 16 МБ": "The file is larger than 16 MB", + "Общий вид заводит администратор": "A shared view is created by an administrator", + "Это единственный общий вид": "This is the only shared view", + "Общий вид меняет администратор": "A shared view is changed by an administrator", + "Данные полигона не загрузились:": "The polygon data did not load:", + "Карточка решения": "Solution card", + "Записи": "Record", + "нет — возможно, её удалили. Открыт список.": "is missing — it may have been deleted. The list is open.", + "ответы хоста:": "host answers:", + "хост не заявляет: ${t.join(": "host does not declare: ${t.join(", + "Анна": "Anna", + "Мой помощник": "My assistant", + "Чем помочь? Спросите о правилах компании или пришлите документ.": "How can I help? Ask about company rules or send a document.", + "Сколько дней отпуска?": "How many days of leave?", + "Как оформить командировку?": "How do I arrange a business trip?", + "Кадры": "HR", + "Вопросы об отпусках, графике и документах.": "Questions about leave, schedules and documents.", + "Отпуск и перенос": "Leave and rescheduling", + "График на ноябрь": "November schedule", + "Сколько дней отпуска мне положено и можно ли его перенести?": "How many days of leave do I have, and can I move them?", + "Ежегодный отпуск — 28 календарных дней[1]. Перенос — по заявлению[2].": "Annual leave is 28 calendar days[1]. It can be moved on request[2].", + "

Ежегодный отпуск — 28 календарных дней[1]. Перенос — по заявлению не позднее чем за две недели[2].

": "

Annual leave is 28 calendar days[1]. It can be moved on a request made at least two weeks ahead[2].

", + "Положение об отпусках": "Leave policy", + "Трудовой кодекс, статья 124": "Labour Code, article 124", + "Какой график работы в ноябре?": "What is the work schedule in November?", + "В ноябре 19 рабочих дней. 4 ноября — выходной, 3 ноября — сокращённый день.": "November has 19 working days. November 4 is a day off, November 3 is a short day.", + "Помощник": "Assistant", + "Это демонстрация: ответы здесь заготовлены. В вашем приложении их даёт ваш сервер или ИИ-сотрудник.": "This is a demo: the answers here are prepared in advance. In your application they come from your server or an AI employee.", + "Новый разговор": "New conversation", + "Как подготовить письмо к рассылке": "How to prepare a newsletter", + "Эта страница написана в режиме содержимого. Просто печатайте:": "This page is written in content mode. Just type:", + "делает новый блок, а косая черта в пустой строке открывает меню.": "makes a new block, and a slash on an empty line opens the menu.", + "Что проверить перед отправкой": "What to check before sending", + "Согласие получателей и ссылку отписки": "Recipients' consent and the unsubscribe link", + "Тему письма и первые слова после неё": "The subject and the first words after it", + "Вид на телефоне и в тёмной теме": "How it looks on a phone and in the dark theme", + "Щёлкните по ручке слева от блока: в её меню есть «Параметры…», а над выбранным блоком появятся быстрые настройки.": "Click the handle to the left of a block: its menu has “Parameters…”, and quick settings appear above the chosen block.", + "Что можно собрать": "What you can build", + "Админка": "Admin", + "Чат": "Chat", + "Редактор": "Editor", + "Административный интерфейс": "Administrative interface" + } +} diff --git a/scripts/export-live-demonstrations.php b/scripts/export-live-demonstrations.php index b7e6c24de..33a7471a8 100644 --- a/scripts/export-live-demonstrations.php +++ b/scripts/export-live-demonstrations.php @@ -46,57 +46,120 @@ // components come from the product package the site pins (the lock's // package_projections), so the page declares that package to the Loader the // way the documentation pages do. Links inside it never navigate (index.js). -$adminSource=$root.'/examples/home/admin'; -$adminTarget=$build.'/demos/home/admin'; +// The English home page shows the same demonstrations in English: the export +// writes a second copy under demos/home/en/, its text taken from +// examples/home/i18n/en.json. A string is matched whole -- a JSON value, a part +// of a JavaScript literal between ${...}, an HTML text or attribute part -- and a +// Russian string the dictionary does not hold stops the export. +$homeTranslation=$root.'/examples/home/i18n/en.json'; +$inputs[substr($homeTranslation,strlen($root)+1)]=hash_file('sha256',$homeTranslation); +$dictionary=json_decode(file_get_contents($homeTranslation),true,512,JSON_THROW_ON_ERROR); +$untranslated=[]; +$translate=static function(string $text) use ($dictionary,&$untranslated): string { + $core=trim($text); + if ($core==='' || preg_match('/[\p{Cyrillic}№]/u',$core)!==1 || in_array($core,$dictionary['keep'],true)) return $text; + $lead=substr($text,0,strlen($text)-strlen(ltrim($text)));$trail=substr($text,strlen(rtrim($text))); + if (array_key_exists($core,$dictionary['strings'])) return $lead.$dictionary['strings'][$core].$trail; + foreach ($dictionary['patterns'] as $pattern) { + if (preg_match('/'.$pattern['match'].'/u',$core,$m)!==1 || !isset($pattern['words'][$m[1]])) continue; + $rest=substr($core,strlen($m[0])); + if ($rest!=='' && !array_key_exists($rest,$dictionary['strings'])) break; + return $lead.str_replace(['{1}','{2}'],[$pattern['words'][$m[1]],$m[2]],$pattern['replace']).($rest===''?'':$dictionary['strings'][$rest]).$trail; + } + $untranslated[$core]=true; + return $text; +}; +$translateParts=static fn(string $text): string=>implode('',array_map( + static fn(string $part): string=>str_starts_with($part,'${')?$part:$translate($part), + preg_split('/(\$\{[^}]*\})/',$text,-1,PREG_SPLIT_DELIM_CAPTURE))); +$translateFile=static function(string $path,string $content) use ($translate,$translateParts,$dictionary): string { + $extension=pathinfo($path,PATHINFO_EXTENSION); + if ($extension==='json') { + $walk=static function($value) use (&$walk,$translate){ + if (is_array($value)) return array_map($walk,$value); + return is_string($value)?$translate($value):$value; + }; + $data=$walk(json_decode($content,true,512,JSON_THROW_ON_ERROR)); + // Values other than text, such as the person's language that the admin + // menu gives the page. + foreach ($dictionary['values'][$path] ?? [] as $key=>$value) { + $node=&$data; + foreach (explode('.',$key) as $step) { + if (!is_array($node) || !array_key_exists($step,$node)) throw new RuntimeException('Home demonstrations: '.$path.' has no '.$key); + $node=&$node[$step]; + } + $node=$value; + unset($node); + } + return json_encode($data,JSON_UNESCAPED_SLASHES|JSON_UNESCAPED_UNICODE); + } + if ($extension==='js') return preg_replace_callback('/`((?:[^`\\\\]|\\\\.)*)`|\'((?:[^\'\\\\\n]|\\\\.)*)\'|"((?:[^"\\\\\n]|\\\\.)*)"/', + static function(array $m) use ($translateParts): string { $quote=$m[0][0]; return $quote.$translateParts(substr($m[0],1,-1)).$quote; },$content); + if ($extension==='html') { + $parts=static fn(string $value): string=>implode('|',array_map(static function(string $part) use ($translate): string { + return preg_match('/\A([a-z-]+:)(.*)\z/s',$part,$m)===1?$m[1].$translate($m[2]):$translate($part); + },explode('|',$value))); + $content=preg_replace('//s','',$content); + return preg_replace_callback('/>([^<>]+)<|="([^"]*)"/',static fn(array $m): string=>isset($m[2])?'="'.$parts($m[2]).'"':'>'.$parts($m[1]).'<',$content); + } + return $content; +}; + +// The administrative interface on the home page (examples/home/admin): a +// standalone page rather than a sandboxed example frame, because it runs its +// own data host, reads its data files and opens records in place. Its +// components come from the product package the site pins (the lock's +// package_projections), so the page declares that package to the Loader the +// way the documentation pages do. Links inside it never navigate (index.js). +// The home page showcase (examples/home/showcase): tabs of the admin, the chat +// and the editor. The admin is the page above in a frame; the chat and the +// editor come from the same product package and are made when their tab opens. $proMount=$lock['package_projections']['pro']['mount'] ?? null; if (!is_string($proMount) || preg_match('~\A_docara/framework-packages/pro/[0-9a-f]{40}\z~', $proMount) !== 1) throw new RuntimeException('Admin demonstration: package mount missing from the lock'); -if (!is_dir($adminTarget)) mkdir($adminTarget,0775,true); -foreach(new RecursiveIteratorIterator(new RecursiveDirectoryIterator($adminSource, FilesystemIterator::SKIP_DOTS)) as $input) { - if (!$input->isFile()) continue; - $relative=substr($input->getPathname(),strlen($adminSource)+1); - $inputs[substr($input->getPathname(),strlen($root)+1)]=hash_file('sha256',$input->getPathname()); - if ($relative==='index.html') continue; - $dest=$adminTarget.'/'.$relative; - if(!is_dir(dirname($dest)))mkdir(dirname($dest),0775,true); - copy($input->getPathname(),$dest); -} // Icons from the runtime's own icon font: the menu and the list use many more // glyphs than the documentation's subset carries. $adminBoot=['theme'=>false,'icons'=>['enabled'=>true,'accumulate'=>false],'smart'=>['base'=>true],'minified'=>false,'packages'=>['pro'=>['base'=>$base.$proMount.'/smart']]]; -$adminHtml='Административный интерфейс' - .'' - .'' - .'' - .'' - .''.file_get_contents($adminSource.'/index.html') - .'' - .''; -file_put_contents($adminTarget.'/index.html',$adminHtml); -foreach(new RecursiveIteratorIterator(new RecursiveDirectoryIterator($adminTarget, FilesystemIterator::SKIP_DOTS)) as $f) if($f->isFile()) $files[]=['path'=>substr($f->getPathname(),strlen($build)+1),'sha256'=>hash_file('sha256',$f->getPathname())]; - -// The home page showcase (examples/home/showcase): tabs of the admin, the chat -// and the editor. The admin is the page above in a frame; the chat and the -// editor come from the same product package and are made when their tab opens. -$showcaseSource=$root.'/examples/home/showcase'; -$showcaseTarget=$build.'/demos/home/showcase'; -if (!is_dir($showcaseTarget)) mkdir($showcaseTarget,0775,true); -foreach(new RecursiveIteratorIterator(new RecursiveDirectoryIterator($showcaseSource, FilesystemIterator::SKIP_DOTS)) as $input) { - if (!$input->isFile()) continue; - $relative=substr($input->getPathname(),strlen($showcaseSource)+1); - $inputs[substr($input->getPathname(),strlen($root)+1)]=hash_file('sha256',$input->getPathname()); - if ($relative==='index.html') continue; - copy($input->getPathname(),$showcaseTarget.'/'.$relative); +$themeFirst=''; +$themeSync=''; +$boot=''; +// The English home links the same addresses as the Russian one, so a Russian +// page moves to its English copy when the page around it is English, or when +// it was opened from an English page. +$toEnglish=''; +$homeDemos=[ + 'admin'=>['html'=>'class="max-h-screen h-full" data-sf-density="compact"','title'=>'Административный интерфейс','modules'=>['index.js','demo.js'],'body'=>'class="flex h-full"'], + 'showcase'=>['html'=>'','title'=>'Что можно собрать','modules'=>['index.js'],'body'=>''], +]; +foreach (['ru'=>'','en'=>'en/'] as $language=>$prefix) { + $tr=$language==='ru'?static fn(string $path,string $content): string=>$content:$translateFile; + foreach ($homeDemos as $name=>$demo) { + $source=$root.'/examples/home/'.$name; + $target=$build.'/demos/home/'.$prefix.$name; + if (!is_dir($target)) mkdir($target,0775,true); + foreach(new RecursiveIteratorIterator(new RecursiveDirectoryIterator($source, FilesystemIterator::SKIP_DOTS)) as $input) { + if (!$input->isFile()) continue; + $relative=substr($input->getPathname(),strlen($source)+1); + $inputs[substr($input->getPathname(),strlen($root)+1)]=hash_file('sha256',$input->getPathname()); + if ($relative==='index.html') continue; + $dest=$target.'/'.$relative; + if(!is_dir(dirname($dest)))mkdir(dirname($dest),0775,true); + file_put_contents($dest,$tr($name.'/'.$relative,file_get_contents($input->getPathname()))); + } + $title=$language==='ru'?$demo['title']:$translate($demo['title']); + $html=''.$title.'' + .($language==='ru'?$toEnglish:'') + .'' + .$themeFirst.$boot + .'' + .implode('',array_map(static fn(string $module): string=>'',$demo['modules'])).'' + .''.$tr('index.html',file_get_contents($source.'/index.html')) + .$themeSync + .''; + file_put_contents($target.'/index.html',$html); + foreach(new RecursiveIteratorIterator(new RecursiveDirectoryIterator($target, FilesystemIterator::SKIP_DOTS)) as $f) if($f->isFile()) $files[]=['path'=>substr($f->getPathname(),strlen($build)+1),'sha256'=>hash_file('sha256',$f->getPathname())]; + } } -$showcaseHtml='Что можно собрать' - .'' - .'' - .'' - .'' - .''.file_get_contents($showcaseSource.'/index.html') - .'' - .''; -file_put_contents($showcaseTarget.'/index.html',$showcaseHtml); -foreach(new RecursiveIteratorIterator(new RecursiveDirectoryIterator($showcaseTarget, FilesystemIterator::SKIP_DOTS)) as $f) if($f->isFile()) $files[]=['path'=>substr($f->getPathname(),strlen($build)+1),'sha256'=>hash_file('sha256',$f->getPathname())]; +if ($untranslated!==[]) throw new RuntimeException('Home demonstrations: no English text for '.implode(' | ',array_keys($untranslated))); $recipeFixture=$root.'/assets/examples/composition/header-switch.json'; $recipeTarget=$build.'/demos/guide/composition-recipe/header-switch.json'; diff --git a/translations.lock.json b/translations.lock.json index 835b44070..0cbd2421e 100644 --- a/translations.lock.json +++ b/translations.lock.json @@ -33,7 +33,7 @@ "source_sha256": "a0ec35d67e1ad940d736713c212ba946e12e308631b4c844e68df57b860ae8d4", "source_structure_sha256": "b1a193f4f03f149994ca921fe18e034a397b6a551b39570b3f71b3d69627c8e8", "target_path": "content/en/index.md", - "target_sha256": "19b890af88ccd08273452976df864c930ff1fec53645cd4e7cf06ed04c014afa", + "target_sha256": "edd2e68a7ab7cee06b4210fd5c5c5adb34136c4835e60a3fba62e8c68e6bb746", "target_structure_sha256": "b1a193f4f03f149994ca921fe18e034a397b6a551b39570b3f71b3d69627c8e8" } ], From d37a07d8e47106bc4a27d3f49c13524d939b8e65 Mon Sep 17 00:00:00 2001 From: Rim Zabarov Date: Thu, 5 Nov 2026 14:10:31 +0300 Subject: [PATCH 3/3] =?UTF-8?q?Naming=20rules=20follow=20the=20set-family-?= =?UTF-8?q?variant=20decision;=20=C2=AB=D0=9D=D0=B0=D0=B1=D0=BE=D1=80?= =?UTF-8?q?=D1=8B=C2=BB=20in=20the=20header?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - guide/smart-components/names: family first (sf-button-icon, sf-input-date), a set's name only for components that live inside one set; one prefix for SIMAI Framework and every set, a family has one owner, shared parts belong to SIMAI Framework; events named after the renamed tags; the November tag renames link to the updating table (old tags until 2027-01-01). - guide/smart-components/packages: sets instead of ui-pro as the second home. - guide/sets: sf-message-log is not a chat family example; the catalogue shows where each set's documentation lives until it has its own site. - Header: Руководство, Утилиты, Компоненты, Смарт-компоненты, Наборы, Pro; Pro stays until each set has its own site (the reachability audit). - Home (ru and en): admin, chat and editor are sets; a card for the sets. Co-Authored-By: Claude Opus 5.5 --- content/en/index.md | 8 +-- content/ru/guide/sets/index.md | 18 ++--- content/ru/guide/sets/names.md | 5 +- content/ru/guide/smart-components/names.md | 65 ++++++++++++------- content/ru/guide/smart-components/packages.md | 13 ++-- content/ru/index.md | 8 +-- content/ru/pro/index.md | 5 ++ content/ru/section.json | 5 ++ .../audit-guide-information-architecture.php | 1 + scripts/audit-reference-separation.php | 2 + translations.lock.json | 8 +-- 11 files changed, 86 insertions(+), 52 deletions(-) diff --git a/content/en/index.md b/content/en/index.md index e3673910d..ca8e1eb1c 100644 --- a/content/en/index.md +++ b/content/en/index.md @@ -23,9 +23,9 @@ loads when you open it. ::: More: [the admin](/demos/home/admin/) on its own page, -[the chat](/ru/pro/chat/) and [the editor](/ru/pro/editor/content-editor/) (in -Russian). All three are [SIMAI Pro](/ru/pro/) components under their own -licence; the rest of SIMAI Framework is open under Apache-2.0. +[the chat](/ru/pro/chat/) and [the editor](/ru/pro/editor/editor/) (in +Russian). They are the [component sets](/ru/guide/sets/) `admin`, `chat` and +`editor` under the Pro licence; SIMAI Framework is open under Apache-2.0. ## Three steps @@ -55,7 +55,7 @@ licence; the rest of SIMAI Framework is open under Apache-2.0. :::features - **[Themes](/ru/guide/colour/themes/)** Light, dark and your own theme from one colour. - **[Updating](/ru/guide/connection/updating/)** A pinned release and the change journal. -- **[Background effects](https://effects.simai.io/)** Live backgrounds for first screens. +- **[Component sets](/ru/guide/sets/)** Admin, tables, chat, mail, editor, effects. - **[Working with AI](/ru/guide/standards/ai/)** The `ai.json` index and a text version of every page. ::: diff --git a/content/ru/guide/sets/index.md b/content/ru/guide/sets/index.md index 8882151b7..1d94945eb 100644 --- a/content/ru/guide/sets/index.md +++ b/content/ru/guide/sets/index.md @@ -31,15 +31,15 @@ description: "Набор компонентов — готовые смарт-к ## Какие бывают наборы -| Набор | Для чего | Лицензия | Сайт | -|:---|:---|:---|:---| -| `admin` | Админка: меню, рабочие экраны, настройки | Pro | [admin.simai.io](https://admin.simai.io/) | -| `view` | Представления данных: умная таблица с сортировкой, фильтрами и страницами, канбан, календарь, диаграмма Ганта | Pro | view.simai.io, появится | -| `chat` | Чат: лента сообщений, поле ввода, список диалогов | Pro | свой поддомен, появится | -| `mail` | Письма: конструктор и просмотр писем | Pro | свой поддомен, появится | -| `editor` | Редактор страниц и текста | Pro | свой поддомен, появится | -| `chart` | Графики и диаграммы | Pro | свой поддомен, появится | -| `effects` | Фоновые эффекты и анимации | Бесплатно | [effects.simai.io](https://effects.simai.io/) | +| Набор | Для чего | Лицензия | Сайт набора | Документация сейчас | +|:---|:---|:---|:---|:---| +| `admin` | Админка: меню, рабочие экраны, настройки | Pro | [admin.simai.io](https://admin.simai.io/) | [Pro → Админка](/ru/pro/admin/) | +| `view` | Представления данных: умная таблица с сортировкой, фильтрами и страницами, канбан, календарь, диаграмма Ганта | Pro | view.simai.io, появится | [Pro → Таблица](/ru/pro/admin/table/), [Свойства записи](/ru/pro/admin/property-view/) | +| `chat` | Чат: лента сообщений, поле ввода, список диалогов | Pro | свой поддомен, появится | [Pro → Чат](/ru/pro/chat/) | +| `mail` | Письма: конструктор и просмотр писем | Pro | свой поддомен, появится | [Pro → Письма](/ru/pro/mail/) | +| `editor` | Редактор страниц и текста | Pro | свой поддомен, появится | [Pro → Редактор](/ru/pro/editor/editor/) | +| `chart` | Графики и диаграммы | Pro | свой поддомен, появится | появится | +| `effects` | Фоновые эффекты и анимации | Бесплатно | [effects.simai.io](https://effects.simai.io/) | на сайте набора | Простой список и простая таблица остаются в бесплатном SIMAI Framework. Набор `view` нужен, когда данным требуются сортировка, фильтры, страницы или diff --git a/content/ru/guide/sets/names.md b/content/ru/guide/sets/names.md index fa1942b04..0e86e88fb 100644 --- a/content/ru/guide/sets/names.md +++ b/content/ru/guide/sets/names.md @@ -19,7 +19,7 @@ description: "У всех наборов одна приставка sf-, имя |:---|:---|:---| | `sf-effect` | `effect` | набор `effects` | | `sf-chat-composer` | `chat` | набор `chat` | -| `sf-message-log` | `message` | набор `chat` | +| `sf-chat-window` | `chat` | набор `chat` | | `sf-view-table` | `view` | набор `view` | | `sf-button` | `button` | SIMAI Framework | @@ -45,4 +45,5 @@ description: "У всех наборов одна приставка sf-, имя Когда компонент переименовывают, старое имя ещё какое-то время работает и пишет в консоль подсказку с новым именем, как и у компонентов SIMAI Framework (см. [Жизненный цикл изменений](/ru/guide/connection/change-lifecycle/)). Срок, -до которого действует старое имя, набор указывает сам. +до которого действует старое имя, набор указывает сам. Таблица переименований +ноября 2026 — на странице [Обновление](/ru/guide/connection/updating/). diff --git a/content/ru/guide/smart-components/names.md b/content/ru/guide/smart-components/names.md index ef7f866a2..6147ddae2 100644 --- a/content/ru/guide/smart-components/names.md +++ b/content/ru/guide/smart-components/names.md @@ -12,15 +12,21 @@ description: "Как называются смарт-компоненты, их ## Имя тега говорит, что это -- Тег — английское словосочетание в kebab-case после приставки: - `sf-<уточнение>-<главное слово>`, **главное слово в конце**: - `sf-menu-context`, `sf-admin-menu`, `sf-slider-range`, `sf-header-page`, - `sf-chat-threads`, `sf-message-log`. -- Компонент того же рода сохраняет главное слово и получает уточнение: - `sf-menu`, `sf-menu-context`, `sf-admin-menu`, `sf-site-menu`. В семье - может быть сколько угодно членов. -- Сборка из сборок называется так же — по тому, что она есть: - `sf-record-screen`, а не по своим частям. +- Тег идёт от общего к частному: `sf-[набор]-<семья>[-<вариант>]`. + **Семья — в начале**, вариант — за ней: `sf-button-icon`, + `sf-input-date`, `sf-menu-context`, `sf-header-page`, `sf-view-table`. +- **Семья** — что это за деталь: `button`, `input`, `menu`, `header`, + `view`, `slider`. Главный член семьи носит одно её имя: `sf-button`, + `sf-input`, `sf-menu`, `sf-view`. Остальные добавляют вариант: + `sf-button`, `sf-button-icon`, `sf-button-copy`, `sf-button-close`. +- **Набор** ставится впереди, только если компонент живёт лишь внутри + своего набора: `sf-admin-menu`, `sf-chat-threads`, `sf-chat-composer`. + Общая деталь имени набора не носит. +- Деталь без родни — одна семья из одного слова: `sf-modal`, `sf-tabs`. + Детали, похожие только ролью (хлебные крошки, шаги, страницы), — разные + семьи, а не одна. +- Вид одной детали — её настройки, а не новое имя: таблица, которая + выглядит иначе, остаётся `sf-view-table`. - После приставки — не больше трёх слов. ## Чего в имени нет @@ -37,16 +43,18 @@ description: "Как называются смарт-компоненты, их - Манифест называет семью компонента: `"family": "menu"`. Каталог, документация и Студия группируют по семье, поэтому все меню видны вместе, как бы они ни назывались. -- **Одна приставка `sf-`** — для всех компонентов SIMAI Framework и ui-pro. -- **Набор `sf-` растёт только через ui-pro.** Новое имя `sf-` сначала - выходит в ui-pro; базовый компонент потом переезжает в SIMAI Framework и - сохраняет имя. -- **Один реестр имён** на обоих. Имя занято, когда компонент выпущен; - второй компонент с занятым именем проверка не пропускает. -- Продукты SIMAI компонентов не делают. Компонент, который продукт всё же - выпустил, переезжает в ui-pro с именем `sf-` и сохраняет старое как - псевдоним с датой. Все поставляемые теги — `sf-`; `sf-chat-composer` - сделан в UI Chat и переехал в ui-pro. +- **Одна приставка `sf-`** — для SIMAI Framework и всех + [наборов компонентов](/ru/guide/sets/) SIMAI. +- **Семьёй владеет кто-то один.** Паспорт набора перечисляет семьи, которые + ему принадлежат (`admin`, `chat`, `mail`, `view`…); общий реестр не + пропускает семью, которую заявили два набора, и имя, которое уже занято. + Подробнее — [Имена в наборах](/ru/guide/sets/names/). +- **Общее — в SIMAI Framework.** Деталь, нужная больше чем одному набору, + уходит из набора в SIMAI Framework и становится общим смарт-компонентом; + набор собирает свои экраны из неё. +- Компонент, который сделал продукт, переезжает в набор или в + SIMAI Framework с именем `sf-` и сохраняет старое как псевдоним с датой: + `sf-chat-composer` сделан в UI Chat и переехал в набор `chat`. - **Пакет партнёра или проекта** берёт свою приставку, никогда не `sf-` — см. [Пакеты партнёров и проектов](/ru/guide/smart-components/packages/). - Слова продукта, места и вида, которых нет в именах, проверка берёт из @@ -59,14 +67,14 @@ description: "Как называются смарт-компоненты, их Экран записей — раздел админки Larena, окно чата, почтовый ящик — собирается из этих ролей; продукт берёт нужные. -| Роль | Что делает | В ui-pro | +| Роль | Что делает | Где сейчас | |:---|:---|:---| | `source` | спрашивает данные у хоста через порт по `collection`, `query`, `filters`, `sort` и `page`; применяет только новейший ответ (`concurrency: latest`); вычисляет состояние данных; сообщает о присланном без запроса и о потоках фактами | порты представления данных и свойств, порт чата | | `search` | текстовый запрос | поиск таблицы и админ-меню | | `filter` | условия на записи | фильтры таблицы | | `list` | показывает записи; открывает одну, выбирает несколько | `sf-view-table`, `sf-view`, `sf-chat-threads` | | `pagination` | страница, размер страницы, полоса массовых действий | `sf-pagination` | -| `feed` | лента, новое внизу, раннее по запросу | `sf-message-log` | +| `feed` | лента, новое внизу, раннее по запросу | `sf-message-log` (станет общим `sf-view-feed`) | | `record` | показывает и правит одну запись | `sf-view-properties` | | `actions` | команды для выбранного или записи | панель инструментов, действия строки | | `composer` | пишет новую запись | поле ввода UI Chat | @@ -106,8 +114,10 @@ description: "Как называются смарт-компоненты, их ## Имена событий - Просьба: `sf-<тег>-<глагол>`; факт: `sf-<тег>-<глагол>ed`. В имени — - **тег компонента**: `sf-property-view-close`, `sf-table-apply`, - `sf-thread-list-open`, `sf-property-view-saved`. Компонент пакета партнёра + **тег компонента**: `sf-view-properties-close`, `sf-view-table-apply`, + `sf-chat-threads-open`, `sf-view-properties-saved`. Когда тег + переименован, его события переименованы вместе с ним, а старые имена + событий приходят следом до той же даты, что и старый тег. Компонент пакета партнёра подставляет свой тег: `acme-map-pick`. - Манифест объявляет событие глаголом (`close`, `saved`), а DOM-имя выводит построение. @@ -226,6 +236,15 @@ id?}` значит «перестать ждать», а `wait` принимае ## Псевдонимы старых имён +**Теги.** Волна переименований тегов ноября 2026 (`sf-table` → +`sf-view-table`, `sf-datepicker` → `sf-input-date` и ещё 24 имени) — в +таблице на странице [Обновление](/ru/guide/connection/updating/). Старый тег +работает до **2027-01-01** и пишет в консоль, каким тегом его заменить. +Подсказки `sf-tooltip` и `sf-help-mark` станут одним `sf-popover` (с +`mark="help|info"` для знака «?» и «i»), когда этот выпуск выйдет. + +**События и ключи** первой волны (октябрь 2026): + Когда семья компонентов переходит на эти имена, каждое старое имя работает как псевдоним с датой. Прослойка отправляет сначала новое имя, затем старые, с одним `detail` и одной отменой, и записывает у каждого `since` и diff --git a/content/ru/guide/smart-components/packages.md b/content/ru/guide/smart-components/packages.md index df470577d..8193f92a5 100644 --- a/content/ru/guide/smart-components/packages.md +++ b/content/ru/guide/smart-components/packages.md @@ -5,7 +5,8 @@ description: "Как партнёр или проект заказчика вы # Пакеты партнёров и проектов -Компоненты SIMAI делают в SIMAI Framework и ui-pro, а партнёр или проект +Компоненты SIMAI делают в SIMAI Framework и в +[наборах компонентов](/ru/guide/sets/) SIMAI, а партнёр или проект заказчика может выпустить **свой пакет** компонентов. Страница описывает, кто может выпускать пакет, как называются его компоненты, как они входят в сборки SIMAI и что проверяется. @@ -14,12 +15,12 @@ description: "Как партнёр или проект заказчика вы | Кто | Может ли выпустить свои компоненты | |:---|:---| -| SIMAI Framework | да: базовые компоненты, приставка `sf-` | -| ui-pro | да: продвинутые и общие компоненты, приставка `sf-` | -| Продукт SIMAI: Larena, решения Bitrix, почта, чат | нет: нужный компонент делают в ui-pro | +| SIMAI Framework | да: общие компоненты, приставка `sf-` | +| Набор компонентов SIMAI (`view`, `admin`, `chat`, `mail`, `editor`, `effects`…) | да: компоненты своих семей, приставка `sf-` | +| Продукт SIMAI: Larena, решения Bitrix | нет: нужный компонент делают в наборе или в SIMAI Framework | | Партнёр, проект заказчика | да: пакет под своей приставкой | -Пакет зависит от SIMAI Framework или ui-pro, а не наоборот: компоненты SIMAI +Пакет зависит от SIMAI Framework и наборов, а не наоборот: компоненты SIMAI о пакетах партнёров ничего не знают. Пакет — это компоненты, которые выпускаются и версионируются вместе под одной приставкой. @@ -29,7 +30,7 @@ description: "Как партнёр или проект заказчика вы `acme-route-list`. - Приставка никогда не `sf-` и не `simai-` и не слово из списка `naming-words.json`. -- Остальные правила имён те же: главное слово в конце, не больше трёх слов +- Остальные правила имён те же: семья в начале, вариант за ней, не больше трёх слов после приставки, семья в поле `family` — см. [Имена и общие слова](/ru/guide/smart-components/names/). - События компонента пакета называются по его тегу: `acme-map-pick`. diff --git a/content/ru/index.md b/content/ru/index.md index 679e8e30a..a61070537 100644 --- a/content/ru/index.md +++ b/content/ru/index.md @@ -18,9 +18,9 @@ ::: Подробнее: [админка](/demos/home/admin/) на отдельной странице, -[чат](/ru/pro/chat/), [редактор](/ru/pro/editor/content-editor/). Все три — -компоненты [SIMAI Pro](/ru/pro/) с отдельной лицензией; остальное в SIMAI -Framework открыто под Apache-2.0. +[чат](/ru/pro/chat/), [редактор](/ru/pro/editor/editor/). Это +[наборы компонентов](/ru/guide/sets/) `admin`, `chat` и `editor` с лицензией +Pro; SIMAI Framework открыт под Apache-2.0. ## Три шага @@ -50,7 +50,7 @@ Framework открыто под Apache-2.0. :::features - **[Темы](/ru/guide/colour/themes/)** Светлая, тёмная и своя тема из одного цвета. - **[Обновление](/ru/guide/connection/updating/)** Закреплённый выпуск и журнал изменений. -- **[Фоновые эффекты](https://effects.simai.io/)** Живые фоны для первых экранов. +- **[Наборы компонентов](/ru/guide/sets/)** Админка, таблицы, чат, письма, редактор, эффекты. - **[Работа с ИИ](/ru/guide/standards/ai/)** Индекс `ai.json` и текстовая версия каждой страницы. ::: diff --git a/content/ru/pro/index.md b/content/ru/pro/index.md index 468f6b90c..4c8a5f819 100644 --- a/content/ru/pro/index.md +++ b/content/ru/pro/index.md @@ -5,6 +5,11 @@ description: "Компоненты SIMAI Pro: админка, чат, письм # Pro +> Компоненты Pro переходят в [наборы компонентов](/ru/guide/sets/): `admin`, +> `view`, `chat`, `mail`, `editor`. У каждого набора будет свой сайт с +> документацией и демонстрациями. Пока сайта набора нет, его компоненты +> описаны здесь, а пакет `pro` подключает их все сразу. + SIMAI Pro — большие смарт-компоненты для продуктов SIMAI: админка, чат, конструктор писем и редактор страниц. Они построены на SIMAI Framework и устроены так же, как его смарт-компоненты, но поставляются отдельно и под diff --git a/content/ru/section.json b/content/ru/section.json index 7815c4ec2..1191de682 100644 --- a/content/ru/section.json +++ b/content/ru/section.json @@ -33,6 +33,11 @@ "label": "Смарт-компоненты", "href": "/ru/smart/" }, + { + "id": "sets", + "label": "Наборы", + "href": "/ru/guide/sets/" + }, { "id": "pro", "label": "Pro", diff --git a/scripts/audit-guide-information-architecture.php b/scripts/audit-guide-information-architecture.php index c195c5419..ca5315583 100755 --- a/scripts/audit-guide-information-architecture.php +++ b/scripts/audit-guide-information-architecture.php @@ -51,6 +51,7 @@ ['Утилиты', '/ru/utilities/'], ['Компоненты', '/ru/components/'], ['Смарт-компоненты', '/ru/smart/'], + ['Наборы', '/ru/guide/sets/'], ['Pro', '/ru/pro/'], ]; $check($headerActual === $headerExpected, 'header_navigation_mismatch', ['actual' => $headerActual]); diff --git a/scripts/audit-reference-separation.php b/scripts/audit-reference-separation.php index 49c64b0eb..60e6b62d9 100644 --- a/scripts/audit-reference-separation.php +++ b/scripts/audit-reference-separation.php @@ -18,6 +18,8 @@ ['Утилиты', '/ru/utilities/'], ['Компоненты', '/ru/components/'], ['Смарт-компоненты', '/ru/smart/'], + // Component sets are taught in the guide; Pro stays until each set has its own site. + ['Наборы', '/ru/guide/sets/'], ['Pro', '/ru/pro/'], ], 'header_is_not_guide_plus_references', ['actual' => $actualHeader]); diff --git a/translations.lock.json b/translations.lock.json index 0cbd2421e..fd5b8979b 100644 --- a/translations.lock.json +++ b/translations.lock.json @@ -30,11 +30,11 @@ "locale": "en", "review": "ai_verified", "source_path": "content/ru/index.md", - "source_sha256": "a0ec35d67e1ad940d736713c212ba946e12e308631b4c844e68df57b860ae8d4", - "source_structure_sha256": "b1a193f4f03f149994ca921fe18e034a397b6a551b39570b3f71b3d69627c8e8", + "source_sha256": "a4b61800b80a90d810b9146b6b2e34b843d7962288ff0961c759fff5c2fe8aa2", + "source_structure_sha256": "e4c323242ea6efa7e2dd9b72e06c73c1773bba5d382af94f82507de236e1902b", "target_path": "content/en/index.md", - "target_sha256": "edd2e68a7ab7cee06b4210fd5c5c5adb34136c4835e60a3fba62e8c68e6bb746", - "target_structure_sha256": "b1a193f4f03f149994ca921fe18e034a397b6a551b39570b3f71b3d69627c8e8" + "target_sha256": "761d66228f0328fdc636c4974865835bfa1dc165def9472be9f8b44b17080310", + "target_structure_sha256": "e4c323242ea6efa7e2dd9b72e06c73c1773bba5d382af94f82507de236e1902b" } ], "exclusions": [],