Skip to content

Layout

Компонент предоставляет адаптивные шаблоны с основной навигацией, "оборачивающий виды роутера", и со слоями для окон всплывающих "поверх всего интерфейса" - поповеров, тултипов и модалей.

Использование

Дизайнеры создают актуальные макеты в двух основных шаблонах - "дашборд" и сайт. Но для того чтобы было можно легко начать внедрять Дизайн-Систему в уже распиленный проект существует и "пустой лейаут", "без верстки".

Роутинг

При разметке новых проектов в шаблонах "сайт" или "дашборд", вы должны "завернуть виды роутера" в основной слот main Лейаута (TODO - дальнейшие примеры еще требуют проверки):

Vue

html
<ds-layout token="site">
  <router-view slot="main" />
</ds-layout>

Angular

html
<ds-layout token="site">
  <router-outlet slot="main"></router-outlet>
</ds-layout>

React

js
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.

html
<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":

html
<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():

html
<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:

css
.slot40 {
  height: 40px;
}

.slot32 {
  height: 30px;
}
html
<!-- Клавиша с идентификатором "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

css
.slot40 {
  height: 40px;
}

.slot32 {
  height: 30px;
}
js
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

NameTypeDescriptionDefault
tokenString: ['default', 'site', 'dashboard']Тип лейаута'default'
breadcrumbsIBreadсrumb[]Только для дашбордов. Модель данных для хлебных крошек[]
menuIMenuItem[]Только для дашбордов и сайтов. Модель данных основного меню[]
notificationsIMenuItem[]Пропс динамический ключ для показа уведомлений[]
valueundefined, StringТолько для дашбордов и сайтов. Актуальный ввод, после первого выбора - содержит значение поле id кнопки по которой произошел последний щелчок мышиundefined
linesNumberТолько для дашбордов. Максимальное количество строчек в меню1
tooltipWidthNumberТолько для дашбордов. Ширина всплывающей подсказки в компактном режиме240
popoverWidthNumberТолько для дашбордов. Ширина всплывающих окон в компактном режиме240
popoverHeightNumberТолько для дашбордов. Максимальная высота всплывающих окон в компактном режиме240
preventBooleanТолько для дашбордов и сайтов. Не закрывать поповеры при клике на элементы без вложенных уровней?false
widthActionsWidestNumberТолько для дашбордов. Ширина слота actions на типоразмере widest320
widthActionsWideNumberТолько для дашбордов и сайтов. Ширина слота actions на типоразмере wide320
widthActionsMiddleNumberТолько для дашбордов и сайтов. Ширина слота actions на типоразмере middle240
widthActionsNarrowNumberТолько для дашбордов и сайтов. Ширина слота actions на типоразмере narrow124
textStringТолько для дашбордов. Заголовок''

Events

NameDescription
inputСобытие на изменение ввода
notifyКлик на кнопку действия в уведомлении

Slots

NameDescription
mainОсновной контент
headerТолько для дашбордов. Слот заголовка
footerСлот снизу меню
actionsСлот для управляющей области
modalsСлот для модалей
popoversСлот для поповеров

Примеры проектов

Дашборд - React

Сайт - React

Дефолт - React

Дашборд - Angular

Сайт - Angular

Дефолт - Angular

Дашборд - Vue

Сайт - Vue

Дефолт - Vue