# Startup UI — full documentation
> Vue 3 UI component library for IT startups (great with Laravel + InertiaJS). Every component is prefixed with `S` (SButton, SInput, …) and strictly typed — read prop/emit/slot types from the .d.ts. FontAwesome and InertiaJS are optional, injected once via app.use(StartupUI, { icon, router, link }). Component docs below are written in Russian; the default runtime locale is English (switchable via configureStartupUi).
---
# Что такое Startup UI
Это библиотека UI-компонентов для [JavaScript-фреймворка Vue3](https://vuejs.org/), заточенная под типовые задачи IT-стартапов. Нативно интегрируется с эффективным для IT-стартапов стеком [Laravel](https://laravel.com/) + [InertiaJS](https://inertiajs.com/).
Разработан и активно используется в [Стартап-Бюро «Сухарь и партнеры»](https://suhar.ru/) в первую очередь для собственных стартапов, и предлагается для использования и создания своих стартапов всем веб-энтузиастам под лицензией MIT.
Чтобы более подробно изучить Startup UI, рекомендуем скачать example-app и локально запустить его по инструкции
## Зачем мы сделали ещё одну библиотеку компонентов
Все началось с того, что мы разработали три IT-стартапа с использованием [Element Plus](https://element-plus.org/), а потом переписали один из них под [PrimeVue](https://primevue.org/). В целом обе библиотеки отличные, но мы постоянно сталкивались с рядом сложностей:
1. Китайская Element Plus заточена под привычные в китайском сегменте пользовательские интерфейсы, американская PrimeVue — под американские. Ни там, ни там нет, например, подсказок под полями ввода в формах, или кликабельного лейбла у свитчера, которые привычны в русскоязычных интерфейсах. Из-за этого разные программисты реализовывают такие интерфейсы разным кодом, они выглядят по-разному и их проблемно переиспользовать между разными проектами.
2. В классических Vue3-библиотеках не хватает более глубокой интеграции со стеком Laravel + InertiaJS: чтобы формы сразу выводили ошибки валидации, пришедшие из FormRequest-ов; чтобы фильтры и постраничная навигация бесшовно работали в связке с SPA-роутером InertiaJS.
3. В обоих библиотеках поддержка иконок реализована на уровне собственной небольшой библиотеки иконок. Не хватает нативной поддержки [Font Awesome](https://fontawesome.com/) — самой большой библиотеки бесплатных иконок, которую очень удобно использовать для быстрого создания интерфейсов в IT-стартапах.
4. Локализация на русский язык идет по совсем остаточному принципу, и периодически это выглядит как машинный перевод.
5. ... и многие другие моменты. В [документации компонентов](/pages/components/forms/sform.html) почти для каждого компонента мы описываем блок «В чем отличие от аналогов?», в котором можно прочитать про это более детально.
Недостающий функционал мы стали реализовывать собственными новыми SFC-компонентами, а также обертками вокруг компонентов популярных библиотек.
Со временем получилась вот такая библиотека, которой мы хотим поделиться с вами, чтобы вы быстрее и эффективнее могли создать свой IT-стартап, и как можно больше выдающихся IT-продуктов (в том числе глобальных) создавалось нашими соотечественниками!
## Как и зачем можно использовать Startup UI
Библиотека распространяется под лицензией MIT — используйте, как хотите.
Но эффективнее всего будет использовать эту библиотеку в веб-интерфейсе IT-стартапа (особенно хорошо для B2B SaaS), чтобы ускорить первоначальную реализацию, упростить взаимозаменяемость между страницами стартапа, дальнейшую поддержку, и внедрение нового функционала.
С использованием стека Laravel + InertiaJS + Vue3 + Startup UI один веб-программист может создавать стартапы с нуля до полноценного работоспособного MVP за 3 недели. (Мы в [Стартап-Бюро](https://suhar.ru/) так и делаем.)
---
# Установка
Добавляем Startup UI в свой проект и подключаем первый компонент.
## Добавляем в проект
Startup UI доступен в репозитории npm.
```sh
# Если используете npm
npm install startup-ui
# Если используете yarn
yarn add startup-ui
```
## Подключаем стили
```js
// app.js
import 'startup-ui/dist/index.css';
```
## Подключаем палитру
Начиная с мажорной версии библиотека **не включает** значения CSS-переменных `--s-*` в свой CSS — она их только использует (`var(--s-primary)` и т.п.). Это убирает конфликт «несколько источников одной переменной» в инструментах и даёт проекту полный контроль над палитрой.
Выберите один вариант:
```js
// Вариант А: подключить готовую палитру по умолчанию
import 'startup-ui/defaults.css';
```
```scss
/* Вариант Б: задать свою палитру (resources/css/variables.scss) */
:root {
--s-primary: #2563eb;
--s-primary-dark: #1e40af;
/* ...остальные --s-* (полный список — на странице «Цвета и настройки») */
}
```
## Регистрация плагина и локализация
Можно импортировать компоненты по отдельности (как ниже), либо зарегистрировать плагин глобально. При регистрации задаётся локаль (по умолчанию — **английская**):
```js
// app.js
import StartupUI from 'startup-ui';
app.use(StartupUI, {
locale: 'ru', // 'en' по умолчанию; 'ru' включает русскую локализацию
// messages: { ru: { confirm: { accept: 'Подтвердить' } } } // точечное переопределение строк
});
```
Подробнее — на странице [«Локализация»](/pages/welcome/basics/localization).
## Подключение с InertiaJS
Startup UI не требует InertiaJS. Без него ссылки в меню и пагинации работают как обычные `` (с перезагрузкой страницы), а формы отправляйте через событие `@submit`.
Если же проект на Inertia, передайте при регистрации плагина две вещи из `@inertiajs/vue3` — роутер `router` и компонент ссылок `Link`. После этого компоненты с навигацией начнут работать «по-Inertia», без перезагрузки страницы:
```js
// app.js
import StartupUI from 'startup-ui';
import { router, Link } from '@inertiajs/vue3';
app.use(StartupUI, {
locale: 'ru',
router, // отправка SForm, пагинация SPagination, фильтры SFilterGroup (bind-to-query)
link: Link, // ссылки в меню (SMenu / SVerticalMenu) и пагинации
});
```
Что это включает:
- **SForm** — отправку формы по `method`/`action` (Inertia-визит с подстановкой ошибок валидации);
- **SPagination** и **SFilterGroup** (`bind-to-query`) — переключение страниц и фильтров без перезагрузки;
- **меню и пагинацию** — SPA-ссылки вместо обычных ``.
На стороне бэкенда: для клиента @inertiajs/core 3.x включите в config/inertia.php опцию use_script_element_for_initial_page — иначе начальная страница не прочитается и вы получите пустой экран без ошибок.
## Подключение иконок
Иконки в `SActionIcon`, `SNote`, `SStatus` (и опционально в `STooltip`, `SDatePicker`) рендерятся через FontAwesome — она **опциональна** и подключается отдельно. Как установить FA и зарегистрировать рендерер (глобально или инъекцией при подключении плагина) — на странице [«Иконки»](/pages/welcome/basics/icons).
## Добавляем первый компонент
Чтобы убедиться, что всё работает, добавляем любой компонент в SFC-шаблон:
```
## Компактные ячейки
По умолчанию у ячеек комфортные отступы. Для плотных таблиц с большим количеством данных можно уменьшить отступы атрибутом compact.
```vue
Пользователь
Тариф
Баланс
Роль
Дата регистрации
{{ row.username }}
{{ row.plan }}
{{ row.balance }}
{{ row.role }}
{{ row.created_at }}
ИТОГО
{{ totalBalance }}
```
## Фиксированная шапка
Чтобы зафиксировать шапку, устанавливаем высоту таблицы в атрибуте `height`.
```vue
Пользователь
Имя
Фамилия
Дата рождения
Рост
Вес
Тариф
Баланс
Роль
Дата регистрации
{{ row.username }}
{{ row.name }}
{{ row.secondname }}
{{ row.birthdate }}
{{ row.height }}
{{ row.weight }}
{{ row.plan }}
{{ row.balance }}
{{ row.role }}
{{ row.created_at }}
ИТОГО
{{ totalBalance }}
```
Для высоты таблицы с фиксированной шапкой удобно использовать 80vh, чтобы таблица занимала 80% от высоты экрана.
## Горизонтальный скролл сверху
```vue
Пользователь
Имя
Фамилия
Дата рождения
Рост
Вес
Тариф
Баланс
Роль
Дата регистрации
{{ row.username }}
{{ row.name }}
{{ row.secondname }}
{{ row.birthdate }}
{{ row.height }}
{{ row.weight }}
{{ row.plan }}
{{ row.balance }}
{{ row.role }}
{{ row.created_at }}
ИТОГО
{{ totalBalance }}
```
## Кастомный контент внутри tbody
Если нужно задать явные строки в tbody вместо перебора #row, то используем дефолтный слот (в нем для отдельных строк нужно явно указать `
`).
```vue
Пользователь
Тариф
Баланс
Роль
Дата регистрации
{{ user.username }}
{{ user.plan }}
{{ user.balance }}
{{ user.role }}
{{ user.created_at }}
ИТОГО
{{ totalBalance }}
```
## Несколько строк в header / footer
Если это нужно, просто используем отдельные слоты headers / footers (добавляется в конце "s"), в которые уже добавляем `
`.
```vue
...
...
...
...
...
```
## Сообщение о том, что нет данных
Когда задаем data и перебираем его через ``, то часто (например, когда есть фильтры страницы) бывает нужно показать состояние «Ничего не найдено», когда в data ноль строк. По умолчанию в таком случае выводится сообщение «Ничего не найдено», которое можно заменить на кастомное через пропс/слот nodata:
```vue
Пользователь
Тариф
Баланс
Роль
Дата регистрации
{{ row.username }}
{{ row.plan }}
{{ row.balance }}
{{ row.role }}
{{ row.created_at }}
ИТОГО
```
или
```vue
По заданным критериям поиска ничего не нашлось
Пользователь
Тариф
Баланс
Роль
Дата регистрации
{{ row.username }}
{{ row.plan }}
{{ row.balance }}
{{ row.role }}
{{ row.created_at }}
ИТОГО
```
## Интерфейс компонента
### Свойства (Props)
| Название | Тип | По умолчанию | Описание |
|----------|-----|--------------|----------|
| data | `T[] \| Record` | `undefined` | Массив или объект данных для итерации (используется вместе со слотом `#row`). |
| hoverable | boolean | `false` | Подсветка строки при наведении курсора. |
| striped | boolean | `false` | Чередование цвета фона строк (выделение четных строк). |
| bordered | boolean | `false` | Отрисовка границ (бордеров) у всех ячеек. |
| compact | boolean | `false` | Уменьшенные отступы в ячейках для плотных таблиц. |
| nodata | string | `'Ничего не найдено'` | Текст, выводимый, когда `data` пустое. |
| fixedHeader | boolean | `false` | Фиксированная шапка (принудительно), если не задана `height`. |
| height | string | `undefined` | Фиксированная высота таблицы (например, `300px` или `80vh`). Автоматически включает `fixedHeader`. |
| topScroll | boolean | `false` | Переносит горизонтальный скролл наверх таблицы. |
### Слоты (Slots)
| Название | Описание |
|----------|-------------|
| header | Содержимое `
` внутри ``. Подходит для большинства таблиц (без rowspan/colspan в шапке). |
| headers | Полный контроль над `` (вместо `header`). Нужно явно писать теги `
`. |
| row | Слот с областью видимости `{ row, index }`. Отрисовывается для каждого элемента из `data`. Внутри нужно писать только `
`. |
| default | Переопределяет содержимое `
`. Используется, если не передан `data`. Нужно явно писать теги `
`. |
| footer | Содержимое `
` внутри ``. |
| footers | Полный контроль над `` (содержит теги `
`). |
| nodata | Кастомный HTML для пустого состояния, заменяет пропс `nodata`. |
---
# STree
Дерево элементов.
Если сейчас перетаскивать элементы, но ничего не делать по drop-событию, то они не перетаскиваются.
## Базовый пример
```vue
```
Где `pages` — это массив вида: `[{id, label, children: [...]}, ...]`
## Выбор элемента
Для возможности выбора элемента добавляем атрибут selectable
```vue
В модель подставляется ID. Текущее значение: {{ value ?? 'null' }}
```
Также изменения можно отслеживать с помощью change-события:
```vue
console.log(node)" />
```
## Кастомный шаблон элемента
```vue
{{ node.label }}
```
## Раскрытые корневые элементы
Набор раскрытых корневых элементов передаём с помощью атрибута expanded-keys
```vue
```
## Перетаскивание элементов
Для поддержки перетаскивания элементов добавляем атрибут draggable
```vue
```
При этом выполняются события:
dragstart(node, event) — при начале перетаскивания;
drop(targetNode, event, dropType) — при заверешнии перетаскивания.
## Чек-боксы
Для поддержки чек-боксов у элементов добавляем атрибут checkboxes
```vue
Выбрано: {{ selectedPageIds }}
```
Если нужно, чтобы при выборе чек-бокса автоматически выбирались чек-боксы вложенных элементов, добавьте атрибут **select-with-children**:
```vue
Выбрано: {{ selectedPageIds }}
```
## Интерфейс компонента
### Свойства (Props)
| Название | Тип | По умолчанию | Описание |
|----------|-----|--------------|----------|
| data | `STreeNode[]` | - | Массив данных дерева. |
| expandedKeys | `(string \| number)[]` | `[]` | Список ID раскрытых узлов. |
| draggable | boolean | `false` | Разрешить перетаскивание узлов. |
| selectable | boolean | `false` | Разрешить выбор одного узла (через клик). |
| checkboxes | boolean | `false` | Отображать чекбоксы для множественного выбора. |
| selectWithChildren | boolean | `false` | При выборе родителя выбирать всех его детей. |
| storeExpandedKeysTo | string | - | Ключ в `localStorage` для сохранения состояния раскрытых узлов. |
| bordered | boolean | `false` | Добавить границы вокруг ячеек. |
### События (Events)
| Название | Параметры | Описание |
|----------|-----------|----------|
| dragstart | `(node: STreeNode, event: DragEvent)` | Вызывается при начале перетаскивания узла. |
| drop | `(targetNode: STreeNode, event: DragEvent, dropType: string \| undefined)` | Вызывается при завершении перетаскивания. |
| change | `(node: STreeNode)` | Вызывается при смене выбранного узла (если `selectable`). |
### Слоты (Slots)
| Название | Параметры | Описание |
|----------|-----------|----------|
| node | `{ node: STreeNode }` | Кастомный шаблон для содержимого узла дерева. |
---
# SCheckboxGroup > SCheckbox
Одиночная галочка или набор галочек.
В отличие от популярных библиотек компонентов для Vue3:
Сразу идет с кликабельным стандартизированным лейблом в качестве простого атрибута. Это унифицирует код и внешний вид компонентов, упрощается поддержка и взаимозаменяемость.
Поддерживает три формата передачи опций в группы чекбоксов, что удобно в зависимости от кейса:
<SCheckbox /> — там где опции являются частью дизайна, их можно и удобно хардкодить в шаблон;
{value1: title1, value2: title2} — что удобно для быстрого получения из key-value конфигов, а также из моделей — User::pluck('name', 'id');
[[value1, title1], [value2, title2]] — что удобно для выгрузки там, где важен порядок. Это минимизирует код в контроллерах, помогая сохранять принцип «тонкого контроллера», которого мы придерживаемся.
Взаимозаменяемость формата опций с другими выбиралками из вариантов. Это позволяет легко заменять SCheckboxGroup на SSelect или SRadioGroup, не трогая бэкенд код.
## Одиночная галочка
```vue
Я согласен
```
Модель принимает значение true/false.
## Группа галочек
```vue
ОшибкаВопросИдея
В модели будет храниться массив выбранных значений: {{ types }}
```
## Динамический набор значений
В предыдущем примере набор вариантов хардкодился в шаблоне, что удобно, когда набор значений относится к логическому уровню интерфейса. Но когда набор вариантов идет из базы данных или конфига, очень неудобно каждый раз формировать набор элементов через v-for, и вместо этого используем атрибут `options`.
```vue
```
Где options — это объект вариантов выбора в формате {value1: title1, value2: title2} или массив в формате [[value1, title1], [value2, title2]]
## Вертикальный список галочек
Чтобы выводить группу галочек вертикальным списком, добавляем атрибут `vertical`:
```vue
```
## Недоступное значение
Добавляем атрибут `disabled` значению, которое должно быть недоступно для переключения.
```vue
ОшибкаВопросИдея
```
## Интерфейс компонента SCheckboxGroup
### Свойства (Props)
| Название | Тип | По умолчанию | Описание |
|----------|-----|--------------|----------|
| v-model | `any[]` | `[]` | Массив выбранных значений. |
| options | Record \| Array | `{}` | Список вариантов (объект или массив пар). |
| vertical | boolean | `false` | Расположение элементов в колонку. |
### Слоты (Slots)
| Название | Описание |
|----------|----------|
| default | Содержимое группы (обычно компоненты `SCheckbox`). |
## Интерфейс компонента SCheckbox
### Свойства (Props)
| Название | Тип | По умолчанию | Описание |
|----------|-----|--------------|----------|
| v-model | any | - | Значение (для одиночного использования). |
| value | any | `undefined` | Значение элемента (для использования в группе). |
| disabled | boolean | `false` | Отключает возможность выбора. |
### Слоты (Slots)
| Название | Описание |
|----------|----------|
| default | Текст лейбла рядом с галочкой. |
### События (Events)
| Название | Параметры | Описание |
|----------|-----------|----------|
| change | `(value: any)` | Вызывается при изменении состояния. |
---
# SDatePicker
Поле выбора даты.
В отличие от популярных библиотек компонентов для Vue3:
Сразу из коробки по дефолту заточено под русскоязычную локализацию.
В отличие от западных библиотек — позволяет выбирать диапазон дат, начиная с более поздней даты. Удобно, когда нужно выбрать несколько последних месяцев.
## Стандартный пример
```vue
Текущее значение: {{ value ?? 'null' }}
```
Выбирает значение в формате `YYYY-MM-DD`.
## Минимальное и максимальное значения
```vue
```
## Кастомный формат значения
```vue
Текущее значение: {{ value ?? 'null' }}
```
Независимо от этого атрибуты min/max всегда идут в своём стандартном формате `YYYY-MM-DD`.
## Выбор периода
Для выбора периода добавляем атрибут `range`:
```vue
Текущее значение: {{ value ?? 'null' }}
```
В модель подставляется массив из двух дат в формате, указанном в `value-format`.
## Выбор вариантов кнопками
Очень часто в фильтрах по диапазону дат удобно использовать однокликовый выбор предзаданного диапазона. Набор таких диапазонов мы устанавливаем через атрибут `buttons`.
```vue
```
Набор доступных кнопок задается в формате {title: value.join('-')}, например: {"2 недели": "20250901-20250914", "Месяц": "20250815-20250914"}
Именно в этом формате backend-класс DateInterval возвращает набор доступных кнопок: `(new DateInterval(request()->period))->titles`
## Выбор времени
Чтобы выбирать время, добавляем атрибут `with-time`. При этом, выходное значение будет в формате 2025-12-22 12:27:
```vue
```
Часы и минуты — это `SSelect` с фильтрацией, поэтому значение можно как выбрать мышью, так и набрать с клавиатуры. В локалях с 12-часовым форматом (например `en-US`) вместо часов 0–23 показываются часы 1–12 и переключатель AM/PM.
## Очистка значения
Атрибут `clearable` добавляет кнопку очистки (×), которая появляется, когда значение выбрано:
```vue
Текущее значение: {{ value ?? 'null' }}
```
## Компактный инлайн-режим (чипы)
Пропс `compact` убирает жёсткую высоту поля и ужимает его по содержимому — удобно для инлайн-«чипов». `icon-position="start"` ставит иконку слева, `placeholder` задаёт текст пустого поля. Цвет иконки и значения наследуется от `color` инстанса, поэтому «красный флажок дедлайна» получается одним `style="color: …"` — без CSS-оверрайдов:
```vue
```
## Слот `#trigger` (headless)
Слот `trigger` заменяет поле произвольным элементом: клик по нему открывает календарь у триггера, `v-model` работает как обычно. Полезно для иконок-действий, ссылок, ячеек таблиц. В слот прокидываются `displayValue`, `value`, `isOpen` и методы `open` / `close` / `toggle`.
```vue
📅 {{ date ? displayValue : 'выбрать дату' }}
```
Календарь телепортируется в <body> как .s-datepicker-calendar. Если у вас есть свои обработчики «клик снаружи» (например, закрытие карточки), они посчитают клик по календарю кликом снаружи. Ориентируйтесь на события open / close или на класс .s-datepicker-calendar, а не на попадание внутрь корня компонента.
## Интерфейс компонента
### Свойства (Props)
| Название | Тип | По умолчанию | Описание |
|----------|-----|--------------|----------|
| v-model | `string \| string[]` | `null` | Выбранное значение (строка для одиночного выбора, массив для диапазона). |
| range | `boolean` | `false` | Режим выбора периода (диапазона дат). |
| value-format | `string` | `'YYYY-MM-DD'` | Формат значения в модели. Если `with-time` включен, по умолчанию `'YYYY-MM-DD HH:mm'`. |
| input-format | `string` | `'DD.MM.YYYY'` | Формат отображения даты в текстовом поле. |
| min | `string` | `undefined` | Минимально допустимая дата (в формате `YYYY-MM-DD`). |
| max | `string` | `undefined` | Максимально допустимая дата (в формате `YYYY-MM-DD`). |
| number-of-months | `number` | `1 \| 2` | Количество отображаемых месяцев в календаре (по умолчанию 2 для `range`, иначе 1). |
| buttons | `Record` | `undefined` | Набор кнопок быстрого выбора диапазона (`{ название: 'date1-date2' }`). |
| with-time | `boolean` | `false` | Позволяет выбирать время (часы и минуты). Только для одиночного выбора. |
| clearable | `boolean` | `false` | Показывает кнопку очистки (×), когда значение выбрано. |
| first-day | `number` | (из локали) | Первый день недели: `0` — воскресенье, `1` — понедельник. |
| icon | `string \| string[]` | `undefined` | Необязательная FontAwesome-иконка календаря (например `['far', 'calendar']`). По умолчанию используется встроенная SVG-иконка — компонент не требует FontAwesome. |
| placeholder | `string` | `undefined` | Текст пустого поля (приглушённый). Заменяет локализованное «Не выбрано». |
| icon-position | `'start' \| 'end'` | `'end'` | Сторона иконки календаря: `end` — справа, `start` — слева. Цвет иконки наследуется от `color` инстанса. |
| compact | `boolean` | `false` | Компактный инлайн-режим: высота по содержимому, поле не растягивается, ширина инпута — по формату. |
Названия дней недели и месяцев, а также 12/24-часовой формат времени больше не задаются атрибутами per-instance — они берутся из активной локали и переопределяются глобально через параметры локализации (`configureStartupUi`). Подробнее — в разделе [Локализация](/pages/welcome/basics/localization).
Иконки (календарь и стрелки переключения месяца) — встроенные SVG, поэтому FontAwesome для `SDatePicker` не обязателен. Дни соседних месяцев в сетке кликабельны. Поддерживается управление с клавиатуры: в фокусе стрелка вниз открывает календарь, стрелки двигают маркер по датам, Enter фиксирует выбор, Esc закрывает.
### События (Events)
| Название | Параметры | Описание |
|----------|-----------|----------|
| update:modelValue | `string \| string[] \| null` | Изменение значения (`v-model`). |
| open | — | Календарь открылся. |
| close | — | Календарь закрылся. |
### Слоты (Slots)
| Название | Пропсы слота | Описание |
|----------|--------------|----------|
| trigger | `{ isOpen, value, displayValue, open, close, toggle }` | Заменяет поле произвольным элементом (headless-режим). Клик открывает календарь у триггера. |
---
# SForm > SFormRow
SForm и SFormRow позволяют быстро собирать функциональные формы.
В отличие от популярных библиотек компонентов для Vue3:
Унифицирует и упрощает вспомогательные элементы (напр. подсказки под полями) и часто используемые состояния (напр. заголовки слева) до простых атрибутов. Это обеспечивает одинаковую реализацию разными программистами, избавляет от визуальных отличий, упрощает дальнейшую поддержку и сохраняет взаимозаменяемость между проектами.
Сразу из коробки связывает форму с InertiaJS-формами и/или Laravel FormRequest-ами, одинаково и аккуратно выводя ошибки валидации
Минимизируют синтаксис и связанность до одной модели на уровне SForm, что делает код чище, упрощает его написание, чтение и поддержку.
Сразу привязывать лейблы правильным образом к соответствующим input-полям, что обеспечит поддержку ARIA — это будет ценно для проектов на европейский рынок, т.к. там это требование законодательства.
## С формой InertiaJS
InertiaJS предлагает [useForm-компонент](https://inertiajs.com/docs/v2/data-props/remembering-state#form-helper), который мы используем по дефолту для всех форм.
```vue
Войти
```
Для компонентов внутри `` не нужно отдельно прописывать модель — она автоматически берется из модели `` по имени.
Аналогично не нужно как-то обрабатывать loading-состояние и отдельно выводить ошибки валидации — при необходимости этот функционал уже реализован в форме.
## С собственным submit-методом
Если по какой-то причине нам нужно вместо атрибутов `method`/`action` задать собственный `submit`-метод, сделать это можно следующим образом:
```vue
Войти
```
Так как мы используем собственный метод, то для показа состояния загрузки формы может понадобиться задавать свой набор ошибок `errors`, а также loading-состояние, которое показывает, находится ли сейчас форма в процессе отправки (чтобы избежать повторной отправки по ошибке)
## Подсказки под полями
Если под полем нужно выводить подсказку, это делается в ``:
```vue
Войти
```
## Заголовки слева
По умолчанию заголовки выводятся над полями формы, но иногда бывает нужно показать их слева от полей. Сделать это можно с помощью пропса `titles-at-left`. Ширину этих полей можно задать через `titles-width`.
```vue
Войти
```
## Установка моделей инпутов напрямую
По дефолту `` привязывает модели вложенных компонентов к соответствующему полю из модели ``. Но это делается исключительно для удобства и не является обязательным. Иногда, когда нужно задать модели вручную это возможно сделать напрямую:
```vue
Согласен с правиламиСогласен получать оповещения
```
## Вывод ошибок из кастомных ключей
Иногда бывает нужно выводить ошибки из кастомных ключей errors-массива (или вложенных путей). Сделать это можно с помощью атрибута `error-key`:
```vue
Отправить
```
Поддерживаются:
- Пути через точку: `orders.0`
- Звездочка для всех вложенных ключей: `orders.*`
- Массивы: `['orders.0', 'orders.1']`
## Интерфейс компонента SForm
### Свойства (Props)
| Название | Тип | По умолчанию | Описание |
|----------|-----|--------------|----------|
| form | object | - | Объект формы InertiaJS (рекомендуется). |
| method | string | `'post'` | HTTP-метод: `post`, `put`, `patch`, `delete`, `get`. |
| action | string | - | URL для отправки формы. |
| preserveScroll | boolean | `true` | Сохранять ли позицию скролла после отправки. |
| isDirty | boolean | `false` | Состояние «изменено» (предупреждение при уходе со страницы). |
| loading | boolean | `undefined` | Состояние загрузки (переопределяет внутреннее состояние формы). |
| summaryErrors | boolean | `false` | Показывать ли список всех ошибок вверху формы. |
### Слоты (Slots)
| Название | Описание |
|----------|----------|
| default | Содержимое формы (инпуты, кнопки и т.д.). |
## Интерфейс компонента SFormRow
### Свойства (Props)
| Название | Тип | По умолчанию | Описание |
|----------|-----|--------------|----------|
| title | string | - | Заголовок (лейбл) поля. |
| hint | string | - | Текст-подсказка под заголовоком. |
| error | string \| string[] | - | Текст ошибки или массив ошибок. |
| errorKey | string | - | Ключ ошибки в объекте `form.errors` (если используется пропс `errorKey`). |
| required | boolean | `false` | Помечает поле как обязательное (добавляет красную звездочку). |
| side | boolean | `false` | Располагает заголовок слева от поля (горизонтальный лейаут). |
### Слоты (Slots)
| Название | Описание |
|----------|----------|
| default | Содержимое строки (обычно компонент ввода — инпут, селект и т.д.). |
| title | Кастомный заголовок (вместо пропса title). |
| hint | Кастомная подсказка (вместо пропса hint). |
---
# SHtmlEditor
Визуальный HTML-редактор.
В отличие от популярных библиотек компонентов для Vue3:
Сразу используем самый удобный TinyMCE. Все остальные редакторы по юзабилити сильно хуже.
Поддержка ембеддинга видео из сервиса Kinescope, который в моменте является наиболее удобной заменой блокируемого YouTube
## Базовый пример
```vue
```
## Плейсхолдер
```vue
```
## Высота редактора
По умолчанию высота равна 300px. Изменить её можно пропом `height` — например, увеличить до 500px:
```vue
```
## Расширяемость
Конфигурацию TinyMCE можно глубоко переопределить пропом `init` (глубокий merge в дефолты). Поле `setup` композируется с библиотечным (вызывается после него и не затирает обёртку картинок), а `plugins` объединяются с базовыми.
```vue
```
- `header-offset` (или CSS-переменная `--s-header-height`) задаёт смещение шапки для корректного fullscreen.
- `content-style` добавляется к базовым стилям контента, `content-css` подключает внешние стили.
- Локаль интерфейса берётся из словаря (`htmlEditor.language`); язык можно задать и явно через `:init="{ language, language_url }"`.
## Интерфейс компонента
### Свойства (Props)
| Название | Тип | По умолчанию | Описание |
|----------|-----|--------------|----------|
| v-model | `string` | `undefined` | HTML-содержимое редактора. |
| upload-url | `string` | `undefined` | URL для загрузки изображений на сервер. |
| placeholder | `string` | `''` | Текст-заполнитель, когда редактор пуст. |
| height | `number` | `300` | Высота редактора, px. |
| media | `boolean` | `false` | Включить плагин медиа (видео-эмбеды). |
| plugins | `string[]` | `[]` | Доп. плагины TinyMCE (объединяются с базовыми). |
| toolbar | `string` | (дефолтный) | Переопределение тулбара. |
| menubar | `string \| boolean` | `false` | Меню-бар TinyMCE. |
| content-style | `string` | `undefined` | Доп. CSS контента (добавляется к базовому). |
| content-css | `string \| string[]` | `undefined` | Внешние CSS контента (`content_css`). |
| header-offset | `number` | `undefined` | Смещение шапки для fullscreen, px. |
| init | `object` | `undefined` | Глубокий merge в конфигурацию TinyMCE (наивысший приоритет). |
### События (Events)
| Название | Параметры | Описание |
|----------|-----------|----------|
| changeContent | - | Вызывается при любом изменении содержимого редактора. |
| init | `editor` | Инстанс TinyMCE готов — для регистрации кастомных плагинов/кнопок. |
---
# SInput
Базовые поля ввода.
В отличие от популярных библиотек компонентов для Vue3:
Исключает опции, которые, как правило, не используются в стартапах (напр. размеры полей), но из-за которых разные программисты реализовывают компонент по-разному. Без лишних опций унифицируется код и внешний вид компонентов, упрощается поддержка и взаимозаменяемость.
## Стандартные поля ввода
```vue
```
Также поддерживаются стандартные HTML-типы полей:
```vue
```
## Многострочное поле ввода
```vue
```
## Префикс / суффикс
Простой текст задаём пропами `prefix` / `suffix`, а для произвольного контента (иконки и т.п.) — одноимёнными слотами:
```vue
Подсказка к полю
```
## Недоступное состояние
```vue
```
## Поле ввода с кнопкой очистки
Добавляем атрибут `clearable` — кнопка очистки появляется, когда в поле есть значение:
```vue
```
## События
```vue
console.log(newValue)" placeholder="Печатаем и смотрим консоль" style="width: 100%" />
```
## Кастомные стили для инпута
Если нужно задать кастомные стили именно для вложенного инпута, то задаем их через `input-style`:
```vue
```
## Интерфейс компонента
### Свойства (Props)
| Название | Тип | По умолчанию | Описание |
|----------|-----|--------------|----------|
| modelValue / v-model | `number \| string \| null` | `undefined` | Связанное значение поля ввода. |
| type | `'text' \| 'string' \| 'number' \| 'email' \| 'password' \| 'textarea'` | `'text'` | Внутренний тип поля. При значении `textarea` отрисовывается многострочное поле. |
| placeholder | string | `undefined` | Текст-заполнитель, отображаемый, когда поле пустое. |
| prefix | string | `undefined` | Простой текст для отображения в начале поля. Добавляет класс `.has-prefix` обертке. |
| suffix | string | `undefined` | Простой текст для отображения в конце поля. Добавляет класс `.has-suffix` обертке. |
| clearable | boolean | `false` | Показывает кнопку очистки, когда в поле есть значение. |
| disabled | boolean | `false` | Флаг, отключающий интерактивность поля. |
| rows | number | `3` | Количество видимых строк текста (применяется только при `type="textarea"`). |
| inputStyle | `StyleValue` | `undefined` | CSS-стили, передаваемые напрямую внутреннему элементу (`input` или `textarea`). |
### Слоты (Slots)
| Название | Описание |
|----------|----------|
| prefix | Расширенный контент (например, иконки) перед текстом. Переопределяет проп `prefix`. |
| suffix | Расширенный контент (например, иконки) после текста. Переопределяет проп `suffix`. |
### События (Events)
| Название | Параметры | Описание |
|----------|-----------|----------|
| change | `(value: string)` | Срабатывает на нативное событие `@input`. Передает текущее строковое значение. |
---
# SRadioGroup > SRadio
Радио-кнопки.
В отличие от популярных библиотек компонентов для Vue3:
Сразу идет с кликабельным стандартизированным лейблом в качестве простого атрибута. Это унифицирует код и внешний вид компонентов, упрощается поддержка и взаимозаменяемость.
Сразу из коробки идет кнопочный стиль, который часто используется.
Поддерживает три формата передачи опций в группы радио-кнопок, что удобно в зависимости от кейса:
<SRadio /> — там где опции являются частью дизайна, их можно и удобно хардкодить в шаблон;
{value1: title1, value2: title2} — что удобно для быстрого получения из key-value конфигов, а также из моделей — User::pluck('name', 'id');
[[value1, title1], [value2, title2]] — что удобно для выгрузки там, где важен порядок. Это минимизирует код в контроллерах, помогая сохранять принцип «тонкого контроллера», которого мы придерживаемся.
Взаимозаменяемость формата опций с другими выбиралками из вариантов. Это позволяет легко заменять SRadioGroup на SSelect или SCheckboxGroup, не трогая бэкенд код.
## Группа радио-кнопок
```vue
ОшибкаВопросИдея
Модель будет принимать значение выбранного варианта: {{ type }}
```
## Динамический набор значений
В предыдущем примере набор вариантов хардкодился в шаблоне, что удобно, когда набор значений относится к логическому уровню интерфейса. Но когда набор вариантов идет из базы данных или конфига, очень неудобно каждый раз формировать набор элементов через v-for, и вместо этого используем атрибут `options`.
```vue
```
Где options — это объект вариантов выбора в формате {value1: title1, value2: title2} или массив в формате [[value1, title1], [value2, title2]]
## Кнопочный стиль
Чтобы заменить стиль с кружочками на группу кнопок, добавляем атрибут `buttons`:
```vue
```
## Вертикальный список радио-кнопок
Чтобы выводить группу радио-кнопок вертикальным списком, добавляем атрибут `vertical`:
```vue
```
## Недоступное значение
Добавляем `disabled`-атрибут значению, которое должно быть недоступно для переключения.
```vue
ОшибкаВопросИдея
```
## Нулевое значение (плейсхолдер)
У радио-кнопок иногда бывает «не выбранное значение», особенно в фильтрах при заданном наборе вариантов. Для этого удобно использовать синтаксис `placeholder`:
```vue
```
## Интерфейс компонента SRadioGroup
### Свойства (Props)
| Название | Тип | По умолчанию | Описание |
|----------|-----|--------------|----------|
| v-model | `any` | `undefined` | Выбранное значение. |
| options | `Record \| Array` | `{}` | Список вариантов (объект `{value: title}` или массив `[[value, title]]`). |
| buttons | `boolean` | `false` | Использовать стиль кнопок вместо кружочков. |
| vertical | `boolean` | `false` | Расположение элементов в колонку. |
| placeholder | `string` | `undefined` | Текст для «нулевого» варианта выбора (с пустым значением). |
### Слоты (Slots)
| Название | Описание |
|----------|----------|
| default | Содержимое группы (обычно компоненты `SRadio`). |
### События (Events)
| Название | Параметры | Описание |
|----------|-----------|----------|
| change | `(value: any)` | Вызывается при изменении выбранного значения. |
## Интерфейс компонента SRadio
### Свойства (Props)
| Название | Тип | По умолчанию | Описание |
|----------|-----|--------------|----------|
| value | `string \| number \| boolean` | - | **Обязательное.** Значение элемента. |
| disabled | `boolean` | `false` | Отключает возможность выбора. |
| labelClass | `string` | `undefined` | Кастомные CSS классы для лейбла. |
### Слоты (Slots)
| Название | Описание |
|----------|----------|
| default | Текст или HTML-содержимое лейбла радио-кнопки. |
---
# SSelect
Выпадающий список с вариантами выбора.
В отличие от популярных библиотек компонентов для Vue3:
Исключает опции, которые, как правило, не используются в стартапах (флоат лейблы, размеры), но из-за которых разные программисты реализовывают компонент по-разному. Без лишних опций унифицируется код и внешний вид компонентов, упрощается поддержка и взаимозаменяемость.
Поддерживает два формата передачи опций, удобных для выгрузки из контроллеров Laravel:
{value1: title1, value2: title2} — что удобно для быстрого получения из key-value конфигов, а также из моделей — User::pluck('name', 'id');
[[value1, title1], [value2, title2]] — что удобно для выгрузки там, где важен порядок. Это минимизирует код в контроллерах, помогая сохранять принцип «тонкого контроллера», которого мы придерживаемся.
Взаимозаменяемость формата опций с другими выбиралками из вариантов. Это позволяет легко заменять SSelect на SCheckboxGroup или SRadioGroup, не трогая бэкенд код.
## Классический вариант
```vue
```
Где options — это объект вариантов выбора в формате {value1: title1, value2: title2} или массив в формате [[value1, title1], [value2, title2]]
## Фильтрация при вводе
```vue
```
## Получение значений по API
Список значений можно подгружать по API — в том числе на каждый ввод. Ниже живой пример: варианты приходят с публичного тестового API [DummyJSON](https://dummyjson.com), запрос уходит в обработчике события `@filter`. Начните вводить имя (например, «jo»):
```vue
```
Обработчик `@filter` получает введённую строку; ответ API мы приводим к формату опций (`[[value, title]]` или `{value: title}`) и кладём в `:options`. В реальном проекте запрос обычно стоит дебаунсить.
## Возможность сброса значения
Иногда бывает нужно сделать возможность сбрасывать значение в невыбранное (null). Для этого используется атрибут `clearable`:
```vue
```
## Виртуальный скролл
Когда доступно очень много вариантов выбора, можно применить виртуальный скролл для более быстрой загрузки, добавив атрибут `virtual`:
```vue
```
## Интерфейс компонента
### Свойства (Props)
| Название | Тип | По умолчанию | Описание |
|----------|-----|--------------|----------|
| v-model | any | - | Текущее выбранное значение. |
| options | Record \| Array | - | Список вариантов (объект или массив пар). |
| placeholder | string | - | Текст заглушки. |
| filterable | boolean | `false` | Включает текстовый поиск. |
| clearable | boolean | `false` | Показывает кнопку сброса значения. |
| disabled | boolean | `false` | Отключает компонент. |
| inline | boolean | `false` | Убирает границы и делает селект компактным. |
| virtual | boolean | `false` | Включает виртуальный скролл. |
| virtualScrollSize | number | `10` | Количество одновременно отображаемых элементов при виртуальном скролле. |
### Слоты (Slots)
| Название | Параметры | Описание |
|----------|-----------|----------|
| value | `{ value: any }` | Кастомное отображение выбранного значения. |
| option | `{ option: { label: string, value: any } }` | Кастомное отображение элемента в выпадающем списке. |
### События (Events)
| Название | Параметры | Описание |
|----------|-----------|----------|
| change | `(value: any)` | Вызывается при изменении значения. |
| filter | `(query: string)` | Вызывается при вводе текста в режиме поиска. |
---
# SSlider
Ползунок для выбора числового значения из диапазона. Рядом с ползунком отображается текущее значение.
## Базовый пример
```vue
```
## Диапазон и шаг
Границы диапазона и шаг задаются свойствами `min`, `max` и `step`:
```vue
```
## Единица измерения
Свойство `unit` добавляет суффикс к отображаемому значению:
```vue
```
## Кастомное отображение значения
Через слот по умолчанию значение можно отформатировать произвольно. Слот получает текущее значение через параметр `value`:
```vue
{{ value.toLocaleString('ru-RU') }} ₽
```
Если значение показывать не нужно, отключите его свойством `:show-value="false"`.
## Недоступное состояние
```vue
```
## Интерфейс компонента
### Свойства (Props)
| Название | Тип | По умолчанию | Описание |
|----------|-----|--------------|----------|
| v-model | `number` | `0` | Текущее значение. |
| min | `number` | `0` | Минимальное значение. |
| max | `number` | `100` | Максимальное значение. |
| step | `number` | `1` | Шаг изменения значения. |
| unit | `string` | `''` | Суффикс к отображаемому значению (например, `%`). |
| show-value | `boolean` | `true` | Показывать ли текущее значение рядом с ползунком. |
| disabled | `boolean` | `false` | Отключает возможность изменения. |
### Слоты (Slots)
| Название | Описание |
|----------|----------|
| default | Кастомное отображение значения. Получает параметр `value` — текущее значение. |
---
# SSwitch
Включатель-выключатель.
В отличие от популярных библиотек компонентов для Vue3:
Сразу идет с кликабельным стандартизированным лейблом в качестве простого атрибута. Это унифицирует код и внешний вид компонентов, упрощается поддержка и взаимозаменяемость.
## Базовый пример
```vue
Значение: {{ checked }}
```
Модель принимает значение true/false.
## Недоступное состояние
```vue
Не работает
```
## Кастомные да/нет-значения
Для включенного/отключенного состояния можно задать кастомные значения:
```vue
Значение: {{ value }}
```
## Интерфейс компонента
### Свойства (Props)
| Название | Тип | По умолчанию | Описание |
|----------|-----|--------------|----------|
| v-model | `any` | `null` | Состояние переключателя. |
| disabled | `boolean` | `false` | Отключает возможность переключения. |
| true-value | `any` | `true` | Значение для «включенного» состояния. |
| false-value | `any` | `false` | Значение для «выключенного» состояния. |
### Слоты (Slots)
| Название | Описание |
|----------|----------|
| default | Текст лейбла (описания) рядом с переключателем. |
---
# SUpload
Загрузка файла. Всегда вставляется внутри некой формы, не используется в отрыве от неё.
В отличие от популярных библиотек компонентов для Vue3:
В других библиотеках Upload работает как поле, которое по дефолту сразу отправляет файл после выбора (что удобно, например, при импорте таблиц). На практике же гораздо чаще встречается кейс, когда файл/картинка — это атрибут некой модели, и этот файл нужно добавлять-редактировать в форме редактирования модели. SUpload в первую очередь заточен под этот, более частый кейс.
SUpload сразу работает в связке с SForm, что позволяет использовать его так же просто, как простые текстовые SInput, не задумываясь о том, как связывать данные с формой.
## Базовый пример
Если нужно вставить полем в форму. Сама отправка идёт через Inertia, поэтому базовый пример показан кодом (вживую не запускается):
```vue
Отправить
```
## Авто-отправка при выборе
Если нужна авто-отправка, то выполняем отправку формы по событию `@select`:
```vue
```
## Кастомный текст кнопки
Можно задать произвольный текст кнопки с помощью атрибута `upload-button-title`
```vue
```
## Кастомный шаблон
```vue
```
Слоты сразу пробрасывают методы и переменные, которые могут быть полезны в собственных шаблонах:
* В слоте кнопки выбора `#header`: `choose()` открывает окно выбора файла, `clear()` очищает набор выбранных файлов, `files` — список текущих выбранных файлов, `isDragging` — булево значение, равное true, когда над компонентом перемещают файл.
* В слоте предпросмотра выбранных файлов `#preview`: `files` — список текущих выбранных файлов, `remove(file)` — удаление конкретного файла из набора (передаётся элемент массива `files`).
## Ограничения выбора
Для ограничения выбора по расширению добавляем атрибут `accept`:
```vue
```
Для ограничения выбора по размеру файла добавляем атрибут `max-file-size`. Можно указывать человекочитаемо (`2M`, `512K`, `1.5GB` — единицы 1024-кратные, как в php.ini) или числом в байтах:
```vue
```
## Выбор нескольких файлов
```vue
```
## Интерфейс компонента
### Свойства (Props)
| Название | Тип | По умолчанию | Описание |
|----------|-----|--------------|----------|
| v-model | `any \| any[]` | `null` | Выбранный файл (объект File или строка) или массив файлов. |
| accept | `string` | `undefined` | Допустимые типы файлов (напр. `.jpg,.png`). |
| max-file-size | `number \| string` | `undefined` | Максимальный размер файла: в байтах (число) или человекочитаемо (`2M`, `512K`, `1.5GB`). |
| multiple | `boolean` | `false` | Позволяет выбирать несколько файлов. |
| upload-button-title | `string` | `'Выбрать файл(ы)'` | Текст на кнопке выбора (если не используется слот `header`). |
### Слоты (Slots)
| Название | Параметры | Описание |
|----------|-----------|----------|
| header | `{ choose, clear, files, isDragging }` | Кастомная область выбора (триггер). |
| preview | `{ files, remove }` | Кастомная область предпросмотра выбранных файлов. |
| default | - | Содержимое под списком файлов. |
### События (Events)
| Название | Параметры | Описание |
|----------|-----------|----------|
| select | `value` | Вызывается при выборе файлов. |
| clear | - | Вызывается при полной очистке списка. |
---
# SActionBar
Полоска действия (обычно, для выбранных элементов).
В популярных библиотеках прямого аналога нет.
## Базовый пример
```vue
Применить
```
## Интерфейс компонента
### Слоты (Slots)
| Название | Описание |
|----------|----------|
| default | Интерактивные элементы, кнопки или формы для отображения в панели действий. Контент использует flexbox, элементы располагаются в ряд. |
---
# SActionIcon
Иконка действия (чаще всего используется в таблицах).
В отличие от популярных библиотек компонентов для Vue3:
Привязка к FontAwesome, который бесплатен и оптимально решает задачи иконок для стартапов.
Упрощает запрос подтверждения перед опасными действиями (напр. удаление) с помощью одного атрибута.
## Стандартный пример
Используются стандартые иконки FontAwesome. Типовой пример с click-событием:
```vue
```
## Ссылка в иконке
Если указать href-атрибут, то по умолчанию иконка станет анкором:
```vue
```
Но при необходимости также через атрибут is можно также передать Link-компонент InertiaJs:
```vue
```
## Подтверждение действия
Для небезопасных действий выделяем иконку цветом (атрибут danger) и запрашиваем подтверждение перед выполнением (атрибут confirm):
```vue
```
Подписи и цвет кнопок диалога настраиваются через `confirm-options` (пробрасываются в `SConfirm`):
```vue
```
## Интерфейс компонента
### Свойства (Props)
| Название | Тип | По умолчанию | Описание |
|----------|-----|--------------|----------|
| icon | string \| string[] | required | Имя иконки FontAwesome (например, `'trash'` или `['far', 'calendar']`) |
| danger | boolean | false | Выделяет иконку красным цветом |
| confirm | string | undefined | Текст диалога подтверждения перед выполнением `@click` |
| confirmTitle | string | 'Необходимо подтверждение' | Заголовок диалога подтверждения |
| confirmOptions | object | undefined | Опции, пробрасываемые в `SConfirm.open` (`acceptLabel`, `cancelLabel`, `variant`, …) |
| is | string \| Component | undefined | HTML-элемент или Vue-компонент для рендеринга (например, InertiaJS `Link`) |
| href | string | undefined | URL для перехода (делает иконку ссылкой) |
| title | string | undefined | Текст подсказки при наведении |
### События (Events)
| Название | Параметры | Описание |
|----------|-----------|----------|
| click | none | Вызывается при клике на иконку. Срабатывает ПОСЛЕ подтверждения, если передан параметр `confirm`. |
---
# SAlert
Оповещение о произошедшем событии.
В отличие от популярных библиотек компонентов для Vue3:
Упрощено до одного метода, не требует добавлять элемент в шаблон.
Добавить возможность собирать серию оповещений друг под другом.
## Базовый пример
Информационное оповещение:
```vue
Информация
```
Оповещение об успешном действии:
```vue
Успех
```
Оповещение об ошибке:
```vue
Ошибка
```
## Увеличенное время до закрытия
По умолчанию оповещения закрываются через 5 секунд. Другое время закрытия можно задать параметром closeAfter:
```vue
Информация
```
## Интерфейс компонента
### Методы
- `SAlert.info(text: string, options?: AlertOptions)` — информационное оповещение
- `SAlert.success(text: string, options?: AlertOptions)` — оповещение об успехе
- `SAlert.error(text: string, options?: AlertOptions)` — оповещение об ошибке
- `SAlert.open(text: string, options?: AlertOptions)` — базовый метод (тип задаётся в `options`)
### AlertOptions
| Название | Тип | По умолчанию | Описание |
|----------|-----|--------------|----------|
| type | `'success'` \| `'info'` \| `'error'` | `'info'` | Визуальный стиль оповещения. |
| closeAfter | number | `3000` | Время в миллисекундах до автозакрытия. |
---
# SButton
Кнопка.
В отличие от популярных библиотек компонентов для Vue3:
В зависимости от контекста сам подбирает семантический элемент: анкор для ссылок или button для отправки формы.
Позволяет передать Link-элемент InertiaJS в качестве атрибута as.
## Стандартный пример
Используйте `color`, `outlined`, `transparent`, `disabled`, `small`, `loading` и `fullwidth` чтобы задать стили кнопок.
### Основной цвет
```vue
Основное действиеДополнительное действиеПрозрачная кнопкаНедоступная кнопкаМаленькая кнопка
```
### Красная кнопка
```vue
Основное действиеДополнительное действиеПрозрачная кнопкаНедоступная кнопкаМаленькая кнопка
```
### Зеленая кнопка
```vue
Основное действиеДополнительное действиеПрозрачная кнопкаНедоступная кнопкаМаленькая кнопка
```
### Жёлтая кнопка
```vue
Основное действиеДополнительное действиеПрозрачная кнопкаНедоступная кнопкаМаленькая кнопка
```
### Золотая кнопка
Акцент для «денежных» и премиум-действий (платные операции, запуск, оплата): градиент золота с тёмным текстом. Использует токены `--s-gold`, `--s-gold-dark`, `--s-gold-lightest` из палитры.
```vue
Запустить (≈ 210 ₽)Дополнительное действиеПрозрачная кнопкаНедоступная кнопкаМаленькая кнопка
```
### Кнопка на всю ширину формы
```vue
Основное действиеОсновное действиеОсновное действиеОсновное действие
```
## Действия по кнопке
### Отправка формы
Если кнопка внутри формы, то отправляет форму:
```vue
...
Создать пользователя
```
### Кастомное действие
```vue
Создать пользователя
```
### Переход по ссылке
Если добавляем href, то кнопка по умолчанию становится семантически правильным анкором:
```vue
Документация
```
### Переход по внутренней ссылке InertiaJs
Если нужно сделать кнопку внутренней InertjaJS-ссылкой, то используем атрибут "is":
```vue
Создать проект
```
## Интерфейс компонента
### Свойства (Props)
| Название | Тип | По умолчанию | Описание |
|----------|-----|--------------|----------|
| outlined | boolean | false | Стиль кнопки с контуром (без заливки) |
| transparent | boolean | false | Прозрачная кнопка без границ |
| fullwidth | boolean | false | Кнопка на всю ширину контейнера |
| small | boolean | false | Маленький размер кнопки |
| disabled | boolean | false | Отключает кнопку (некликабельна, прозрачность 0.3) |
| loading | boolean | false | Состояние загрузки (некликабельна, курсор ожидания) |
| color | string | — | Цвет кнопки: `"red"`, `"green"`, `"yellow"`, `"gold"` или кастомный |
| is | string \| Component | — | HTML-элемент или Vue-компонент для рендеринга (например, InertiaJS `Link`) |
| href | string | — | URL для перехода (делает кнопку ссылкой) |
### Слоты (Slots)
| Название | Описание |
|----------|----------|
| default | Содержимое кнопки (текст, иконка и т.д.) |
---
# SColumnSettings
Включение/выключение колонок в таблице.
## Базовый пример
```vue
Пользователь
{{ availableColumns[tableColumn] }}
{{ row.username }}
{{ row[tableColumn] }}
```
## Сброс колонок до значений по умолчанию
Если нужно сбрасывать колонки до набора по умолчанию, это можно сделать так:
```vue
Пользователь
{{ availableColumns[tableColumn] }}
{{ row.username }}
{{ row[tableColumn] }}
```
Когда набор полей всего один, по умолчанию в футере выпадающего списка выводится строка «Сбросить изменения», когда несколько — выводится название каждого набора. Это повдение можно изменить с помощью слота setpreset:
```vue
Сбросить на {{ preset.title }}
```
## Постоянные колонки
Если нужно запретить удаление определенных колонок, передайте массив с ними в атрибут permanent-columns:
```vue
Пользователь
{{ availableColumns[tableColumn] }}
{{ row.username }}
{{ row[tableColumn] }}
```
## Интерфейс компонента
### Свойства (Props)
| Название | Тип | По умолчанию | Описание |
|----------|-----|--------------|----------|
| modelValue / v-model | `string[]` | `[]` | Массив ключей активных колонок. |
| options | `Record` | `{}` | Объект (словарь), сопоставляющий ключи колонок с их отображаемыми заголовками, например `{ id: 'Идентификатор' }`. |
| columnPresets | `SColumnSettingsPreset[]` | `[]` | Массив объектов `{ title: string, columns: string[] }`. Используется для быстрого сброса колонок на заданные пресеты. |
| permanentColumns | `string[]` | `[]` | Массив ключей колонок, которые пользователь не может выключить. |
### Слоты (Slots)
| Название | Описание |
|----------|----------|
| label | Основное содержимое кнопки, открывающей выпадающий список. По умолчанию отображает иконку и текст "Настроить колонки". |
| setpreset | Слот для переопределения шаблона кнопки пресета в подвале выпадающего списка. Передает параментр `{ preset }`. |
---
# SConfirm
Диалоговое окно подтверждения действия.
В отличие от популярных библиотек компонентов для Vue3:
Упрощено до одного метода, не требует добавлять элемент в шаблон.
## Базовый пример
```vue
Удалить пользователя
```
## Интерфейс компонента
`SConfirm.open(message: string, options?: ConfirmOptions)`
### Аргументы
| Название | Тип | Описание |
|----------|-----|----------|
| message | string | Обязательный. Основной текст/HTML диалога подтверждения. |
| options | object | Необязательный объект конфигурации (см. ConfirmOptions ниже). |
### ConfirmOptions
| Название | Тип | По умолчанию | Описание |
|----------|-----|--------------|----------|
| title | string | `'Необходимо подтверждение'` | Заголовок диалогового окна. |
| acceptLabel | string | `'Да'` | Текст кнопки подтверждения. |
| cancelLabel | string | `'Нет'` | Текст кнопки отмены. |
| variant | `'primary' \| 'danger'` | `'danger'` | Цвет кнопки подтверждения: `danger` (красная) для разрушающих действий, `primary` — для неразрушающих (move и т.п.). |
| onAccept | function | `() => {}` | Коллбэк при нажатии кнопки подтверждения. |
| onCancel | function | `() => {}` | Коллбэк при нажатии кнопки отмены или фонового оверлея. |
---
# SCopyText
Копируемый текст.
В популярных библиотеках элементов для Vue3 прямого аналога нет.
## Базовый пример
```vue
ABCD-EFGH-1234-5678
```
## Внутристрочный пример
```vue
Секретный код для копирования в обычном тексте.
```
## Копируем не то, что выводим
```vue
Секретный код: 777
```
## Интерфейс компонента
### Свойства (Props)
| Название | Тип | По умолчанию | Описание |
|----------|-----|--------------|----------|
| layout | `'input'` \| `'inline'` | `'input'` | Вид компонента. `'input'` — блок с рамкой, `'inline'` — текст с пунктирным подчёркиванием. |
| copytext | string | undefined | Строка, которая будет скопирована в буфер. Если не указана, копируется текст из слота. |
| size | `'small'` \| `'normal'` \| `'large'` | `'normal'` | Размер компонента. |
### Слоты (Slots)
| Название | Описание |
|----------|----------|
| default | Текстовое содержимое, отображаемое пользователю. |
---
# SDashboard > SDashboardItem
Дешборд блоков (как правило, удобно использовать для отчетов).
В попурярных библиотеках компонентов для Vue3 прямого аналога нет.
## Базовый пример
```vue
Информация о продажах.
Информация о стоимости услуг.
```
## Кастомный заголовок
Если текста не достаточно, то для заголовка можно использовать слот:
```vue
Продажи Только с подписанными актами
Информация о продажах.
```
## Доп.элемент справа от заголовка
Справа от заголовка часто бывает сподручно разместить дополнительную ссылку или что-то ещё. Сделать это можно в слоте #extra:
```vue
Как работают тарифы?
Описание работы тарифов
```
## Максимальная высота контента
Иногда динамически генерируемый контент внутри SDashboardItem может превращаться в длинную простыню. Чтобы не занимать большое пространство подобным блоком, такой контент можно ограничить по высоте, и в случае превышения в блоке появится свой внутренний горизонтальный скролл.
```vue
...
```
## Цвета
По умолчанию блоки идут в самом светлом цвете акцента, но при необходимости можно использовать кастомные выделения цветом:
```vue
```
## Интерфейс компонента SDashboard
### Свойства (Props)
_Нет свойств. Это просто контейнер для обертки и автоматического позиционирования (flex/grid)._
## Интерфейс компонента SDashboardItem
### Свойства (Props)
| Название | Тип | По умолчанию | Описание |
|----------|-----|--------------|----------|
| title | string | undefined | Текстовый заголовок блока дашборда. |
| maxContentHeight | string \| number | undefined | Фиксированная максимальная высота контента (например, `300` или `'300px'`). При переполнении появится скролл. |
| gray | boolean | `false` | Применяет серый цвет фона. |
| green | boolean | `false` | Применяет светло-зеленый цвет фона. |
| red | boolean | `false` | Применяет светло-красный цвет фона. |
### Слоты (Slots)
| Название | Описание |
|----------|----------|
| default | Основное содержимое блока. |
| title | Заменяет строковый заголовок (`title`) на кастомный HTML/компоненты. |
| extra | Контейнер с правой стороны заголовка, полезен для ссылок или кнопок действий. |
---
# SDialog
Диалоговое окно.
## Базовый пример
```vue
ВойтиОткрыть окно
```
Окно можно перетаскивать по экрану, зажав его шапку (заголовок с названием и крестиком).
## Фиксированная ширина
```vue
ВойтиОткрыть окно
```
## Не-модальное окно
По умолчанию окно модальное (нельзя взаимодействовать с другими объектами при открытом окне). Но если нужно отключить модальность, это можно сделать вот так:
```vue
ВойтиОткрыть окно
```
Немодальные окна можно открывать несколько одновременно и перекрывать между собой — клик по любому месту окна поднимает его над остальными. Модальное окно всегда отображается поверх немодальных.
## Фиксированная позиция окна
По умолчанию окно центрируется. Пропсом `position` можно закрепить его в нужном месте вьюпорта — задаём CSS-значения `top` / `left` / `right` / `bottom`. Удобно для немодальных окон, пристыкованных к углу. Перетаскивать окно за шапку всё равно можно.
```vue
Окно закреплено в правом верхнем углу.
Его по-прежнему можно перетащить за шапку.
Открыть окно
```
## Не закрывать по клику на оверлей
По умолчанию при клике на оверлей окно закрывается, если надо перехватывать-останавливать событие, то:
```vue
ВойтиОткрыть окно
```
## Кастомная шапка, футер и фиксированный футер
Слот `#header` заменяет содержимое заголовка (крестик и перетаскивание за шапку сохраняются), слот `#footer` добавляет футер — например, кнопки действий.
По умолчанию футер прокручивается вместе с содержимым. Пропс `fixed-footer` закрепляет шапку и футер, оставляя прокрутку только в теле — удобно для длинных окон, чтобы кнопки действий всегда были на виду.
```vue
Условия использования
{{ n }}. Длинный текст соглашения, который не помещается в окно и прокручивается в теле, пока шапка и футер остаются на месте.
ОтменаПринятьОткрыть окно
```
## Интерфейс компонента
### Свойства (Props)
| Название | Тип | По умолчанию | Описание |
|----------|-----|--------------|----------|
| modelValue (v-model) | boolean | false | Управляет видимостью диалога. |
| title | string | undefined | Текст заголовка в шапке окна. |
| width | string | undefined | Кастомная ширина окна (например, `'500px'`, `'80vw'`). |
| notModal | boolean | false | Если `true`, убирает фоновый оверлей (не-модальное окно). |
| fixedFooter | boolean | false | Закрепляет футер: шапка и футер остаются на месте, прокручивается только тело. Без него футер прокручивается вместе с содержимым. |
| position | `{ top?, left?, right?, bottom? }` | undefined | Закрепляет окно в заданной позиции вьюпорта (CSS-значения) вместо центрирования. Окно остаётся перетаскиваемым. |
### События (Events)
| Название | Параметры | Описание |
|----------|-----------|----------|
| update:modelValue | boolean | Срабатывает при изменении v-model. |
| overlay-click | — | Срабатывает при клике на фоновый оверлей. Окно закрывается, если не предотвращено (`.stop.prevent`). |
| hide | — | Срабатывает при закрытии окна (крестиком или кликом на оверлей). |
### Слоты (Slots)
| Название | Описание |
|----------|----------|
| default | Основное содержимое диалогового окна (тело). |
| header | Кастомное содержимое заголовка (вместо `title`). Крестик закрытия и перетаскивание за шапку сохраняются. |
| footer | Футер окна, например кнопки действий. Рендерится, только если передан. |
---
# SImagePreview
Картинка, которую можно посмотреть более детально в диалоговом окне.
## Базовый пример
Выводим картинку, которая увеличивается при клике.
```vue
```
## Кастомное превью
Если первоначально до клика показывается другое изображение (напр.меньшего размера), то используем атрибут preview:
```vue
```
Если нужно вставить кастомный контент, используем слот "preview":
```vue
```
## Кастомная иконка увеличения
В icon-атрибуте указываем название иконки:
```vue
```
Если нужно вставить кастомный контент, используем слот "icon":
```vue
🔍
```
## Интерфейс компонента
### Свойства (Props)
| Название | Тип | По умолчанию | Описание |
|----------|-----|--------------|----------|
| src | string | undefined | URL полноразмерного изображения, показываемого в модальном окне. |
| preview | string | undefined | URL миниатюры. Если не указан, используется `src`. |
| icon | string \| string[] | `'magnifying-glass'` | Имя иконки FontAwesome для оверлея при наведении. |
### Слоты (Slots)
| Название | Описание |
|----------|----------|
| preview | Полностью заменяет стандартный элемент `` миниатюры. |
| icon | Заменяет иконку увеличения, появляющуюся при наведении. |
---
# SNote
Текстовая заметка.
В отличие от популярных библиотек компонентов для Vue3:
Привязка к FontAwesome, который бесплатен и оптимально решает задачи иконок для стартапов.
## Базовый пример
```vue
Стандартный стиль (основной цвет)В сером цветеПривлечение вниманияУспешное действиеОписание ошибки
```
## С иконкой и заголовком
```vue
Добавьте как можно больше запросов, заходы по которым из поиска приносят вам наибольший доход.
Сервис оценит конкуренцию, шанс выхода в топ и бюджет по каждому ключевику.
```
В качестве иконок используются названия иконок font-awesome.
## Интерфейс компонента
### Свойства (Props)
| Название | Тип | По умолчанию | Описание |
|----------|-----|--------------|----------|
| icon | string \| string[] | undefined | Имя иконки FontAwesome для отображения рядом с заголовком |
| title | string | undefined | Текст заголовка, отображаемый сверху заметки |
| gray | boolean | false | Стилизует заметку с серым (нейтральным) фоном |
| attention | boolean | false | Стилизует заметку с желтым фоном (для предупреждений/внимания) |
| success | boolean | false | Стилизует заметку с зеленым фоном (для сообщений об успехе) |
| error | boolean | false | Стилизует заметку с красным фоном и границей (для ошибок) |
### Слоты (Slots)
| Название | Описание |
|----------|----------|
| default | Основное содержимое заметки. Поддерживает текст или HTML (абзацы, списки и т.д.) |
---
# SProgressBar
Полоска прогресса.
В отличие от популярных библиотек компонентов для Vue3:
Есть лейбл-пояснение, формирующий ожидание пользователей, упрощенный до одного атрибута.
## Базовый пример
```vue
Обновляем проект...
```
## Интерфейс компонента
### Свойства (Props)
| Название | Тип | По умолчанию | Описание |
|----------|-----|--------------|----------|
| percentage | number | undefined | Обязательный. Текущее значение прогресса от 0 до 100. |
### Слоты (Slots)
| Название | Описание |
|----------|----------|
| default | Текстовая метка, отображаемая рядом с полосой прогресса (например, «Обновляем проект...»). |
---
# SStat
Строка статистики, выровненная по заголовкам.
В популярных библиотеках компонентов для Vue3 прямого аналога нет.
## Базовый пример
```vue
112777 000 ₽
```
## Кастомный заголовок
```vue
Сумма платежей За выбранный период
777 000 ₽
```
## Модификаторы
С помощью логических (boolean) свойств можно изменить внешний вид строки:
```vue
777 000 ₽Очень длинное описание, которое может не поместиться...10
```
## Интерфейс компонента
### Свойства (Props)
| Название | Тип | По умолчанию | Описание |
|----------|-----|--------------|----------|
| title | string | undefined | Подпись для статистики. |
| value | string \| number | undefined | Альтернатива базовому слоту: передает значение статистики через атрибут. |
| nowrap | boolean | `false` | Запрещает перенос текста и использует многоточие для длинных значений. |
| large | boolean | `false` | Увеличивает размер шрифта и высоту строки для значения. |
| wide | boolean | `false` | Использует `justify-content: space-between`, чтобы прижать значение к правому краю. |
### Слоты (Slots)
| Название | Описание |
|----------|----------|
| default | Основное содержимое для значения статистики. Имеет приоритет над атрибутом `value`. |
| title | Для кастомного заголовка (например, с иконками или тултипами). Имеет приоритет над атрибутом `title`. |
---
# SStatus
Текстовый статус (как правило с иконкой).
В отличие от популярных библиотек компонентов для Vue3:
Привязка к FontAwesome, который бесплатен и оптимально решает задачи иконок для стартапов.
Привязка к стандартым цветам проекта, упрощает семантику до минимальных настроек и унифицирует цвета.
## Базовый пример
```vue
РаботаетОстановленНе запущен
```
## Различные цвета
Помимо иконок можно кастомизировать цвет статуса по стандартной палитре цветов:
```vue
texttext-lightprimaryprimary-darkprimary-darkestredred-darkyellowyellow-darkgreengreen-dark
```
## Интерфейс компонента
### Свойства (Props)
| Название | Тип | По умолчанию | Описание |
|----------|-----|--------------|----------|
| color | string | undefined | Цвет текста и иконки из стандартной палитре: `text`, `text-light`, `primary`, `primary-dark`, `primary-darkest`, `red`, `red-dark`, `yellow`, `yellow-dark`, `green`, `green-dark` и др. |
| icon | string \| string[] | undefined | Имя иконки FontAwesome (например, `'check'`, `'triangle-exclamation'`). |
### Слоты (Slots)
| Название | Описание |
|----------|----------|
| default | Текстовое содержимое, отображаемое рядом с иконкой. |
---
# SStepper
Индикатор шагов многошагового сценария (мастер, воронка): пройденные шаги отмечаются галочкой и позволяют вернуться назад кликом, будущие шаги открываются самим сценарием.
В отличие от популярных библиотек компонентов для Vue3:
Формат шагов взаимозаменяем с опциями SSelect и SRadioGroup — те же map/массивы, ничего не нужно переформатировать.
Навигация ограничена пройденными шагами из коробки: движение вперёд контролирует сценарий, а не пользователь.
## Базовый пример
```vue
```
Шаги до текущего считаются пройденными: получают галочку и становятся кликабельными — клик возвращает модель на выбранный шаг. Шаги после текущего неактивны.
## Массив строк
Если значения шагов не нужны, достаточно массива строк — значением модели будет сама строка:
```vue
```
## Интерфейс компонента
### Свойства (Props)
| Название | Тип | По умолчанию | Описание |
|----------|-----|--------------|----------|
| v-model | `any` | `undefined` | Значение текущего шага. Если значение не найдено среди шагов, активным считается первый шаг. |
| options | `Record \| Array` | `{}` | Шаги (объект `{value: title}`, массив `[[value, title]]`, массив объектов `{value, label}` или массив строк). |
### События (Emits)
| Название | Payload | Описание |
|----------|---------|----------|
| update:modelValue | `any` | Клик по пройденному шагу — возврат на него. |
---
# STag
Тег (может также использоваться как отображение статуса).
В отличие от популярных библиотек компонентов для Vue3:
Привязка к стандартым цветам проекта, упрощает семантику до минимальных настроек и унифицирует цвета.
## Базовый пример
```vue
Новый
```
## Различные цвета
Атрибутом `color` можно передать значение цвета из палитры цветов:
```vue
grayprimaryprimary-darkprimary-darkestprimary-lightprimary-lightestredred-darkred-lightred-lightestyellowyellow-darkyellow-lightyellow-lightestgreengreen-darkgreen-lightgreen-lightest
```
## Интерфейс компонента
### Свойства (Props)
| Название | Тип | По умолчанию | Описание |
|----------|-----|--------------|----------|
| color | string | `'gray'` | Цвет фона и текста. Поддерживает значения из палитры: `gray`, `primary`, `primary-dark`, `primary-darkest`, `primary-light`, `primary-lightest`, `red`, `red-dark`, `red-light`, `red-lightest`, `yellow`, `yellow-dark`, `yellow-light`, `yellow-lightest`, `green`, `green-dark`, `green-light`, `green-lightest`. |
### Слоты (Slots)
| Название | Описание |
|----------|----------|
| default | Текстовое содержимое или HTML внутри тега. |
---
# STimeline
Вертикальная черта с точками-пунктами.
В отличие от популярных библиотек компонентов для Vue3:
Упрощено до минимально необходимого функционала, что обеспечивает одинаковое написание кода и взаимозаменяемость компонентов дальше.
## Базовый пример
```vue
{{ item.last_visit_diff }} назад {{ item.username }} остановил переходы
```
## Интерфейс компонента
### Свойства (Props)
| Название | Тип | По умолчанию | Описание |
|----------|-----|--------------|----------|
| items | `Array` | `undefined` | Обязательный массив объектов данных для итерации по таймлайну. |
### Слоты (Slots)
| Название | Привязки | Описание |
|----------|----------|----------|
| item | `{ item: Object, index: number }` | Слот для отображения содержимого рядом с маркером таймлайна для каждого элемента. |
---
# SToggleGroup > SToggle
Открывающийся-закрывающийся блок.
## Базовый пример
```vue
Результат до оплаты. После регистрации и стартовых действий ты получаешь стартовый депозит, на котором сможешь сделать быстрый тест и получить первые результаты.
```
## Первоначально открытое состояние
```vue
Результат до оплаты. После регистрации и стартовых действий ты получаешь стартовый депозит, на котором сможешь сделать быстрый тест и получить первые результаты.
```
## Кастомный заголовок
Когда просто текста не достаточно, используем слот:
```vue
Обратите внимание 1
При пополнении счета банковской картой вы получаете бонус в размере 10 000 рублей.
```
## Несколько блоков (аккордеон)
```vue
5 минут в день. Базовая настройка и запуск обычно занимает от 5 до 30 минут.Результат до оплаты. После регистрации и стартовых действий ты получаешь стартовый депозит, на котором сможешь сделать быстрый тест и получить первые результаты. И это лучше любых гарантий!
```
По умолчанию будет давать открыть не более одного тоггла (остальные будет закрывать). Если нужно открыть несколько, то добавляем multiple:
```vue
5 минут в день. Базовая настройка и запуск обычно занимает от 5 до 30 минут.Результат до оплаты. После регистрации и стартовых действий ты получаешь стартовый депозит, на котором сможешь сделать быстрый тест и получить первые результаты. И это лучше любых гарантий!
```
## Цвета
Атрибут `color` позволяет менять фоновый стиль заголовка `SToggle`.
```vue
Контент...Контент...Контент...Контент...
```
## Интерфейс компонента SToggleGroup
### Свойства (Props)
| Название | Тип | По умолчанию | Описание |
|----------|-----|--------------|----------|
| multiple | boolean | false | Если `true`, позволяет одновременно открывать несколько блоков внутри группы. |
## Интерфейс компонента SToggle
### Свойства (Props)
| Название | Тип | По умолчанию | Описание |
|----------|-----|--------------|----------|
| title | string | undefined | Текст заголовка. |
| opened | boolean | false | Если `true`, блок открыт по умолчанию. |
| color | `'bg'` \| `'primary'` \| `'red'` \| `'green'` | `'bg'` | Цветовая схема заголовка. |
### Слоты (Slots)
| Название | Описание |
|----------|----------|
| title | Кастомное содержимое для заголовка (переопределяет проп `title`). |
| default | Основное содержимое, которое раскрывается при клике. |
---
# STooltip
Иконка вопроса со всплывающей подсказкой.
В отличие от популярных библиотек компонентов для Vue3:
Текст подсказки в слоте, так что там можно размещать HTML-контент и ссылки на расширенную информацию.
Событийная логика сделана так, что мышку можно перевести с иконки на текст подсказки и кликнуть по ссылке, которая в ней.
## Базовый пример
```vue
Показы Кол-во показов поискового сниппета. Данные из вебмастера за последний день, когда они есть для запроса
```
## Фиксированное положение
По умолчанию положение подсказки выбирается исходя из того, где эта подсказка уместится на экране. Но если нужно указать положение явно, можно использовать атрибут `at`:
```vue
Сверху Подсказка сверху
Справа Подсказка справа
Снизу Подсказка снизу
Слева Подсказка слева
```
## Кастомная иконка
Если нужна другая иконка, то её можно заменить атрибутом icon:
```vue
Подсказка с другой иконкой Используем иконку circle-info
```
Если нужна совсем нестандартная иконка/область наведения, то можно использовать слот icon:
```vue
❓
Используем в качестве иконки эмодзи
```
## Интерфейс компонента
### Свойства (Props)
| Название | Тип | По умолчанию | Описание |
|----------|-----|--------------|----------|
| at | `'top'` \| `'bottom'` \| `'right'` \| `'left'` \| `null` | `null` | Принудительно задает положение подсказки. По умолчанию рассчитывается автоматически. |
| icon | string \| string[] | `'circle-question'` | Имя иконки FontAwesome для триггера подсказки. |
### Слоты (Slots)
| Название | Описание |
|----------|----------|
| default | Содержимое внутри пузыря подсказки. Поддерживает HTML. |
| icon | Переопределяет стандартную иконку FontAwesome. Позволяет разместить эмодзи, текст или кастомные элементы. |
---
# SCanvas + SFooter
Общий шаблон страницы.
## Базовый пример
```vue
Шапка
Второй блок шапки
Боковой блок страницы
Основной контент страницы
```
## Утилиты SFooter
У компонента `SFooter` нет собственных свойств, но его CSS включает класс `.s-footer-h`, специально созданный для центрирования контента с максимальной шириной (`1200px`):
```vue
```
## Интерфейс компонента SCanvas
### Слоты (Slots)
| Название | Описание |
|----------|----------|
| header | Самая верхняя навигационная панель. Элементы с классом `.right` будут выровнены по правому краю на десктопе. |
| subheader | Вторичная шапка под основной. Часто используется для хлебных крошек или подзаголовка. |
| sidebar | Левая боковая панель навигации. На мобильных устройствах по умолчанию скрыта и доступна через бургер-меню. |
| content | Основная область для контента страницы. Занимает оставшееся пространство рядом с сайдбаром. |
| default | Рендерится между подшапкой и блоками `sidebar`/`content`. Часто используется для плашек (alerts) на всю ширину или для размещения `SFooter` в низу интерфейса. |
## Интерфейс компонента SFooter
### Слоты (Slots)
| Название | Описание |
|----------|----------|
| default | Содержимое подвала (футера). |
---
# SMenu
Горизонтальное меню с выпадающими подменю. Подходит для шапки (`header`) и подшапки (`subheader`) — объединяет в одном компоненте плоскую навигацию и дропдауны.
Меню рассчитано на тёмную полосу (как `subheader`), поэтому в примерах ниже оно обёрнуто в контейнер с фоном `--s-bg-subheader`.
## Базовый пример
Пункт с массивом `children` раскрывает выпадающее подменю при наведении. Активный пункт отмечается «уголком».
```vue
```
## Иконки, счётчики и аватары
У пунктов могут быть иконки (`icon`), числовые бейджи (`counter`) и круглые аватары (`avatar`). Иконки берутся из FontAwesome — см. [«Иконки»](/pages/welcome/basics/icons).
```vue
```
Внешние ссылки (абсолютный URL на другой домен) открываются в новой вкладке; локальные ссылки используют SPA-навигацию, если при подключении плагина передан `link`-компонент (напр. Inertia `Link`) — см. [«Установка»](/pages/welcome/basics/installing).
## Интерфейс компонента
### Свойства (Props)
| Название | Тип | По умолчанию | Описание |
|----------|-----|--------------|----------|
| items | `SMenuItem[]` | `[]` | Пункты меню. |
### Объект пункта (SMenuItem)
| Поле | Тип | Описание |
|------|-----|----------|
| label | string | Текст пункта. |
| url | string | Ссылка. Внешние URL открываются в новой вкладке. |
| icon | string \| string[] | Имя иконки FontAwesome (если не задан `avatar`). |
| avatar | string | URL картинки-аватара (круглая, вместо иконки). |
| counter | string \| number | Бейдж со счётчиком (напр. число непрочитанного). |
| active | boolean | Подсветить как активный (жирный + «уголок» снизу). |
| method | string | HTTP-метод для ссылки (напр. `'post'` для пункта «Выйти»). |
| class | string | Дополнительный класс на пункт. |
| children | `SMenuItem[]` | Вложенные пункты — раскрываются выпадающим подменю при наведении. |
### Слоты (Slots)
| Название | Описание |
|----------|----------|
| default | Произвольный контент в конце меню (после всех пунктов). |
---
# SVerticalMenu
Боковое меню.
В отличие от популярных библиотек компонентов для Vue3:
Может сохранять набор раскрытых элементов в localStorage одним простым атрибутом.
## Базовый пример
```vue
```
Где menuLinks — это массив в формате `[{label, url, active, ?type, ?className, ?children}, ...]`
## Раскрытые элементы
Чтобы нужные элементы были раскрыты сразу, мы передаем массив их ID в атрибуте expanded-keys:
```vue
```
## Запоминание раскрытых элементов
Во всякого рода документациях
Когда мы добавляем атрибут store-expanded-keys-to, раскрытые элементы сохраняются в localStorage. Теперь, если обновить страницу, раскрытые элементы сохранятся.
```vue
```
## Интерфейс компонента SVerticalMenu
### Свойства (Props)
| Название | Тип | По умолчанию | Описание |
|----------|-----|--------------|----------|
| links | `SVerticalMenuLink[]` | `[]` | Массив навигационных ссылок с поддержкой вложенности. |
| expandedKeys | `(string \| number)[]` | `[]` | Массив ID элементов, которые должны быть раскрыты по умолчанию. |
| storeExpandedKeysTo | string | `undefined` | Ключ в localStorage для сохранения состояния раскрытых элементов. |
### Слоты (Slots)
| Название | Описание |
|----------|----------|
| default | По умолчанию слоты отсутствуют, меню генерируется автоматически по пропсу `links`. |
## Интерфейс объекта SVerticalMenuLink
| Свойство | Тип | Описание |
|----------|-----|----------|
| id | string \| number | **Обязательное.** Уникальный идентификатор пункта меню (нужен для логики открытия/закрытия). |
| label | string | **Обязательное.** Текст пункта меню. |
| url | string | URL для перехода. Если указан — рендерится ссылкой (зарегистрированный `Link`, напр. Inertia; иначе обычный ``). Если нет — используется как папка для дочерних элементов. |
| active | boolean | Если `true`, пункт визуально помечается как активный. |
| type | string | Может быть `'section'` для заголовка раздела (жирнее и с отступами). |
| isPublished | boolean | Если `false`, пункт затеняется и появляется иконка перечеркнутого глаза (чтобы показать, что раздел скрыт на сайте). |
| className | string | Дополнительные CSS классы пункта. |
| children | `SVerticalMenuLink[]` | Вложенный массив дочерних пунктов. |