Andrey Epifancev d2b4ff2018 feat: skill aura-design — дизайн-система AURA для личных проектов (#17)
Скилл переносится из ~/.claude/skills/aura-design в репозиторий обвязки:
SKILL.md, справочники reference/ и набор kit/ (токены, base.css, компоненты
React, оболочка AppShell, тест токенов, test-setup, примеры входа).
install.sh ставит его в ~/.claude/skills/aura-design, --check его видит.
tests/test-aura-design.sh проверяет структуру и инварианты набора.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 12:10:34 +04:00

271 lines
20 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* базовые компоненты AURA: только переменные из styles/tokens.css, веса 400/600/700 */
.ui-btn, .ui-icon-btn, .ui-seg__item, .ui-theme, .ui-chip__x {
font-family: var(--font-ui); cursor: pointer;
transition: background var(--motion), border-color var(--motion), color var(--motion);
}
.ui-btn:focus-visible, .ui-icon-btn:focus-visible, .ui-seg__item:focus-visible, .ui-theme:focus-visible, .ui-chip__x:focus-visible {
outline: 2px solid var(--color-focus-ring); outline-offset: 2px;
}
.ui-btn {
display: inline-flex; align-items: center; justify-content: center; gap: var(--space-2);
height: var(--control-h); padding: 0 var(--space-4); border: 1px solid transparent; border-radius: var(--radius-round);
font-size: var(--fs-body); line-height: var(--lh-body); font-weight: 600; white-space: nowrap;
}
.ui-btn--lg { height: var(--control-h-lg); padding: 0 var(--space-5); }
.ui-btn--primary { background: var(--color-action-primary); color: var(--color-text-on-primary); }
.ui-btn--primary:hover:not(:disabled) { background: var(--color-action-primary-hover); }
.ui-btn--secondary { background: transparent; border-color: var(--color-border-strong); color: var(--color-text-primary); }
.ui-btn--secondary:hover:not(:disabled) { border-color: var(--color-action-primary); }
.ui-btn--secondary[aria-pressed="true"] {
background: var(--color-bg-selected); border-color: var(--color-action-primary); color: var(--color-action-primary);
}
.ui-btn--danger { background: var(--color-action-danger); color: var(--color-text-on-primary); }
.ui-btn--danger:hover:not(:disabled) { background: var(--color-action-danger-hover); }
.ui-btn--ghost { background: transparent; color: var(--color-action-primary); }
.ui-btn--ghost:hover:not(:disabled) { background: var(--color-bg-hover); color: var(--color-action-primary-hover); }
.ui-btn:disabled { cursor: not-allowed; color: var(--color-text-disabled); }
.ui-btn--primary:disabled, .ui-btn--danger:disabled { background: var(--color-bg-track); border-color: var(--color-border-default); }
.ui-btn[aria-busy="true"] { cursor: progress; }
/* загрузка: вид своего варианта, а не серая «выключенная» кнопка (AURA); повторный щелчок невозможен — disabled */
.ui-btn--primary[aria-busy="true"]:disabled { background: var(--color-action-primary); border-color: transparent; color: var(--color-text-on-primary); }
.ui-btn--danger[aria-busy="true"]:disabled { background: var(--color-action-danger); border-color: transparent; color: var(--color-text-on-primary); }
.ui-btn--secondary[aria-busy="true"]:disabled { color: var(--color-text-primary); }
.ui-btn--ghost[aria-busy="true"]:disabled { color: var(--color-action-primary); }
.ui-btn--primary[aria-busy="true"] .ui-spinner, .ui-btn--danger[aria-busy="true"] .ui-spinner {
border-color: color-mix(in srgb, var(--color-text-on-primary) 35%, transparent); border-top-color: var(--color-text-on-primary);
}
.ui-spinner {
width: 16px; height: 16px; border-radius: var(--radius-round);
border: 2px solid var(--color-border-strong); border-top-color: var(--color-action-primary);
animation: ui-spin 800ms linear infinite;
}
@keyframes ui-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .ui-spinner { animation-duration: 2400ms; } }
.ui-icon-btn {
display: inline-flex; align-items: center; justify-content: center; width: var(--control-h); height: var(--control-h);
padding: 0; border: 1px solid transparent; border-radius: var(--control-radius); background: transparent; color: var(--color-text-secondary);
}
.ui-icon-btn:hover:not(:disabled) { background: var(--color-bg-hover); border-color: var(--color-border-strong); color: var(--color-text-primary); }
.ui-icon-btn:disabled { cursor: not-allowed; color: var(--color-text-disabled); }
.ui-seg {
display: inline-flex; gap: var(--space-1); padding: var(--space-1); border-radius: var(--radius-round); background: var(--color-bg-track);
}
.ui-seg__item {
display: inline-flex; align-items: center; height: 24px; padding: 0 var(--space-4); border: 1px solid transparent;
border-radius: var(--radius-round); background: transparent; color: var(--color-text-secondary);
font-size: var(--fs-body); line-height: var(--lh-body); font-weight: 400; text-decoration: none; white-space: nowrap;
}
.ui-seg__item:hover { color: var(--color-text-primary); }
.ui-seg__item[aria-checked="true"], .ui-seg__item[aria-current="page"] {
background: var(--color-bg-surface); border-color: var(--color-border-selected); color: var(--color-action-primary); font-weight: 600;
}
.ui-theme {
display: inline-flex; align-items: center; width: 44px; height: 24px; padding: 2px; border: 1px solid var(--color-border-strong);
border-radius: var(--radius-round); background: var(--color-bg-track); color: var(--color-text-secondary);
}
.ui-theme__knob {
display: inline-flex; align-items: center; justify-content: center; width: 18px; height: 18px; border-radius: var(--radius-round);
background: var(--color-bg-surface); box-shadow: inset 0 0 0 1px var(--color-border-default); transition: transform var(--motion);
}
.ui-theme[aria-checked="true"] { border-color: var(--color-border-selected); color: var(--color-action-primary); }
.ui-theme[aria-checked="true"] .ui-theme__knob { transform: translateX(20px); }
.ui-badge {
display: inline-flex; align-items: center; height: 20px; padding: 0 var(--space-2); border: 1px solid transparent;
border-radius: var(--radius-round); font-size: var(--fs-caption); line-height: var(--lh-caption); font-weight: 600; white-space: nowrap;
}
.ui-badge--neutral { background: var(--color-bg-track); border-color: var(--color-border-default); color: var(--color-text-secondary); }
.ui-badge--success { background: var(--color-status-success-bg); border-color: var(--color-status-success); color: var(--color-status-success); }
.ui-badge--error { background: var(--color-status-error-bg); border-color: var(--color-status-error); color: var(--color-status-error); }
.ui-badge--warning { background: var(--color-status-warning-bg); border-color: var(--color-status-warning-border); color: color-mix(in srgb, var(--color-status-warning) 55%, var(--color-text-primary)); }
.ui-badge--info { background: var(--color-bg-subtle); border-color: var(--color-border-strong); color: var(--color-text-primary); }
.ui-chip {
display: inline-flex; align-items: center; gap: var(--space-1); height: 24px; padding: 0 var(--space-1) 0 var(--space-3);
border: 1px solid var(--color-border-selected); border-radius: var(--radius-round); background: var(--color-bg-selected);
color: var(--color-action-primary); font-size: var(--fs-caption); line-height: var(--lh-caption); font-weight: 600;
}
.ui-chip__x {
display: inline-flex; align-items: center; justify-content: center; width: 20px; height: 20px; padding: 0; border: 0;
border-radius: var(--radius-round); background: transparent; color: inherit;
}
.ui-chip__x:hover { background: var(--color-bg-hover); }
.ui-notice {
display: flex; align-items: flex-start; gap: var(--space-3); padding: var(--space-3) var(--space-4);
border: 1px solid var(--color-border-default); border-radius: var(--radius-lg); background: var(--color-bg-subtle);
}
.ui-notice__icon {
display: inline-flex; flex: none; align-items: center; justify-content: center; width: 20px; height: 20px;
border-radius: var(--radius-round); color: var(--color-text-on-primary); background: var(--color-text-secondary);
}
.ui-notice__body { flex: 1; min-width: 0; }
.ui-notice__title { font-size: var(--fs-body); line-height: var(--lh-body); font-weight: 600; color: var(--color-text-primary); }
.ui-notice__text { font-size: var(--fs-caption); line-height: var(--lh-caption); color: var(--color-text-primary); }
.ui-notice__action { flex: none; }
.ui-notice a { color: var(--color-action-primary); }
.ui-notice--warning a { color: var(--color-text-primary); text-decoration: underline; }
.ui-notice--success { background: var(--color-status-success-bg); border-color: var(--color-status-success); }
.ui-notice--success .ui-notice__icon { background: var(--color-status-success); }
.ui-notice--error { background: var(--color-status-error-bg); border-color: var(--color-status-error); }
.ui-notice--error .ui-notice__icon { background: var(--color-status-error); }
.ui-notice--warning { background: var(--color-status-warning-bg); border-color: var(--color-status-warning-border); }
.ui-notice--warning .ui-notice__icon { background: var(--color-status-warning); }
.ui-panel {
background: var(--color-bg-surface); border: 1px solid var(--color-border-default); border-radius: var(--radius-xl);
}
.ui-panel--md { padding: var(--space-4); }
.ui-panel--lg { padding: var(--space-6); }
.ui-panel--none { padding: 0; }
.ui-page-header { display: flex; flex-direction: column; gap: var(--space-4); margin-bottom: var(--space-4); }
.ui-page-header__row { display: flex; flex-wrap: wrap; align-items: flex-start; justify-content: space-between; gap: var(--space-4); }
.ui-page-header__text { min-width: 0; }
.ui-page-header__title { margin: 0; font-size: var(--fs-section); line-height: var(--lh-section); font-weight: 700; color: var(--color-text-primary); }
.ui-page-header__subtitle { margin: var(--space-1) 0 0; font-size: var(--fs-body); line-height: var(--lh-body); color: var(--color-text-secondary); }
.ui-page-header__actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); }
/* поля */
.ui-field { display: flex; flex-direction: column; gap: var(--space-1); }
.ui-field__label { font-size: var(--fs-body); line-height: var(--lh-body); font-weight: 600; color: var(--color-text-primary); }
.ui-field__hint { font-size: var(--fs-caption); line-height: var(--lh-caption); color: var(--color-text-secondary); }
.ui-field__error { font-size: var(--fs-caption); line-height: var(--lh-caption); color: var(--color-status-error); }
.ui-input {
box-sizing: border-box; width: 100%; height: var(--control-h); padding: 0 var(--space-3);
border: 1px solid var(--color-border-default); border-radius: var(--control-radius);
background: var(--color-bg-surface); color: var(--color-text-primary);
font: inherit; font-family: var(--font-ui); font-size: var(--fs-body); line-height: var(--lh-body);
transition: border-color var(--motion), box-shadow var(--motion);
}
.ui-input--lg { height: var(--control-h-lg); }
.ui-input::placeholder { color: var(--color-text-placeholder); }
.ui-input:hover:not(:disabled) { border-color: var(--color-border-strong); }
.ui-input:focus-visible { outline: 2px solid var(--color-focus-ring); outline-offset: 2px; border-color: var(--color-action-primary); }
.ui-input[aria-invalid="true"] { border-color: var(--color-status-error); }
.ui-input:disabled { cursor: not-allowed; color: var(--color-text-disabled); background: var(--color-bg-track); }
.ui-textarea { height: auto; min-height: 80px; padding: var(--space-2) var(--space-3); resize: vertical; }
.ui-search { position: relative; display: inline-flex; align-items: center; width: 100%; }
.ui-search__icon { position: absolute; left: var(--space-3); display: inline-flex; color: var(--color-text-secondary); pointer-events: none; }
.ui-search__input { padding-left: calc(var(--space-3) + 24px); padding-right: calc(var(--space-2) + var(--control-h)); }
.ui-search__input::-webkit-search-cancel-button { display: none; }
.ui-search__clear { position: absolute; right: 0; }
.ui-select { position: relative; display: inline-flex; align-items: center; width: 100%; }
.ui-select__control { appearance: none; padding-right: calc(var(--space-3) + 24px); cursor: pointer; }
.ui-select--lg .ui-select__control { height: var(--control-h-lg); }
.ui-select__chevron { position: absolute; right: var(--space-3); display: inline-flex; color: var(--color-text-secondary); pointer-events: none; }
.ui-check { display: inline-flex; align-items: center; gap: var(--space-2); font-size: var(--fs-body); line-height: var(--lh-body); color: var(--color-text-primary); cursor: pointer; }
.ui-check__box { width: 16px; height: 16px; margin: 0; border-radius: var(--radius-xs); accent-color: var(--color-action-primary); cursor: pointer; }
.ui-check__box:focus-visible { outline: 2px solid var(--color-focus-ring); outline-offset: 2px; }
/* окно */
.ui-dialog {
box-sizing: border-box; max-width: none; max-height: 90vh; padding: var(--space-6); overflow: auto;
border: 1px solid var(--color-border-default); border-radius: var(--radius-2xl);
background: var(--color-bg-surface); color: var(--color-text-primary); box-shadow: var(--shadow-dialog);
font-family: var(--font-ui);
}
.ui-dialog::backdrop { background: var(--color-overlay); }
.ui-dialog--sm { width: min(480px, calc(100vw - 32px)); }
.ui-dialog--md { width: min(640px, calc(100vw - 32px)); }
.ui-dialog--lg { width: min(1000px, calc(100vw - 32px)); }
@media (max-width: 700px) {
.ui-dialog { width: 100vw; max-width: 100vw; height: 100vh; max-height: 100vh; margin: 0; border-radius: 0; }
}
/* выпадающая панель и меню: пункты — кнопки; «выбрано» — цветом текста и галочкой */
.dd { position: relative; display: inline-block; }
.dd-menu {
position: absolute; top: calc(100% + var(--space-1)); left: 0; z-index: 20; min-width: 280px; max-width: 420px;
display: flex; flex-direction: column; gap: var(--space-2); padding: var(--space-2);
background: var(--color-bg-surface); border: 1px solid var(--color-border-default); border-radius: var(--radius-lg);
box-shadow: var(--shadow-popover); color: var(--color-text-primary); font-family: var(--font-ui);
}
.dd-menu.menu { right: 0; left: auto; min-width: 230px; gap: 0; padding: var(--space-1); }
.dd-list { max-height: 260px; overflow: auto; display: flex; flex-direction: column; }
.dd-item {
display: flex; align-items: center; gap: var(--space-2); padding: var(--space-1) var(--space-2); border-radius: var(--radius-sm);
font-size: var(--fs-body); line-height: var(--lh-body); cursor: pointer;
}
.dd-item:hover { background: var(--color-bg-hover); }
.dd-item input { flex: none; width: 16px; height: 16px; margin: 0; accent-color: var(--color-action-primary); cursor: pointer; }
.dd-item input:focus-visible { outline: 2px solid var(--color-focus-ring); outline-offset: 2px; }
.dd-item .n { margin-left: auto; font-size: var(--fs-caption); color: var(--color-text-secondary); font-variant-numeric: tabular-nums; }
.dd-empty { padding: var(--space-2); font-size: var(--fs-caption); line-height: var(--lh-caption); color: var(--color-text-secondary); }
.dd-foot { display: flex; gap: var(--space-2); justify-content: space-between; border-top: 1px solid var(--color-border-default); padding-top: var(--space-2); }
.dd--start > .dd-menu.menu { left: 0; right: auto; }
.dd--up > .dd-menu { top: auto; bottom: calc(100% + var(--space-1)); }
.menu button {
display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); width: 100%;
min-height: var(--control-h); padding: var(--space-1) var(--space-3); border: 0; border-radius: var(--radius-sm);
background: none; color: var(--color-text-primary); font: inherit; font-family: var(--font-ui);
font-size: var(--fs-body); line-height: var(--lh-body); text-align: left; cursor: pointer;
transition: background var(--motion), color var(--motion);
}
.menu button:hover { background: var(--color-bg-hover); }
.menu button:focus-visible { outline: 2px solid var(--color-focus-ring); outline-offset: -2px; background: var(--color-bg-hover); }
.menu button[aria-pressed="true"] { color: var(--color-action-primary); }
.menu button[aria-pressed="true"]::after { content: "✓"; font-weight: 600; }
.menu button.danger { color: var(--color-status-error); }
.menu hr { border: 0; border-top: 1px solid var(--color-border-default); margin: var(--space-1) 0; }
/* таблица: внутри <Panel padding="none" className="ui-table-wrap">; шапка липнет; строки 44 px, hover — фоном.
Узко — прокрутка внутри обёртки (@container page), а не превращение в карточки; там шапка не липнет (липкость
внутри прокручиваемой обёртки сдвинула бы её на --topbar-h поверх первой строки).
position: relative — чтобы .visually-hidden в ячейках не растягивал страницу за правый край. */
.ui-table-wrap { position: relative; overflow: clip; }
/* --table-min: ширина, уже которой таблица не сжимается, а прокручивается (style={{"--table-min": "760px"}}) */
.ui-table { width: 100%; min-width: var(--table-min, 0); border-collapse: separate; border-spacing: 0; font-size: var(--fs-body); line-height: var(--lh-body); }
.ui-table th, .ui-table td {
height: 44px; padding: 0 var(--space-3); text-align: left; vertical-align: middle; border-bottom: 1px solid var(--color-border-default);
}
.ui-table tbody tr:last-child td { border-bottom: 0; }
.ui-table th {
position: sticky; top: var(--topbar-h, 0); z-index: 1; background: var(--color-bg-surface); color: var(--color-text-secondary);
font-size: var(--fs-caption); line-height: var(--lh-caption); font-weight: 600; white-space: nowrap;
}
.ui-table th:first-child { border-top-left-radius: calc(var(--radius-xl) - 1px); }
.ui-table th:last-child { border-top-right-radius: calc(var(--radius-xl) - 1px); }
.ui-table td { color: var(--color-text-primary); }
.ui-table td.num, .ui-table th.num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.ui-table tbody tr.is-clickable { cursor: pointer; }
/* постоянные действия строки — IconButton в последней ячейке, справа */
.ui-table td.actions { width: 1%; white-space: nowrap; text-align: right; }
.ui-table td.actions .ui-icon-btn + .ui-icon-btn { margin-left: var(--space-1); }
.ui-table tbody tr:hover td { background: var(--color-bg-hover); }
/* после правил шапки: при равной специфичности побеждает то, что ниже */
@container page (max-width: 1051.98px) {
.ui-table-wrap { overflow-x: auto; }
.ui-table th { position: static; }
}
/* просрочка/срок: цвет ошибки и полужирный у самой даты, без заливки строки; рядом visually-hidden «, просрочено» */
.ui-late { color: var(--color-status-error); font-weight: 600; }
/* пустое состояние: по центру панели, вторичным текстом, с действием */
.ui-empty {
display: flex; flex-direction: column; align-items: center; gap: var(--space-3); padding: var(--space-8) var(--space-4);
text-align: center; color: var(--color-text-secondary);
}
.ui-empty__title { font-size: var(--fs-lg); line-height: var(--lh-lg); font-weight: 700; color: var(--color-text-primary); }
/* строка фильтров над списком: поиск растягивается (до 480), остальное — по содержимому, перенос по ширине */
.ui-toolbar { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); margin-bottom: var(--space-4); }
.ui-toolbar > .ui-search { flex: 1 1 280px; max-width: 480px; }
@container page (max-width: 607.98px) { .ui-toolbar > .ui-search { max-width: none; } }
.ui-chips { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); margin: calc(-1 * var(--space-2)) 0 var(--space-4); }
/* форма и окно: поля столбцом с шагом 16, кнопки внизу справа («Отмена» слева от основной) */
.ui-form { display: flex; flex-direction: column; gap: var(--space-4); }
.ui-actions { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: var(--space-2); margin-top: var(--space-2); }
.ui-dialog__title { margin: 0 0 var(--space-4); font-size: var(--fs-lg); line-height: var(--lh-lg); font-weight: 700; }
.ui-dialog__text { margin: 0 0 var(--space-2); color: var(--color-text-secondary); }
/* цветная точка категории: <span class="ui-dot" style="--dot: var(--color-cat-3)"></span> */
.ui-dot { display: inline-block; flex: none; width: 8px; height: 8px; border-radius: var(--radius-round); background: var(--dot, currentColor); vertical-align: middle; }