@qor/ui

@qor/ui

Расширение темы Nuxt UI 4 для QOR.

Модуль @qor/ui расширяет тему Nuxt UI 4 с кастомными настройками для платформы QOR.

Установка

Terminal
pnpm add @qor/ui
nuxt.config.ts
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" />

Переопределения компонентов

Настроены стили по умолчанию для компонентов:

КомпонентИзменения
UButtoncolor: neutral, variant: subtle
UInput / UTextareacolor: neutral, variant: subtle, custom focus ring
USelectcolor: neutral, variant: subtle
UCardvariant: subtle, shadow, custom padding
UTableУвеличенные отступы, muted заголовки
UTabsКастомные стили для pill и link вариантов
UBadgecolor: neutral, variant: subtle
Dashboard компонентыКастомные стили sidebar, navbar, panel

Опции модуля

nuxt.config.ts
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 (стартовый плагин не нужен):

nuxt.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' },
      },
    },
  },
})
app.config.ts
export default defineAppConfig({
  qorUI: {
    statusRegistries: { /* … (имеет приоритет над nuxt.config) */ },
  },
})

Runtime-регистрация registerStatus(registry, entries) тоже доступна и теперь SSR-safe: оверрайды хранятся per-request (useState), а не в модульном синглтоне — больше нет утечки реестров между запросами на сервере.