Layout
Компонент предоставляет адаптивные шаблоны с основной навигацией, "оборачивающий виды роутера", и со слоями для окон всплывающих "поверх всего интерфейса" - поповеров, тултипов и модалей.
Использование
Дизайнеры создают актуальные макеты в двух основных шаблонах - "дашборд" и сайт. Но для того чтобы было можно легко начать внедрять Дизайн-Систему в уже распиленный проект существует и "пустой лейаут", "без верстки".
Роутинг
При разметке новых проектов в шаблонах "сайт" или "дашборд", вы должны "завернуть виды роутера" в основной слот main Лейаута (TODO - дальнейшие примеры еще требуют проверки):
Vue
<ds-layout token="site">
<router-view slot="main" />
</ds-layout>Angular
<ds-layout token="site">
<router-outlet slot="main"></router-outlet>
</ds-layout>React
import { Routes, Route } from 'react-router';
import { Layout } from '@rir/ds-library';
<Layout token="site">
<Routes slot="main">
<Route />
<Route />
<Route />
...
</Routes>
</Layout>Компонент Wrapper для горизонтальных отступов
Основной слот лейаута занимает "всю имеющуюся ширину", то есть - горизонтальные отступы затребованые дизайном не предоставляются через компонент Layout. Вы должны использовать обертку Wrapper для этого. Сделано так специально. Почему? По опыту, в очень многих ситуациях, при реализации сложных адаптивных дизайнов, верстка будет нуждаться в том, чтобы подобных горизонтальных отступов не было, чаще всего - на мобильном типоразмере. Часто встречающийся случай: слайдер с фотографиями, который на декстопах и таблетках находится "в теле сайта", то есть имеет отступы по бокам такие же как и у всего контента, а на наладонниках - должен занять всю ширину экрана. Здесь вам на помощь придет эффективное дублирование разметки с помощью предоставляемых Дизайн-Системой специальных адаптивных классов CSS.
<ds-layout token="site">
<!-- Обертка без отступов по горизонтали для всего основного контента -->
<main slot="main" role="main">
<!-- Предположим - секция для десктопов и планшетов, в которой некий слайдер фотографий "ограничен по краям" -->
<section class="visible--block--not-narrow">
<ds-wrapper>...Верстка для декстопов и планшетов...</ds-wrapper>
</section>
<!-- Дублирующая секция для смартфонов, в которой этот же слайдер занимает всю ширину экрана -->
<section class="visible--block--narrow">......Верстка для мобильных экранов...</section>
<!-- Еще какая-то секция -->
<section>
<ds-wrapper>...</ds-wrapper>
</section>
</main>
</ds-layout>Но если верстка внутри такой секции - может быть успешно переиспользована - вы можете "просто отключить отступы на мобилах", с помощью пропса full на Wrapper":
<ds-layout token="site">
<!-- Обертка без отступов по горизонтали для всего основного контента -->
<main slot="main" role="main">
<!-- -->
<section>
<ds-wrapper full>...Верстка которую можно переиспользовать на всех типоразмерах...</ds-wrapper>
</section>
<!-- Еще какая-то секция -->
<section>
<ds-wrapper>...</ds-wrapper>
</section>
</main>
</ds-layout>HTML
Передать данные в модель можно даже из HTML, следующим образом, с помощью значения в виде строки, которую сможет разобрать функция JSON.parse():
<ds-layout
token="dashboard"
breadcrumbs='[{ "id": "1", "text": "1111" }, { "id": "2", "text": "2222" }, { "id": "3", "text": "3333" }]'
menu='[{ "id": "1", "text": "1111" }, { "id": "2", "text": "2222" }, { "id": "3", "text": "3333" }]'
>
</ds-layout>WARNING
Для корректной работы компонента в данных конфигурации не должно быть одинаковых полей id для разных пунктов.
INFO
Для того чтобы сразу выбрать определенный элемент меню, нужно передать проп value компонента со значением id нужного элемента.
INFO
Обратите внимание!!! В примерах - устанавливается разная высота контента в слотах и используются готовые классы для адаптива для его подмены в слоте actions на разных типоразмеров.
Дизайн-Система покажет сообщения в консоли в следующих случаях:
- идентификатор (id) какого-либо элемента не указан, неверного типа или пустой
- идентификатор не уникальный
- отсутсвует основная подпись (text) у какого-либо элемента
- основная подпись не уникальна
Или установить из javascript:
.slot40 {
height: 40px;
}
.slot32 {
height: 30px;
}<!-- Клавиша с идентификатором "1" будет "выбрана" по умолчанию -->
<ds-layout id="layout" token="dashboard" value="1">
<div slot="logo" class="slot40">
header
</div>
<div slot="footer" class="slot32">
footer
</div>
<div slot="actions" class="slot40 visible--block--not-narrow">
actions
</div>
<div slot="actions" class="slot32 visible--block--narrow">
actions
</div>
<main slot="main">
content
</main>
</ds-layout>
<script>
const layout = document.getElementById('layout');
if (layout) {
const breadcrumbs = {
model: [
{
id: '1',
text: '1111 43534 4534',
},
{
id: '2',
text: '2222 3333 345455',
width: 80,
disabled: true,
},
// ...
],
};
const menu = {
model: [
{
id: '1dfs',
text: '1111',
icon: 'avatar',
bulb: '99+',
color: 'fargo',
},
{
id: '5hjmg',
text: '55555 sdaf asd asd asd asdsa asddf',
icon: 'avatar',
childrens: [
{
id: '10vbchnjg',
text: '2222 sdaf asd asd asd asdsa asddf asdf dsf zsdFFGZSDFDF',
disabled: true,
icon: 'avatar',
},
// ...
],
},
{
id: '6bvnb',
text: '2222 sdaf asd asd asd asdsa asddf asdf dsf zsdFFGZSDFDF sdaF dsf DFS dfgg dfdfg fdgh fdgd f ',
icon: 'avatar',
childrens: [
{
id: '10ghf',
text: '2222 sdaf asd asd asd asdsa asddf asdf dsf zsdFFGZSDFDF sdaF dsf DFS dfgg dfdfg fdgh fdgd f ',
icon: 'avatar',
childrens: [
{
id: '10vhgjhj',
text: '2222 sdaf asd asd asd asdsa asddf asdf dsf zsdFFGZSDFDF sdaF dsf DFS dfgg dfdfg fdgh fdgd f ',
icon: 'avatar',
childrens: [
{
id: '10vhg444jhj',
text: '2222 sdaf asd asd asd asdsa asddf asdf dsf zsdFFGZSDFDF sdaF dsf DFS dfgg dfdfg fdgh fdgd f ',
disabled: true,
icon: 'avatar',
},
// ...
],
},
// ...
],
},
// ...
],
},
// ...
],
};
layout.setAttribute('breadcrumbs', JSON.stringify(breadcrumbs));
layout.setAttribute('menu', JSON.stringify(menu));
layout.addEventListener('input', (e) => {
// В консоль выведет идентефикатор по полю id актуального выбора и всю модель группы целиком
console.log(
'Выбор в Лейауте:',
e.target.getAttribute('value'),
);
});
}
</script>React
.slot40 {
height: 40px;
}
.slot32 {
height: 30px;
}import { useState, useCallback } from 'react';
import { Layout } from '@rir/ds-library';
const menu = {
model: [
{
id: '1dfs',
text: '1111',
childrens: [
{
id: 'a1dfs',
text: '11112222',
},
// ...
],
},
{
id: '33433',
text: '22222',
},
{
id: '335433',
text: '333333',
},
{
id: '44fdgd4',
text: '444444',
childrens: [
{
id: 'bba1dfs',
text: '4444441111',
},
// ...
],
},
// ...
],
};
function Component() {
const [value, setValue] = useState('');
const onInput = useCallback((e: Event) => {
// В консоль выведет идентефикатор по полю id актуального выбора и всю модель списка целиком
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
console.log('Выбор на Сайте:', e.target?.getAttribute('value'));
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
setValue(e.target.getAttribute('value'));
}, []);
return (
<>
<Layout
token="site"
menu={menu}
widthActionsWide="300"
>
<div slot="logo" className="slot40">
header
</div>
<div slot="footer" className="slot32">
footer
</div>
<div slot="actions" className="slot40 visible--block--not-narrow">
actions
</div>
<div slot="actions" className="slot32 visible--block--narrow">
actions
</div>
<main slot="main">
content
</main>
</Layout>
</>
);
}
export default Component;API
Props
| Name | Type | Description | Default |
|---|---|---|---|
| token | String: ['default', 'site', 'dashboard'] | Тип лейаута | 'default' |
| breadcrumbs | IBreadсrumb[] | Только для дашбордов. Модель данных для хлебных крошек | [] |
| menu | IMenuItem[] | Только для дашбордов и сайтов. Модель данных основного меню | [] |
| notifications | IMenuItem[] | Пропс динамический ключ для показа уведомлений | [] |
| value | undefined, String | Только для дашбордов и сайтов. Актуальный ввод, после первого выбора - содержит значение поле id кнопки по которой произошел последний щелчок мыши | undefined |
| lines | Number | Только для дашбордов. Максимальное количество строчек в меню | 1 |
| tooltipWidth | Number | Только для дашбордов. Ширина всплывающей подсказки в компактном режиме | 240 |
| popoverWidth | Number | Только для дашбордов. Ширина всплывающих окон в компактном режиме | 240 |
| popoverHeight | Number | Только для дашбордов. Максимальная высота всплывающих окон в компактном режиме | 240 |
| prevent | Boolean | Только для дашбордов и сайтов. Не закрывать поповеры при клике на элементы без вложенных уровней? | false |
| widthActionsWidest | Number | Только для дашбордов. Ширина слота actions на типоразмере widest | 320 |
| widthActionsWide | Number | Только для дашбордов и сайтов. Ширина слота actions на типоразмере wide | 320 |
| widthActionsMiddle | Number | Только для дашбордов и сайтов. Ширина слота actions на типоразмере middle | 240 |
| widthActionsNarrow | Number | Только для дашбордов и сайтов. Ширина слота actions на типоразмере narrow | 124 |
| text | String | Только для дашбордов. Заголовок | '' |
Events
| Name | Description |
|---|---|
| input | Событие на изменение ввода |
| notify | Клик на кнопку действия в уведомлении |
Slots
| Name | Description |
|---|---|
| main | Основной контент |
| header | Только для дашбордов. Слот заголовка |
| footer | Слот снизу меню |
| actions | Слот для управляющей области |
| modals | Слот для модалей |
| popovers | Слот для поповеров |
Примеры проектов
Дашборд - React
Сайт - React
Дефолт - React
Дашборд - Angular
Сайт - Angular
Дефолт - Angular
Дашборд - Vue
Сайт - Vue
Дефолт - Vue