oscript-ui
oscript-ui

Дерево разделов

Дерево разделов — навигация внутри объекта или приложения: список ссылок на разделы, при необходимости с вложенными. Колонкой оно стоит слева в доме настроек, рядом — в шапке страницы. Текущий раздел подсвечен индикатором Material, и подсвечивает его сервер.

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

  • У объекта или приложения больше пяти-шести разделов, и вкладками их уже не уместить.
  • Разделы группируются: «Доступ» и под ним «Метки», «Ключи».
  • Навигация должна стоять на каждой странице одинаково — в боковой колонке или в шапке.

Не берите дерево для двух-трёх видов одного объекта — им место во вкладках. Для выбора значений в иерархии есть дерево галок: там пункты отмечают, а здесь по ним переходят.

Колонкой#

Вертикаль — вид по умолчанию: пункты идут колонкой, каждый ростом 48 пикселей, вложенные сдвинуты вправо. Так выглядит колонка разделов в доме настроек и оглавление слева на этом сайте.

Вертикаль — дом настроек

Дети = Новый Массив(); Дети.Добавить(Новый Структура("Подпись, Адрес", "Метки", "/настройки/метки")); Разделы = Новый Массив(); Разделы.Добавить(Новый Структура("Подпись, Адрес, Активен, Иконка", "Общие", "/настройки", Истина, "шестерёнка")); Разделы.Добавить(Новый Структура("Подпись, Адрес, Дети", "Доступ", "/настройки/доступ", Дети)); HTML = Набор.ДеревоРазделов().Отрисовать(Новый Структура("Заголовок, Разделы", "Настройки проекта", Разделы));

В дереве холста имя дерева задаёт слово Заголовок, а разделы приходят прежним списком структур: слов для пунктов у дерева нет (см. Язык узлов).

Узлом холста — словами

Дети = Новый Массив(); Дети.Добавить(Новый Структура("Подпись, Адрес", "Метки", "/настройки/метки")); Разделы = Новый Массив(); Разделы.Добавить(Новый Структура("Подпись, Адрес, Активен, Иконка", "Общие", "/настройки", Истина, "шестерёнка")); Разделы.Добавить(Новый Структура("Подпись, Адрес, Дети", "Доступ", "/настройки/доступ", Дети)); HTML = Кит.ДеревоРазделов(Новый Структура("Разделы", Разделы)) .Заголовок("Настройки проекта").Рендер();

Пункт — пилюля ящика навигации Material. Текущий раздел залит цветом secondary-container; на наведении пункт проявляется слоем состояния.

Рубрики и опасный раздел#

Десять и больше разделов плоским списком не читаются. Поле раздела Рубрика группирует их: подпись рубрики печатается над первым разделом с этим именем — заголовком секции ящика навигации Material: title-small обычным регистром, приглушённо и с воздухом сверху. Разделы не переставляются: порядок остаётся тот, что пришёл, поэтому разделы одной рубрики кладите подряд.

Поле Опасный помечает раздел необратимого. Он печатается цветом ошибки, значок тоже, и стоит последним и без рубрики, где бы ни пришёл в списке. Открытый опасный раздел залит цветом error-container и несёт aria-current, как любой текущий.

Три рубрики и опасный раздел

Разделы = Новый Массив(); Разделы.Добавить(Настройки.Раздел("Удаление проекта", "/настройки/удаление", "корзина", Ложь, "", Истина)); Разделы.Добавить(Настройки.Раздел("Общие", "/настройки", "шестерёнка", Истина)); Разделы.Добавить(Настройки.Раздел("Участники", "/настройки/участники", "аккаунт", Ложь, "Доступ")); Разделы.Добавить(Настройки.Раздел("Ключи", "/настройки/ключи", "ключ", Ложь, "Доступ")); Разделы.Добавить(Настройки.Раздел("Почта", "/настройки/почта", "конверт", Ложь, "Оповещения")); Разделы.Добавить(Настройки.Раздел("Метки", "/настройки/метки", "тег", Ложь, "Оповещения")); Разделы.Добавить(Настройки.Раздел("История", "/настройки/история", "история", Ложь, "Журнал")); HTML = Кит.ДеревоРазделов(Новый Структура("Разделы", Разделы)) .Заголовок("Настройки проекта").Рендер();

В доме настроек рубрики и опасный раздел задаются словами: Рубрика(Подпись) у дома и Опасный() у раздела. В ряду шапки рубрики не печатаются — подпись между ходами читалась бы ещё одним ходом, по которому нельзя перейти. В группе разделов единого меню на телефоне — печатаются, в том же порядке.

Рядом#

Ориентация = «горизонталь» ставит пункты в ряд. Так каркас страницы печатает дороги приложения в шапке — тем же компонентом, с классом tree--top, который раздвигает пункты пошире.

Горизонталь — шапка

