Реестр
Реестр — список немногих записей, у каждой из которых своя жизнь: подключения проекта, источники данных, ключи доступа, подписки на события. Свёрнутая строка записи отвечает «что это и в каком оно состоянии», справа от неё — действия, которые нужны без раскрытия, а раскрытое тело отдаёт подробности и кнопки.
Когда использовать#
- Записей единицы, а не страницы, и каждую настраивают по отдельности: включают, переставляют, правят, удаляют.
- У записи есть подробности, которые не нужны в списке, но нужны под рукой: адрес, ключ, расписание.
- Состояние записи видно сразу — плашками у имени, — а действие над ней делается в одно касание, без перехода на отдельную страницу.
Не берите реестр для длинного списка, который листают и отбирают: такой список — таблица с пагинацией. Запись без действий и подробностей — это сводка в строке списка.
Запись: сводка, действия и тело#
Кит.Реестр(д…) собирается из записей Кит.ЗаписьРеестра(Имя, д…тело). Свёрнутая строка — сводка: Имя позицией, значок словом Значок, плашки словом Плашка, приглушённая строка словом Подпись, строки «подпись — значение» словом Факт. Дети записи — её тело, обычно свойства.
Второй холст Действия(д…) стоит справа от свёрнутой строки, вне неё: тумблер с СохранятьСразу, стрелки порядка. Третий холст Кнопки(д…) — набор действий записи: из него кит печатает и меню ⚙ у свёрнутой записи, и кнопки внизу раскрытого тела. У раскрытой записи меню прячется: те же действия уже на виду.
Подключения проекта: раскрытая запись, свёрнутая с меню, запись из конфигурации
ПочтаработаетSMTP · TLS
- сервер
smtp.example.org:587- отправитель
- noreply@example.org
- письма
- о сбоях и новых участниках
Чат-ботвебхуквыключенитоги сборок в чат команды
- канал
- #сборки
Корпоративный входиз конфигурацииправится в файле конфигурации
- издатель
https://sso.example.org
HTML = Кит.Реестр(
Кит.ЗаписьРеестра("Почта",
Кит.Свойства(
Кит.Свойство("сервер", Кит.Код("smtp.example.org:587")),
Кит.Свойство("отправитель", "noreply@example.org"),
Кит.Свойство("письма", "о сбоях и новых участниках")))
.Значок("конверт").Плашка(Кит.Плашка("работает").Вид("ok")).Подпись("SMTP · TLS")
.Действия(Кит.Форма("/проекты/альфа/почта/вкл",
Кит.Тумблер("вкл", "Почта включена").Включено().СохранятьСразу(),
Кит.Кнопка("Сохранить").Иконка("сохранить").ТолькоИконка().Малая()).БезПерезагрузки())
.Кнопки(
Кит.Кнопка("Изменить").Вторичная().Иконка("карандаш").Адрес("/проекты/альфа/почта"),
Кит.Форма("/проекты/альфа/почта/проверить",
Кит.Кнопка("Проверить").Вторичная().Иконка("галочка")),
Кит.Форма("/проекты/альфа/почта/удалить",
Кит.Кнопка("Удалить").Опасная().Иконка("корзина")))
.Открыть(),
Кит.ЗаписьРеестра("Чат-бот", Кит.Свойства(Кит.Свойство("канал", "#сборки")))
.Значок("ссылка").Плашка("вебхук").Плашка(Кит.Плашка("выключен"))
.Подпись("итоги сборок в чат команды")
.Действия(Кит.Форма("/проекты/альфа/чат/вкл",
Кит.Тумблер("вкл", "Чат-бот включён").СохранятьСразу(),
Кит.Кнопка("Сохранить").Иконка("сохранить").ТолькоИконка().Малая()).БезПерезагрузки())
.Кнопки(
Кит.Кнопка("Изменить").Вторичная().Иконка("карандаш").Адрес("/проекты/альфа/чат"),
Кит.Форма("/проекты/альфа/чат/удалить",
Кит.Кнопка("Удалить").Опасная().Иконка("корзина"))),
Кит.ЗаписьРеестра("Корпоративный вход", Кит.Свойства(Кит.Свойство("издатель",
Кит.Код("https://sso.example.org"))))
.Значок("замок").Плашка(Кит.Плашка("из конфигурации").Вид("warn"))
.Подпись("правится в файле конфигурации")
.Действия(Кит.Тумблер("", "Корпоративный вход включён").Включено().Заблокировано()))
.Подпись("Подключения проекта").Токен("т0кен").Рендер();Без скрипта запись работает целиком: раскрывается нативный <details>, меню ⚙ открывает браузер (popover), кнопки и формы — обычные ссылки и отправки. Тумблер с СохранятьСразу отправляет свою форму скриптом кита по щелчку; без скрипта отправить её нечем, кроме её же кнопки, — поэтому кладите в форму тумблера кнопку «Сохранить» (значком — место у свёрнутой строки дорого): лист стилей прячет её там, где скрипт есть (@media (scripting: enabled)).
Набор действий: меню и кнопки из одного списка#
В Кнопки(д…) кладут кнопки, ссылки-кнопки и формы из одной кнопки. Каждое действие печатается дважды: пунктом меню ⚙ (вид пункта задаёт меню, какой бы вариант кнопки ни пришёл) и кнопкой внизу тела — тем вариантом, что задан. Держать два списка одинаковыми руками не нужно. Имя меню — «Действия: имя записи», из словаря интерфейса по ключу registry.entry.actions. Идентификаторы на странице не повторяются: id (якорь формы, форма с подтверждением) несёт пункт меню, а копия внизу печатается без него и ссылается на пункт меню — кнопка подтверждения шлёт форму меню атрибутом form. Формы одинаковы, поэтому уходит одно и то же, откуда бы ни нажали.
Свёрнутая запись: действия в меню ⚙
Ключ для сборкичтениепоследний входвчера, 18:40
- права
- чтение
HTML = Кит.Реестр(
Кит.ЗаписьРеестра("Ключ для сборки", Кит.Свойства(Кит.Свойство("права", "чтение")))
.Значок("ключ").Плашка("чтение").Факт("последний вход", "вчера, 18:40")
.Кнопки(
Кит.Кнопка("Продлить").Вторичная().Иконка("часы").Адрес("/ключи/сборка/продлить"),
Кит.Форма("/ключи/сборка/отозвать",
Кит.Кнопка("Отозвать").Опасная().Иконка("корзина"))))
.Токен("т0кен").Рендер();Запись без тела и без кнопок раскрывать нечем: её свёрнутая строка печатается обычной строкой панели, без <details>.
Запись без подробностей
- Аннавладелецanna@example.org
- Борисучастникboris@example.org
HTML = Кит.Реестр(
Кит.ЗаписьРеестра("Анна").Значок("аккаунт").Плашка(Кит.Плашка("владелец").Вид("accent"))
.Подпись("anna@example.org"),
Кит.ЗаписьРеестра("Борис").Значок("аккаунт").Плашка("участник")
.Подпись("boris@example.org")).Рендер();Окна и подтверждения записи#
Действие из набора часто открывает окно: правку записи или подтверждение удаления. Само окно можно положить в тело записи, рядом с тем, к чему оно относится, — кит напечатает его после списка, а не внутри записи. Тело свёрнутой записи браузер не показывает: окно, открытое оттуда из меню ⚙, стало бы модальным, но невидимым, и страница замерла бы до Esc. Узел окна остаётся на своём месте в дереве, поэтому его идентификатор и связь с кнопками и формами набора прежние. Окно, напечатанное открытым (?окно=…), тоже стоит после списка — на виду.
Удаление из меню ⚙ спрашивает подтверждение
Ключ для сборки
- права
- чтение
Подтв = Кит.Подтверждение("Удалить ключ «сборка»?", "Сборка перестанет получать пакеты.")
.Эхо("name", "сборка").Кнопка("Удалить").Якорь("udalit-klyuch-sborka");
Правка = Кит.Окно("Права ключа «сборка»", Кит.Поле("rights", "Права").Значение("чтение"))
.Форма("/ключи/сборка").Адрес("/ключи?окно=права-сборка").Якорь("prava-klyuch-sborka")
.Действия(Кит.Кнопка("Сохранить").Основная());
HTML = Кит.Реестр(
Кит.ЗаписьРеестра("Ключ для сборки", Кит.Свойства(Кит.Свойство("права", "чтение")), Правка, Подтв)
.Значок("ключ")
.Кнопки(
Кит.Кнопка("Права").Вторичная().Иконка("карандаш").Открывает(Правка),
Кит.Форма("/ключи/сборка/удалить", Кит.Кнопка("Удалить").Опасная().Иконка("корзина"))
.СПодтверждением(Подтв)))
.Токен("т0кен").Рендер();Окну, которое отправляет форму вокруг себя внутри записи, своей формы нет: вынести его за список нельзя, и сборка останавливается с подсказкой. Дайте такому окну свою форму словом Форма(…), а подтверждение назовите у формы словом СПодтверждением(…).
Порядок и номера#
У реестра, где порядок значим — порядок опроса источников, очередь, приоритет, — слово Нумерованный(): записи нумеруются по порядку, а список печатается <ol>. Своё число задаёт слово записи Номер(Число). Стрелки порядка — маленькая форма в Действия(д…) с двумя кнопками-значками: сервер переставляет запись и отвечает перенаправлением обратно.
Источники данных по порядку опроса
1https://data.example.org/доступен
- кэш
- 900 с
2https://mirror.example.org/не отвечает с 7 октября
- кэш
- 300 с
HTML = Кит.Реестр(
Кит.ЗаписьРеестра("https://data.example.org/", Кит.Свойства(Кит.Свойство("кэш", "900 с")))
.Плашка(Кит.Плашка("доступен").Вид("ok"))
.Действия(Кит.Форма("/источники/1/порядок",
Кит.Кнопка("Ниже").Иконка("вниз").ТолькоИконка().Малая().Вторичная().Имя("сдвиг", "вниз"),
Кит.Кнопка("Выше").Иконка("вверх").ТолькоИконка().Малая().Вторичная().Имя("сдвиг", "вверх")
.Заблокирована())),
Кит.ЗаписьРеестра("https://mirror.example.org/", Кит.Свойства(Кит.Свойство("кэш", "300 с")))
.Плашка(Кит.Плашка("не отвечает с 7 октября").Вид("err"))
.Действия(Кит.Форма("/источники/2/порядок",
Кит.Кнопка("Ниже").Иконка("вниз").ТолькоИконка().Малая().Вторичная().Имя("сдвиг", "вниз")
.Заблокирована(),
Кит.Кнопка("Выше").Иконка("вверх").ТолькоИконка().Малая().Вторичная().Имя("сдвиг", "вверх"))))
.Нумерованный().Подпись("Источники данных").Токен("т0кен").Рендер();Значок или картинка#
Значок(ИмяГлифа) — глиф из набора кита. Картинка(Адрес) — картинка инсталляции, например логотип сервиса: она старше значка. Обе декоративны — имя записи стоит рядом текстом.
Картинка инсталляции вместо глифа
Каталогосновной каталог
HTML = Кит.Реестр(
Кит.ЗаписьРеестра("Каталог").Картинка("/static/знак.svg").Подпись("основной каталог"))
.Рендер();Пустой реестр#
Реестр без записей печатает пустое состояние вместо списка. Текст задаёт слово Пусто(Текст); без него — текст словаря интерфейса по ключу registry.empty. Свои узлы — кнопку «Добавить», ссылку на справку — кладут в тот же холст: Пусто(д…).
Подключений ещё нет
Подключений пока нет. Добавьте почту или чат, чтобы получать итоги сборок.
HTML = Кит.Реестр().Пусто("Подключений пока нет. Добавьте почту или чат, чтобы получать итоги сборок.").Рендер();Свои узлы на месте пустого реестра
Ключей пока нет.
HTML = Кит.Реестр().Пусто(Кит.ПустоеСостояние("Ключей пока нет.").Компактное()
.Действие(Кит.Кнопка("Создать ключ").Основная().Иконка("плюс").Адрес("/ключи/новый"))).Рендер();На телефоне#
До 640 px свёрнутая строка переносит плашки на следующие строки — имя остаётся первым, — действия справа сужают её ровно на свою ширину, а кнопки внизу тела встают столбиком во всю ширину, под палец.
Гайдлайны#
Почтаработает
- сервер
smtp.example.org
Код
HTML = Кит.Реестр(
Кит.ЗаписьРеестра("Почта", Кит.Свойства(Кит.Свойство("сервер", Кит.Код("smtp.example.org"))))
.Значок("конверт").Плашка(Кит.Плашка("работает").Вид("ok"))).Рендер();- Почта smtp.example.org:587, отправитель noreply@example.org, TLS
Код
HTML = Кит.Реестр(
Кит.ЗаписьРеестра("Почта smtp.example.org:587, отправитель noreply@example.org, TLS")
.Значок("конверт")).Рендер();Ключ для сборки
- права
- чтение
Код
HTML = Кит.Реестр(
Кит.ЗаписьРеестра("Ключ для сборки", Кит.Свойства(Кит.Свойство("права", "чтение")))
.Значок("ключ")
.Кнопки(Кит.Кнопка("Продлить").Вторичная().Адрес("/ключи/сборка/продлить"))).Рендер();Ключ для сборки
- права
- чтение
Код
HTML = Кит.Реестр(
Кит.ЗаписьРеестра("Ключ для сборки", Кит.Свойства(Кит.Свойство("права", "чтение")),
Кит.Кнопка("Продлить").Вторичная().Адрес("/ключи/сборка/продлить"))
.Значок("ключ")).Рендер();Доступность#
- Реестр — список
<ul>(нумерованный —<ol>), запись — его пункт: скринридер называет число записей и место каждой. Имя списку задаёт словоПодпись(aria-label). - Свёрнутая строка —
<summary>нативной раскрывашки: она берёт фокус, раскрывается Enter и пробелом, а состояние «развёрнуто» читает скринридер. - Действия лежат вне
<summary>: тумблер и кнопки не раскрывают запись и не читаются частью её названия. В разметке они стоят перед раскрывашкой, поэтому табуляция проходит действия записи, затем её свёрнутую строку. - Подпись тумблера в ряду действий скрыта визуально, но остаётся его именем для скринридера: задавайте тумблеру метку («Почта включена»).
- Меню ⚙ — кнопка-значок с именем «Действия: имя записи»; открытие, закрытие по Esc и возврат фокуса на кнопку даёт браузер (
popover). - Номер — часть свёрнутой строки и читается с именем; значок и картинка декоративны (
aria-hidden, пустойalt).
Модель#
В дереве холста реестр и запись собираются словами (см. Язык узлов); печатает их рисователь Реестр — ниже его модель.
Кит.Реестр()src/Классы/холст/Кит.os
Реестр — список немногих записей: провайдеров, подключений, подписок, ключей. Каждая запись — Кит.ЗаписьРеестра: свёрнутая строка-сводка, действия справа от неё и тело с подробностями. Без записей реестр печатает пустое состояние: текст — словом Пусто(Текст) (по умолчанию из словаря «registry.empty»), свои узлы — Пусто(д…). Слова: Нумерованный (номера по порядку, список <ol>), Пусто(д…), Подпись (имя списка для скринридера), Якорь. Параметры: Р1…Р8 - ЭлементЭкрана - (необязательные) записи, узлы Кит.ЗаписьРеестра. Возвращаемое значение: ЭлементЭкрана
Кит.ЗаписьРеестра()src/Классы/холст/Кит.os
Запись реестра. Дети — тело под свёрнутой строкой (обычно Кит.Свойства); второй холст Действия(д…) — то, что стоит справа от свёрнутой строки, вне её: тумблер с СохранятьСразу, стрелки порядка; третий холст Кнопки(д…) — набор действий записи: из него печатаются и меню ⚙ у свёрнутой записи, и кнопки внизу раскрытого тела. Слова: Значок(ИмяГлифа), Картинка(Адрес), Плашка(узел | текст), Подпись (повторный вызов добавляет часть через « · »), Факт(Подпись, Значение, Вид), Номер(Число), Открыть, Действия(д…), Кнопки(д…), Якорь. Параметры: Имя - Строка - название записи: имя, адрес, номер. Р1…Р8 - ЭлементЭкрана, Строка - (необязательные) тело записи; строка — текст. Возвращаемое значение: ЭлементЭкрана
Реестр.ОтрисоватьЗапись()src/Классы/холст/Реестр.os
Отрисовывает одну запись реестра — пункт списка.
Параметры:
Модель - Структура - Имя (обязательно: название в сводке и имя меню действий),
Значок (имя глифа кита перед именем), Картинка (адрес картинки инсталляции
вместо значка), Плашки (Массив моделей «Плашки» у имени), Подпись (Строка
либо Массив из Строка — части через « · »), Факты (Массив из Структура:
Подпись, Значение, Вид — "" | "warn"), Номер (Число или Строка — номер перед
значком), Открыта (Булево: тело раскрыто), Атрибуты (ДОВЕРЕННЫЙ фрагмент
атрибутов пункта), Тело (ДОВЕРЕННЫЙ HTML подробностей), Действия (ДОВЕРЕННЫЙ
HTML действий снаружи сводки), Кнопки (Массив из Строка — ДОВЕРЕННЫЙ HTML
каждого действия набора: им печатаются и меню ⚙, и кнопки внизу тела),
КнопкиНиже (Массив из Строка — ДОВЕРЕННЫЙ HTML тех же действий для кнопок
внизу тела, копия без id: id на странице несут пункты меню ⚙; не задан —
внизу печатаются Кнопки).
Номер - Число, Неопределено - (необязательный) порядковый номер, если свой Номер
у записи не задан.
Возвращаемое значение:
Строка - фрагмент <li class="entry">. Кидается исключением, если Имя пусто.