@qor/ui
Модуль @qor/ui расширяет тему Nuxt UI 4 с кастомными настройками для платформы QOR.
Установка
pnpm add @qor/ui
export default defineNuxtConfig({
modules: ['@qor/ui'],
})
@nuxt/ui v4 — peer dependency. Убедитесь, что он установлен в проекте.Возможности
Цвет бренда QOR
Модуль добавляет кастомный цвет qor (на базе #B9FE47) с полной палитрой оттенков 50-950:
--color-qor-400: oklch(0.93 0.27 125); /* #B9FE47 */
По умолчанию qor используется как primary цвет.
Шрифт
Используется шрифт Geist с оптимизированным letter-spacing:
--font-sans: "Geist", sans-serif;
letter-spacing: -0.2px;
Кастомные иконки
Модуль регистрирует коллекцию иконок qor:* (включая логотип):
<UIcon name="qor:logo" />
Переопределения компонентов
Настроены стили по умолчанию для компонентов:
| Компонент | Изменения |
|---|---|
UButton | color: neutral, variant: subtle |
UInput / UTextarea | color: neutral, variant: subtle, custom focus ring |
USelect | color: neutral, variant: subtle |
UCard | variant: subtle, shadow, custom padding |
UTable | Увеличенные отступы, muted заголовки |
UTabs | Кастомные стили для pill и link вариантов |
UBadge | color: neutral, variant: subtle |
| Dashboard компоненты | Кастомные стили sidebar, navbar, panel |
Опции модуля
export default defineNuxtConfig({
modules: ['@qor/ui'],
qorUI: {
primary: 'qor', // или 'green', 'blue', etc.
neutral: 'neutral',
radius: 0.25, // border-radius multiplier
theme: {}, // deep merge с темой
},
})
Использование
После установки все компоненты Nuxt UI используются как обычно, но с применёнными стилями QOR:
<template>
<UButton>Сохранить</UButton>
<UInput v-model="search" placeholder="Поиск..." />
<UCard>
<UTable :columns="columns" :rows="rows" />
</UCard>
</template>
Компоненты Qor*
Все компоненты авто-импортируются (addComponentsDir), писать импорты не нужно.
| Компонент | Назначение |
|---|---|
QorStatusBadge | Бейдж статуса, связанный с useStatusConfig (цвет/иконка/лейбл из реестра) |
QorThemeToggle | Переключатель темы: segmented / switch / button |
QorSkeleton | Пресеты заглушек загрузки (text/title/avatar/button/card/rect) |
QorListSkeleton | Заглушка для списков/таблиц |
QorPageHeader | Единый заголовок страницы |
QorPhoneInput | Поле ввода телефона (маска KZ) |
QorThemeToggle + useIsDark
Единый переключатель темы вместо ручных colorMode-обвязок в каждом приложении.
<template>
<!-- сегментированный пикер: Система / Светлая / Тёмная -->
<QorThemeToggle />
<QorThemeToggle variant="segmented" labels />
<!-- свитч light ⇄ dark -->
<QorThemeToggle variant="switch" />
<!-- иконка-кнопка -->
<QorThemeToggle variant="button" />
</template>
useIsDark() — реактивный (writable) признак тёмной темы поверх useColorMode:
const { isDark, preference, toggle, setSystem } = useIsDark()
isDark.value = true // → preference = 'dark'
toggle() // light ⇄ dark
setSystem() // следовать системе
useStatusConfig
Единый реестр представления статусов/энумов (цвет + иконка + RU-лейбл + классы +
lifecycle-флаги). Один источник истины вместо локальных мап статус → {label,color,icon}
в каждом приложении.
<script setup lang="ts">
const { resolve, classes, dotClass, band, isTerminal } = useStatusConfig()
</script>
<template>
<!-- предпочтительно: готовый бейдж -->
<QorStatusBadge registry="order_status" :value="order.status" />
<!-- либо вручную через resolve() -->
<UBadge :color="resolve('payment_status', payment.status).color">
{{ resolve('payment_status', payment.status).label }}
</UBadge>
</template>
Реестры
Service-контур (новое в 0.5.0): order_status, service_request_status,
payment_status, payment_method, booking_status, fulfillment, delivery_mode,
channel, conversation_type, participant_type, order_event, priority, presence.
SOMS-контур: incident_status, incident_severity, incident_type, shift_status,
patrol_method. (Значения SOMS в 0.5.0 не ресинкаются — это отдельный breaking-шаг.)
Неизвестное значение не ломает UI: resolve возвращает нейтральный фолбэк с
humanize(value).
Безопасные классы (без динамических имён)
classes() / dotClass() / barClass() возвращают СТАТИЧЕСКИЕ bg-*/text-*/border-*
классы (правило oro-playbook — никаких склеенных на лету имён классов):
<span class="size-2 rounded-full" :class="dotClass('presence', user.presence)" />
<div class="h-full" :class="classes('order_status', order.status).bar" />
Цвет по проценту (SLA/прогресс): band(p) / bandClasses(p) —
>=95 success, >=85 warning, иначе error (пороги переопределяемы).
Lifecycle-флаги
Записи реестров несут terminal / cancellable / active:
const { isTerminal, isCancellable, isActive } = useStatusConfig()
if (isCancellable('order_status', order.status)) { /* показать «Отменить» */ }
Декларативная + SSR-safe регистрация
Объявите доменные реестры декларативно — через опцию модуля или app.config.ts
(стартовый плагин не нужен):
export default defineNuxtConfig({
modules: ['@qor/ui', '@nuxt/ui'],
qorUI: {
statusRegistries: {
delivery_slot: {
morning: { label: 'Утро', color: 'info', icon: 'i-lucide-sunrise' },
evening: { label: 'Вечер', color: 'warning', icon: 'i-lucide-sunset' },
},
},
},
})
export default defineAppConfig({
qorUI: {
statusRegistries: { /* … (имеет приоритет над nuxt.config) */ },
},
})
Runtime-регистрация registerStatus(registry, entries) тоже доступна и теперь
SSR-safe: оверрайды хранятся per-request (useState), а не в модульном
синглтоне — больше нет утечки реестров между запросами на сервере.