Дети = Новый Массив(); Дети.Добавить(Новый Структура("Подпись, Адрес", "Метки", "/настройки/метки")); Разделы = Новый Массив(); Разделы.Добавить(Новый Структура("Подпись, Адрес, Активен, Иконка", "Общие", "/настройки", Истина, "шестерёнка")); Разделы.Добавить(Новый Структура("Подпись, Адрес, Дети", "Доступ", "/настройки/доступ", Дети)); HTML = Набор.ДеревоРазделов().Отрисовать( Новый Структура("Заголовок, Разделы, Ориентация", "Основная навигация", Разделы, "горизонталь"));

В ряду вложенный список встаёт под своим пунктом и разрывает строку. Держите горизонталь в один уровень — как в гайдлайнах ниже.

Ряд дорог шапки

Дороги = Новый Массив(); Дороги.Добавить(Новый Структура("Подпись, Адрес, Иконка, Активен", "Проекты", "/проекты", "куб", Истина)); Дороги.Добавить(Новый Структура("Подпись, Адрес, Иконка", "Команды", "/команды", "стопка")); Дороги.Добавить(Новый Структура("Подпись, Адрес, Иконка", "Настройки", "/настройки", "шестерёнка")); HTML = Набор.ДеревоРазделов().Отрисовать( Новый Структура("Заголовок, Разделы, Ориентация, Класс", "Дороги приложения", Дороги, "горизонталь", "tree--top"));

Вложенность#

Дети раздела — массив той же формы, что и разделы. Компонент печатает всё, что пришло: свернуть ветку в браузере нельзя. Хотите показать подразделы только у текущего раздела — кладите Дети только ему, это решает сервер.

Ветка открыта у текущего раздела

Ключи = Новый Массив(); Ключи.Добавить(Новый Структура("Подпись, Адрес, Активен", "Ключи доступа", "/настройки/доступ/ключи", Истина)); Ключи.Добавить(Новый Структура("Подпись, Адрес", "Участники", "/настройки/доступ/участники")); Разделы = Новый Массив(); Разделы.Добавить(Новый Структура("Подпись, Адрес, Иконка", "Общие", "/настройки", "шестерёнка")); Разделы.Добавить(Новый Структура("Подпись, Адрес, Иконка, Дети", "Доступ", "/настройки/доступ", "замок", Ключи)); Разделы.Добавить(Новый Структура("Подпись, Адрес, Иконка", "Уведомления", "/настройки/уведомления", "конверт")); HTML = Набор.ДеревоРазделов().Отрисовать(Новый Структура("Заголовок, Разделы", "Настройки проекта", Разделы));

Глубина ограничена четырьмя уровнями: модель приходит извне, и раздел может оказаться в собственных детях. Всё, что глубже, не печатается.

Раздел без адреса или с опасной схемой адреса остаётся в списке подписью, но перестаёт быть ссылкой. Пустой список разделов не печатает ничего.

Гайдлайны#

ДелайтеВ ряду — один уровень разделов
Код
Разделы = Новый Массив();
Разделы.Добавить(Новый Структура("Подпись, Адрес, Активен", "Проекты", "/проекты", Истина));
Разделы.Добавить(Новый Структура("Подпись, Адрес", "Команды", "/команды"));
Разделы.Добавить(Новый Структура("Подпись, Адрес", "Настройки", "/настройки"));
HTML = Набор.ДеревоРазделов().Отрисовать(Новый Структура("Разделы, Ориентация", Разделы, "горизонталь"));
Не делайтеДети в ряду: вложенный список рвёт строку
Код
Дети = Новый Массив();
Дети.Добавить(Новый Структура("Подпись, Адрес", "Метки", "/команды/метки"));
Дети.Добавить(Новый Структура("Подпись, Адрес", "Квоты", "/команды/квоты"));
Разделы = Новый Массив();
Разделы.Добавить(Новый Структура("Подпись, Адрес, Активен", "Проекты", "/проекты", Истина));
Разделы.Добавить(Новый Структура("Подпись, Адрес, Дети", "Команды", "/команды", Дети));
Разделы.Добавить(Новый Структура("Подпись, Адрес", "Настройки", "/настройки"));
HTML = Набор.ДеревоРазделов().Отрисовать(Новый Структура("Разделы, Ориентация", Разделы, "горизонталь"));
ДелайтеТекущий раздел — ровно один
Код
Разделы = Новый Массив();
Разделы.Добавить(Новый Структура("Подпись, Адрес", "Общие", "/настройки"));
Разделы.Добавить(Новый Структура("Подпись, Адрес, Активен", "Доступ", "/настройки/доступ", Истина));
Разделы.Добавить(Новый Структура("Подпись, Адрес", "Уведомления", "/настройки/уведомления"));
HTML = Набор.ДеревоРазделов().Отрисовать(Новый Структура("Разделы", Разделы));
Не делайтеПодсвечены двое: где человек — непонятно
Код
Разделы = Новый Массив();
Разделы.Добавить(Новый Структура("Подпись, Адрес, Активен", "Общие", "/настройки", Истина));
Разделы.Добавить(Новый Структура("Подпись, Адрес, Активен", "Доступ", "/настройки/доступ", Истина));
Разделы.Добавить(Новый Структура("Подпись, Адрес", "Уведомления", "/настройки/уведомления"));
HTML = Набор.ДеревоРазделов().Отрисовать(Новый Структура("Разделы", Разделы));
ДелайтеИконки — у всех разделов уровня или ни у кого
Код
Разделы = Новый Массив();
Разделы.Добавить(Новый Структура("Подпись, Адрес, Иконка, Активен", "Общие", "/н", "шестерёнка", Истина));
Разделы.Добавить(Новый Структура("Подпись, Адрес, Иконка", "Доступ", "/н/доступ", "замок"));
Разделы.Добавить(Новый Структура("Подпись, Адрес, Иконка", "Уведомления", "/н/уведомления", "конверт"));
HTML = Набор.ДеревоРазделов().Отрисовать(Новый Структура("Разделы", Разделы));
Не делайтеИконка у одного пункта: колонка теряет ровный край
Код
Разделы = Новый Массив();
Разделы.Добавить(Новый Структура("Подпись, Адрес, Иконка, Активен", "Общие", "/н", "шестерёнка", Истина));
Разделы.Добавить(Новый Структура("Подпись, Адрес", "Доступ", "/н/доступ"));
Разделы.Добавить(Новый Структура("Подпись, Адрес", "Уведомления", "/н/уведомления"));
HTML = Набор.ДеревоРазделов().Отрисовать(Новый Структура("Разделы", Разделы));

