Подписи и состояния
Называйте действие прямо. Показывайте загрузку, ошибку и результат.
01 / Основы
Выделяйте одно основное действие. Обозначайте состояние текстом или иконкой вместе с цветом. Объединяйте связанные элементы отступами и общим фоном.
Называйте действие прямо. Показывайте загрузку, ошибку и результат.
Используйте общие размеры и отступы. Одинаковые элементы должны работать одинаково.
Клавиатура, видимый фокус, подписи полей и достаточный контраст.
Светлая тема со шрифтом Gavia Sans.
Тёмная тема с бирюзовым акцентом и шрифтом Gavia Sans.
Светлая тема с синим акцентом.
Тёмная тема с цветами для статусов.
Светлая тема с тёплым фоном под бумагу.
Карточки и разделы / elevation-surface
Меню и панели / elevation-floating
02 / Типографика
Размер задаётся ролью. Семантические h1–h6 сохраняют структуру документа; класс определяет внешний вид. Newspaper использует свои шрифты через те же токены.
display40px / 48px · 700
Display
Главный заголовок вступления; один на экран.
title28px / 36px · 700
Заголовок страницы
Название страницы и крупного диалога.
heading20px / 28px · 650
Заголовок раздела
Раздел страницы и самостоятельный блок.
subheading16px / 24px · 600
Заголовок блока
Карточка, группа полей, небольшой диалог.
body14px / 20px · 400
Основной текст
Описания, инструкции, текст формы.
small12px / 18px · 400
Компактный текст
Подписи и вспомогательный текст.
label13px / 20px · 500
Метка
Короткая подпись действия или поля.
code12px / 18px · 400
Код и данные
Токены, идентификаторы и технические значения.
Текст основного сценария — body, пояснения — small + text-muted. Ограничивайте длинную строку примерно 60–75 символами. --wl-text-3 оставлен для декоративных деталей.
03 / Сетка и отступы
Малая группа — 8 px, поля формы — 16 px, карточка — 24 px, разделы — 48–64 px. Компактная плотность подходит для экранов с большим количеством данных.
none0px2xs2pxxs4pxsm8pxmd12pxlg16pxxl24px2xl32px3xl48px4xl64pxКарточки автоматически переходят в одну колонку. Контейнер: 1240px.
<section class="wl-container">
<div class="wl-stack" data-space="xl">
<h1 class="wl-text-title">Заголовок страницы</h1>
<div class="wl-grid" data-space="lg">
<article class="wl-surface">Содержимое</article>
</div>
</div>
</section>CSS подключается явно: styles/primitives.css. На узком экране сохраняйте логичный порядок чтения, переносите действия и используйте горизонтальную прокрутку только внутри таблиц.
04 / Токены
Foundation → semantic → component. Каталог, CSS и типы генерируются из tokens/source.json. Значения ниже соответствуют теме gavia.
.page {
color: var(--wl-text);
background: var(--wl-bg);
gap: var(--wl-space-lg);
}
/* Настройка конкретного компонента */
.page-actions { --wl-btn-height: var(--wl-control-height-lg); }Найдено токенов: 171 / 447
| Токен / роль | Ссылка | Значение |
|---|---|---|
--wl-type-text-renderingРежим рендеринга текста выбранной темы. semantic | var(--wl-font-text-rendering) | geometricPrecision |
--wl-bgОсновная поверхность страницы и контента. semantic | var(--wl-palette-bg) | #faf9f6 |
--wl-bg-raisedСветлая поверхность карточек и локальных панелей над фоном страницы. semantic | var(--wl-palette-bg-raised) | #fefdfb |
--wl-bg-softСгруппированные блоки и вторичные поверхности. semantic | var(--wl-palette-bg-soft) | #eef2f3 |
--wl-bg-hoverПоверхность интерактивного элемента при наведении. semantic | var(--wl-palette-bg-hover) | #e5ecef |
--wl-borderТонкие разделители поверхностей. semantic | var(--wl-palette-border) | #d5dfe3 |
--wl-border-2Усиленная граница группы. semantic | var(--wl-palette-border-2) | #b8c7ce |
--wl-textОсновной читаемый текст. semantic | var(--wl-palette-text) | #0f1a23 |
--wl-text-accentАкцентный текст ссылок, мягких действий и выбранных пунктов на стандартных и мягких поверхностях. semantic | var(--wl-palette-text-accent) | #326179 |
--wl-text-accent-hoverАкцентный текст при наведении на ссылки и мягкие действия. semantic | var(--wl-palette-accent-hover) | #326179 |
--wl-text-2Вторичный читаемый текст и подписи. semantic | var(--wl-palette-text-2) | #5b6470 |
--wl-text-3Приглушённые декоративные метаданные; не для обязательных инструкций. semantic | var(--wl-palette-text-3) | #75818c |
--wl-accentАкцент для выбора, ссылок и основных действий. semantic | var(--wl-palette-accent) | #3c7490 |
--wl-accent-hoverАкцент при наведении. semantic | var(--wl-palette-accent-hover) | #326179 |
--wl-accent-softЦвет роли accent-soft. semantic | var(--wl-palette-accent-soft) | #dfe8eb |
--wl-accent-borderЦвет роли accent-border. semantic | var(--wl-palette-accent-border) | #b8cbd3 |
--wl-accent-soft-hoverЦвет роли accent-soft-hover. semantic | var(--wl-palette-accent-soft-hover) | #d3dfe4 |
--wl-accent-border-hoverЦвет роли accent-border-hover. semantic | var(--wl-palette-accent-border-hover) | #9eb7c2 |
--wl-on-accentИсторический цвет на акцентной поверхности. semantic | var(--wl-palette-on-accent) | #ffffff |
--wl-successСигнал успешного результата. semantic | var(--wl-palette-success) | #2e9e68 |
--wl-success-softЦвет роли success-soft. semantic | var(--wl-palette-success-soft) | #eaf6f0 |
--wl-success-borderЦвет роли success-border. semantic | var(--wl-palette-success-border) | #cdeadb |
--wl-warnСигнал предупреждения. semantic | var(--wl-palette-warn) | #bf8615 |
--wl-warn-softЦвет роли warn-soft. semantic | var(--wl-palette-warn-soft) | #fbf4e2 |
--wl-warn-borderЦвет роли warn-border. semantic | var(--wl-palette-warn-border) | #f0dfae |
--wl-dangerСигнал опасного действия или ошибки. semantic | var(--wl-palette-danger) | #ab4448 |
--wl-danger-hoverЦвет роли danger-hover. semantic | var(--wl-palette-danger-hover) | #963c3f |
--wl-danger-softЦвет роли danger-soft. semantic | var(--wl-palette-danger-soft) | #f7eeed |
--wl-danger-soft-hoverЦвет роли danger-soft-hover. semantic | var(--wl-palette-danger-soft-hover) | #f3e5e4 |
--wl-danger-borderЦвет роли danger-border. semantic | var(--wl-palette-danger-border) | #e5c6c5 |
--wl-info-textЦвет роли info-text. semantic | var(--wl-palette-info-text) | #1e3f8f |
--wl-ok-textЦвет роли ok-text. semantic | var(--wl-palette-ok-text) | #1c6b47 |
--wl-warn-textЦвет роли warn-text. semantic | var(--wl-palette-warn-text) | #7d5a0e |
--wl-err-textЦвет роли err-text. semantic | var(--wl-palette-err-text) | #ab4448 |
--wl-mask-bgЗатемнение фона модального окна. semantic | var(--wl-palette-mask-bg) | rgba(15, 26, 35, 0.28) |
--wl-avatar-bgЦвет роли avatar-bg. semantic | var(--wl-palette-avatar-bg) | #253540 |
--wl-tooltip-bgПоверхность краткой подсказки. semantic | var(--wl-palette-tooltip-bg) | #0f1a23 |
--wl-tooltip-textТекст краткой подсказки. semantic | var(--wl-palette-tooltip-text) | #ffffff |
--wl-control-height-mdРоль btn-height. semantic | var(--wl-dimension-btn-height) | 40px |
--wl-control-height-smРоль btn-height-sm. semantic | var(--wl-dimension-btn-height-sm) | 32px |
--wl-control-height-lgРоль btn-height-lg. semantic | var(--wl-dimension-btn-height-lg) | 48px |
--wl-control-height-xsРоль btn-height-xs. semantic | var(--wl-dimension-btn-height-xs) | 26px |
--wl-corner-controlРоль btn-radius. semantic | var(--wl-radius) | 8px |
--wl-corner-control-smРоль btn-radius-sm. semantic | var(--wl-radius-sm) | 6px |
--wl-control-padding-inlineРоль btn-pad-x. semantic | var(--wl-dimension-btn-pad-x) | 14px |
--wl-type-control-sizeРоль btn-font-size. semantic | var(--wl-dimension-btn-font-size) | 13.5px |
--wl-corner-inputРоль input-radius. semantic | var(--wl-dimension-input-radius) | 6px |
--wl-focus-shadowРоль focus-ring. semantic | 0 0 0 3px var(--wl-accent-soft) | 0 0 0 3px #dfe8eb |
--wl-focus-invalid-shadowРоль focus-ring-danger. semantic | 0 0 0 3px var(--wl-danger-soft) | 0 0 0 3px #f7eeed |
--wl-metric-check-sizeРоль check-size. semantic | var(--wl-dimension-check-size) | 18px |
--wl-metric-switch-widthРоль switch-width. semantic | var(--wl-dimension-switch-width) | 36px |
--wl-metric-switch-heightРоль switch-height. semantic | var(--wl-dimension-switch-height) | 22px |
--wl-metric-tag-heightРоль tag-height. semantic | var(--wl-dimension-tag-height) | 20px |
--wl-metric-chip-heightРоль chip-height. semantic | var(--wl-dimension-chip-height) | 30px |
--wl-metric-badge-heightРоль badge-height. semantic | var(--wl-dimension-badge-height) | 18px |
--wl-corner-surfaceРоль card-radius. semantic | var(--wl-radius) | 8px |
--wl-corner-overlayРоль dialog-radius. semantic | var(--wl-radius-xl) | 12px |
--wl-layout-drawer-widthРоль drawer-width. semantic | var(--wl-dimension-drawer-width) | 420px |
--wl-layer-maskРоль mask-z. semantic | var(--wl-dimension-mask-z) | 70 |
--wl-layer-popoverРоль overlay-z. semantic | var(--wl-dimension-overlay-z) | 80 |
--wl-metric-iconbtn-size-smРоль iconbtn-size-sm. semantic | var(--wl-dimension-iconbtn-size-sm) | 30px |
--wl-metric-sidebar-widthРоль sidebar-width. semantic | var(--wl-dimension-sidebar-width) | 68px |
--wl-metric-sidebar-expanded-widthРоль sidebar-expanded-width. semantic | var(--wl-dimension-sidebar-expanded-width) | 228px |
--wl-layer-navigationРоль sidebar-z. semantic | var(--wl-dimension-sidebar-z) | 40 |
--wl-layer-navigation-modalРоль sidebar-mobile-z. semantic | var(--wl-dimension-sidebar-mobile-z) | 90 |
--wl-metric-segmented-shadowРоль segmented-shadow. semantic | 0 1px 2px var(--wl-ink-a08) | 0 1px 2px rgba(20, 22, 28, 0.08) |
--wl-layout-menu-widthРоль menu-width. semantic | var(--wl-dimension-menu-width) | 230px |
--wl-layout-popover-widthРоль popover-width. semantic | var(--wl-dimension-popover-width) | 280px |
--wl-layout-command-widthРоль command-width. semantic | var(--wl-dimension-command-width) | 580px |
--wl-metric-command-max-heightРоль command-max-height. semantic | var(--wl-dimension-command-max-height) | 420px |
--wl-metric-command-input-heightРоль command-input-height. semantic | var(--wl-dimension-command-input-height) | 52px |
--wl-layer-commandРоль command-z. semantic | var(--wl-dimension-command-z) | 90 |
--wl-metric-page-header-gapРоль page-header-gap. semantic | var(--wl-dimension-page-header-gap) | 16px |
--wl-metric-filter-bar-gapРоль filter-bar-gap. semantic | var(--wl-dimension-filter-bar-gap) | 10px |
--wl-metric-filter-drawer-widthРоль filter-drawer-width. semantic | var(--wl-dimension-filter-drawer-width) | 380px |
--wl-layer-filterРоль filter-z. semantic | var(--wl-dimension-filter-z) | 90 |
--wl-layer-toastРоль toast-z. semantic | var(--wl-dimension-toast-z) | 100 |
--wl-status-info-iconРоль toast-icon-info. semantic | var(--wl-blue-300) | #9cbdf0 |
--wl-status-success-iconРоль toast-icon-ok. semantic | var(--wl-green-400) | #4cc38a |
--wl-status-warning-iconРоль toast-icon-warn. semantic | var(--wl-amber-400) | #e0a93e |
--wl-status-danger-iconРоль toast-icon-err. semantic | var(--wl-palette-danger) | #ab4448 |
--wl-metric-stepper-input-widthРоль stepper-input-width. semantic | var(--wl-dimension-stepper-input-width) | 76px |
--wl-metric-stepper-btn-widthРоль stepper-btn-width. semantic | var(--wl-dimension-stepper-btn-width) | 36px |
--wl-metric-slider-heightРоль slider-height. semantic | var(--wl-dimension-slider-height) | 6px |
--wl-metric-slider-thumbРоль slider-thumb. semantic | var(--wl-dimension-slider-thumb) | 18px |
--wl-metric-step-numРоль step-num. semantic | var(--wl-dimension-step-num) | 24px |
--wl-metric-table-cell-pad-yРоль table-cell-pad-y. semantic | var(--wl-dimension-table-cell-pad-y) | 11px |
--wl-metric-table-cell-pad-xРоль table-cell-pad-x. semantic | var(--wl-dimension-table-cell-pad-x) | 12px |
--wl-metric-table-head-pad-yРоль table-head-pad-y. semantic | var(--wl-dimension-table-head-pad-y) | 8px |
--wl-metric-stat-bar-heightРоль stat-bar-height. semantic | var(--wl-dimension-stat-bar-height) | 3px |
--wl-metric-colorpick-swРоль colorpick-sw. semantic | var(--wl-dimension-colorpick-sw) | 26px |
--wl-metric-colorpick-sw-smРоль colorpick-sw-sm. semantic | var(--wl-dimension-colorpick-sw-sm) | 20px |
--wl-metric-colorpick-gapРоль colorpick-gap. semantic | var(--wl-dimension-colorpick-gap) | 8px |
--wl-metric-cal-gapРоль cal-gap. semantic | var(--wl-dimension-cal-gap) | 5px |
--wl-metric-cal-day-min-hРоль cal-day-min-h. semantic | var(--wl-dimension-cal-day-min-h) | 60px |
--wl-metric-cal-ev-sizeРоль cal-ev-size. semantic | var(--wl-dimension-cal-ev-size) | 10.5px |
--wl-metric-dp-day-sizeРоль dp-day-size. semantic | var(--wl-dimension-dp-day-size) | 30px |
--wl-metric-dp-panel-padРоль dp-panel-pad. semantic | var(--wl-dimension-dp-panel-pad) | 12px |
--wl-metric-upload-drop-pad-yРоль upload-drop-pad-y. semantic | var(--wl-dimension-upload-drop-pad-y) | 26px |
--wl-metric-upload-drop-pad-xРоль upload-drop-pad-x. semantic | var(--wl-dimension-upload-drop-pad-x) | 20px |
--wl-space-noneОтступ none: 0 px. semantic | var(--wl-space-0) | 0px |
--wl-space-2xsОтступ 2xs: 2 px. semantic | var(--wl-space-2) | 2px |
--wl-space-xsОтступ xs: 4 px. semantic | var(--wl-space-4) | 4px |
--wl-space-smОтступ sm: 8 px. semantic | var(--wl-space-8) | 8px |
--wl-space-mdОтступ md: 12 px. semantic | var(--wl-space-12) | 12px |
--wl-space-lgОтступ lg: 16 px. semantic | var(--wl-space-16) | 16px |
--wl-space-xlОтступ xl: 24 px. semantic | var(--wl-space-24) | 24px |
--wl-space-2xlОтступ 2xl: 32 px. semantic | var(--wl-space-32) | 32px |
--wl-space-3xlОтступ 3xl: 48 px. semantic | var(--wl-space-48) | 48px |
--wl-space-4xlОтступ 4xl: 64 px. semantic | var(--wl-space-64) | 64px |
--wl-type-display-sizeГлавный заголовок вступления; один на экран. semantic | var(--wl-font-display-size) | 40px |
--wl-type-display-line-heightГлавный заголовок вступления; один на экран. semantic | var(--wl-font-display-line-height) | 48px |
--wl-type-display-weightГлавный заголовок вступления; один на экран. semantic | var(--wl-font-display-weight) | 700 |
--wl-type-display-familyГлавный заголовок вступления; один на экран. semantic | var(--wl-font-display-family) | "Gavia Sans Core", "Gavia Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif |
--wl-type-title-sizeНазвание страницы и крупного диалога. semantic | var(--wl-font-title-size) | 28px |
--wl-type-title-line-heightНазвание страницы и крупного диалога. semantic | var(--wl-font-title-line-height) | 36px |
--wl-type-title-weightНазвание страницы и крупного диалога. semantic | var(--wl-font-title-weight) | 700 |
--wl-type-title-familyНазвание страницы и крупного диалога. semantic | var(--wl-font-title-family) | "Gavia Sans Core", "Gavia Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif |
--wl-type-heading-sizeРаздел страницы и самостоятельный блок. semantic | var(--wl-font-heading-size) | 20px |
--wl-type-heading-line-heightРаздел страницы и самостоятельный блок. semantic | var(--wl-font-heading-line-height) | 28px |
--wl-type-heading-weightРаздел страницы и самостоятельный блок. semantic | var(--wl-font-heading-weight) | 650 |
--wl-type-heading-familyРаздел страницы и самостоятельный блок. semantic | var(--wl-font-heading-family) | "Gavia Sans Core", "Gavia Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif |
--wl-type-subheading-sizeКарточка, группа полей, небольшой диалог. semantic | var(--wl-font-subheading-size) | 16px |
--wl-type-subheading-line-heightКарточка, группа полей, небольшой диалог. semantic | var(--wl-font-subheading-line-height) | 24px |
--wl-type-subheading-weightКарточка, группа полей, небольшой диалог. semantic | var(--wl-font-subheading-weight) | 600 |
--wl-type-subheading-familyКарточка, группа полей, небольшой диалог. semantic | var(--wl-font-subheading-family) | "Gavia Sans Core", "Gavia Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif |
--wl-type-body-sizeОписания, инструкции, текст формы. semantic | var(--wl-font-body-size) | 14px |
--wl-type-body-line-heightОписания, инструкции, текст формы. semantic | var(--wl-font-body-line-height) | 20px |
--wl-type-body-weightОписания, инструкции, текст формы. semantic | var(--wl-font-body-weight) | 400 |
--wl-type-body-familyОписания, инструкции, текст формы. semantic | var(--wl-font-body-family) | "Gavia Sans Core", "Gavia Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif |
--wl-type-small-sizeПодписи и вспомогательный текст. semantic | var(--wl-font-small-size) | 12px |
--wl-type-small-line-heightПодписи и вспомогательный текст. semantic | var(--wl-font-small-line-height) | 18px |
--wl-type-small-weightПодписи и вспомогательный текст. semantic | var(--wl-font-small-weight) | 400 |
--wl-type-small-familyПодписи и вспомогательный текст. semantic | var(--wl-font-small-family) | "Gavia Sans Core", "Gavia Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif |
--wl-type-label-sizeКороткая подпись действия или поля. semantic | var(--wl-font-label-size) | 13px |
--wl-type-label-line-heightКороткая подпись действия или поля. semantic | var(--wl-font-label-line-height) | 20px |
--wl-type-label-weightКороткая подпись действия или поля. semantic | var(--wl-font-label-weight) | 500 |
--wl-type-label-familyКороткая подпись действия или поля. semantic | var(--wl-font-label-family) | "Gavia Sans Core", "Gavia Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif |
--wl-type-code-sizeТокены, идентификаторы и технические значения. semantic | var(--wl-font-code-size) | 12px |
--wl-type-code-line-heightТокены, идентификаторы и технические значения. semantic | var(--wl-font-code-line-height) | 18px |
--wl-type-code-weightТокены, идентификаторы и технические значения. semantic | var(--wl-font-code-weight) | 400 |
--wl-type-code-familyТокены, идентификаторы и технические значения. semantic | var(--wl-font-code-family) | "SF Mono", ui-monospace, "Cascadia Mono", Menlo, Consolas, monospace |
--wl-text-mutedВспомогательный текст с контрастом не ниже 4.5:1. semantic | var(--wl-text-2) | #5b6470 |
--wl-focus-colorВидимая обводка клавиатурного фокуса. semantic | var(--wl-accent) | #3c7490 |
--wl-focus-invalid-colorОбводка фокуса поля с ошибкой. semantic | var(--wl-danger-hover) | #963c3f |
--wl-text-dangerЧитаемый текст ошибки на основной поверхности. semantic | var(--wl-err-text) | #ab4448 |
--wl-action-primary-bgПоверхность основного действия. semantic | var(--wl-palette-action-primary-bg) | #3c7490 |
--wl-action-primary-hoverОсновное действие при наведении. semantic | var(--wl-palette-action-primary-hover) | #376b84 |
--wl-action-primary-textЧитаемый текст основного действия. semantic | var(--wl-palette-action-primary-text) | #ffffff |
--wl-action-danger-bgПоверхность опасного действия. semantic | var(--wl-palette-danger) | #ab4448 |
--wl-action-danger-hoverОпасное действие при наведении. semantic | var(--wl-palette-danger-hover) | #963c3f |
--wl-action-danger-textЧитаемый текст опасного действия. semantic | var(--wl-on-accent) | #ffffff |
--wl-layout-page-maxШирина контейнера страницы. semantic | var(--wl-size-page-max) | 1240px |
--wl-layout-page-gutterОтступ контента от границы страницы. semantic | var(--wl-space-xl) | 24px |
--wl-layout-grid-gapИнтервал адаптивной сетки. semantic | var(--wl-space-lg) | 16px |
--wl-elevation-surfaceНебольшое возвышение карточки. semantic | var(--wl-shadow-card) | 0 1px 3px rgba(15, 26, 35, 0.05) |
--wl-elevation-floatingВозвышение плавающей поверхности. semantic | var(--wl-shadow-pop) | 0 4px 14px rgba(15, 26, 35, 0.08), 0 16px 44px rgba(15, 26, 35, 0.12) |
--wl-motion-fastМикроотклик кнопки и поля. semantic | var(--wl-dur-2) | 0.12s |
--wl-motion-normalПоявление небольшой панели. semantic | var(--wl-dur-4) | 0.18s |
--wl-motion-slowКрупный модальный переход. semantic | var(--wl-dur-5) | 0.2s |
--wl-motion-easeКривая движения. semantic | var(--wl-ease) | ease |
--wl-layout-reading-maxШирина узкого контейнера для статей и инструкций. semantic | var(--wl-size-reading-max) | 72ch |
--wl-layout-grid-minМинимальная ширина колонки wl-grid; внутри узкого контейнера ограничивается 100%. semantic | var(--wl-size-grid-min) | 240px |
--wl-layer-baseСлой обычного позиционированного контента в его stacking context. semantic | var(--wl-z-base) | 0 |
--wl-layer-stickyСлой sticky-шапки или навигации; не поднимает элемент над родительским stacking context. semantic | var(--wl-z-sticky) | 50 |
--wl-action-primary-activeПоверхность основного действия при нажатии. semantic | var(--wl-palette-action-primary-active) | #326179 |
--wl-accent-warmДозированный тёплый акцент для иллюстраций, декоративных отметок и небольших деталей. semantic | var(--wl-palette-accent-warm) | #948775 |
--wl-accent-warm-softФон декоративного тёплого выделения; для текста использовать основную текстовую роль. semantic | var(--wl-palette-accent-warm-soft) | #efebe3 |
--wl-corner-buttonСкругление обычной кнопки, независимое от полей и карточек. semantic | var(--wl-dimension-btn-radius) | 4px |
--wl-corner-button-smСкругление кнопок размеров xs и sm. semantic | var(--wl-dimension-btn-radius-sm) | 3px |
--wl-corner-button-lgСкругление кнопки размера lg. semantic | var(--wl-dimension-btn-radius-lg) | 5px |
05 / Компоненты
Props, модели, события и слоты берутся из манифеста библиотеки. Размер и плотность меняют геометрию; вариант передаёт смысл действия; состояния отражают его доступность.
Один primary на группу. Danger — для необратимого действия с подтверждением. Loading блокирует повторную отправку; disabled сопровождается объяснением причины рядом.
Кнопка действия с вариантами, размерами и состоянием загрузки.
| Prop | Тип / значения | Назначение |
|---|---|---|
variant | primary | secondary | ghost | soft | link | Визуальный вариант кнопки. По умолчанию: "secondary" |
tone | neutral | accent | info | success | warning | danger | Семантический цвет, независимый от варианта оформления. |
size | xs | sm | md | lg | Размер кнопки. По умолчанию: "md" |
density | default | compact | В режиме compact высота кнопки меньше. По умолчанию: "default" |
loading | boolean | Показывает загрузку вместо иконки и блокирует нажатие. По умолчанию: false |
disabled | boolean | Отключает кнопку. По умолчанию: false |
block | boolean | Растянуть на всю ширину контейнера. По умолчанию: false |
type | button | submit | reset | Нативный type кнопки. По умолчанию: "button" |
pt | object | Атрибуты внутренних элементов Gavia UI. |
as | union | Явно выбирает отрисовку ссылки; href или to тоже включают этот режим. |
href | string | Адрес ссылки, передаваемый в WlLink. |
to | union | Назначение маршрута приложения, которое обрабатывает настроенный адаптер ссылок. |
iconPosition | union | Располагает иконку перед основным слотом или после него. |
default — Текст или другое содержимое кнопки.icon — Иконка слева (скрывается при loading).click — MouseEventНажатий: 0
Hover и нажатие проверяйте мышью; focus — клавиатурой. Выбор, открытие и закрытие меняют v-model. Настройки выше можно сочетать.
<script setup lang="ts">
import { WlButton, WlIcon } from "gavia-ui";
import { ref } from "vue";
const count = ref(0);
</script>
<template>
<div class="wl-stack" data-space="md">
<div>
<WlButton @click="count++"><template #icon><WlIcon name="plus" /></template>{{ "Добавить" }}</WlButton>
</div>
<p role="status" class="wl-text-small">{{ "Нажатий:" }} {{ count }}</p>
</div>
</template>06 / Паттерны
Компоненты отвечают за отображение и взаимодействие. Валидацию, запросы и бизнес-правила задаёт приложение. Примеры на этой странице работают без сервера.
WlField передаёт id, invalid и ariaDescribedby через scoped slot. Placeholder дополняет подпись.
| Материал | Состояние |
|---|---|
| Правила типографики | Готово |
| Каталог токенов | Готово |
| Контракты компонентов | Готово |
Drawer открывается поверх страницы. Escape закрывает панель, фокус возвращается к кнопке открытия. Анимацию можно задать для приложения или отдельной панели.
07 / Рецепты
Шесть примеров с кодом для копирования: состояния данных, отмена, ошибки и повторные действия. Сценарии проверяются вместе с компонентами.
Поиск, фильтры, сортировка и страницы. Создание и редактирование в Drawer, подтверждение удаления и Toast.
| Материал | Статус | Действия |
|---|---|---|
| Доступы и роли | В работе | |
| Доступы и роли · 12 | В работе | |
| Доступы и роли · 8 | В работе | |
| План исследования | В работе |
Найдено: 12 · страница 1 из 3
<script setup lang="ts">
import { useWlConfirm, useWlToast, WlButton, WlDrawer, WlEmpty, WlField, WlFilterBar, WlInput, WlPageHeader, WlPagination, WlPill, WlSelect, WlTable, type WlTableColumn, WlTag } from "gavia-ui";
import { computed, nextTick, ref, watch } from "vue";
type Material = { id: number; title: string; status: string };
const materials = ref<Material[]>(Array.from({ length: 12 }, (_, index) => ({
id: index + 1, title: ["Руководство команды", "План исследования", "Правила ревью", "Доступы и роли"][index % 4] + (index < 4 ? "" : ` · ${index + 1}`),
status: index % 2 ? "progress" : "done"
})));
const search = ref("");
const status = ref<string | null>(null);
const order = ref<string | null>("asc");
const page = ref(1);
const confirm = useWlConfirm();
const toast = useWlToast();
const filtered = computed(() => materials.value.filter((item) =>
item.title.toLocaleLowerCase("ru").includes(search.value.toLocaleLowerCase("ru")) && (!status.value || item.status === status.value))
.sort((a, b) => a.title.localeCompare(b.title, "ru") * (order.value === "desc" ? -1 : 1)));
const pageCount = computed(() => Math.max(1, Math.ceil(filtered.value.length / 4)));
const visibleRows = computed(() => filtered.value.slice((page.value - 1) * 4, page.value * 4));
watch([search, status, order], () => {
page.value = 1;
});
watch(pageCount, (count) => {
page.value = Math.min(page.value, count);
});
const columns: readonly WlTableColumn<Material>[] = [{ key: "title", label: "Материал" }, { key: "status", label: "Статус" }, { key: "actions", label: "Действия", kind: "virtual" }];
function clear(): void {
search.value = "";
status.value = null;
}
const editing = ref(false);
const editingId = ref<number | null>(null);
const title = ref("");
const titleError = ref("");
let nextId = 13;
function edit(item?: Material): void {
editingId.value = item?.id ?? null;
title.value = item?.title ?? "";
titleError.value = "";
editing.value = true;
}
async function save(): Promise<void> {
titleError.value = title.value.trim() ? "" : "Введите название.";
if (titleError.value) {
await nextTick();
document.getElementById("recipe-material-title")?.focus();
return;
}
const current = materials.value.find((item) => item.id === editingId.value);
if (current) current.title = title.value.trim();
else materials.value.push({ id: nextId++, title: title.value.trim(), status: "progress" });
editing.value = false;
toast.ok("Материал сохранён");
}
function remove(id: number): void {
const item = materials.value.find((entry) => entry.id === id);
if (!item) return;
confirm.confirmDanger({
header: "Удалить материал?", message: `«${item.title}${"» будет удалён."}`, acceptLabel: "Удалить", rejectLabel: "Отмена",
accept: () => {
materials.value = materials.value.filter((entry) => entry.id !== id);
toast.ok("Материал удалён");
}
});
}
</script>
<template>
<section class="wl-stack" data-space="lg" aria-label="Список материалов">
<WlPageHeader
title="Материалы команды"
description="Документы, договорённости и исследования."
:heading-level="2"
size="md"
>
<template #meta><WlTag>{{ materials.length }} {{ "материалов" }}</WlTag></template>
<template #actions><WlButton variant="primary" @click="edit()">{{ "Создать материал" }}</WlButton></template>
</WlPageHeader>
<WlInput
v-model="search"
type="search"
placeholder="Найти материал"
aria-label="Найти материал"
/>
<WlFilterBar
:active-count="Number(Boolean(status))"
aria-label="Фильтры материалов"
panel-title="Фильтры материалов"
@clear="clear"
>
<WlSelect
v-model="status"
:options="[{ label: 'Готово', value: 'done' }, { label: 'В работе', value: 'progress' }]"
option-label="label"
option-value="value"
aria-label="Статус материалов"
placeholder="Все статусы"
/>
<WlSelect
v-model="order"
:options="[{ label: 'Название А–Я', value: 'asc' }, { label: 'Название Я–А', value: 'desc' }]"
option-label="label"
option-value="value"
aria-label="Порядок материалов"
/>
<template #summary><WlTag
v-if="status"
removable
remove-label="Убрать фильтр статуса"
@remove="status = null"
>{{ status === 'done' ? "Готово" : "В работе" }}</WlTag></template>
</WlFilterBar>
<div
v-if="filtered.length"
class="ds-material-table"
role="region"
aria-label="Материалы команды"
tabindex="0"
><WlTable :columns="columns" :value="visibleRows" :pt="{ root: { style: { minWidth: '640px' } } }">
<template #cell-status="{ value }">
<WlPill
:tone="value === 'done' ? 'success' : 'info'"
:label="value === 'done' ? 'Готово' : 'В работе'"
/>
</template>
<template #cell-actions="{ row }"><div class="wl-inline" data-space="xs"><WlButton
size="sm"
variant="ghost"
:aria-label="`${'Редактировать '}${row.title}`"
@click="edit(materials.find((item) => item.id === row.id))"
>{{ "Изменить" }}</WlButton><WlButton
size="sm"
variant="ghost"
tone="danger"
:aria-label="`${'Удалить '}${row.title}`"
@click="remove(Number(row.id))"
>{{ "Удалить" }}</WlButton></div></template>
</WlTable></div>
<WlEmpty
v-else
icon="search"
title="Материалы не найдены"
description="Измените запрос или сбросьте фильтры."
><template #action><WlButton @click="clear">{{ "Сбросить поиск" }}</WlButton></template></WlEmpty>
<div class="wl-inline" data-space="md">
<WlPagination v-if="filtered.length" v-model:page="page" :page-count="pageCount" />
<p class="wl-text-small wl-text-muted" role="status">
{{ "Найдено:" }} {{ filtered.length }} {{ "· страница" }}
{{ page }} {{ "из" }} {{ pageCount }}
</p>
</div>
<WlDrawer v-model:visible="editing" :header="editingId ? 'Редактирование материала' : 'Новый материал'">
<form
id="recipe-material-form"
class="wl-stack"
data-space="lg"
@submit.prevent="save"
>
<WlField
id="recipe-material-title"
v-slot="field"
label="Название"
required
:error="titleError"
><WlInput
:id="field.id"
v-model="title"
:invalid="field.invalid"
:aria-describedby="field.ariaDescribedby"
maxlength="120"
/></WlField>
<p class="wl-text-small wl-text-muted">{{ "Чтобы применить изменения, нажмите «Сохранить»." }}</p>
</form>
<template #footer>
<WlButton variant="ghost" @click="editing = false">{{ "Отмена" }}</WlButton>
<WlButton variant="primary" type="submit" form="recipe-material-form">{{ "Сохранить" }}</WlButton>
</template>
</WlDrawer>
</section>
</template>
<style scoped>
.ds-material-table { overflow: auto; max-width: 100%; }
</style>В примерах тестовые данные. Сохранение и загрузка имитируются в браузере. В своём приложении подключите запросы к серверу. Сценарий и код для копирования берутся из одного Vue-файла.
// main.ts — CSS подключается явно; тему задаёт data-wl-theme на html.
import { createApp } from "vue";
import { WlConfig, WlToastService, WlConfirmationService, createWlPt, wlLocaleRu } from "gavia-ui";
import "gavia-ui/styles/reset.css";
import "gavia-ui/styles/base.css";
import "gavia-ui/styles/primitives.css";
import "gavia-ui/themes/white.css";
import "gavia-ui/themes/graphite.css";
import "gavia-ui/themes/newspaper.css";
import "gavia-ui/styles/fonts/gavia.css";
import "gavia-ui/themes/gavia.css";
import "gavia-ui/themes/gavia-dark.css";
import App from "./App.vue";
document.documentElement.dataset.wlTheme = "white";
// WlConfig merges application pt with defaults; local component pt is applied last.
const pt = createWlPt({ button: { root: { "data-ui": "action" } } });
createApp(App).use(WlConfig, { locale: wlLocaleRu, motion: true, pt })
.use(WlToastService).use(WlConfirmationService).mount("#app");
// App.vue: импортируйте WlToast/WlConfirmDialog и смонтируйте по одному
// контейнеру рядом со страницей. Уведомления и подтверждения используют их.
// <template><YourPage /><WlToast /><WlConfirmDialog /></template>08 / Сложный контент
Длинный русский текст, восемь тегов, 80 вариантов выбора, 20 строк таблицы, ограниченные даты и вложенные оверлеи. Изменяйте ширину окна и размер текста.
| Длинное название | Идентификатор |
|---|---|
| Договорённости международной распределённой команды по совместной подготовке материалов и проведению исследований · 1 | research_material_without_spaces_2026_10_01_abcdefghijklmnopqrstuvwxyz |
| Договорённости международной распределённой команды по совместной подготовке материалов и проведению исследований · 2 | research_material_without_spaces_2026_10_01_abcdefghijklmnopqrstuvwxyz |
| Договорённости международной распределённой команды по совместной подготовке материалов и проведению исследований · 3 | research_material_without_spaces_2026_10_01_abcdefghijklmnopqrstuvwxyz |
| Договорённости международной распределённой команды по совместной подготовке материалов и проведению исследований · 4 | research_material_without_spaces_2026_10_01_abcdefghijklmnopqrstuvwxyz |
| Договорённости международной распределённой команды по совместной подготовке материалов и проведению исследований · 5 | research_material_without_spaces_2026_10_01_abcdefghijklmnopqrstuvwxyz |
| Договорённости международной распределённой команды по совместной подготовке материалов и проведению исследований · 6 | research_material_without_spaces_2026_10_01_abcdefghijklmnopqrstuvwxyz |
| Договорённости международной распределённой команды по совместной подготовке материалов и проведению исследований · 7 | research_material_without_spaces_2026_10_01_abcdefghijklmnopqrstuvwxyz |
| Договорённости международной распределённой команды по совместной подготовке материалов и проведению исследований · 8 | research_material_without_spaces_2026_10_01_abcdefghijklmnopqrstuvwxyz |
| Договорённости международной распределённой команды по совместной подготовке материалов и проведению исследований · 9 | research_material_without_spaces_2026_10_01_abcdefghijklmnopqrstuvwxyz |
| Договорённости международной распределённой команды по совместной подготовке материалов и проведению исследований · 10 | research_material_without_spaces_2026_10_01_abcdefghijklmnopqrstuvwxyz |
| Договорённости международной распределённой команды по совместной подготовке материалов и проведению исследований · 11 | research_material_without_spaces_2026_10_01_abcdefghijklmnopqrstuvwxyz |
| Договорённости международной распределённой команды по совместной подготовке материалов и проведению исследований · 12 | research_material_without_spaces_2026_10_01_abcdefghijklmnopqrstuvwxyz |
| Договорённости международной распределённой команды по совместной подготовке материалов и проведению исследований · 13 | research_material_without_spaces_2026_10_01_abcdefghijklmnopqrstuvwxyz |
| Договорённости международной распределённой команды по совместной подготовке материалов и проведению исследований · 14 | research_material_without_spaces_2026_10_01_abcdefghijklmnopqrstuvwxyz |
| Договорённости международной распределённой команды по совместной подготовке материалов и проведению исследований · 15 | research_material_without_spaces_2026_10_01_abcdefghijklmnopqrstuvwxyz |
| Договорённости международной распределённой команды по совместной подготовке материалов и проведению исследований · 16 | research_material_without_spaces_2026_10_01_abcdefghijklmnopqrstuvwxyz |
| Договорённости международной распределённой команды по совместной подготовке материалов и проведению исследований · 17 | research_material_without_spaces_2026_10_01_abcdefghijklmnopqrstuvwxyz |
| Договорённости международной распределённой команды по совместной подготовке материалов и проведению исследований · 18 | research_material_without_spaces_2026_10_01_abcdefghijklmnopqrstuvwxyz |
| Договорённости международной распределённой команды по совместной подготовке материалов и проведению исследований · 19 | research_material_without_spaces_2026_10_01_abcdefghijklmnopqrstuvwxyz |
| Договорённости международной распределённой команды по совместной подготовке материалов и проведению исследований · 20 | research_material_without_spaces_2026_10_01_abcdefghijklmnopqrstuvwxyz |
09 / Доступность
Контраст текста — от 4.5:1, индикатора фокуса — от 3:1. Отчёт проверяет перечисленные пары токенов; пользовательские цвета и весь экран проверяются отдельно.
Tab — переход. Enter / Space — действие. Стрелки — выбор. Escape — закрытие оверлея. Фокус виден и возвращается после закрытия.
motion: false выключает переходы. Системное prefers-reduced-motion действует во всех темах. Анимация не меняет смысл или время жизни данных.
Иконка действия получает aria-label. Ошибка объясняет следующий шаг. Цель на touch-экране: ориентир 44 × 44 px; выбирайте lg и достаточные интервалы.
| Пара / gavia | Факт | Минимум |
|---|---|---|
| Основной текст | 16.73:1 | 4.5:1 |
| Вспомогательный текст | 5.7:1 | 4.5:1 |
| Текст на вторичной поверхности | 15.63:1 | 4.5:1 |
| Основное действие | 5.13:1 | 4.5:1 |
| Основное действие: hover | 5.84:1 | 4.5:1 |
| Основное действие: active | 6.73:1 | 4.5:1 |
| Опасное действие | 5.75:1 | 4.5:1 |
| Опасное действие: hover | 6.97:1 | 4.5:1 |
| Подсказка | 17.61:1 | 4.5:1 |
| Информационное сообщение | 7.8:1 | 4.5:1 |
| Успешное сообщение | 5.84:1 | 4.5:1 |
| Предупреждение | 5.73:1 | 4.5:1 |
| Сообщение об ошибке | 5.04:1 | 4.5:1 |
| Фокус на странице | 4.87:1 | 3:1 |
| Ссылка на странице | 6.39:1 | 4.5:1 |
| Фокус на вторичной поверхности | 4.55:1 | 3:1 |
| Текст на поднятой поверхности | 17.33:1 | 4.5:1 |
| Вспомогательный текст на поднятой поверхности | 5.9:1 | 4.5:1 |
| Фокус на поднятой поверхности | 5.05:1 | 3:1 |
| Акцентный текст на поднятой поверхности | 6.62:1 | 4.5:1 |
| Акцентный текст на вторичной поверхности | 5.97:1 | 4.5:1 |
| Акцентный текст на выбранной поверхности | 5.41:1 | 4.5:1 |
| Акцентный текст на мягкой поверхности при наведении | 4.95:1 | 4.5:1 |
Новые токены проходят tokens:check. Паттерны проверяются в Chromium, Firefox, WebKit и мобильном Chromium. Перед релизом также проверяются типы, архив и изолированный потребитель.