oscript-ui
oscript-ui

Реестр

Реестр — список немногих записей, у каждой из которых своя жизнь: подключения проекта, источники данных, ключи доступа, подписки на события. Свёрнутая строка записи отвечает «что это и в каком оно состоянии», справа от неё — действия, которые нужны без раскрытия, а раскрытое тело отдаёт подробности и кнопки.

Когда использовать#

  • Записей единицы, а не страницы, и каждую настраивают по отдельности: включают, переставляют, правят, удаляют.
  • У записи есть подробности, которые не нужны в списке, но нужны под рукой: адрес, ключ, расписание.
  • Состояние записи видно сразу — плашками у имени, — а действие над ней делается в одно касание, без перехода на отдельную страницу.

Не берите реестр для длинного списка, который листают и отбирают: такой список — таблица с пагинацией. Запись без действий и подробностей — это сводка в строке списка.

Запись: сводка, действия и тело#

Кит.Реестр(д…) собирается из записей Кит.ЗаписьРеестра(Имя, д…тело). Свёрнутая строка — сводка: Имя позицией, значок словом Значок, плашки словом Плашка, приглушённая строка словом Подпись, строки «подпись — значение» словом Факт. Дети записи — её тело, обычно свойства.

Второй холст Действия(д…) стоит справа от свёрнутой строки, вне неё: тумблер с СохранятьСразу, стрелки порядка. Третий холст Кнопки(д…) — набор действий записи: из него кит печатает и меню ⚙ у свёрнутой записи, и кнопки внизу раскрытого тела. У раскрытой записи меню прячется: те же действия уже на виду.

Подключения проекта: раскрытая запись, свёрнутая с меню, запись из конфигурации

  • Почтаработает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>. Своё число задаёт слово записи Номер(Число). Стрелки порядка — маленькая форма в Действия(д…) с двумя кнопками-значками: сервер переставляет запись и отвечает перенаправлением обратно.

Источники данных по порядку опроса

  1. 1https://data.example.org/доступен
    кэш
    900 с
  2. 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">. Кидается исключением, если Имя пусто.