Доступность#

  • Дерево печатается <nav> с aria-label: по умолчанию «Разделы», своё имя — поле Заголовок. На странице с несколькими навигациями имена обязаны различаться, иначе скринридер покажет два одинаковых «Разделы».
  • Текущий раздел-ссылка несёт aria-current="page"; цвет индикатора — только второй носитель этого смысла.
  • Вложенность выражена вложенными списками <ul>, поэтому скринридер называет уровень и число пунктов в нём.
  • Иконка пункта декоративна, имя пункта — его подпись. Пункт без подписи не называется ничем: подпись обязательна.
  • Рубрика — элемент списка с текстом, не ссылка: скринридер читает её на своём месте, перед разделами её группы.
  • Опасный раздел отличается не только цветом: он всегда последний, и подпись называет необратимое словами («Удаление проекта»).

Узлом холста#

На холсте дерево — узел рода «разделы»: его кладут в боковую колонку раскладки.

Дерево узлом

Дети = Новый Массив(); Дети.Добавить(Новый Структура("Подпись, Адрес", "Метки", "/настройки/метки")); Разделы = Новый Массив(); Разделы.Добавить(Новый Структура("Подпись, Адрес, Активен, Иконка", "Общие", "/настройки", Истина, "шестерёнка")); Разделы.Добавить(Новый Структура("Подпись, Адрес, Дети", "Доступ", "/настройки/доступ", Дети)); HTML = Кит.ДеревоРазделов(Новый Структура("Разделы", Разделы)) .Заголовок("Настройки проекта").Рендер();

Модель#

Структура ниже — прежний вид модели. В дереве холста из её полей словом пишется только Заголовок; Разделы, Ориентация и Класс по-прежнему передают структурой.

ДеревоРазделов.Отрисовать()src/Классы/компоненты/ДеревоРазделов.os

Отрисовывает дерево разделов.

Параметры:
 Модель - Структура - Заголовок (aria-label, "Разделы"), Разделы (массив структур
          Подпись, Адрес, Активен, Иконка, Рубрика (подпись над первым разделом с этим
          именем рубрики; в горизонтали не печатается), Опасный (раздел цветом ошибки,
          всегда последним и без рубрики), Дети — вложенные разделы той же формы),
          Класс, Ориентация ("вертикаль" | "горизонталь").

Возвращаемое значение:
 Строка - фрагмент <nav class="tree"> либо "" для пустого списка разделов.

Кит.ДеревоРазделов()src/Классы/холст/Кит.os

Дерево разделов — навигация по дому настроек. Слова: Заголовок.

Параметры:
 Модель - Структура - модель компонента «Дерево разделов».

Возвращаемое значение:
 ЭлементЭкрана

ДеревоРазделов.ПредельнаяГлубина()src/Классы/компоненты/ДеревоРазделов.os

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

Возвращаемое значение:
 Число

ДеревоРазделов.ПунктыПоПорядку()src/Классы/компоненты/ДеревоРазделов.os

Разделы в порядке печати и подписи рубрик над ними. Рубрика печатается над ПЕРВЫМ
разделом со своим именем: разделы не переставляются, поэтому порядок, который выбрал
дом, сохраняется. Опасные разделы уходят в конец и рубрики не получают: необратимое
не должно стоять между «Метками» и «Тегами», и под чужой рубрикой ему тоже не место.

Параметры:
 Разделы - Массив из Структура - разделы одного уровня, см. Отрисовать.

Возвращаемое значение:
 Массив из Структура - Раздел (структура раздела как пришла), Рубрика (подпись, которую
                       печатать над ним; "" — не печатать).