// @ts-expect-error vuetify/styles — CSS-импорт без d.ts import 'vuetify/styles'; import { h, type Component } from 'vue'; import { createVuetify } from 'vuetify'; import type { ThemeDefinition, IconSet, IconProps } from 'vuetify'; import { Activity, AlertCircle, AlertTriangle, Archive, ArrowDown, ArrowLeft, ArrowRightLeft, ArrowUp, Bell, BellOff, Calendar, CalendarDays, Camera, Check, CheckCircle, ChevronDown, ChevronLeft, ChevronRight, ChevronsLeft, ChevronsRight, ChevronsUpDown, ChevronUp, Circle, CircleDot, CircleStop, Clock, Code, Columns3, Copy, CreditCard, Download, Eye, EyeOff, FilterX, FileText, FlaskConical, Folder, Folders, Globe, HelpCircle, Info, Key, KeyRound, LayoutDashboard, List, LogOut, Mail, Megaphone, Menu, MessageSquare, MessageSquareText, Minus, MoreVertical, Paperclip, Pause, Pencil, Phone, Play, Plus, PlusCircle, Puzzle, ReceiptText, RefreshCw, RotateCcw, RotateCw, RussianRuble, Save, Search, Settings, Shield, ShieldCheck, ShieldOff, Square, SquareCheck, SquareMinus, Star, StarHalf, Tag, Trash2, User, UserCheck, UserCog, UserPlus, Users, Wallet, Webhook, X, XCircle, } from 'lucide-vue-next'; /** * Палитра Forest extended (Iteration 1 — Quiet Luxury redesign). * Spec: docs/superpowers/specs/2026-05-12-portal-redesign-quiet-luxury-design.md §3 * CSS-токены: app/resources/css/tokens.css (single source of truth) * * 14 OKLCH-статусов воронки маппятся на slugs из db/schema.sql:2076 (lead_statuses) * через `useStatusPill` composable, НЕ через Vuetify theme. */ const liderraForest: ThemeDefinition = { dark: false, colors: { background: '#F6F3EC', surface: '#FFFFFF', primary: '#0F6E56', 'on-primary': '#FFFFFF', secondary: '#012019', 'on-secondary': '#F6F3EC', success: '#2E8B57', warning: '#D9A441', error: '#B83A3A', info: '#3F7C95', // Расширения — для data viz и semantic uses 'liderra-plum': '#7A5BA3', 'liderra-salmon': '#CC6E50', 'liderra-teal-deep': '#0A5A47', 'liderra-muted': '#6B6356', }, }; /** * Liderra Lucide IconSet (CTO-19 closure, v1.83). * Spec: docs/superpowers/specs/2026-05-13-cto-19-lucide-icon-migration-design.md * * Maps 78 mdi-* semantic-ID strings (used across 51 Vue/TS files in resources/js/) * to Lucide Vue components for rendering. Views НЕ touched — mdi-* строки остаются * как semantic identifiers, рендерятся через Lucide stroke-based SVG icons. * * CLAUDE.md §2 «Иконки: Lucide» — бренд-spec compliance. */ const lucideMap: Record = { 'mdi-account-arrow-right-outline': UserCheck, 'mdi-account-group-outline': Users, 'mdi-account-outline': User, 'mdi-account-plus-outline': UserPlus, 'mdi-account-switch': UserCog, 'mdi-alert-circle': AlertCircle, 'mdi-alert-circle-outline': AlertCircle, 'mdi-alert-outline': AlertTriangle, 'mdi-api': Webhook, 'mdi-archive': Archive, 'mdi-arrow-down': ArrowDown, 'mdi-arrow-left': ArrowLeft, 'mdi-arrow-up': ArrowUp, 'mdi-autorenew': RotateCw, 'mdi-bell-off-outline': BellOff, 'mdi-bell-outline': Bell, 'mdi-bullhorn-outline': Megaphone, 'mdi-camera': Camera, 'mdi-cash-plus': PlusCircle, 'mdi-chart-box-outline': LayoutDashboard, 'mdi-check': Check, 'mdi-check-circle': CheckCircle, 'mdi-check-circle-outline': CheckCircle, 'mdi-chevron-right': ChevronRight, 'mdi-clock-check-outline': Clock, 'mdi-clock-outline': Clock, 'mdi-close': X, 'mdi-close-circle': XCircle, 'mdi-cog-outline': Settings, 'mdi-comment-outline': MessageSquare, 'mdi-content-copy': Copy, 'mdi-content-save-outline': Save, 'mdi-credit-card-outline': CreditCard, 'mdi-currency-rub': RussianRuble, 'mdi-delete-outline': Trash2, 'mdi-dots-vertical': MoreVertical, 'mdi-download': Download, 'mdi-email-outline': Mail, 'mdi-eye': Eye, 'mdi-eye-off': EyeOff, 'mdi-eye-outline': Eye, 'mdi-file-pdf-box': FileText, 'mdi-filter-off': FilterX, 'mdi-folder-multiple-outline': Folders, 'mdi-folder-outline': Folder, 'mdi-format-list-bulleted': List, 'mdi-key': Key, 'mdi-lock-reset': KeyRound, 'mdi-logout': LogOut, 'mdi-magnify': Search, 'mdi-message-text': MessageSquareText, 'mdi-pause': Pause, 'mdi-pencil': Pencil, 'mdi-pencil-outline': Pencil, 'mdi-phone': Phone, 'mdi-play': Play, 'mdi-plus': Plus, 'mdi-plus-circle-outline': PlusCircle, 'mdi-progress-clock': Clock, 'mdi-pulse': Activity, 'mdi-puzzle-outline': Puzzle, 'mdi-receipt-text-check-outline': ReceiptText, 'mdi-refresh': RefreshCw, 'mdi-restore': RotateCcw, 'mdi-shield-account-outline': ShieldCheck, 'mdi-shield-key': Shield, 'mdi-shield-lock-outline': ShieldCheck, 'mdi-shield-off': ShieldOff, 'mdi-stop-circle-outline': CircleStop, 'mdi-swap-horizontal': ArrowRightLeft, 'mdi-tag-arrow-right': Tag, 'mdi-test-tube': FlaskConical, 'mdi-trash-can-outline': Trash2, 'mdi-view-column-outline': Columns3, 'mdi-view-dashboard-outline': LayoutDashboard, 'mdi-wallet-outline': Wallet, 'mdi-web': Globe, 'mdi-xml': Code, // Vuetify-internal default mdi-* aliases (CTO-19 closure extension) 'mdi-chevron-down': ChevronDown, 'mdi-chevron-left': ChevronLeft, 'mdi-menu-down': ChevronDown, 'mdi-menu-right': ChevronRight, 'mdi-menu-up': ChevronUp, 'mdi-menu': Menu, 'mdi-page-first': ChevronsLeft, 'mdi-page-last': ChevronsRight, 'mdi-checkbox-marked': SquareCheck, 'mdi-checkbox-blank-outline': Square, 'mdi-minus-box': SquareMinus, 'mdi-radiobox-marked': CircleDot, 'mdi-radiobox-blank': Circle, 'mdi-circle': Circle, 'mdi-information': Info, 'mdi-minus': Minus, 'mdi-calendar': Calendar, 'mdi-calendar-month': CalendarDays, 'mdi-paperclip': Paperclip, 'mdi-unfold-more-horizontal': ChevronsUpDown, 'mdi-window-close': X, 'mdi-cached': RefreshCw, 'mdi-star': Star, 'mdi-star-outline': Star, 'mdi-star-half-full': StarHalf, }; const liderraLucideSet: IconSet = { component: (props: IconProps) => { const Icon = lucideMap[String(props.icon)] || HelpCircle; return h(Icon, { size: 20, strokeWidth: 1.75 }); }, }; export const vuetify = createVuetify({ theme: { defaultTheme: 'liderraForest', themes: { liderraForest }, }, icons: { defaultSet: 'liderra', sets: { liderra: liderraLucideSet }, }, defaults: { VBtn: { variant: 'flat', rounded: 'lg', }, VCard: { rounded: 'lg', variant: 'flat', border: true, }, VTextField: { variant: 'outlined', density: 'comfortable', color: 'primary', }, VTextarea: { variant: 'outlined', density: 'comfortable', color: 'primary', }, VSelect: { variant: 'outlined', density: 'comfortable', }, VChip: { rounded: 'pill', size: 'small', }, VDataTable: { density: 'comfortable', }, VDialog: { scrim: 'rgba(1, 32, 25, 0.32)', }, }, });