@dskripchenko/laravel-admin 1.1.20 → 1.1.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../resources/ts/stores/registry.ts","../resources/ts/stores/theme.ts","../resources/ts/components/shell/widgets/ThemeToggle.vue","../resources/ts/stores/locale.ts","../resources/ts/components/shell/widgets/LocaleSwitcher.vue","../resources/ts/stores/notifications.ts","../resources/ts/components/shell/widgets/NotificationBell.vue","../resources/ts/api/errors.ts","../resources/ts/stores/auth.ts","../resources/ts/components/shell/widgets/UserMenu.vue","../resources/ts/components/shell/AdminTopBar.vue","../resources/ts/stores/menu.ts","../resources/ts/components/shell/AdminSidebar.vue","../resources/ts/components/shell/AdminShell.vue","../resources/ts/stores/navigation.ts","../resources/ts/components/AdminLoadingBar.vue","../resources/ts/components/AdminApp.vue","../resources/ts/stores/manifest.ts","../resources/ts/components/HomePage.vue","../resources/ts/components/ForbiddenPage.vue","../resources/ts/components/NotFoundPage.vue","../resources/ts/components/SettingsPage.vue","../resources/ts/components/UnknownScreenPage.vue","../resources/ts/components/auth/LoginForm.vue","../resources/ts/components/auth/TwoFactorForm.vue","../resources/ts/components/auth/LoginPage.vue","../resources/ts/stores/resourceIndex.ts","../resources/ts/components/resource/cellFormat.ts","../resources/ts/components/resource/ResourceIndexPage.vue","../resources/ts/stores/resourceForm.ts","../resources/ts/components/createComponentRegistry.ts","../resources/ts/components/render/registry.ts","../resources/ts/components/fields/UnknownField.vue","../resources/ts/components/render/FieldRenderer.vue","../resources/ts/components/render/LayoutRenderer.vue","../resources/ts/components/resource/ResourceFormPage.vue","../resources/ts/components/infolist/registry.ts","../resources/ts/components/infolist/UnknownEntry.vue","../resources/ts/components/infolist/InfolistRenderer.vue","../resources/ts/components/infolist/recordContext.ts","../resources/ts/components/resource/ResourceViewPage.vue","../resources/ts/components/profile/ProfilePage.vue","../resources/ts/components/dashboard/registry.ts","../resources/ts/components/dashboard/UnknownWidget.vue","../resources/ts/components/dashboard/WidgetRenderer.vue","../resources/ts/components/dashboard/DashboardPage.vue","../resources/ts/components/dashboard/StatWidget.vue","../resources/ts/components/dashboard/BarChartWidget.vue","../resources/ts/components/dashboard/DonutChartWidget.vue","../resources/ts/components/dashboard/RecentTableWidget.vue","../resources/ts/components/dashboard/HeatmapWidget.vue","../resources/ts/components/dashboard/GaugeWidget.vue","../resources/ts/components/dashboard/MarkdownWidget.vue","../resources/ts/components/dashboard/builtin.ts","../resources/ts/api/envelope.ts","../resources/ts/api/client.ts","../resources/ts/router/builder.ts","../resources/ts/router/guards.ts","../resources/ts/router/index.ts","../resources/ts/components/fields/TextField.vue","../resources/ts/components/fields/TextAreaField.vue","../resources/ts/components/fields/NumberField.vue","../resources/ts/components/fields/SelectField.vue","../resources/ts/components/fields/CheckboxField.vue","../resources/ts/components/fields/DateField.vue","../resources/ts/components/layouts/RowsLayout.vue","../resources/ts/components/layouts/ColumnsLayout.vue","../resources/ts/components/layouts/SectionLayout.vue","../resources/ts/components/layouts/TabsLayout.vue","../resources/ts/components/render/builtin.ts","../resources/ts/components/infolist/TextEntry.vue","../resources/ts/components/infolist/BadgeEntry.vue","../resources/ts/components/infolist/IconEntry.vue","../resources/ts/components/infolist/KeyValueEntry.vue","../resources/ts/components/infolist/builtin.ts","../resources/ts/createAdminApp.ts","../resources/ts/api/bootstrap.ts","../resources/ts/components/notifications/NotificationsDrawer.vue","../resources/ts/components/import/ImportWizardPage.vue","../resources/ts/components/gallery/FieldGalleryPage.vue"],"sourcesContent":["/**\n * Глобальный registry AdminClient'а для Pinia stores.\n *\n * Stores не получают client через параметры — это сильно усложняет API\n * (`useAuthStore(client)` каждый раз). Вместо этого client регистрируется\n * один раз при bootstrap'е приложения через `setAdminClient()`, и stores\n * читают его через `getAdminClient()`.\n *\n * Это singleton-pattern — допустим в случае admin-SPA, потому что\n * client всегда один на весь жизненный цикл.\n */\n\nimport type { AdminClient } from '../api/client'\n\nlet _client: AdminClient | null = null\n\nexport function setAdminClient(client: AdminClient): void {\n _client = client\n}\n\nexport function getAdminClient(): AdminClient {\n if (_client === null) {\n throw new Error(\n '[admin] AdminClient is not registered. Call setAdminClient(...) before using stores.',\n )\n }\n return _client\n}\n\nexport function clearAdminClient(): void {\n _client = null\n}\n\nexport function hasAdminClient(): boolean {\n return _client !== null\n}\n","/**\n * Theme store: текущая тема + список доступных + persist через API.\n *\n * Side effect: применяет `<html data-theme=\"...\">` при изменении.\n * SPA рассчитывает на это для CSS-vars overrides.\n */\n\nimport { defineStore } from 'pinia'\nimport { computed, ref } from 'vue'\nimport { getAdminClient } from './registry'\nimport type { AdminBootstrap } from '../types/bootstrap'\n\nexport const useThemeStore = defineStore('admin-theme', () => {\n const current = ref<string>('light')\n const available = ref<string[]>(['light', 'dark'])\n\n const isDark = computed(() => current.value === 'dark')\n\n function hydrate(bootstrap: AdminBootstrap): void {\n current.value = bootstrap.theme\n available.value = bootstrap.availableThemes\n applyHtmlAttr(bootstrap.theme)\n }\n\n /**\n * Локальное переключение без round-trip'а. Используется когда нужно\n * мгновенно применить тему до получения ответа от сервера.\n */\n function applyLocal(theme: string): void {\n if (!available.value.includes(theme)) {\n throw new Error(`Theme \"${theme}\" is not available`)\n }\n current.value = theme\n applyHtmlAttr(theme)\n }\n\n /**\n * POST /system/setTheme — persist в user.theme + cookie.\n * Применяет тему к DOM немедленно (optimistic update).\n */\n async function setTheme(theme: string): Promise<void> {\n if (!available.value.includes(theme)) {\n throw new Error(`Theme \"${theme}\" is not available`)\n }\n\n const previous = current.value\n applyLocal(theme)\n\n try {\n const client = getAdminClient()\n await client.post('/system/setTheme', { theme })\n } catch (err) {\n // Откатываем optimistic update.\n applyLocal(previous)\n throw err\n }\n }\n\n function applyHtmlAttr(theme: string): void {\n if (typeof document !== 'undefined' && document.documentElement) {\n document.documentElement.setAttribute('data-theme', theme)\n }\n }\n\n return {\n current,\n available,\n isDark,\n hydrate,\n applyLocal,\n setTheme,\n }\n})\n","<script setup lang=\"ts\">\n/**\n * Toggle между light/dark поверх @dskripchenko/ui. Использует topbar\n * icon-button-стиль (.admin-topbar__icon-btn) для визуальной согласованности\n * с остальными widget'ами в баре.\n */\nimport { computed } from 'vue'\nimport { useThemeStore } from '../../../stores/theme'\n\nconst theme = useThemeStore()\n\nconst isDark = computed(() => theme.current === 'dark')\nconst iconName = computed(() => (isDark.value ? 'sun' : 'moon'))\nconst ariaLabel = computed(() =>\n isDark.value ? 'Переключить на светлую тему' : 'Переключить на тёмную тему',\n)\n\nasync function toggle(): Promise<void> {\n const next = isDark.value ? 'light' : 'dark'\n await theme.setTheme(next)\n}\n</script>\n\n<template>\n <button\n type=\"button\"\n class=\"admin-topbar__icon-btn\"\n :aria-label=\"ariaLabel\"\n :aria-pressed=\"isDark\"\n @click=\"toggle\"\n >\n <span class=\"admin-topbar__icon\" :data-icon=\"iconName\" />\n </button>\n</template>\n","/**\n * Locale store: текущая локаль + persist + sync с AdminClient.\n *\n * Side effects при смене:\n * - `<html lang=\"...\">` обновляется\n * - AdminClient.setLocale() — все следующие запросы получат правильный\n * X-Admin-Locale header\n * - POST /system/setLocale → persist в user.locale + cookie\n */\n\nimport { defineStore } from 'pinia'\nimport { ref } from 'vue'\nimport { getAdminClient } from './registry'\nimport type { AdminBootstrap } from '../types/bootstrap'\n\nexport const useLocaleStore = defineStore('admin-locale', () => {\n const current = ref<string>('ru')\n const available = ref<string[]>(['ru', 'en'])\n\n function hydrate(bootstrap: AdminBootstrap): void {\n current.value = bootstrap.locale\n available.value = bootstrap.availableLocales\n applySideEffects(bootstrap.locale)\n }\n\n function applyLocal(locale: string): void {\n if (!available.value.includes(locale)) {\n throw new Error(`Locale \"${locale}\" is not available`)\n }\n current.value = locale\n applySideEffects(locale)\n }\n\n async function setLocale(locale: string): Promise<void> {\n if (!available.value.includes(locale)) {\n throw new Error(`Locale \"${locale}\" is not available`)\n }\n\n const previous = current.value\n applyLocal(locale)\n\n try {\n const client = getAdminClient()\n await client.post('/system/setLocale', { locale })\n } catch (err) {\n applyLocal(previous)\n throw err\n }\n }\n\n function applySideEffects(locale: string): void {\n if (typeof document !== 'undefined' && document.documentElement) {\n document.documentElement.setAttribute('lang', locale)\n }\n // Try-catch потому что в test-окружении registry может быть пуст.\n try {\n getAdminClient().setLocale(locale)\n } catch {\n // ignore — клиент ещё не зарегистрирован\n }\n }\n\n return {\n current,\n available,\n hydrate,\n applyLocal,\n setLocale,\n }\n})\n","<script setup lang=\"ts\">\n/**\n * Переключение локали через UidMenu. В topbar показываем компактно\n * (icon + uppercase-код), под ним выпадает список доступных локалей.\n */\nimport { UidMenu, UidMenuItem } from '@dskripchenko/ui'\nimport { useLocaleStore } from '../../../stores/locale'\n\nconst locale = useLocaleStore()\n\nasync function pick(loc: string): Promise<void> {\n if (loc === locale.current) return\n await locale.setLocale(loc)\n}\n</script>\n\n<template>\n <UidMenu>\n <template #trigger>\n <button\n type=\"button\"\n class=\"admin-topbar__icon-btn\"\n style=\"width: auto; padding: 0 8px; gap: 4px; font-size: 12px;\"\n aria-label=\"Сменить локаль\"\n >\n <span class=\"admin-topbar__icon\" data-icon=\"globe\" />\n <span>{{ (locale.current ?? '').toUpperCase() }}</span>\n </button>\n </template>\n\n <UidMenuItem\n v-for=\"loc in locale.available\"\n :key=\"loc\"\n @click=\"pick(loc)\"\n >\n {{ loc.toUpperCase() }}\n </UidMenuItem>\n </UidMenu>\n</template>\n","/**\n * Notifications store: список + unread count + read/delete actions.\n *\n * Bell-badge polling реализуется на уровне UI через setInterval +\n * вызов loadUnread() — store сам не polling'ит, чтобы не дублировать\n * SetInterval'ы между tab'ами.\n */\n\nimport { defineStore } from 'pinia'\nimport { computed, ref } from 'vue'\nimport { getAdminClient } from './registry'\nimport type { AdminBootstrap } from '../types/bootstrap'\n\nexport interface NotificationItem {\n id: string\n type: string\n data: Record<string, unknown>\n read_at: string | null\n created_at: string | null\n}\n\nexport type NotificationFilter = 'all' | 'unread' | 'read'\n\nexport const useNotificationsStore = defineStore('admin-notifications', () => {\n const items = ref<NotificationItem[]>([])\n const unreadCount = ref(0)\n const loading = ref(false)\n const lastFilter = ref<NotificationFilter>('all')\n const meta = ref<{ page: number; per_page: number; total: number; last_page: number } | null>(null)\n\n const hasUnread = computed(() => unreadCount.value > 0)\n\n function hydrate(bootstrap: AdminBootstrap): void {\n unreadCount.value = bootstrap.unread_notifications_count\n }\n\n async function load(filter: NotificationFilter = 'all', page = 1): Promise<void> {\n loading.value = true\n try {\n const client = getAdminClient()\n const result = await client.get<{\n data: NotificationItem[]\n meta: { page: number; per_page: number; total: number; last_page: number; unread_count: number }\n }>(`/notifications/list?type=${filter}&page=${page}`)\n items.value = result.data\n unreadCount.value = result.meta.unread_count\n meta.value = {\n page: result.meta.page,\n per_page: result.meta.per_page,\n total: result.meta.total,\n last_page: result.meta.last_page,\n }\n lastFilter.value = filter\n } finally {\n loading.value = false\n }\n }\n\n /**\n * Лёгкий polling-endpoint — только count + последние 20.\n * Для bell-badge.\n */\n async function loadUnread(): Promise<void> {\n const client = getAdminClient()\n const result = await client.get<{ count: number; data: NotificationItem[] }>(\n '/notifications/unread',\n )\n unreadCount.value = result.count\n // Не подменяем items если в данный момент open'нут другой filter.\n if (lastFilter.value === 'unread') {\n items.value = result.data\n }\n }\n\n async function markAsRead(id: string): Promise<void> {\n const client = getAdminClient()\n await client.post('/notifications/markAsRead', { id })\n // Optimistic update в локальном state.\n const item = items.value.find((n) => n.id === id)\n if (item && item.read_at === null) {\n item.read_at = new Date().toISOString()\n unreadCount.value = Math.max(0, unreadCount.value - 1)\n }\n }\n\n async function markAllAsRead(): Promise<void> {\n const client = getAdminClient()\n await client.post('/notifications/markAllAsRead')\n const now = new Date().toISOString()\n for (const item of items.value) {\n if (item.read_at === null) item.read_at = now\n }\n unreadCount.value = 0\n }\n\n async function destroy(id: string): Promise<void> {\n const client = getAdminClient()\n await client.post('/notifications/destroy', { id })\n const index = items.value.findIndex((n) => n.id === id)\n if (index !== -1) {\n const wasUnread = items.value[index].read_at === null\n items.value.splice(index, 1)\n if (wasUnread) {\n unreadCount.value = Math.max(0, unreadCount.value - 1)\n }\n }\n }\n\n return {\n items,\n unreadCount,\n loading,\n meta,\n lastFilter,\n hasUnread,\n hydrate,\n load,\n loadUnread,\n markAsRead,\n markAllAsRead,\n destroy,\n }\n})\n","<script setup lang=\"ts\">\n/**\n * Bell с unread-badge. По эталону handoff'а — badge `.admin-topbar__bell-badge`\n * (округлая красная пилюля 14×14 + tabular-nums + max '99+').\n */\nimport { computed } from 'vue'\nimport { RouterLink } from 'vue-router'\nimport { useNotificationsStore } from '../../../stores/notifications'\n\nconst notifications = useNotificationsStore()\n\nconst display = computed(() => {\n const n = notifications.unreadCount\n if (n <= 0) return null\n return n > 99 ? '99+' : String(n)\n})\n</script>\n\n<template>\n <RouterLink\n to=\"/notifications\"\n class=\"admin-topbar__icon-btn\"\n aria-label=\"Уведомления\"\n >\n <span class=\"admin-topbar__icon\" data-icon=\"bell\" />\n <span\n v-if=\"display !== null\"\n class=\"admin-topbar__bell-badge\"\n :title=\"`Непрочитанных: ${notifications.unreadCount}`\"\n >\n {{ display }}\n </span>\n </RouterLink>\n</template>\n","/**\n * Кастомные Error-классы для admin API.\n *\n * Все API-ошибки бросаются как ApiError или его подклассы. Потребители\n * могут делать `instanceof ValidationError` для специфичной обработки.\n */\n\nimport type { ErrorEnvelope } from './envelope'\n\nexport class ApiError extends Error {\n public readonly status: number\n public readonly errorKey: string\n public readonly payload: ErrorEnvelope['payload']\n\n constructor(status: number, payload: ErrorEnvelope['payload']) {\n super(payload.message ?? `API error ${status}`)\n this.name = 'ApiError'\n this.status = status\n this.errorKey = payload.errorKey ?? 'unknown'\n this.payload = payload\n }\n}\n\nexport class UnauthenticatedError extends ApiError {\n constructor(payload: ErrorEnvelope['payload']) {\n super(401, payload)\n this.name = 'UnauthenticatedError'\n }\n}\n\nexport class ForbiddenError extends ApiError {\n constructor(payload: ErrorEnvelope['payload']) {\n super(403, payload)\n this.name = 'ForbiddenError'\n }\n}\n\nexport class NotFoundError extends ApiError {\n constructor(payload: ErrorEnvelope['payload']) {\n super(404, payload)\n this.name = 'NotFoundError'\n }\n}\n\nexport class ValidationError extends ApiError {\n /** Field-keyed map of error messages. */\n public readonly fields: Record<string, string[]>\n\n constructor(payload: ErrorEnvelope['payload']) {\n super(422, payload)\n this.name = 'ValidationError'\n this.fields = payload.messages ?? {}\n }\n\n /** Первое сообщение из field'а — удобно для toast. */\n firstFieldMessage(): string | null {\n for (const messages of Object.values(this.fields)) {\n if (messages.length > 0) {\n return messages[0]\n }\n }\n return null\n }\n}\n\n/**\n * Network-failure (не дошли до сервера). Отдельный класс чтобы UI мог\n * показать «Нет соединения» вместо «500 Server Error».\n */\nexport class NetworkError extends Error {\n constructor(message = 'Network error') {\n super(message)\n this.name = 'NetworkError'\n }\n}\n\n/**\n * Превращает HTTP-status + envelope в правильный подкласс ApiError.\n */\nexport function toApiError(status: number, payload: ErrorEnvelope['payload']): ApiError {\n switch (status) {\n case 401: return new UnauthenticatedError(payload)\n case 403: return new ForbiddenError(payload)\n case 404: return new NotFoundError(payload)\n case 422: return new ValidationError(payload)\n default: return new ApiError(status, payload)\n }\n}\n","/**\n * Auth store: текущий user, permissions, login/logout/2FA flow.\n *\n * Wildcard в permissions:\n * - `*` — полный доступ ко всему.\n * - `admin.users.*` — доступ ко всем admin.users.{view,create,update,delete}.\n *\n * 2FA flow:\n * 1. login() с верными creds + 2FA включена → success: false +\n * errorKey: 'two_factor_required' + challenge_token. State переходит в\n * `pendingChallenge`.\n * 2. UI показывает 2FA-форму. twoFactorChallenge(code) или\n * twoFactorRecovery(recovery_code) → success login flow.\n */\n\nimport { defineStore } from 'pinia'\nimport { computed, ref } from 'vue'\nimport { getAdminClient } from './registry'\nimport { ApiError } from '../api/errors'\nimport type { AdminUser, AdminBootstrap } from '../types/bootstrap'\n\nexport interface PendingChallenge {\n challengeToken: string\n remember: boolean\n}\n\nexport interface LoginPayload {\n email: string\n password: string\n remember?: boolean\n}\n\nexport const useAuthStore = defineStore('admin-auth', () => {\n const user = ref<AdminUser | null>(null)\n const permissions = ref<string[]>([])\n const pendingChallenge = ref<PendingChallenge | null>(null)\n\n const isAuthenticated = computed(() => user.value !== null)\n const isChallengePending = computed(() => pendingChallenge.value !== null)\n\n /** Заполнить store из bootstrap-payload'а (стартовая инициализация). */\n function hydrate(bootstrap: AdminBootstrap): void {\n user.value = bootstrap.user\n permissions.value = bootstrap.permissions\n }\n\n /**\n * Проверить permission. Поддерживает wildcards:\n * - `*` — даёт доступ всем.\n * - `admin.users.*` — даёт доступ ко всем admin.users.X.\n */\n function hasPermission(key: string): boolean {\n if (permissions.value.includes('*')) return true\n if (permissions.value.includes(key)) return true\n return permissions.value.some((permission) => {\n if (!permission.endsWith('.*')) return false\n const prefix = permission.slice(0, -1) // 'admin.users.'\n return key.startsWith(prefix)\n })\n }\n\n function hasAnyPermission(keys: string[]): boolean {\n return keys.some(hasPermission)\n }\n\n function hasAllPermissions(keys: string[]): boolean {\n return keys.every(hasPermission)\n }\n\n /**\n * POST /auth/login. При 2FA-required envelope success:false +\n * errorKey:'two_factor_required' конвертируется interceptor'ом в ApiError;\n * мы ловим его, переходим в challenge-mode и возвращаем 'two_factor_required'.\n * На полный success — заполняем user и возвращаем 'authenticated'.\n * На реальную ошибку — throw'ит ApiError выше.\n */\n async function login(payload: LoginPayload): Promise<'authenticated' | 'two_factor_required'> {\n const client = getAdminClient()\n try {\n const result = await client.post<{ user?: AdminUser; permissions?: string[] }>(\n '/auth/login',\n payload,\n )\n if (result?.user) {\n user.value = result.user\n }\n if (Array.isArray(result?.permissions)) {\n permissions.value = result.permissions\n }\n pendingChallenge.value = null\n return 'authenticated'\n } catch (err) {\n if (err instanceof ApiError && err.errorKey === 'two_factor_required') {\n const challengeToken = (err.payload as Record<string, unknown>).challenge_token\n pendingChallenge.value = {\n challengeToken: typeof challengeToken === 'string' ? challengeToken : '',\n remember: payload.remember ?? false,\n }\n return 'two_factor_required'\n }\n throw err\n }\n }\n\n /** POST /auth/twoFactorChallenge. Завершает login. */\n async function twoFactorChallenge(code: string): Promise<void> {\n if (pendingChallenge.value === null) {\n throw new Error('No pending 2FA challenge')\n }\n const client = getAdminClient()\n const result = await client.post<{ user: AdminUser }>('/auth/twoFactorChallenge', {\n challenge_token: pendingChallenge.value.challengeToken,\n code,\n })\n user.value = result.user\n pendingChallenge.value = null\n }\n\n /** POST /auth/twoFactorRecovery. Использует recovery-код вместо TOTP. */\n async function twoFactorRecovery(recoveryCode: string): Promise<{ remaining: number }> {\n if (pendingChallenge.value === null) {\n throw new Error('No pending 2FA challenge')\n }\n const client = getAdminClient()\n const result = await client.post<{\n user: AdminUser\n recovery_codes_remaining: number\n }>('/auth/twoFactorRecovery', {\n challenge_token: pendingChallenge.value.challengeToken,\n recovery_code: recoveryCode,\n })\n user.value = result.user\n pendingChallenge.value = null\n return { remaining: result.recovery_codes_remaining }\n }\n\n /** Сбросить pending challenge — для возврата на login-форму. */\n function cancelChallenge(): void {\n pendingChallenge.value = null\n }\n\n /** POST /auth/logout. Чистит store. */\n async function logout(): Promise<void> {\n const client = getAdminClient()\n try {\n await client.post('/auth/logout')\n } finally {\n user.value = null\n permissions.value = []\n pendingChallenge.value = null\n }\n }\n\n return {\n // state\n user,\n permissions,\n pendingChallenge,\n // getters\n isAuthenticated,\n isChallengePending,\n // actions\n hydrate,\n hasPermission,\n hasAnyPermission,\n hasAllPermissions,\n login,\n twoFactorChallenge,\n twoFactorRecovery,\n cancelChallenge,\n logout,\n }\n})\n","<script setup lang=\"ts\">\n/**\n * UserMenu с avatar + dropdown через UidMenu из @dskripchenko/ui.\n * В trigger'е — UidAvatar (с инициалами либо src, размер sm).\n */\nimport { UidAvatar, UidMenu, UidMenuItem, UidMenuSeparator } from '@dskripchenko/ui'\nimport { useRouter } from 'vue-router'\nimport { useAuthStore } from '../../../stores/auth'\n\nconst auth = useAuthStore()\nconst router = useRouter()\n\nasync function logout(): Promise<void> {\n try {\n await auth.logout()\n } finally {\n await router.push({ name: 'admin.login' })\n }\n}\n\nfunction goProfile(): void {\n void router.push({ name: 'admin.profile' })\n}\n</script>\n\n<template>\n <UidMenu>\n <template #trigger>\n <button\n type=\"button\"\n class=\"admin-topbar__icon-btn admin-user-menu__trigger\"\n aria-label=\"Меню пользователя\"\n aria-haspopup=\"menu\"\n style=\"width: auto; padding: 0 4px; gap: 8px;\"\n >\n <UidAvatar\n :src=\"auth.user?.avatar ?? undefined\"\n :name=\"auth.user?.name ?? '?'\"\n :alt=\"auth.user?.name ?? 'User'\"\n size=\"sm\"\n />\n </button>\n </template>\n\n <UidMenuItem @click=\"goProfile\">Профиль</UidMenuItem>\n <UidMenuSeparator />\n <UidMenuItem variant=\"danger\" @click=\"logout\">Выйти</UidMenuItem>\n </UidMenu>\n</template>\n","<script setup lang=\"ts\">\n/**\n * Admin top bar поверх UID-токенов. Структура из docs/design_handoff_laravel_admin/\n * screens-shell.jsx (Topbar): collapse-toggle / breadcrumbs / spacer /\n * search-pill / bell / theme / locale / avatar.\n *\n * Slots:\n * - actions — host может вставить дополнительные actions перед widget'ами\n * - search — кастомизация ⌘K command-palette pill (по умолчанию — статичный\n * placeholder; host сверху поднимет UidCommand или свой)\n * - breadcrumbs — переопределить хлебные крошки\n */\nimport { computed } from 'vue'\nimport ThemeToggle from './widgets/ThemeToggle.vue'\nimport LocaleSwitcher from './widgets/LocaleSwitcher.vue'\nimport NotificationBell from './widgets/NotificationBell.vue'\nimport UserMenu from './widgets/UserMenu.vue'\n\ninterface Crumb {\n label: string\n to?: string | Record<string, unknown> | null\n}\n\ninterface Props {\n /** Хлебные крошки. Последний элемент — текущая страница (без to). */\n breadcrumbs?: Crumb[]\n /** Показывать кнопку collapse сайдбара (только в shell-layout'е). */\n showCollapseToggle?: boolean\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n breadcrumbs: () => [],\n showCollapseToggle: true,\n})\n\nconst emit = defineEmits<{\n 'toggle-sidebar': []\n}>()\n\nconst lastIdx = computed(() => props.breadcrumbs.length - 1)\n</script>\n\n<template>\n <header class=\"admin-topbar\">\n <button\n v-if=\"showCollapseToggle\"\n type=\"button\"\n class=\"admin-topbar__icon-btn\"\n aria-label=\"Свернуть меню\"\n @click=\"emit('toggle-sidebar')\"\n >\n <span class=\"admin-topbar__icon\" data-icon=\"panel-left\" />\n </button>\n\n <div class=\"admin-topbar__breadcrumbs\">\n <slot name=\"breadcrumbs\">\n <template v-for=\"(crumb, idx) in breadcrumbs\" :key=\"idx\">\n <span v-if=\"idx > 0\" class=\"sep\">›</span>\n <component\n :is=\"crumb.to ? 'a' : 'span'\"\n :href=\"typeof crumb.to === 'string' ? crumb.to : undefined\"\n :class=\"idx === lastIdx ? 'cur' : ''\"\n >\n {{ crumb.label }}\n </component>\n </template>\n </slot>\n </div>\n\n <div class=\"admin-topbar__spacer\" />\n\n <slot name=\"search\">\n <div class=\"admin-topbar__search\" role=\"button\" tabindex=\"0\">\n <span class=\"admin-topbar__icon\" data-icon=\"search\" />\n <span>Поиск везде…</span>\n <kbd>⌘K</kbd>\n </div>\n </slot>\n\n <slot name=\"actions\" />\n <NotificationBell />\n <ThemeToggle />\n <LocaleSwitcher />\n <UserMenu />\n </header>\n</template>\n","/**\n * Menu store: дерево пунктов сайдбара.\n *\n * Источник — /system/menu (backend строит из ResourceRegistry/ScreenRegistry/\n * Settings + plugin-вкладов). Фронт фильтрует по permission'ам залогиненного\n * пользователя через auth-store.\n */\n\nimport { defineStore } from 'pinia'\nimport { computed, ref } from 'vue'\nimport { getAdminClient } from './registry'\nimport { useAuthStore } from './auth'\n\nexport interface MenuItem {\n /** Уникальный идентификатор. */\n key: string\n /** Текст пункта. */\n label: string\n /** Имя icon'а (опционально — host-проект сам резолвит icon-set). */\n icon?: string | null\n /** URL (внутренний router-target) либо null для группы. */\n url?: string | null\n /** Имя router-route (если задано — приоритет над url). */\n routeName?: string | null\n /** Бейдж справа (число unread, ярлык вроде \"new\"). */\n badge?: string | number | null\n /** Группа (header в sidebar). */\n group?: string | null\n /** Сортировочный вес. */\n order?: number\n /** Permission-keys; если заданы — пункт виден только при hasAnyPermission. */\n permissions?: string[]\n /** Вложенные пункты. */\n children?: MenuItem[]\n}\n\nexport interface MenuGroup {\n /** Заголовок группы (null = пункты без группы). */\n group: string | null\n items: MenuItem[]\n}\n\ninterface MenuResponse {\n items: MenuItem[]\n}\n\nexport const useMenuStore = defineStore('admin-menu', () => {\n const items = ref<MenuItem[]>([])\n const loading = ref(false)\n const error = ref<Error | null>(null)\n const isLoaded = ref(false)\n\n /**\n * Видимые пункты — отфильтрованные по permission'ам через auth-store.\n * Поддерживает wildcards (`*`, `admin.users.*`) через auth.hasAnyPermission.\n * Items без permissions считаются открытыми всем.\n */\n const visibleItems = computed<MenuItem[]>(() => {\n const auth = useAuthStore()\n const filter = (it: MenuItem): MenuItem | null => {\n if (Array.isArray(it.permissions) && it.permissions.length > 0) {\n if (!auth.hasAnyPermission(it.permissions)) return null\n }\n const filteredChildren = (it.children ?? [])\n .map(filter)\n .filter((c): c is MenuItem => c !== null)\n return { ...it, children: filteredChildren }\n }\n return items.value.map(filter).filter((i): i is MenuItem => i !== null)\n })\n\n /**\n * Группированный список — для рендера в sidebar по секциям.\n * Сортировка: order по возрастанию, затем label по алфавиту.\n */\n const groupedItems = computed<MenuGroup[]>(() => {\n const groups = new Map<string | null, MenuItem[]>()\n for (const item of visibleItems.value) {\n const groupKey = item.group ?? null\n if (!groups.has(groupKey)) groups.set(groupKey, [])\n groups.get(groupKey)!.push(item)\n }\n const result: MenuGroup[] = []\n for (const [group, list] of groups) {\n list.sort((a, b) => {\n const orderDiff = (a.order ?? 0) - (b.order ?? 0)\n if (orderDiff !== 0) return orderDiff\n return a.label.localeCompare(b.label)\n })\n result.push({ group, items: list })\n }\n return result\n })\n\n /** Загрузить меню с backend'а. Кэшируется до reset()/force=true. */\n async function load(force = false): Promise<MenuItem[]> {\n if (isLoaded.value && !force) return items.value\n loading.value = true\n error.value = null\n try {\n const client = getAdminClient()\n const response = await client.get<MenuResponse>('/system/menu')\n items.value = Array.isArray(response.items) ? response.items : []\n isLoaded.value = true\n return items.value\n } catch (err) {\n error.value = err instanceof Error ? err : new Error(String(err))\n throw err\n } finally {\n loading.value = false\n }\n }\n\n /** Установить items напрямую (например, host-проект построил из manifest'а). */\n function setItems(next: MenuItem[]): void {\n items.value = next\n isLoaded.value = true\n error.value = null\n }\n\n function reset(): void {\n items.value = []\n isLoaded.value = false\n error.value = null\n loading.value = false\n }\n\n return {\n items,\n loading,\n error,\n isLoaded,\n visibleItems,\n groupedItems,\n load,\n setItems,\n reset,\n }\n})\n","<script setup lang=\"ts\">\n/**\n * Sidebar admin-каркаса поверх UidSidebar/UidSidebarGroup/UidSidebarItem.\n *\n * Источник данных — useMenuStore (groupedItems, отфильтрованные по permission'ам\n * через auth.hasAnyPermission). UidSidebarItem поддерживает вложенный icon-slot\n * + active + badge — маппим прямо из MenuItem.\n *\n * Brand-row сверху + опциональный tenant-block + footer с версией/docs —\n * по эталону docs/design_handoff_laravel_admin/screens-shell.jsx (Sidebar).\n */\nimport { computed, h, type Component } from 'vue'\nimport { useRoute } from 'vue-router'\nimport { UidSidebar, UidSidebarGroup, UidSidebarItem } from '@dskripchenko/ui'\nimport { useMenuStore, type MenuItem } from '../../stores/menu'\n\ninterface Props {\n collapsed?: boolean\n /** Заголовок бренда. */\n brandName?: string\n /** Logo-mark (буква/инициалы) — отображается вместо логотипа. */\n brandMark?: string\n /** Тенант / workspace — опционально показывается под брендом. */\n tenant?: { label: string; name: string } | null\n /** Версия + ссылка на docs в footer'е. */\n version?: string | null\n docsUrl?: string | null\n}\n\nwithDefaults(defineProps<Props>(), {\n collapsed: false,\n brandName: 'Laravel Admin',\n brandMark: 'L',\n tenant: null,\n version: null,\n docsUrl: null,\n})\n\nconst menu = useMenuStore()\nconst route = useRoute()\n\nconst groups = computed(() => menu.groupedItems)\n\nfunction isActive(item: MenuItem): boolean {\n if (item.routeName && route.name === item.routeName) return true\n if (item.url && route.path === item.url) return true\n return false\n}\n\n/**\n * UidSidebarItem ожидает icon-slot. MenuItem.icon — строка (имя lucide-икoнки),\n * host-проект может зарегистрировать свой icon-resolver. Здесь возвращаем\n * простой <span data-icon> placeholder — host'у достаточно css-rule по\n * `[data-icon='users']` чтобы подставить SVG.\n */\nfunction iconSlot(name?: string | null): Component | undefined {\n if (!name) return undefined\n // Functional component возвращающий <span data-icon> placeholder.\n // Host-проект может перебить через css-rule по `[data-icon='users']`.\n return () => h('span', { class: 'admin-sidebar__icon', 'data-icon': name })\n}\n\n/** UidSidebarItem.to принимает string | object; routeName маппим через route-object. */\nfunction itemTarget(item: MenuItem): string | Record<string, unknown> | undefined {\n // URL приоритетнее routeName — vue-router бросает \"no match for {name}\" если\n // route'а ещё нет (dynamic-routes добавляются async после manifest.load).\n // URL-based navigation матчится в любой момент через path.\n if (item.url) return item.url\n if (item.routeName) return { name: item.routeName }\n return undefined\n}\n</script>\n\n<template>\n <UidSidebar :collapsed=\"collapsed\">\n <template #header>\n <div class=\"admin-sidebar-brand\">\n <div class=\"admin-sidebar-brand__mark\">{{ brandMark }}</div>\n <div v-if=\"!collapsed\" class=\"admin-sidebar-brand__name\">{{ brandName }}</div>\n </div>\n <div v-if=\"tenant && !collapsed\" class=\"admin-sidebar-tenant\">\n <span>{{ tenant.label }}</span>\n <b>{{ tenant.name }}</b>\n </div>\n </template>\n\n <template #nav>\n <UidSidebarGroup\n v-for=\"(grp, idx) in groups\"\n :key=\"`grp-${idx}`\"\n :title=\"grp.group ?? undefined\"\n >\n <UidSidebarItem\n v-for=\"item in grp.items\"\n :key=\"item.key\"\n :to=\"itemTarget(item)\"\n :active=\"isActive(item)\"\n :badge=\"item.badge ?? undefined\"\n >\n <template v-if=\"item.icon\" #icon>\n <component :is=\"iconSlot(item.icon)\" />\n </template>\n {{ item.label }}\n </UidSidebarItem>\n </UidSidebarGroup>\n </template>\n\n <template v-if=\"version || docsUrl\" #footer>\n <div class=\"admin-sidebar-foot\">\n <span v-if=\"version\" class=\"admin-sidebar-foot__text\">{{ version }}</span>\n <a v-if=\"docsUrl\" :href=\"docsUrl\" class=\"admin-sidebar-foot__text admin-sidebar-foot__link\">\n Docs\n </a>\n </div>\n </template>\n </UidSidebar>\n</template>\n\n<style>\n.admin-sidebar-brand {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 14px 16px;\n border-bottom: 1px solid var(--uid-border-subtle);\n}\n.admin-sidebar-brand__mark {\n width: 28px;\n height: 28px;\n border-radius: 7px;\n flex: none;\n background: var(--uid-text-primary);\n color: var(--uid-surface-raised);\n display: grid;\n place-items: center;\n font-family: var(--uid-font-family-display);\n font-weight: var(--uid-font-weight-bold);\n font-size: 14px;\n letter-spacing: -0.02em;\n}\n.admin-sidebar-brand__name {\n font-family: var(--uid-font-family-display);\n font-size: 14px;\n font-weight: var(--uid-font-weight-semibold);\n letter-spacing: -0.01em;\n white-space: nowrap;\n overflow: hidden;\n color: var(--uid-text-primary);\n}\n.admin-sidebar-tenant {\n margin: 8px;\n display: flex;\n align-items: center;\n gap: 8px;\n height: 32px;\n padding: 0 8px;\n border: 1px solid var(--uid-border-subtle);\n border-radius: var(--uid-radius-md);\n font-size: var(--uid-font-size-xs);\n color: var(--uid-text-secondary);\n background: var(--uid-surface-base);\n}\n.admin-sidebar-tenant b { color: var(--uid-text-primary); font-weight: 500; }\n.admin-sidebar-foot {\n padding: 10px 16px;\n border-top: 1px solid var(--uid-border-subtle);\n display: flex;\n align-items: center;\n justify-content: space-between;\n font-size: 11px;\n color: var(--uid-text-tertiary);\n}\n.admin-sidebar-foot__link { cursor: pointer; }\n.admin-sidebar-foot__link:hover { color: var(--uid-text-primary); }\n\n.admin-sidebar__icon {\n width: 16px;\n height: 16px;\n display: inline-block;\n flex: none;\n color: currentColor;\n}\n</style>\n","<script setup lang=\"ts\">\n/**\n * Корневой layout admin-панели поверх UidSidebarLayout из @dskripchenko/ui.\n *\n * Slots:\n * - sidebar — обычно AdminSidebar (default)\n * - header — AdminTopBar (default)\n * - default — main-area (host рендерит <RouterView/>)\n *\n * v-model — boolean флаг сворачивания сайдбара (240→56 px, transition в uid).\n *\n * Impersonation: prop `impersonation` показывает 32-px amber бейдж над shell'ом\n * с кнопкой выхода — стиль из docs/design_handoff_laravel_admin/app.css:159\n * (.imp-banner). На <html> ставим data-impersonating='true' чтобы корректно\n * сместить sticky-элементы вниз.\n */\nimport { onBeforeUnmount, watch } from 'vue'\nimport { UidSidebarLayout } from '@dskripchenko/ui'\nimport AdminTopBar from './AdminTopBar.vue'\nimport AdminSidebar from './AdminSidebar.vue'\n\ninterface ImpersonationData {\n /** Имя того, в кого вошли. */\n asName: string\n}\n\ninterface Props {\n /** Сворачивание сайдбара. */\n collapsed?: boolean\n /** Если задано — показывает amber-banner и сдвигает контент. */\n impersonation?: ImpersonationData | null\n}\nconst props = withDefaults(defineProps<Props>(), {\n collapsed: false,\n impersonation: null,\n})\n\nconst emit = defineEmits<{\n 'update:collapsed': [value: boolean]\n 'exit-impersonation': []\n}>()\n\nfunction onCollapseChange(value: boolean): void {\n emit('update:collapsed', value)\n}\n\nfunction exitImpersonation(): void {\n emit('exit-impersonation')\n}\n\n// Маркер на <html> — для shell-classes которые делают paddding-top + sticky-offset.\nconst HTML_ATTR = 'data-admin-impersonating'\n\nwatch(\n () => props.impersonation,\n (val) => {\n if (typeof document === 'undefined') return\n if (val !== null) document.documentElement.setAttribute(HTML_ATTR, 'true')\n else document.documentElement.removeAttribute(HTML_ATTR)\n },\n { immediate: true },\n)\n\nonBeforeUnmount(() => {\n if (typeof document !== 'undefined') {\n document.documentElement.removeAttribute(HTML_ATTR)\n }\n})\n</script>\n\n<template>\n <div class=\"admin-shell-root\">\n <div v-if=\"impersonation\" class=\"admin-impersonation-banner\" role=\"status\">\n <span>\n Вы вошли как <b>{{ impersonation.asName }}</b> · режим имперсонации\n </span>\n <button\n type=\"button\"\n class=\"admin-impersonation-banner__exit\"\n @click=\"exitImpersonation\"\n >\n Выйти из режима\n </button>\n </div>\n <UidSidebarLayout\n :model-value=\"collapsed\"\n @update:model-value=\"onCollapseChange\"\n >\n <template #sidebar>\n <slot name=\"sidebar\">\n <AdminSidebar :collapsed=\"collapsed\" />\n </slot>\n </template>\n <template #header>\n <slot name=\"topbar\">\n <AdminTopBar @toggle-sidebar=\"onCollapseChange(!collapsed)\" />\n </slot>\n </template>\n <slot />\n </UidSidebarLayout>\n </div>\n</template>\n\n<style>\n.admin-shell-root[data-admin-impersonating='true'] {\n /* Sidebar/topbar sticky уже учтут `--admin-page-pad` и offset через CSS-классы. */\n padding-top: 32px;\n}\n:root[data-admin-impersonating='true'] {\n scroll-padding-top: 32px;\n}\n</style>\n","/**\n * useNavigationStore — глобальный pending-counter для top-loading-bar.\n *\n * При router.beforeEach (старт навигации) — вызываем `start()`.\n * При router.afterEach + resource-page завершила data-fetch — вызываем `end()`.\n *\n * Counter (а не bool) защищает от race condition'ов: если несколько\n * параллельных fetch'ей, bar остаётся видимым пока хоть один pending.\n */\n\nimport { defineStore } from 'pinia'\nimport { computed, ref } from 'vue'\n\nexport const useNavigationStore = defineStore('admin-navigation', () => {\n const pending = ref<number>(0)\n const isLoading = computed<boolean>(() => pending.value > 0)\n\n function start(): void {\n pending.value += 1\n }\n\n function end(): void {\n if (pending.value > 0) pending.value -= 1\n }\n\n /** Сбросить counter (на случай зависшего pending в dev). */\n function reset(): void {\n pending.value = 0\n }\n\n return { pending, isLoading, start, end, reset }\n})\n","<script setup lang=\"ts\">\n/**\n * Top loading bar (как у YouTube/GitHub/Vercel).\n *\n * Реактивно отображает useNavigationStore.isLoading. Indeterminate-anim\n * (CSS keyframes) — slide bar слева направо в бесконечном цикле пока\n * pending > 0.\n *\n * Hide-delay 120ms: если pending быстро спадает к 0, bar успевает\n * мигнуть в полный размер вместо instant-cutoff.\n */\nimport { computed, ref, watch } from 'vue'\nimport { useNavigationStore } from '../stores/navigation'\n\nconst nav = useNavigationStore()\n\n// Soft-hide: bar остаётся 120ms после end() для плавности.\nconst visible = ref<boolean>(false)\nlet hideTimer: ReturnType<typeof setTimeout> | null = null\n\nwatch(\n () => nav.isLoading,\n (loading) => {\n if (loading) {\n if (hideTimer !== null) {\n clearTimeout(hideTimer)\n hideTimer = null\n }\n visible.value = true\n } else {\n hideTimer = setTimeout(() => {\n visible.value = false\n hideTimer = null\n }, 120)\n }\n },\n { immediate: true },\n)\n\nconst cls = computed(() => ({\n 'admin-loading-bar': true,\n 'admin-loading-bar--visible': visible.value,\n}))\n</script>\n\n<template>\n <div :class=\"cls\" role=\"progressbar\" aria-busy=\"true\" />\n</template>\n\n<style>\n.admin-loading-bar {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n height: 2px;\n z-index: var(--uid-z-toast, 9999);\n pointer-events: none;\n opacity: 0;\n transition: opacity 120ms ease-out;\n background: transparent;\n}\n\n.admin-loading-bar--visible {\n opacity: 1;\n}\n\n.admin-loading-bar--visible::before {\n content: '';\n position: absolute;\n inset: 0;\n background: var(--uid-accent, var(--uid-color-primary, #14b8a6));\n transform-origin: 0 50%;\n animation: admin-loading-bar-slide 1.4s cubic-bezier(0.4, 0, 0.2, 1) infinite;\n}\n\n@keyframes admin-loading-bar-slide {\n 0% {\n transform: translateX(-100%) scaleX(0.4);\n }\n 50% {\n transform: translateX(0%) scaleX(0.7);\n }\n 100% {\n transform: translateX(100%) scaleX(0.4);\n }\n}\n\n/* Reduced-motion: статичный bar 60% width. */\n@media (prefers-reduced-motion: reduce) {\n .admin-loading-bar--visible::before {\n animation: none;\n width: 60%;\n transform: none;\n }\n}\n</style>\n","<script setup lang=\"ts\">\n/**\n * Root компонент SPA admin'а — рендерит router-view, оборачивая его в\n * AdminShell layout (TopBar + Sidebar + content) для аутентифицированных\n * роутов. Auth-роуты (login, 403, 404) и роуты с meta.fullscreen рендерятся\n * без shell.\n *\n * Используется createAdminApp() как root-component. Host'ы редко\n * переопределяют — обычно достаточно настроить отдельные pages через опции.\n */\nimport { computed } from 'vue'\nimport { useRoute } from 'vue-router'\nimport AdminShell from './shell/AdminShell.vue'\nimport AdminLoadingBar from './AdminLoadingBar.vue'\n\nconst route = useRoute()\n\nconst useShell = computed<boolean>(() => {\n if (route.meta?.fullscreen === true) return false\n if (route.meta?.kind === 'auth') return false\n if (route.name === 'admin.notFound') return false\n return true\n})\n</script>\n\n<template>\n <!-- Top loading-bar: показывается пока nav/data не закончили (см. useNavigationStore). -->\n <AdminLoadingBar />\n\n <AdminShell v-if=\"useShell\">\n <div class=\"admin-page-host\">\n <router-view v-slot=\"{ Component }\">\n <Transition name=\"admin-page\">\n <component :is=\"Component\" />\n </Transition>\n </router-view>\n </div>\n </AdminShell>\n <router-view v-else v-slot=\"{ Component }\">\n <Transition name=\"admin-page\">\n <component :is=\"Component\" />\n </Transition>\n </router-view>\n</template>\n\n<style>\n/*\n * Page-host: relative контейнер. Старая страница leaving делается absolute\n * (overlay поверх новой), entering в нормальном flow с slide-from-right.\n *\n * Тайминги (по запросу):\n * - leaving fade-out: 140ms ease-out (быстро уходит).\n * - entering slide-from-right + fade-in: 320ms cubic-bezier easing,\n * с 60ms delay чтобы старая успела \"пропасть до того как новая\n * доберётся до позиции\".\n *\n * overflow:hidden на host — slide справа не вылезает за viewport.\n */\n.admin-page-host {\n position: relative;\n min-height: 200px;\n overflow: hidden;\n}\n\n/* Leaving page absolute — не двигает layout, остаётся на месте пока fade'ится. */\n.admin-page-leave-active {\n position: absolute;\n inset: 0;\n width: 100%;\n transition: opacity 140ms ease-out;\n}\n\n.admin-page-leave-to {\n opacity: 0;\n}\n\n/* Entering page: slide-in справа + fade-in. Delay 60ms — старая уже почти ушла. */\n.admin-page-enter-active {\n transition:\n opacity 320ms cubic-bezier(0.2, 0.8, 0.2, 1) 60ms,\n transform 320ms cubic-bezier(0.2, 0.8, 0.2, 1) 60ms;\n}\n\n.admin-page-enter-from {\n opacity: 0;\n transform: translateX(28px);\n}\n\n.admin-page-enter-to {\n opacity: 1;\n transform: translateX(0);\n}\n\n@media (prefers-reduced-motion: reduce) {\n .admin-page-enter-active,\n .admin-page-leave-active {\n transition: opacity 80ms ease-out;\n }\n .admin-page-enter-from {\n transform: none;\n }\n}\n</style>\n","/**\n * Manifest store: lazy-load JSON-манифеста админки + кеширование по version.\n *\n * Manifest содержит описание всех Resource'ов, Screen'ов, Settings'ов,\n * Plugin'ов. SPA загружает один раз на старте и переиспользует.\n *\n * ETag-based 304 Not Modified backend-side — фронт ничего особенного не\n * делает (axios + browser handle If-None-Match). Свежий version записывается\n * в lastVersion для cheap-сравнения.\n */\n\nimport { defineStore } from 'pinia'\nimport { computed, ref } from 'vue'\nimport { getAdminClient } from './registry'\n\n/**\n * Узел manifest'а с обязательным `type`. Совместим с LayoutNode/FieldNode/\n * InfolistNode — позволяет передавать массив прямо в renderer без cast'а.\n */\nexport interface ManifestNode extends Record<string, unknown> {\n type: string\n}\n\nexport interface ManifestResourceMeta {\n slug: string\n label: string\n icon?: string\n group?: string | null\n permissions: Record<string, string>\n fields: ManifestNode[]\n columns: ManifestNode[]\n filters: ManifestNode[]\n actions: ManifestNode[]\n searchable: string[]\n with: string[]\n features: Record<string, unknown>\n screens?: Record<string, unknown>\n}\n\nexport interface ManifestScreenMeta {\n slug: string\n name: string\n description: string | null\n permission: string[] | string | null\n}\n\nexport interface ManifestSettingsMeta {\n kind: 'settings'\n slug: string\n label: string\n permissions: Record<string, string>\n fields: ManifestNode[]\n}\n\nexport interface AdminManifest {\n version: string\n locale: string\n resources: ManifestResourceMeta[]\n screens: ManifestScreenMeta[]\n settings: ManifestSettingsMeta[]\n dashboards: unknown[]\n plugins: string[]\n permissions: unknown[]\n}\n\nexport const useManifestStore = defineStore('admin-manifest', () => {\n const manifest = ref<AdminManifest | null>(null)\n const loading = ref(false)\n const error = ref<Error | null>(null)\n\n const isLoaded = computed(() => manifest.value !== null)\n const version = computed(() => manifest.value?.version ?? null)\n const resources = computed(() => manifest.value?.resources ?? [])\n const screens = computed(() => manifest.value?.screens ?? [])\n const settings = computed(() => manifest.value?.settings ?? [])\n const plugins = computed(() => manifest.value?.plugins ?? [])\n\n function getResource(slug: string): ManifestResourceMeta | null {\n return resources.value.find((r) => r.slug === slug) ?? null\n }\n\n function getScreen(slug: string): ManifestScreenMeta | null {\n return screens.value.find((s) => s.slug === slug) ?? null\n }\n\n function getSettings(slug: string): ManifestSettingsMeta | null {\n return settings.value.find((s) => s.slug === slug) ?? null\n }\n\n /**\n * Загрузить manifest. Если уже загружен — возвращает cached.\n * Force=true принудительно обновит с сервера.\n */\n async function load(force = false): Promise<AdminManifest> {\n if (manifest.value !== null && !force) {\n return manifest.value\n }\n\n loading.value = true\n error.value = null\n try {\n const client = getAdminClient()\n const result = await client.get<AdminManifest>('/system/manifest')\n manifest.value = result\n return result\n } catch (err) {\n error.value = err instanceof Error ? err : new Error(String(err))\n throw err\n } finally {\n loading.value = false\n }\n }\n\n function reset(): void {\n manifest.value = null\n error.value = null\n loading.value = false\n }\n\n return {\n // state\n manifest,\n loading,\n error,\n // getters\n isLoaded,\n version,\n resources,\n screens,\n settings,\n plugins,\n // actions\n getResource,\n getScreen,\n getSettings,\n load,\n reset,\n }\n})\n","<script setup lang=\"ts\">\n/**\n * Default home-страница admin'а. Host'ы перебивают через\n * createAdminApp({ pages: { home: MyHome } }).\n *\n * Показывает welcome-карточку + список зарегистрированных Resource'ов из\n * manifest store (быстрая навигация для свежепоставленной админки).\n */\nimport { computed } from 'vue'\nimport { useRouter } from 'vue-router'\nimport { UidCard } from '@dskripchenko/ui'\nimport { useManifestStore } from '../stores/manifest'\nimport { useAuthStore } from '../stores/auth'\n\nconst manifest = useManifestStore()\nconst auth = useAuthStore()\nconst router = useRouter()\n\nconst userName = computed(() => auth.user?.name ?? '')\nconst resources = computed(() => manifest.manifest?.resources ?? [])\n</script>\n\n<template>\n <div class=\"admin-home\">\n <UidCard padding=\"lg\" class=\"admin-home__hero\">\n <h1 class=\"admin-home__title\">Добро пожаловать{{ userName ? ', ' + userName : '' }}</h1>\n <p class=\"admin-home__lead\">\n Админ-панель готова. Воспользуйтесь сайдбаром или переходите к ресурсам ниже.\n </p>\n </UidCard>\n\n <section v-if=\"resources.length\" class=\"admin-home__resources\">\n <h2 class=\"admin-home__heading\">Ресурсы</h2>\n <ul class=\"admin-home__grid\">\n <li v-for=\"r in resources\" :key=\"r.slug\">\n <button\n type=\"button\"\n class=\"admin-home__card\"\n @click=\"router.push({ name: `admin.resource.${r.slug}.index` })\"\n >\n <span class=\"admin-home__card-label\">{{ r.label }}</span>\n <span class=\"admin-home__card-slug\">{{ r.slug }}</span>\n </button>\n </li>\n </ul>\n </section>\n </div>\n</template>\n\n<style>\n.admin-home {\n display: flex;\n flex-direction: column;\n gap: var(--uid-space-lg);\n padding: var(--uid-space-md);\n}\n.admin-home__title {\n font-size: var(--uid-font-size-2xl);\n font-weight: var(--uid-font-weight-bold);\n margin: 0 0 var(--uid-space-sm);\n}\n.admin-home__lead {\n color: var(--uid-text-secondary);\n margin: 0;\n}\n.admin-home__heading {\n font-size: var(--uid-font-size-lg);\n font-weight: var(--uid-font-weight-semibold);\n margin: 0 0 var(--uid-space-sm);\n}\n.admin-home__grid {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));\n gap: var(--uid-space-sm);\n list-style: none;\n padding: 0;\n margin: 0;\n}\n.admin-home__card {\n display: flex;\n flex-direction: column;\n gap: var(--uid-space-2xs);\n padding: var(--uid-space-md);\n border: 1px solid var(--uid-border-subtle);\n border-radius: var(--uid-radius-md);\n background: var(--uid-surface-raised);\n text-align: left;\n cursor: pointer;\n transition: border-color 0.15s ease, transform 0.15s ease;\n}\n.admin-home__card:hover {\n border-color: var(--uid-accent);\n transform: translateY(-1px);\n}\n.admin-home__card-label {\n font-weight: var(--uid-font-weight-medium);\n}\n.admin-home__card-slug {\n font-size: var(--uid-font-size-xs);\n color: var(--uid-text-tertiary);\n}\n</style>\n","<script setup lang=\"ts\">\n/**\n * 403 fallback. Host может переопределить через createAdminApp({ pages: { forbidden } }).\n */\nimport { UidCard, UidButton } from '@dskripchenko/ui'\nimport { useRouter } from 'vue-router'\n\nconst router = useRouter()\n</script>\n\n<template>\n <div class=\"admin-status-page\">\n <UidCard padding=\"lg\" class=\"admin-status-page__card\">\n <h1 class=\"admin-status-page__code\">403</h1>\n <p class=\"admin-status-page__message\">Доступ запрещён.</p>\n <UidButton variant=\"ghost\" @click=\"router.replace({ name: 'admin.home' })\">\n На главную\n </UidButton>\n </UidCard>\n </div>\n</template>\n\n<style>\n.admin-status-page {\n display: flex;\n align-items: center;\n justify-content: center;\n min-height: 60vh;\n padding: var(--uid-space-lg);\n}\n.admin-status-page__card {\n text-align: center;\n max-width: 480px;\n}\n.admin-status-page__code {\n font-size: 64px;\n font-weight: var(--uid-font-weight-bold);\n margin: 0 0 var(--uid-space-sm);\n color: var(--uid-text-secondary);\n}\n.admin-status-page__message {\n margin: 0 0 var(--uid-space-md);\n color: var(--uid-text-secondary);\n}\n</style>\n","<script setup lang=\"ts\">\n/**\n * 404 fallback. Host может переопределить через createAdminApp({ pages: { notFound } }).\n */\nimport { UidCard, UidButton } from '@dskripchenko/ui'\nimport { useRouter } from 'vue-router'\n\nconst router = useRouter()\n</script>\n\n<template>\n <div class=\"admin-status-page\">\n <UidCard padding=\"lg\" class=\"admin-status-page__card\">\n <h1 class=\"admin-status-page__code\">404</h1>\n <p class=\"admin-status-page__message\">Страница не найдена.</p>\n <UidButton variant=\"ghost\" @click=\"router.replace({ name: 'admin.home' })\">\n На главную\n </UidButton>\n </UidCard>\n </div>\n</template>\n","<script setup lang=\"ts\">\n/**\n * Default страница для admin.settings.{slug} роутов.\n *\n * Загружает settings-meta из manifest'а и рендерит fields через LayoutRenderer\n * с form-state поверх SettingsApiClient. Host'ы переопределяют через\n * createAdminApp({ pages: { settings: MySettings } }) если нужна более\n * специфичная UX (например, side-tab навигация по Settings-классам).\n */\nimport { computed } from 'vue'\nimport { useRoute } from 'vue-router'\nimport { UidCard } from '@dskripchenko/ui'\nimport { useManifestStore } from '../stores/manifest'\n\nconst route = useRoute()\nconst manifest = useManifestStore()\n\nconst slug = computed(() => String(route.params.slug ?? ''))\nconst meta = computed(() => manifest.manifest?.settings?.find((s) => s.slug === slug.value) ?? null)\n</script>\n\n<template>\n <div class=\"admin-settings-page\">\n <UidCard padding=\"lg\">\n <h1 class=\"admin-settings-page__title\">{{ meta?.label ?? slug }}</h1>\n <p v-if=\"!meta\" class=\"admin-settings-page__hint\">\n Settings «{{ slug }}» не найдено в manifest'е.\n </p>\n <pre v-else class=\"admin-settings-page__debug\">{{ JSON.stringify(meta.fields, null, 2) }}</pre>\n </UidCard>\n </div>\n</template>\n\n<style>\n.admin-settings-page {\n padding: var(--uid-space-md);\n}\n.admin-settings-page__title {\n font-size: var(--uid-font-size-xl);\n font-weight: var(--uid-font-weight-semibold);\n margin: 0 0 var(--uid-space-sm);\n}\n.admin-settings-page__debug {\n background: var(--uid-surface-raised);\n border: 1px solid var(--uid-border-subtle);\n padding: var(--uid-space-sm);\n border-radius: var(--uid-radius-sm);\n font-family: var(--uid-font-mono);\n font-size: var(--uid-font-size-xs);\n overflow: auto;\n max-height: 60vh;\n}\n.admin-settings-page__hint {\n color: var(--uid-text-secondary);\n}\n</style>\n","<script setup lang=\"ts\">\n/**\n * Заглушка для произвольных Screen-роутов из manifest'а.\n * Host'ы переопределяют через createAdminApp({ pages: { screen: MyScreen } })\n * и кастомным компонентом рендерят `route.params.slug` через любой template.\n */\nimport { computed } from 'vue'\nimport { useRoute } from 'vue-router'\nimport { UidCard } from '@dskripchenko/ui'\n\nconst route = useRoute()\nconst slug = computed(() => String(route.params.slug ?? ''))\nconst title = computed(() => String(route.meta?.title ?? slug.value))\n</script>\n\n<template>\n <div class=\"admin-status-page\">\n <UidCard padding=\"lg\" class=\"admin-status-page__card\">\n <h1 class=\"admin-status-page__title\">{{ title }}</h1>\n <p class=\"admin-status-page__hint\">\n Это заглушка для screen «{{ slug }}». Передайте свой компонент через\n <code>createAdminApp({{ '{' }} pages: {{ '{' }} screen: MyScreen {{ '}' }} {{ '}' }})</code>.\n </p>\n </UidCard>\n </div>\n</template>\n\n<style>\n.admin-status-page__title {\n font-size: var(--uid-font-size-xl);\n font-weight: var(--uid-font-weight-semibold);\n margin: 0 0 var(--uid-space-sm);\n}\n.admin-status-page__hint {\n margin: 0;\n color: var(--uid-text-secondary);\n font-size: var(--uid-font-size-sm);\n}\n</style>\n","<script setup lang=\"ts\">\n/**\n * LoginForm — email/password/remember поверх UidInput/UidButton/UidCheckbox/\n * UidAlert. Архитектура auth-card по docs/design_handoff_laravel_admin/\n * screens-secondary.jsx (LoginScreen).\n */\nimport { computed, ref } from 'vue'\nimport { UidAlert, UidButton, UidCheckbox, UidInput } from '@dskripchenko/ui'\nimport { useAuthStore } from '../../stores/auth'\nimport { ApiError, NetworkError, ValidationError } from '../../api/errors'\n\ninterface Props {\n /** URL «Забыли пароль?» — если задан, показывается link справа от remember. */\n forgotUrl?: string | null\n /** Текст SSO-ссылки или null чтобы скрыть. */\n ssoLinkLabel?: string | null\n ssoUrl?: string | null\n}\n\nwithDefaults(defineProps<Props>(), {\n forgotUrl: null,\n ssoLinkLabel: null,\n ssoUrl: null,\n})\n\nconst emit = defineEmits<{\n success: [result: 'authenticated' | 'two_factor_required']\n}>()\n\nconst auth = useAuthStore()\n\nconst email = ref('')\nconst password = ref('')\nconst remember = ref(false)\n\nconst submitting = ref(false)\nconst generalError = ref<string | null>(null)\nconst fieldErrors = ref<Record<string, string[]>>({})\n\nconst emailError = computed<string | undefined>(() => fieldErrors.value.email?.[0])\nconst passwordError = computed<string | undefined>(() => fieldErrors.value.password?.[0])\n\nasync function submit(): Promise<void> {\n if (submitting.value) return\n submitting.value = true\n generalError.value = null\n fieldErrors.value = {}\n\n try {\n const result = await auth.login({\n email: email.value,\n password: password.value,\n remember: remember.value,\n })\n emit('success', result)\n } catch (err) {\n if (err instanceof ValidationError) {\n fieldErrors.value = err.fields\n generalError.value = err.firstFieldMessage()\n } else if (err instanceof NetworkError) {\n generalError.value = 'Нет соединения с сервером'\n } else if (err instanceof ApiError) {\n generalError.value = err.message || 'Не удалось войти'\n } else {\n generalError.value = (err as Error).message\n }\n } finally {\n submitting.value = false\n }\n}\n</script>\n\n<template>\n <form class=\"admin-auth-card__bd\" novalidate @submit.prevent=\"submit\">\n <UidAlert\n v-if=\"generalError\"\n variant=\"danger\"\n class=\"admin-auth-card__alert\"\n role=\"alert\"\n >\n {{ generalError }}\n </UidAlert>\n\n <UidInput\n v-model=\"email\"\n type=\"email\"\n label=\"Email\"\n placeholder=\"you@company.com\"\n autocomplete=\"username\"\n :required=\"true\"\n :disabled=\"submitting\"\n :error=\"emailError\"\n name=\"email\"\n />\n\n <UidInput\n v-model=\"password\"\n type=\"password\"\n label=\"Пароль\"\n autocomplete=\"current-password\"\n :required=\"true\"\n :disabled=\"submitting\"\n :error=\"passwordError\"\n name=\"password\"\n />\n\n <div class=\"admin-auth-card__row\">\n <UidCheckbox v-model=\"remember\" :disabled=\"submitting\">\n Запомнить меня\n </UidCheckbox>\n <a v-if=\"forgotUrl\" :href=\"forgotUrl\" class=\"admin-auth-card__link\">\n Забыли пароль?\n </a>\n </div>\n\n <UidButton\n type=\"submit\"\n variant=\"primary\"\n size=\"lg\"\n :loading=\"submitting\"\n :disabled=\"submitting\"\n >\n {{ submitting ? 'Вход…' : 'Войти' }}\n </UidButton>\n\n <div\n v-if=\"ssoLinkLabel && ssoUrl\"\n style=\"text-align: center; font-size: var(--uid-font-size-xs); color: var(--uid-text-secondary); padding-top: 4px;\"\n >\n или войдите через\n <a :href=\"ssoUrl\" class=\"admin-auth-card__link\">{{ ssoLinkLabel }}</a>\n </div>\n </form>\n</template>\n","<script setup lang=\"ts\">\n/**\n * 2FA-форма: 6-cell mono TOTP-input + alt recovery-code.\n *\n * Эталон — docs/design_handoff_laravel_admin/screens-secondary.jsx (TwoFactor):\n * 6 input'ов 44×52, IBM Plex Mono 22px, при заполнении одного — фокус\n * автопереходит на следующий, paste-event раскладывает 6 цифр сразу.\n */\nimport { computed, nextTick, ref } from 'vue'\nimport { UidAlert, UidButton, UidInput } from '@dskripchenko/ui'\nimport { useAuthStore } from '../../stores/auth'\nimport { ApiError, NetworkError, ValidationError } from '../../api/errors'\n\nconst emit = defineEmits<{\n success: []\n cancel: []\n}>()\n\nconst auth = useAuthStore()\n\nconst mode = ref<'totp' | 'recovery'>('totp')\nconst cells = ref<string[]>(['', '', '', '', '', ''])\nconst recoveryCode = ref('')\nconst cellRefs = ref<HTMLInputElement[]>([])\n\nconst submitting = ref(false)\nconst generalError = ref<string | null>(null)\nconst remaining = ref<number | null>(null)\n\nconst totpCode = computed(() => cells.value.join(''))\nconst isValid = computed(() => {\n if (mode.value === 'totp') return totpCode.value.length === 6\n return recoveryCode.value.trim().length > 0\n})\n\nfunction setCellRef(idx: number, el: Element | null): void {\n if (el instanceof HTMLInputElement) cellRefs.value[idx] = el\n}\n\nfunction onCellInput(idx: number, event: Event): void {\n const target = event.target as HTMLInputElement\n // Только цифры; обрезаем до 1 символа.\n const digit = target.value.replace(/\\D/g, '').slice(-1)\n cells.value[idx] = digit\n target.value = digit\n if (digit && idx < cells.value.length - 1) {\n void nextTick(() => cellRefs.value[idx + 1]?.focus())\n }\n if (totpCode.value.length === cells.value.length) {\n void submit()\n }\n}\n\nfunction onCellKeydown(idx: number, event: KeyboardEvent): void {\n if (event.key === 'Backspace' && !cells.value[idx] && idx > 0) {\n void nextTick(() => cellRefs.value[idx - 1]?.focus())\n } else if (event.key === 'ArrowLeft' && idx > 0) {\n cellRefs.value[idx - 1]?.focus()\n event.preventDefault()\n } else if (event.key === 'ArrowRight' && idx < cells.value.length - 1) {\n cellRefs.value[idx + 1]?.focus()\n event.preventDefault()\n }\n}\n\nfunction onPaste(event: ClipboardEvent): void {\n const pasted = event.clipboardData?.getData('text') ?? ''\n const digits = pasted.replace(/\\D/g, '').slice(0, cells.value.length)\n if (digits.length === 0) return\n event.preventDefault()\n for (let i = 0; i < cells.value.length; i++) {\n cells.value[i] = digits[i] ?? ''\n }\n void nextTick(() => {\n cellRefs.value[Math.min(digits.length, cells.value.length - 1)]?.focus()\n if (digits.length === cells.value.length) void submit()\n })\n}\n\nasync function submit(): Promise<void> {\n if (submitting.value || !isValid.value) return\n submitting.value = true\n generalError.value = null\n\n try {\n if (mode.value === 'totp') {\n await auth.twoFactorChallenge(totpCode.value)\n } else {\n const res = await auth.twoFactorRecovery(recoveryCode.value.trim())\n remaining.value = res.remaining\n }\n emit('success')\n } catch (err) {\n if (err instanceof ValidationError) {\n generalError.value = err.firstFieldMessage() ?? 'Неверный код'\n } else if (err instanceof NetworkError) {\n generalError.value = 'Нет соединения с сервером'\n } else if (err instanceof ApiError) {\n generalError.value = err.message || 'Не удалось проверить код'\n } else {\n generalError.value = (err as Error).message\n }\n } finally {\n submitting.value = false\n }\n}\n\nfunction cancel(): void {\n auth.cancelChallenge()\n emit('cancel')\n}\n\nfunction switchMode(): void {\n mode.value = mode.value === 'totp' ? 'recovery' : 'totp'\n generalError.value = null\n}\n</script>\n\n<template>\n <form class=\"admin-auth-card__bd\" novalidate @submit.prevent=\"submit\">\n <UidAlert\n v-if=\"generalError\"\n variant=\"danger\"\n class=\"admin-auth-card__alert\"\n role=\"alert\"\n >\n {{ generalError }}\n </UidAlert>\n <UidAlert\n v-if=\"remaining !== null\"\n variant=\"info\"\n class=\"admin-auth-card__alert\"\n role=\"status\"\n >\n Использован recovery-код. Осталось: {{ remaining }}\n </UidAlert>\n\n <div v-if=\"mode === 'totp'\" class=\"admin-code-input\" @paste=\"onPaste\">\n <input\n v-for=\"(_, idx) in cells\"\n :key=\"idx\"\n :ref=\"(el) => setCellRef(idx, el as Element | null)\"\n :value=\"cells[idx]\"\n type=\"text\"\n inputmode=\"numeric\"\n autocomplete=\"one-time-code\"\n maxlength=\"1\"\n :disabled=\"submitting\"\n :aria-label=\"`Цифра ${idx + 1}`\"\n @input=\"onCellInput(idx, $event)\"\n @keydown=\"onCellKeydown(idx, $event)\"\n />\n </div>\n\n <UidInput\n v-else\n v-model=\"recoveryCode\"\n type=\"text\"\n label=\"Recovery-код\"\n autocomplete=\"one-time-code\"\n :disabled=\"submitting\"\n name=\"recovery-code\"\n />\n\n <UidButton\n type=\"submit\"\n variant=\"primary\"\n size=\"lg\"\n :loading=\"submitting\"\n :disabled=\"submitting || !isValid\"\n >\n {{ submitting ? 'Проверка…' : 'Подтвердить' }}\n </UidButton>\n\n <div class=\"admin-auth-card__row\">\n <button type=\"button\" class=\"admin-auth-card__link\" @click=\"switchMode\">\n <template v-if=\"mode === 'totp'\">Использовать recovery-код</template>\n <template v-else>Вернуться к коду из приложения</template>\n </button>\n <button type=\"button\" class=\"admin-auth-card__link\" @click=\"cancel\">\n Отмена\n </button>\n </div>\n </form>\n</template>\n","<script setup lang=\"ts\">\n/**\n * LoginPage поверх UID design handoff: centered auth-card 400/440 px на\n * `--uid-surface-base`-фоне с corner-actions (theme + locale toggles).\n *\n * Композиция: LoginForm либо TwoFactorForm в зависимости от\n * auth.isChallengePending. Редирект на main завязан на watch\n * (auth.isAuthenticated) — это переживает unmount форм при смене ветки.\n *\n * `?redirect`-query учитывает только относительные пути (защита от\n * open-redirect).\n */\nimport { onMounted, watch } from 'vue'\nimport { useRouter, useRoute } from 'vue-router'\nimport { UidCard } from '@dskripchenko/ui'\nimport { useAuthStore } from '../../stores/auth'\nimport LoginForm from './LoginForm.vue'\nimport TwoFactorForm from './TwoFactorForm.vue'\nimport ThemeToggle from '../shell/widgets/ThemeToggle.vue'\nimport LocaleSwitcher from '../shell/widgets/LocaleSwitcher.vue'\n\ninterface Props {\n brandName?: string\n brandMark?: string\n brandLogo?: string | null\n homeRouteName?: string\n redirectQueryKey?: string\n /** URL «Забыли пароль?» — пробрасывается в LoginForm. */\n forgotUrl?: string | null\n /** SSO-link (label + url) — пробрасывается в LoginForm. */\n ssoLinkLabel?: string | null\n ssoUrl?: string | null\n /** Показывать ли theme/locale toggle'ы в углу. */\n showCornerActions?: boolean\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n brandName: 'Laravel Admin',\n brandMark: 'L',\n brandLogo: null,\n homeRouteName: 'admin.home',\n redirectQueryKey: 'redirect',\n forgotUrl: null,\n ssoLinkLabel: null,\n ssoUrl: null,\n showCornerActions: true,\n})\n\nconst auth = useAuthStore()\nconst router = useRouter()\nconst route = useRoute()\n\nasync function redirectToHome(): Promise<void> {\n const target = route.query[props.redirectQueryKey]\n if (typeof target === 'string' && target.length > 0 && target.startsWith('/')) {\n await router.push(target)\n return\n }\n await router.push({ name: props.homeRouteName })\n}\n\nwatch(\n () => auth.isAuthenticated,\n (next) => {\n if (next) void redirectToHome()\n },\n)\nonMounted(() => {\n if (auth.isAuthenticated) void redirectToHome()\n})\n</script>\n\n<template>\n <div class=\"admin-auth-page\">\n <div v-if=\"showCornerActions\" class=\"admin-auth-page__corner\">\n <ThemeToggle />\n <LocaleSwitcher />\n </div>\n\n <UidCard\n :class=\"['admin-auth-card', auth.isChallengePending ? 'admin-auth-card--wide' : '']\"\n padding=\"none\"\n >\n <div class=\"admin-auth-card__hd\">\n <div\n :class=\"['admin-auth-card__logo', auth.isChallengePending ? 'admin-auth-card__logo--accent' : '']\"\n >\n <img v-if=\"brandLogo && !auth.isChallengePending\" :src=\"brandLogo\" :alt=\"brandName\" />\n <span v-else-if=\"auth.isChallengePending\" aria-hidden=\"true\">🛡</span>\n <span v-else>{{ brandMark }}</span>\n </div>\n <div class=\"admin-auth-card__title\">\n <template v-if=\"auth.isChallengePending\">Двухфакторная проверка</template>\n <template v-else>{{ brandName }}</template>\n </div>\n <div class=\"admin-auth-card__sub\">\n <template v-if=\"auth.isChallengePending\">\n Введите 6-значный код из приложения-аутентификатора\n </template>\n <template v-else>Войдите, чтобы продолжить работу</template>\n </div>\n </div>\n\n <TwoFactorForm\n v-if=\"auth.isChallengePending\"\n @success=\"() => undefined\"\n @cancel=\"() => undefined\"\n />\n <LoginForm\n v-else\n :forgot-url=\"forgotUrl\"\n :sso-link-label=\"ssoLinkLabel\"\n :sso-url=\"ssoUrl\"\n @success=\"() => undefined\"\n />\n </UidCard>\n </div>\n</template>\n","/**\n * useResourceIndexStore — list-page state для одного Resource'а.\n *\n * Поддерживает:\n * - items + pagination meta из envelope payload\n * - filters (typed Record<string, unknown>) — отправляются как query\n * - sort (key + direction)\n * - selection (Set<row-id>) для bulk-actions; tri-state header-checkbox\n * - loading/error состояния (UI рендерит UidSkeleton/UidErrorState)\n *\n * Один store-instance переиспользуется на разных Resource-страницах через\n * `useResourceIndexStore(slug)` с явным `setSlug` — это даёт чистый reset\n * между resource'ами.\n */\n\nimport { defineStore } from 'pinia'\nimport { computed, ref } from 'vue'\nimport { getAdminClient } from './registry'\n\nexport interface IndexMeta {\n page: number\n per_page: number\n total: number\n last_page: number\n}\n\nexport type SortDirection = 'asc' | 'desc' | null\n\nexport interface IndexParams {\n page?: number\n per_page?: number\n sort?: string | null\n direction?: SortDirection\n search?: string | null\n filters?: Record<string, unknown>\n}\n\ninterface ListResponse {\n data: Array<Record<string, unknown>>\n meta: IndexMeta\n}\n\nconst DEFAULT_META: IndexMeta = { page: 1, per_page: 20, total: 0, last_page: 1 }\n\nexport const useResourceIndexStore = defineStore('admin-resource-index', () => {\n /** Текущий resource-slug (urls/users/posts/etc). */\n const slug = ref<string | null>(null)\n\n const items = ref<Array<Record<string, unknown>>>([])\n const meta = ref<IndexMeta>({ ...DEFAULT_META })\n\n const loading = ref(false)\n /**\n * `slowLoading` = true только если loading длится > SLOW_LOADING_DELAY мс.\n * UI использует это для skeleton — чтобы быстрые ответы (<200мс) не\n * мерцали 'data → skeleton → data'. Если запрос быстрый, skeleton\n * никогда не показывается.\n */\n const slowLoading = ref(false)\n const error = ref<Error | null>(null)\n let slowLoadingTimer: ReturnType<typeof setTimeout> | null = null\n const SLOW_LOADING_DELAY = 200\n\n const search = ref<string>('')\n const filters = ref<Record<string, unknown>>({})\n const sortKey = ref<string | null>(null)\n const sortDirection = ref<SortDirection>(null)\n\n /** Set ID-шников выбранных строк (bulk-actions). */\n const selection = ref<Set<string | number>>(new Set())\n\n const isEmpty = computed(() => !loading.value && error.value === null && items.value.length === 0)\n const selectedCount = computed(() => selection.value.size)\n const hasSelection = computed(() => selection.value.size > 0)\n const hasError = computed(() => error.value !== null)\n\n /** Tri-state: 'all' / 'mixed' / 'none' для header-checkbox. */\n const selectionState = computed<'all' | 'mixed' | 'none'>(() => {\n if (selection.value.size === 0) return 'none'\n if (items.value.length === 0) return 'none'\n const allSelected = items.value.every((row) => selection.value.has(rowId(row)))\n return allSelected ? 'all' : 'mixed'\n })\n\n /** Извлекает ID строки. По умолчанию — поле `id`; host может переопределить. */\n function rowId(row: Record<string, unknown>): string | number {\n return (row.id ?? row.key ?? '') as string | number\n }\n\n /**\n * Сменить ресурс — сброс state'а.\n *\n * `loading=true` ставится сразу, чтобы в окне между setSlug() и load() не\n * рендерилась EmptyState (\"Нет данных\") — это вызывало flicker при\n * navigation между Resource'ами.\n */\n function setSlug(next: string | null): void {\n if (slug.value === next) return\n slug.value = next\n reset()\n loading.value = true\n }\n\n function reset(): void {\n items.value = []\n meta.value = { ...DEFAULT_META }\n loading.value = false\n error.value = null\n search.value = ''\n filters.value = {}\n sortKey.value = null\n sortDirection.value = null\n selection.value = new Set()\n }\n\n function buildParams(override: IndexParams = {}): Record<string, unknown> {\n const params: Record<string, unknown> = {\n page: override.page ?? meta.value.page,\n per_page: override.per_page ?? meta.value.per_page,\n }\n // Free-text: backend ждёт `q`. См. HttpFilterParser::searchTerm.\n const ss = override.search ?? search.value\n if (ss) params.q = ss\n\n // Order: массив {column, direction}. Backend читает `order[]` через input('order').\n // Если direction === null → не добавляем order (3-режимная sort: off).\n const sk = override.sort ?? sortKey.value\n const dir = override.direction ?? sortDirection.value\n if (sk && dir !== null) {\n params.order = [{ column: sk, direction: dir }]\n }\n\n // Filters: map-style {column: value} — HttpFilterParser auto-detect режим 1.\n const f = override.filters ?? filters.value\n const filtersMap: Record<string, unknown> = {}\n for (const [k, v] of Object.entries(f)) {\n if (v === null || v === undefined || v === '') continue\n filtersMap[k] = Array.isArray(v) ? v.join(',') : v\n }\n if (Object.keys(filtersMap).length > 0) params.filters = filtersMap\n\n return params\n }\n\n /** Загрузить страницу. Без аргументов — текущие фильтры/сортировка/page. */\n async function load(override: IndexParams = {}): Promise<void> {\n if (!slug.value) {\n throw new Error('useResourceIndexStore.load() called before setSlug()')\n }\n loading.value = true\n error.value = null\n // Debounced flag для skeleton: true только если запрос длится > 200мс.\n if (slowLoadingTimer !== null) clearTimeout(slowLoadingTimer)\n slowLoadingTimer = setTimeout(() => {\n slowLoading.value = true\n }, SLOW_LOADING_DELAY)\n try {\n const client = getAdminClient()\n const body = buildParams(override)\n // Backend ResourceController.search: POST /{slug}/search.\n // Тело — параметры (фильтры/сортировка/пагинация). Возвращает\n // {data, meta:{page,per_page,total,last_page,...}}.\n const res = await client.post<ListResponse>(`/${slug.value}/search`, body)\n items.value = res.data\n meta.value = res.meta\n } catch (err) {\n error.value = err instanceof Error ? err : new Error(String(err))\n throw err\n } finally {\n loading.value = false\n slowLoading.value = false\n if (slowLoadingTimer !== null) {\n clearTimeout(slowLoadingTimer)\n slowLoadingTimer = null\n }\n }\n }\n\n async function setSearch(value: string): Promise<void> {\n search.value = value\n meta.value.page = 1\n await load()\n }\n\n async function setFilter(key: string, value: unknown): Promise<void> {\n if (value === null || value === undefined || value === '') {\n delete filters.value[key]\n } else {\n filters.value[key] = value\n }\n meta.value.page = 1\n await load()\n }\n\n async function clearFilters(): Promise<void> {\n filters.value = {}\n meta.value.page = 1\n await load()\n }\n\n async function setSort(key: string | null, direction: SortDirection = 'asc'): Promise<void> {\n sortKey.value = key\n sortDirection.value = direction\n await load()\n }\n\n /**\n * 3-режимная sort. Click по same key → asc → desc → off (sort=null).\n * Click по другому key → asc.\n */\n async function toggleSort(key: string): Promise<void> {\n if (sortKey.value === key) {\n if (sortDirection.value === 'asc') {\n sortDirection.value = 'desc'\n } else if (sortDirection.value === 'desc') {\n sortKey.value = null\n sortDirection.value = null\n } else {\n sortDirection.value = 'asc'\n }\n } else {\n sortKey.value = key\n sortDirection.value = 'asc'\n }\n await load()\n }\n\n async function setPage(page: number): Promise<void> {\n meta.value.page = page\n await load()\n }\n\n function toggleRow(id: string | number): void {\n const next = new Set(selection.value)\n if (next.has(id)) next.delete(id)\n else next.add(id)\n selection.value = next\n }\n\n /** Toggle: выделить все на странице если что-то не выбрано, иначе очистить. */\n function toggleAllOnPage(): void {\n if (selectionState.value === 'all') {\n selection.value = new Set()\n return\n }\n const next = new Set(selection.value)\n for (const row of items.value) next.add(rowId(row))\n selection.value = next\n }\n\n function clearSelection(): void {\n selection.value = new Set()\n }\n\n /** Проверить выбор конкретной строки. */\n function isSelected(id: string | number): boolean {\n return selection.value.has(id)\n }\n\n return {\n // state\n slug,\n items,\n meta,\n loading,\n slowLoading,\n error,\n search,\n filters,\n sortKey,\n sortDirection,\n selection,\n // getters\n isEmpty,\n hasError,\n hasSelection,\n selectedCount,\n selectionState,\n // actions\n setSlug,\n reset,\n load,\n setSearch,\n setFilter,\n clearFilters,\n setSort,\n toggleSort,\n setPage,\n toggleRow,\n toggleAllOnPage,\n clearSelection,\n isSelected,\n rowId,\n }\n})\n","/**\n * Formatter cell-значений для ResourceIndexPage.\n *\n * Backend-side TableColumn presets:\n * - text → as-is (string).\n * - date → 'd.m.Y' (default).\n * - datetime → 'd.m.Y H:i:s' (default).\n * - money → '{value} {currency}' с decimals.\n * - boolean → trueLabel / falseLabel из meta.\n * - badge → текст; стилизация на UI рендере (через slot или CSS-class).\n * - bytes → human-readable размер.\n * - text → fallback.\n *\n * `auto-format` для колонок без явного preset'а: если значение похоже на ISO\n * datetime (`*_at` или строка с T...Z) — применяется default datetime формат.\n */\n\nexport type CellPreset = 'text' | 'date' | 'datetime' | 'money' | 'boolean' | 'badge' | 'bytes'\n\nexport interface CellMeta {\n format?: string\n currency?: string\n decimals?: number\n trueLabel?: string | null\n falseLabel?: string | null\n [key: string]: unknown\n}\n\nconst DEFAULT_DATETIME = 'd.m.Y H:i:s'\nconst DEFAULT_DATE = 'd.m.Y'\n\nconst ISO_DATETIME_RE = /^\\d{4}-\\d{2}-\\d{2}[T\\s]\\d{2}:\\d{2}/\n\nexport function formatCell(\n value: unknown,\n preset: string | undefined,\n meta: CellMeta = {},\n): string {\n if (value === null || value === undefined) return ''\n\n // Auto-detection ISO datetime для колонок без preset'а.\n if (!preset && typeof value === 'string' && ISO_DATETIME_RE.test(value)) {\n return formatDateString(value, DEFAULT_DATETIME)\n }\n\n switch (preset) {\n case 'date':\n return formatDateString(String(value), meta.format ?? DEFAULT_DATE)\n case 'datetime':\n return formatDateString(String(value), meta.format ?? DEFAULT_DATETIME)\n case 'money':\n return formatMoney(value, meta.currency ?? 'RUB', meta.decimals ?? 2)\n case 'boolean':\n return formatBoolean(value, meta.trueLabel ?? 'Да', meta.falseLabel ?? 'Нет')\n case 'bytes':\n return formatBytes(value)\n default:\n return String(value)\n }\n}\n\n/**\n * PHP-стиль format strings → JS-Date.\n *\n * Поддерживаемые токены:\n * d → 01-31, m → 01-12, Y → 2026, y → 26\n * H → 00-23, h → 12-hour, i → minutes, s → seconds\n * D → Mon-Sun (3-letter), l → full day name, M → Jan, F → January\n * N → 1-7 (ISO weekday), w → 0-6\n * U → Unix timestamp, c → ISO 8601\n */\nfunction formatDateString(input: string, format: string): string {\n const date = new Date(input)\n if (isNaN(date.getTime())) return input\n\n const pad = (n: number, w = 2): string => String(n).padStart(w, '0')\n\n const tokens: Record<string, string> = {\n d: pad(date.getDate()),\n m: pad(date.getMonth() + 1),\n Y: String(date.getFullYear()),\n y: pad(date.getFullYear() % 100),\n H: pad(date.getHours()),\n h: pad(((date.getHours() + 11) % 12) + 1),\n i: pad(date.getMinutes()),\n s: pad(date.getSeconds()),\n U: String(Math.floor(date.getTime() / 1000)),\n c: date.toISOString(),\n N: String(((date.getDay() + 6) % 7) + 1),\n w: String(date.getDay()),\n }\n\n // Замена с учётом escape '\\\\' (PHP: backslash escapes the next char).\n let out = ''\n for (let i = 0; i < format.length; i++) {\n const ch = format[i]\n if (ch === '\\\\' && i + 1 < format.length) {\n out += format[i + 1]\n i++\n continue\n }\n out += tokens[ch] ?? ch\n }\n return out\n}\n\nfunction formatMoney(value: unknown, currency: string, decimals: number): string {\n const n = typeof value === 'number' ? value : Number(value)\n if (isNaN(n)) return String(value)\n return `${n.toFixed(decimals)} ${currency}`\n}\n\nfunction formatBoolean(value: unknown, trueLabel: string, falseLabel: string): string {\n const truthy = value === true || value === 1 || value === '1' || value === 'true'\n return truthy ? trueLabel : falseLabel\n}\n\nfunction formatBytes(value: unknown): string {\n const n = typeof value === 'number' ? value : Number(value)\n if (isNaN(n)) return String(value)\n if (n < 1024) return `${n} B`\n if (n < 1024 * 1024) return `${(n / 1024).toFixed(1)} KB`\n if (n < 1024 * 1024 * 1024) return `${(n / 1024 / 1024).toFixed(1)} MB`\n return `${(n / 1024 / 1024 / 1024).toFixed(1)} GB`\n}\n","<script setup lang=\"ts\">\n/**\n * ResourceIndexPage — list-screen для одного Resource'а из manifest'а.\n * Архитектура по docs/design_handoff_laravel_admin/screens-shell.jsx (Resource List).\n *\n * Композиция:\n * - Page header (title + count + actions cluster)\n * - Filter bar с search + chips\n * - Bulk toolbar (заменяет filter bar при selectedCount > 0)\n * - UidTable с manifest.columns\n * - States: loading (UidSkeleton ×8) / empty (UidEmptyState) / error (UidErrorState)\n * - UidPagination внизу\n *\n * Host рендерит page через router. resource-slug приходит из props (либо\n * из route.params).\n */\nimport { computed, nextTick, onMounted, watch } from 'vue'\nimport {\n UidButton,\n UidEmptyState,\n UidErrorState,\n UidPagination,\n UidSkeleton,\n UidTable,\n type UidTableColumn,\n} from '@dskripchenko/ui'\nimport { useResourceIndexStore } from '../../stores/resourceIndex'\nimport { useManifestStore } from '../../stores/manifest'\nimport { useNavigationStore } from '../../stores/navigation'\nimport { formatCell, type CellMeta } from './cellFormat'\n\ninterface Props {\n /** Slug ресурса (users/articles/etc). */\n slug: string\n /** Заголовок страницы. Если не задан — берётся из manifest'а. */\n title?: string | null\n /** Подпись под заголовком (например \"Аналитика контента\"). */\n subtitle?: string | null\n /** Текст primary-кнопки «Создать». */\n createLabel?: string\n /** Имя router-route для action «Создать». */\n createRouteName?: string | null\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n title: null,\n subtitle: null,\n createLabel: 'Создать',\n createRouteName: null,\n})\n\nconst emit = defineEmits<{\n /** Bulk-action triggered с текущим Set'ом id. */\n 'bulk-action': [action: string, ids: Array<string | number>]\n /** Click на row — host решает (push edit / open view). */\n 'row-click': [row: Record<string, unknown>]\n}>()\n\nconst index = useResourceIndexStore()\nconst manifest = useManifestStore()\nconst nav = useNavigationStore()\n\nconst resourceMeta = computed(() => manifest.getResource(props.slug))\n\nconst displayTitle = computed(\n () => props.title ?? resourceMeta.value?.label ?? props.slug,\n)\n\nconst columns = computed<UidTableColumn[]>(() => {\n const cols = resourceMeta.value?.columns ?? []\n return cols.map((c) => {\n const col = c as Record<string, unknown>\n return {\n key: String(col.key ?? col.name ?? ''),\n label: String(col.label ?? col.name ?? ''),\n sortable: Boolean(col.sortable),\n align: (col.align as 'left' | 'center' | 'right' | undefined) ?? 'left',\n width: typeof col.width === 'string' ? col.width : undefined,\n }\n }).filter((c) => c.key)\n})\n\n// Колоночная meta (preset / format / currency / etc.) из manifest'а.\n// Используется для formatCell (datetime → 'd.m.Y H:i:s', money → '{val} {ccy}').\nconst columnMeta = computed<Record<string, { preset?: string; meta: CellMeta }>>(() => {\n const cols = resourceMeta.value?.columns ?? []\n const result: Record<string, { preset?: string; meta: CellMeta }> = {}\n for (const c of cols) {\n const col = c as Record<string, unknown>\n const key = String(col.key ?? col.name ?? '')\n if (!key) continue\n result[key] = {\n preset: typeof col.preset === 'string' ? col.preset : undefined,\n meta: (col.meta as CellMeta) ?? {},\n }\n }\n return result\n})\n\nfunction renderCell(key: string, slotProps: unknown): string {\n // UidTable scoped-slot передаёт {row: actualRow}.\n const row = (slotProps as { row?: Record<string, unknown> } | undefined)?.row\n const value = row?.[key]\n const m = columnMeta.value[key]\n return formatCell(value, m?.preset, m?.meta ?? {})\n}\n\nfunction rowFromSlot(slotProps: unknown): Record<string, unknown> | undefined {\n return (slotProps as { row?: Record<string, unknown> } | undefined)?.row\n}\n\n/**\n * Показывать ли filter-bar:\n * - если есть данные → всегда (search + фильтры внутри);\n * - если данных нет, но есть активный search/filter → ДА (чтобы пользователь\n * мог сбросить и снова увидеть items);\n * - если данных нет и фильтры/поиск пустые → НЕТ (initial empty state).\n */\nconst hasActiveFilters = computed<boolean>(\n () => index.search !== '' || Object.keys(index.filters).length > 0,\n)\nconst showFilterBar = computed<boolean>(\n () => !index.isEmpty || hasActiveFilters.value,\n)\n\nconst totalLabel = computed(() => {\n const t = index.meta.total\n if (t === 0) return ''\n return `${index.items.length} из ${t}`\n})\n\n/**\n * Обёртка над index.load — увеличивает navigation pending counter\n * (top loading-bar) на время запроса. router.beforeEach уже инкрементирует\n * counter при start navigation; этот wrap держит bar до конца data-fetch'а.\n */\nasync function loadWithProgress(): Promise<void> {\n nav.start()\n try {\n await index.load()\n } catch {\n // silent; ошибка отображается в hasError state\n } finally {\n nav.end()\n }\n}\n\nonMounted(async () => {\n index.setSlug(props.slug)\n if (manifest.manifest === null) {\n await manifest.load().catch(() => undefined)\n }\n await loadWithProgress()\n})\n\nwatch(\n () => props.slug,\n async (next, prev) => {\n if (next === prev) return\n index.setSlug(next)\n await loadWithProgress()\n },\n)\n\nasync function onSortKeyUpdate(key: string | null): Promise<void> {\n // UidTable управляет своим 3-режимным cycle; здесь только применяем итог.\n // sortDirection приходит отдельным событием — apply через setSort одним\n // вызовом (после nextTick — Vue batches событий).\n await nextTick()\n await index.setSort(key, index.sortDirection)\n}\n\nasync function onSortDirUpdate(dir: 'asc' | 'desc' | null): Promise<void> {\n await nextTick()\n await index.setSort(index.sortKey, dir)\n}\n\nfunction onSelectionUpdate(next: Set<string | number>): void {\n index.selection = next\n}\n\nasync function onPageChange(page: number): Promise<void> {\n await index.setPage(page)\n}\n\nfunction onRowClick(row: Record<string, unknown>): void {\n emit('row-click', row)\n}\n\nfunction bulkAction(action: string): void {\n emit('bulk-action', action, [...index.selection])\n}\n\nasync function retryLoad(): Promise<void> {\n await index.load().catch(() => undefined)\n}\n</script>\n\n<template>\n <section class=\"admin-page admin-resource-index\">\n <!-- Header -->\n <header class=\"admin-page__hd\">\n <div class=\"admin-page__title-wrap\">\n <h1 class=\"admin-page__title\">{{ displayTitle }}</h1>\n <div v-if=\"subtitle || totalLabel\" class=\"admin-page__count\">\n <template v-if=\"subtitle\">{{ subtitle }}</template>\n <template v-if=\"subtitle && totalLabel\"> · </template>\n <template v-if=\"totalLabel\">{{ totalLabel }}</template>\n </div>\n </div>\n <div class=\"admin-page__actions\">\n <slot name=\"actions\" />\n <UidButton\n v-if=\"createRouteName\"\n variant=\"primary\"\n @click=\"$router.push({ name: createRouteName })\"\n >\n {{ createLabel }}\n </UidButton>\n </div>\n </header>\n\n <!-- Bulk toolbar (selection > 0) ИЛИ filter bar -->\n <div v-if=\"index.hasSelection\" class=\"admin-bulk-toolbar\" role=\"toolbar\">\n <span class=\"admin-bulk-toolbar__count\">\n Выбрано <b>{{ index.selectedCount }}</b>\n </span>\n <span class=\"admin-bulk-toolbar__divider\" />\n <UidButton size=\"sm\" variant=\"ghost\" @click=\"bulkAction('publish')\">Опубликовать</UidButton>\n <UidButton size=\"sm\" variant=\"ghost\" @click=\"bulkAction('archive')\">Архивировать</UidButton>\n <UidButton size=\"sm\" variant=\"ghost\" @click=\"bulkAction('export')\">Экспорт</UidButton>\n <UidButton size=\"sm\" variant=\"danger\" @click=\"bulkAction('delete')\">Удалить</UidButton>\n <span class=\"admin-bulk-toolbar__spacer\" />\n <UidButton size=\"sm\" variant=\"ghost\" @click=\"index.clearSelection\">\n Снять выделение\n </UidButton>\n </div>\n\n <div v-else-if=\"showFilterBar\" class=\"admin-filter-bar\">\n <input\n :value=\"index.search\"\n type=\"search\"\n placeholder=\"Поиск…\"\n class=\"admin-filter-bar__search\"\n @keydown.enter=\"(e) => index.setSearch((e.target as HTMLInputElement).value)\"\n />\n <slot name=\"filters\" :filters=\"index.filters\" :set-filter=\"index.setFilter\" />\n <span class=\"admin-filter-bar__spacer\" />\n <UidButton\n v-if=\"Object.keys(index.filters).length > 0\"\n size=\"sm\"\n variant=\"ghost\"\n @click=\"index.clearFilters\"\n >\n Сброс\n </UidButton>\n </div>\n\n <!-- States -->\n <!-- Initial-loading стейт (между setSlug и первым успехом load).\n Показываем placeholder вместо UidTable — иначе сама таблица\n рендерит \"Нет данных\" empty state, что создаёт flicker\n \"Нет данных → реальные строки\" при navigation. -->\n <div\n v-if=\"index.loading && index.items.length === 0\"\n class=\"admin-resource-index__loading\"\n >\n <UidSkeleton\n v-if=\"index.slowLoading\"\n v-for=\"i in 8\"\n :key=\"i\"\n height=\"40px\"\n />\n </div>\n <UidErrorState\n v-else-if=\"index.hasError\"\n title=\"Не удалось загрузить данные\"\n :description=\"index.error?.message ?? 'Попробуйте обновить страницу.'\"\n class=\"admin-resource-index__state\"\n >\n <template #actions>\n <UidButton variant=\"primary\" @click=\"retryLoad\">Обновить</UidButton>\n </template>\n </UidErrorState>\n <UidEmptyState\n v-else-if=\"index.isEmpty\"\n title=\"Пока пусто\"\n description=\"Создайте первую запись или измените фильтры.\"\n class=\"admin-resource-index__state\"\n >\n <template #actions>\n <UidButton\n v-if=\"createRouteName\"\n variant=\"primary\"\n @click=\"$router.push({ name: createRouteName })\"\n >\n {{ createLabel }}\n </UidButton>\n </template>\n </UidEmptyState>\n\n <!-- Таблица — UidTable native selection (UidTable.selectable + selection prop). -->\n <div v-else class=\"admin-resource-index__table\">\n <UidTable\n :columns=\"columns\"\n :data=\"index.items\"\n :sort-key=\"index.sortKey\"\n :sort-direction=\"index.sortDirection\"\n selectable\n :selection=\"index.selection\"\n :row-key=\"(row) => index.rowId(row)\"\n @update:sort-key=\"onSortKeyUpdate\"\n @update:sort-direction=\"onSortDirUpdate\"\n @update:selection=\"onSelectionUpdate\"\n @row-click=\"onRowClick\"\n >\n <template\n v-for=\"col in columns\"\n #[col.key]=\"slotProps\"\n :key=\"col.key\"\n >\n <slot :name=\"`cell-${col.key}`\" :row=\"rowFromSlot(slotProps)\">\n {{ renderCell(col.key, slotProps) }}\n </slot>\n </template>\n </UidTable>\n </div>\n\n <!-- Pagination -->\n <footer\n v-if=\"!index.loading && !index.hasError && !index.isEmpty\"\n class=\"admin-resource-index__footer\"\n >\n <UidPagination\n :model-value=\"index.meta.page\"\n :total=\"index.meta.total\"\n :per-page=\"index.meta.per_page\"\n @update:model-value=\"onPageChange\"\n />\n </footer>\n </section>\n</template>\n\n<style>\n.admin-resource-index__loading {\n display: flex;\n flex-direction: column;\n gap: var(--uid-space-sm);\n margin-top: var(--uid-space-md);\n /* min-height предотвращает layout-collapse при первом mount'е,\n когда slowLoading ещё false (быстрый запрос — placeholder пустой). */\n min-height: 320px;\n}\n.admin-resource-index__state {\n margin-top: var(--uid-space-xl);\n}\n.admin-resource-index__table {\n /* table визуально приклеена к filter-bar / bulk-toolbar сверху —\n убираем gap, скругляем только нижние углы у table-wrap'а. */\n margin-top: 0;\n}\n.admin-resource-index__table .uid-table-wrap {\n border: 1px solid var(--uid-border-subtle);\n border-top: 0;\n border-radius: 0 0 var(--uid-radius-lg) var(--uid-radius-lg);\n}\n.admin-resource-index__footer {\n display: flex;\n justify-content: flex-end;\n padding: var(--uid-space-md) 0;\n}\n\n/* Filter bar */\n.admin-filter-bar {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--uid-space-sm);\n padding: var(--uid-space-sm) var(--uid-space-md);\n border: 1px solid var(--uid-border-subtle);\n background: var(--uid-surface-raised);\n border-radius: var(--uid-radius-lg) var(--uid-radius-lg) 0 0;\n border-bottom: 0;\n margin-top: var(--uid-space-md);\n}\n.admin-filter-bar__search {\n flex: 1;\n min-width: 200px;\n max-width: 320px;\n height: 28px;\n padding: 0 var(--uid-space-sm);\n border: 1px solid var(--uid-border-subtle);\n background: var(--uid-surface-base);\n border-radius: var(--uid-radius-md);\n color: var(--uid-text-primary);\n font-size: 13px;\n outline: none;\n}\n.admin-filter-bar__search:focus {\n border-color: var(--uid-accent);\n outline: 2px solid color-mix(in srgb, var(--uid-accent) 18%, transparent);\n}\n.admin-filter-bar__spacer { flex: 1; }\n\n/* Bulk toolbar — dark zinc-900 surface, заменяет filter bar */\n.admin-bulk-toolbar {\n display: flex;\n align-items: center;\n gap: var(--uid-space-sm);\n padding: var(--uid-space-sm) var(--uid-space-md);\n background: var(--uid-color-zinc-900, #18181b);\n color: var(--uid-color-zinc-100, #f4f4f5);\n border-radius: var(--uid-radius-lg) var(--uid-radius-lg) 0 0;\n border: 1px solid var(--uid-color-zinc-900, #18181b);\n border-bottom: 0;\n margin-top: var(--uid-space-md);\n}\n.admin-bulk-toolbar__count { font-size: 13px; }\n.admin-bulk-toolbar__count b { font-weight: var(--uid-font-weight-semibold); }\n.admin-bulk-toolbar__divider {\n width: 1px;\n height: 20px;\n background: rgba(255, 255, 255, 0.15);\n}\n.admin-bulk-toolbar__spacer { flex: 1; }\n.admin-bulk-toolbar .uid-button {\n background: transparent;\n border-color: rgba(255, 255, 255, 0.15);\n color: var(--uid-color-zinc-100, #f4f4f5);\n}\n.admin-bulk-toolbar .uid-button:hover:not([disabled]) {\n background: rgba(255, 255, 255, 0.08);\n}\n.admin-bulk-toolbar .uid-button--danger {\n color: var(--uid-color-rose-400, #fb7185);\n}\n\n/* Selected row tint */\n.admin-resource-index__row--selected {\n background: color-mix(in srgb, var(--uid-accent) 8%, transparent);\n}\n</style>\n","/**\n * useResourceFormStore — state для Resource Create/Edit/View screens.\n *\n * Управляет:\n * - mode ('create' | 'edit' | 'view')\n * - record (raw из API), state (working copy в form-state, но мы держим\n * reference на initial для unsaved-changes detection)\n * - errors (field-keyed) — устанавливаются при ValidationError\n * - loading/saving/deleting — для disable submit / show spinner\n * - dirty (computed) — есть ли несохранённые изменения\n *\n * Endpoints (laravel-admin contract):\n * GET /{slug}/read — fetch one (id в query)\n * POST /{slug}/create\n * POST /{slug}/update\n * POST /{slug}/delete\n */\n\nimport { defineStore } from 'pinia'\nimport { computed, ref } from 'vue'\nimport { getAdminClient } from './registry'\nimport { ApiError, ValidationError } from '../api/errors'\n\nexport type FormMode = 'create' | 'edit' | 'view'\n\ninterface ReadResponse {\n // backend ResourceController::read возвращает payload {record}.\n record: Record<string, unknown>\n}\n\ninterface SaveResponse {\n // backend create/update возвращает payload {record, redirect_url, message}.\n record?: Record<string, unknown>\n id?: string | number\n redirect_url?: string\n message?: string\n}\n\nexport const useResourceFormStore = defineStore('admin-resource-form', () => {\n const slug = ref<string | null>(null)\n const mode = ref<FormMode>('create')\n const recordId = ref<string | number | null>(null)\n\n /** Текущее состояние формы — мутируется через setField. */\n const state = ref<Record<string, unknown>>({})\n /** Snapshot изначальных значений (после load) — для dirty-detection. */\n const initial = ref<Record<string, unknown>>({})\n\n /** Field-keyed errors. Очищаются при successful save. */\n const errors = ref<Record<string, string[]>>({})\n\n const loading = ref(false)\n const saving = ref(false)\n const deleting = ref(false)\n const error = ref<Error | null>(null)\n\n const isCreate = computed(() => mode.value === 'create')\n const isEdit = computed(() => mode.value === 'edit')\n const isView = computed(() => mode.value === 'view')\n const hasError = computed(() => error.value !== null)\n\n /** Dirty: state отличается от initial хотя бы по одному ключу. */\n const isDirty = computed(() => {\n const a = state.value\n const b = initial.value\n const keys = new Set([...Object.keys(a), ...Object.keys(b)])\n for (const k of keys) {\n if (!Object.is(a[k], b[k])) {\n // Простое сравнение скаляров; объекты/массивы сравниваем JSON-сериализацией.\n if (typeof a[k] === 'object' || typeof b[k] === 'object') {\n if (JSON.stringify(a[k]) !== JSON.stringify(b[k])) return true\n } else {\n return true\n }\n }\n }\n return false\n })\n\n /** In-place мутация reactive-объекта — сохраняет identity для provide/inject. */\n function replaceObject(target: Record<string, unknown>, next: Record<string, unknown>): void {\n for (const k of Object.keys(target)) delete target[k]\n Object.assign(target, next)\n }\n\n function reset(): void {\n replaceObject(state.value, {})\n replaceObject(initial.value, {})\n errors.value = {}\n loading.value = false\n saving.value = false\n deleting.value = false\n error.value = null\n recordId.value = null\n }\n\n /** Подготовить store для create-mode на ресурсе. */\n function prepareCreate(resourceSlug: string, defaults: Record<string, unknown> = {}): void {\n slug.value = resourceSlug\n mode.value = 'create'\n recordId.value = null\n replaceObject(state.value, defaults)\n replaceObject(initial.value, defaults)\n errors.value = {}\n error.value = null\n }\n\n /** Загрузить запись для edit либо view-режима. */\n async function load(\n resourceSlug: string,\n id: string | number,\n targetMode: 'edit' | 'view' = 'edit',\n ): Promise<void> {\n slug.value = resourceSlug\n mode.value = targetMode\n recordId.value = id\n loading.value = true\n error.value = null\n errors.value = {}\n\n try {\n const client = getAdminClient()\n const res = await client.get<ReadResponse>(`/${resourceSlug}/read`, {\n params: { id },\n })\n replaceObject(state.value, res.record)\n replaceObject(initial.value, res.record)\n } catch (err) {\n error.value = err instanceof Error ? err : new Error(String(err))\n throw err\n } finally {\n loading.value = false\n }\n }\n\n /** Установить значение поля (через FormState composable обычно). */\n function setField(name: string, value: unknown): void {\n state.value[name] = value\n if (errors.value[name]) {\n // Очищаем ошибку конкретного поля при изменении (стандартный UX).\n const next = { ...errors.value }\n delete next[name]\n errors.value = next\n }\n }\n\n function setErrors(next: Record<string, string[]>): void {\n errors.value = { ...next }\n }\n\n function clearErrors(): void {\n errors.value = {}\n }\n\n /**\n * Сохранить. На create — POST /create; на edit — POST /update с id.\n * Возвращает new id (для post-create редиректа).\n */\n async function save(): Promise<string | number> {\n if (!slug.value) throw new Error('useResourceFormStore.save() before slug set')\n if (saving.value) throw new Error('Already saving')\n\n saving.value = true\n error.value = null\n errors.value = {}\n\n try {\n const client = getAdminClient()\n const url =\n mode.value === 'create'\n ? `/${slug.value}/create`\n : `/${slug.value}/update`\n\n const payload =\n mode.value === 'create'\n ? state.value\n : { id: recordId.value, ...state.value }\n\n const res = await client.post<SaveResponse>(url, payload)\n // Backend отдаёт `record: {id, ...}`. Старый формат `{id}` тоже поддерживаем.\n const newId = (res.record?.id ?? res.id) as string | number | undefined\n if (newId === undefined) {\n throw new Error('save: backend response does not contain record.id')\n }\n recordId.value = newId\n // После успешного save обновим initial = state, чтобы dirty=false.\n replaceObject(initial.value, { ...state.value })\n mode.value = 'edit'\n return newId\n } catch (err) {\n if (err instanceof ValidationError) {\n errors.value = { ...err.fields }\n } else if (err instanceof ApiError) {\n error.value = err\n } else if (err instanceof Error) {\n error.value = err\n }\n throw err\n } finally {\n saving.value = false\n }\n }\n\n /** Удалить текущую запись (только в edit-mode). */\n async function destroy(): Promise<void> {\n if (!slug.value || recordId.value === null) {\n throw new Error('Nothing to delete')\n }\n if (deleting.value) throw new Error('Already deleting')\n\n deleting.value = true\n error.value = null\n try {\n const client = getAdminClient()\n await client.post(`/${slug.value}/delete`, { id: recordId.value })\n } catch (err) {\n if (err instanceof Error) error.value = err\n throw err\n } finally {\n deleting.value = false\n }\n }\n\n return {\n // state\n slug,\n mode,\n recordId,\n state,\n initial,\n errors,\n loading,\n saving,\n deleting,\n error,\n // getters\n isCreate,\n isEdit,\n isView,\n isDirty,\n hasError,\n // actions\n reset,\n prepareCreate,\n load,\n setField,\n setErrors,\n clearErrors,\n save,\n destroy,\n }\n})\n","/**\n * Generic factory для component-registry'ов (fields, layouts, widgets,\n * infolist entries и т.п.).\n *\n * Все component-registry в admin'е по сути одинаковы: keyed Map<string, Component>\n * + register/get/has/list/clear/registerBundle. Этот factory вытаскивает паттерн\n * один раз; конкретные модули просто переименовывают экспорты.\n *\n * const reg = createComponentRegistry<Component>()\n * export const registerWidget = reg.register\n * export const getWidget = reg.get\n * // ...\n */\n\nexport interface ComponentRegistry<T> {\n register(type: string, value: T): void\n get(type: string): T | null\n has(type: string): boolean\n list(): string[]\n clear(): void\n registerBundle(bundle: Record<string, T>): void\n}\n\nexport function createComponentRegistry<T>(): ComponentRegistry<T> {\n const store = new Map<string, T>()\n\n return {\n register(type, value) {\n store.set(type, value)\n },\n get(type) {\n return store.get(type) ?? null\n },\n has(type) {\n return store.has(type)\n },\n list() {\n return [...store.keys()]\n },\n clear() {\n store.clear()\n },\n registerBundle(bundle) {\n for (const [type, value] of Object.entries(bundle)) {\n store.set(type, value)\n }\n },\n }\n}\n","/**\n * Реестр Vue-компонентов для JSON-driven рендеринга.\n *\n * Содержит две Map'ы — для `field`-типов (input'ы, контролы) и для\n * `layout`-типов (контейнеры). LayoutRenderer и FieldRenderer резолвят тип\n * через эти реестры; host-проект может зарегистрировать кастомные компоненты\n * через `registerField()` / `registerLayout()`.\n *\n * Singleton — один регистр на admin-instance. Тестовый сценарий —\n * `clearRegistry()` + `registerField()` в `beforeEach`.\n */\n\nimport type { Component } from 'vue'\nimport { createComponentRegistry } from '../createComponentRegistry'\n\nconst fields = createComponentRegistry<Component>()\nconst layouts = createComponentRegistry<Component>()\n\nexport const registerField = fields.register\nexport const getField = fields.get\nexport const hasField = fields.has\nexport const listFields = fields.list\n\nexport const registerLayout = layouts.register\nexport const getLayout = layouts.get\nexport const hasLayout = layouts.has\nexport const listLayouts = layouts.list\n\n/** Очистить оба реестра. Используется в тестах. */\nexport function clearRegistry(): void {\n fields.clear()\n layouts.clear()\n}\n\n/**\n * Зарегистрировать сразу несколько компонентов.\n *\n * registerComponents({\n * fields: { text: TextField, select: SelectField },\n * layouts: { rows: RowsLayout, tabs: TabsLayout },\n * })\n */\nexport interface ComponentBundle {\n fields?: Record<string, Component>\n layouts?: Record<string, Component>\n}\n\nexport function registerComponents(bundle: ComponentBundle): void {\n if (bundle.fields) fields.registerBundle(bundle.fields)\n if (bundle.layouts) layouts.registerBundle(bundle.layouts)\n}\n","<script setup lang=\"ts\">\n/**\n * Fallback на missing field-registration. Видимый dev-warn вместо silent fail —\n * host-проект сразу замечает unregistered field-type.\n */\nimport { UidAlert } from '@dskripchenko/ui'\n\ninterface Props {\n type: string\n name?: string\n}\ndefineProps<Props>()\n</script>\n\n<template>\n <UidAlert variant=\"warning\">\n <template #title>Неизвестный тип поля: {{ type }}</template>\n <template v-if=\"name\">\n <code>{{ name }}</code> — зарегистрируйте field-компонент через\n <code>registerField('{{ type }}', YourComponent)</code>.\n </template>\n </UidAlert>\n</template>\n","<script setup lang=\"ts\">\n/**\n * FieldRenderer резолвит конкретный field-компонент по `node.type` из реестра\n * и forwards остальные props через v-bind.\n *\n * Узлы манифеста имеют форму:\n * { type: 'text', name: 'title', label: 'Заголовок', required: true, ... }\n *\n * Field хранит value через provide/inject form-state — узлу не передаётся\n * `modelValue` напрямую. Это позволяет строить произвольно-глубокие layout'ы\n * без явного proppin'га state'а.\n */\nimport { computed } from 'vue'\nimport { getField } from './registry'\nimport UnknownField from '../fields/UnknownField.vue'\n\nexport interface FieldNode extends Record<string, unknown> {\n type: string\n name: string\n}\n\ninterface Props {\n node: FieldNode\n}\n\nconst props = defineProps<Props>()\nconst component = computed(() => getField(props.node.type))\nconst fieldProps = computed(() => {\n const { type: _type, ...rest } = props.node\n return rest\n})\n</script>\n\n<template>\n <component :is=\"component\" v-if=\"component\" v-bind=\"fieldProps\" />\n <UnknownField v-else :type=\"node.type\" :name=\"node.name\" />\n</template>\n","<script setup lang=\"ts\">\n/**\n * Универсальный рекурсивный renderer manifest-узлов.\n *\n * Узел вида `{ kind: 'field', type: 'text', name: 'title', ... }` рендерится\n * через FieldRenderer. Узел вида `{ kind: 'layout', type: 'rows', items: [...] }`\n * — через зарегистрированный layout-компонент с children-списком.\n *\n * Для совместимости со старыми JSON'ами без `kind` — если type есть в\n * field-registry, считаем field; если в layout-registry — считаем layout;\n * иначе — UnknownField fallback.\n */\nimport { computed } from 'vue'\nimport { getField, getLayout } from './registry'\nimport FieldRenderer, { type FieldNode } from './FieldRenderer.vue'\nimport UnknownField from '../fields/UnknownField.vue'\n\nexport interface LayoutNode extends Record<string, unknown> {\n type: string\n kind?: 'field' | 'layout'\n items?: LayoutNode[]\n}\n\ninterface Props {\n node: LayoutNode\n}\nconst props = defineProps<Props>()\n\ntype Resolved =\n | { kind: 'field' }\n | { kind: 'layout'; component: ReturnType<typeof getLayout> }\n | { kind: 'unknown' }\n\nconst resolved = computed<Resolved>(() => {\n // Явный hint через `kind` всегда приоритетнее.\n if (props.node.kind === 'field') {\n return { kind: 'field' }\n }\n if (props.node.kind === 'layout') {\n const component = getLayout(props.node.type)\n return component ? { kind: 'layout', component } : { kind: 'unknown' }\n }\n // Auto-detect.\n const layoutComponent = getLayout(props.node.type)\n if (layoutComponent) return { kind: 'layout', component: layoutComponent }\n if (getField(props.node.type)) return { kind: 'field' }\n return { kind: 'unknown' }\n})\n\nconst layoutProps = computed(() => {\n const { type: _type, kind: _kind, ...rest } = props.node\n return rest\n})\n\nconst fieldNode = computed<FieldNode>(() => props.node as unknown as FieldNode)\n</script>\n\n<template>\n <component\n :is=\"resolved.component\"\n v-if=\"resolved.kind === 'layout' && resolved.component\"\n v-bind=\"layoutProps\"\n />\n <FieldRenderer v-else-if=\"resolved.kind === 'field'\" :node=\"fieldNode\" />\n <UnknownField v-else :type=\"node.type\" :name=\"(node.name as string | undefined)\" />\n</template>\n","<script setup lang=\"ts\">\n/**\n * ResourceFormPage — unified create/edit page для Resource'а.\n *\n * Архитектура по docs/design_handoff_laravel_admin/screens-shell.jsx\n * (Resource Form):\n * - Header: back-breadcrumb + title + status-badge + actions\n * (Preview / Удалить / Сохранить-primary)\n * - Body: layout из manifest.fields (LayoutRenderer + provideFormState)\n * - Sticky save-bar внизу с unsaved-changes hint\n *\n * Mode определяется наличием `id`-prop'а: id=null → create, иначе → edit.\n *\n * Form-state предоставляется через provideFormState из useResourceFormStore.state.\n * FieldRenderer'ы внутри форм автоматически подхватывают через useFormState.\n */\nimport { computed, onMounted, watch } from 'vue'\nimport { useRouter } from 'vue-router'\nimport {\n UidAlert,\n UidBadge,\n UidButton,\n UidCard,\n UidSkeleton,\n} from '@dskripchenko/ui'\nimport { useResourceFormStore } from '../../stores/resourceForm'\nimport { useManifestStore } from '../../stores/manifest'\nimport { provideFormState } from '../render/formState'\nimport LayoutRenderer from '../render/LayoutRenderer.vue'\nimport type { LayoutNode } from '../render/LayoutRenderer.vue'\n\ninterface Props {\n /** Slug ресурса (articles/users/etc). */\n slug: string\n /** ID записи. null/undefined → create-mode; число/строка → edit. */\n id?: string | number | null\n /** Имя router-route на index page (для back-redirect после save/delete). */\n indexRouteName?: string\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n id: null,\n indexRouteName: 'admin.home',\n})\n\nconst form = useResourceFormStore()\nconst manifest = useManifestStore()\nconst router = useRouter()\n\n// provideFormState ОБЯЗАН вызываться в setup() — связываем со store.state.\n// Сам form-context форвардит setField → store.setField (с auto-clear errors).\nconst ctx = provideFormState(form.state, form.errors)\n\n// Watcher: при изменениях через ctx.setField (обёртка которой) — синхронизируем\n// в store, чтобы isDirty работало. Поскольку state.value === ctx.state (тот же\n// reactive object — provideFormState не делает копию), мутации видны напрямую\n// в store. setField'у в ctx достаточно.\nwatch(\n () => form.errors,\n (next) => {\n // При обновлении store.errors — выкидываем в form-context.\n ctx.setErrors({ ...next })\n },\n)\n\nconst resourceMeta = computed(() => manifest.getResource(props.slug))\n\nconst layoutNodes = computed<LayoutNode[]>(\n () => resourceMeta.value?.fields ?? [],\n)\n\nconst titleLabel = computed(() => {\n if (form.isCreate) return `Создать: ${resourceMeta.value?.label ?? props.slug}`\n return `${resourceMeta.value?.label ?? props.slug}: запись #${props.id}`\n})\n\nconst statusValue = computed<string | null>(() => {\n const v = form.state.status\n return typeof v === 'string' ? v : null\n})\n\nconst statusBadgeVariant = computed<'success' | 'warning' | 'danger' | 'default'>(() => {\n switch (statusValue.value) {\n case 'published': return 'success'\n case 'review':\n case 'draft': return 'warning'\n case 'archived': return 'danger'\n default: return 'default'\n }\n})\n\nonMounted(async () => {\n if (manifest.manifest === null) {\n await manifest.load().catch(() => undefined)\n }\n if (props.id !== null && props.id !== undefined) {\n await form.load(props.slug, props.id, 'edit').catch(() => undefined)\n } else {\n form.prepareCreate(props.slug)\n }\n})\n\nwatch(\n () => [props.slug, props.id] as const,\n async ([nextSlug, nextId]) => {\n if (nextId !== null && nextId !== undefined) {\n await form.load(nextSlug, nextId, 'edit').catch(() => undefined)\n } else {\n form.prepareCreate(nextSlug)\n }\n },\n)\n\nasync function onSave(): Promise<void> {\n try {\n const newId = await form.save()\n if (form.isCreate) {\n // create → редирект на edit с новым id (host route'ит).\n void router.push({\n name: `admin.resource.${props.slug}.edit`,\n params: { id: newId },\n }).catch(() => undefined)\n }\n } catch {\n // ValidationError уже превратился в form.errors через store; остальные\n // ошибки попали в form.error и отрисуются как UidAlert ниже.\n }\n}\n\nasync function onDelete(): Promise<void> {\n if (!confirm('Удалить запись?')) return\n await form.destroy().catch(() => undefined)\n if (!form.hasError) {\n void router.push({ name: props.indexRouteName }).catch(() => undefined)\n }\n}\n\nfunction onCancel(): void {\n if (form.isDirty && !confirm('Несохранённые изменения будут потеряны. Продолжить?')) {\n return\n }\n void router.push({ name: props.indexRouteName }).catch(() => undefined)\n}\n</script>\n\n<template>\n <section class=\"admin-page admin-resource-form\">\n <header class=\"admin-page__hd\">\n <div class=\"admin-page__title-wrap\">\n <a class=\"admin-resource-form__back\" @click=\"onCancel\">← Назад</a>\n <h1 class=\"admin-page__title\">{{ titleLabel }}</h1>\n <UidBadge v-if=\"statusValue\" :variant=\"statusBadgeVariant\">\n {{ statusValue }}\n </UidBadge>\n </div>\n <div class=\"admin-page__actions\">\n <UidButton\n variant=\"ghost\"\n :disabled=\"form.saving || form.deleting\"\n @click=\"onCancel\"\n >\n Отмена\n </UidButton>\n <UidButton\n v-if=\"form.isEdit\"\n variant=\"danger\"\n :disabled=\"form.saving || form.deleting\"\n :loading=\"form.deleting\"\n @click=\"onDelete\"\n >\n Удалить\n </UidButton>\n <UidButton\n variant=\"primary\"\n :disabled=\"form.saving || form.loading\"\n :loading=\"form.saving\"\n @click=\"onSave\"\n >\n {{ form.isCreate ? 'Создать' : 'Сохранить' }}\n </UidButton>\n </div>\n </header>\n\n <UidAlert\n v-if=\"form.hasError\"\n variant=\"danger\"\n class=\"admin-resource-form__alert\"\n role=\"alert\"\n >\n {{ form.error?.message ?? 'Не удалось сохранить запись' }}\n </UidAlert>\n\n <!-- Loading state — UidSkeleton imitates form-rows -->\n <div v-if=\"form.loading\" class=\"admin-resource-form__loading\">\n <UidSkeleton v-for=\"i in 6\" :key=\"i\" height=\"40px\" />\n </div>\n\n <!-- Body: layout из manifest -->\n <UidCard v-else padding=\"md\" class=\"admin-resource-form__body\">\n <LayoutRenderer\n v-for=\"(node, idx) in layoutNodes\"\n :key=\"idx\"\n :node=\"node\"\n />\n </UidCard>\n\n <!-- Sticky save-bar — показывается при unsaved-changes -->\n <div v-if=\"form.isDirty && !form.loading\" class=\"admin-resource-form__savebar\">\n <span class=\"admin-resource-form__savebar-hint\">\n Есть несохранённые изменения\n </span>\n <UidButton variant=\"ghost\" size=\"sm\" @click=\"onCancel\">Отмена</UidButton>\n <UidButton\n variant=\"primary\"\n size=\"sm\"\n :loading=\"form.saving\"\n :disabled=\"form.saving\"\n @click=\"onSave\"\n >\n Сохранить\n </UidButton>\n </div>\n </section>\n</template>\n\n<style>\n.admin-resource-form__back {\n font-size: var(--uid-font-size-xs);\n color: var(--uid-text-secondary);\n cursor: pointer;\n text-decoration: none;\n display: inline-block;\n margin-bottom: 4px;\n}\n.admin-resource-form__back:hover { color: var(--uid-text-primary); }\n\n.admin-resource-form__alert {\n margin-bottom: var(--uid-space-md);\n}\n.admin-resource-form__loading {\n display: flex;\n flex-direction: column;\n gap: var(--uid-space-sm);\n}\n.admin-resource-form__body { margin-bottom: var(--uid-space-2xl); }\n\n.admin-resource-form__savebar {\n position: sticky;\n bottom: 0;\n display: flex;\n align-items: center;\n gap: var(--uid-space-sm);\n padding: var(--uid-space-sm) var(--uid-space-md);\n background: var(--uid-surface-raised);\n border-top: 1px solid var(--uid-border-default);\n border-radius: var(--uid-radius-md);\n box-shadow: var(--uid-shadow-md);\n margin-top: var(--uid-space-md);\n}\n.admin-resource-form__savebar-hint {\n flex: 1;\n font-size: 13px;\n color: var(--uid-warning);\n}\n</style>\n","/**\n * Реестр infolist-entry-компонентов.\n *\n * Аналог field-registry, но для read-only display'я. Узлы манифеста имеют\n * форму:\n * { type: 'text', name: 'title', label: 'Заголовок', value?: '...' }\n * либо без явного `value` — тогда entry извлекает `record[name]` из\n * provide'нутого `record`.\n *\n * Host регистрирует кастомные entry через `registerInfolistEntry()` /\n * `registerInfolistEntries()` bundle.\n */\n\nimport type { Component } from 'vue'\nimport { createComponentRegistry } from '../createComponentRegistry'\n\nconst entries = createComponentRegistry<Component>()\n\nexport const registerInfolistEntry = entries.register\nexport const getInfolistEntry = entries.get\nexport const hasInfolistEntry = entries.has\nexport const listInfolistEntries = entries.list\nexport const clearInfolistRegistry = entries.clear\nexport const registerInfolistEntries = entries.registerBundle\n","<script setup lang=\"ts\">\nimport { UidAlert } from '@dskripchenko/ui'\n\ninterface Props {\n type: string\n name?: string\n}\ndefineProps<Props>()\n</script>\n\n<template>\n <UidAlert variant=\"warning\">\n <template #title>Неизвестный тип infolist-entry: {{ type }}</template>\n Зарегистрируйте через <code>registerInfolistEntry('{{ type }}', YourComponent)</code>.\n </UidAlert>\n</template>\n","<script setup lang=\"ts\">\n/**\n * InfolistRenderer — read-only аналог LayoutRenderer для view-страниц.\n *\n * Узлы:\n * { type: 'text', name: 'title', label: 'Заголовок' } — entry (leaf)\n * { type: 'rows', items: [ ... ] } — layout (recurse)\n * { type: 'section', title: 'X', items: [ ... ] } — layout\n * { type: 'columns', items: [ ... ] } — layout\n *\n * Внимание: layout-узлы рендерятся СВОИМ внутренним wrapper'ом, а не\n * registered uid-layouts из render/registry, потому что те делегируют детей\n * в LayoutRenderer (field-registry → useFormState ОБЯЗАТЕЛЕН). Здесь record-\n * read-only режим — детей рендерим через сам InfolistRenderer.\n */\nimport { computed } from 'vue'\nimport { getInfolistEntry } from './registry'\nimport UnknownEntry from './UnknownEntry.vue'\n\nexport interface InfolistNode extends Record<string, unknown> {\n type: string\n /** Hint: 'entry' либо 'layout'. */\n kind?: 'entry' | 'layout'\n items?: InfolistNode[]\n}\n\ninterface Props {\n node: InfolistNode\n}\nconst props = defineProps<Props>()\n\nconst KNOWN_LAYOUTS = new Set(['rows', 'columns', 'section', 'block', 'tabs'])\n\ntype Resolved =\n | { kind: 'entry'; component: NonNullable<ReturnType<typeof getInfolistEntry>> }\n | { kind: 'layout'; layoutType: string }\n | { kind: 'unknown' }\n\nconst resolved = computed<Resolved>(() => {\n if (props.node.kind === 'entry') {\n const c = getInfolistEntry(props.node.type)\n return c ? { kind: 'entry', component: c } : { kind: 'unknown' }\n }\n if (props.node.kind === 'layout') {\n return KNOWN_LAYOUTS.has(props.node.type)\n ? { kind: 'layout', layoutType: props.node.type }\n : { kind: 'unknown' }\n }\n // Auto-detect: layouts по имени, entries по registry.\n if (KNOWN_LAYOUTS.has(props.node.type)) {\n return { kind: 'layout', layoutType: props.node.type }\n }\n const entry = getInfolistEntry(props.node.type)\n if (entry) return { kind: 'entry', component: entry }\n return { kind: 'unknown' }\n})\n\nconst entryProps = computed(() => {\n const { type: _t, kind: _k, items: _i, ...rest } = props.node\n return rest\n})\n\nconst items = computed<InfolistNode[]>(\n () => (props.node.items ?? []) as InfolistNode[],\n)\n\nconst sectionTitle = computed(() => (props.node.title as string | undefined) ?? null)\nconst sectionDescription = computed(\n () => (props.node.description as string | undefined) ?? null,\n)\nconst tabsActive = computed<number>(() => {\n const a = props.node.active\n return typeof a === 'number' ? a : 0\n})\n\ninterface InfolistTab {\n key?: string\n label: string\n items: InfolistNode[]\n}\nconst tabsList = computed<InfolistTab[]>(() => {\n return (props.node.items ?? []) as unknown as InfolistTab[]\n})\n</script>\n\n<template>\n <!-- Entry -->\n <component\n :is=\"resolved.component\"\n v-if=\"resolved.kind === 'entry'\"\n v-bind=\"entryProps\"\n />\n\n <!-- Layout: rows -->\n <div\n v-else-if=\"resolved.kind === 'layout' && resolved.layoutType === 'rows'\"\n class=\"admin-infolist-rows\"\n >\n <InfolistRenderer\n v-for=\"(child, idx) in items\"\n :key=\"idx\"\n :node=\"child\"\n />\n </div>\n\n <!-- Layout: columns (12-grid с per-item span) -->\n <div\n v-else-if=\"resolved.kind === 'layout' && resolved.layoutType === 'columns'\"\n class=\"admin-infolist-cols\"\n >\n <div\n v-for=\"(child, idx) in items\"\n :key=\"idx\"\n class=\"admin-infolist-cols__item\"\n :style=\"{\n gridColumn: `span ${\n typeof (child as Record<string, unknown>).span === 'number'\n ? (child as Record<string, unknown>).span\n : Math.max(1, Math.floor(12 / items.length))\n }`,\n }\"\n >\n <InfolistRenderer :node=\"child\" />\n </div>\n </div>\n\n <!-- Layout: section / block -->\n <section\n v-else-if=\"resolved.kind === 'layout' && (resolved.layoutType === 'section' || resolved.layoutType === 'block')\"\n class=\"admin-infolist-section\"\n >\n <header v-if=\"sectionTitle || sectionDescription\" class=\"admin-infolist-section__hd\">\n <h3 v-if=\"sectionTitle\" class=\"admin-infolist-section__title\">{{ sectionTitle }}</h3>\n <p v-if=\"sectionDescription\" class=\"admin-infolist-section__description\">\n {{ sectionDescription }}\n </p>\n </header>\n <div class=\"admin-infolist-section__body\">\n <InfolistRenderer\n v-for=\"(child, idx) in items\"\n :key=\"idx\"\n :node=\"child\"\n />\n </div>\n </section>\n\n <!-- Layout: tabs (минимальные — без переключения, показываем active по prop'у) -->\n <div\n v-else-if=\"resolved.kind === 'layout' && resolved.layoutType === 'tabs'\"\n class=\"admin-infolist-tabs\"\n >\n <ul class=\"admin-infolist-tabs__list\" role=\"tablist\">\n <li\n v-for=\"(tab, idx) in tabsList\"\n :key=\"tab.key ?? idx\"\n :class=\"[\n 'admin-infolist-tabs__tab',\n { 'admin-infolist-tabs__tab--active': idx === tabsActive },\n ]\"\n >\n {{ tab.label }}\n </li>\n </ul>\n <div class=\"admin-infolist-tabs__panel\">\n <InfolistRenderer\n v-for=\"(child, idx) in tabsList[tabsActive]?.items ?? []\"\n :key=\"idx\"\n :node=\"child\"\n />\n </div>\n </div>\n\n <UnknownEntry v-else :type=\"node.type\" :name=\"(node.name as string | undefined)\" />\n</template>\n\n<style>\n.admin-infolist-rows {\n display: flex;\n flex-direction: column;\n gap: var(--uid-space-sm);\n}\n.admin-infolist-cols {\n display: grid;\n grid-template-columns: repeat(12, minmax(0, 1fr));\n gap: var(--uid-space-md);\n}\n.admin-infolist-section {\n margin-bottom: var(--uid-space-md);\n padding: var(--uid-space-md);\n border: 1px solid var(--uid-border-subtle);\n border-radius: var(--uid-radius-lg);\n background: var(--uid-surface-raised);\n}\n.admin-infolist-section__hd { margin-bottom: var(--uid-space-sm); }\n.admin-infolist-section__title {\n margin: 0;\n font-size: var(--uid-font-size-sm);\n font-weight: var(--uid-font-weight-semibold);\n}\n.admin-infolist-section__description {\n margin: var(--uid-space-2xs) 0 0;\n font-size: var(--uid-font-size-xs);\n color: var(--uid-text-tertiary);\n}\n.admin-infolist-section__body {\n display: flex;\n flex-direction: column;\n gap: var(--uid-space-sm);\n}\n.admin-infolist-tabs__list {\n list-style: none;\n margin: 0 0 var(--uid-space-sm);\n padding: 0;\n display: flex;\n gap: var(--uid-space-xs);\n border-bottom: 1px solid var(--uid-border-subtle);\n}\n.admin-infolist-tabs__tab {\n padding: var(--uid-space-sm) var(--uid-space-sm);\n font-size: 13px;\n color: var(--uid-text-secondary);\n border-bottom: 2px solid transparent;\n}\n.admin-infolist-tabs__tab--active {\n color: var(--uid-text-primary);\n border-bottom-color: var(--uid-accent);\n font-weight: var(--uid-font-weight-medium);\n}\n</style>\n","/**\n * Composable для read-only record-контекста, передаваемого Infolist'ом.\n *\n * Контейнер (ResourceViewPage) вызывает `provideRecord(record)`, entry-\n * компоненты — `useRecord()` для чтения значения.\n */\n\nimport { inject, provide, type InjectionKey } from 'vue'\n\nconst RecordKey: InjectionKey<Record<string, unknown>> = Symbol('admin.infolist-record')\n\nexport function provideRecord(record: Record<string, unknown>): void {\n provide(RecordKey, record)\n}\n\nexport function useRecord(): Record<string, unknown> {\n const r = inject(RecordKey)\n if (!r) {\n throw new Error('useRecord() called outside of provideRecord() scope')\n }\n return r\n}\n\nexport function tryUseRecord(): Record<string, unknown> | null {\n return inject(RecordKey, null) as Record<string, unknown> | null\n}\n","<script setup lang=\"ts\">\n/**\n * ResourceViewPage — read-only зеркало form-страницы.\n *\n * Архитектура по docs/design_handoff_laravel_admin (ResourceView):\n * - Header: title + actions (Edit / Удалить)\n * - Body: 2-col grid (1fr Infolist + 320px side card с метриками)\n * - InfolistRenderer бежит по manifest.fields (тот же layout, но\n * leaf-узлы резолвятся через infolist-registry, не field-registry)\n */\nimport { computed, onMounted, watch } from 'vue'\nimport { useRouter } from 'vue-router'\nimport {\n UidAlert,\n UidButton,\n UidCard,\n UidSkeleton,\n} from '@dskripchenko/ui'\nimport { useResourceFormStore } from '../../stores/resourceForm'\nimport { useManifestStore } from '../../stores/manifest'\nimport InfolistRenderer from '../infolist/InfolistRenderer.vue'\nimport type { InfolistNode } from '../infolist/InfolistRenderer.vue'\nimport { provideRecord } from '../infolist/recordContext'\n\ninterface Props {\n slug: string\n id: string | number\n /** Имя router-route для перехода в edit. */\n editRouteName?: string\n /** Имя router-route для возврата на index. */\n indexRouteName?: string\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n editRouteName: undefined,\n indexRouteName: 'admin.home',\n})\n\nconst form = useResourceFormStore()\nconst manifest = useManifestStore()\nconst router = useRouter()\n\n// provideRecord даёт infolist-entry'ям читать record[name] через useRecord.\nprovideRecord(form.state)\n\nconst resourceMeta = computed(() => manifest.getResource(props.slug))\nconst layoutNodes = computed<InfolistNode[]>(\n () => resourceMeta.value?.fields ?? [],\n)\nconst titleLabel = computed(\n () => `${resourceMeta.value?.label ?? props.slug}: запись #${props.id}`,\n)\n\nonMounted(async () => {\n if (manifest.manifest === null) {\n await manifest.load().catch(() => undefined)\n }\n await form.load(props.slug, props.id, 'view').catch(() => undefined)\n})\n\nwatch(\n () => [props.slug, props.id] as const,\n async ([s, id]) => {\n await form.load(s, id, 'view').catch(() => undefined)\n },\n)\n\nfunction onEdit(): void {\n if (!props.editRouteName) {\n router\n .push(`/r/${props.slug}/${props.id}/edit`)\n .catch(() => undefined)\n return\n }\n router\n .push({ name: props.editRouteName, params: { id: props.id } })\n .catch(() => undefined)\n}\n\nasync function onDelete(): Promise<void> {\n if (!confirm('Удалить запись?')) return\n await form.destroy().catch(() => undefined)\n if (!form.hasError) {\n router.push({ name: props.indexRouteName }).catch(() => undefined)\n }\n}\n</script>\n\n<template>\n <section class=\"admin-page admin-resource-view\">\n <header class=\"admin-page__hd\">\n <div class=\"admin-page__title-wrap\">\n <h1 class=\"admin-page__title\">{{ titleLabel }}</h1>\n </div>\n <div class=\"admin-page__actions\">\n <UidButton variant=\"ghost\" @click=\"onEdit\">Редактировать</UidButton>\n <UidButton\n variant=\"danger\"\n :loading=\"form.deleting\"\n :disabled=\"form.deleting\"\n @click=\"onDelete\"\n >\n Удалить\n </UidButton>\n </div>\n </header>\n\n <UidAlert\n v-if=\"form.hasError\"\n variant=\"danger\"\n class=\"admin-resource-view__alert\"\n role=\"alert\"\n >\n {{ form.error?.message ?? 'Не удалось загрузить запись' }}\n </UidAlert>\n\n <div v-if=\"form.loading\" class=\"admin-resource-view__loading\">\n <UidSkeleton v-for=\"i in 8\" :key=\"i\" height=\"24px\" />\n </div>\n\n <UidCard v-else padding=\"md\" class=\"admin-resource-view__body\">\n <InfolistRenderer\n v-for=\"(node, idx) in layoutNodes\"\n :key=\"idx\"\n :node=\"node\"\n />\n </UidCard>\n </section>\n</template>\n\n<style>\n.admin-resource-view__alert {\n margin-bottom: var(--uid-space-md);\n}\n.admin-resource-view__loading {\n display: flex;\n flex-direction: column;\n gap: var(--uid-space-sm);\n}\n</style>\n","<script setup lang=\"ts\">\n/**\n * ProfilePage — профильный экран по эталону handoff'а (screens-secondary.jsx\n * → Profile). Layout 200px nav / 1fr cards.\n *\n * Slot model: каждая section экспонирует свою карточку. По умолчанию\n * library рендерит общие \"Основное\" + \"Безопасность\" (на existing-данных\n * auth.user). Host подмешивает свои \"API токены\" и \"Сессии\" через slot'ы.\n */\nimport { computed, ref } from 'vue'\nimport {\n UidAvatar,\n UidBadge,\n UidButton,\n UidCard,\n UidInput,\n UidSelect,\n} from '@dskripchenko/ui'\nimport { useAuthStore } from '../../stores/auth'\nimport { useThemeStore } from '../../stores/theme'\nimport { useLocaleStore } from '../../stores/locale'\n\ninterface Props {\n /** Заголовок страницы (по умолчанию «Profile»). */\n title?: string\n /** Подзаголовок (по умолчанию из handoff'а). */\n subtitle?: string\n /** Какая section активна. */\n section?: 'general' | 'security' | 'tokens' | 'sessions' | string\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n title: 'Profile',\n subtitle: 'Личные данные, безопасность, токены',\n section: 'general',\n})\n\nconst emit = defineEmits<{\n 'update:section': [value: string]\n /** Host реагирует — например запросом /me/uploadAvatar. */\n 'avatar-replace': []\n /** 2FA disable triggered — host показывает confirmation modal. */\n 'two-factor-disable': []\n /** 2FA recovery-codes regenerate. */\n 'two-factor-regenerate': []\n /** Save profile fields. */\n save: [payload: { name: string; email: string; locale: string; theme: string }]\n}>()\n\nconst auth = useAuthStore()\nconst theme = useThemeStore()\nconst locale = useLocaleStore()\n\nconst navItems = [\n { id: 'general', label: 'Основное', icon: 'user' },\n { id: 'security', label: 'Безопасность', icon: 'shield' },\n { id: 'tokens', label: 'API токены', icon: 'key' },\n { id: 'sessions', label: 'Сессии', icon: 'monitor' },\n]\n\nconst localSection = ref(props.section)\nfunction selectSection(id: string): void {\n localSection.value = id\n emit('update:section', id)\n}\n\n// Form-state для general-tab.\nconst profile = ref({\n name: auth.user?.name ?? '',\n email: auth.user?.email ?? '',\n locale: locale.current,\n theme: theme.current,\n})\n\nconst localeOptions = computed(() =>\n locale.available.map((l) => ({ value: l, label: l.toUpperCase() })),\n)\nconst themeOptions = computed(() =>\n theme.available.map((t) => ({ value: t, label: t === 'dark' ? 'Тёмная' : t === 'light' ? 'Светлая' : t })),\n)\n\nfunction onSave(): void {\n emit('save', { ...profile.value })\n}\n\nfunction onAvatarReplace(): void {\n emit('avatar-replace')\n}\n\nfunction on2FADisable(): void {\n emit('two-factor-disable')\n}\n\nfunction on2FARegenerate(): void {\n emit('two-factor-regenerate')\n}\n\nconst has2FA = computed(() => Boolean(auth.user?.twoFactorEnabled))\n</script>\n\n<template>\n <section class=\"admin-page admin-profile\">\n <header class=\"admin-page__hd\">\n <div class=\"admin-page__title-wrap\">\n <h1 class=\"admin-page__title\">{{ title }}</h1>\n <div class=\"admin-page__count\">{{ subtitle }}</div>\n </div>\n </header>\n\n <div class=\"admin-profile__layout\">\n <nav class=\"admin-profile__nav\" aria-label=\"Profile sections\">\n <button\n v-for=\"item in navItems\"\n :key=\"item.id\"\n type=\"button\"\n :class=\"[\n 'admin-profile__nav-item',\n { 'admin-profile__nav-item--active': localSection === item.id },\n ]\"\n @click=\"selectSection(item.id)\"\n >\n <span class=\"admin-profile__nav-icon\" :data-icon=\"item.icon\" />\n <span>{{ item.label }}</span>\n </button>\n </nav>\n\n <div class=\"admin-profile__content\">\n <!-- General -->\n <UidCard v-if=\"localSection === 'general'\" padding=\"md\">\n <header class=\"admin-profile__card-hd\">\n <h3 class=\"admin-profile__card-title\">Профиль</h3>\n </header>\n\n <div class=\"admin-profile__hero\">\n <UidAvatar\n :src=\"auth.user?.avatar ?? undefined\"\n :name=\"auth.user?.name ?? '?'\"\n size=\"lg\"\n />\n <div class=\"admin-profile__hero-text\">\n <div class=\"admin-profile__hero-name\">{{ auth.user?.name ?? '—' }}</div>\n <div class=\"admin-profile__hero-meta\">\n {{ auth.user?.email ?? '—' }}\n </div>\n </div>\n <div style=\"flex:1\" />\n <UidButton variant=\"ghost\" size=\"sm\" @click=\"onAvatarReplace\">\n Заменить\n </UidButton>\n </div>\n\n <div class=\"admin-profile__form\">\n <UidInput\n v-model=\"profile.name\"\n label=\"Имя\"\n name=\"name\"\n />\n <UidInput\n v-model=\"profile.email\"\n label=\"Email\"\n type=\"email\"\n name=\"email\"\n />\n <UidSelect\n v-model=\"profile.locale\"\n :options=\"localeOptions\"\n label=\"Язык\"\n />\n <UidSelect\n v-model=\"profile.theme\"\n :options=\"themeOptions\"\n label=\"Тема\"\n />\n </div>\n\n <footer class=\"admin-profile__card-ft\">\n <UidButton variant=\"primary\" @click=\"onSave\">Сохранить</UidButton>\n </footer>\n </UidCard>\n\n <!-- Security -->\n <UidCard v-else-if=\"localSection === 'security'\" padding=\"md\">\n <header class=\"admin-profile__card-hd\">\n <h3 class=\"admin-profile__card-title\">Двухфакторная аутентификация</h3>\n <UidBadge :variant=\"has2FA ? 'success' : 'default'\">\n {{ has2FA ? 'Включена' : 'Отключена' }}\n </UidBadge>\n </header>\n\n <p v-if=\"has2FA\" class=\"admin-profile__hint\">\n 2FA включена. У вас остались recovery-коды на случай потери устройства.\n </p>\n <p v-else class=\"admin-profile__hint\">\n Включите 2FA для дополнительной защиты аккаунта.\n </p>\n\n <footer class=\"admin-profile__card-ft\">\n <template v-if=\"has2FA\">\n <UidButton variant=\"ghost\" size=\"sm\" @click=\"on2FARegenerate\">\n Перегенерировать коды\n </UidButton>\n <UidButton variant=\"danger\" size=\"sm\" @click=\"on2FADisable\">\n Отключить 2FA\n </UidButton>\n </template>\n <template v-else>\n <slot name=\"enable-2fa\">\n <UidButton variant=\"primary\" disabled>\n Включить 2FA (host customize)\n </UidButton>\n </slot>\n </template>\n </footer>\n </UidCard>\n\n <!-- Tokens / Sessions / другое — host рендерит через slot -->\n <slot v-else :name=\"localSection\" :section=\"localSection\">\n <UidCard padding=\"md\">\n <p class=\"admin-profile__hint\">\n Section «{{ localSection }}» не реализована библиотекой —\n host-проект подключает её через slot {{ localSection }}.\n </p>\n </UidCard>\n </slot>\n </div>\n </div>\n </section>\n</template>\n\n<style>\n.admin-profile__layout {\n display: grid;\n grid-template-columns: 200px 1fr;\n gap: var(--uid-space-lg);\n align-items: start;\n}\n.admin-profile__nav {\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n.admin-profile__nav-item {\n appearance: none;\n border: 0;\n background: transparent;\n text-align: left;\n display: flex;\n align-items: center;\n gap: var(--uid-space-sm);\n padding: var(--uid-space-sm) var(--uid-space-sm);\n border-radius: var(--uid-radius-md);\n font-size: 13px;\n color: var(--uid-text-secondary);\n cursor: pointer;\n}\n.admin-profile__nav-item:hover {\n background: var(--uid-surface-hover);\n color: var(--uid-text-primary);\n}\n.admin-profile__nav-item--active {\n background: var(--uid-surface-base);\n color: var(--uid-text-primary);\n font-weight: var(--uid-font-weight-medium);\n}\n.admin-profile__nav-icon {\n width: 14px;\n height: 14px;\n flex: none;\n}\n.admin-profile__content {\n display: flex;\n flex-direction: column;\n gap: var(--uid-space-md);\n}\n\n.admin-profile__card-hd {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: var(--uid-space-md);\n}\n.admin-profile__card-title {\n margin: 0;\n font-size: var(--uid-font-size-sm);\n font-weight: var(--uid-font-weight-semibold);\n}\n.admin-profile__card-ft {\n margin-top: var(--uid-space-md);\n display: flex;\n gap: var(--uid-space-sm);\n}\n.admin-profile__hint {\n margin: 0;\n font-size: var(--uid-font-size-sm);\n color: var(--uid-text-secondary);\n}\n\n.admin-profile__hero {\n display: flex;\n align-items: center;\n gap: var(--uid-space-md);\n margin-bottom: var(--uid-space-md);\n}\n.admin-profile__hero-text { display: flex; flex-direction: column; gap: 4px; }\n.admin-profile__hero-name {\n font-weight: var(--uid-font-weight-semibold);\n color: var(--uid-text-primary);\n}\n.admin-profile__hero-meta {\n font-size: var(--uid-font-size-xs);\n color: var(--uid-text-tertiary);\n}\n\n.admin-profile__form {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: var(--uid-space-md);\n}\n@media (max-width: 720px) {\n .admin-profile__form { grid-template-columns: 1fr; }\n}\n</style>\n","/**\n * Реестр dashboard widget-компонентов.\n *\n * Manifest узлы dashboard выглядят так:\n * {\n * slug: 'main',\n * label: 'Главный',\n * widgets: [\n * { type: 'stat', name: 'total', title: 'Всего', value: 1284,\n * span: 3, trend: 12 },\n * { type: 'bar-chart', span: 8, ... },\n * { type: 'recent-table', span: 8, columns: [...], rows: [...] },\n * ]\n * }\n *\n * Host регистрирует кастомные widget'ы через `registerWidget()` /\n * `registerWidgets()` bundle.\n */\n\nimport type { Component } from 'vue'\nimport { createComponentRegistry } from '../createComponentRegistry'\n\nconst widgets = createComponentRegistry<Component>()\n\nexport const registerWidget = widgets.register\nexport const getWidget = widgets.get\nexport const hasWidget = widgets.has\nexport const listWidgets = widgets.list\nexport const clearWidgetRegistry = widgets.clear\nexport const registerWidgets = widgets.registerBundle\n","<script setup lang=\"ts\">\nimport { UidAlert } from '@dskripchenko/ui'\n\ninterface Props {\n type: string\n}\ndefineProps<Props>()\n</script>\n\n<template>\n <UidAlert variant=\"warning\">\n <template #title>Неизвестный widget-тип: {{ type }}</template>\n Зарегистрируйте через <code>registerWidget('{{ type }}', YourComponent)</code>.\n </UidAlert>\n</template>\n","<script setup lang=\"ts\">\n/**\n * Резолвит widget-компонент по `node.type` и forwards остальные props.\n */\nimport { computed } from 'vue'\nimport { getWidget } from './registry'\nimport UnknownWidget from './UnknownWidget.vue'\n\nexport interface WidgetNode extends Record<string, unknown> {\n type: string\n /** Сколько колонок занимает в 12-grid (1..12). */\n span?: number\n}\n\ninterface Props {\n node: WidgetNode\n}\nconst props = defineProps<Props>()\n\nconst component = computed(() => getWidget(props.node.type))\nconst widgetProps = computed(() => {\n const { type: _type, span: _span, ...rest } = props.node\n return rest\n})\n</script>\n\n<template>\n <component :is=\"component\" v-if=\"component\" v-bind=\"widgetProps\" />\n <UnknownWidget v-else :type=\"node.type\" />\n</template>\n","<script setup lang=\"ts\">\n/**\n * DashboardPage — 12-col grid из widget'ов по эталону handoff'а\n * (docs/design_handoff_laravel_admin/screens-secondary.jsx → Dashboard).\n *\n * Источник widget'ов:\n * - Если задан `slug` — берём dashboard из manifest.dashboards по slug\n * - Если задан `widgets` prop — рендерим переданные узлы напрямую\n *\n * Каждый widget — `{ type: 'stat', span: 3, title: '...', value: 1284 }`,\n * span — колонки в 12-grid (1..12), default 12 (full width).\n */\nimport { computed } from 'vue'\nimport { useManifestStore } from '../../stores/manifest'\nimport WidgetRenderer, { type WidgetNode } from './WidgetRenderer.vue'\n\ninterface DashboardManifest {\n slug: string\n label?: string\n description?: string | null\n widgets: WidgetNode[]\n}\n\ninterface Props {\n /** Slug dashboard'а в manifest.dashboards. */\n slug?: string\n /** Прямой override widget'ов (если slug не задан или не нашёлся). */\n widgets?: WidgetNode[]\n /** Заголовок страницы. */\n title?: string\n /** Подзаголовок (description). */\n subtitle?: string\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n slug: undefined,\n widgets: undefined,\n title: undefined,\n subtitle: undefined,\n})\n\nconst manifest = useManifestStore()\n\nconst dashboard = computed<DashboardManifest | null>(() => {\n if (!props.slug || !manifest.manifest) return null\n const dashboards = manifest.manifest.dashboards as DashboardManifest[] | undefined\n return dashboards?.find((d) => d.slug === props.slug) ?? null\n})\n\nconst resolvedWidgets = computed<WidgetNode[]>(() => {\n if (props.widgets) return props.widgets\n if (dashboard.value) return dashboard.value.widgets ?? []\n return []\n})\n\nconst resolvedTitle = computed(\n () => props.title ?? dashboard.value?.label ?? 'Dashboard',\n)\nconst resolvedSubtitle = computed(\n () => props.subtitle ?? dashboard.value?.description ?? null,\n)\n\nfunction spanFor(w: WidgetNode): number {\n const s = typeof w.span === 'number' ? w.span : 12\n return Math.max(1, Math.min(12, s))\n}\n</script>\n\n<template>\n <section class=\"admin-page admin-dashboard\">\n <header class=\"admin-page__hd\">\n <div class=\"admin-page__title-wrap\">\n <h1 class=\"admin-page__title\">{{ resolvedTitle }}</h1>\n <div v-if=\"resolvedSubtitle\" class=\"admin-page__count\">\n {{ resolvedSubtitle }}\n </div>\n </div>\n <div class=\"admin-page__actions\">\n <slot name=\"actions\" />\n </div>\n </header>\n\n <div class=\"admin-dashboard__grid\">\n <div\n v-for=\"(w, idx) in resolvedWidgets\"\n :key=\"idx\"\n class=\"admin-dashboard__cell\"\n :style=\"{ gridColumn: `span ${spanFor(w)} / span ${spanFor(w)}` }\"\n >\n <WidgetRenderer :node=\"w\" />\n </div>\n </div>\n </section>\n</template>\n\n<style>\n.admin-dashboard__grid {\n display: grid;\n grid-template-columns: repeat(12, minmax(0, 1fr));\n gap: var(--uid-space-md);\n}\n.admin-dashboard__cell {\n min-width: 0;\n}\n</style>\n","<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport { UidStat } from '@dskripchenko/ui'\nimport type { StatTone } from '@dskripchenko/ui'\n\ntype SemanticTone = 'neutral' | 'positive' | 'negative' | 'warning' | 'info'\n\ninterface Props {\n title?: string\n value?: number | string\n prefix?: string\n suffix?: string\n trend?: number\n precision?: number\n tone?: SemanticTone\n loading?: boolean\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n title: '',\n value: 0,\n prefix: '',\n suffix: '',\n trend: undefined,\n precision: 0,\n tone: 'neutral',\n loading: false,\n})\n\nconst TONE_MAP: Record<SemanticTone, StatTone> = {\n neutral: 'primary',\n positive: 'success',\n negative: 'danger',\n warning: 'warning',\n info: 'info',\n}\n\nconst uidTone = computed<StatTone>(() => TONE_MAP[props.tone])\n</script>\n\n<template>\n <UidStat\n :title=\"title\"\n :value=\"value\"\n :prefix=\"prefix\"\n :suffix=\"suffix\"\n :trend=\"trend\"\n :precision=\"precision\"\n :tone=\"uidTone\"\n :loading=\"loading\"\n />\n</template>\n","<script setup lang=\"ts\">\n/**\n * BarChartWidget — простой SVG-bar chart без внешних зависимостей.\n *\n * Manifest:\n * { type: 'bar-chart', title: '30 дней',\n * data: [{ label: '01', value: 12 }, ...],\n * accent: 'var(--uid-accent)' }\n */\nimport { computed } from 'vue'\nimport { UidCard } from '@dskripchenko/ui'\n\ninterface Datum {\n label: string\n value: number\n}\n\ninterface Props {\n title?: string\n description?: string\n data: Datum[]\n accent?: string\n height?: number\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n title: '',\n description: '',\n accent: 'var(--uid-accent)',\n height: 200,\n})\n\nconst maxValue = computed(() => Math.max(1, ...props.data.map((d) => d.value)))\n\nconst bars = computed(() => {\n const n = Math.max(1, props.data.length)\n const barWidth = 100 / n\n return props.data.map((d, i) => ({\n label: d.label,\n value: d.value,\n x: i * barWidth + barWidth * 0.1,\n width: barWidth * 0.8,\n heightPct: (d.value / maxValue.value) * 100,\n }))\n})\n</script>\n\n<template>\n <UidCard padding=\"md\" class=\"admin-widget\">\n <header v-if=\"title || description\" class=\"admin-widget__hd\">\n <h3 v-if=\"title\" class=\"admin-widget__title\">{{ title }}</h3>\n <p v-if=\"description\" class=\"admin-widget__desc\">{{ description }}</p>\n </header>\n <svg\n class=\"admin-widget-bar-chart\"\n :viewBox=\"`0 0 100 ${height}`\"\n preserveAspectRatio=\"none\"\n :height=\"height\"\n width=\"100%\"\n role=\"img\"\n :aria-label=\"title || 'Bar chart'\"\n >\n <rect\n v-for=\"(bar, idx) in bars\"\n :key=\"idx\"\n :x=\"bar.x\"\n :y=\"height - (bar.heightPct / 100) * height\"\n :width=\"bar.width\"\n :height=\"(bar.heightPct / 100) * height\"\n :fill=\"accent\"\n rx=\"1\"\n :data-label=\"bar.label\"\n :data-value=\"bar.value\"\n >\n <title>{{ bar.label }}: {{ bar.value }}</title>\n </rect>\n </svg>\n </UidCard>\n</template>\n\n<style>\n.admin-widget__hd { margin-bottom: var(--uid-space-sm); }\n.admin-widget__title {\n margin: 0;\n font-size: var(--uid-font-size-sm);\n font-weight: var(--uid-font-weight-semibold);\n color: var(--uid-text-primary);\n}\n.admin-widget__desc {\n margin: var(--uid-space-2xs) 0 0;\n font-size: var(--uid-font-size-xs);\n color: var(--uid-text-tertiary);\n}\n.admin-widget-bar-chart {\n display: block;\n width: 100%;\n}\n</style>\n","<script setup lang=\"ts\">\n/**\n * DonutChartWidget — SVG donut + legend.\n *\n * Manifest:\n * { type: 'donut-chart', title: 'Status',\n * data: [{ label: 'Published', value: 156, color: '...' }, ...] }\n */\nimport { computed } from 'vue'\nimport { UidCard } from '@dskripchenko/ui'\n\ninterface Slice {\n label: string\n value: number\n color?: string\n}\n\ninterface Props {\n title?: string\n data: Slice[]\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n title: '',\n})\n\nconst PALETTE = [\n 'var(--uid-color-teal-500, #14b8a6)',\n 'var(--uid-color-zinc-700, #3f3f46)',\n 'var(--uid-color-amber-400, #fbbf24)',\n 'var(--uid-color-rose-400, #fb7185)',\n 'var(--uid-color-blue-400, #60a5fa)',\n]\n\nconst total = computed(() => props.data.reduce((s, x) => s + x.value, 0) || 1)\n\nconst slices = computed(() => {\n let cumulative = 0\n return props.data.map((s, idx) => {\n const startAngle = (cumulative / total.value) * 2 * Math.PI\n cumulative += s.value\n const endAngle = (cumulative / total.value) * 2 * Math.PI\n\n const r = 50\n const cx = 60\n const cy = 60\n\n const x1 = cx + r * Math.cos(startAngle - Math.PI / 2)\n const y1 = cy + r * Math.sin(startAngle - Math.PI / 2)\n const x2 = cx + r * Math.cos(endAngle - Math.PI / 2)\n const y2 = cy + r * Math.sin(endAngle - Math.PI / 2)\n\n const largeArc = endAngle - startAngle > Math.PI ? 1 : 0\n\n const path = props.data.length === 1\n ? `M ${cx - r} ${cy} a ${r} ${r} 0 1 0 ${r * 2} 0 a ${r} ${r} 0 1 0 ${-r * 2} 0`\n : `M ${cx} ${cy} L ${x1} ${y1} A ${r} ${r} 0 ${largeArc} 1 ${x2} ${y2} Z`\n\n return {\n ...s,\n path,\n color: s.color ?? PALETTE[idx % PALETTE.length],\n pct: ((s.value / total.value) * 100).toFixed(1),\n }\n })\n})\n</script>\n\n<template>\n <UidCard padding=\"md\" class=\"admin-widget admin-donut-widget\">\n <header v-if=\"title\" class=\"admin-widget__hd\">\n <h3 class=\"admin-widget__title\">{{ title }}</h3>\n </header>\n <div class=\"admin-donut-widget__row\">\n <svg viewBox=\"0 0 120 120\" class=\"admin-donut-widget__svg\" role=\"img\" :aria-label=\"title\">\n <path\n v-for=\"(s, idx) in slices\"\n :key=\"idx\"\n :d=\"s.path\"\n :fill=\"s.color\"\n >\n <title>{{ s.label }}: {{ s.value }} ({{ s.pct }}%)</title>\n </path>\n <circle cx=\"60\" cy=\"60\" r=\"30\" fill=\"var(--uid-surface-raised)\" />\n </svg>\n <ul class=\"admin-donut-widget__legend\">\n <li v-for=\"(s, idx) in slices\" :key=\"idx\">\n <span class=\"admin-donut-widget__dot\" :style=\"{ background: s.color }\" />\n <span class=\"admin-donut-widget__label\">{{ s.label }}</span>\n <span class=\"admin-donut-widget__value\">{{ s.pct }}%</span>\n </li>\n </ul>\n </div>\n </UidCard>\n</template>\n\n<style>\n.admin-donut-widget__row {\n display: flex;\n align-items: center;\n gap: var(--uid-space-md);\n}\n.admin-donut-widget__svg {\n width: 120px;\n height: 120px;\n flex: none;\n}\n.admin-donut-widget__legend {\n list-style: none;\n margin: 0;\n padding: 0;\n flex: 1;\n display: flex;\n flex-direction: column;\n gap: var(--uid-space-xs);\n}\n.admin-donut-widget__legend li {\n display: flex;\n align-items: center;\n gap: var(--uid-space-sm);\n font-size: var(--uid-font-size-xs);\n}\n.admin-donut-widget__dot {\n width: 10px;\n height: 10px;\n border-radius: var(--uid-radius-full);\n flex: none;\n}\n.admin-donut-widget__label { flex: 1; color: var(--uid-text-primary); }\n.admin-donut-widget__value {\n color: var(--uid-text-tertiary);\n font-variant-numeric: tabular-nums;\n}\n</style>\n","<script setup lang=\"ts\">\nimport { UidCard, UidTable, type UidTableColumn } from '@dskripchenko/ui'\n\ninterface Props {\n title?: string\n columns: UidTableColumn[]\n rows: Record<string, unknown>[]\n emptyText?: string\n}\n\nwithDefaults(defineProps<Props>(), {\n title: '',\n emptyText: 'Нет данных',\n})\n</script>\n\n<template>\n <UidCard padding=\"md\" class=\"admin-widget\">\n <header v-if=\"title\" class=\"admin-widget__hd\">\n <h3 class=\"admin-widget__title\">{{ title }}</h3>\n </header>\n <UidTable :columns=\"columns\" :data=\"rows\" :empty-text=\"emptyText\" />\n </UidCard>\n</template>\n","<script setup lang=\"ts\">\nimport { UidCard, UidHeatmap } from '@dskripchenko/ui'\n\ninterface HeatmapPoint {\n date: string\n value: number\n}\n\ninterface Props {\n title?: string\n data: HeatmapPoint[]\n levels?: number\n color?: string\n gap?: number\n}\n\nwithDefaults(defineProps<Props>(), {\n title: '',\n levels: 5,\n color: undefined,\n gap: 2,\n})\n</script>\n\n<template>\n <UidCard padding=\"md\" class=\"admin-widget\">\n <header v-if=\"title\" class=\"admin-widget__hd\">\n <h3 class=\"admin-widget__title\">{{ title }}</h3>\n </header>\n <UidHeatmap :data=\"data\" :levels=\"levels\" :color=\"color\" :gap=\"gap\" />\n </UidCard>\n</template>\n","<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport { UidCard, UidGauge } from '@dskripchenko/ui'\nimport type { GaugeTone, GaugeRange } from '@dskripchenko/ui'\n\ntype SemanticTone = 'neutral' | 'positive' | 'warning' | 'negative'\n\ninterface Props {\n title?: string\n value?: number\n min?: number\n max?: number\n size?: number\n ranges?: GaugeRange[]\n tone?: SemanticTone\n color?: string\n label?: string\n suffix?: string\n precision?: number\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n title: '',\n value: 0,\n min: 0,\n max: 100,\n size: 160,\n ranges: () => [],\n tone: 'neutral',\n color: undefined,\n label: '',\n suffix: '',\n precision: 0,\n})\n\nconst TONE_MAP: Record<SemanticTone, GaugeTone> = {\n neutral: 'primary',\n positive: 'success',\n warning: 'warning',\n negative: 'danger',\n}\n\nconst uidTone = computed<GaugeTone>(() => TONE_MAP[props.tone])\n</script>\n\n<template>\n <UidCard padding=\"md\" class=\"admin-widget\">\n <header v-if=\"title\" class=\"admin-widget__hd\">\n <h3 class=\"admin-widget__title\">{{ title }}</h3>\n </header>\n <div style=\"display:flex; justify-content:center;\">\n <UidGauge\n :value=\"value\"\n :min=\"min\"\n :max=\"max\"\n :size=\"size\"\n :ranges=\"ranges\"\n :tone=\"uidTone\"\n :color=\"color\"\n :label=\"label\"\n :suffix=\"suffix\"\n :precision=\"precision\"\n />\n </div>\n </UidCard>\n</template>\n","<script setup lang=\"ts\">\n/**\n * Markdown widget — простой preformatted-блок. Для production хост может\n * подкинуть свой widget с marked/MDX через registerWidget('markdown', ...).\n *\n * Тут — fallback с базовым форматированием через line-break preserve.\n */\nimport { UidCard } from '@dskripchenko/ui'\n\ninterface Props {\n title?: string\n content: string\n}\n\nwithDefaults(defineProps<Props>(), { title: '' })\n</script>\n\n<template>\n <UidCard padding=\"md\" class=\"admin-widget\">\n <header v-if=\"title\" class=\"admin-widget__hd\">\n <h3 class=\"admin-widget__title\">{{ title }}</h3>\n </header>\n <div class=\"admin-markdown-widget\">{{ content }}</div>\n </UidCard>\n</template>\n\n<style>\n.admin-markdown-widget {\n font-size: var(--uid-font-size-sm);\n color: var(--uid-text-secondary);\n white-space: pre-wrap;\n line-height: var(--uid-line-height-normal);\n}\n</style>\n","/**\n * Default-bundle с минимальным набором builtin widget-типов.\n */\n\nimport { registerWidgets } from './registry'\nimport StatWidget from './StatWidget.vue'\nimport BarChartWidget from './BarChartWidget.vue'\nimport DonutChartWidget from './DonutChartWidget.vue'\nimport RecentTableWidget from './RecentTableWidget.vue'\nimport HeatmapWidget from './HeatmapWidget.vue'\nimport GaugeWidget from './GaugeWidget.vue'\nimport MarkdownWidget from './MarkdownWidget.vue'\n\nexport function registerBuiltinWidgets(): void {\n registerWidgets({\n stat: StatWidget,\n 'bar-chart': BarChartWidget,\n 'donut-chart': DonutChartWidget,\n 'recent-table': RecentTableWidget,\n heatmap: HeatmapWidget,\n gauge: GaugeWidget,\n markdown: MarkdownWidget,\n })\n}\n","/**\n * Контракт ответов laravel-api: каждое тело — `{success, payload}`.\n *\n * Success: `{success: true, payload: {...}}`\n * Error: `{success: false, payload: {errorKey, message, ...}}`\n *\n * Helper'ы здесь — для type-narrowing'а в потребителях.\n */\n\nexport interface SuccessEnvelope<T = unknown> {\n success: true\n payload: T\n}\n\nexport interface ErrorEnvelope {\n success: false\n payload: {\n errorKey: string\n message: string\n messages?: Record<string, string[]>\n [key: string]: unknown\n }\n}\n\nexport type ApiEnvelope<T = unknown> = SuccessEnvelope<T> | ErrorEnvelope\n\nexport function isSuccess<T>(env: ApiEnvelope<T>): env is SuccessEnvelope<T> {\n return env.success === true\n}\n\nexport function isError(env: ApiEnvelope): env is ErrorEnvelope {\n return env.success === false\n}\n","/**\n * Axios-клиент для admin API.\n *\n * Особенности:\n * - baseURL берётся из bootstrap.apiUrl (либо передаётся явно).\n * - X-XSRF-TOKEN добавляется автоматически из cookie (Laravel Sanctum/web).\n * - X-CSRF-TOKEN — fallback из meta[name=csrf-token] (Blade-injection).\n * - X-Admin-Locale выставляется при наличии текущей локали.\n * - Response interceptor разворачивает envelope и бросает ApiError.\n * - 401 → onUnauthenticated callback (редирект на login на стороне consumer'а).\n */\n\nimport axios, { AxiosError, type AxiosInstance, type AxiosRequestConfig } from 'axios'\nimport { isSuccess, type ApiEnvelope, type ErrorEnvelope } from './envelope'\nimport { NetworkError, toApiError, UnauthenticatedError } from './errors'\n\nexport interface ClientOptions {\n baseURL: string\n csrfToken?: string\n locale?: string\n /** Вызывается при 401. Обычно — push на /admin/login. */\n onUnauthenticated?: () => void\n}\n\nexport interface AdminClient {\n /** Низкоуровневый axios — для специфичных случаев. */\n raw: AxiosInstance\n get<T = unknown>(url: string, config?: AxiosRequestConfig): Promise<T>\n post<T = unknown>(url: string, data?: unknown, config?: AxiosRequestConfig): Promise<T>\n put<T = unknown>(url: string, data?: unknown, config?: AxiosRequestConfig): Promise<T>\n patch<T = unknown>(url: string, data?: unknown, config?: AxiosRequestConfig): Promise<T>\n delete<T = unknown>(url: string, config?: AxiosRequestConfig): Promise<T>\n setLocale(locale: string): void\n}\n\nexport function createAdminClient(opts: ClientOptions): AdminClient {\n const instance = axios.create({\n baseURL: opts.baseURL,\n withCredentials: true,\n headers: {\n Accept: 'application/json',\n 'X-Requested-With': 'XMLHttpRequest',\n },\n })\n\n if (opts.csrfToken) {\n instance.defaults.headers.common['X-CSRF-TOKEN'] = opts.csrfToken\n }\n if (opts.locale) {\n instance.defaults.headers.common['X-Admin-Locale'] = opts.locale\n }\n\n // Подцепляем XSRF из cookie на каждый запрос — браузер сам обновит\n // его после первого 419, но axios reads на вызове.\n instance.interceptors.request.use((config) => {\n const xsrf = readCookie('XSRF-TOKEN')\n if (xsrf) {\n config.headers.set('X-XSRF-TOKEN', decodeURIComponent(xsrf))\n }\n return config\n })\n\n // Response interceptor — разворачиваем envelope, бросаем правильную ошибку.\n instance.interceptors.response.use(\n (response) => {\n const env = response.data as ApiEnvelope\n if (env && typeof env === 'object' && 'success' in env) {\n if (isSuccess(env)) {\n // payload подменяет data — теперь callers получают чистый payload.\n response.data = env.payload\n return response\n }\n // success: false → throw как ApiError\n throw toApiError(response.status, env.payload)\n }\n // Не envelope (например, бинарный stream) — пропускаем как есть.\n return response\n },\n (error: AxiosError<ErrorEnvelope>) => {\n if (error.response) {\n const status = error.response.status\n const payload =\n error.response.data?.payload ?? {\n errorKey: 'unknown',\n message: error.message,\n }\n const apiError = toApiError(status, payload)\n if (apiError instanceof UnauthenticatedError) {\n opts.onUnauthenticated?.()\n }\n return Promise.reject(apiError)\n }\n // network failure / timeout\n return Promise.reject(new NetworkError(error.message))\n },\n )\n\n const wrap = <T>(method: 'get' | 'delete', url: string, config?: AxiosRequestConfig): Promise<T> =>\n instance[method]<unknown, { data: T }>(url, config).then((r) => r.data)\n\n const wrapBody = <T>(\n method: 'post' | 'put' | 'patch',\n url: string,\n data?: unknown,\n config?: AxiosRequestConfig,\n ): Promise<T> => instance[method]<unknown, { data: T }>(url, data, config).then((r) => r.data)\n\n return {\n raw: instance,\n get: <T>(url: string, config?: AxiosRequestConfig) => wrap<T>('get', url, config),\n delete: <T>(url: string, config?: AxiosRequestConfig) => wrap<T>('delete', url, config),\n post: <T>(url: string, data?: unknown, config?: AxiosRequestConfig) =>\n wrapBody<T>('post', url, data, config),\n put: <T>(url: string, data?: unknown, config?: AxiosRequestConfig) =>\n wrapBody<T>('put', url, data, config),\n patch: <T>(url: string, data?: unknown, config?: AxiosRequestConfig) =>\n wrapBody<T>('patch', url, data, config),\n setLocale: (locale: string): void => {\n instance.defaults.headers.common['X-Admin-Locale'] = locale\n },\n }\n}\n\n/** Читает cookie из document.cookie. Returns null если нет. */\nfunction readCookie(name: string): string | null {\n if (typeof document === 'undefined') return null\n const match = document.cookie.match(new RegExp('(^|; )' + escapeRegex(name) + '=([^;]*)'))\n return match ? match[2] : null\n}\n\nfunction escapeRegex(s: string): string {\n return s.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n}\n","/**\n * buildRoutesFromManifest — превращает AdminManifest в массив RouteRecordRaw.\n *\n * Маппинг:\n * - resource{slug} → /r/{slug} (index)\n * /r/{slug}/create (create)\n * /r/{slug}/:id/edit (edit)\n * /r/{slug}/:id (view, опционально)\n * - screen{slug} → /screens/{slug}\n * - settings{slug} → /settings/{slug}\n * - dashboard{slug} → /dashboard/{slug}\n *\n * Component'ы передаются через resolver — host-проект решает, что отрисовать.\n * Это позволяет library не тащить рендереры внутрь себя жёстко.\n */\n\nimport type { RouteRecordRaw } from 'vue-router'\nimport type { Component } from 'vue'\nimport type {\n AdminManifest,\n ManifestResourceMeta,\n ManifestScreenMeta,\n ManifestSettingsMeta,\n} from '../stores/manifest'\n\n/** Vue Component либо async-loader (для code-splitting). */\nexport type AdminRouteComponent = Component | (() => Promise<Component>)\n\nexport interface RouteMeta {\n /** Требует залогиненного пользователя. */\n requiresAuth?: boolean\n /** Permissions, нужные для входа. ANY-логика (хотя бы одно совпадение). */\n permissions?: string[]\n /** Заголовок страницы (рендерим в <title> через router.afterEach). */\n title?: string\n /** Тип админ-роута — для UI breadcrumbs/active-state. */\n kind?: 'resource' | 'screen' | 'settings' | 'dashboard' | 'system' | 'auth'\n /** Slug сущности из манифеста — для извлечения мета внутри компонента. */\n slug?: string\n}\n\ndeclare module 'vue-router' {\n // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n interface RouteMeta extends Record<string, unknown> {}\n}\n\n/**\n * Resolver компонентов для динамических роутов.\n *\n * Host-проект передаёт конкретные Vue-компоненты для каждой роли.\n * Library не зависит от конкретных view'ов.\n */\nexport interface RouteComponentResolver {\n resourceIndex: AdminRouteComponent\n resourceCreate: AdminRouteComponent\n resourceEdit: AdminRouteComponent\n resourceView: AdminRouteComponent\n screen: AdminRouteComponent\n settings: AdminRouteComponent\n dashboard: AdminRouteComponent\n}\n\n/**\n * Извлекает permissions из meta'ы ресурса / скрина / settings'а.\n *\n * resource.permissions = { view: 'admin.users.view', ... } → ['admin.users.view']\n * (для index используется view; для create/edit — соответственно).\n */\nfunction pickResourcePermission(\n resource: ManifestResourceMeta,\n ability: 'view' | 'create' | 'update',\n): string[] {\n const perm = resource.permissions?.[ability]\n return typeof perm === 'string' && perm.length > 0 ? [perm] : []\n}\n\nfunction pickSettingsPermission(s: ManifestSettingsMeta, ability: 'view' | 'update'): string[] {\n const perm = s.permissions?.[ability]\n return typeof perm === 'string' && perm.length > 0 ? [perm] : []\n}\n\nfunction pickScreenPermission(s: ManifestScreenMeta): string[] {\n if (Array.isArray(s.permission)) return s.permission\n if (typeof s.permission === 'string' && s.permission.length > 0) return [s.permission]\n return []\n}\n\nfunction buildResourceRoutes(\n resource: ManifestResourceMeta,\n components: RouteComponentResolver,\n): RouteRecordRaw[] {\n const slug = resource.slug\n const base = `/r/${slug}`\n\n return [\n {\n path: base,\n name: `admin.resource.${slug}.index`,\n component: components.resourceIndex,\n meta: {\n requiresAuth: true,\n kind: 'resource',\n slug,\n title: resource.label,\n permissions: pickResourcePermission(resource, 'view'),\n },\n // slug передаётся в page-component'ы как prop. Конкретный slug запекаем в\n // function-mode, чтобы page видел его одинаково и через named-route, и через\n // path-routing (без params).\n props: { slug },\n },\n {\n path: `${base}/create`,\n name: `admin.resource.${slug}.create`,\n component: components.resourceCreate,\n meta: {\n requiresAuth: true,\n kind: 'resource',\n slug,\n title: `${resource.label}: создать`,\n permissions: pickResourcePermission(resource, 'create'),\n },\n props: { slug },\n },\n {\n path: `${base}/:id/edit`,\n name: `admin.resource.${slug}.edit`,\n component: components.resourceEdit,\n meta: {\n requiresAuth: true,\n kind: 'resource',\n slug,\n title: `${resource.label}: редактирование`,\n permissions: pickResourcePermission(resource, 'update'),\n },\n // slug запекаем, id из route-params.\n props: (route) => ({ slug, id: route.params.id }),\n },\n {\n path: `${base}/:id`,\n name: `admin.resource.${slug}.view`,\n component: components.resourceView,\n meta: {\n requiresAuth: true,\n kind: 'resource',\n slug,\n title: resource.label,\n permissions: pickResourcePermission(resource, 'view'),\n },\n props: (route) => ({ slug, id: route.params.id }),\n },\n ]\n}\n\nfunction buildScreenRoute(\n screen: ManifestScreenMeta,\n components: RouteComponentResolver,\n): RouteRecordRaw {\n return {\n path: `/screens/${screen.slug}`,\n name: `admin.screen.${screen.slug}`,\n component: components.screen,\n meta: {\n requiresAuth: true,\n kind: 'screen',\n slug: screen.slug,\n title: screen.name,\n permissions: pickScreenPermission(screen),\n },\n }\n}\n\nfunction buildSettingsRoute(\n settings: ManifestSettingsMeta,\n components: RouteComponentResolver,\n): RouteRecordRaw {\n return {\n path: `/settings/${settings.slug}`,\n name: `admin.settings.${settings.slug}`,\n component: components.settings,\n meta: {\n requiresAuth: true,\n kind: 'settings',\n slug: settings.slug,\n title: settings.label,\n permissions: pickSettingsPermission(settings, 'view'),\n },\n }\n}\n\ninterface DashboardMeta {\n slug?: string\n label?: string\n permission?: string | string[] | null\n}\n\nfunction buildDashboardRoute(\n dashboard: DashboardMeta,\n components: RouteComponentResolver,\n): RouteRecordRaw | null {\n if (typeof dashboard.slug !== 'string' || dashboard.slug.length === 0) return null\n const permission = dashboard.permission\n const permissions = Array.isArray(permission)\n ? permission\n : typeof permission === 'string' && permission.length > 0\n ? [permission]\n : []\n return {\n path: `/dashboard/${dashboard.slug}`,\n name: `admin.dashboard.${dashboard.slug}`,\n component: components.dashboard,\n meta: {\n requiresAuth: true,\n kind: 'dashboard',\n slug: dashboard.slug,\n title: dashboard.label ?? 'Dashboard',\n permissions,\n },\n }\n}\n\nexport function buildRoutesFromManifest(\n manifest: AdminManifest | null,\n components: RouteComponentResolver,\n): RouteRecordRaw[] {\n if (manifest === null) return []\n\n const routes: RouteRecordRaw[] = []\n\n for (const resource of manifest.resources) {\n routes.push(...buildResourceRoutes(resource, components))\n }\n for (const screen of manifest.screens) {\n routes.push(buildScreenRoute(screen, components))\n }\n for (const s of manifest.settings) {\n routes.push(buildSettingsRoute(s, components))\n }\n for (const d of manifest.dashboards as DashboardMeta[]) {\n const route = buildDashboardRoute(d, components)\n if (route) routes.push(route)\n }\n\n return routes\n}\n","/**\n * Router-guards: auth + permissions.\n *\n * Логика:\n * 1. Если route.meta.requiresAuth и пользователь не залогинен → /login\n * с ?redirect=...\n * 2. Если у user'а есть pendingChallenge (2FA) — все защищённые роуты\n * редиректят на /login (challenge-form там).\n * 3. Если route.meta.permissions заданы — проверяем hasAnyPermission().\n * Нет ни одного → /forbidden (или роут с name='admin.forbidden').\n *\n * Guards используют useAuthStore — но НЕ берут client напрямую: всё через\n * permissions/isAuthenticated/pendingChallenge state. Stores должны быть\n * захайдрейчены до setup'а router'а.\n */\n\nimport type { RouteLocationNormalized, RouteLocationRaw } from 'vue-router'\nimport { useAuthStore } from '../stores/auth'\n\n/** Тип возвращаемого значения guard'а — true (passthrough) либо redirect-target. */\ntype GuardResult = boolean | RouteLocationRaw\n\n/**\n * Простая 3-арг функция (то что router.beforeEach принимает).\n * Не используем NavigationGuardWithThis<undefined>, т.к. она требует\n * `this: undefined` что неудобно для прямого вызова в тестах.\n */\ntype SimpleGuard = (\n to: RouteLocationNormalized,\n from: RouteLocationNormalized,\n next?: unknown,\n) => GuardResult\n\nexport interface AuthGuardOptions {\n /** Имя login-роута. По умолчанию 'admin.login'. */\n loginRouteName?: string\n /** Имя роута 403-страницы. По умолчанию 'admin.forbidden'. */\n forbiddenRouteName?: string\n /**\n * Имя query-параметра для возврата на исходную страницу после login.\n * По умолчанию 'redirect'.\n */\n redirectQueryKey?: string\n}\n\n/**\n * Создаёт beforeEach guard. Pinia должна быть activeInstance к моменту\n * вызова guard'а (router.beforeEach срабатывает на каждой навигации,\n * включая первую — Pinia уже должна быть установлена).\n */\nexport function createAuthGuard(opts: AuthGuardOptions = {}): SimpleGuard {\n const loginRouteName = opts.loginRouteName ?? 'admin.login'\n const forbiddenRouteName = opts.forbiddenRouteName ?? 'admin.forbidden'\n const redirectQueryKey = opts.redirectQueryKey ?? 'redirect'\n\n return (to: RouteLocationNormalized) => {\n // Login-роут всегда доступен.\n if (to.name === loginRouteName) {\n return true\n }\n\n const auth = useAuthStore()\n const requiresAuth = to.meta?.requiresAuth === true\n\n if (requiresAuth && !auth.isAuthenticated) {\n return {\n name: loginRouteName,\n query: { [redirectQueryKey]: to.fullPath },\n }\n }\n\n // Залогиненный, но в процессе 2FA — нельзя ходить никуда кроме login.\n if (auth.isChallengePending) {\n return {\n name: loginRouteName,\n query: { [redirectQueryKey]: to.fullPath },\n }\n }\n\n // Permission-check. ANY-логика (хотя бы одно permission совпало).\n const permissionsMeta = to.meta?.permissions\n if (Array.isArray(permissionsMeta) && permissionsMeta.length > 0) {\n const allowed = auth.hasAnyPermission(permissionsMeta as string[])\n if (!allowed) {\n return { name: forbiddenRouteName }\n }\n }\n\n return true\n }\n}\n\nexport interface TitleGuardOptions {\n /** Шаблон заголовка. {title} — meta.title, {brand} — название бренда. */\n template?: string\n /** Имя бренда. */\n brand?: string\n /** Default title если в meta нет. */\n fallback?: string\n}\n\n/**\n * Создаёт afterEach hook, обновляющий document.title.\n *\n * Шаблон по умолчанию: '{title} · {brand}' если оба, иначе один из.\n */\nexport function createTitleGuard(\n opts: TitleGuardOptions = {},\n): (to: RouteLocationNormalized, from?: RouteLocationNormalized, failure?: unknown) => void {\n const template = opts.template\n const brand = opts.brand ?? ''\n const fallback = opts.fallback ?? ''\n\n return (to) => {\n if (typeof document === 'undefined') return\n const t = (to.meta?.title as string | undefined) ?? fallback\n let title: string\n if (template) {\n title = template.replace('{title}', t).replace('{brand}', brand)\n } else if (t && brand) {\n title = `${t} · ${brand}`\n } else {\n title = t || brand\n }\n document.title = title\n }\n}\n","/**\n * createAdminRouter — фабрика admin-router'а.\n *\n * Использование:\n *\n * const router = createAdminRouter({\n * base: '/admin',\n * components: { ... },\n * brand: 'My App',\n * })\n * await router.replaceManifestRoutes(manifestStore.manifest)\n * app.use(router)\n *\n * Library намеренно не делает createWebHistory выбор за host'а — host передаёт\n * объект history (createWebHistory / createWebHashHistory).\n */\n\nimport {\n createRouter,\n createWebHistory,\n type Router,\n type RouteRecordRaw,\n type RouterHistory,\n} from 'vue-router'\nimport type { AdminManifest } from '../stores/manifest'\nimport { buildRoutesFromManifest, type RouteComponentResolver, type AdminRouteComponent } from './builder'\nimport { createAuthGuard, createTitleGuard, type AuthGuardOptions, type TitleGuardOptions } from './guards'\n\nexport interface AdminRouterOptions {\n /** Base URL admin-панели. По умолчанию '/admin'. */\n base?: string\n /** History-implementation. По умолчанию createWebHistory(base). */\n history?: RouterHistory\n /** Component resolver для resource/screen/settings/dashboard роутов. */\n components: RouteComponentResolver & {\n /** Login. */\n login: AdminRouteComponent\n /** Главная (либо overview-dashboard). */\n home: AdminRouteComponent\n /** 403 forbidden. */\n forbidden: AdminRouteComponent\n /** 404 not found. */\n notFound: AdminRouteComponent\n /** Страница профиля. */\n profile?: AdminRouteComponent\n /** Страница уведомлений. */\n notifications?: AdminRouteComponent\n }\n /** Дополнительные руты сверху динамики. */\n extraRoutes?: RouteRecordRaw[]\n /** Опции auth-guard. */\n authGuard?: AuthGuardOptions\n /** Опции title-guard. */\n titleGuard?: TitleGuardOptions\n}\n\n/**\n * Расширенный Router с возможностью пере-построить динамические роуты.\n */\nexport interface AdminRouter extends Router {\n /**\n * Пере-собрать динамические роуты из manifest'а.\n * Удаляет старые admin.resource.* / admin.screen.* / admin.settings.* / admin.dashboard.*\n * и заменяет на актуальные. Полезно при перезагрузке manifest'а.\n */\n replaceManifestRoutes(manifest: AdminManifest | null): void\n}\n\n/**\n * Префиксы dynamic-роутов которые подменяются при replaceManifestRoutes.\n */\nconst DYNAMIC_NAME_PREFIXES = [\n 'admin.resource.',\n 'admin.screen.',\n 'admin.settings.',\n 'admin.dashboard.',\n]\n\nfunction isDynamicRouteName(name: unknown): boolean {\n if (typeof name !== 'string') return false\n return DYNAMIC_NAME_PREFIXES.some((p) => name.startsWith(p))\n}\n\nexport function createAdminRouter(opts: AdminRouterOptions): AdminRouter {\n const base = opts.base ?? '/admin'\n const history = opts.history ?? createWebHistory(base)\n\n const staticRoutes: RouteRecordRaw[] = [\n {\n path: '/login',\n name: 'admin.login',\n component: opts.components.login,\n meta: { kind: 'auth', title: 'Вход' },\n },\n {\n path: '/',\n name: 'admin.home',\n component: opts.components.home,\n meta: { requiresAuth: true, kind: 'system', title: 'Главная' },\n },\n {\n path: '/forbidden',\n name: 'admin.forbidden',\n component: opts.components.forbidden,\n meta: { requiresAuth: true, kind: 'system', title: '403 — доступ запрещён' },\n },\n ]\n\n if (opts.components.profile) {\n staticRoutes.push({\n path: '/profile',\n name: 'admin.profile',\n component: opts.components.profile,\n meta: { requiresAuth: true, kind: 'system', title: 'Профиль' },\n })\n }\n\n if (opts.components.notifications) {\n staticRoutes.push({\n path: '/notifications',\n name: 'admin.notifications',\n component: opts.components.notifications,\n meta: { requiresAuth: true, kind: 'system', title: 'Уведомления' },\n })\n }\n\n // Catch-all 404 кладём в конец — vue-router matches in order и динамика\n // может быть добавлена позже через addRoute.\n const notFoundRoute: RouteRecordRaw = {\n path: '/:pathMatch(.*)*',\n name: 'admin.notFound',\n component: opts.components.notFound,\n meta: { kind: 'system', title: '404' },\n }\n\n const router = createRouter({\n history,\n routes: [...staticRoutes, ...(opts.extraRoutes ?? []), notFoundRoute],\n }) as AdminRouter\n\n router.beforeEach(createAuthGuard(opts.authGuard))\n router.afterEach(createTitleGuard(opts.titleGuard))\n\n router.replaceManifestRoutes = (manifest: AdminManifest | null): void => {\n // Удаляем все старые динамические роуты по name.\n const allRoutes = router.getRoutes()\n for (const route of allRoutes) {\n if (isDynamicRouteName(route.name)) {\n router.removeRoute(route.name as string)\n }\n }\n\n // Удаляем catch-all чтобы потом добавить его обратно последним.\n if (router.hasRoute('admin.notFound')) {\n router.removeRoute('admin.notFound')\n }\n\n const dynamic = buildRoutesFromManifest(manifest, opts.components)\n for (const route of dynamic) {\n router.addRoute(route)\n }\n router.addRoute(notFoundRoute)\n }\n\n return router\n}\n\nexport { buildRoutesFromManifest } from './builder'\nexport type { RouteComponentResolver, RouteMeta, AdminRouteComponent } from './builder'\nexport { createAuthGuard, createTitleGuard } from './guards'\nexport type { AuthGuardOptions, TitleGuardOptions } from './guards'\n","<script setup lang=\"ts\">\n/**\n * TextField — wrapper над UidInput из @dskripchenko/ui. Двусторонняя связь\n * с form-state через provideFormState/useFormState. Тип input'а (text/email/\n * url/password/tel/search) пробрасывается как `type`.\n */\nimport { computed } from 'vue'\nimport { UidInput } from '@dskripchenko/ui'\nimport { useFormState } from '../render/formState'\n\ninterface Props {\n name: string\n label?: string | null\n help?: string | null\n required?: boolean\n placeholder?: string | null\n inputType?: 'text' | 'email' | 'url' | 'password' | 'tel' | 'search'\n disabled?: boolean\n readonly?: boolean\n autocomplete?: string | null\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n label: null,\n help: null,\n placeholder: null,\n inputType: 'text',\n required: false,\n disabled: false,\n readonly: false,\n autocomplete: null,\n})\n\nconst form = useFormState()\nconst value = computed<string>(() => (form.getField(props.name) as string | null | undefined) ?? '')\nconst errorMsg = computed<string | undefined>(() => form.errors[props.name]?.[0])\n\nfunction onUpdate(next: string): void {\n form.setField(props.name, next)\n}\n</script>\n\n<template>\n <UidInput\n :model-value=\"value\"\n :type=\"inputType\"\n :label=\"label ?? undefined\"\n :hint=\"help ?? undefined\"\n :error=\"errorMsg\"\n :placeholder=\"placeholder ?? undefined\"\n :required=\"required\"\n :disabled=\"disabled\"\n :readonly=\"readonly\"\n :name=\"name\"\n :autocomplete=\"autocomplete ?? undefined\"\n @update:model-value=\"onUpdate\"\n />\n</template>\n","<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport { UidTextarea, UidFormField } from '@dskripchenko/ui'\nimport { useFormState } from '../render/formState'\n\ninterface Props {\n name: string\n label?: string | null\n help?: string | null\n required?: boolean\n placeholder?: string | null\n rows?: number\n disabled?: boolean\n readonly?: boolean\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n label: null,\n help: null,\n placeholder: null,\n rows: 4,\n required: false,\n disabled: false,\n readonly: false,\n})\n\nconst form = useFormState()\nconst value = computed<string>(() => (form.getField(props.name) as string | null | undefined) ?? '')\nconst errorMsg = computed<string | undefined>(() => form.errors[props.name]?.[0])\n\nfunction onUpdate(next: string): void {\n form.setField(props.name, next)\n}\n</script>\n\n<template>\n <UidFormField\n :label=\"label ?? undefined\"\n :hint=\"help ?? undefined\"\n :error=\"errorMsg\"\n :required=\"required\"\n :disabled=\"disabled\"\n >\n <UidTextarea\n :model-value=\"value\"\n :rows=\"rows\"\n :placeholder=\"placeholder ?? undefined\"\n :disabled=\"disabled\"\n :readonly=\"readonly\"\n :name=\"name\"\n @update:model-value=\"onUpdate\"\n />\n </UidFormField>\n</template>\n","<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport { UidNumberInput, UidFormField } from '@dskripchenko/ui'\nimport { useFormState } from '../render/formState'\n\ninterface Props {\n name: string\n label?: string | null\n help?: string | null\n required?: boolean\n placeholder?: string | null\n min?: number | null\n max?: number | null\n step?: number | null\n disabled?: boolean\n readonly?: boolean\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n label: null,\n help: null,\n placeholder: null,\n min: null,\n max: null,\n step: null,\n required: false,\n disabled: false,\n readonly: false,\n})\n\nconst form = useFormState()\nconst value = computed<number | null>(() => {\n const v = form.getField(props.name)\n if (v === null || v === undefined || v === '') return null\n return typeof v === 'number' ? v : Number(v)\n})\nconst errorMsg = computed<string | undefined>(() => form.errors[props.name]?.[0])\n\nfunction onUpdate(next: number | null): void {\n form.setField(props.name, next)\n}\n</script>\n\n<template>\n <UidFormField\n :label=\"label ?? undefined\"\n :hint=\"help ?? undefined\"\n :error=\"errorMsg\"\n :required=\"required\"\n :disabled=\"disabled\"\n >\n <UidNumberInput\n :model-value=\"value\"\n :min=\"min ?? undefined\"\n :max=\"max ?? undefined\"\n :step=\"step ?? undefined\"\n :placeholder=\"placeholder ?? undefined\"\n :disabled=\"disabled\"\n :readonly=\"readonly\"\n :name=\"name\"\n @update:model-value=\"onUpdate\"\n />\n </UidFormField>\n</template>\n","<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport { UidSelect, UidFormField } from '@dskripchenko/ui'\nimport { useFormState } from '../render/formState'\n\nexport interface SelectOption {\n value: string | number\n label: string\n disabled?: boolean\n}\n\ninterface Props {\n name: string\n options: SelectOption[]\n label?: string | null\n help?: string | null\n required?: boolean\n placeholder?: string | null\n disabled?: boolean\n searchable?: boolean\n clearable?: boolean\n size?: 'sm' | 'md' | 'lg'\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n label: null,\n help: null,\n placeholder: null,\n required: false,\n disabled: false,\n searchable: false,\n clearable: false,\n size: 'md',\n})\n\nconst form = useFormState()\nconst value = computed<string | number | null>(() => {\n const v = form.getField(props.name)\n if (v === null || v === undefined || v === '') return null\n return v as string | number\n})\nconst errorMsg = computed<string | undefined>(() => form.errors[props.name]?.[0])\n\nfunction onUpdate(next: string | number | null): void {\n form.setField(props.name, next)\n}\n</script>\n\n<template>\n <UidFormField\n :label=\"label ?? undefined\"\n :hint=\"help ?? undefined\"\n :error=\"errorMsg\"\n :required=\"required\"\n :disabled=\"disabled\"\n >\n <UidSelect\n :model-value=\"value\"\n :options=\"options\"\n :placeholder=\"placeholder ?? undefined\"\n :disabled=\"disabled\"\n :searchable=\"searchable\"\n :clearable=\"clearable\"\n :size=\"size\"\n @update:model-value=\"onUpdate\"\n />\n </UidFormField>\n</template>\n","<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport { UidCheckbox, UidFormField } from '@dskripchenko/ui'\nimport { useFormState } from '../render/formState'\n\ninterface Props {\n name: string\n label?: string | null\n help?: string | null\n required?: boolean\n inlineLabel?: string | null\n disabled?: boolean\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n label: null,\n help: null,\n inlineLabel: null,\n required: false,\n disabled: false,\n})\n\nconst form = useFormState()\nconst checked = computed<boolean>(() => Boolean(form.getField(props.name)))\nconst errorMsg = computed<string | undefined>(() => form.errors[props.name]?.[0])\n\nfunction onUpdate(next: boolean): void {\n form.setField(props.name, next)\n}\n</script>\n\n<template>\n <UidFormField\n :label=\"label ?? undefined\"\n :hint=\"help ?? undefined\"\n :error=\"errorMsg\"\n :required=\"required\"\n :disabled=\"disabled\"\n >\n <UidCheckbox\n :model-value=\"checked\"\n :disabled=\"disabled\"\n :name=\"name\"\n @update:model-value=\"onUpdate\"\n >\n <template v-if=\"inlineLabel\">{{ inlineLabel }}</template>\n </UidCheckbox>\n </UidFormField>\n</template>\n","<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport { UidDatePicker, UidFormField } from '@dskripchenko/ui'\nimport { useFormState } from '../render/formState'\n\ninterface Props {\n name: string\n label?: string | null\n help?: string | null\n required?: boolean\n /**\n * Тип input'а: 'date' (default), 'datetime-local', 'time'.\n * UidDatePicker внутри обрабатывает формат через свои props; для совместимости\n * со старым API оставляем prop.\n */\n inputType?: 'date' | 'datetime-local' | 'time'\n min?: string | null\n max?: string | null\n disabled?: boolean\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n label: null,\n help: null,\n inputType: 'date',\n min: null,\n max: null,\n required: false,\n disabled: false,\n})\n\nconst form = useFormState()\nconst value = computed<string | null>(() => {\n const v = form.getField(props.name)\n return v === null || v === undefined || v === '' ? null : String(v)\n})\nconst errorMsg = computed<string | undefined>(() => form.errors[props.name]?.[0])\n\nfunction onUpdate(next: string | null): void {\n form.setField(props.name, next)\n}\n</script>\n\n<template>\n <UidFormField\n :label=\"label ?? undefined\"\n :hint=\"help ?? undefined\"\n :error=\"errorMsg\"\n :required=\"required\"\n :disabled=\"disabled\"\n >\n <UidDatePicker\n :model-value=\"value\"\n :min=\"min ?? undefined\"\n :max=\"max ?? undefined\"\n :disabled=\"disabled\"\n :name=\"name\"\n @update:model-value=\"onUpdate\"\n />\n </UidFormField>\n</template>\n","<script setup lang=\"ts\">\n/**\n * Rows-layout — UidStack column.\n */\nimport { UidStack } from '@dskripchenko/ui'\nimport LayoutRenderer from '../render/LayoutRenderer.vue'\nimport type { LayoutNode } from '../render/LayoutRenderer.vue'\n\ninterface Props {\n items: LayoutNode[]\n /** CSS-зазор между элементами (token либо px), по умолчанию --uid-space-md. */\n gap?: string\n}\nwithDefaults(defineProps<Props>(), { gap: 'var(--uid-space-md)' })\n</script>\n\n<template>\n <UidStack direction=\"column\" :gap=\"gap\" align=\"stretch\">\n <LayoutRenderer v-for=\"(child, idx) in items\" :key=\"idx\" :node=\"child\" />\n </UidStack>\n</template>\n","<script setup lang=\"ts\">\n/**\n * Columns: 12-колоночный grid поверх UidGrid из @dskripchenko/ui.\n * Каждый item.span (1..cols) задаёт ширину; default равные доли.\n */\nimport { computed } from 'vue'\nimport { UidGrid } from '@dskripchenko/ui'\nimport LayoutRenderer from '../render/LayoutRenderer.vue'\nimport type { LayoutNode } from '../render/LayoutRenderer.vue'\n\ninterface Props {\n items: LayoutNode[]\n /** Зазор между ячейками (CSS, token или px). */\n gap?: string\n /** Сколько колонок в гриде (default 12). */\n cols?: number\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n gap: 'var(--uid-space-md)',\n cols: 12,\n})\n\nconst defaultSpan = computed(() => {\n if (props.items.length === 0) return props.cols\n return Math.max(1, Math.floor(props.cols / props.items.length))\n})\n\nfunction spanFor(item: LayoutNode): number {\n const s = (item as Record<string, unknown>).span\n if (typeof s === 'number' && s > 0) return Math.min(s, props.cols)\n return defaultSpan.value\n}\n</script>\n\n<template>\n <UidGrid :cols=\"cols\" :gap=\"gap\">\n <div\n v-for=\"(child, idx) in items\"\n :key=\"idx\"\n class=\"admin-columns__item\"\n :style=\"{ gridColumn: `span ${spanFor(child)} / span ${spanFor(child)}` }\"\n >\n <LayoutRenderer :node=\"child\" />\n </div>\n </UidGrid>\n</template>\n","<script setup lang=\"ts\">\n/**\n * Section/Block layout — UidCard с заголовком + опциональным описанием.\n */\nimport { UidCard } from '@dskripchenko/ui'\nimport LayoutRenderer from '../render/LayoutRenderer.vue'\nimport type { LayoutNode } from '../render/LayoutRenderer.vue'\n\ninterface Props {\n items: LayoutNode[]\n title?: string | null\n description?: string | null\n}\n\nwithDefaults(defineProps<Props>(), {\n title: null,\n description: null,\n})\n</script>\n\n<template>\n <UidCard padding=\"md\" class=\"admin-section\">\n <header v-if=\"title || description\" class=\"admin-section__header\">\n <h3 v-if=\"title\" class=\"admin-section__title\">{{ title }}</h3>\n <p v-if=\"description\" class=\"admin-section__description\">{{ description }}</p>\n </header>\n <div class=\"admin-section__body\">\n <LayoutRenderer v-for=\"(child, idx) in items\" :key=\"idx\" :node=\"child\" />\n </div>\n </UidCard>\n</template>\n\n<style>\n.admin-section { margin-bottom: var(--uid-space-md); }\n.admin-section__header { margin-bottom: var(--uid-space-sm); }\n.admin-section__title {\n margin: 0;\n font-size: var(--uid-font-size-sm);\n font-weight: var(--uid-font-weight-semibold);\n color: var(--uid-text-primary);\n}\n.admin-section__description {\n margin: var(--uid-space-2xs) 0 0;\n font-size: var(--uid-font-size-xs);\n color: var(--uid-text-tertiary);\n}\n.admin-section__body {\n display: flex;\n flex-direction: column;\n gap: var(--uid-space-sm);\n}\n</style>\n","<script setup lang=\"ts\">\n/**\n * TabsLayout поверх UidTabs/UidTab/UidTabPanel.\n * Активная вкладка двусторонне связана через v-model:active.\n */\nimport { ref } from 'vue'\nimport { UidTabs, UidTab, UidTabPanel } from '@dskripchenko/ui'\nimport LayoutRenderer from '../render/LayoutRenderer.vue'\nimport type { LayoutNode } from '../render/LayoutRenderer.vue'\n\nexport interface TabNode {\n /** Уникальный ключ вкладки. Если не задан — берётся индекс. */\n key?: string\n /** Текст вкладки. */\n label: string\n icon?: string | null\n items: LayoutNode[]\n}\n\ninterface Props {\n items: TabNode[]\n /** Активная вкладка (key либо индекс при отсутствии key). */\n active?: string | number\n}\n\nconst props = withDefaults(defineProps<Props>(), { active: 0 })\nconst emit = defineEmits<{ 'update:active': [value: string | number] }>()\n\nfunction tabKey(tab: TabNode, idx: number): string | number {\n return tab.key ?? idx\n}\n\nconst localActive = ref<string | number>(props.active ?? tabKey(props.items[0] ?? { label: '' }, 0))\n\nfunction onUpdate(value: string | number): void {\n localActive.value = value\n emit('update:active', value)\n}\n</script>\n\n<template>\n <UidTabs :model-value=\"localActive\" @update:model-value=\"onUpdate\">\n <template #list>\n <UidTab\n v-for=\"(tab, idx) in items\"\n :key=\"tabKey(tab, idx)\"\n :value=\"tabKey(tab, idx)\"\n >\n {{ tab.label }}\n </UidTab>\n </template>\n\n <UidTabPanel\n v-for=\"(tab, idx) in items\"\n :key=\"`panel-${tabKey(tab, idx)}`\"\n :value=\"tabKey(tab, idx)\"\n >\n <LayoutRenderer\n v-for=\"(child, cidx) in tab.items\"\n :key=\"cidx\"\n :node=\"child\"\n />\n </UidTabPanel>\n </UidTabs>\n</template>\n","/**\n * Default-bundle с минимальным набором builtin-компонентов.\n *\n * Использование:\n *\n * import { registerBuiltinComponents } from '@dskripchenko/laravel-admin'\n * registerBuiltinComponents()\n */\n\nimport { registerComponents } from './registry'\nimport TextField from '../fields/TextField.vue'\nimport TextAreaField from '../fields/TextAreaField.vue'\nimport NumberField from '../fields/NumberField.vue'\nimport SelectField from '../fields/SelectField.vue'\nimport CheckboxField from '../fields/CheckboxField.vue'\nimport DateField from '../fields/DateField.vue'\nimport RowsLayout from '../layouts/RowsLayout.vue'\nimport ColumnsLayout from '../layouts/ColumnsLayout.vue'\nimport SectionLayout from '../layouts/SectionLayout.vue'\nimport TabsLayout from '../layouts/TabsLayout.vue'\n\nexport function registerBuiltinComponents(): void {\n registerComponents({\n fields: {\n // Backend Field-классы из dskripchenko/laravel-admin отдают эти fieldType()\n // строки. Соответствие см. core/src/Field/{Input,TextArea,Select,...}.php.\n input: TextField,\n text: TextField,\n email: TextField,\n url: TextField,\n password: TextField,\n tel: TextField,\n search: TextField,\n slug: TextField,\n hidden: TextField,\n label: TextField,\n textarea: TextAreaField,\n // Fallback для wysiwyg/markdown/code — обычный TextAreaField.\n // Реальный rich-editor host подключает через subpath:\n // import { QuillField } from '@dskripchenko/laravel-admin/quill'\n // registerField('wysiwyg', QuillField)\n wysiwyg: TextAreaField,\n markdown: TextAreaField,\n code: TextAreaField,\n number: NumberField,\n slider: NumberField,\n rating: NumberField,\n select: SelectField,\n combobox: SelectField,\n radio: SelectField,\n tags: SelectField,\n 'morph-switcher': SelectField,\n relation: SelectField,\n cascader: SelectField,\n 'tree-select': SelectField,\n checkbox: CheckboxField,\n switcher: CheckboxField,\n boolean: CheckboxField,\n date: DateField,\n datetime: DateField,\n datepicker: DateField,\n 'date-range': DateField,\n time: DateField,\n 'time-picker': DateField,\n 'color-picker': TextField,\n },\n layouts: {\n rows: RowsLayout,\n columns: ColumnsLayout,\n section: SectionLayout,\n block: SectionLayout,\n tabs: TabsLayout,\n accordion: SectionLayout,\n group: RowsLayout,\n step: SectionLayout,\n wizard: SectionLayout,\n },\n })\n}\n","<script setup lang=\"ts\">\n/**\n * TextEntry — строковое read-only значение.\n *\n * Источник: prop.value либо record[name].\n * Для empty-state — placeholder («—» по умолчанию).\n */\nimport { computed } from 'vue'\nimport { tryUseRecord } from './recordContext'\n\ninterface Props {\n name?: string\n label?: string\n value?: string | number | null\n /** Заместитель пустого значения. */\n placeholder?: string\n /** Применить mono-font (например для ID/UUID). */\n mono?: boolean\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n name: '',\n label: '',\n value: undefined,\n placeholder: '—',\n mono: false,\n})\n\nconst record = tryUseRecord()\nconst display = computed<string>(() => {\n let v: unknown = props.value\n if (v === undefined && record && props.name) {\n v = record[props.name]\n }\n if (v === null || v === undefined || v === '') return props.placeholder\n return String(v)\n})\n</script>\n\n<template>\n <span :class=\"['admin-infolist-text', mono ? 'admin-infolist-text--mono' : '']\">\n {{ display }}\n </span>\n</template>\n\n<style>\n.admin-infolist-text {\n font-size: var(--uid-font-size-sm);\n color: var(--uid-text-primary);\n}\n.admin-infolist-text--mono {\n font-family: var(--uid-font-family-mono);\n font-size: var(--uid-font-size-xs);\n}\n</style>\n","<script setup lang=\"ts\">\n/**\n * BadgeEntry — строковое значение в виде UidBadge с variant'ом по value-mapping.\n *\n * Manifest:\n * { type: 'badge', name: 'status', label: 'Status',\n * map: { published: 'success', draft: 'warning', archived: 'danger' } }\n */\nimport { computed } from 'vue'\nimport { UidBadge } from '@dskripchenko/ui'\nimport { tryUseRecord } from './recordContext'\n\ntype BadgeVariant = 'default' | 'success' | 'warning' | 'danger' | 'info'\n\ninterface Props {\n name?: string\n label?: string\n value?: string | null\n /** map value → variant. Если не задан — default. */\n map?: Record<string, BadgeVariant>\n /** Принудительный variant. */\n variant?: BadgeVariant\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n name: '',\n label: '',\n value: undefined,\n map: () => ({}),\n variant: undefined,\n})\n\nconst record = tryUseRecord()\nconst value = computed<string>(() => {\n let v: unknown = props.value\n if (v === undefined && record && props.name) {\n v = record[props.name]\n }\n return v === null || v === undefined ? '' : String(v)\n})\nconst resolvedVariant = computed<BadgeVariant>(() => {\n if (props.variant) return props.variant\n return props.map[value.value] ?? 'default'\n})\n</script>\n\n<template>\n <UidBadge v-if=\"value\" :variant=\"resolvedVariant\">\n {{ value }}\n </UidBadge>\n <span v-else class=\"admin-infolist-text\">—</span>\n</template>\n","<script setup lang=\"ts\">\n/**\n * IconEntry — boolean-флаг как иконка (true → check, false → x).\n * Опционально labels: '{ true: \"Опубликовано\", false: \"Черновик\" }'.\n */\nimport { computed } from 'vue'\nimport { tryUseRecord } from './recordContext'\n\ninterface Props {\n name?: string\n label?: string\n value?: boolean | null\n /** Имя icon'и для true (lucide-key, например 'check-circle-2'). */\n trueIcon?: string\n /** Имя icon'и для false. */\n falseIcon?: string\n /** Текстовые подписи. */\n trueLabel?: string\n falseLabel?: string\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n name: '',\n label: '',\n value: undefined,\n trueIcon: 'check-circle-2',\n falseIcon: 'circle',\n trueLabel: '',\n falseLabel: '',\n})\n\nconst record = tryUseRecord()\nconst flag = computed<boolean>(() => {\n let v: unknown = props.value\n if (v === undefined && record && props.name) {\n v = record[props.name]\n }\n return Boolean(v)\n})\nconst displayLabel = computed(() => (flag.value ? props.trueLabel : props.falseLabel))\nconst iconName = computed(() => (flag.value ? props.trueIcon : props.falseIcon))\n</script>\n\n<template>\n <span :class=\"['admin-infolist-icon', flag ? 'admin-infolist-icon--on' : 'admin-infolist-icon--off']\">\n <span class=\"admin-infolist-icon__glyph\" :data-icon=\"iconName\" />\n <span v-if=\"displayLabel\">{{ displayLabel }}</span>\n </span>\n</template>\n\n<style>\n.admin-infolist-icon {\n display: inline-flex;\n align-items: center;\n gap: var(--uid-space-xs);\n font-size: var(--uid-font-size-sm);\n}\n.admin-infolist-icon--on { color: var(--uid-success); }\n.admin-infolist-icon--off { color: var(--uid-text-tertiary); }\n.admin-infolist-icon__glyph {\n display: inline-block;\n width: 14px;\n height: 14px;\n}\n</style>\n","<script setup lang=\"ts\">\n/**\n * KeyValueEntry — словарь {key: value} как UidDescriptionList.\n * Source: prop.value (Record) либо record[name].\n */\nimport { computed } from 'vue'\nimport { UidDescriptionList, UidDescriptionItem } from '@dskripchenko/ui'\nimport { tryUseRecord } from './recordContext'\n\ninterface Props {\n name?: string\n label?: string\n value?: Record<string, unknown>\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n name: '',\n label: '',\n value: undefined,\n})\n\nconst record = tryUseRecord()\nconst items = computed<Array<[string, unknown]>>(() => {\n let v: unknown = props.value\n if (v === undefined && record && props.name) {\n v = record[props.name]\n }\n if (v === null || v === undefined) return []\n if (typeof v !== 'object') return []\n return Object.entries(v as Record<string, unknown>)\n})\n\nfunction formatValue(v: unknown): string {\n if (v === null || v === undefined) return '—'\n if (typeof v === 'object') return JSON.stringify(v)\n return String(v)\n}\n</script>\n\n<template>\n <UidDescriptionList v-if=\"items.length > 0\" direction=\"vertical\" :columns=\"1\">\n <UidDescriptionItem\n v-for=\"[k, v] in items\"\n :key=\"k\"\n :label=\"k\"\n >\n {{ formatValue(v) }}\n </UidDescriptionItem>\n </UidDescriptionList>\n <span v-else class=\"admin-infolist-text\">—</span>\n</template>\n","/**\n * Default-bundle с минимальным набором builtin infolist-entry'ев.\n *\n * View-страница (ResourceViewPage) использует те же type-strings что и\n * form-page (ResourceFormPage) — backend Field::fieldType() возвращает\n * одинаковое имя в обоих контекстах. Поэтому infolist-mapping должен\n * покрывать те же типы что registerBuiltinComponents — fallback на\n * TextEntry для всех stdread-only представлений.\n */\n\nimport { registerInfolistEntries } from './registry'\nimport TextEntry from './TextEntry.vue'\nimport BadgeEntry from './BadgeEntry.vue'\nimport IconEntry from './IconEntry.vue'\nimport KeyValueEntry from './KeyValueEntry.vue'\n\nexport function registerBuiltinInfolistEntries(): void {\n registerInfolistEntries({\n // Дефолтные типы infolist (BadgeEntry::make() и т.п.).\n text: TextEntry,\n badge: BadgeEntry,\n icon: IconEntry,\n keyvalue: KeyValueEntry,\n 'key-value': KeyValueEntry,\n // Маппинг от backend Field::fieldType() → TextEntry для view-режима.\n // Host'ы могут перебить registerInfolistEntry('wysiwyg', WysiwygEntry).\n input: TextEntry,\n email: TextEntry,\n url: TextEntry,\n password: TextEntry,\n tel: TextEntry,\n search: TextEntry,\n slug: TextEntry,\n hidden: TextEntry,\n label: TextEntry,\n textarea: TextEntry,\n wysiwyg: TextEntry,\n markdown: TextEntry,\n code: TextEntry,\n number: TextEntry,\n slider: TextEntry,\n rating: TextEntry,\n select: TextEntry,\n combobox: TextEntry,\n radio: TextEntry,\n tags: TextEntry,\n 'morph-switcher': TextEntry,\n relation: TextEntry,\n cascader: TextEntry,\n 'tree-select': TextEntry,\n checkbox: TextEntry,\n switcher: TextEntry,\n boolean: TextEntry,\n date: TextEntry,\n datetime: TextEntry,\n datepicker: TextEntry,\n 'date-range': TextEntry,\n time: TextEntry,\n 'time-picker': TextEntry,\n 'color-picker': TextEntry,\n })\n}\n","/**\n * createAdminApp — фабрика-helper для host-проектов.\n *\n * Собирает Vue-app со всем нужным: Pinia, Router, AdminClient, hydrated\n * stores, built-in fields/layouts/widgets/infolist, default страницы.\n * Возвращает объект где `app` готов к `.mount('#admin-app')`.\n *\n * Минимальный пример (host's resources/js/admin.js):\n *\n * import { createAdminApp } from '@dskripchenko/laravel-admin'\n * import '@dskripchenko/laravel-admin/style.css'\n *\n * const { app } = createAdminApp(window.__ADMIN_BOOTSTRAP__)\n * app.mount('#admin-app')\n *\n * Расширенное использование с переопределением страниц:\n *\n * const { app } = createAdminApp(window.__ADMIN_BOOTSTRAP__, {\n * pages: { home: MyDashboard },\n * onAppCreated: (app) => app.use(SomePlugin),\n * })\n */\n\nimport { createApp, watch, type App, type Component } from 'vue'\nimport { createPinia } from 'pinia'\nimport { createWebHistory } from 'vue-router'\n\nimport AdminApp from './components/AdminApp.vue'\nimport HomePage from './components/HomePage.vue'\nimport ForbiddenPage from './components/ForbiddenPage.vue'\nimport NotFoundPage from './components/NotFoundPage.vue'\nimport SettingsPage from './components/SettingsPage.vue'\nimport UnknownScreenPage from './components/UnknownScreenPage.vue'\nimport { LoginPage } from './components/auth'\nimport {\n ResourceIndexPage,\n ResourceFormPage,\n ResourceViewPage,\n} from './components/resource'\nimport { ProfilePage } from './components/profile'\nimport { DashboardPage } from './components/dashboard'\n\nimport { createAdminClient, type AdminClient } from './api/client'\nimport { setAdminClient } from './stores'\nimport { useAuthStore } from './stores/auth'\nimport { useLocaleStore } from './stores/locale'\nimport { useThemeStore } from './stores/theme'\nimport { useNotificationsStore } from './stores/notifications'\nimport { useManifestStore } from './stores/manifest'\nimport { useMenuStore } from './stores/menu'\nimport { useNavigationStore } from './stores/navigation'\n\nimport { createAdminRouter, type AdminRouter, type AdminRouterOptions } from './router'\nimport { registerBuiltinComponents } from './components/render/builtin'\nimport { registerBuiltinWidgets } from './components/dashboard/builtin'\nimport { registerBuiltinInfolistEntries } from './components/infolist/builtin'\n\nimport type { AdminBootstrap } from './types/bootstrap'\n\nexport interface CreateAdminAppPages {\n /** Login page. По умолчанию core'овский LoginPage. */\n login?: Component\n /** Главная (после login). По умолчанию HomePage. */\n home?: Component\n /** 403. По умолчанию ForbiddenPage. */\n forbidden?: Component\n /** 404. По умолчанию NotFoundPage. */\n notFound?: Component\n /** Профиль. По умолчанию ProfilePage. */\n profile?: Component\n /** Resource index/form/view. По умолчанию core'овские. */\n resourceIndex?: Component\n resourceCreate?: Component\n resourceEdit?: Component\n resourceView?: Component\n /** Dashboard страница (для роутов admin.dashboard.*). */\n dashboard?: Component\n /** Settings page (для admin.settings.*). */\n settings?: Component\n /** Custom Screen page (для admin.screen.*). */\n screen?: Component\n}\n\nexport interface CreateAdminAppOptions {\n /**\n * Базовый URL admin-панели. По умолчанию берётся из bootstrap.baseUrl\n * (если он pathname вида '/admin'), иначе '/admin'.\n */\n base?: string\n /** Override отдельных страниц. */\n pages?: CreateAdminAppPages\n /** Дополнительные опции router'а (extraRoutes, history, guards). */\n router?: Partial<Omit<AdminRouterOptions, 'components'>>\n /** Hook для до-настройки app перед mount (app.use(plugin), app.provide(...)). */\n onAppCreated?: (app: App) => void\n /**\n * Не вызывать manifestStore.load() автоматически. По умолчанию false —\n * createAdminApp сам подгружает manifest и выстраивает динамические роуты.\n */\n skipManifestLoad?: boolean\n}\n\nexport interface AdminAppHandle {\n app: App\n router: AdminRouter\n client: AdminClient\n}\n\n/**\n * Создать Vue admin-app, готовый к `.mount('#admin-app')`.\n *\n * Шаги внутри:\n * 1. Pinia + AdminClient (axios через bootstrap.csrf/apiUrl).\n * 2. Hydrate auth/locale/theme/notifications stores из bootstrap.\n * 3. Регистрация built-in fields/layouts/widgets/infolist entries.\n * 4. Router со static-routes (login/home/profile/forbidden/notFound) +\n * async manifest load → replaceManifestRoutes для resource/screen/\n * settings/dashboard.\n * 5. Возврат `{ app, router, client }`. Host вызывает `app.mount(...)`.\n */\nexport function createAdminApp(\n bootstrap: AdminBootstrap,\n options: CreateAdminAppOptions = {},\n): AdminAppHandle {\n const pages = options.pages ?? {}\n const base = options.base ?? deriveBase(bootstrap.baseUrl) ?? '/admin'\n\n // 1. AdminClient\n const client = createAdminClient({\n baseURL: bootstrap.apiUrl,\n csrfToken: bootstrap.csrf,\n })\n setAdminClient(client)\n\n // 2. Vue app + Pinia\n const app = createApp(AdminApp)\n const pinia = createPinia()\n app.use(pinia)\n\n // 3. Pinia stores hydrate\n useAuthStore().hydrate(bootstrap)\n useLocaleStore().hydrate(bootstrap)\n useThemeStore().hydrate(bootstrap)\n useNotificationsStore().hydrate(bootstrap)\n\n // 4. Builtin field/layout/widget/infolist registries\n registerBuiltinComponents()\n registerBuiltinWidgets()\n registerBuiltinInfolistEntries()\n\n // 5. Router\n const router = createAdminRouter({\n base,\n history: options.router?.history ?? createWebHistory(base),\n components: {\n login: pages.login ?? LoginPage,\n home: pages.home ?? HomePage,\n forbidden: pages.forbidden ?? ForbiddenPage,\n notFound: pages.notFound ?? NotFoundPage,\n profile: pages.profile ?? ProfilePage,\n resourceIndex: pages.resourceIndex ?? ResourceIndexPage,\n resourceCreate: pages.resourceCreate ?? ResourceFormPage,\n resourceEdit: pages.resourceEdit ?? ResourceFormPage,\n resourceView: pages.resourceView ?? ResourceViewPage,\n dashboard: pages.dashboard ?? DashboardPage,\n settings: pages.settings ?? SettingsPage,\n screen: pages.screen ?? UnknownScreenPage,\n },\n extraRoutes: options.router?.extraRoutes,\n authGuard: options.router?.authGuard,\n titleGuard: options.router?.titleGuard,\n })\n app.use(router)\n\n // 5.1 Top loading-bar hooks: pending++ при старте навигации, pending--\n // при её завершении. ResourceIndexPage/FormPage добавляют свой counter\n // поверх через onMounted+onBeforeUnmount → useNavigationStore.\n const navStore = useNavigationStore()\n router.beforeEach((to, from, next) => {\n if (to.fullPath !== from.fullPath) navStore.start()\n next()\n })\n router.afterEach(() => {\n navStore.end()\n })\n router.onError(() => {\n navStore.end()\n })\n\n // 6. Manifest async-load + dynamic routes (только если authenticated;\n // при появлении user после login — manifest подгружается автоматически).\n if (!options.skipManifestLoad) {\n const manifestStore = useManifestStore()\n const authStore = useAuthStore()\n\n const menuStore = useMenuStore()\n\n const loadAndApply = (): void => {\n // Параллельно с manifest'ом тянем sidebar-меню (от backend menu endpoint).\n void menuStore.load().catch(() => undefined)\n\n void manifestStore\n .load()\n .then((manifest) => {\n router.replaceManifestRoutes(manifest)\n // Если текущий route был разрешён в catch-all notFound (deep-link\n // на /r/articles/123/edit при первом mount, когда динамические\n // роуты ещё не были добавлены) — перерезолвим его теперь, когда\n // routes есть.\n const current = router.currentRoute.value\n if (current.name === 'admin.notFound' && current.fullPath !== '/') {\n void router.replace(current.fullPath)\n }\n })\n .catch((error: unknown) => {\n // Silent fail — host может перехватить через onAppCreated →\n // app.config.errorHandler. Manifest перезагрузится при следующем\n // появлении user (watch ниже).\n if (typeof console !== 'undefined') {\n console.error('[laravel-admin] manifest load failed:', error)\n }\n })\n }\n\n if (authStore.isAuthenticated) {\n // Inline-bootstrap уже принёс user'а — грузим сразу.\n loadAndApply()\n }\n // Если user'а ещё нет (login flow) либо появится позже —\n // подписываемся и грузим когда появится. immediate: false чтобы не\n // дублировать вызов при isAuthenticated=true выше.\n watch(\n () => authStore.user,\n (newUser, oldUser) => {\n if (newUser && !oldUser) {\n loadAndApply()\n }\n },\n )\n }\n\n // 7. host hook\n options.onAppCreated?.(app)\n\n return { app, router, client }\n}\n\n/**\n * Извлечь base path из bootstrap.baseUrl ('http://app.test/admin' → '/admin').\n */\nfunction deriveBase(baseUrl: string | undefined): string | null {\n if (!baseUrl) return null\n try {\n const url = new URL(baseUrl)\n return url.pathname || '/admin'\n } catch {\n return baseUrl.startsWith('/') ? baseUrl : null\n }\n}\n","/**\n * Загрузка bootstrap-payload'а в SPA.\n *\n * Поддерживает обе стратегии:\n * - 'inline' — читает window.__ADMIN_BOOTSTRAP__ (инжект через\n * shell.blade при strategy=inline).\n * - 'xhr' — fetch'ит /api/admin/system/bootstrap.\n *\n * Если оба способа не дали результата — throw'ит. SPA должна это поймать\n * и показать full-screen error.\n */\n\nimport type { AdminBootstrap } from '../types/bootstrap'\nimport type { AdminClient } from './client'\nimport { NetworkError } from './errors'\n\nexport interface LoadBootstrapOptions {\n /** Если задан client — fallback на xhr через него. */\n client?: AdminClient\n /** Override URL для xhr. Default: '/system/bootstrap'. */\n xhrUrl?: string\n}\n\n/**\n * Возвращает bootstrap или null если не загрузился.\n *\n * Порядок:\n * 1. window.__ADMIN_BOOTSTRAP__ (inline-strategy).\n * 2. xhr fetch если передан client.\n * 3. null — caller решает что делать (показать error-screen).\n */\nexport async function loadBootstrap(\n opts: LoadBootstrapOptions = {},\n): Promise<AdminBootstrap | null> {\n const inline = readInlineBootstrap()\n if (inline) {\n return inline\n }\n\n if (opts.client) {\n try {\n const url = opts.xhrUrl ?? '/system/bootstrap'\n return await opts.client.get<AdminBootstrap>(url)\n } catch (err) {\n if (err instanceof NetworkError) {\n // Network failure — caller должен показать offline-screen.\n return null\n }\n throw err\n }\n }\n\n return null\n}\n\n/**\n * Прочитать bootstrap из window — только в браузерном контексте.\n */\nexport function readInlineBootstrap(): AdminBootstrap | null {\n if (typeof window === 'undefined') return null\n return window.__ADMIN_BOOTSTRAP__ ?? null\n}\n\n/**\n * Прочитать CSRF-token из meta-tag (Blade-injection через `csrf_token()`).\n *\n * Используется как fallback если bootstrap.csrf отсутствует.\n */\nexport function readCsrfFromMeta(): string | null {\n if (typeof document === 'undefined') return null\n const meta = document.querySelector('meta[name=\"csrf-token\"]')\n return meta?.getAttribute('content') ?? null\n}\n","<script setup lang=\"ts\">\n/**\n * NotificationsDrawer — UidDrawer (right, 400px) с tabs (Все/Непрочитанные/\n * Прочитанные) и списком notification-items.\n *\n * Эталон handoff'а (screens-secondary.jsx → NotificationDrawer):\n * - Header: «Уведомления (3)» + actions (Прочитать все)\n * - Tabs: counts, активный tab подсвечен accent\n * - Item: kind-coloured icon (info/success/warning/error) +\n * title (bold если unread) + body + relative timestamp;\n * unread items имеют tinted background + dot слева\n * - Click на item → переход на data.url + auto markAsRead\n * - Hover показывает кнопку '×' (destroy)\n */\nimport { computed, watch } from 'vue'\nimport { UidButton, UidDrawer, UidTabs, UidTab, UidTabPanel } from '@dskripchenko/ui'\nimport { useNotificationsStore, type NotificationFilter, type NotificationItem } from '../../stores/notifications'\n\ninterface Props {\n /** v-model:open. */\n open: boolean\n}\n\nconst props = defineProps<Props>()\nconst emit = defineEmits<{\n 'update:open': [value: boolean]\n /** Click on notification item — host обрабатывает navigation на data.url. */\n 'select-item': [item: NotificationItem]\n}>()\n\nconst notifications = useNotificationsStore()\n\nfunction setOpen(v: boolean): void {\n emit('update:open', v)\n}\n\n// Загружаем при открытии.\nwatch(\n () => props.open,\n async (next) => {\n if (next) {\n await notifications.load(notifications.lastFilter ?? 'all', 1).catch(() => undefined)\n }\n },\n { immediate: true },\n)\n\nconst activeFilter = computed<NotificationFilter>(() => notifications.lastFilter ?? 'all')\n\nasync function setFilter(filter: NotificationFilter | string | number): Promise<void> {\n await notifications\n .load(filter as NotificationFilter, 1)\n .catch(() => undefined)\n}\n\nasync function markAllRead(): Promise<void> {\n await notifications.markAllAsRead().catch(() => undefined)\n}\n\nasync function onItemClick(item: NotificationItem): Promise<void> {\n emit('select-item', item)\n if (!item.read_at) {\n await notifications.markAsRead(item.id).catch(() => undefined)\n }\n}\n\nasync function onDestroy(item: NotificationItem, event: Event): Promise<void> {\n event.stopPropagation()\n await notifications.destroy(item.id).catch(() => undefined)\n}\n\nfunction itemKind(item: NotificationItem): 'info' | 'success' | 'warning' | 'danger' {\n const lvl = item.data.level\n if (lvl === 'success' || lvl === 'warning' || lvl === 'danger') return lvl\n return 'info'\n}\n\nfunction itemTitle(item: NotificationItem): string {\n return (item.data.title as string | undefined) ?? '—'\n}\n\nfunction itemBody(item: NotificationItem): string {\n return (item.data.body as string | undefined) ?? ''\n}\n\nfunction relTime(iso: string | null): string {\n if (!iso) return ''\n const dt = new Date(iso)\n const diff = Math.max(0, Date.now() - dt.getTime())\n const mins = Math.floor(diff / 60000)\n if (mins < 1) return 'только что'\n if (mins < 60) return `${mins} мин назад`\n const hours = Math.floor(mins / 60)\n if (hours < 24) return `${hours} ч назад`\n const days = Math.floor(hours / 24)\n if (days < 7) return `${days} д назад`\n return dt.toLocaleDateString('ru-RU')\n}\n</script>\n\n<template>\n <UidDrawer\n :model-value=\"open\"\n side=\"right\"\n width=\"400px\"\n title=\"Уведомления\"\n @update:model-value=\"setOpen\"\n >\n <template #header>\n <div class=\"admin-notifs__hd\">\n <h2 class=\"admin-notifs__title\">\n Уведомления\n <span v-if=\"notifications.unreadCount > 0\" class=\"admin-notifs__count\">\n ({{ notifications.unreadCount }})\n </span>\n </h2>\n <UidButton\n v-if=\"notifications.unreadCount > 0\"\n variant=\"ghost\"\n size=\"sm\"\n @click=\"markAllRead\"\n >\n Прочитать все\n </UidButton>\n </div>\n </template>\n\n <UidTabs :model-value=\"activeFilter\" @update:model-value=\"setFilter\">\n <template #list>\n <UidTab value=\"all\">Все</UidTab>\n <UidTab value=\"unread\">\n Непрочитанные<template v-if=\"notifications.unreadCount > 0\">\n ({{ notifications.unreadCount }})\n </template>\n </UidTab>\n <UidTab value=\"read\">Прочитанные</UidTab>\n </template>\n\n <UidTabPanel v-for=\"filter in (['all','unread','read'] as const)\" :key=\"filter\" :value=\"filter\">\n <ul class=\"admin-notifs__list\">\n <li v-if=\"notifications.loading\" class=\"admin-notifs__empty\">\n Загрузка…\n </li>\n <li v-else-if=\"notifications.items.length === 0\" class=\"admin-notifs__empty\">\n Нет уведомлений\n </li>\n <li\n v-for=\"item in notifications.items\"\n :key=\"item.id\"\n :class=\"[\n 'admin-notifs__item',\n `admin-notifs__item--${itemKind(item)}`,\n { 'admin-notifs__item--unread': !item.read_at },\n ]\"\n @click=\"onItemClick(item)\"\n >\n <span class=\"admin-notifs__icon\" :data-kind=\"itemKind(item)\" />\n <div class=\"admin-notifs__body\">\n <div class=\"admin-notifs__row1\">\n <strong v-if=\"!item.read_at\" class=\"admin-notifs__title-strong\">\n {{ itemTitle(item) }}\n </strong>\n <span v-else class=\"admin-notifs__title-soft\">{{ itemTitle(item) }}</span>\n <span class=\"admin-notifs__time\">{{ relTime(item.created_at) }}</span>\n </div>\n <p v-if=\"itemBody(item)\" class=\"admin-notifs__text\">{{ itemBody(item) }}</p>\n </div>\n <button\n type=\"button\"\n class=\"admin-notifs__close\"\n :aria-label=\"'Удалить'\"\n @click=\"onDestroy(item, $event)\"\n >\n ×\n </button>\n </li>\n </ul>\n </UidTabPanel>\n </UidTabs>\n </UidDrawer>\n</template>\n\n<style>\n.admin-notifs__hd {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--uid-space-sm);\n}\n.admin-notifs__title {\n margin: 0;\n font-size: var(--uid-font-size-md);\n font-weight: var(--uid-font-weight-semibold);\n}\n.admin-notifs__count {\n color: var(--uid-text-tertiary);\n font-weight: var(--uid-font-weight-regular);\n font-size: var(--uid-font-size-sm);\n}\n\n.admin-notifs__list {\n list-style: none;\n margin: 0;\n padding: 0;\n}\n.admin-notifs__empty {\n padding: var(--uid-space-xl) var(--uid-space-md);\n text-align: center;\n color: var(--uid-text-tertiary);\n font-size: var(--uid-font-size-sm);\n}\n.admin-notifs__item {\n position: relative;\n display: flex;\n gap: var(--uid-space-sm);\n padding: var(--uid-space-sm) var(--uid-space-md);\n cursor: pointer;\n border-bottom: 1px solid var(--uid-border-subtle);\n}\n.admin-notifs__item:hover { background: var(--uid-surface-hover); }\n.admin-notifs__item--unread {\n background: color-mix(in srgb, var(--uid-accent) 6%, transparent);\n}\n.admin-notifs__item--unread:hover {\n background: color-mix(in srgb, var(--uid-accent) 10%, transparent);\n}\n\n.admin-notifs__icon {\n width: 28px;\n height: 28px;\n border-radius: var(--uid-radius-md);\n flex: none;\n margin-top: 2px;\n}\n.admin-notifs__icon[data-kind='info'] {\n background: color-mix(in srgb, var(--uid-info) 14%, transparent);\n}\n.admin-notifs__icon[data-kind='success'] {\n background: color-mix(in srgb, var(--uid-success) 14%, transparent);\n}\n.admin-notifs__icon[data-kind='warning'] {\n background: color-mix(in srgb, var(--uid-warning) 14%, transparent);\n}\n.admin-notifs__icon[data-kind='danger'] {\n background: color-mix(in srgb, var(--uid-danger) 14%, transparent);\n}\n\n.admin-notifs__body { flex: 1; min-width: 0; }\n.admin-notifs__row1 {\n display: flex;\n align-items: baseline;\n gap: var(--uid-space-sm);\n margin-bottom: 2px;\n}\n.admin-notifs__title-strong {\n font-size: var(--uid-font-size-sm);\n font-weight: var(--uid-font-weight-semibold);\n color: var(--uid-text-primary);\n flex: 1;\n min-width: 0;\n}\n.admin-notifs__title-soft {\n font-size: var(--uid-font-size-sm);\n color: var(--uid-text-primary);\n flex: 1;\n min-width: 0;\n}\n.admin-notifs__time {\n font-size: 11px;\n color: var(--uid-text-tertiary);\n flex: none;\n font-variant-numeric: tabular-nums;\n}\n.admin-notifs__text {\n margin: 0;\n font-size: var(--uid-font-size-xs);\n color: var(--uid-text-secondary);\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n.admin-notifs__close {\n position: absolute;\n top: 6px;\n right: 8px;\n appearance: none;\n border: 0;\n background: transparent;\n color: var(--uid-text-tertiary);\n cursor: pointer;\n font-size: 18px;\n width: 22px;\n height: 22px;\n border-radius: var(--uid-radius-sm);\n opacity: 0;\n transition: opacity var(--uid-duration-fast, 100ms);\n}\n.admin-notifs__item:hover .admin-notifs__close { opacity: 1; }\n.admin-notifs__close:hover {\n background: var(--uid-surface-hover);\n color: var(--uid-text-primary);\n}\n</style>\n","<script setup lang=\"ts\">\n/**\n * ImportWizardPage — 4-step wizard для импорта данных в Resource.\n *\n * Эталон: docs/design_handoff_laravel_admin/screens-secondary.jsx (ImportWizard).\n *\n * Шаги:\n * 1. Загрузка файла — UidFileUpload (CSV/TSV/XLSX)\n * 2. Сопоставление колонок — header'ы файла → field-name'ы ресурса\n * 3. Предпросмотр — таблица первых N строк с warning'ами\n * 4. Импорт — progress-bar + KPI (created/updated/errors)\n *\n * Library предоставляет каркас + state. Конкретные API-вызовы (analyze\n * uploaded file → headers/sample, mapping submit → preview, run import →\n * progress events) — host реализует через emit'ы.\n */\nimport { computed, ref } from 'vue'\nimport {\n UidAlert,\n UidButton,\n UidCard,\n UidFileUpload,\n UidProgress,\n UidSelect,\n UidStat,\n UidStepper,\n UidTable,\n type UidTableColumn,\n} from '@dskripchenko/ui'\n\ninterface ColumnHeader {\n key: string\n label: string\n sample?: string\n}\n\ninterface Mapping {\n /** Header из файла. */\n source: string\n /** Field-name в ресурсе либо null = пропустить. */\n target: string | null\n}\n\ninterface PreviewRow extends Record<string, unknown> {\n __warning?: string | null\n}\n\ninterface ImportProgress {\n created: number\n updated: number\n errors: number\n total: number\n}\n\ninterface Props {\n /** Заголовок страницы. */\n title?: string\n /** Опции для select'а target field'а на step 2. */\n fieldOptions: Array<{ value: string; label: string }>\n /** Headers + sample из uploaded file (host передаёт после step 1). */\n headers?: ColumnHeader[]\n /** Preview rows с warning'ами (host передаёт после step 2 submit). */\n preview?: PreviewRow[]\n /** Preview-table columns (host передаёт). */\n previewColumns?: UidTableColumn[]\n /** Финальная сводка импорта. */\n progress?: ImportProgress | null\n /** Внешне controlled-mode current step (опц.). */\n step?: number\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n title: 'Импорт',\n headers: () => [],\n preview: () => [],\n previewColumns: () => [],\n progress: null,\n step: undefined,\n})\n\nconst emit = defineEmits<{\n /** Файл загружен — host анализирует, отдаёт headers через v-bind. */\n 'file-uploaded': [file: File]\n /** Mapping submit — host генерирует preview. */\n 'mapping-submit': [mapping: Mapping[]]\n /** Run import — host выполняет с реальной записью. */\n 'run-import': []\n /** Cancel wizard. */\n cancel: []\n}>()\n\nconst STEPS = [\n { label: 'Загрузка', description: 'CSV / TSV / XLSX' },\n { label: 'Сопоставление', description: 'Колонки файла → поля' },\n { label: 'Предпросмотр', description: 'Проверка первых строк' },\n { label: 'Импорт', description: 'Запуск + сводка' },\n]\n\nconst internalStep = ref(0)\nconst currentStep = computed(() => props.step ?? internalStep.value)\n\nfunction setStep(idx: number): void {\n if (props.step !== undefined) return // controlled mode — host сам сдвигает\n if (idx < 0 || idx >= STEPS.length) return\n internalStep.value = idx\n}\n\n// Step 1: file upload\nconst uploadedFiles = ref<Array<{ file: File; id: string }>>([])\nfunction onUpload(files: Array<{ file: File; id: string }>): void {\n uploadedFiles.value = files\n if (files.length > 0) {\n emit('file-uploaded', files[0].file)\n }\n}\n\n// Step 2: mapping\nconst mapping = ref<Record<string, string | null>>({})\n\nfunction setTarget(source: string, value: string | number | null): void {\n mapping.value[source] = value === null || value === '' ? null : String(value)\n}\n\nfunction buildMapping(): Mapping[] {\n return props.headers.map((h) => ({\n source: h.key,\n target: mapping.value[h.key] ?? null,\n }))\n}\n\nfunction onMappingSubmit(): void {\n emit('mapping-submit', buildMapping())\n setStep(2)\n}\n\n// Step 3 → 4\nfunction onConfirmRun(): void {\n emit('run-import')\n setStep(3)\n}\n\n// Кнопки навигации\nconst canGoBack = computed(() => currentStep.value > 0)\nconst canGoNext = computed(() => {\n switch (currentStep.value) {\n case 0: return uploadedFiles.value.length > 0\n case 1: return Object.values(mapping.value).some((v) => v !== null)\n case 2: return true\n default: return false\n }\n})\n\nconst fileOptions = computed<Array<{ value: string; label: string }>>(() => {\n return [\n { value: '', label: 'Не импортировать' },\n ...props.fieldOptions,\n ]\n})\n\nfunction onCancel(): void {\n emit('cancel')\n}\n</script>\n\n<template>\n <section class=\"admin-page admin-import-wizard\">\n <header class=\"admin-page__hd\">\n <div class=\"admin-page__title-wrap\">\n <h1 class=\"admin-page__title\">{{ title }}</h1>\n </div>\n <div class=\"admin-page__actions\">\n <UidButton variant=\"ghost\" @click=\"onCancel\">Отмена</UidButton>\n </div>\n </header>\n\n <UidStepper :steps=\"STEPS\" :current=\"currentStep\" />\n\n <!-- Step 1: Upload -->\n <UidCard v-if=\"currentStep === 0\" padding=\"md\" class=\"admin-import-wizard__card\">\n <header class=\"admin-import-wizard__card-hd\">\n <h3>1. Загрузите файл</h3>\n <p>CSV / TSV / XLSX, до 50 MB</p>\n </header>\n <UidFileUpload\n :model-value=\"uploadedFiles\"\n accept=\".csv,.tsv,.xlsx\"\n :max-size=\"50 * 1024 * 1024\"\n :max-files=\"1\"\n primary-text=\"Перетащите файл сюда или\"\n secondary-text=\"нажмите чтобы выбрать\"\n @update:model-value=\"onUpload\"\n />\n </UidCard>\n\n <!-- Step 2: Mapping -->\n <UidCard v-else-if=\"currentStep === 1\" padding=\"md\" class=\"admin-import-wizard__card\">\n <header class=\"admin-import-wizard__card-hd\">\n <h3>2. Сопоставьте колонки</h3>\n <p>Выберите поле ресурса для каждой колонки файла</p>\n </header>\n\n <div v-if=\"headers.length === 0\" class=\"admin-import-wizard__empty\">\n Нет данных — host ещё не отдал headers. Загрузите файл сначала.\n </div>\n\n <div v-else class=\"admin-import-wizard__mapping\">\n <div v-for=\"h in headers\" :key=\"h.key\" class=\"admin-import-wizard__map-row\">\n <div class=\"admin-import-wizard__map-source\">\n <strong>{{ h.label }}</strong>\n <span v-if=\"h.sample\" class=\"admin-import-wizard__map-sample\">\n «{{ h.sample }}»\n </span>\n </div>\n <span class=\"admin-import-wizard__map-arrow\">→</span>\n <UidSelect\n :model-value=\"mapping[h.key] ?? ''\"\n :options=\"fileOptions\"\n placeholder=\"Не импортировать\"\n @update:model-value=\"(v) => setTarget(h.key, v)\"\n />\n </div>\n </div>\n </UidCard>\n\n <!-- Step 3: Preview -->\n <UidCard v-else-if=\"currentStep === 2\" padding=\"md\" class=\"admin-import-wizard__card\">\n <header class=\"admin-import-wizard__card-hd\">\n <h3>3. Предпросмотр</h3>\n <p>Первые {{ preview.length }} строк перед импортом</p>\n </header>\n\n <UidAlert\n v-if=\"preview.some((r) => r.__warning)\"\n variant=\"warning\"\n style=\"margin-bottom: var(--uid-space-md);\"\n >\n Часть строк имеет предупреждения — проверьте перед импортом.\n </UidAlert>\n\n <UidTable\n v-if=\"previewColumns.length > 0\"\n :columns=\"previewColumns\"\n :data=\"preview\"\n />\n <div v-else class=\"admin-import-wizard__empty\">\n Host не передал previewColumns/preview.\n </div>\n </UidCard>\n\n <!-- Step 4: Run + Summary -->\n <UidCard v-else padding=\"md\" class=\"admin-import-wizard__card\">\n <header class=\"admin-import-wizard__card-hd\">\n <h3>4. Импорт</h3>\n </header>\n\n <div v-if=\"!progress\" class=\"admin-import-wizard__empty\">\n Запускается импорт…\n </div>\n <template v-else>\n <UidProgress\n v-if=\"progress.total > 0\"\n :model-value=\"progress.created + progress.updated + progress.errors\"\n :max=\"progress.total\"\n />\n <div class=\"admin-import-wizard__kpi\">\n <UidStat title=\"Создано\" :value=\"progress.created\" tone=\"success\" />\n <UidStat title=\"Обновлено\" :value=\"progress.updated\" tone=\"info\" />\n <UidStat title=\"Ошибки\" :value=\"progress.errors\" tone=\"danger\" />\n </div>\n </template>\n </UidCard>\n\n <!-- Navigation buttons -->\n <footer class=\"admin-import-wizard__nav\">\n <UidButton\n v-if=\"canGoBack\"\n variant=\"ghost\"\n @click=\"setStep(currentStep - 1)\"\n >\n Назад\n </UidButton>\n <span style=\"flex:1\" />\n <UidButton\n v-if=\"currentStep === 0\"\n variant=\"primary\"\n :disabled=\"!canGoNext\"\n @click=\"setStep(1)\"\n >\n Далее\n </UidButton>\n <UidButton\n v-else-if=\"currentStep === 1\"\n variant=\"primary\"\n :disabled=\"!canGoNext\"\n @click=\"onMappingSubmit\"\n >\n Подтвердить mapping\n </UidButton>\n <UidButton\n v-else-if=\"currentStep === 2\"\n variant=\"primary\"\n @click=\"onConfirmRun\"\n >\n Запустить импорт\n </UidButton>\n </footer>\n </section>\n</template>\n\n<style>\n.admin-import-wizard {\n max-width: 1100px;\n margin: 0 auto;\n}\n.admin-import-wizard__card {\n margin-top: var(--uid-space-md);\n}\n.admin-import-wizard__card-hd {\n margin-bottom: var(--uid-space-md);\n}\n.admin-import-wizard__card-hd h3 {\n margin: 0 0 var(--uid-space-2xs);\n font-size: var(--uid-font-size-md);\n font-weight: var(--uid-font-weight-semibold);\n}\n.admin-import-wizard__card-hd p {\n margin: 0;\n font-size: var(--uid-font-size-xs);\n color: var(--uid-text-tertiary);\n}\n.admin-import-wizard__empty {\n padding: var(--uid-space-md);\n text-align: center;\n color: var(--uid-text-tertiary);\n font-size: var(--uid-font-size-sm);\n}\n.admin-import-wizard__mapping {\n display: flex;\n flex-direction: column;\n gap: var(--uid-space-sm);\n}\n.admin-import-wizard__map-row {\n display: grid;\n grid-template-columns: 1fr auto 1fr;\n gap: var(--uid-space-md);\n align-items: center;\n}\n.admin-import-wizard__map-source {\n display: flex;\n align-items: center;\n gap: var(--uid-space-sm);\n}\n.admin-import-wizard__map-sample {\n color: var(--uid-text-tertiary);\n font-size: var(--uid-font-size-xs);\n font-style: italic;\n}\n.admin-import-wizard__map-arrow {\n color: var(--uid-text-tertiary);\n font-size: var(--uid-font-size-md);\n}\n.admin-import-wizard__kpi {\n display: grid;\n grid-template-columns: repeat(3, minmax(0, 1fr));\n gap: var(--uid-space-md);\n margin-top: var(--uid-space-md);\n}\n.admin-import-wizard__nav {\n display: flex;\n align-items: center;\n gap: var(--uid-space-sm);\n margin-top: var(--uid-space-md);\n}\n</style>\n","<script setup lang=\"ts\">\n/**\n * FieldGalleryPage — каталог field-компонентов.\n *\n * Эталон: docs/design_handoff_laravel_admin/screens-secondary.jsx (FieldGallery).\n *\n * 3-col grid из demo-cards. Каждая card:\n * - Group label (например \"Текстовые\")\n * - Тип поля (json type-key)\n * - Демо-компонент с sample-данными\n * - Краткое описание\n *\n * Используется как:\n * 1. Тестовая площадка для devs (визуально все Uid* fields на одной странице)\n * 2. Docs / referencer для host'ов\n *\n * Все секции рендерятся через FieldRenderer + provideFormState с локальной\n * state-mock'ой.\n */\nimport { reactive } from 'vue'\nimport { UidCard } from '@dskripchenko/ui'\nimport FieldRenderer, { type FieldNode } from '../render/FieldRenderer.vue'\nimport { provideFormState } from '../render/formState'\n\ninterface Demo {\n type: string\n group: string\n title: string\n description: string\n /** Demo node для FieldRenderer'а. */\n node: FieldNode\n /** Initial state для form-context. */\n initial: Record<string, unknown>\n}\n\nconst DEMOS: Demo[] = [\n // Текстовые\n {\n type: 'text',\n group: 'Текстовые',\n title: 'Input',\n description: 'Простой текстовый input. type=email/url/password/tel доступны через inputType.',\n node: { type: 'text', name: 'demo_text', label: 'Заголовок статьи', placeholder: 'Например: Введение в Laravel' },\n initial: { demo_text: 'Hello World' },\n },\n {\n type: 'textarea',\n group: 'Текстовые',\n title: 'Textarea',\n description: 'Многострочный input с настраиваемым числом rows.',\n node: { type: 'textarea', name: 'demo_textarea', label: 'Описание', rows: 4 },\n initial: { demo_textarea: 'Multi-line text...' },\n },\n {\n type: 'number',\n group: 'Текстовые',\n title: 'NumberInput',\n description: 'Числовой input. Empty/NaN автоматически конвертируются в null.',\n node: { type: 'number', name: 'demo_number', label: 'Цена', min: 0, max: 1000 },\n initial: { demo_number: 42 },\n },\n // Выбор\n {\n type: 'select',\n group: 'Выбор',\n title: 'Select',\n description: 'Single-select с options. Поддерживает searchable + clearable.',\n node: {\n type: 'select',\n name: 'demo_select',\n label: 'Категория',\n options: [\n { value: 'frontend', label: 'Frontend' },\n { value: 'backend', label: 'Backend' },\n { value: 'devops', label: 'DevOps' },\n ],\n },\n initial: { demo_select: 'backend' },\n },\n {\n type: 'checkbox',\n group: 'Выбор',\n title: 'Checkbox',\n description: 'Boolean toggle. inlineLabel рядом с боксом.',\n node: { type: 'checkbox', name: 'demo_checkbox', label: 'Опубликовать', inlineLabel: 'Сделать доступным всем' },\n initial: { demo_checkbox: true },\n },\n // Дата/время\n {\n type: 'date',\n group: 'Дата/время',\n title: 'DatePicker',\n description: 'date / datetime-local / time через inputType.',\n node: { type: 'date', name: 'demo_date', label: 'Дата публикации', inputType: 'date' },\n initial: { demo_date: '2026-05-01' },\n },\n]\n\n// Группируем для рендера.\nconst groupedDemos = DEMOS.reduce<Record<string, Demo[]>>((acc, d) => {\n if (!acc[d.group]) acc[d.group] = []\n acc[d.group].push(d)\n return acc\n}, {})\n\n// provideFormState на корневом уровне — все demo'и шарят один form-context\n// (имена не пересекаются благодаря demo_ префиксу).\nconst allInitial = reactive<Record<string, unknown>>(\n DEMOS.reduce<Record<string, unknown>>((acc, d) => Object.assign(acc, d.initial), {}),\n)\nprovideFormState(allInitial)\n</script>\n\n<template>\n <section class=\"admin-page admin-field-gallery\">\n <header class=\"admin-page__hd\">\n <div class=\"admin-page__title-wrap\">\n <h1 class=\"admin-page__title\">Field Gallery</h1>\n <div class=\"admin-page__count\">\n Каталог встроенных field-компонентов library + примеры использования\n </div>\n </div>\n </header>\n\n <section v-for=\"(items, group) in groupedDemos\" :key=\"group\" class=\"admin-gallery__group\">\n <h2 class=\"admin-gallery__group-title\">{{ group }}</h2>\n <div class=\"admin-gallery__grid\">\n <UidCard\n v-for=\"demo in items\"\n :key=\"demo.type + demo.title\"\n padding=\"md\"\n class=\"admin-gallery__card\"\n >\n <header class=\"admin-gallery__card-hd\">\n <h3 class=\"admin-gallery__card-title\">{{ demo.title }}</h3>\n <code class=\"admin-gallery__card-type\">type: {{ demo.type }}</code>\n </header>\n <p class=\"admin-gallery__card-desc\">{{ demo.description }}</p>\n <div class=\"admin-gallery__card-demo\">\n <FieldRenderer :node=\"demo.node\" />\n </div>\n </UidCard>\n </div>\n </section>\n </section>\n</template>\n\n<style>\n.admin-gallery__group {\n margin-bottom: var(--uid-space-2xl);\n}\n.admin-gallery__group-title {\n margin: 0 0 var(--uid-space-md);\n font-size: var(--uid-font-size-lg);\n font-weight: var(--uid-font-weight-semibold);\n color: var(--uid-text-primary);\n}\n.admin-gallery__grid {\n display: grid;\n grid-template-columns: repeat(3, minmax(0, 1fr));\n gap: var(--uid-space-md);\n}\n@media (max-width: 960px) {\n .admin-gallery__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }\n}\n@media (max-width: 640px) {\n .admin-gallery__grid { grid-template-columns: 1fr; }\n}\n.admin-gallery__card {\n display: flex;\n flex-direction: column;\n}\n.admin-gallery__card-hd {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--uid-space-sm);\n margin-bottom: var(--uid-space-xs);\n}\n.admin-gallery__card-title {\n margin: 0;\n font-size: var(--uid-font-size-sm);\n font-weight: var(--uid-font-weight-semibold);\n}\n.admin-gallery__card-type {\n font-family: var(--uid-font-family-mono);\n font-size: 11px;\n color: var(--uid-text-tertiary);\n background: var(--uid-surface-base);\n padding: 1px 6px;\n border-radius: var(--uid-radius-sm);\n border: 1px solid var(--uid-border-subtle);\n}\n.admin-gallery__card-desc {\n margin: 0 0 var(--uid-space-md);\n font-size: var(--uid-font-size-xs);\n color: var(--uid-text-tertiary);\n line-height: var(--uid-line-height-normal);\n}\n.admin-gallery__card-demo {\n flex: 1;\n display: flex;\n flex-direction: column;\n justify-content: flex-end;\n}\n</style>\n"],"names":["_client","setAdminClient","client","getAdminClient","clearAdminClient","hasAdminClient","useThemeStore","defineStore","current","ref","available","isDark","computed","hydrate","bootstrap","applyHtmlAttr","applyLocal","theme","setTheme","previous","err","iconName","ariaLabel","toggle","next","_createElementBlock","_createElementVNode","useLocaleStore","applySideEffects","locale","setLocale","pick","loc","_createBlock","_unref","UidMenu","_hoisted_1","_toDisplayString","_openBlock","_Fragment","_renderList","UidMenuItem","$event","_createTextVNode","useNotificationsStore","items","unreadCount","loading","lastFilter","meta","hasUnread","load","filter","page","result","loadUnread","markAsRead","id","item","n","markAllAsRead","now","destroy","index","wasUnread","notifications","display","RouterLink","ApiError","status","payload","UnauthenticatedError","ForbiddenError","NotFoundError","ValidationError","messages","NetworkError","message","toApiError","useAuthStore","user","permissions","pendingChallenge","isAuthenticated","isChallengePending","hasPermission","key","permission","prefix","hasAnyPermission","keys","hasAllPermissions","login","challengeToken","twoFactorChallenge","code","twoFactorRecovery","recoveryCode","cancelChallenge","logout","auth","router","useRouter","goProfile","_createVNode","UidAvatar","_cache","UidMenuSeparator","props","__props","emit","__emit","lastIdx","_hoisted_2","_renderSlot","_ctx","crumb","idx","_hoisted_3","_resolveDynamicComponent","_normalizeClass","NotificationBell","ThemeToggle","LocaleSwitcher","UserMenu","useMenuStore","error","isLoaded","visibleItems","it","filteredChildren","c","i","groupedItems","groups","groupKey","group","list","a","b","orderDiff","force","response","setItems","reset","menu","route","useRoute","isActive","iconSlot","name","h","itemTarget","UidSidebar","_createSlots","_hoisted_4","grp","UidSidebarGroup","UidSidebarItem","_hoisted_5","_hoisted_6","_hoisted_7","HTML_ATTR","onCollapseChange","value","exitImpersonation","watch","val","onBeforeUnmount","UidSidebarLayout","AdminSidebar","AdminTopBar","useNavigationStore","pending","isLoading","start","end","nav","visible","hideTimer","cls","useShell","AdminLoadingBar","AdminShell","_component_router_view","_withCtx","Component","_Transition","useManifestStore","manifest","version","resources","screens","settings","plugins","getResource","slug","r","getScreen","s","getSettings","userName","UidCard","UidButton","title","email","password","remember","submitting","generalError","fieldErrors","emailError","passwordError","submit","UidAlert","UidInput","UidCheckbox","mode","cells","cellRefs","remaining","totpCode","isValid","setCellRef","el","onCellInput","event","target","digit","nextTick","onCellKeydown","onPaste","digits","res","cancel","switchMode","_","redirectToHome","onMounted","_hoisted_8","TwoFactorForm","LoginForm","DEFAULT_META","useResourceIndexStore","slowLoading","slowLoadingTimer","SLOW_LOADING_DELAY","search","filters","sortKey","sortDirection","selection","isEmpty","selectedCount","hasSelection","hasError","selectionState","row","rowId","setSlug","buildParams","override","params","ss","sk","dir","f","filtersMap","k","v","body","setSearch","setFilter","clearFilters","setSort","direction","toggleSort","setPage","toggleRow","toggleAllOnPage","clearSelection","isSelected","DEFAULT_DATETIME","DEFAULT_DATE","ISO_DATETIME_RE","formatCell","preset","formatDateString","formatMoney","formatBoolean","formatBytes","input","format","date","pad","w","tokens","out","ch","currency","decimals","trueLabel","falseLabel","resourceMeta","displayTitle","columns","col","columnMeta","cols","renderCell","slotProps","m","rowFromSlot","hasActiveFilters","showFilterBar","totalLabel","t","loadWithProgress","prev","onSortKeyUpdate","onSortDirUpdate","onSelectionUpdate","onPageChange","onRowClick","bulkAction","action","retryLoad","$router","_hoisted_9","_withKeys","e","_hoisted_11","UidSkeleton","UidErrorState","UidEmptyState","_hoisted_12","UidTable","_hoisted_13","UidPagination","useResourceFormStore","recordId","state","initial","errors","saving","deleting","isCreate","isEdit","isView","isDirty","replaceObject","prepareCreate","resourceSlug","defaults","targetMode","setField","setErrors","clearErrors","save","url","newId","createComponentRegistry","store","type","bundle","fields","layouts","registerField","getField","hasField","listFields","registerLayout","getLayout","hasLayout","listLayouts","clearRegistry","registerComponents","component","fieldProps","_type","rest","_normalizeProps","_mergeProps","UnknownField","resolved","layoutComponent","layoutProps","_kind","fieldNode","FieldRenderer","form","ctx","provideFormState","layoutNodes","titleLabel","statusValue","statusBadgeVariant","nextSlug","nextId","onSave","onDelete","onCancel","UidBadge","node","LayoutRenderer","entries","registerInfolistEntry","getInfolistEntry","hasInfolistEntry","listInfolistEntries","clearInfolistRegistry","registerInfolistEntries","KNOWN_LAYOUTS","entry","entryProps","_t","_k","_i","sectionTitle","sectionDescription","tabsActive","tabsList","child","_component_InfolistRenderer","_normalizeStyle","tab","_hoisted_10","UnknownEntry","RecordKey","provideRecord","record","provide","useRecord","inject","tryUseRecord","onEdit","InfolistRenderer","navItems","localSection","selectSection","profile","localeOptions","l","themeOptions","onAvatarReplace","on2FADisable","on2FARegenerate","has2FA","_hoisted_14","_hoisted_15","UidSelect","_hoisted_16","_hoisted_17","_hoisted_18","_hoisted_19","_hoisted_20","_hoisted_21","widgets","registerWidget","getWidget","hasWidget","listWidgets","clearWidgetRegistry","registerWidgets","widgetProps","_span","UnknownWidget","dashboard","d","resolvedWidgets","resolvedTitle","resolvedSubtitle","spanFor","WidgetRenderer","TONE_MAP","uidTone","UidStat","maxValue","bars","barWidth","bar","PALETTE","total","x","slices","cumulative","startAngle","endAngle","cx","cy","x1","y1","x2","y2","largeArc","path","UidHeatmap","UidGauge","registerBuiltinWidgets","StatWidget","BarChartWidget","DonutChartWidget","RecentTableWidget","HeatmapWidget","GaugeWidget","MarkdownWidget","isSuccess","env","isError","createAdminClient","opts","instance","axios","config","xsrf","readCookie","apiError","wrap","method","wrapBody","data","match","escapeRegex","pickResourcePermission","resource","ability","perm","pickSettingsPermission","pickScreenPermission","buildResourceRoutes","components","base","buildScreenRoute","screen","buildSettingsRoute","buildDashboardRoute","buildRoutesFromManifest","routes","createAuthGuard","loginRouteName","forbiddenRouteName","redirectQueryKey","to","permissionsMeta","createTitleGuard","template","brand","fallback","DYNAMIC_NAME_PREFIXES","isDynamicRouteName","p","createAdminRouter","history","createWebHistory","staticRoutes","notFoundRoute","createRouter","allRoutes","dynamic","useFormState","errorMsg","onUpdate","UidFormField","UidTextarea","UidNumberInput","checked","UidDatePicker","UidStack","defaultSpan","UidGrid","tabKey","localActive","UidTabs","UidTab","UidTabPanel","cidx","registerBuiltinComponents","TextField","TextAreaField","NumberField","SelectField","CheckboxField","DateField","RowsLayout","ColumnsLayout","SectionLayout","TabsLayout","resolvedVariant","flag","displayLabel","formatValue","UidDescriptionList","UidDescriptionItem","registerBuiltinInfolistEntries","TextEntry","BadgeEntry","IconEntry","KeyValueEntry","createAdminApp","options","pages","deriveBase","app","createApp","AdminApp","pinia","createPinia","LoginPage","HomePage","ForbiddenPage","NotFoundPage","ProfilePage","ResourceIndexPage","ResourceFormPage","ResourceViewPage","DashboardPage","SettingsPage","UnknownScreenPage","navStore","from","manifestStore","authStore","menuStore","loadAndApply","newUser","oldUser","baseUrl","loadBootstrap","inline","readInlineBootstrap","readCsrfFromMeta","setOpen","activeFilter","markAllRead","onItemClick","onDestroy","itemKind","lvl","itemTitle","itemBody","relTime","iso","dt","diff","mins","hours","days","UidDrawer","STEPS","internalStep","currentStep","setStep","uploadedFiles","onUpload","files","mapping","setTarget","source","buildMapping","onMappingSubmit","onConfirmRun","canGoBack","canGoNext","fileOptions","UidStepper","UidFileUpload","UidProgress","DEMOS","groupedDemos","acc","allInitial","reactive","demo"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","sources":["../resources/ts/stores/registry.ts","../resources/ts/stores/theme.ts","../resources/ts/components/shell/widgets/ThemeToggle.vue","../resources/ts/stores/locale.ts","../resources/ts/components/shell/widgets/LocaleSwitcher.vue","../resources/ts/stores/notifications.ts","../resources/ts/components/shell/widgets/NotificationBell.vue","../resources/ts/api/errors.ts","../resources/ts/stores/auth.ts","../resources/ts/components/shell/widgets/UserMenu.vue","../resources/ts/components/shell/AdminTopBar.vue","../resources/ts/stores/menu.ts","../resources/ts/components/shell/AdminSidebar.vue","../resources/ts/components/shell/AdminShell.vue","../resources/ts/stores/navigation.ts","../resources/ts/components/AdminLoadingBar.vue","../resources/ts/components/AdminApp.vue","../resources/ts/stores/manifest.ts","../resources/ts/components/HomePage.vue","../resources/ts/components/ForbiddenPage.vue","../resources/ts/components/NotFoundPage.vue","../resources/ts/components/SettingsPage.vue","../resources/ts/components/UnknownScreenPage.vue","../resources/ts/components/auth/LoginForm.vue","../resources/ts/components/auth/TwoFactorForm.vue","../resources/ts/components/auth/LoginPage.vue","../resources/ts/stores/resourceIndex.ts","../resources/ts/components/resource/cellFormat.ts","../resources/ts/components/resource/ResourceIndexPage.vue","../resources/ts/stores/resourceForm.ts","../resources/ts/components/createComponentRegistry.ts","../resources/ts/components/render/registry.ts","../resources/ts/components/fields/UnknownField.vue","../resources/ts/components/render/FieldRenderer.vue","../resources/ts/components/render/LayoutRenderer.vue","../resources/ts/components/resource/ResourceFormPage.vue","../resources/ts/components/infolist/registry.ts","../resources/ts/components/infolist/UnknownEntry.vue","../resources/ts/components/infolist/InfolistRenderer.vue","../resources/ts/components/infolist/recordContext.ts","../resources/ts/components/resource/ResourceViewPage.vue","../resources/ts/components/profile/ProfilePage.vue","../resources/ts/components/dashboard/registry.ts","../resources/ts/components/dashboard/UnknownWidget.vue","../resources/ts/components/dashboard/WidgetRenderer.vue","../resources/ts/components/dashboard/DashboardPage.vue","../resources/ts/components/dashboard/StatWidget.vue","../resources/ts/components/dashboard/BarChartWidget.vue","../resources/ts/components/dashboard/DonutChartWidget.vue","../resources/ts/components/dashboard/RecentTableWidget.vue","../resources/ts/components/dashboard/HeatmapWidget.vue","../resources/ts/components/dashboard/GaugeWidget.vue","../resources/ts/components/dashboard/MarkdownWidget.vue","../resources/ts/components/dashboard/builtin.ts","../resources/ts/api/envelope.ts","../resources/ts/api/client.ts","../resources/ts/router/builder.ts","../resources/ts/router/guards.ts","../resources/ts/router/index.ts","../resources/ts/components/fields/TextField.vue","../resources/ts/components/fields/TextAreaField.vue","../resources/ts/components/fields/NumberField.vue","../resources/ts/components/fields/SelectField.vue","../resources/ts/components/fields/CheckboxField.vue","../resources/ts/components/fields/DateField.vue","../resources/ts/components/layouts/RowsLayout.vue","../resources/ts/components/layouts/ColumnsLayout.vue","../resources/ts/components/layouts/SectionLayout.vue","../resources/ts/components/layouts/TabsLayout.vue","../resources/ts/components/render/builtin.ts","../resources/ts/components/infolist/TextEntry.vue","../resources/ts/components/infolist/BadgeEntry.vue","../resources/ts/components/infolist/IconEntry.vue","../resources/ts/components/infolist/KeyValueEntry.vue","../resources/ts/components/infolist/builtin.ts","../resources/ts/createAdminApp.ts","../resources/ts/api/bootstrap.ts","../resources/ts/components/notifications/NotificationsDrawer.vue","../resources/ts/components/import/ImportWizardPage.vue","../resources/ts/components/gallery/FieldGalleryPage.vue"],"sourcesContent":["/**\n * Глобальный registry AdminClient'а для Pinia stores.\n *\n * Stores не получают client через параметры — это сильно усложняет API\n * (`useAuthStore(client)` каждый раз). Вместо этого client регистрируется\n * один раз при bootstrap'е приложения через `setAdminClient()`, и stores\n * читают его через `getAdminClient()`.\n *\n * Это singleton-pattern — допустим в случае admin-SPA, потому что\n * client всегда один на весь жизненный цикл.\n */\n\nimport type { AdminClient } from '../api/client'\n\nlet _client: AdminClient | null = null\n\nexport function setAdminClient(client: AdminClient): void {\n _client = client\n}\n\nexport function getAdminClient(): AdminClient {\n if (_client === null) {\n throw new Error(\n '[admin] AdminClient is not registered. Call setAdminClient(...) before using stores.',\n )\n }\n return _client\n}\n\nexport function clearAdminClient(): void {\n _client = null\n}\n\nexport function hasAdminClient(): boolean {\n return _client !== null\n}\n","/**\n * Theme store: текущая тема + список доступных + persist через API.\n *\n * Side effect: применяет `<html data-theme=\"...\">` при изменении.\n * SPA рассчитывает на это для CSS-vars overrides.\n */\n\nimport { defineStore } from 'pinia'\nimport { computed, ref } from 'vue'\nimport { getAdminClient } from './registry'\nimport type { AdminBootstrap } from '../types/bootstrap'\n\nexport const useThemeStore = defineStore('admin-theme', () => {\n const current = ref<string>('light')\n const available = ref<string[]>(['light', 'dark'])\n\n const isDark = computed(() => current.value === 'dark')\n\n function hydrate(bootstrap: AdminBootstrap): void {\n current.value = bootstrap.theme\n available.value = bootstrap.availableThemes\n applyHtmlAttr(bootstrap.theme)\n }\n\n /**\n * Локальное переключение без round-trip'а. Используется когда нужно\n * мгновенно применить тему до получения ответа от сервера.\n */\n function applyLocal(theme: string): void {\n if (!available.value.includes(theme)) {\n throw new Error(`Theme \"${theme}\" is not available`)\n }\n current.value = theme\n applyHtmlAttr(theme)\n }\n\n /**\n * POST /system/setTheme — persist в user.theme + cookie.\n * Применяет тему к DOM немедленно (optimistic update).\n */\n async function setTheme(theme: string): Promise<void> {\n if (!available.value.includes(theme)) {\n throw new Error(`Theme \"${theme}\" is not available`)\n }\n\n const previous = current.value\n applyLocal(theme)\n\n try {\n const client = getAdminClient()\n await client.post('/system/setTheme', { theme })\n } catch (err) {\n // Откатываем optimistic update.\n applyLocal(previous)\n throw err\n }\n }\n\n function applyHtmlAttr(theme: string): void {\n if (typeof document !== 'undefined' && document.documentElement) {\n document.documentElement.setAttribute('data-theme', theme)\n }\n }\n\n return {\n current,\n available,\n isDark,\n hydrate,\n applyLocal,\n setTheme,\n }\n})\n","<script setup lang=\"ts\">\n/**\n * Toggle между light/dark поверх @dskripchenko/ui. Использует topbar\n * icon-button-стиль (.admin-topbar__icon-btn) для визуальной согласованности\n * с остальными widget'ами в баре.\n */\nimport { computed } from 'vue'\nimport { useThemeStore } from '../../../stores/theme'\n\nconst theme = useThemeStore()\n\nconst isDark = computed(() => theme.current === 'dark')\nconst iconName = computed(() => (isDark.value ? 'sun' : 'moon'))\nconst ariaLabel = computed(() =>\n isDark.value ? 'Переключить на светлую тему' : 'Переключить на тёмную тему',\n)\n\nasync function toggle(): Promise<void> {\n const next = isDark.value ? 'light' : 'dark'\n await theme.setTheme(next)\n}\n</script>\n\n<template>\n <button\n type=\"button\"\n class=\"admin-topbar__icon-btn\"\n :aria-label=\"ariaLabel\"\n :aria-pressed=\"isDark\"\n @click=\"toggle\"\n >\n <span class=\"admin-topbar__icon\" :data-icon=\"iconName\" />\n </button>\n</template>\n","/**\n * Locale store: текущая локаль + persist + sync с AdminClient.\n *\n * Side effects при смене:\n * - `<html lang=\"...\">` обновляется\n * - AdminClient.setLocale() — все следующие запросы получат правильный\n * X-Admin-Locale header\n * - POST /system/setLocale → persist в user.locale + cookie\n */\n\nimport { defineStore } from 'pinia'\nimport { ref } from 'vue'\nimport { getAdminClient } from './registry'\nimport type { AdminBootstrap } from '../types/bootstrap'\n\nexport const useLocaleStore = defineStore('admin-locale', () => {\n const current = ref<string>('ru')\n const available = ref<string[]>(['ru', 'en'])\n\n function hydrate(bootstrap: AdminBootstrap): void {\n current.value = bootstrap.locale\n available.value = bootstrap.availableLocales\n applySideEffects(bootstrap.locale)\n }\n\n function applyLocal(locale: string): void {\n if (!available.value.includes(locale)) {\n throw new Error(`Locale \"${locale}\" is not available`)\n }\n current.value = locale\n applySideEffects(locale)\n }\n\n async function setLocale(locale: string): Promise<void> {\n if (!available.value.includes(locale)) {\n throw new Error(`Locale \"${locale}\" is not available`)\n }\n\n const previous = current.value\n applyLocal(locale)\n\n try {\n const client = getAdminClient()\n await client.post('/system/setLocale', { locale })\n } catch (err) {\n applyLocal(previous)\n throw err\n }\n }\n\n function applySideEffects(locale: string): void {\n if (typeof document !== 'undefined' && document.documentElement) {\n document.documentElement.setAttribute('lang', locale)\n }\n // Try-catch потому что в test-окружении registry может быть пуст.\n try {\n getAdminClient().setLocale(locale)\n } catch {\n // ignore — клиент ещё не зарегистрирован\n }\n }\n\n return {\n current,\n available,\n hydrate,\n applyLocal,\n setLocale,\n }\n})\n","<script setup lang=\"ts\">\n/**\n * Переключение локали через UidMenu. В topbar показываем компактно\n * (icon + uppercase-код), под ним выпадает список доступных локалей.\n */\nimport { UidMenu, UidMenuItem } from '@dskripchenko/ui'\nimport { useLocaleStore } from '../../../stores/locale'\n\nconst locale = useLocaleStore()\n\nasync function pick(loc: string): Promise<void> {\n if (loc === locale.current) return\n await locale.setLocale(loc)\n}\n</script>\n\n<template>\n <UidMenu>\n <template #trigger>\n <button\n type=\"button\"\n class=\"admin-topbar__icon-btn\"\n style=\"width: auto; padding: 0 8px; gap: 4px; font-size: 12px;\"\n aria-label=\"Сменить локаль\"\n >\n <span class=\"admin-topbar__icon\" data-icon=\"globe\" />\n <span>{{ (locale.current ?? '').toUpperCase() }}</span>\n </button>\n </template>\n\n <UidMenuItem\n v-for=\"loc in locale.available\"\n :key=\"loc\"\n @click=\"pick(loc)\"\n >\n {{ loc.toUpperCase() }}\n </UidMenuItem>\n </UidMenu>\n</template>\n","/**\n * Notifications store: список + unread count + read/delete actions.\n *\n * Bell-badge polling реализуется на уровне UI через setInterval +\n * вызов loadUnread() — store сам не polling'ит, чтобы не дублировать\n * SetInterval'ы между tab'ами.\n */\n\nimport { defineStore } from 'pinia'\nimport { computed, ref } from 'vue'\nimport { getAdminClient } from './registry'\nimport type { AdminBootstrap } from '../types/bootstrap'\n\nexport interface NotificationItem {\n id: string\n type: string\n data: Record<string, unknown>\n read_at: string | null\n created_at: string | null\n}\n\nexport type NotificationFilter = 'all' | 'unread' | 'read'\n\nexport const useNotificationsStore = defineStore('admin-notifications', () => {\n const items = ref<NotificationItem[]>([])\n const unreadCount = ref(0)\n const loading = ref(false)\n const lastFilter = ref<NotificationFilter>('all')\n const meta = ref<{ page: number; per_page: number; total: number; last_page: number } | null>(null)\n\n const hasUnread = computed(() => unreadCount.value > 0)\n\n function hydrate(bootstrap: AdminBootstrap): void {\n unreadCount.value = bootstrap.unread_notifications_count\n }\n\n async function load(filter: NotificationFilter = 'all', page = 1): Promise<void> {\n loading.value = true\n try {\n const client = getAdminClient()\n const result = await client.get<{\n data: NotificationItem[]\n meta: { page: number; per_page: number; total: number; last_page: number; unread_count: number }\n }>(`/notifications/list?type=${filter}&page=${page}`)\n items.value = result.data\n unreadCount.value = result.meta.unread_count\n meta.value = {\n page: result.meta.page,\n per_page: result.meta.per_page,\n total: result.meta.total,\n last_page: result.meta.last_page,\n }\n lastFilter.value = filter\n } finally {\n loading.value = false\n }\n }\n\n /**\n * Лёгкий polling-endpoint — только count + последние 20.\n * Для bell-badge.\n */\n async function loadUnread(): Promise<void> {\n const client = getAdminClient()\n const result = await client.get<{ count: number; data: NotificationItem[] }>(\n '/notifications/unread',\n )\n unreadCount.value = result.count\n // Не подменяем items если в данный момент open'нут другой filter.\n if (lastFilter.value === 'unread') {\n items.value = result.data\n }\n }\n\n async function markAsRead(id: string): Promise<void> {\n const client = getAdminClient()\n await client.post('/notifications/markAsRead', { id })\n // Optimistic update в локальном state.\n const item = items.value.find((n) => n.id === id)\n if (item && item.read_at === null) {\n item.read_at = new Date().toISOString()\n unreadCount.value = Math.max(0, unreadCount.value - 1)\n }\n }\n\n async function markAllAsRead(): Promise<void> {\n const client = getAdminClient()\n await client.post('/notifications/markAllAsRead')\n const now = new Date().toISOString()\n for (const item of items.value) {\n if (item.read_at === null) item.read_at = now\n }\n unreadCount.value = 0\n }\n\n async function destroy(id: string): Promise<void> {\n const client = getAdminClient()\n await client.post('/notifications/destroy', { id })\n const index = items.value.findIndex((n) => n.id === id)\n if (index !== -1) {\n const wasUnread = items.value[index].read_at === null\n items.value.splice(index, 1)\n if (wasUnread) {\n unreadCount.value = Math.max(0, unreadCount.value - 1)\n }\n }\n }\n\n return {\n items,\n unreadCount,\n loading,\n meta,\n lastFilter,\n hasUnread,\n hydrate,\n load,\n loadUnread,\n markAsRead,\n markAllAsRead,\n destroy,\n }\n})\n","<script setup lang=\"ts\">\n/**\n * Bell с unread-badge. По эталону handoff'а — badge `.admin-topbar__bell-badge`\n * (округлая красная пилюля 14×14 + tabular-nums + max '99+').\n */\nimport { computed } from 'vue'\nimport { RouterLink } from 'vue-router'\nimport { useNotificationsStore } from '../../../stores/notifications'\n\nconst notifications = useNotificationsStore()\n\nconst display = computed(() => {\n const n = notifications.unreadCount\n if (n <= 0) return null\n return n > 99 ? '99+' : String(n)\n})\n</script>\n\n<template>\n <RouterLink\n to=\"/notifications\"\n class=\"admin-topbar__icon-btn\"\n aria-label=\"Уведомления\"\n >\n <span class=\"admin-topbar__icon\" data-icon=\"bell\" />\n <span\n v-if=\"display !== null\"\n class=\"admin-topbar__bell-badge\"\n :title=\"`Непрочитанных: ${notifications.unreadCount}`\"\n >\n {{ display }}\n </span>\n </RouterLink>\n</template>\n","/**\n * Кастомные Error-классы для admin API.\n *\n * Все API-ошибки бросаются как ApiError или его подклассы. Потребители\n * могут делать `instanceof ValidationError` для специфичной обработки.\n */\n\nimport type { ErrorEnvelope } from './envelope'\n\nexport class ApiError extends Error {\n public readonly status: number\n public readonly errorKey: string\n public readonly payload: ErrorEnvelope['payload']\n\n constructor(status: number, payload: ErrorEnvelope['payload']) {\n super(payload.message ?? `API error ${status}`)\n this.name = 'ApiError'\n this.status = status\n this.errorKey = payload.errorKey ?? 'unknown'\n this.payload = payload\n }\n}\n\nexport class UnauthenticatedError extends ApiError {\n constructor(payload: ErrorEnvelope['payload']) {\n super(401, payload)\n this.name = 'UnauthenticatedError'\n }\n}\n\nexport class ForbiddenError extends ApiError {\n constructor(payload: ErrorEnvelope['payload']) {\n super(403, payload)\n this.name = 'ForbiddenError'\n }\n}\n\nexport class NotFoundError extends ApiError {\n constructor(payload: ErrorEnvelope['payload']) {\n super(404, payload)\n this.name = 'NotFoundError'\n }\n}\n\nexport class ValidationError extends ApiError {\n /** Field-keyed map of error messages. */\n public readonly fields: Record<string, string[]>\n\n constructor(payload: ErrorEnvelope['payload']) {\n super(422, payload)\n this.name = 'ValidationError'\n this.fields = payload.messages ?? {}\n }\n\n /** Первое сообщение из field'а — удобно для toast. */\n firstFieldMessage(): string | null {\n for (const messages of Object.values(this.fields)) {\n if (messages.length > 0) {\n return messages[0]\n }\n }\n return null\n }\n}\n\n/**\n * Network-failure (не дошли до сервера). Отдельный класс чтобы UI мог\n * показать «Нет соединения» вместо «500 Server Error».\n */\nexport class NetworkError extends Error {\n constructor(message = 'Network error') {\n super(message)\n this.name = 'NetworkError'\n }\n}\n\n/**\n * Превращает HTTP-status + envelope в правильный подкласс ApiError.\n */\nexport function toApiError(status: number, payload: ErrorEnvelope['payload']): ApiError {\n switch (status) {\n case 401: return new UnauthenticatedError(payload)\n case 403: return new ForbiddenError(payload)\n case 404: return new NotFoundError(payload)\n case 422: return new ValidationError(payload)\n default: return new ApiError(status, payload)\n }\n}\n","/**\n * Auth store: текущий user, permissions, login/logout/2FA flow.\n *\n * Wildcard в permissions:\n * - `*` — полный доступ ко всему.\n * - `admin.users.*` — доступ ко всем admin.users.{view,create,update,delete}.\n *\n * 2FA flow:\n * 1. login() с верными creds + 2FA включена → success: false +\n * errorKey: 'two_factor_required' + challenge_token. State переходит в\n * `pendingChallenge`.\n * 2. UI показывает 2FA-форму. twoFactorChallenge(code) или\n * twoFactorRecovery(recovery_code) → success login flow.\n */\n\nimport { defineStore } from 'pinia'\nimport { computed, ref } from 'vue'\nimport { getAdminClient } from './registry'\nimport { ApiError } from '../api/errors'\nimport type { AdminUser, AdminBootstrap } from '../types/bootstrap'\n\nexport interface PendingChallenge {\n challengeToken: string\n remember: boolean\n}\n\nexport interface LoginPayload {\n email: string\n password: string\n remember?: boolean\n}\n\nexport const useAuthStore = defineStore('admin-auth', () => {\n const user = ref<AdminUser | null>(null)\n const permissions = ref<string[]>([])\n const pendingChallenge = ref<PendingChallenge | null>(null)\n\n const isAuthenticated = computed(() => user.value !== null)\n const isChallengePending = computed(() => pendingChallenge.value !== null)\n\n /** Заполнить store из bootstrap-payload'а (стартовая инициализация). */\n function hydrate(bootstrap: AdminBootstrap): void {\n user.value = bootstrap.user\n permissions.value = bootstrap.permissions\n }\n\n /**\n * Проверить permission. Поддерживает wildcards:\n * - `*` — даёт доступ всем.\n * - `admin.users.*` — даёт доступ ко всем admin.users.X.\n */\n function hasPermission(key: string): boolean {\n if (permissions.value.includes('*')) return true\n if (permissions.value.includes(key)) return true\n return permissions.value.some((permission) => {\n if (!permission.endsWith('.*')) return false\n const prefix = permission.slice(0, -1) // 'admin.users.'\n return key.startsWith(prefix)\n })\n }\n\n function hasAnyPermission(keys: string[]): boolean {\n return keys.some(hasPermission)\n }\n\n function hasAllPermissions(keys: string[]): boolean {\n return keys.every(hasPermission)\n }\n\n /**\n * POST /auth/login. При 2FA-required envelope success:false +\n * errorKey:'two_factor_required' конвертируется interceptor'ом в ApiError;\n * мы ловим его, переходим в challenge-mode и возвращаем 'two_factor_required'.\n * На полный success — заполняем user и возвращаем 'authenticated'.\n * На реальную ошибку — throw'ит ApiError выше.\n */\n async function login(payload: LoginPayload): Promise<'authenticated' | 'two_factor_required'> {\n const client = getAdminClient()\n try {\n const result = await client.post<{ user?: AdminUser; permissions?: string[] }>(\n '/auth/login',\n payload,\n )\n if (result?.user) {\n user.value = result.user\n }\n if (Array.isArray(result?.permissions)) {\n permissions.value = result.permissions\n }\n pendingChallenge.value = null\n return 'authenticated'\n } catch (err) {\n if (err instanceof ApiError && err.errorKey === 'two_factor_required') {\n const challengeToken = (err.payload as Record<string, unknown>).challenge_token\n pendingChallenge.value = {\n challengeToken: typeof challengeToken === 'string' ? challengeToken : '',\n remember: payload.remember ?? false,\n }\n return 'two_factor_required'\n }\n throw err\n }\n }\n\n /** POST /auth/twoFactorChallenge. Завершает login. */\n async function twoFactorChallenge(code: string): Promise<void> {\n if (pendingChallenge.value === null) {\n throw new Error('No pending 2FA challenge')\n }\n const client = getAdminClient()\n const result = await client.post<{ user: AdminUser }>('/auth/twoFactorChallenge', {\n challenge_token: pendingChallenge.value.challengeToken,\n code,\n })\n user.value = result.user\n pendingChallenge.value = null\n }\n\n /** POST /auth/twoFactorRecovery. Использует recovery-код вместо TOTP. */\n async function twoFactorRecovery(recoveryCode: string): Promise<{ remaining: number }> {\n if (pendingChallenge.value === null) {\n throw new Error('No pending 2FA challenge')\n }\n const client = getAdminClient()\n const result = await client.post<{\n user: AdminUser\n recovery_codes_remaining: number\n }>('/auth/twoFactorRecovery', {\n challenge_token: pendingChallenge.value.challengeToken,\n recovery_code: recoveryCode,\n })\n user.value = result.user\n pendingChallenge.value = null\n return { remaining: result.recovery_codes_remaining }\n }\n\n /** Сбросить pending challenge — для возврата на login-форму. */\n function cancelChallenge(): void {\n pendingChallenge.value = null\n }\n\n /** POST /auth/logout. Чистит store. */\n async function logout(): Promise<void> {\n const client = getAdminClient()\n try {\n await client.post('/auth/logout')\n } finally {\n user.value = null\n permissions.value = []\n pendingChallenge.value = null\n }\n }\n\n return {\n // state\n user,\n permissions,\n pendingChallenge,\n // getters\n isAuthenticated,\n isChallengePending,\n // actions\n hydrate,\n hasPermission,\n hasAnyPermission,\n hasAllPermissions,\n login,\n twoFactorChallenge,\n twoFactorRecovery,\n cancelChallenge,\n logout,\n }\n})\n","<script setup lang=\"ts\">\n/**\n * UserMenu с avatar + dropdown через UidMenu из @dskripchenko/ui.\n * В trigger'е — UidAvatar (с инициалами либо src, размер sm).\n */\nimport { UidAvatar, UidMenu, UidMenuItem, UidMenuSeparator } from '@dskripchenko/ui'\nimport { useRouter } from 'vue-router'\nimport { useAuthStore } from '../../../stores/auth'\n\nconst auth = useAuthStore()\nconst router = useRouter()\n\nasync function logout(): Promise<void> {\n try {\n await auth.logout()\n } finally {\n await router.push({ name: 'admin.login' })\n }\n}\n\nfunction goProfile(): void {\n void router.push({ name: 'admin.profile' })\n}\n</script>\n\n<template>\n <UidMenu>\n <template #trigger>\n <button\n type=\"button\"\n class=\"admin-topbar__icon-btn admin-user-menu__trigger\"\n aria-label=\"Меню пользователя\"\n aria-haspopup=\"menu\"\n style=\"width: auto; padding: 0 4px; gap: 8px;\"\n >\n <UidAvatar\n :src=\"auth.user?.avatar ?? undefined\"\n :name=\"auth.user?.name ?? '?'\"\n :alt=\"auth.user?.name ?? 'User'\"\n size=\"sm\"\n />\n </button>\n </template>\n\n <UidMenuItem @click=\"goProfile\">Профиль</UidMenuItem>\n <UidMenuSeparator />\n <UidMenuItem variant=\"danger\" @click=\"logout\">Выйти</UidMenuItem>\n </UidMenu>\n</template>\n","<script setup lang=\"ts\">\n/**\n * Admin top bar поверх UID-токенов. Структура из docs/design_handoff_laravel_admin/\n * screens-shell.jsx (Topbar): collapse-toggle / breadcrumbs / spacer /\n * search-pill / bell / theme / locale / avatar.\n *\n * Slots:\n * - actions — host может вставить дополнительные actions перед widget'ами\n * - search — кастомизация ⌘K command-palette pill (по умолчанию — статичный\n * placeholder; host сверху поднимет UidCommand или свой)\n * - breadcrumbs — переопределить хлебные крошки\n */\nimport { computed } from 'vue'\nimport ThemeToggle from './widgets/ThemeToggle.vue'\nimport LocaleSwitcher from './widgets/LocaleSwitcher.vue'\nimport NotificationBell from './widgets/NotificationBell.vue'\nimport UserMenu from './widgets/UserMenu.vue'\n\ninterface Crumb {\n label: string\n to?: string | Record<string, unknown> | null\n}\n\ninterface Props {\n /** Хлебные крошки. Последний элемент — текущая страница (без to). */\n breadcrumbs?: Crumb[]\n /** Показывать кнопку collapse сайдбара (только в shell-layout'е). */\n showCollapseToggle?: boolean\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n breadcrumbs: () => [],\n showCollapseToggle: true,\n})\n\nconst emit = defineEmits<{\n 'toggle-sidebar': []\n}>()\n\nconst lastIdx = computed(() => props.breadcrumbs.length - 1)\n</script>\n\n<template>\n <header class=\"admin-topbar\">\n <button\n v-if=\"showCollapseToggle\"\n type=\"button\"\n class=\"admin-topbar__icon-btn\"\n aria-label=\"Свернуть меню\"\n @click=\"emit('toggle-sidebar')\"\n >\n <span class=\"admin-topbar__icon\" data-icon=\"panel-left\" />\n </button>\n\n <div class=\"admin-topbar__breadcrumbs\">\n <slot name=\"breadcrumbs\">\n <template v-for=\"(crumb, idx) in breadcrumbs\" :key=\"idx\">\n <span v-if=\"idx > 0\" class=\"sep\">›</span>\n <component\n :is=\"crumb.to ? 'a' : 'span'\"\n :href=\"typeof crumb.to === 'string' ? crumb.to : undefined\"\n :class=\"idx === lastIdx ? 'cur' : ''\"\n >\n {{ crumb.label }}\n </component>\n </template>\n </slot>\n </div>\n\n <div class=\"admin-topbar__spacer\" />\n\n <slot name=\"search\">\n <div class=\"admin-topbar__search\" role=\"button\" tabindex=\"0\">\n <span class=\"admin-topbar__icon\" data-icon=\"search\" />\n <span>Поиск везде…</span>\n <kbd>⌘K</kbd>\n </div>\n </slot>\n\n <slot name=\"actions\" />\n <NotificationBell />\n <ThemeToggle />\n <LocaleSwitcher />\n <UserMenu />\n </header>\n</template>\n","/**\n * Menu store: дерево пунктов сайдбара.\n *\n * Источник — /system/menu (backend строит из ResourceRegistry/ScreenRegistry/\n * Settings + plugin-вкладов). Фронт фильтрует по permission'ам залогиненного\n * пользователя через auth-store.\n */\n\nimport { defineStore } from 'pinia'\nimport { computed, ref } from 'vue'\nimport { getAdminClient } from './registry'\nimport { useAuthStore } from './auth'\n\nexport interface MenuItem {\n /** Уникальный идентификатор. */\n key: string\n /** Текст пункта. */\n label: string\n /** Имя icon'а (опционально — host-проект сам резолвит icon-set). */\n icon?: string | null\n /** URL (внутренний router-target) либо null для группы. */\n url?: string | null\n /** Имя router-route (если задано — приоритет над url). */\n routeName?: string | null\n /** Бейдж справа (число unread, ярлык вроде \"new\"). */\n badge?: string | number | null\n /** Группа (header в sidebar). */\n group?: string | null\n /** Сортировочный вес. */\n order?: number\n /** Permission-keys; если заданы — пункт виден только при hasAnyPermission. */\n permissions?: string[]\n /** Вложенные пункты. */\n children?: MenuItem[]\n}\n\nexport interface MenuGroup {\n /** Заголовок группы (null = пункты без группы). */\n group: string | null\n items: MenuItem[]\n}\n\ninterface MenuResponse {\n items: MenuItem[]\n}\n\nexport const useMenuStore = defineStore('admin-menu', () => {\n const items = ref<MenuItem[]>([])\n const loading = ref(false)\n const error = ref<Error | null>(null)\n const isLoaded = ref(false)\n\n /**\n * Видимые пункты — отфильтрованные по permission'ам через auth-store.\n * Поддерживает wildcards (`*`, `admin.users.*`) через auth.hasAnyPermission.\n * Items без permissions считаются открытыми всем.\n */\n const visibleItems = computed<MenuItem[]>(() => {\n const auth = useAuthStore()\n const filter = (it: MenuItem): MenuItem | null => {\n if (Array.isArray(it.permissions) && it.permissions.length > 0) {\n if (!auth.hasAnyPermission(it.permissions)) return null\n }\n const filteredChildren = (it.children ?? [])\n .map(filter)\n .filter((c): c is MenuItem => c !== null)\n return { ...it, children: filteredChildren }\n }\n return items.value.map(filter).filter((i): i is MenuItem => i !== null)\n })\n\n /**\n * Группированный список — для рендера в sidebar по секциям.\n * Сортировка: order по возрастанию, затем label по алфавиту.\n */\n const groupedItems = computed<MenuGroup[]>(() => {\n const groups = new Map<string | null, MenuItem[]>()\n for (const item of visibleItems.value) {\n const groupKey = item.group ?? null\n if (!groups.has(groupKey)) groups.set(groupKey, [])\n groups.get(groupKey)!.push(item)\n }\n const result: MenuGroup[] = []\n for (const [group, list] of groups) {\n list.sort((a, b) => {\n const orderDiff = (a.order ?? 0) - (b.order ?? 0)\n if (orderDiff !== 0) return orderDiff\n return a.label.localeCompare(b.label)\n })\n result.push({ group, items: list })\n }\n return result\n })\n\n /** Загрузить меню с backend'а. Кэшируется до reset()/force=true. */\n async function load(force = false): Promise<MenuItem[]> {\n if (isLoaded.value && !force) return items.value\n loading.value = true\n error.value = null\n try {\n const client = getAdminClient()\n const response = await client.get<MenuResponse>('/system/menu')\n items.value = Array.isArray(response.items) ? response.items : []\n isLoaded.value = true\n return items.value\n } catch (err) {\n error.value = err instanceof Error ? err : new Error(String(err))\n throw err\n } finally {\n loading.value = false\n }\n }\n\n /** Установить items напрямую (например, host-проект построил из manifest'а). */\n function setItems(next: MenuItem[]): void {\n items.value = next\n isLoaded.value = true\n error.value = null\n }\n\n function reset(): void {\n items.value = []\n isLoaded.value = false\n error.value = null\n loading.value = false\n }\n\n return {\n items,\n loading,\n error,\n isLoaded,\n visibleItems,\n groupedItems,\n load,\n setItems,\n reset,\n }\n})\n","<script setup lang=\"ts\">\n/**\n * Sidebar admin-каркаса поверх UidSidebar/UidSidebarGroup/UidSidebarItem.\n *\n * Источник данных — useMenuStore (groupedItems, отфильтрованные по permission'ам\n * через auth.hasAnyPermission). UidSidebarItem поддерживает вложенный icon-slot\n * + active + badge — маппим прямо из MenuItem.\n *\n * Brand-row сверху + опциональный tenant-block + footer с версией/docs —\n * по эталону docs/design_handoff_laravel_admin/screens-shell.jsx (Sidebar).\n */\nimport { computed, h, type Component } from 'vue'\nimport { useRoute } from 'vue-router'\nimport { UidSidebar, UidSidebarGroup, UidSidebarItem } from '@dskripchenko/ui'\nimport { useMenuStore, type MenuItem } from '../../stores/menu'\n\ninterface Props {\n collapsed?: boolean\n /** Заголовок бренда. */\n brandName?: string\n /** Logo-mark (буква/инициалы) — отображается вместо логотипа. */\n brandMark?: string\n /** Тенант / workspace — опционально показывается под брендом. */\n tenant?: { label: string; name: string } | null\n /** Версия + ссылка на docs в footer'е. */\n version?: string | null\n docsUrl?: string | null\n}\n\nwithDefaults(defineProps<Props>(), {\n collapsed: false,\n brandName: 'Laravel Admin',\n brandMark: 'L',\n tenant: null,\n version: null,\n docsUrl: null,\n})\n\nconst menu = useMenuStore()\nconst route = useRoute()\n\nconst groups = computed(() => menu.groupedItems)\n\nfunction isActive(item: MenuItem): boolean {\n if (item.routeName && route.name === item.routeName) return true\n if (item.url && route.path === item.url) return true\n return false\n}\n\n/**\n * UidSidebarItem ожидает icon-slot. MenuItem.icon — строка (имя lucide-икoнки),\n * host-проект может зарегистрировать свой icon-resolver. Здесь возвращаем\n * простой <span data-icon> placeholder — host'у достаточно css-rule по\n * `[data-icon='users']` чтобы подставить SVG.\n */\nfunction iconSlot(name?: string | null): Component | undefined {\n if (!name) return undefined\n // Functional component возвращающий <span data-icon> placeholder.\n // Host-проект может перебить через css-rule по `[data-icon='users']`.\n return () => h('span', { class: 'admin-sidebar__icon', 'data-icon': name })\n}\n\n/** UidSidebarItem.to принимает string | object; routeName маппим через route-object. */\nfunction itemTarget(item: MenuItem): string | Record<string, unknown> | undefined {\n // URL приоритетнее routeName — vue-router бросает \"no match for {name}\" если\n // route'а ещё нет (dynamic-routes добавляются async после manifest.load).\n // URL-based navigation матчится в любой момент через path.\n if (item.url) return item.url\n if (item.routeName) return { name: item.routeName }\n return undefined\n}\n</script>\n\n<template>\n <UidSidebar :collapsed=\"collapsed\">\n <template #header>\n <div class=\"admin-sidebar-brand\">\n <div class=\"admin-sidebar-brand__mark\">{{ brandMark }}</div>\n <div v-if=\"!collapsed\" class=\"admin-sidebar-brand__name\">{{ brandName }}</div>\n </div>\n <div v-if=\"tenant && !collapsed\" class=\"admin-sidebar-tenant\">\n <span>{{ tenant.label }}</span>\n <b>{{ tenant.name }}</b>\n </div>\n </template>\n\n <template #nav>\n <UidSidebarGroup\n v-for=\"(grp, idx) in groups\"\n :key=\"`grp-${idx}`\"\n :title=\"grp.group ?? undefined\"\n >\n <UidSidebarItem\n v-for=\"item in grp.items\"\n :key=\"item.key\"\n :to=\"itemTarget(item)\"\n :active=\"isActive(item)\"\n :badge=\"item.badge ?? undefined\"\n >\n <template v-if=\"item.icon\" #icon>\n <component :is=\"iconSlot(item.icon)\" />\n </template>\n {{ item.label }}\n </UidSidebarItem>\n </UidSidebarGroup>\n </template>\n\n <template v-if=\"version || docsUrl\" #footer>\n <div class=\"admin-sidebar-foot\">\n <span v-if=\"version\" class=\"admin-sidebar-foot__text\">{{ version }}</span>\n <a v-if=\"docsUrl\" :href=\"docsUrl\" class=\"admin-sidebar-foot__text admin-sidebar-foot__link\">\n Docs\n </a>\n </div>\n </template>\n </UidSidebar>\n</template>\n\n<style>\n.admin-sidebar-brand {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 14px 16px;\n border-bottom: 1px solid var(--uid-border-subtle);\n}\n.admin-sidebar-brand__mark {\n width: 28px;\n height: 28px;\n border-radius: 7px;\n flex: none;\n background: var(--uid-text-primary);\n color: var(--uid-surface-raised);\n display: grid;\n place-items: center;\n font-family: var(--uid-font-family-display);\n font-weight: var(--uid-font-weight-bold);\n font-size: 14px;\n letter-spacing: -0.02em;\n}\n.admin-sidebar-brand__name {\n font-family: var(--uid-font-family-display);\n font-size: 14px;\n font-weight: var(--uid-font-weight-semibold);\n letter-spacing: -0.01em;\n white-space: nowrap;\n overflow: hidden;\n color: var(--uid-text-primary);\n}\n.admin-sidebar-tenant {\n margin: 8px;\n display: flex;\n align-items: center;\n gap: 8px;\n height: 32px;\n padding: 0 8px;\n border: 1px solid var(--uid-border-subtle);\n border-radius: var(--uid-radius-md);\n font-size: var(--uid-font-size-xs);\n color: var(--uid-text-secondary);\n background: var(--uid-surface-base);\n}\n.admin-sidebar-tenant b { color: var(--uid-text-primary); font-weight: 500; }\n.admin-sidebar-foot {\n padding: 10px 16px;\n border-top: 1px solid var(--uid-border-subtle);\n display: flex;\n align-items: center;\n justify-content: space-between;\n font-size: 11px;\n color: var(--uid-text-tertiary);\n}\n.admin-sidebar-foot__link { cursor: pointer; }\n.admin-sidebar-foot__link:hover { color: var(--uid-text-primary); }\n\n.admin-sidebar__icon {\n width: 16px;\n height: 16px;\n display: inline-block;\n flex: none;\n color: currentColor;\n}\n</style>\n","<script setup lang=\"ts\">\n/**\n * Корневой layout admin-панели поверх UidSidebarLayout из @dskripchenko/ui.\n *\n * Slots:\n * - sidebar — обычно AdminSidebar (default)\n * - header — AdminTopBar (default)\n * - default — main-area (host рендерит <RouterView/>)\n *\n * v-model — boolean флаг сворачивания сайдбара (240→56 px, transition в uid).\n *\n * Impersonation: prop `impersonation` показывает 32-px amber бейдж над shell'ом\n * с кнопкой выхода — стиль из docs/design_handoff_laravel_admin/app.css:159\n * (.imp-banner). На <html> ставим data-impersonating='true' чтобы корректно\n * сместить sticky-элементы вниз.\n */\nimport { onBeforeUnmount, watch } from 'vue'\nimport { UidSidebarLayout } from '@dskripchenko/ui'\nimport AdminTopBar from './AdminTopBar.vue'\nimport AdminSidebar from './AdminSidebar.vue'\n\ninterface ImpersonationData {\n /** Имя того, в кого вошли. */\n asName: string\n}\n\ninterface Props {\n /** Сворачивание сайдбара. */\n collapsed?: boolean\n /** Если задано — показывает amber-banner и сдвигает контент. */\n impersonation?: ImpersonationData | null\n}\nconst props = withDefaults(defineProps<Props>(), {\n collapsed: false,\n impersonation: null,\n})\n\nconst emit = defineEmits<{\n 'update:collapsed': [value: boolean]\n 'exit-impersonation': []\n}>()\n\nfunction onCollapseChange(value: boolean): void {\n emit('update:collapsed', value)\n}\n\nfunction exitImpersonation(): void {\n emit('exit-impersonation')\n}\n\n// Маркер на <html> — для shell-classes которые делают paddding-top + sticky-offset.\nconst HTML_ATTR = 'data-admin-impersonating'\n\nwatch(\n () => props.impersonation,\n (val) => {\n if (typeof document === 'undefined') return\n if (val !== null) document.documentElement.setAttribute(HTML_ATTR, 'true')\n else document.documentElement.removeAttribute(HTML_ATTR)\n },\n { immediate: true },\n)\n\nonBeforeUnmount(() => {\n if (typeof document !== 'undefined') {\n document.documentElement.removeAttribute(HTML_ATTR)\n }\n})\n</script>\n\n<template>\n <div class=\"admin-shell-root\">\n <div v-if=\"impersonation\" class=\"admin-impersonation-banner\" role=\"status\">\n <span>\n Вы вошли как <b>{{ impersonation.asName }}</b> · режим имперсонации\n </span>\n <button\n type=\"button\"\n class=\"admin-impersonation-banner__exit\"\n @click=\"exitImpersonation\"\n >\n Выйти из режима\n </button>\n </div>\n <UidSidebarLayout\n :model-value=\"collapsed\"\n @update:model-value=\"onCollapseChange\"\n >\n <template #sidebar>\n <slot name=\"sidebar\">\n <AdminSidebar :collapsed=\"collapsed\" />\n </slot>\n </template>\n <template #header>\n <slot name=\"topbar\">\n <AdminTopBar @toggle-sidebar=\"onCollapseChange(!collapsed)\" />\n </slot>\n </template>\n <slot />\n </UidSidebarLayout>\n </div>\n</template>\n\n<style>\n.admin-shell-root[data-admin-impersonating='true'] {\n /* Sidebar/topbar sticky уже учтут `--admin-page-pad` и offset через CSS-классы. */\n padding-top: 32px;\n}\n:root[data-admin-impersonating='true'] {\n scroll-padding-top: 32px;\n}\n</style>\n","/**\n * useNavigationStore — глобальный pending-counter для top-loading-bar.\n *\n * При router.beforeEach (старт навигации) — вызываем `start()`.\n * При router.afterEach + resource-page завершила data-fetch — вызываем `end()`.\n *\n * Counter (а не bool) защищает от race condition'ов: если несколько\n * параллельных fetch'ей, bar остаётся видимым пока хоть один pending.\n */\n\nimport { defineStore } from 'pinia'\nimport { computed, ref } from 'vue'\n\nexport const useNavigationStore = defineStore('admin-navigation', () => {\n const pending = ref<number>(0)\n const isLoading = computed<boolean>(() => pending.value > 0)\n\n function start(): void {\n pending.value += 1\n }\n\n function end(): void {\n if (pending.value > 0) pending.value -= 1\n }\n\n /** Сбросить counter (на случай зависшего pending в dev). */\n function reset(): void {\n pending.value = 0\n }\n\n return { pending, isLoading, start, end, reset }\n})\n","<script setup lang=\"ts\">\n/**\n * Top loading bar (как у YouTube/GitHub/Vercel).\n *\n * Реактивно отображает useNavigationStore.isLoading. Indeterminate-anim\n * (CSS keyframes) — slide bar слева направо в бесконечном цикле пока\n * pending > 0.\n *\n * Hide-delay 120ms: если pending быстро спадает к 0, bar успевает\n * мигнуть в полный размер вместо instant-cutoff.\n */\nimport { computed, ref, watch } from 'vue'\nimport { useNavigationStore } from '../stores/navigation'\n\nconst nav = useNavigationStore()\n\n// Soft-hide: bar остаётся 120ms после end() для плавности.\nconst visible = ref<boolean>(false)\nlet hideTimer: ReturnType<typeof setTimeout> | null = null\n\nwatch(\n () => nav.isLoading,\n (loading) => {\n if (loading) {\n if (hideTimer !== null) {\n clearTimeout(hideTimer)\n hideTimer = null\n }\n visible.value = true\n } else {\n hideTimer = setTimeout(() => {\n visible.value = false\n hideTimer = null\n }, 120)\n }\n },\n { immediate: true },\n)\n\nconst cls = computed(() => ({\n 'admin-loading-bar': true,\n 'admin-loading-bar--visible': visible.value,\n}))\n</script>\n\n<template>\n <div :class=\"cls\" role=\"progressbar\" aria-busy=\"true\" />\n</template>\n\n<style>\n.admin-loading-bar {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n height: 2px;\n z-index: var(--uid-z-toast, 9999);\n pointer-events: none;\n opacity: 0;\n transition: opacity 120ms ease-out;\n background: transparent;\n}\n\n.admin-loading-bar--visible {\n opacity: 1;\n}\n\n.admin-loading-bar--visible::before {\n content: '';\n position: absolute;\n inset: 0;\n background: var(--uid-accent, var(--uid-color-primary, #14b8a6));\n transform-origin: 0 50%;\n animation: admin-loading-bar-slide 1.4s cubic-bezier(0.4, 0, 0.2, 1) infinite;\n}\n\n@keyframes admin-loading-bar-slide {\n 0% {\n transform: translateX(-100%) scaleX(0.4);\n }\n 50% {\n transform: translateX(0%) scaleX(0.7);\n }\n 100% {\n transform: translateX(100%) scaleX(0.4);\n }\n}\n\n/* Reduced-motion: статичный bar 60% width. */\n@media (prefers-reduced-motion: reduce) {\n .admin-loading-bar--visible::before {\n animation: none;\n width: 60%;\n transform: none;\n }\n}\n</style>\n","<script setup lang=\"ts\">\n/**\n * Root компонент SPA admin'а — рендерит router-view, оборачивая его в\n * AdminShell layout (TopBar + Sidebar + content) для аутентифицированных\n * роутов. Auth-роуты (login, 403, 404) и роуты с meta.fullscreen рендерятся\n * без shell.\n *\n * Используется createAdminApp() как root-component. Host'ы редко\n * переопределяют — обычно достаточно настроить отдельные pages через опции.\n */\nimport { computed } from 'vue'\nimport { useRoute } from 'vue-router'\nimport AdminShell from './shell/AdminShell.vue'\nimport AdminLoadingBar from './AdminLoadingBar.vue'\n\nconst route = useRoute()\n\nconst useShell = computed<boolean>(() => {\n if (route.meta?.fullscreen === true) return false\n if (route.meta?.kind === 'auth') return false\n if (route.name === 'admin.notFound') return false\n return true\n})\n</script>\n\n<template>\n <!-- Top loading-bar: показывается пока nav/data не закончили (см. useNavigationStore). -->\n <AdminLoadingBar />\n\n <AdminShell v-if=\"useShell\">\n <div class=\"admin-page-host\">\n <router-view v-slot=\"{ Component }\">\n <Transition name=\"admin-page\">\n <component :is=\"Component\" />\n </Transition>\n </router-view>\n </div>\n </AdminShell>\n <router-view v-else v-slot=\"{ Component }\">\n <Transition name=\"admin-page\">\n <component :is=\"Component\" />\n </Transition>\n </router-view>\n</template>\n\n<style>\n/*\n * Page-host: relative контейнер. Старая страница leaving делается absolute\n * (overlay поверх новой), entering в нормальном flow с slide-from-right.\n *\n * Тайминги (по запросу):\n * - leaving fade-out: 140ms ease-out (быстро уходит).\n * - entering slide-from-right + fade-in: 320ms cubic-bezier easing,\n * с 60ms delay чтобы старая успела \"пропасть до того как новая\n * доберётся до позиции\".\n *\n * overflow:hidden на host — slide справа не вылезает за viewport.\n */\n.admin-page-host {\n position: relative;\n min-height: 200px;\n overflow: hidden;\n}\n\n/* Leaving page absolute — не двигает layout, остаётся на месте пока fade'ится. */\n.admin-page-leave-active {\n position: absolute;\n inset: 0;\n width: 100%;\n transition: opacity 140ms ease-out;\n}\n\n.admin-page-leave-to {\n opacity: 0;\n}\n\n/* Entering page: slide-in справа + fade-in. Delay 60ms — старая уже почти ушла. */\n.admin-page-enter-active {\n transition:\n opacity 320ms cubic-bezier(0.2, 0.8, 0.2, 1) 60ms,\n transform 320ms cubic-bezier(0.2, 0.8, 0.2, 1) 60ms;\n}\n\n.admin-page-enter-from {\n opacity: 0;\n transform: translateX(28px);\n}\n\n.admin-page-enter-to {\n opacity: 1;\n transform: translateX(0);\n}\n\n@media (prefers-reduced-motion: reduce) {\n .admin-page-enter-active,\n .admin-page-leave-active {\n transition: opacity 80ms ease-out;\n }\n .admin-page-enter-from {\n transform: none;\n }\n}\n</style>\n","/**\n * Manifest store: lazy-load JSON-манифеста админки + кеширование по version.\n *\n * Manifest содержит описание всех Resource'ов, Screen'ов, Settings'ов,\n * Plugin'ов. SPA загружает один раз на старте и переиспользует.\n *\n * ETag-based 304 Not Modified backend-side — фронт ничего особенного не\n * делает (axios + browser handle If-None-Match). Свежий version записывается\n * в lastVersion для cheap-сравнения.\n */\n\nimport { defineStore } from 'pinia'\nimport { computed, ref } from 'vue'\nimport { getAdminClient } from './registry'\n\n/**\n * Узел manifest'а с обязательным `type`. Совместим с LayoutNode/FieldNode/\n * InfolistNode — позволяет передавать массив прямо в renderer без cast'а.\n */\nexport interface ManifestNode extends Record<string, unknown> {\n type: string\n}\n\nexport interface ManifestResourceMeta {\n slug: string\n label: string\n icon?: string\n group?: string | null\n permissions: Record<string, string>\n fields: ManifestNode[]\n columns: ManifestNode[]\n filters: ManifestNode[]\n actions: ManifestNode[]\n searchable: string[]\n with: string[]\n features: Record<string, unknown>\n screens?: Record<string, unknown>\n}\n\nexport interface ManifestScreenMeta {\n slug: string\n name: string\n description: string | null\n permission: string[] | string | null\n}\n\nexport interface ManifestSettingsMeta {\n kind: 'settings'\n slug: string\n label: string\n permissions: Record<string, string>\n fields: ManifestNode[]\n}\n\nexport interface AdminManifest {\n version: string\n locale: string\n resources: ManifestResourceMeta[]\n screens: ManifestScreenMeta[]\n settings: ManifestSettingsMeta[]\n dashboards: unknown[]\n plugins: string[]\n permissions: unknown[]\n}\n\nexport const useManifestStore = defineStore('admin-manifest', () => {\n const manifest = ref<AdminManifest | null>(null)\n const loading = ref(false)\n const error = ref<Error | null>(null)\n\n const isLoaded = computed(() => manifest.value !== null)\n const version = computed(() => manifest.value?.version ?? null)\n const resources = computed(() => manifest.value?.resources ?? [])\n const screens = computed(() => manifest.value?.screens ?? [])\n const settings = computed(() => manifest.value?.settings ?? [])\n const plugins = computed(() => manifest.value?.plugins ?? [])\n\n function getResource(slug: string): ManifestResourceMeta | null {\n return resources.value.find((r) => r.slug === slug) ?? null\n }\n\n function getScreen(slug: string): ManifestScreenMeta | null {\n return screens.value.find((s) => s.slug === slug) ?? null\n }\n\n function getSettings(slug: string): ManifestSettingsMeta | null {\n return settings.value.find((s) => s.slug === slug) ?? null\n }\n\n /**\n * Загрузить manifest. Если уже загружен — возвращает cached.\n * Force=true принудительно обновит с сервера.\n */\n async function load(force = false): Promise<AdminManifest> {\n if (manifest.value !== null && !force) {\n return manifest.value\n }\n\n loading.value = true\n error.value = null\n try {\n const client = getAdminClient()\n const result = await client.get<AdminManifest>('/system/manifest')\n manifest.value = result\n return result\n } catch (err) {\n error.value = err instanceof Error ? err : new Error(String(err))\n throw err\n } finally {\n loading.value = false\n }\n }\n\n function reset(): void {\n manifest.value = null\n error.value = null\n loading.value = false\n }\n\n return {\n // state\n manifest,\n loading,\n error,\n // getters\n isLoaded,\n version,\n resources,\n screens,\n settings,\n plugins,\n // actions\n getResource,\n getScreen,\n getSettings,\n load,\n reset,\n }\n})\n","<script setup lang=\"ts\">\n/**\n * Default home-страница admin'а. Host'ы перебивают через\n * createAdminApp({ pages: { home: MyHome } }).\n *\n * Показывает welcome-карточку + список зарегистрированных Resource'ов из\n * manifest store (быстрая навигация для свежепоставленной админки).\n */\nimport { computed } from 'vue'\nimport { useRouter } from 'vue-router'\nimport { UidCard } from '@dskripchenko/ui'\nimport { useManifestStore } from '../stores/manifest'\nimport { useAuthStore } from '../stores/auth'\n\nconst manifest = useManifestStore()\nconst auth = useAuthStore()\nconst router = useRouter()\n\nconst userName = computed(() => auth.user?.name ?? '')\nconst resources = computed(() => manifest.manifest?.resources ?? [])\n</script>\n\n<template>\n <div class=\"admin-home\">\n <UidCard padding=\"lg\" class=\"admin-home__hero\">\n <h1 class=\"admin-home__title\">Добро пожаловать{{ userName ? ', ' + userName : '' }}</h1>\n <p class=\"admin-home__lead\">\n Админ-панель готова. Воспользуйтесь сайдбаром или переходите к ресурсам ниже.\n </p>\n </UidCard>\n\n <section v-if=\"resources.length\" class=\"admin-home__resources\">\n <h2 class=\"admin-home__heading\">Ресурсы</h2>\n <ul class=\"admin-home__grid\">\n <li v-for=\"r in resources\" :key=\"r.slug\">\n <button\n type=\"button\"\n class=\"admin-home__card\"\n @click=\"router.push({ name: `admin.resource.${r.slug}.index` })\"\n >\n <span class=\"admin-home__card-label\">{{ r.label }}</span>\n <span class=\"admin-home__card-slug\">{{ r.slug }}</span>\n </button>\n </li>\n </ul>\n </section>\n </div>\n</template>\n\n<style>\n.admin-home {\n display: flex;\n flex-direction: column;\n gap: var(--uid-space-lg);\n padding: var(--uid-space-md);\n}\n.admin-home__title {\n font-size: var(--uid-font-size-2xl);\n font-weight: var(--uid-font-weight-bold);\n margin: 0 0 var(--uid-space-sm);\n}\n.admin-home__lead {\n color: var(--uid-text-secondary);\n margin: 0;\n}\n.admin-home__heading {\n font-size: var(--uid-font-size-lg);\n font-weight: var(--uid-font-weight-semibold);\n margin: 0 0 var(--uid-space-sm);\n}\n.admin-home__grid {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));\n gap: var(--uid-space-sm);\n list-style: none;\n padding: 0;\n margin: 0;\n}\n.admin-home__card {\n display: flex;\n flex-direction: column;\n gap: var(--uid-space-2xs);\n padding: var(--uid-space-md);\n border: 1px solid var(--uid-border-subtle);\n border-radius: var(--uid-radius-md);\n background: var(--uid-surface-raised);\n text-align: left;\n cursor: pointer;\n transition: border-color 0.15s ease, transform 0.15s ease;\n}\n.admin-home__card:hover {\n border-color: var(--uid-accent);\n transform: translateY(-1px);\n}\n.admin-home__card-label {\n font-weight: var(--uid-font-weight-medium);\n}\n.admin-home__card-slug {\n font-size: var(--uid-font-size-xs);\n color: var(--uid-text-tertiary);\n}\n</style>\n","<script setup lang=\"ts\">\n/**\n * 403 fallback. Host может переопределить через createAdminApp({ pages: { forbidden } }).\n */\nimport { UidCard, UidButton } from '@dskripchenko/ui'\nimport { useRouter } from 'vue-router'\n\nconst router = useRouter()\n</script>\n\n<template>\n <div class=\"admin-status-page\">\n <UidCard padding=\"lg\" class=\"admin-status-page__card\">\n <h1 class=\"admin-status-page__code\">403</h1>\n <p class=\"admin-status-page__message\">Доступ запрещён.</p>\n <UidButton variant=\"ghost\" @click=\"router.replace({ name: 'admin.home' })\">\n На главную\n </UidButton>\n </UidCard>\n </div>\n</template>\n\n<style>\n.admin-status-page {\n display: flex;\n align-items: center;\n justify-content: center;\n min-height: 60vh;\n padding: var(--uid-space-lg);\n}\n.admin-status-page__card {\n text-align: center;\n max-width: 480px;\n}\n.admin-status-page__code {\n font-size: 64px;\n font-weight: var(--uid-font-weight-bold);\n margin: 0 0 var(--uid-space-sm);\n color: var(--uid-text-secondary);\n}\n.admin-status-page__message {\n margin: 0 0 var(--uid-space-md);\n color: var(--uid-text-secondary);\n}\n</style>\n","<script setup lang=\"ts\">\n/**\n * 404 fallback. Host может переопределить через createAdminApp({ pages: { notFound } }).\n */\nimport { UidCard, UidButton } from '@dskripchenko/ui'\nimport { useRouter } from 'vue-router'\n\nconst router = useRouter()\n</script>\n\n<template>\n <div class=\"admin-status-page\">\n <UidCard padding=\"lg\" class=\"admin-status-page__card\">\n <h1 class=\"admin-status-page__code\">404</h1>\n <p class=\"admin-status-page__message\">Страница не найдена.</p>\n <UidButton variant=\"ghost\" @click=\"router.replace({ name: 'admin.home' })\">\n На главную\n </UidButton>\n </UidCard>\n </div>\n</template>\n","<script setup lang=\"ts\">\n/**\n * Default страница для admin.settings.{slug} роутов.\n *\n * Загружает settings-meta из manifest'а и рендерит fields через LayoutRenderer\n * с form-state поверх SettingsApiClient. Host'ы переопределяют через\n * createAdminApp({ pages: { settings: MySettings } }) если нужна более\n * специфичная UX (например, side-tab навигация по Settings-классам).\n */\nimport { computed } from 'vue'\nimport { useRoute } from 'vue-router'\nimport { UidCard } from '@dskripchenko/ui'\nimport { useManifestStore } from '../stores/manifest'\n\nconst route = useRoute()\nconst manifest = useManifestStore()\n\nconst slug = computed(() => String(route.params.slug ?? ''))\nconst meta = computed(() => manifest.manifest?.settings?.find((s) => s.slug === slug.value) ?? null)\n</script>\n\n<template>\n <div class=\"admin-settings-page\">\n <UidCard padding=\"lg\">\n <h1 class=\"admin-settings-page__title\">{{ meta?.label ?? slug }}</h1>\n <p v-if=\"!meta\" class=\"admin-settings-page__hint\">\n Settings «{{ slug }}» не найдено в manifest'е.\n </p>\n <pre v-else class=\"admin-settings-page__debug\">{{ JSON.stringify(meta.fields, null, 2) }}</pre>\n </UidCard>\n </div>\n</template>\n\n<style>\n.admin-settings-page {\n padding: var(--uid-space-md);\n}\n.admin-settings-page__title {\n font-size: var(--uid-font-size-xl);\n font-weight: var(--uid-font-weight-semibold);\n margin: 0 0 var(--uid-space-sm);\n}\n.admin-settings-page__debug {\n background: var(--uid-surface-raised);\n border: 1px solid var(--uid-border-subtle);\n padding: var(--uid-space-sm);\n border-radius: var(--uid-radius-sm);\n font-family: var(--uid-font-mono);\n font-size: var(--uid-font-size-xs);\n overflow: auto;\n max-height: 60vh;\n}\n.admin-settings-page__hint {\n color: var(--uid-text-secondary);\n}\n</style>\n","<script setup lang=\"ts\">\n/**\n * Заглушка для произвольных Screen-роутов из manifest'а.\n * Host'ы переопределяют через createAdminApp({ pages: { screen: MyScreen } })\n * и кастомным компонентом рендерят `route.params.slug` через любой template.\n */\nimport { computed } from 'vue'\nimport { useRoute } from 'vue-router'\nimport { UidCard } from '@dskripchenko/ui'\n\nconst route = useRoute()\nconst slug = computed(() => String(route.params.slug ?? ''))\nconst title = computed(() => String(route.meta?.title ?? slug.value))\n</script>\n\n<template>\n <div class=\"admin-status-page\">\n <UidCard padding=\"lg\" class=\"admin-status-page__card\">\n <h1 class=\"admin-status-page__title\">{{ title }}</h1>\n <p class=\"admin-status-page__hint\">\n Это заглушка для screen «{{ slug }}». Передайте свой компонент через\n <code>createAdminApp({{ '{' }} pages: {{ '{' }} screen: MyScreen {{ '}' }} {{ '}' }})</code>.\n </p>\n </UidCard>\n </div>\n</template>\n\n<style>\n.admin-status-page__title {\n font-size: var(--uid-font-size-xl);\n font-weight: var(--uid-font-weight-semibold);\n margin: 0 0 var(--uid-space-sm);\n}\n.admin-status-page__hint {\n margin: 0;\n color: var(--uid-text-secondary);\n font-size: var(--uid-font-size-sm);\n}\n</style>\n","<script setup lang=\"ts\">\n/**\n * LoginForm — email/password/remember поверх UidInput/UidButton/UidCheckbox/\n * UidAlert. Архитектура auth-card по docs/design_handoff_laravel_admin/\n * screens-secondary.jsx (LoginScreen).\n */\nimport { computed, ref } from 'vue'\nimport { UidAlert, UidButton, UidCheckbox, UidInput } from '@dskripchenko/ui'\nimport { useAuthStore } from '../../stores/auth'\nimport { ApiError, NetworkError, ValidationError } from '../../api/errors'\n\ninterface Props {\n /** URL «Забыли пароль?» — если задан, показывается link справа от remember. */\n forgotUrl?: string | null\n /** Текст SSO-ссылки или null чтобы скрыть. */\n ssoLinkLabel?: string | null\n ssoUrl?: string | null\n}\n\nwithDefaults(defineProps<Props>(), {\n forgotUrl: null,\n ssoLinkLabel: null,\n ssoUrl: null,\n})\n\nconst emit = defineEmits<{\n success: [result: 'authenticated' | 'two_factor_required']\n}>()\n\nconst auth = useAuthStore()\n\nconst email = ref('')\nconst password = ref('')\nconst remember = ref(false)\n\nconst submitting = ref(false)\nconst generalError = ref<string | null>(null)\nconst fieldErrors = ref<Record<string, string[]>>({})\n\nconst emailError = computed<string | undefined>(() => fieldErrors.value.email?.[0])\nconst passwordError = computed<string | undefined>(() => fieldErrors.value.password?.[0])\n\nasync function submit(): Promise<void> {\n if (submitting.value) return\n submitting.value = true\n generalError.value = null\n fieldErrors.value = {}\n\n try {\n const result = await auth.login({\n email: email.value,\n password: password.value,\n remember: remember.value,\n })\n emit('success', result)\n } catch (err) {\n if (err instanceof ValidationError) {\n fieldErrors.value = err.fields\n generalError.value = err.firstFieldMessage()\n } else if (err instanceof NetworkError) {\n generalError.value = 'Нет соединения с сервером'\n } else if (err instanceof ApiError) {\n generalError.value = err.message || 'Не удалось войти'\n } else {\n generalError.value = (err as Error).message\n }\n } finally {\n submitting.value = false\n }\n}\n</script>\n\n<template>\n <form class=\"admin-auth-card__bd\" novalidate @submit.prevent=\"submit\">\n <UidAlert\n v-if=\"generalError\"\n variant=\"danger\"\n class=\"admin-auth-card__alert\"\n role=\"alert\"\n >\n {{ generalError }}\n </UidAlert>\n\n <UidInput\n v-model=\"email\"\n type=\"email\"\n label=\"Email\"\n placeholder=\"you@company.com\"\n autocomplete=\"username\"\n :required=\"true\"\n :disabled=\"submitting\"\n :error=\"emailError\"\n name=\"email\"\n />\n\n <UidInput\n v-model=\"password\"\n type=\"password\"\n label=\"Пароль\"\n autocomplete=\"current-password\"\n :required=\"true\"\n :disabled=\"submitting\"\n :error=\"passwordError\"\n name=\"password\"\n />\n\n <div class=\"admin-auth-card__row\">\n <UidCheckbox v-model=\"remember\" :disabled=\"submitting\">\n Запомнить меня\n </UidCheckbox>\n <a v-if=\"forgotUrl\" :href=\"forgotUrl\" class=\"admin-auth-card__link\">\n Забыли пароль?\n </a>\n </div>\n\n <UidButton\n type=\"submit\"\n variant=\"primary\"\n size=\"lg\"\n :loading=\"submitting\"\n :disabled=\"submitting\"\n >\n {{ submitting ? 'Вход…' : 'Войти' }}\n </UidButton>\n\n <div\n v-if=\"ssoLinkLabel && ssoUrl\"\n style=\"text-align: center; font-size: var(--uid-font-size-xs); color: var(--uid-text-secondary); padding-top: 4px;\"\n >\n или войдите через\n <a :href=\"ssoUrl\" class=\"admin-auth-card__link\">{{ ssoLinkLabel }}</a>\n </div>\n </form>\n</template>\n","<script setup lang=\"ts\">\n/**\n * 2FA-форма: 6-cell mono TOTP-input + alt recovery-code.\n *\n * Эталон — docs/design_handoff_laravel_admin/screens-secondary.jsx (TwoFactor):\n * 6 input'ов 44×52, IBM Plex Mono 22px, при заполнении одного — фокус\n * автопереходит на следующий, paste-event раскладывает 6 цифр сразу.\n */\nimport { computed, nextTick, ref } from 'vue'\nimport { UidAlert, UidButton, UidInput } from '@dskripchenko/ui'\nimport { useAuthStore } from '../../stores/auth'\nimport { ApiError, NetworkError, ValidationError } from '../../api/errors'\n\nconst emit = defineEmits<{\n success: []\n cancel: []\n}>()\n\nconst auth = useAuthStore()\n\nconst mode = ref<'totp' | 'recovery'>('totp')\nconst cells = ref<string[]>(['', '', '', '', '', ''])\nconst recoveryCode = ref('')\nconst cellRefs = ref<HTMLInputElement[]>([])\n\nconst submitting = ref(false)\nconst generalError = ref<string | null>(null)\nconst remaining = ref<number | null>(null)\n\nconst totpCode = computed(() => cells.value.join(''))\nconst isValid = computed(() => {\n if (mode.value === 'totp') return totpCode.value.length === 6\n return recoveryCode.value.trim().length > 0\n})\n\nfunction setCellRef(idx: number, el: Element | null): void {\n if (el instanceof HTMLInputElement) cellRefs.value[idx] = el\n}\n\nfunction onCellInput(idx: number, event: Event): void {\n const target = event.target as HTMLInputElement\n // Только цифры; обрезаем до 1 символа.\n const digit = target.value.replace(/\\D/g, '').slice(-1)\n cells.value[idx] = digit\n target.value = digit\n if (digit && idx < cells.value.length - 1) {\n void nextTick(() => cellRefs.value[idx + 1]?.focus())\n }\n if (totpCode.value.length === cells.value.length) {\n void submit()\n }\n}\n\nfunction onCellKeydown(idx: number, event: KeyboardEvent): void {\n if (event.key === 'Backspace' && !cells.value[idx] && idx > 0) {\n void nextTick(() => cellRefs.value[idx - 1]?.focus())\n } else if (event.key === 'ArrowLeft' && idx > 0) {\n cellRefs.value[idx - 1]?.focus()\n event.preventDefault()\n } else if (event.key === 'ArrowRight' && idx < cells.value.length - 1) {\n cellRefs.value[idx + 1]?.focus()\n event.preventDefault()\n }\n}\n\nfunction onPaste(event: ClipboardEvent): void {\n const pasted = event.clipboardData?.getData('text') ?? ''\n const digits = pasted.replace(/\\D/g, '').slice(0, cells.value.length)\n if (digits.length === 0) return\n event.preventDefault()\n for (let i = 0; i < cells.value.length; i++) {\n cells.value[i] = digits[i] ?? ''\n }\n void nextTick(() => {\n cellRefs.value[Math.min(digits.length, cells.value.length - 1)]?.focus()\n if (digits.length === cells.value.length) void submit()\n })\n}\n\nasync function submit(): Promise<void> {\n if (submitting.value || !isValid.value) return\n submitting.value = true\n generalError.value = null\n\n try {\n if (mode.value === 'totp') {\n await auth.twoFactorChallenge(totpCode.value)\n } else {\n const res = await auth.twoFactorRecovery(recoveryCode.value.trim())\n remaining.value = res.remaining\n }\n emit('success')\n } catch (err) {\n if (err instanceof ValidationError) {\n generalError.value = err.firstFieldMessage() ?? 'Неверный код'\n } else if (err instanceof NetworkError) {\n generalError.value = 'Нет соединения с сервером'\n } else if (err instanceof ApiError) {\n generalError.value = err.message || 'Не удалось проверить код'\n } else {\n generalError.value = (err as Error).message\n }\n } finally {\n submitting.value = false\n }\n}\n\nfunction cancel(): void {\n auth.cancelChallenge()\n emit('cancel')\n}\n\nfunction switchMode(): void {\n mode.value = mode.value === 'totp' ? 'recovery' : 'totp'\n generalError.value = null\n}\n</script>\n\n<template>\n <form class=\"admin-auth-card__bd\" novalidate @submit.prevent=\"submit\">\n <UidAlert\n v-if=\"generalError\"\n variant=\"danger\"\n class=\"admin-auth-card__alert\"\n role=\"alert\"\n >\n {{ generalError }}\n </UidAlert>\n <UidAlert\n v-if=\"remaining !== null\"\n variant=\"info\"\n class=\"admin-auth-card__alert\"\n role=\"status\"\n >\n Использован recovery-код. Осталось: {{ remaining }}\n </UidAlert>\n\n <div v-if=\"mode === 'totp'\" class=\"admin-code-input\" @paste=\"onPaste\">\n <input\n v-for=\"(_, idx) in cells\"\n :key=\"idx\"\n :ref=\"(el) => setCellRef(idx, el as Element | null)\"\n :value=\"cells[idx]\"\n type=\"text\"\n inputmode=\"numeric\"\n autocomplete=\"one-time-code\"\n maxlength=\"1\"\n :disabled=\"submitting\"\n :aria-label=\"`Цифра ${idx + 1}`\"\n @input=\"onCellInput(idx, $event)\"\n @keydown=\"onCellKeydown(idx, $event)\"\n />\n </div>\n\n <UidInput\n v-else\n v-model=\"recoveryCode\"\n type=\"text\"\n label=\"Recovery-код\"\n autocomplete=\"one-time-code\"\n :disabled=\"submitting\"\n name=\"recovery-code\"\n />\n\n <UidButton\n type=\"submit\"\n variant=\"primary\"\n size=\"lg\"\n :loading=\"submitting\"\n :disabled=\"submitting || !isValid\"\n >\n {{ submitting ? 'Проверка…' : 'Подтвердить' }}\n </UidButton>\n\n <div class=\"admin-auth-card__row\">\n <button type=\"button\" class=\"admin-auth-card__link\" @click=\"switchMode\">\n <template v-if=\"mode === 'totp'\">Использовать recovery-код</template>\n <template v-else>Вернуться к коду из приложения</template>\n </button>\n <button type=\"button\" class=\"admin-auth-card__link\" @click=\"cancel\">\n Отмена\n </button>\n </div>\n </form>\n</template>\n","<script setup lang=\"ts\">\n/**\n * LoginPage поверх UID design handoff: centered auth-card 400/440 px на\n * `--uid-surface-base`-фоне с corner-actions (theme + locale toggles).\n *\n * Композиция: LoginForm либо TwoFactorForm в зависимости от\n * auth.isChallengePending. Редирект на main завязан на watch\n * (auth.isAuthenticated) — это переживает unmount форм при смене ветки.\n *\n * `?redirect`-query учитывает только относительные пути (защита от\n * open-redirect).\n */\nimport { onMounted, watch } from 'vue'\nimport { useRouter, useRoute } from 'vue-router'\nimport { UidCard } from '@dskripchenko/ui'\nimport { useAuthStore } from '../../stores/auth'\nimport LoginForm from './LoginForm.vue'\nimport TwoFactorForm from './TwoFactorForm.vue'\nimport ThemeToggle from '../shell/widgets/ThemeToggle.vue'\nimport LocaleSwitcher from '../shell/widgets/LocaleSwitcher.vue'\n\ninterface Props {\n brandName?: string\n brandMark?: string\n brandLogo?: string | null\n homeRouteName?: string\n redirectQueryKey?: string\n /** URL «Забыли пароль?» — пробрасывается в LoginForm. */\n forgotUrl?: string | null\n /** SSO-link (label + url) — пробрасывается в LoginForm. */\n ssoLinkLabel?: string | null\n ssoUrl?: string | null\n /** Показывать ли theme/locale toggle'ы в углу. */\n showCornerActions?: boolean\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n brandName: 'Laravel Admin',\n brandMark: 'L',\n brandLogo: null,\n homeRouteName: 'admin.home',\n redirectQueryKey: 'redirect',\n forgotUrl: null,\n ssoLinkLabel: null,\n ssoUrl: null,\n showCornerActions: true,\n})\n\nconst auth = useAuthStore()\nconst router = useRouter()\nconst route = useRoute()\n\nasync function redirectToHome(): Promise<void> {\n const target = route.query[props.redirectQueryKey]\n if (typeof target === 'string' && target.length > 0 && target.startsWith('/')) {\n await router.push(target)\n return\n }\n await router.push({ name: props.homeRouteName })\n}\n\nwatch(\n () => auth.isAuthenticated,\n (next) => {\n if (next) void redirectToHome()\n },\n)\nonMounted(() => {\n if (auth.isAuthenticated) void redirectToHome()\n})\n</script>\n\n<template>\n <div class=\"admin-auth-page\">\n <div v-if=\"showCornerActions\" class=\"admin-auth-page__corner\">\n <ThemeToggle />\n <LocaleSwitcher />\n </div>\n\n <UidCard\n :class=\"['admin-auth-card', auth.isChallengePending ? 'admin-auth-card--wide' : '']\"\n padding=\"none\"\n >\n <div class=\"admin-auth-card__hd\">\n <div\n :class=\"['admin-auth-card__logo', auth.isChallengePending ? 'admin-auth-card__logo--accent' : '']\"\n >\n <img v-if=\"brandLogo && !auth.isChallengePending\" :src=\"brandLogo\" :alt=\"brandName\" />\n <span v-else-if=\"auth.isChallengePending\" aria-hidden=\"true\">🛡</span>\n <span v-else>{{ brandMark }}</span>\n </div>\n <div class=\"admin-auth-card__title\">\n <template v-if=\"auth.isChallengePending\">Двухфакторная проверка</template>\n <template v-else>{{ brandName }}</template>\n </div>\n <div class=\"admin-auth-card__sub\">\n <template v-if=\"auth.isChallengePending\">\n Введите 6-значный код из приложения-аутентификатора\n </template>\n <template v-else>Войдите, чтобы продолжить работу</template>\n </div>\n </div>\n\n <TwoFactorForm\n v-if=\"auth.isChallengePending\"\n @success=\"() => undefined\"\n @cancel=\"() => undefined\"\n />\n <LoginForm\n v-else\n :forgot-url=\"forgotUrl\"\n :sso-link-label=\"ssoLinkLabel\"\n :sso-url=\"ssoUrl\"\n @success=\"() => undefined\"\n />\n </UidCard>\n </div>\n</template>\n","/**\n * useResourceIndexStore — list-page state для одного Resource'а.\n *\n * Поддерживает:\n * - items + pagination meta из envelope payload\n * - filters (typed Record<string, unknown>) — отправляются как query\n * - sort (key + direction)\n * - selection (Set<row-id>) для bulk-actions; tri-state header-checkbox\n * - loading/error состояния (UI рендерит UidSkeleton/UidErrorState)\n *\n * Один store-instance переиспользуется на разных Resource-страницах через\n * `useResourceIndexStore(slug)` с явным `setSlug` — это даёт чистый reset\n * между resource'ами.\n */\n\nimport { defineStore } from 'pinia'\nimport { computed, ref } from 'vue'\nimport { getAdminClient } from './registry'\n\nexport interface IndexMeta {\n page: number\n per_page: number\n total: number\n last_page: number\n}\n\nexport type SortDirection = 'asc' | 'desc' | null\n\nexport interface IndexParams {\n page?: number\n per_page?: number\n sort?: string | null\n direction?: SortDirection\n search?: string | null\n filters?: Record<string, unknown>\n}\n\ninterface ListResponse {\n data: Array<Record<string, unknown>>\n meta: IndexMeta\n}\n\nconst DEFAULT_META: IndexMeta = { page: 1, per_page: 20, total: 0, last_page: 1 }\n\nexport const useResourceIndexStore = defineStore('admin-resource-index', () => {\n /** Текущий resource-slug (urls/users/posts/etc). */\n const slug = ref<string | null>(null)\n\n const items = ref<Array<Record<string, unknown>>>([])\n const meta = ref<IndexMeta>({ ...DEFAULT_META })\n\n const loading = ref(false)\n /**\n * `slowLoading` = true только если loading длится > SLOW_LOADING_DELAY мс.\n * UI использует это для skeleton — чтобы быстрые ответы (<200мс) не\n * мерцали 'data → skeleton → data'. Если запрос быстрый, skeleton\n * никогда не показывается.\n */\n const slowLoading = ref(false)\n const error = ref<Error | null>(null)\n let slowLoadingTimer: ReturnType<typeof setTimeout> | null = null\n const SLOW_LOADING_DELAY = 200\n\n const search = ref<string>('')\n const filters = ref<Record<string, unknown>>({})\n const sortKey = ref<string | null>(null)\n const sortDirection = ref<SortDirection>(null)\n\n /** Set ID-шников выбранных строк (bulk-actions). */\n const selection = ref<Set<string | number>>(new Set())\n\n const isEmpty = computed(() => !loading.value && error.value === null && items.value.length === 0)\n const selectedCount = computed(() => selection.value.size)\n const hasSelection = computed(() => selection.value.size > 0)\n const hasError = computed(() => error.value !== null)\n\n /** Tri-state: 'all' / 'mixed' / 'none' для header-checkbox. */\n const selectionState = computed<'all' | 'mixed' | 'none'>(() => {\n if (selection.value.size === 0) return 'none'\n if (items.value.length === 0) return 'none'\n const allSelected = items.value.every((row) => selection.value.has(rowId(row)))\n return allSelected ? 'all' : 'mixed'\n })\n\n /** Извлекает ID строки. По умолчанию — поле `id`; host может переопределить. */\n function rowId(row: Record<string, unknown>): string | number {\n return (row.id ?? row.key ?? '') as string | number\n }\n\n /**\n * Сменить ресурс — сброс state'а.\n *\n * `loading=true` ставится сразу, чтобы в окне между setSlug() и load() не\n * рендерилась EmptyState (\"Нет данных\") — это вызывало flicker при\n * navigation между Resource'ами.\n */\n function setSlug(next: string | null): void {\n if (slug.value === next) return\n slug.value = next\n reset()\n loading.value = true\n }\n\n function reset(): void {\n items.value = []\n meta.value = { ...DEFAULT_META }\n loading.value = false\n error.value = null\n search.value = ''\n filters.value = {}\n sortKey.value = null\n sortDirection.value = null\n selection.value = new Set()\n }\n\n function buildParams(override: IndexParams = {}): Record<string, unknown> {\n const params: Record<string, unknown> = {\n page: override.page ?? meta.value.page,\n per_page: override.per_page ?? meta.value.per_page,\n }\n // Free-text: backend ждёт `q`. См. HttpFilterParser::searchTerm.\n const ss = override.search ?? search.value\n if (ss) params.q = ss\n\n // Order: массив {column, direction}. Backend читает `order[]` через input('order').\n // Если direction === null → не добавляем order (3-режимная sort: off).\n const sk = override.sort ?? sortKey.value\n const dir = override.direction ?? sortDirection.value\n if (sk && dir !== null) {\n params.order = [{ column: sk, direction: dir }]\n }\n\n // Filters: map-style {column: value} — HttpFilterParser auto-detect режим 1.\n const f = override.filters ?? filters.value\n const filtersMap: Record<string, unknown> = {}\n for (const [k, v] of Object.entries(f)) {\n if (v === null || v === undefined || v === '') continue\n filtersMap[k] = Array.isArray(v) ? v.join(',') : v\n }\n if (Object.keys(filtersMap).length > 0) params.filters = filtersMap\n\n return params\n }\n\n /** Загрузить страницу. Без аргументов — текущие фильтры/сортировка/page. */\n async function load(override: IndexParams = {}): Promise<void> {\n if (!slug.value) {\n throw new Error('useResourceIndexStore.load() called before setSlug()')\n }\n loading.value = true\n error.value = null\n // Debounced flag для skeleton: true только если запрос длится > 200мс.\n if (slowLoadingTimer !== null) clearTimeout(slowLoadingTimer)\n slowLoadingTimer = setTimeout(() => {\n slowLoading.value = true\n }, SLOW_LOADING_DELAY)\n try {\n const client = getAdminClient()\n const body = buildParams(override)\n // Backend ResourceController.search: POST /{slug}/search.\n // Тело — параметры (фильтры/сортировка/пагинация). Возвращает\n // {data, meta:{page,per_page,total,last_page,...}}.\n const res = await client.post<ListResponse>(`/${slug.value}/search`, body)\n items.value = res.data\n meta.value = res.meta\n } catch (err) {\n error.value = err instanceof Error ? err : new Error(String(err))\n throw err\n } finally {\n loading.value = false\n slowLoading.value = false\n if (slowLoadingTimer !== null) {\n clearTimeout(slowLoadingTimer)\n slowLoadingTimer = null\n }\n }\n }\n\n async function setSearch(value: string): Promise<void> {\n search.value = value\n meta.value.page = 1\n await load()\n }\n\n async function setFilter(key: string, value: unknown): Promise<void> {\n if (value === null || value === undefined || value === '') {\n delete filters.value[key]\n } else {\n filters.value[key] = value\n }\n meta.value.page = 1\n await load()\n }\n\n async function clearFilters(): Promise<void> {\n filters.value = {}\n meta.value.page = 1\n await load()\n }\n\n async function setSort(key: string | null, direction: SortDirection = 'asc'): Promise<void> {\n sortKey.value = key\n sortDirection.value = direction\n await load()\n }\n\n /**\n * 3-режимная sort. Click по same key → asc → desc → off (sort=null).\n * Click по другому key → asc.\n */\n async function toggleSort(key: string): Promise<void> {\n if (sortKey.value === key) {\n if (sortDirection.value === 'asc') {\n sortDirection.value = 'desc'\n } else if (sortDirection.value === 'desc') {\n sortKey.value = null\n sortDirection.value = null\n } else {\n sortDirection.value = 'asc'\n }\n } else {\n sortKey.value = key\n sortDirection.value = 'asc'\n }\n await load()\n }\n\n async function setPage(page: number): Promise<void> {\n meta.value.page = page\n await load()\n }\n\n function toggleRow(id: string | number): void {\n const next = new Set(selection.value)\n if (next.has(id)) next.delete(id)\n else next.add(id)\n selection.value = next\n }\n\n /** Toggle: выделить все на странице если что-то не выбрано, иначе очистить. */\n function toggleAllOnPage(): void {\n if (selectionState.value === 'all') {\n selection.value = new Set()\n return\n }\n const next = new Set(selection.value)\n for (const row of items.value) next.add(rowId(row))\n selection.value = next\n }\n\n function clearSelection(): void {\n selection.value = new Set()\n }\n\n /** Проверить выбор конкретной строки. */\n function isSelected(id: string | number): boolean {\n return selection.value.has(id)\n }\n\n return {\n // state\n slug,\n items,\n meta,\n loading,\n slowLoading,\n error,\n search,\n filters,\n sortKey,\n sortDirection,\n selection,\n // getters\n isEmpty,\n hasError,\n hasSelection,\n selectedCount,\n selectionState,\n // actions\n setSlug,\n reset,\n load,\n setSearch,\n setFilter,\n clearFilters,\n setSort,\n toggleSort,\n setPage,\n toggleRow,\n toggleAllOnPage,\n clearSelection,\n isSelected,\n rowId,\n }\n})\n","/**\n * Formatter cell-значений для ResourceIndexPage.\n *\n * Backend-side TableColumn presets:\n * - text → as-is (string).\n * - date → 'd.m.Y' (default).\n * - datetime → 'd.m.Y H:i:s' (default).\n * - money → '{value} {currency}' с decimals.\n * - boolean → trueLabel / falseLabel из meta.\n * - badge → текст; стилизация на UI рендере (через slot или CSS-class).\n * - bytes → human-readable размер.\n * - text → fallback.\n *\n * `auto-format` для колонок без явного preset'а: если значение похоже на ISO\n * datetime (`*_at` или строка с T...Z) — применяется default datetime формат.\n */\n\nexport type CellPreset = 'text' | 'date' | 'datetime' | 'money' | 'boolean' | 'badge' | 'bytes'\n\nexport interface CellMeta {\n format?: string\n currency?: string\n decimals?: number\n trueLabel?: string | null\n falseLabel?: string | null\n [key: string]: unknown\n}\n\nconst DEFAULT_DATETIME = 'd.m.Y H:i:s'\nconst DEFAULT_DATE = 'd.m.Y'\n\nconst ISO_DATETIME_RE = /^\\d{4}-\\d{2}-\\d{2}[T\\s]\\d{2}:\\d{2}/\n\nexport function formatCell(\n value: unknown,\n preset: string | undefined,\n meta: CellMeta = {},\n): string {\n if (value === null || value === undefined) return ''\n\n // Auto-detection ISO datetime для колонок без preset'а.\n if (!preset && typeof value === 'string' && ISO_DATETIME_RE.test(value)) {\n return formatDateString(value, DEFAULT_DATETIME)\n }\n\n switch (preset) {\n case 'date':\n return formatDateString(String(value), meta.format ?? DEFAULT_DATE)\n case 'datetime':\n return formatDateString(String(value), meta.format ?? DEFAULT_DATETIME)\n case 'money':\n return formatMoney(value, meta.currency ?? 'RUB', meta.decimals ?? 2)\n case 'boolean':\n return formatBoolean(value, meta.trueLabel ?? 'Да', meta.falseLabel ?? 'Нет')\n case 'bytes':\n return formatBytes(value)\n default:\n return String(value)\n }\n}\n\n/**\n * PHP-стиль format strings → JS-Date.\n *\n * Поддерживаемые токены:\n * d → 01-31, m → 01-12, Y → 2026, y → 26\n * H → 00-23, h → 12-hour, i → minutes, s → seconds\n * D → Mon-Sun (3-letter), l → full day name, M → Jan, F → January\n * N → 1-7 (ISO weekday), w → 0-6\n * U → Unix timestamp, c → ISO 8601\n */\nfunction formatDateString(input: string, format: string): string {\n const date = new Date(input)\n if (isNaN(date.getTime())) return input\n\n const pad = (n: number, w = 2): string => String(n).padStart(w, '0')\n\n const tokens: Record<string, string> = {\n d: pad(date.getDate()),\n m: pad(date.getMonth() + 1),\n Y: String(date.getFullYear()),\n y: pad(date.getFullYear() % 100),\n H: pad(date.getHours()),\n h: pad(((date.getHours() + 11) % 12) + 1),\n i: pad(date.getMinutes()),\n s: pad(date.getSeconds()),\n U: String(Math.floor(date.getTime() / 1000)),\n c: date.toISOString(),\n N: String(((date.getDay() + 6) % 7) + 1),\n w: String(date.getDay()),\n }\n\n // Замена с учётом escape '\\\\' (PHP: backslash escapes the next char).\n let out = ''\n for (let i = 0; i < format.length; i++) {\n const ch = format[i]\n if (ch === '\\\\' && i + 1 < format.length) {\n out += format[i + 1]\n i++\n continue\n }\n out += tokens[ch] ?? ch\n }\n return out\n}\n\nfunction formatMoney(value: unknown, currency: string, decimals: number): string {\n const n = typeof value === 'number' ? value : Number(value)\n if (isNaN(n)) return String(value)\n return `${n.toFixed(decimals)} ${currency}`\n}\n\nfunction formatBoolean(value: unknown, trueLabel: string, falseLabel: string): string {\n const truthy = value === true || value === 1 || value === '1' || value === 'true'\n return truthy ? trueLabel : falseLabel\n}\n\nfunction formatBytes(value: unknown): string {\n const n = typeof value === 'number' ? value : Number(value)\n if (isNaN(n)) return String(value)\n if (n < 1024) return `${n} B`\n if (n < 1024 * 1024) return `${(n / 1024).toFixed(1)} KB`\n if (n < 1024 * 1024 * 1024) return `${(n / 1024 / 1024).toFixed(1)} MB`\n return `${(n / 1024 / 1024 / 1024).toFixed(1)} GB`\n}\n","<script setup lang=\"ts\">\n/**\n * ResourceIndexPage — list-screen для одного Resource'а из manifest'а.\n * Архитектура по docs/design_handoff_laravel_admin/screens-shell.jsx (Resource List).\n *\n * Композиция:\n * - Page header (title + count + actions cluster)\n * - Filter bar с search + chips\n * - Bulk toolbar (заменяет filter bar при selectedCount > 0)\n * - UidTable с manifest.columns\n * - States: loading (UidSkeleton ×8) / empty (UidEmptyState) / error (UidErrorState)\n * - UidPagination внизу\n *\n * Host рендерит page через router. resource-slug приходит из props (либо\n * из route.params).\n */\nimport { computed, nextTick, onMounted, watch } from 'vue'\nimport {\n UidButton,\n UidEmptyState,\n UidErrorState,\n UidPagination,\n UidSkeleton,\n UidTable,\n type UidTableColumn,\n} from '@dskripchenko/ui'\nimport { useResourceIndexStore } from '../../stores/resourceIndex'\nimport { useManifestStore } from '../../stores/manifest'\nimport { useNavigationStore } from '../../stores/navigation'\nimport { formatCell, type CellMeta } from './cellFormat'\n\ninterface Props {\n /** Slug ресурса (users/articles/etc). */\n slug: string\n /** Заголовок страницы. Если не задан — берётся из manifest'а. */\n title?: string | null\n /** Подпись под заголовком (например \"Аналитика контента\"). */\n subtitle?: string | null\n /** Текст primary-кнопки «Создать». */\n createLabel?: string\n /** Имя router-route для action «Создать». */\n createRouteName?: string | null\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n title: null,\n subtitle: null,\n createLabel: 'Создать',\n createRouteName: null,\n})\n\nconst emit = defineEmits<{\n /** Bulk-action triggered с текущим Set'ом id. */\n 'bulk-action': [action: string, ids: Array<string | number>]\n /** Click на row — host решает (push edit / open view). */\n 'row-click': [row: Record<string, unknown>]\n}>()\n\nconst index = useResourceIndexStore()\nconst manifest = useManifestStore()\nconst nav = useNavigationStore()\n\nconst resourceMeta = computed(() => manifest.getResource(props.slug))\n\nconst displayTitle = computed(\n () => props.title ?? resourceMeta.value?.label ?? props.slug,\n)\n\nconst columns = computed<UidTableColumn[]>(() => {\n const cols = resourceMeta.value?.columns ?? []\n return cols.map((c) => {\n const col = c as Record<string, unknown>\n return {\n key: String(col.key ?? col.name ?? ''),\n label: String(col.label ?? col.name ?? ''),\n sortable: Boolean(col.sortable),\n align: (col.align as 'left' | 'center' | 'right' | undefined) ?? 'left',\n width: typeof col.width === 'string' ? col.width : undefined,\n }\n }).filter((c) => c.key)\n})\n\n// Колоночная meta (preset / format / currency / etc.) из manifest'а.\n// Используется для formatCell (datetime → 'd.m.Y H:i:s', money → '{val} {ccy}').\nconst columnMeta = computed<Record<string, { preset?: string; meta: CellMeta }>>(() => {\n const cols = resourceMeta.value?.columns ?? []\n const result: Record<string, { preset?: string; meta: CellMeta }> = {}\n for (const c of cols) {\n const col = c as Record<string, unknown>\n const key = String(col.key ?? col.name ?? '')\n if (!key) continue\n result[key] = {\n preset: typeof col.preset === 'string' ? col.preset : undefined,\n meta: (col.meta as CellMeta) ?? {},\n }\n }\n return result\n})\n\nfunction renderCell(key: string, slotProps: unknown): string {\n // UidTable scoped-slot передаёт {row: actualRow}.\n const row = (slotProps as { row?: Record<string, unknown> } | undefined)?.row\n const value = row?.[key]\n const m = columnMeta.value[key]\n return formatCell(value, m?.preset, m?.meta ?? {})\n}\n\nfunction rowFromSlot(slotProps: unknown): Record<string, unknown> | undefined {\n return (slotProps as { row?: Record<string, unknown> } | undefined)?.row\n}\n\n/**\n * Показывать ли filter-bar:\n * - если есть данные → всегда (search + фильтры внутри);\n * - если данных нет, но есть активный search/filter → ДА (чтобы пользователь\n * мог сбросить и снова увидеть items);\n * - если данных нет и фильтры/поиск пустые → НЕТ (initial empty state).\n */\nconst hasActiveFilters = computed<boolean>(\n () => index.search !== '' || Object.keys(index.filters).length > 0,\n)\nconst showFilterBar = computed<boolean>(\n () => !index.isEmpty || hasActiveFilters.value,\n)\n\nconst totalLabel = computed(() => {\n const t = index.meta.total\n if (t === 0) return ''\n return `${index.items.length} из ${t}`\n})\n\n/**\n * Обёртка над index.load — увеличивает navigation pending counter\n * (top loading-bar) на время запроса. router.beforeEach уже инкрементирует\n * counter при start navigation; этот wrap держит bar до конца data-fetch'а.\n */\nasync function loadWithProgress(): Promise<void> {\n nav.start()\n try {\n await index.load()\n } catch {\n // silent; ошибка отображается в hasError state\n } finally {\n nav.end()\n }\n}\n\n/**\n * Mount-init: setSlug + load data.\n *\n * При SPA navigation от router.push первичный data-fetch также делается\n * в router.beforeResolve (см. createAdminApp.ts) — он держит navigation\n * в pending пока данные не пришли. Здесь load всё равно вызываем как\n * resilient fallback (direct page mount, page reload, test).\n */\nonMounted(async () => {\n index.setSlug(props.slug)\n if (manifest.manifest === null) {\n await manifest.load().catch(() => undefined)\n }\n await loadWithProgress()\n})\n\nwatch(\n () => props.slug,\n async (next, prev) => {\n if (next === prev) return\n index.setSlug(next)\n await loadWithProgress()\n },\n)\n\nasync function onSortKeyUpdate(key: string | null): Promise<void> {\n // UidTable управляет своим 3-режимным cycle; здесь только применяем итог.\n // sortDirection приходит отдельным событием — apply через setSort одним\n // вызовом (после nextTick — Vue batches событий).\n await nextTick()\n await index.setSort(key, index.sortDirection)\n}\n\nasync function onSortDirUpdate(dir: 'asc' | 'desc' | null): Promise<void> {\n await nextTick()\n await index.setSort(index.sortKey, dir)\n}\n\nfunction onSelectionUpdate(next: Set<string | number>): void {\n index.selection = next\n}\n\nasync function onPageChange(page: number): Promise<void> {\n await index.setPage(page)\n}\n\nfunction onRowClick(row: Record<string, unknown>): void {\n emit('row-click', row)\n}\n\nfunction bulkAction(action: string): void {\n emit('bulk-action', action, [...index.selection])\n}\n\nasync function retryLoad(): Promise<void> {\n await index.load().catch(() => undefined)\n}\n</script>\n\n<template>\n <section class=\"admin-page admin-resource-index\">\n <!-- Header -->\n <header class=\"admin-page__hd\">\n <div class=\"admin-page__title-wrap\">\n <h1 class=\"admin-page__title\">{{ displayTitle }}</h1>\n <div v-if=\"subtitle || totalLabel\" class=\"admin-page__count\">\n <template v-if=\"subtitle\">{{ subtitle }}</template>\n <template v-if=\"subtitle && totalLabel\"> · </template>\n <template v-if=\"totalLabel\">{{ totalLabel }}</template>\n </div>\n </div>\n <div class=\"admin-page__actions\">\n <slot name=\"actions\" />\n <UidButton\n v-if=\"createRouteName\"\n variant=\"primary\"\n @click=\"$router.push({ name: createRouteName })\"\n >\n {{ createLabel }}\n </UidButton>\n </div>\n </header>\n\n <!-- Bulk toolbar (selection > 0) ИЛИ filter bar -->\n <div v-if=\"index.hasSelection\" class=\"admin-bulk-toolbar\" role=\"toolbar\">\n <span class=\"admin-bulk-toolbar__count\">\n Выбрано <b>{{ index.selectedCount }}</b>\n </span>\n <span class=\"admin-bulk-toolbar__divider\" />\n <UidButton size=\"sm\" variant=\"ghost\" @click=\"bulkAction('publish')\">Опубликовать</UidButton>\n <UidButton size=\"sm\" variant=\"ghost\" @click=\"bulkAction('archive')\">Архивировать</UidButton>\n <UidButton size=\"sm\" variant=\"ghost\" @click=\"bulkAction('export')\">Экспорт</UidButton>\n <UidButton size=\"sm\" variant=\"danger\" @click=\"bulkAction('delete')\">Удалить</UidButton>\n <span class=\"admin-bulk-toolbar__spacer\" />\n <UidButton size=\"sm\" variant=\"ghost\" @click=\"index.clearSelection\">\n Снять выделение\n </UidButton>\n </div>\n\n <div v-else-if=\"showFilterBar\" class=\"admin-filter-bar\">\n <input\n :value=\"index.search\"\n type=\"search\"\n placeholder=\"Поиск…\"\n class=\"admin-filter-bar__search\"\n @keydown.enter=\"(e) => index.setSearch((e.target as HTMLInputElement).value)\"\n />\n <slot name=\"filters\" :filters=\"index.filters\" :set-filter=\"index.setFilter\" />\n <span class=\"admin-filter-bar__spacer\" />\n <UidButton\n v-if=\"Object.keys(index.filters).length > 0\"\n size=\"sm\"\n variant=\"ghost\"\n @click=\"index.clearFilters\"\n >\n Сброс\n </UidButton>\n </div>\n\n <!-- States -->\n <!-- Initial-loading стейт (между setSlug и первым успехом load).\n Показываем placeholder вместо UidTable — иначе сама таблица\n рендерит \"Нет данных\" empty state, что создаёт flicker\n \"Нет данных → реальные строки\" при navigation. -->\n <div\n v-if=\"index.loading && index.items.length === 0\"\n class=\"admin-resource-index__loading\"\n >\n <UidSkeleton\n v-if=\"index.slowLoading\"\n v-for=\"i in 8\"\n :key=\"i\"\n height=\"40px\"\n />\n </div>\n <UidErrorState\n v-else-if=\"index.hasError\"\n title=\"Не удалось загрузить данные\"\n :description=\"index.error?.message ?? 'Попробуйте обновить страницу.'\"\n class=\"admin-resource-index__state\"\n >\n <template #actions>\n <UidButton variant=\"primary\" @click=\"retryLoad\">Обновить</UidButton>\n </template>\n </UidErrorState>\n <UidEmptyState\n v-else-if=\"index.isEmpty\"\n title=\"Пока пусто\"\n description=\"Создайте первую запись или измените фильтры.\"\n class=\"admin-resource-index__state\"\n >\n <template #actions>\n <UidButton\n v-if=\"createRouteName\"\n variant=\"primary\"\n @click=\"$router.push({ name: createRouteName })\"\n >\n {{ createLabel }}\n </UidButton>\n </template>\n </UidEmptyState>\n\n <!-- Таблица — UidTable native selection (UidTable.selectable + selection prop). -->\n <div v-else class=\"admin-resource-index__table\">\n <UidTable\n :columns=\"columns\"\n :data=\"index.items\"\n :sort-key=\"index.sortKey\"\n :sort-direction=\"index.sortDirection\"\n selectable\n :selection=\"index.selection\"\n :row-key=\"(row) => index.rowId(row)\"\n @update:sort-key=\"onSortKeyUpdate\"\n @update:sort-direction=\"onSortDirUpdate\"\n @update:selection=\"onSelectionUpdate\"\n @row-click=\"onRowClick\"\n >\n <template\n v-for=\"col in columns\"\n #[col.key]=\"slotProps\"\n :key=\"col.key\"\n >\n <slot :name=\"`cell-${col.key}`\" :row=\"rowFromSlot(slotProps)\">\n {{ renderCell(col.key, slotProps) }}\n </slot>\n </template>\n </UidTable>\n </div>\n\n <!-- Pagination -->\n <footer\n v-if=\"!index.loading && !index.hasError && !index.isEmpty\"\n class=\"admin-resource-index__footer\"\n >\n <UidPagination\n :model-value=\"index.meta.page\"\n :total=\"index.meta.total\"\n :per-page=\"index.meta.per_page\"\n @update:model-value=\"onPageChange\"\n />\n </footer>\n </section>\n</template>\n\n<style>\n.admin-resource-index__loading {\n display: flex;\n flex-direction: column;\n gap: var(--uid-space-sm);\n margin-top: var(--uid-space-md);\n /* min-height предотвращает layout-collapse при первом mount'е,\n когда slowLoading ещё false (быстрый запрос — placeholder пустой). */\n min-height: 320px;\n}\n.admin-resource-index__state {\n margin-top: var(--uid-space-xl);\n}\n.admin-resource-index__table {\n /* table визуально приклеена к filter-bar / bulk-toolbar сверху —\n убираем gap, скругляем только нижние углы у table-wrap'а. */\n margin-top: 0;\n}\n.admin-resource-index__table .uid-table-wrap {\n border: 1px solid var(--uid-border-subtle);\n border-top: 0;\n border-radius: 0 0 var(--uid-radius-lg) var(--uid-radius-lg);\n}\n.admin-resource-index__footer {\n display: flex;\n justify-content: flex-end;\n padding: var(--uid-space-md) 0;\n}\n\n/* Filter bar */\n.admin-filter-bar {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--uid-space-sm);\n padding: var(--uid-space-sm) var(--uid-space-md);\n border: 1px solid var(--uid-border-subtle);\n background: var(--uid-surface-raised);\n border-radius: var(--uid-radius-lg) var(--uid-radius-lg) 0 0;\n border-bottom: 0;\n margin-top: var(--uid-space-md);\n}\n.admin-filter-bar__search {\n flex: 1;\n min-width: 200px;\n max-width: 320px;\n height: 28px;\n padding: 0 var(--uid-space-sm);\n border: 1px solid var(--uid-border-subtle);\n background: var(--uid-surface-base);\n border-radius: var(--uid-radius-md);\n color: var(--uid-text-primary);\n font-size: 13px;\n outline: none;\n}\n.admin-filter-bar__search:focus {\n border-color: var(--uid-accent);\n outline: 2px solid color-mix(in srgb, var(--uid-accent) 18%, transparent);\n}\n.admin-filter-bar__spacer { flex: 1; }\n\n/* Bulk toolbar — dark zinc-900 surface, заменяет filter bar */\n.admin-bulk-toolbar {\n display: flex;\n align-items: center;\n gap: var(--uid-space-sm);\n padding: var(--uid-space-sm) var(--uid-space-md);\n background: var(--uid-color-zinc-900, #18181b);\n color: var(--uid-color-zinc-100, #f4f4f5);\n border-radius: var(--uid-radius-lg) var(--uid-radius-lg) 0 0;\n border: 1px solid var(--uid-color-zinc-900, #18181b);\n border-bottom: 0;\n margin-top: var(--uid-space-md);\n}\n.admin-bulk-toolbar__count { font-size: 13px; }\n.admin-bulk-toolbar__count b { font-weight: var(--uid-font-weight-semibold); }\n.admin-bulk-toolbar__divider {\n width: 1px;\n height: 20px;\n background: rgba(255, 255, 255, 0.15);\n}\n.admin-bulk-toolbar__spacer { flex: 1; }\n.admin-bulk-toolbar .uid-button {\n background: transparent;\n border-color: rgba(255, 255, 255, 0.15);\n color: var(--uid-color-zinc-100, #f4f4f5);\n}\n.admin-bulk-toolbar .uid-button:hover:not([disabled]) {\n background: rgba(255, 255, 255, 0.08);\n}\n.admin-bulk-toolbar .uid-button--danger {\n color: var(--uid-color-rose-400, #fb7185);\n}\n\n/* Selected row tint */\n.admin-resource-index__row--selected {\n background: color-mix(in srgb, var(--uid-accent) 8%, transparent);\n}\n</style>\n","/**\n * useResourceFormStore — state для Resource Create/Edit/View screens.\n *\n * Управляет:\n * - mode ('create' | 'edit' | 'view')\n * - record (raw из API), state (working copy в form-state, но мы держим\n * reference на initial для unsaved-changes detection)\n * - errors (field-keyed) — устанавливаются при ValidationError\n * - loading/saving/deleting — для disable submit / show spinner\n * - dirty (computed) — есть ли несохранённые изменения\n *\n * Endpoints (laravel-admin contract):\n * GET /{slug}/read — fetch one (id в query)\n * POST /{slug}/create\n * POST /{slug}/update\n * POST /{slug}/delete\n */\n\nimport { defineStore } from 'pinia'\nimport { computed, ref } from 'vue'\nimport { getAdminClient } from './registry'\nimport { ApiError, ValidationError } from '../api/errors'\n\nexport type FormMode = 'create' | 'edit' | 'view'\n\ninterface ReadResponse {\n // backend ResourceController::read возвращает payload {record}.\n record: Record<string, unknown>\n}\n\ninterface SaveResponse {\n // backend create/update возвращает payload {record, redirect_url, message}.\n record?: Record<string, unknown>\n id?: string | number\n redirect_url?: string\n message?: string\n}\n\nexport const useResourceFormStore = defineStore('admin-resource-form', () => {\n const slug = ref<string | null>(null)\n const mode = ref<FormMode>('create')\n const recordId = ref<string | number | null>(null)\n\n /** Текущее состояние формы — мутируется через setField. */\n const state = ref<Record<string, unknown>>({})\n /** Snapshot изначальных значений (после load) — для dirty-detection. */\n const initial = ref<Record<string, unknown>>({})\n\n /** Field-keyed errors. Очищаются при successful save. */\n const errors = ref<Record<string, string[]>>({})\n\n const loading = ref(false)\n const saving = ref(false)\n const deleting = ref(false)\n const error = ref<Error | null>(null)\n\n const isCreate = computed(() => mode.value === 'create')\n const isEdit = computed(() => mode.value === 'edit')\n const isView = computed(() => mode.value === 'view')\n const hasError = computed(() => error.value !== null)\n\n /** Dirty: state отличается от initial хотя бы по одному ключу. */\n const isDirty = computed(() => {\n const a = state.value\n const b = initial.value\n const keys = new Set([...Object.keys(a), ...Object.keys(b)])\n for (const k of keys) {\n if (!Object.is(a[k], b[k])) {\n // Простое сравнение скаляров; объекты/массивы сравниваем JSON-сериализацией.\n if (typeof a[k] === 'object' || typeof b[k] === 'object') {\n if (JSON.stringify(a[k]) !== JSON.stringify(b[k])) return true\n } else {\n return true\n }\n }\n }\n return false\n })\n\n /** In-place мутация reactive-объекта — сохраняет identity для provide/inject. */\n function replaceObject(target: Record<string, unknown>, next: Record<string, unknown>): void {\n for (const k of Object.keys(target)) delete target[k]\n Object.assign(target, next)\n }\n\n function reset(): void {\n replaceObject(state.value, {})\n replaceObject(initial.value, {})\n errors.value = {}\n loading.value = false\n saving.value = false\n deleting.value = false\n error.value = null\n recordId.value = null\n }\n\n /** Подготовить store для create-mode на ресурсе. */\n function prepareCreate(resourceSlug: string, defaults: Record<string, unknown> = {}): void {\n slug.value = resourceSlug\n mode.value = 'create'\n recordId.value = null\n replaceObject(state.value, defaults)\n replaceObject(initial.value, defaults)\n errors.value = {}\n error.value = null\n }\n\n /** Загрузить запись для edit либо view-режима. */\n async function load(\n resourceSlug: string,\n id: string | number,\n targetMode: 'edit' | 'view' = 'edit',\n ): Promise<void> {\n slug.value = resourceSlug\n mode.value = targetMode\n recordId.value = id\n loading.value = true\n error.value = null\n errors.value = {}\n\n try {\n const client = getAdminClient()\n const res = await client.get<ReadResponse>(`/${resourceSlug}/read`, {\n params: { id },\n })\n replaceObject(state.value, res.record)\n replaceObject(initial.value, res.record)\n } catch (err) {\n error.value = err instanceof Error ? err : new Error(String(err))\n throw err\n } finally {\n loading.value = false\n }\n }\n\n /** Установить значение поля (через FormState composable обычно). */\n function setField(name: string, value: unknown): void {\n state.value[name] = value\n if (errors.value[name]) {\n // Очищаем ошибку конкретного поля при изменении (стандартный UX).\n const next = { ...errors.value }\n delete next[name]\n errors.value = next\n }\n }\n\n function setErrors(next: Record<string, string[]>): void {\n errors.value = { ...next }\n }\n\n function clearErrors(): void {\n errors.value = {}\n }\n\n /**\n * Сохранить. На create — POST /create; на edit — POST /update с id.\n * Возвращает new id (для post-create редиректа).\n */\n async function save(): Promise<string | number> {\n if (!slug.value) throw new Error('useResourceFormStore.save() before slug set')\n if (saving.value) throw new Error('Already saving')\n\n saving.value = true\n error.value = null\n errors.value = {}\n\n try {\n const client = getAdminClient()\n const url =\n mode.value === 'create'\n ? `/${slug.value}/create`\n : `/${slug.value}/update`\n\n const payload =\n mode.value === 'create'\n ? state.value\n : { id: recordId.value, ...state.value }\n\n const res = await client.post<SaveResponse>(url, payload)\n // Backend отдаёт `record: {id, ...}`. Старый формат `{id}` тоже поддерживаем.\n const newId = (res.record?.id ?? res.id) as string | number | undefined\n if (newId === undefined) {\n throw new Error('save: backend response does not contain record.id')\n }\n recordId.value = newId\n // После успешного save обновим initial = state, чтобы dirty=false.\n replaceObject(initial.value, { ...state.value })\n mode.value = 'edit'\n return newId\n } catch (err) {\n if (err instanceof ValidationError) {\n errors.value = { ...err.fields }\n } else if (err instanceof ApiError) {\n error.value = err\n } else if (err instanceof Error) {\n error.value = err\n }\n throw err\n } finally {\n saving.value = false\n }\n }\n\n /** Удалить текущую запись (только в edit-mode). */\n async function destroy(): Promise<void> {\n if (!slug.value || recordId.value === null) {\n throw new Error('Nothing to delete')\n }\n if (deleting.value) throw new Error('Already deleting')\n\n deleting.value = true\n error.value = null\n try {\n const client = getAdminClient()\n await client.post(`/${slug.value}/delete`, { id: recordId.value })\n } catch (err) {\n if (err instanceof Error) error.value = err\n throw err\n } finally {\n deleting.value = false\n }\n }\n\n return {\n // state\n slug,\n mode,\n recordId,\n state,\n initial,\n errors,\n loading,\n saving,\n deleting,\n error,\n // getters\n isCreate,\n isEdit,\n isView,\n isDirty,\n hasError,\n // actions\n reset,\n prepareCreate,\n load,\n setField,\n setErrors,\n clearErrors,\n save,\n destroy,\n }\n})\n","/**\n * Generic factory для component-registry'ов (fields, layouts, widgets,\n * infolist entries и т.п.).\n *\n * Все component-registry в admin'е по сути одинаковы: keyed Map<string, Component>\n * + register/get/has/list/clear/registerBundle. Этот factory вытаскивает паттерн\n * один раз; конкретные модули просто переименовывают экспорты.\n *\n * const reg = createComponentRegistry<Component>()\n * export const registerWidget = reg.register\n * export const getWidget = reg.get\n * // ...\n */\n\nexport interface ComponentRegistry<T> {\n register(type: string, value: T): void\n get(type: string): T | null\n has(type: string): boolean\n list(): string[]\n clear(): void\n registerBundle(bundle: Record<string, T>): void\n}\n\nexport function createComponentRegistry<T>(): ComponentRegistry<T> {\n const store = new Map<string, T>()\n\n return {\n register(type, value) {\n store.set(type, value)\n },\n get(type) {\n return store.get(type) ?? null\n },\n has(type) {\n return store.has(type)\n },\n list() {\n return [...store.keys()]\n },\n clear() {\n store.clear()\n },\n registerBundle(bundle) {\n for (const [type, value] of Object.entries(bundle)) {\n store.set(type, value)\n }\n },\n }\n}\n","/**\n * Реестр Vue-компонентов для JSON-driven рендеринга.\n *\n * Содержит две Map'ы — для `field`-типов (input'ы, контролы) и для\n * `layout`-типов (контейнеры). LayoutRenderer и FieldRenderer резолвят тип\n * через эти реестры; host-проект может зарегистрировать кастомные компоненты\n * через `registerField()` / `registerLayout()`.\n *\n * Singleton — один регистр на admin-instance. Тестовый сценарий —\n * `clearRegistry()` + `registerField()` в `beforeEach`.\n */\n\nimport type { Component } from 'vue'\nimport { createComponentRegistry } from '../createComponentRegistry'\n\nconst fields = createComponentRegistry<Component>()\nconst layouts = createComponentRegistry<Component>()\n\nexport const registerField = fields.register\nexport const getField = fields.get\nexport const hasField = fields.has\nexport const listFields = fields.list\n\nexport const registerLayout = layouts.register\nexport const getLayout = layouts.get\nexport const hasLayout = layouts.has\nexport const listLayouts = layouts.list\n\n/** Очистить оба реестра. Используется в тестах. */\nexport function clearRegistry(): void {\n fields.clear()\n layouts.clear()\n}\n\n/**\n * Зарегистрировать сразу несколько компонентов.\n *\n * registerComponents({\n * fields: { text: TextField, select: SelectField },\n * layouts: { rows: RowsLayout, tabs: TabsLayout },\n * })\n */\nexport interface ComponentBundle {\n fields?: Record<string, Component>\n layouts?: Record<string, Component>\n}\n\nexport function registerComponents(bundle: ComponentBundle): void {\n if (bundle.fields) fields.registerBundle(bundle.fields)\n if (bundle.layouts) layouts.registerBundle(bundle.layouts)\n}\n","<script setup lang=\"ts\">\n/**\n * Fallback на missing field-registration. Видимый dev-warn вместо silent fail —\n * host-проект сразу замечает unregistered field-type.\n */\nimport { UidAlert } from '@dskripchenko/ui'\n\ninterface Props {\n type: string\n name?: string\n}\ndefineProps<Props>()\n</script>\n\n<template>\n <UidAlert variant=\"warning\">\n <template #title>Неизвестный тип поля: {{ type }}</template>\n <template v-if=\"name\">\n <code>{{ name }}</code> — зарегистрируйте field-компонент через\n <code>registerField('{{ type }}', YourComponent)</code>.\n </template>\n </UidAlert>\n</template>\n","<script setup lang=\"ts\">\n/**\n * FieldRenderer резолвит конкретный field-компонент по `node.type` из реестра\n * и forwards остальные props через v-bind.\n *\n * Узлы манифеста имеют форму:\n * { type: 'text', name: 'title', label: 'Заголовок', required: true, ... }\n *\n * Field хранит value через provide/inject form-state — узлу не передаётся\n * `modelValue` напрямую. Это позволяет строить произвольно-глубокие layout'ы\n * без явного proppin'га state'а.\n */\nimport { computed } from 'vue'\nimport { getField } from './registry'\nimport UnknownField from '../fields/UnknownField.vue'\n\nexport interface FieldNode extends Record<string, unknown> {\n type: string\n name: string\n}\n\ninterface Props {\n node: FieldNode\n}\n\nconst props = defineProps<Props>()\nconst component = computed(() => getField(props.node.type))\nconst fieldProps = computed(() => {\n const { type: _type, ...rest } = props.node\n return rest\n})\n</script>\n\n<template>\n <component :is=\"component\" v-if=\"component\" v-bind=\"fieldProps\" />\n <UnknownField v-else :type=\"node.type\" :name=\"node.name\" />\n</template>\n","<script setup lang=\"ts\">\n/**\n * Универсальный рекурсивный renderer manifest-узлов.\n *\n * Узел вида `{ kind: 'field', type: 'text', name: 'title', ... }` рендерится\n * через FieldRenderer. Узел вида `{ kind: 'layout', type: 'rows', items: [...] }`\n * — через зарегистрированный layout-компонент с children-списком.\n *\n * Для совместимости со старыми JSON'ами без `kind` — если type есть в\n * field-registry, считаем field; если в layout-registry — считаем layout;\n * иначе — UnknownField fallback.\n */\nimport { computed } from 'vue'\nimport { getField, getLayout } from './registry'\nimport FieldRenderer, { type FieldNode } from './FieldRenderer.vue'\nimport UnknownField from '../fields/UnknownField.vue'\n\nexport interface LayoutNode extends Record<string, unknown> {\n type: string\n kind?: 'field' | 'layout'\n items?: LayoutNode[]\n}\n\ninterface Props {\n node: LayoutNode\n}\nconst props = defineProps<Props>()\n\ntype Resolved =\n | { kind: 'field' }\n | { kind: 'layout'; component: ReturnType<typeof getLayout> }\n | { kind: 'unknown' }\n\nconst resolved = computed<Resolved>(() => {\n // Явный hint через `kind` всегда приоритетнее.\n if (props.node.kind === 'field') {\n return { kind: 'field' }\n }\n if (props.node.kind === 'layout') {\n const component = getLayout(props.node.type)\n return component ? { kind: 'layout', component } : { kind: 'unknown' }\n }\n // Auto-detect.\n const layoutComponent = getLayout(props.node.type)\n if (layoutComponent) return { kind: 'layout', component: layoutComponent }\n if (getField(props.node.type)) return { kind: 'field' }\n return { kind: 'unknown' }\n})\n\nconst layoutProps = computed(() => {\n const { type: _type, kind: _kind, ...rest } = props.node\n return rest\n})\n\nconst fieldNode = computed<FieldNode>(() => props.node as unknown as FieldNode)\n</script>\n\n<template>\n <component\n :is=\"resolved.component\"\n v-if=\"resolved.kind === 'layout' && resolved.component\"\n v-bind=\"layoutProps\"\n />\n <FieldRenderer v-else-if=\"resolved.kind === 'field'\" :node=\"fieldNode\" />\n <UnknownField v-else :type=\"node.type\" :name=\"(node.name as string | undefined)\" />\n</template>\n","<script setup lang=\"ts\">\n/**\n * ResourceFormPage — unified create/edit page для Resource'а.\n *\n * Архитектура по docs/design_handoff_laravel_admin/screens-shell.jsx\n * (Resource Form):\n * - Header: back-breadcrumb + title + status-badge + actions\n * (Preview / Удалить / Сохранить-primary)\n * - Body: layout из manifest.fields (LayoutRenderer + provideFormState)\n * - Sticky save-bar внизу с unsaved-changes hint\n *\n * Mode определяется наличием `id`-prop'а: id=null → create, иначе → edit.\n *\n * Form-state предоставляется через provideFormState из useResourceFormStore.state.\n * FieldRenderer'ы внутри форм автоматически подхватывают через useFormState.\n */\nimport { computed, onMounted, watch } from 'vue'\nimport { useRouter } from 'vue-router'\nimport {\n UidAlert,\n UidBadge,\n UidButton,\n UidCard,\n UidSkeleton,\n} from '@dskripchenko/ui'\nimport { useResourceFormStore } from '../../stores/resourceForm'\nimport { useManifestStore } from '../../stores/manifest'\nimport { provideFormState } from '../render/formState'\nimport LayoutRenderer from '../render/LayoutRenderer.vue'\nimport type { LayoutNode } from '../render/LayoutRenderer.vue'\n\ninterface Props {\n /** Slug ресурса (articles/users/etc). */\n slug: string\n /** ID записи. null/undefined → create-mode; число/строка → edit. */\n id?: string | number | null\n /** Имя router-route на index page (для back-redirect после save/delete). */\n indexRouteName?: string\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n id: null,\n indexRouteName: 'admin.home',\n})\n\nconst form = useResourceFormStore()\nconst manifest = useManifestStore()\nconst router = useRouter()\n\n// provideFormState ОБЯЗАН вызываться в setup() — связываем со store.state.\n// Сам form-context форвардит setField → store.setField (с auto-clear errors).\nconst ctx = provideFormState(form.state, form.errors)\n\n// Watcher: при изменениях через ctx.setField (обёртка которой) — синхронизируем\n// в store, чтобы isDirty работало. Поскольку state.value === ctx.state (тот же\n// reactive object — provideFormState не делает копию), мутации видны напрямую\n// в store. setField'у в ctx достаточно.\nwatch(\n () => form.errors,\n (next) => {\n // При обновлении store.errors — выкидываем в form-context.\n ctx.setErrors({ ...next })\n },\n)\n\nconst resourceMeta = computed(() => manifest.getResource(props.slug))\n\nconst layoutNodes = computed<LayoutNode[]>(\n () => resourceMeta.value?.fields ?? [],\n)\n\nconst titleLabel = computed(() => {\n if (form.isCreate) return `Создать: ${resourceMeta.value?.label ?? props.slug}`\n return `${resourceMeta.value?.label ?? props.slug}: запись #${props.id}`\n})\n\nconst statusValue = computed<string | null>(() => {\n const v = form.state.status\n return typeof v === 'string' ? v : null\n})\n\nconst statusBadgeVariant = computed<'success' | 'warning' | 'danger' | 'default'>(() => {\n switch (statusValue.value) {\n case 'published': return 'success'\n case 'review':\n case 'draft': return 'warning'\n case 'archived': return 'danger'\n default: return 'default'\n }\n})\n\nonMounted(async () => {\n if (manifest.manifest === null) {\n await manifest.load().catch(() => undefined)\n }\n if (props.id !== null && props.id !== undefined) {\n await form.load(props.slug, props.id, 'edit').catch(() => undefined)\n } else {\n form.prepareCreate(props.slug)\n }\n})\n\nwatch(\n () => [props.slug, props.id] as const,\n async ([nextSlug, nextId]) => {\n if (nextId !== null && nextId !== undefined) {\n await form.load(nextSlug, nextId, 'edit').catch(() => undefined)\n } else {\n form.prepareCreate(nextSlug)\n }\n },\n)\n\nasync function onSave(): Promise<void> {\n try {\n const newId = await form.save()\n if (form.isCreate) {\n // create → редирект на edit с новым id (host route'ит).\n void router.push({\n name: `admin.resource.${props.slug}.edit`,\n params: { id: newId },\n }).catch(() => undefined)\n }\n } catch {\n // ValidationError уже превратился в form.errors через store; остальные\n // ошибки попали в form.error и отрисуются как UidAlert ниже.\n }\n}\n\nasync function onDelete(): Promise<void> {\n if (!confirm('Удалить запись?')) return\n await form.destroy().catch(() => undefined)\n if (!form.hasError) {\n void router.push({ name: props.indexRouteName }).catch(() => undefined)\n }\n}\n\nfunction onCancel(): void {\n if (form.isDirty && !confirm('Несохранённые изменения будут потеряны. Продолжить?')) {\n return\n }\n void router.push({ name: props.indexRouteName }).catch(() => undefined)\n}\n</script>\n\n<template>\n <section class=\"admin-page admin-resource-form\">\n <header class=\"admin-page__hd\">\n <div class=\"admin-page__title-wrap\">\n <a class=\"admin-resource-form__back\" @click=\"onCancel\">← Назад</a>\n <h1 class=\"admin-page__title\">{{ titleLabel }}</h1>\n <UidBadge v-if=\"statusValue\" :variant=\"statusBadgeVariant\">\n {{ statusValue }}\n </UidBadge>\n </div>\n <div class=\"admin-page__actions\">\n <UidButton\n variant=\"ghost\"\n :disabled=\"form.saving || form.deleting\"\n @click=\"onCancel\"\n >\n Отмена\n </UidButton>\n <UidButton\n v-if=\"form.isEdit\"\n variant=\"danger\"\n :disabled=\"form.saving || form.deleting\"\n :loading=\"form.deleting\"\n @click=\"onDelete\"\n >\n Удалить\n </UidButton>\n <UidButton\n variant=\"primary\"\n :disabled=\"form.saving || form.loading\"\n :loading=\"form.saving\"\n @click=\"onSave\"\n >\n {{ form.isCreate ? 'Создать' : 'Сохранить' }}\n </UidButton>\n </div>\n </header>\n\n <UidAlert\n v-if=\"form.hasError\"\n variant=\"danger\"\n class=\"admin-resource-form__alert\"\n role=\"alert\"\n >\n {{ form.error?.message ?? 'Не удалось сохранить запись' }}\n </UidAlert>\n\n <!-- Loading state — UidSkeleton imitates form-rows -->\n <div v-if=\"form.loading\" class=\"admin-resource-form__loading\">\n <UidSkeleton v-for=\"i in 6\" :key=\"i\" height=\"40px\" />\n </div>\n\n <!-- Body: layout из manifest -->\n <UidCard v-else padding=\"md\" class=\"admin-resource-form__body\">\n <LayoutRenderer\n v-for=\"(node, idx) in layoutNodes\"\n :key=\"idx\"\n :node=\"node\"\n />\n </UidCard>\n\n <!-- Sticky save-bar — показывается при unsaved-changes -->\n <div v-if=\"form.isDirty && !form.loading\" class=\"admin-resource-form__savebar\">\n <span class=\"admin-resource-form__savebar-hint\">\n Есть несохранённые изменения\n </span>\n <UidButton variant=\"ghost\" size=\"sm\" @click=\"onCancel\">Отмена</UidButton>\n <UidButton\n variant=\"primary\"\n size=\"sm\"\n :loading=\"form.saving\"\n :disabled=\"form.saving\"\n @click=\"onSave\"\n >\n Сохранить\n </UidButton>\n </div>\n </section>\n</template>\n\n<style>\n.admin-resource-form__back {\n font-size: var(--uid-font-size-xs);\n color: var(--uid-text-secondary);\n cursor: pointer;\n text-decoration: none;\n display: inline-block;\n margin-bottom: 4px;\n}\n.admin-resource-form__back:hover { color: var(--uid-text-primary); }\n\n.admin-resource-form__alert {\n margin-bottom: var(--uid-space-md);\n}\n.admin-resource-form__loading {\n display: flex;\n flex-direction: column;\n gap: var(--uid-space-sm);\n}\n.admin-resource-form__body { margin-bottom: var(--uid-space-2xl); }\n\n.admin-resource-form__savebar {\n position: sticky;\n bottom: 0;\n display: flex;\n align-items: center;\n gap: var(--uid-space-sm);\n padding: var(--uid-space-sm) var(--uid-space-md);\n background: var(--uid-surface-raised);\n border-top: 1px solid var(--uid-border-default);\n border-radius: var(--uid-radius-md);\n box-shadow: var(--uid-shadow-md);\n margin-top: var(--uid-space-md);\n}\n.admin-resource-form__savebar-hint {\n flex: 1;\n font-size: 13px;\n color: var(--uid-warning);\n}\n</style>\n","/**\n * Реестр infolist-entry-компонентов.\n *\n * Аналог field-registry, но для read-only display'я. Узлы манифеста имеют\n * форму:\n * { type: 'text', name: 'title', label: 'Заголовок', value?: '...' }\n * либо без явного `value` — тогда entry извлекает `record[name]` из\n * provide'нутого `record`.\n *\n * Host регистрирует кастомные entry через `registerInfolistEntry()` /\n * `registerInfolistEntries()` bundle.\n */\n\nimport type { Component } from 'vue'\nimport { createComponentRegistry } from '../createComponentRegistry'\n\nconst entries = createComponentRegistry<Component>()\n\nexport const registerInfolistEntry = entries.register\nexport const getInfolistEntry = entries.get\nexport const hasInfolistEntry = entries.has\nexport const listInfolistEntries = entries.list\nexport const clearInfolistRegistry = entries.clear\nexport const registerInfolistEntries = entries.registerBundle\n","<script setup lang=\"ts\">\nimport { UidAlert } from '@dskripchenko/ui'\n\ninterface Props {\n type: string\n name?: string\n}\ndefineProps<Props>()\n</script>\n\n<template>\n <UidAlert variant=\"warning\">\n <template #title>Неизвестный тип infolist-entry: {{ type }}</template>\n Зарегистрируйте через <code>registerInfolistEntry('{{ type }}', YourComponent)</code>.\n </UidAlert>\n</template>\n","<script setup lang=\"ts\">\n/**\n * InfolistRenderer — read-only аналог LayoutRenderer для view-страниц.\n *\n * Узлы:\n * { type: 'text', name: 'title', label: 'Заголовок' } — entry (leaf)\n * { type: 'rows', items: [ ... ] } — layout (recurse)\n * { type: 'section', title: 'X', items: [ ... ] } — layout\n * { type: 'columns', items: [ ... ] } — layout\n *\n * Внимание: layout-узлы рендерятся СВОИМ внутренним wrapper'ом, а не\n * registered uid-layouts из render/registry, потому что те делегируют детей\n * в LayoutRenderer (field-registry → useFormState ОБЯЗАТЕЛЕН). Здесь record-\n * read-only режим — детей рендерим через сам InfolistRenderer.\n */\nimport { computed } from 'vue'\nimport { getInfolistEntry } from './registry'\nimport UnknownEntry from './UnknownEntry.vue'\n\nexport interface InfolistNode extends Record<string, unknown> {\n type: string\n /** Hint: 'entry' либо 'layout'. */\n kind?: 'entry' | 'layout'\n items?: InfolistNode[]\n}\n\ninterface Props {\n node: InfolistNode\n}\nconst props = defineProps<Props>()\n\nconst KNOWN_LAYOUTS = new Set(['rows', 'columns', 'section', 'block', 'tabs'])\n\ntype Resolved =\n | { kind: 'entry'; component: NonNullable<ReturnType<typeof getInfolistEntry>> }\n | { kind: 'layout'; layoutType: string }\n | { kind: 'unknown' }\n\nconst resolved = computed<Resolved>(() => {\n if (props.node.kind === 'entry') {\n const c = getInfolistEntry(props.node.type)\n return c ? { kind: 'entry', component: c } : { kind: 'unknown' }\n }\n if (props.node.kind === 'layout') {\n return KNOWN_LAYOUTS.has(props.node.type)\n ? { kind: 'layout', layoutType: props.node.type }\n : { kind: 'unknown' }\n }\n // Auto-detect: layouts по имени, entries по registry.\n if (KNOWN_LAYOUTS.has(props.node.type)) {\n return { kind: 'layout', layoutType: props.node.type }\n }\n const entry = getInfolistEntry(props.node.type)\n if (entry) return { kind: 'entry', component: entry }\n return { kind: 'unknown' }\n})\n\nconst entryProps = computed(() => {\n const { type: _t, kind: _k, items: _i, ...rest } = props.node\n return rest\n})\n\nconst items = computed<InfolistNode[]>(\n () => (props.node.items ?? []) as InfolistNode[],\n)\n\nconst sectionTitle = computed(() => (props.node.title as string | undefined) ?? null)\nconst sectionDescription = computed(\n () => (props.node.description as string | undefined) ?? null,\n)\nconst tabsActive = computed<number>(() => {\n const a = props.node.active\n return typeof a === 'number' ? a : 0\n})\n\ninterface InfolistTab {\n key?: string\n label: string\n items: InfolistNode[]\n}\nconst tabsList = computed<InfolistTab[]>(() => {\n return (props.node.items ?? []) as unknown as InfolistTab[]\n})\n</script>\n\n<template>\n <!-- Entry -->\n <component\n :is=\"resolved.component\"\n v-if=\"resolved.kind === 'entry'\"\n v-bind=\"entryProps\"\n />\n\n <!-- Layout: rows -->\n <div\n v-else-if=\"resolved.kind === 'layout' && resolved.layoutType === 'rows'\"\n class=\"admin-infolist-rows\"\n >\n <InfolistRenderer\n v-for=\"(child, idx) in items\"\n :key=\"idx\"\n :node=\"child\"\n />\n </div>\n\n <!-- Layout: columns (12-grid с per-item span) -->\n <div\n v-else-if=\"resolved.kind === 'layout' && resolved.layoutType === 'columns'\"\n class=\"admin-infolist-cols\"\n >\n <div\n v-for=\"(child, idx) in items\"\n :key=\"idx\"\n class=\"admin-infolist-cols__item\"\n :style=\"{\n gridColumn: `span ${\n typeof (child as Record<string, unknown>).span === 'number'\n ? (child as Record<string, unknown>).span\n : Math.max(1, Math.floor(12 / items.length))\n }`,\n }\"\n >\n <InfolistRenderer :node=\"child\" />\n </div>\n </div>\n\n <!-- Layout: section / block -->\n <section\n v-else-if=\"resolved.kind === 'layout' && (resolved.layoutType === 'section' || resolved.layoutType === 'block')\"\n class=\"admin-infolist-section\"\n >\n <header v-if=\"sectionTitle || sectionDescription\" class=\"admin-infolist-section__hd\">\n <h3 v-if=\"sectionTitle\" class=\"admin-infolist-section__title\">{{ sectionTitle }}</h3>\n <p v-if=\"sectionDescription\" class=\"admin-infolist-section__description\">\n {{ sectionDescription }}\n </p>\n </header>\n <div class=\"admin-infolist-section__body\">\n <InfolistRenderer\n v-for=\"(child, idx) in items\"\n :key=\"idx\"\n :node=\"child\"\n />\n </div>\n </section>\n\n <!-- Layout: tabs (минимальные — без переключения, показываем active по prop'у) -->\n <div\n v-else-if=\"resolved.kind === 'layout' && resolved.layoutType === 'tabs'\"\n class=\"admin-infolist-tabs\"\n >\n <ul class=\"admin-infolist-tabs__list\" role=\"tablist\">\n <li\n v-for=\"(tab, idx) in tabsList\"\n :key=\"tab.key ?? idx\"\n :class=\"[\n 'admin-infolist-tabs__tab',\n { 'admin-infolist-tabs__tab--active': idx === tabsActive },\n ]\"\n >\n {{ tab.label }}\n </li>\n </ul>\n <div class=\"admin-infolist-tabs__panel\">\n <InfolistRenderer\n v-for=\"(child, idx) in tabsList[tabsActive]?.items ?? []\"\n :key=\"idx\"\n :node=\"child\"\n />\n </div>\n </div>\n\n <UnknownEntry v-else :type=\"node.type\" :name=\"(node.name as string | undefined)\" />\n</template>\n\n<style>\n.admin-infolist-rows {\n display: flex;\n flex-direction: column;\n gap: var(--uid-space-sm);\n}\n.admin-infolist-cols {\n display: grid;\n grid-template-columns: repeat(12, minmax(0, 1fr));\n gap: var(--uid-space-md);\n}\n.admin-infolist-section {\n margin-bottom: var(--uid-space-md);\n padding: var(--uid-space-md);\n border: 1px solid var(--uid-border-subtle);\n border-radius: var(--uid-radius-lg);\n background: var(--uid-surface-raised);\n}\n.admin-infolist-section__hd { margin-bottom: var(--uid-space-sm); }\n.admin-infolist-section__title {\n margin: 0;\n font-size: var(--uid-font-size-sm);\n font-weight: var(--uid-font-weight-semibold);\n}\n.admin-infolist-section__description {\n margin: var(--uid-space-2xs) 0 0;\n font-size: var(--uid-font-size-xs);\n color: var(--uid-text-tertiary);\n}\n.admin-infolist-section__body {\n display: flex;\n flex-direction: column;\n gap: var(--uid-space-sm);\n}\n.admin-infolist-tabs__list {\n list-style: none;\n margin: 0 0 var(--uid-space-sm);\n padding: 0;\n display: flex;\n gap: var(--uid-space-xs);\n border-bottom: 1px solid var(--uid-border-subtle);\n}\n.admin-infolist-tabs__tab {\n padding: var(--uid-space-sm) var(--uid-space-sm);\n font-size: 13px;\n color: var(--uid-text-secondary);\n border-bottom: 2px solid transparent;\n}\n.admin-infolist-tabs__tab--active {\n color: var(--uid-text-primary);\n border-bottom-color: var(--uid-accent);\n font-weight: var(--uid-font-weight-medium);\n}\n</style>\n","/**\n * Composable для read-only record-контекста, передаваемого Infolist'ом.\n *\n * Контейнер (ResourceViewPage) вызывает `provideRecord(record)`, entry-\n * компоненты — `useRecord()` для чтения значения.\n */\n\nimport { inject, provide, type InjectionKey } from 'vue'\n\nconst RecordKey: InjectionKey<Record<string, unknown>> = Symbol('admin.infolist-record')\n\nexport function provideRecord(record: Record<string, unknown>): void {\n provide(RecordKey, record)\n}\n\nexport function useRecord(): Record<string, unknown> {\n const r = inject(RecordKey)\n if (!r) {\n throw new Error('useRecord() called outside of provideRecord() scope')\n }\n return r\n}\n\nexport function tryUseRecord(): Record<string, unknown> | null {\n return inject(RecordKey, null) as Record<string, unknown> | null\n}\n","<script setup lang=\"ts\">\n/**\n * ResourceViewPage — read-only зеркало form-страницы.\n *\n * Архитектура по docs/design_handoff_laravel_admin (ResourceView):\n * - Header: title + actions (Edit / Удалить)\n * - Body: 2-col grid (1fr Infolist + 320px side card с метриками)\n * - InfolistRenderer бежит по manifest.fields (тот же layout, но\n * leaf-узлы резолвятся через infolist-registry, не field-registry)\n */\nimport { computed, onMounted, watch } from 'vue'\nimport { useRouter } from 'vue-router'\nimport {\n UidAlert,\n UidButton,\n UidCard,\n UidSkeleton,\n} from '@dskripchenko/ui'\nimport { useResourceFormStore } from '../../stores/resourceForm'\nimport { useManifestStore } from '../../stores/manifest'\nimport InfolistRenderer from '../infolist/InfolistRenderer.vue'\nimport type { InfolistNode } from '../infolist/InfolistRenderer.vue'\nimport { provideRecord } from '../infolist/recordContext'\n\ninterface Props {\n slug: string\n id: string | number\n /** Имя router-route для перехода в edit. */\n editRouteName?: string\n /** Имя router-route для возврата на index. */\n indexRouteName?: string\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n editRouteName: undefined,\n indexRouteName: 'admin.home',\n})\n\nconst form = useResourceFormStore()\nconst manifest = useManifestStore()\nconst router = useRouter()\n\n// provideRecord даёт infolist-entry'ям читать record[name] через useRecord.\nprovideRecord(form.state)\n\nconst resourceMeta = computed(() => manifest.getResource(props.slug))\nconst layoutNodes = computed<InfolistNode[]>(\n () => resourceMeta.value?.fields ?? [],\n)\nconst titleLabel = computed(\n () => `${resourceMeta.value?.label ?? props.slug}: запись #${props.id}`,\n)\n\nonMounted(async () => {\n if (manifest.manifest === null) {\n await manifest.load().catch(() => undefined)\n }\n await form.load(props.slug, props.id, 'view').catch(() => undefined)\n})\n\nwatch(\n () => [props.slug, props.id] as const,\n async ([s, id]) => {\n await form.load(s, id, 'view').catch(() => undefined)\n },\n)\n\nfunction onEdit(): void {\n if (!props.editRouteName) {\n router\n .push(`/r/${props.slug}/${props.id}/edit`)\n .catch(() => undefined)\n return\n }\n router\n .push({ name: props.editRouteName, params: { id: props.id } })\n .catch(() => undefined)\n}\n\nasync function onDelete(): Promise<void> {\n if (!confirm('Удалить запись?')) return\n await form.destroy().catch(() => undefined)\n if (!form.hasError) {\n router.push({ name: props.indexRouteName }).catch(() => undefined)\n }\n}\n</script>\n\n<template>\n <section class=\"admin-page admin-resource-view\">\n <header class=\"admin-page__hd\">\n <div class=\"admin-page__title-wrap\">\n <h1 class=\"admin-page__title\">{{ titleLabel }}</h1>\n </div>\n <div class=\"admin-page__actions\">\n <UidButton variant=\"ghost\" @click=\"onEdit\">Редактировать</UidButton>\n <UidButton\n variant=\"danger\"\n :loading=\"form.deleting\"\n :disabled=\"form.deleting\"\n @click=\"onDelete\"\n >\n Удалить\n </UidButton>\n </div>\n </header>\n\n <UidAlert\n v-if=\"form.hasError\"\n variant=\"danger\"\n class=\"admin-resource-view__alert\"\n role=\"alert\"\n >\n {{ form.error?.message ?? 'Не удалось загрузить запись' }}\n </UidAlert>\n\n <div v-if=\"form.loading\" class=\"admin-resource-view__loading\">\n <UidSkeleton v-for=\"i in 8\" :key=\"i\" height=\"24px\" />\n </div>\n\n <UidCard v-else padding=\"md\" class=\"admin-resource-view__body\">\n <InfolistRenderer\n v-for=\"(node, idx) in layoutNodes\"\n :key=\"idx\"\n :node=\"node\"\n />\n </UidCard>\n </section>\n</template>\n\n<style>\n.admin-resource-view__alert {\n margin-bottom: var(--uid-space-md);\n}\n.admin-resource-view__loading {\n display: flex;\n flex-direction: column;\n gap: var(--uid-space-sm);\n}\n</style>\n","<script setup lang=\"ts\">\n/**\n * ProfilePage — профильный экран по эталону handoff'а (screens-secondary.jsx\n * → Profile). Layout 200px nav / 1fr cards.\n *\n * Slot model: каждая section экспонирует свою карточку. По умолчанию\n * library рендерит общие \"Основное\" + \"Безопасность\" (на existing-данных\n * auth.user). Host подмешивает свои \"API токены\" и \"Сессии\" через slot'ы.\n */\nimport { computed, ref } from 'vue'\nimport {\n UidAvatar,\n UidBadge,\n UidButton,\n UidCard,\n UidInput,\n UidSelect,\n} from '@dskripchenko/ui'\nimport { useAuthStore } from '../../stores/auth'\nimport { useThemeStore } from '../../stores/theme'\nimport { useLocaleStore } from '../../stores/locale'\n\ninterface Props {\n /** Заголовок страницы (по умолчанию «Profile»). */\n title?: string\n /** Подзаголовок (по умолчанию из handoff'а). */\n subtitle?: string\n /** Какая section активна. */\n section?: 'general' | 'security' | 'tokens' | 'sessions' | string\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n title: 'Profile',\n subtitle: 'Личные данные, безопасность, токены',\n section: 'general',\n})\n\nconst emit = defineEmits<{\n 'update:section': [value: string]\n /** Host реагирует — например запросом /me/uploadAvatar. */\n 'avatar-replace': []\n /** 2FA disable triggered — host показывает confirmation modal. */\n 'two-factor-disable': []\n /** 2FA recovery-codes regenerate. */\n 'two-factor-regenerate': []\n /** Save profile fields. */\n save: [payload: { name: string; email: string; locale: string; theme: string }]\n}>()\n\nconst auth = useAuthStore()\nconst theme = useThemeStore()\nconst locale = useLocaleStore()\n\nconst navItems = [\n { id: 'general', label: 'Основное', icon: 'user' },\n { id: 'security', label: 'Безопасность', icon: 'shield' },\n { id: 'tokens', label: 'API токены', icon: 'key' },\n { id: 'sessions', label: 'Сессии', icon: 'monitor' },\n]\n\nconst localSection = ref(props.section)\nfunction selectSection(id: string): void {\n localSection.value = id\n emit('update:section', id)\n}\n\n// Form-state для general-tab.\nconst profile = ref({\n name: auth.user?.name ?? '',\n email: auth.user?.email ?? '',\n locale: locale.current,\n theme: theme.current,\n})\n\nconst localeOptions = computed(() =>\n locale.available.map((l) => ({ value: l, label: l.toUpperCase() })),\n)\nconst themeOptions = computed(() =>\n theme.available.map((t) => ({ value: t, label: t === 'dark' ? 'Тёмная' : t === 'light' ? 'Светлая' : t })),\n)\n\nfunction onSave(): void {\n emit('save', { ...profile.value })\n}\n\nfunction onAvatarReplace(): void {\n emit('avatar-replace')\n}\n\nfunction on2FADisable(): void {\n emit('two-factor-disable')\n}\n\nfunction on2FARegenerate(): void {\n emit('two-factor-regenerate')\n}\n\nconst has2FA = computed(() => Boolean(auth.user?.twoFactorEnabled))\n</script>\n\n<template>\n <section class=\"admin-page admin-profile\">\n <header class=\"admin-page__hd\">\n <div class=\"admin-page__title-wrap\">\n <h1 class=\"admin-page__title\">{{ title }}</h1>\n <div class=\"admin-page__count\">{{ subtitle }}</div>\n </div>\n </header>\n\n <div class=\"admin-profile__layout\">\n <nav class=\"admin-profile__nav\" aria-label=\"Profile sections\">\n <button\n v-for=\"item in navItems\"\n :key=\"item.id\"\n type=\"button\"\n :class=\"[\n 'admin-profile__nav-item',\n { 'admin-profile__nav-item--active': localSection === item.id },\n ]\"\n @click=\"selectSection(item.id)\"\n >\n <span class=\"admin-profile__nav-icon\" :data-icon=\"item.icon\" />\n <span>{{ item.label }}</span>\n </button>\n </nav>\n\n <div class=\"admin-profile__content\">\n <!-- General -->\n <UidCard v-if=\"localSection === 'general'\" padding=\"md\">\n <header class=\"admin-profile__card-hd\">\n <h3 class=\"admin-profile__card-title\">Профиль</h3>\n </header>\n\n <div class=\"admin-profile__hero\">\n <UidAvatar\n :src=\"auth.user?.avatar ?? undefined\"\n :name=\"auth.user?.name ?? '?'\"\n size=\"lg\"\n />\n <div class=\"admin-profile__hero-text\">\n <div class=\"admin-profile__hero-name\">{{ auth.user?.name ?? '—' }}</div>\n <div class=\"admin-profile__hero-meta\">\n {{ auth.user?.email ?? '—' }}\n </div>\n </div>\n <div style=\"flex:1\" />\n <UidButton variant=\"ghost\" size=\"sm\" @click=\"onAvatarReplace\">\n Заменить\n </UidButton>\n </div>\n\n <div class=\"admin-profile__form\">\n <UidInput\n v-model=\"profile.name\"\n label=\"Имя\"\n name=\"name\"\n />\n <UidInput\n v-model=\"profile.email\"\n label=\"Email\"\n type=\"email\"\n name=\"email\"\n />\n <UidSelect\n v-model=\"profile.locale\"\n :options=\"localeOptions\"\n label=\"Язык\"\n />\n <UidSelect\n v-model=\"profile.theme\"\n :options=\"themeOptions\"\n label=\"Тема\"\n />\n </div>\n\n <footer class=\"admin-profile__card-ft\">\n <UidButton variant=\"primary\" @click=\"onSave\">Сохранить</UidButton>\n </footer>\n </UidCard>\n\n <!-- Security -->\n <UidCard v-else-if=\"localSection === 'security'\" padding=\"md\">\n <header class=\"admin-profile__card-hd\">\n <h3 class=\"admin-profile__card-title\">Двухфакторная аутентификация</h3>\n <UidBadge :variant=\"has2FA ? 'success' : 'default'\">\n {{ has2FA ? 'Включена' : 'Отключена' }}\n </UidBadge>\n </header>\n\n <p v-if=\"has2FA\" class=\"admin-profile__hint\">\n 2FA включена. У вас остались recovery-коды на случай потери устройства.\n </p>\n <p v-else class=\"admin-profile__hint\">\n Включите 2FA для дополнительной защиты аккаунта.\n </p>\n\n <footer class=\"admin-profile__card-ft\">\n <template v-if=\"has2FA\">\n <UidButton variant=\"ghost\" size=\"sm\" @click=\"on2FARegenerate\">\n Перегенерировать коды\n </UidButton>\n <UidButton variant=\"danger\" size=\"sm\" @click=\"on2FADisable\">\n Отключить 2FA\n </UidButton>\n </template>\n <template v-else>\n <slot name=\"enable-2fa\">\n <UidButton variant=\"primary\" disabled>\n Включить 2FA (host customize)\n </UidButton>\n </slot>\n </template>\n </footer>\n </UidCard>\n\n <!-- Tokens / Sessions / другое — host рендерит через slot -->\n <slot v-else :name=\"localSection\" :section=\"localSection\">\n <UidCard padding=\"md\">\n <p class=\"admin-profile__hint\">\n Section «{{ localSection }}» не реализована библиотекой —\n host-проект подключает её через slot {{ localSection }}.\n </p>\n </UidCard>\n </slot>\n </div>\n </div>\n </section>\n</template>\n\n<style>\n.admin-profile__layout {\n display: grid;\n grid-template-columns: 200px 1fr;\n gap: var(--uid-space-lg);\n align-items: start;\n}\n.admin-profile__nav {\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n.admin-profile__nav-item {\n appearance: none;\n border: 0;\n background: transparent;\n text-align: left;\n display: flex;\n align-items: center;\n gap: var(--uid-space-sm);\n padding: var(--uid-space-sm) var(--uid-space-sm);\n border-radius: var(--uid-radius-md);\n font-size: 13px;\n color: var(--uid-text-secondary);\n cursor: pointer;\n}\n.admin-profile__nav-item:hover {\n background: var(--uid-surface-hover);\n color: var(--uid-text-primary);\n}\n.admin-profile__nav-item--active {\n background: var(--uid-surface-base);\n color: var(--uid-text-primary);\n font-weight: var(--uid-font-weight-medium);\n}\n.admin-profile__nav-icon {\n width: 14px;\n height: 14px;\n flex: none;\n}\n.admin-profile__content {\n display: flex;\n flex-direction: column;\n gap: var(--uid-space-md);\n}\n\n.admin-profile__card-hd {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: var(--uid-space-md);\n}\n.admin-profile__card-title {\n margin: 0;\n font-size: var(--uid-font-size-sm);\n font-weight: var(--uid-font-weight-semibold);\n}\n.admin-profile__card-ft {\n margin-top: var(--uid-space-md);\n display: flex;\n gap: var(--uid-space-sm);\n}\n.admin-profile__hint {\n margin: 0;\n font-size: var(--uid-font-size-sm);\n color: var(--uid-text-secondary);\n}\n\n.admin-profile__hero {\n display: flex;\n align-items: center;\n gap: var(--uid-space-md);\n margin-bottom: var(--uid-space-md);\n}\n.admin-profile__hero-text { display: flex; flex-direction: column; gap: 4px; }\n.admin-profile__hero-name {\n font-weight: var(--uid-font-weight-semibold);\n color: var(--uid-text-primary);\n}\n.admin-profile__hero-meta {\n font-size: var(--uid-font-size-xs);\n color: var(--uid-text-tertiary);\n}\n\n.admin-profile__form {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: var(--uid-space-md);\n}\n@media (max-width: 720px) {\n .admin-profile__form { grid-template-columns: 1fr; }\n}\n</style>\n","/**\n * Реестр dashboard widget-компонентов.\n *\n * Manifest узлы dashboard выглядят так:\n * {\n * slug: 'main',\n * label: 'Главный',\n * widgets: [\n * { type: 'stat', name: 'total', title: 'Всего', value: 1284,\n * span: 3, trend: 12 },\n * { type: 'bar-chart', span: 8, ... },\n * { type: 'recent-table', span: 8, columns: [...], rows: [...] },\n * ]\n * }\n *\n * Host регистрирует кастомные widget'ы через `registerWidget()` /\n * `registerWidgets()` bundle.\n */\n\nimport type { Component } from 'vue'\nimport { createComponentRegistry } from '../createComponentRegistry'\n\nconst widgets = createComponentRegistry<Component>()\n\nexport const registerWidget = widgets.register\nexport const getWidget = widgets.get\nexport const hasWidget = widgets.has\nexport const listWidgets = widgets.list\nexport const clearWidgetRegistry = widgets.clear\nexport const registerWidgets = widgets.registerBundle\n","<script setup lang=\"ts\">\nimport { UidAlert } from '@dskripchenko/ui'\n\ninterface Props {\n type: string\n}\ndefineProps<Props>()\n</script>\n\n<template>\n <UidAlert variant=\"warning\">\n <template #title>Неизвестный widget-тип: {{ type }}</template>\n Зарегистрируйте через <code>registerWidget('{{ type }}', YourComponent)</code>.\n </UidAlert>\n</template>\n","<script setup lang=\"ts\">\n/**\n * Резолвит widget-компонент по `node.type` и forwards остальные props.\n */\nimport { computed } from 'vue'\nimport { getWidget } from './registry'\nimport UnknownWidget from './UnknownWidget.vue'\n\nexport interface WidgetNode extends Record<string, unknown> {\n type: string\n /** Сколько колонок занимает в 12-grid (1..12). */\n span?: number\n}\n\ninterface Props {\n node: WidgetNode\n}\nconst props = defineProps<Props>()\n\nconst component = computed(() => getWidget(props.node.type))\nconst widgetProps = computed(() => {\n const { type: _type, span: _span, ...rest } = props.node\n return rest\n})\n</script>\n\n<template>\n <component :is=\"component\" v-if=\"component\" v-bind=\"widgetProps\" />\n <UnknownWidget v-else :type=\"node.type\" />\n</template>\n","<script setup lang=\"ts\">\n/**\n * DashboardPage — 12-col grid из widget'ов по эталону handoff'а\n * (docs/design_handoff_laravel_admin/screens-secondary.jsx → Dashboard).\n *\n * Источник widget'ов:\n * - Если задан `slug` — берём dashboard из manifest.dashboards по slug\n * - Если задан `widgets` prop — рендерим переданные узлы напрямую\n *\n * Каждый widget — `{ type: 'stat', span: 3, title: '...', value: 1284 }`,\n * span — колонки в 12-grid (1..12), default 12 (full width).\n */\nimport { computed } from 'vue'\nimport { useManifestStore } from '../../stores/manifest'\nimport WidgetRenderer, { type WidgetNode } from './WidgetRenderer.vue'\n\ninterface DashboardManifest {\n slug: string\n label?: string\n description?: string | null\n widgets: WidgetNode[]\n}\n\ninterface Props {\n /** Slug dashboard'а в manifest.dashboards. */\n slug?: string\n /** Прямой override widget'ов (если slug не задан или не нашёлся). */\n widgets?: WidgetNode[]\n /** Заголовок страницы. */\n title?: string\n /** Подзаголовок (description). */\n subtitle?: string\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n slug: undefined,\n widgets: undefined,\n title: undefined,\n subtitle: undefined,\n})\n\nconst manifest = useManifestStore()\n\nconst dashboard = computed<DashboardManifest | null>(() => {\n if (!props.slug || !manifest.manifest) return null\n const dashboards = manifest.manifest.dashboards as DashboardManifest[] | undefined\n return dashboards?.find((d) => d.slug === props.slug) ?? null\n})\n\nconst resolvedWidgets = computed<WidgetNode[]>(() => {\n if (props.widgets) return props.widgets\n if (dashboard.value) return dashboard.value.widgets ?? []\n return []\n})\n\nconst resolvedTitle = computed(\n () => props.title ?? dashboard.value?.label ?? 'Dashboard',\n)\nconst resolvedSubtitle = computed(\n () => props.subtitle ?? dashboard.value?.description ?? null,\n)\n\nfunction spanFor(w: WidgetNode): number {\n const s = typeof w.span === 'number' ? w.span : 12\n return Math.max(1, Math.min(12, s))\n}\n</script>\n\n<template>\n <section class=\"admin-page admin-dashboard\">\n <header class=\"admin-page__hd\">\n <div class=\"admin-page__title-wrap\">\n <h1 class=\"admin-page__title\">{{ resolvedTitle }}</h1>\n <div v-if=\"resolvedSubtitle\" class=\"admin-page__count\">\n {{ resolvedSubtitle }}\n </div>\n </div>\n <div class=\"admin-page__actions\">\n <slot name=\"actions\" />\n </div>\n </header>\n\n <div class=\"admin-dashboard__grid\">\n <div\n v-for=\"(w, idx) in resolvedWidgets\"\n :key=\"idx\"\n class=\"admin-dashboard__cell\"\n :style=\"{ gridColumn: `span ${spanFor(w)} / span ${spanFor(w)}` }\"\n >\n <WidgetRenderer :node=\"w\" />\n </div>\n </div>\n </section>\n</template>\n\n<style>\n.admin-dashboard__grid {\n display: grid;\n grid-template-columns: repeat(12, minmax(0, 1fr));\n gap: var(--uid-space-md);\n}\n.admin-dashboard__cell {\n min-width: 0;\n}\n</style>\n","<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport { UidStat } from '@dskripchenko/ui'\nimport type { StatTone } from '@dskripchenko/ui'\n\ntype SemanticTone = 'neutral' | 'positive' | 'negative' | 'warning' | 'info'\n\ninterface Props {\n title?: string\n value?: number | string\n prefix?: string\n suffix?: string\n trend?: number\n precision?: number\n tone?: SemanticTone\n loading?: boolean\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n title: '',\n value: 0,\n prefix: '',\n suffix: '',\n trend: undefined,\n precision: 0,\n tone: 'neutral',\n loading: false,\n})\n\nconst TONE_MAP: Record<SemanticTone, StatTone> = {\n neutral: 'primary',\n positive: 'success',\n negative: 'danger',\n warning: 'warning',\n info: 'info',\n}\n\nconst uidTone = computed<StatTone>(() => TONE_MAP[props.tone])\n</script>\n\n<template>\n <UidStat\n :title=\"title\"\n :value=\"value\"\n :prefix=\"prefix\"\n :suffix=\"suffix\"\n :trend=\"trend\"\n :precision=\"precision\"\n :tone=\"uidTone\"\n :loading=\"loading\"\n />\n</template>\n","<script setup lang=\"ts\">\n/**\n * BarChartWidget — простой SVG-bar chart без внешних зависимостей.\n *\n * Manifest:\n * { type: 'bar-chart', title: '30 дней',\n * data: [{ label: '01', value: 12 }, ...],\n * accent: 'var(--uid-accent)' }\n */\nimport { computed } from 'vue'\nimport { UidCard } from '@dskripchenko/ui'\n\ninterface Datum {\n label: string\n value: number\n}\n\ninterface Props {\n title?: string\n description?: string\n data: Datum[]\n accent?: string\n height?: number\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n title: '',\n description: '',\n accent: 'var(--uid-accent)',\n height: 200,\n})\n\nconst maxValue = computed(() => Math.max(1, ...props.data.map((d) => d.value)))\n\nconst bars = computed(() => {\n const n = Math.max(1, props.data.length)\n const barWidth = 100 / n\n return props.data.map((d, i) => ({\n label: d.label,\n value: d.value,\n x: i * barWidth + barWidth * 0.1,\n width: barWidth * 0.8,\n heightPct: (d.value / maxValue.value) * 100,\n }))\n})\n</script>\n\n<template>\n <UidCard padding=\"md\" class=\"admin-widget\">\n <header v-if=\"title || description\" class=\"admin-widget__hd\">\n <h3 v-if=\"title\" class=\"admin-widget__title\">{{ title }}</h3>\n <p v-if=\"description\" class=\"admin-widget__desc\">{{ description }}</p>\n </header>\n <svg\n class=\"admin-widget-bar-chart\"\n :viewBox=\"`0 0 100 ${height}`\"\n preserveAspectRatio=\"none\"\n :height=\"height\"\n width=\"100%\"\n role=\"img\"\n :aria-label=\"title || 'Bar chart'\"\n >\n <rect\n v-for=\"(bar, idx) in bars\"\n :key=\"idx\"\n :x=\"bar.x\"\n :y=\"height - (bar.heightPct / 100) * height\"\n :width=\"bar.width\"\n :height=\"(bar.heightPct / 100) * height\"\n :fill=\"accent\"\n rx=\"1\"\n :data-label=\"bar.label\"\n :data-value=\"bar.value\"\n >\n <title>{{ bar.label }}: {{ bar.value }}</title>\n </rect>\n </svg>\n </UidCard>\n</template>\n\n<style>\n.admin-widget__hd { margin-bottom: var(--uid-space-sm); }\n.admin-widget__title {\n margin: 0;\n font-size: var(--uid-font-size-sm);\n font-weight: var(--uid-font-weight-semibold);\n color: var(--uid-text-primary);\n}\n.admin-widget__desc {\n margin: var(--uid-space-2xs) 0 0;\n font-size: var(--uid-font-size-xs);\n color: var(--uid-text-tertiary);\n}\n.admin-widget-bar-chart {\n display: block;\n width: 100%;\n}\n</style>\n","<script setup lang=\"ts\">\n/**\n * DonutChartWidget — SVG donut + legend.\n *\n * Manifest:\n * { type: 'donut-chart', title: 'Status',\n * data: [{ label: 'Published', value: 156, color: '...' }, ...] }\n */\nimport { computed } from 'vue'\nimport { UidCard } from '@dskripchenko/ui'\n\ninterface Slice {\n label: string\n value: number\n color?: string\n}\n\ninterface Props {\n title?: string\n data: Slice[]\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n title: '',\n})\n\nconst PALETTE = [\n 'var(--uid-color-teal-500, #14b8a6)',\n 'var(--uid-color-zinc-700, #3f3f46)',\n 'var(--uid-color-amber-400, #fbbf24)',\n 'var(--uid-color-rose-400, #fb7185)',\n 'var(--uid-color-blue-400, #60a5fa)',\n]\n\nconst total = computed(() => props.data.reduce((s, x) => s + x.value, 0) || 1)\n\nconst slices = computed(() => {\n let cumulative = 0\n return props.data.map((s, idx) => {\n const startAngle = (cumulative / total.value) * 2 * Math.PI\n cumulative += s.value\n const endAngle = (cumulative / total.value) * 2 * Math.PI\n\n const r = 50\n const cx = 60\n const cy = 60\n\n const x1 = cx + r * Math.cos(startAngle - Math.PI / 2)\n const y1 = cy + r * Math.sin(startAngle - Math.PI / 2)\n const x2 = cx + r * Math.cos(endAngle - Math.PI / 2)\n const y2 = cy + r * Math.sin(endAngle - Math.PI / 2)\n\n const largeArc = endAngle - startAngle > Math.PI ? 1 : 0\n\n const path = props.data.length === 1\n ? `M ${cx - r} ${cy} a ${r} ${r} 0 1 0 ${r * 2} 0 a ${r} ${r} 0 1 0 ${-r * 2} 0`\n : `M ${cx} ${cy} L ${x1} ${y1} A ${r} ${r} 0 ${largeArc} 1 ${x2} ${y2} Z`\n\n return {\n ...s,\n path,\n color: s.color ?? PALETTE[idx % PALETTE.length],\n pct: ((s.value / total.value) * 100).toFixed(1),\n }\n })\n})\n</script>\n\n<template>\n <UidCard padding=\"md\" class=\"admin-widget admin-donut-widget\">\n <header v-if=\"title\" class=\"admin-widget__hd\">\n <h3 class=\"admin-widget__title\">{{ title }}</h3>\n </header>\n <div class=\"admin-donut-widget__row\">\n <svg viewBox=\"0 0 120 120\" class=\"admin-donut-widget__svg\" role=\"img\" :aria-label=\"title\">\n <path\n v-for=\"(s, idx) in slices\"\n :key=\"idx\"\n :d=\"s.path\"\n :fill=\"s.color\"\n >\n <title>{{ s.label }}: {{ s.value }} ({{ s.pct }}%)</title>\n </path>\n <circle cx=\"60\" cy=\"60\" r=\"30\" fill=\"var(--uid-surface-raised)\" />\n </svg>\n <ul class=\"admin-donut-widget__legend\">\n <li v-for=\"(s, idx) in slices\" :key=\"idx\">\n <span class=\"admin-donut-widget__dot\" :style=\"{ background: s.color }\" />\n <span class=\"admin-donut-widget__label\">{{ s.label }}</span>\n <span class=\"admin-donut-widget__value\">{{ s.pct }}%</span>\n </li>\n </ul>\n </div>\n </UidCard>\n</template>\n\n<style>\n.admin-donut-widget__row {\n display: flex;\n align-items: center;\n gap: var(--uid-space-md);\n}\n.admin-donut-widget__svg {\n width: 120px;\n height: 120px;\n flex: none;\n}\n.admin-donut-widget__legend {\n list-style: none;\n margin: 0;\n padding: 0;\n flex: 1;\n display: flex;\n flex-direction: column;\n gap: var(--uid-space-xs);\n}\n.admin-donut-widget__legend li {\n display: flex;\n align-items: center;\n gap: var(--uid-space-sm);\n font-size: var(--uid-font-size-xs);\n}\n.admin-donut-widget__dot {\n width: 10px;\n height: 10px;\n border-radius: var(--uid-radius-full);\n flex: none;\n}\n.admin-donut-widget__label { flex: 1; color: var(--uid-text-primary); }\n.admin-donut-widget__value {\n color: var(--uid-text-tertiary);\n font-variant-numeric: tabular-nums;\n}\n</style>\n","<script setup lang=\"ts\">\nimport { UidCard, UidTable, type UidTableColumn } from '@dskripchenko/ui'\n\ninterface Props {\n title?: string\n columns: UidTableColumn[]\n rows: Record<string, unknown>[]\n emptyText?: string\n}\n\nwithDefaults(defineProps<Props>(), {\n title: '',\n emptyText: 'Нет данных',\n})\n</script>\n\n<template>\n <UidCard padding=\"md\" class=\"admin-widget\">\n <header v-if=\"title\" class=\"admin-widget__hd\">\n <h3 class=\"admin-widget__title\">{{ title }}</h3>\n </header>\n <UidTable :columns=\"columns\" :data=\"rows\" :empty-text=\"emptyText\" />\n </UidCard>\n</template>\n","<script setup lang=\"ts\">\nimport { UidCard, UidHeatmap } from '@dskripchenko/ui'\n\ninterface HeatmapPoint {\n date: string\n value: number\n}\n\ninterface Props {\n title?: string\n data: HeatmapPoint[]\n levels?: number\n color?: string\n gap?: number\n}\n\nwithDefaults(defineProps<Props>(), {\n title: '',\n levels: 5,\n color: undefined,\n gap: 2,\n})\n</script>\n\n<template>\n <UidCard padding=\"md\" class=\"admin-widget\">\n <header v-if=\"title\" class=\"admin-widget__hd\">\n <h3 class=\"admin-widget__title\">{{ title }}</h3>\n </header>\n <UidHeatmap :data=\"data\" :levels=\"levels\" :color=\"color\" :gap=\"gap\" />\n </UidCard>\n</template>\n","<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport { UidCard, UidGauge } from '@dskripchenko/ui'\nimport type { GaugeTone, GaugeRange } from '@dskripchenko/ui'\n\ntype SemanticTone = 'neutral' | 'positive' | 'warning' | 'negative'\n\ninterface Props {\n title?: string\n value?: number\n min?: number\n max?: number\n size?: number\n ranges?: GaugeRange[]\n tone?: SemanticTone\n color?: string\n label?: string\n suffix?: string\n precision?: number\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n title: '',\n value: 0,\n min: 0,\n max: 100,\n size: 160,\n ranges: () => [],\n tone: 'neutral',\n color: undefined,\n label: '',\n suffix: '',\n precision: 0,\n})\n\nconst TONE_MAP: Record<SemanticTone, GaugeTone> = {\n neutral: 'primary',\n positive: 'success',\n warning: 'warning',\n negative: 'danger',\n}\n\nconst uidTone = computed<GaugeTone>(() => TONE_MAP[props.tone])\n</script>\n\n<template>\n <UidCard padding=\"md\" class=\"admin-widget\">\n <header v-if=\"title\" class=\"admin-widget__hd\">\n <h3 class=\"admin-widget__title\">{{ title }}</h3>\n </header>\n <div style=\"display:flex; justify-content:center;\">\n <UidGauge\n :value=\"value\"\n :min=\"min\"\n :max=\"max\"\n :size=\"size\"\n :ranges=\"ranges\"\n :tone=\"uidTone\"\n :color=\"color\"\n :label=\"label\"\n :suffix=\"suffix\"\n :precision=\"precision\"\n />\n </div>\n </UidCard>\n</template>\n","<script setup lang=\"ts\">\n/**\n * Markdown widget — простой preformatted-блок. Для production хост может\n * подкинуть свой widget с marked/MDX через registerWidget('markdown', ...).\n *\n * Тут — fallback с базовым форматированием через line-break preserve.\n */\nimport { UidCard } from '@dskripchenko/ui'\n\ninterface Props {\n title?: string\n content: string\n}\n\nwithDefaults(defineProps<Props>(), { title: '' })\n</script>\n\n<template>\n <UidCard padding=\"md\" class=\"admin-widget\">\n <header v-if=\"title\" class=\"admin-widget__hd\">\n <h3 class=\"admin-widget__title\">{{ title }}</h3>\n </header>\n <div class=\"admin-markdown-widget\">{{ content }}</div>\n </UidCard>\n</template>\n\n<style>\n.admin-markdown-widget {\n font-size: var(--uid-font-size-sm);\n color: var(--uid-text-secondary);\n white-space: pre-wrap;\n line-height: var(--uid-line-height-normal);\n}\n</style>\n","/**\n * Default-bundle с минимальным набором builtin widget-типов.\n */\n\nimport { registerWidgets } from './registry'\nimport StatWidget from './StatWidget.vue'\nimport BarChartWidget from './BarChartWidget.vue'\nimport DonutChartWidget from './DonutChartWidget.vue'\nimport RecentTableWidget from './RecentTableWidget.vue'\nimport HeatmapWidget from './HeatmapWidget.vue'\nimport GaugeWidget from './GaugeWidget.vue'\nimport MarkdownWidget from './MarkdownWidget.vue'\n\nexport function registerBuiltinWidgets(): void {\n registerWidgets({\n stat: StatWidget,\n 'bar-chart': BarChartWidget,\n 'donut-chart': DonutChartWidget,\n 'recent-table': RecentTableWidget,\n heatmap: HeatmapWidget,\n gauge: GaugeWidget,\n markdown: MarkdownWidget,\n })\n}\n","/**\n * Контракт ответов laravel-api: каждое тело — `{success, payload}`.\n *\n * Success: `{success: true, payload: {...}}`\n * Error: `{success: false, payload: {errorKey, message, ...}}`\n *\n * Helper'ы здесь — для type-narrowing'а в потребителях.\n */\n\nexport interface SuccessEnvelope<T = unknown> {\n success: true\n payload: T\n}\n\nexport interface ErrorEnvelope {\n success: false\n payload: {\n errorKey: string\n message: string\n messages?: Record<string, string[]>\n [key: string]: unknown\n }\n}\n\nexport type ApiEnvelope<T = unknown> = SuccessEnvelope<T> | ErrorEnvelope\n\nexport function isSuccess<T>(env: ApiEnvelope<T>): env is SuccessEnvelope<T> {\n return env.success === true\n}\n\nexport function isError(env: ApiEnvelope): env is ErrorEnvelope {\n return env.success === false\n}\n","/**\n * Axios-клиент для admin API.\n *\n * Особенности:\n * - baseURL берётся из bootstrap.apiUrl (либо передаётся явно).\n * - X-XSRF-TOKEN добавляется автоматически из cookie (Laravel Sanctum/web).\n * - X-CSRF-TOKEN — fallback из meta[name=csrf-token] (Blade-injection).\n * - X-Admin-Locale выставляется при наличии текущей локали.\n * - Response interceptor разворачивает envelope и бросает ApiError.\n * - 401 → onUnauthenticated callback (редирект на login на стороне consumer'а).\n */\n\nimport axios, { AxiosError, type AxiosInstance, type AxiosRequestConfig } from 'axios'\nimport { isSuccess, type ApiEnvelope, type ErrorEnvelope } from './envelope'\nimport { NetworkError, toApiError, UnauthenticatedError } from './errors'\n\nexport interface ClientOptions {\n baseURL: string\n csrfToken?: string\n locale?: string\n /** Вызывается при 401. Обычно — push на /admin/login. */\n onUnauthenticated?: () => void\n}\n\nexport interface AdminClient {\n /** Низкоуровневый axios — для специфичных случаев. */\n raw: AxiosInstance\n get<T = unknown>(url: string, config?: AxiosRequestConfig): Promise<T>\n post<T = unknown>(url: string, data?: unknown, config?: AxiosRequestConfig): Promise<T>\n put<T = unknown>(url: string, data?: unknown, config?: AxiosRequestConfig): Promise<T>\n patch<T = unknown>(url: string, data?: unknown, config?: AxiosRequestConfig): Promise<T>\n delete<T = unknown>(url: string, config?: AxiosRequestConfig): Promise<T>\n setLocale(locale: string): void\n}\n\nexport function createAdminClient(opts: ClientOptions): AdminClient {\n const instance = axios.create({\n baseURL: opts.baseURL,\n withCredentials: true,\n headers: {\n Accept: 'application/json',\n 'X-Requested-With': 'XMLHttpRequest',\n },\n })\n\n if (opts.csrfToken) {\n instance.defaults.headers.common['X-CSRF-TOKEN'] = opts.csrfToken\n }\n if (opts.locale) {\n instance.defaults.headers.common['X-Admin-Locale'] = opts.locale\n }\n\n // Подцепляем XSRF из cookie на каждый запрос — браузер сам обновит\n // его после первого 419, но axios reads на вызове.\n instance.interceptors.request.use((config) => {\n const xsrf = readCookie('XSRF-TOKEN')\n if (xsrf) {\n config.headers.set('X-XSRF-TOKEN', decodeURIComponent(xsrf))\n }\n return config\n })\n\n // Response interceptor — разворачиваем envelope, бросаем правильную ошибку.\n instance.interceptors.response.use(\n (response) => {\n const env = response.data as ApiEnvelope\n if (env && typeof env === 'object' && 'success' in env) {\n if (isSuccess(env)) {\n // payload подменяет data — теперь callers получают чистый payload.\n response.data = env.payload\n return response\n }\n // success: false → throw как ApiError\n throw toApiError(response.status, env.payload)\n }\n // Не envelope (например, бинарный stream) — пропускаем как есть.\n return response\n },\n (error: AxiosError<ErrorEnvelope>) => {\n if (error.response) {\n const status = error.response.status\n const payload =\n error.response.data?.payload ?? {\n errorKey: 'unknown',\n message: error.message,\n }\n const apiError = toApiError(status, payload)\n if (apiError instanceof UnauthenticatedError) {\n opts.onUnauthenticated?.()\n }\n return Promise.reject(apiError)\n }\n // network failure / timeout\n return Promise.reject(new NetworkError(error.message))\n },\n )\n\n const wrap = <T>(method: 'get' | 'delete', url: string, config?: AxiosRequestConfig): Promise<T> =>\n instance[method]<unknown, { data: T }>(url, config).then((r) => r.data)\n\n const wrapBody = <T>(\n method: 'post' | 'put' | 'patch',\n url: string,\n data?: unknown,\n config?: AxiosRequestConfig,\n ): Promise<T> => instance[method]<unknown, { data: T }>(url, data, config).then((r) => r.data)\n\n return {\n raw: instance,\n get: <T>(url: string, config?: AxiosRequestConfig) => wrap<T>('get', url, config),\n delete: <T>(url: string, config?: AxiosRequestConfig) => wrap<T>('delete', url, config),\n post: <T>(url: string, data?: unknown, config?: AxiosRequestConfig) =>\n wrapBody<T>('post', url, data, config),\n put: <T>(url: string, data?: unknown, config?: AxiosRequestConfig) =>\n wrapBody<T>('put', url, data, config),\n patch: <T>(url: string, data?: unknown, config?: AxiosRequestConfig) =>\n wrapBody<T>('patch', url, data, config),\n setLocale: (locale: string): void => {\n instance.defaults.headers.common['X-Admin-Locale'] = locale\n },\n }\n}\n\n/** Читает cookie из document.cookie. Returns null если нет. */\nfunction readCookie(name: string): string | null {\n if (typeof document === 'undefined') return null\n const match = document.cookie.match(new RegExp('(^|; )' + escapeRegex(name) + '=([^;]*)'))\n return match ? match[2] : null\n}\n\nfunction escapeRegex(s: string): string {\n return s.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n}\n","/**\n * buildRoutesFromManifest — превращает AdminManifest в массив RouteRecordRaw.\n *\n * Маппинг:\n * - resource{slug} → /r/{slug} (index)\n * /r/{slug}/create (create)\n * /r/{slug}/:id/edit (edit)\n * /r/{slug}/:id (view, опционально)\n * - screen{slug} → /screens/{slug}\n * - settings{slug} → /settings/{slug}\n * - dashboard{slug} → /dashboard/{slug}\n *\n * Component'ы передаются через resolver — host-проект решает, что отрисовать.\n * Это позволяет library не тащить рендереры внутрь себя жёстко.\n */\n\nimport type { RouteRecordRaw } from 'vue-router'\nimport type { Component } from 'vue'\nimport type {\n AdminManifest,\n ManifestResourceMeta,\n ManifestScreenMeta,\n ManifestSettingsMeta,\n} from '../stores/manifest'\n\n/** Vue Component либо async-loader (для code-splitting). */\nexport type AdminRouteComponent = Component | (() => Promise<Component>)\n\nexport interface RouteMeta {\n /** Требует залогиненного пользователя. */\n requiresAuth?: boolean\n /** Permissions, нужные для входа. ANY-логика (хотя бы одно совпадение). */\n permissions?: string[]\n /** Заголовок страницы (рендерим в <title> через router.afterEach). */\n title?: string\n /** Тип админ-роута — для UI breadcrumbs/active-state. */\n kind?: 'resource' | 'screen' | 'settings' | 'dashboard' | 'system' | 'auth'\n /** Slug сущности из манифеста — для извлечения мета внутри компонента. */\n slug?: string\n}\n\ndeclare module 'vue-router' {\n // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n interface RouteMeta extends Record<string, unknown> {}\n}\n\n/**\n * Resolver компонентов для динамических роутов.\n *\n * Host-проект передаёт конкретные Vue-компоненты для каждой роли.\n * Library не зависит от конкретных view'ов.\n */\nexport interface RouteComponentResolver {\n resourceIndex: AdminRouteComponent\n resourceCreate: AdminRouteComponent\n resourceEdit: AdminRouteComponent\n resourceView: AdminRouteComponent\n screen: AdminRouteComponent\n settings: AdminRouteComponent\n dashboard: AdminRouteComponent\n}\n\n/**\n * Извлекает permissions из meta'ы ресурса / скрина / settings'а.\n *\n * resource.permissions = { view: 'admin.users.view', ... } → ['admin.users.view']\n * (для index используется view; для create/edit — соответственно).\n */\nfunction pickResourcePermission(\n resource: ManifestResourceMeta,\n ability: 'view' | 'create' | 'update',\n): string[] {\n const perm = resource.permissions?.[ability]\n return typeof perm === 'string' && perm.length > 0 ? [perm] : []\n}\n\nfunction pickSettingsPermission(s: ManifestSettingsMeta, ability: 'view' | 'update'): string[] {\n const perm = s.permissions?.[ability]\n return typeof perm === 'string' && perm.length > 0 ? [perm] : []\n}\n\nfunction pickScreenPermission(s: ManifestScreenMeta): string[] {\n if (Array.isArray(s.permission)) return s.permission\n if (typeof s.permission === 'string' && s.permission.length > 0) return [s.permission]\n return []\n}\n\nfunction buildResourceRoutes(\n resource: ManifestResourceMeta,\n components: RouteComponentResolver,\n): RouteRecordRaw[] {\n const slug = resource.slug\n const base = `/r/${slug}`\n\n return [\n {\n path: base,\n name: `admin.resource.${slug}.index`,\n component: components.resourceIndex,\n meta: {\n requiresAuth: true,\n kind: 'resource',\n slug,\n title: resource.label,\n permissions: pickResourcePermission(resource, 'view'),\n },\n // slug передаётся в page-component'ы как prop. Конкретный slug запекаем в\n // function-mode, чтобы page видел его одинаково и через named-route, и через\n // path-routing (без params).\n props: { slug },\n },\n {\n path: `${base}/create`,\n name: `admin.resource.${slug}.create`,\n component: components.resourceCreate,\n meta: {\n requiresAuth: true,\n kind: 'resource',\n slug,\n title: `${resource.label}: создать`,\n permissions: pickResourcePermission(resource, 'create'),\n },\n props: { slug },\n },\n {\n path: `${base}/:id/edit`,\n name: `admin.resource.${slug}.edit`,\n component: components.resourceEdit,\n meta: {\n requiresAuth: true,\n kind: 'resource',\n slug,\n title: `${resource.label}: редактирование`,\n permissions: pickResourcePermission(resource, 'update'),\n },\n // slug запекаем, id из route-params.\n props: (route) => ({ slug, id: route.params.id }),\n },\n {\n path: `${base}/:id`,\n name: `admin.resource.${slug}.view`,\n component: components.resourceView,\n meta: {\n requiresAuth: true,\n kind: 'resource',\n slug,\n title: resource.label,\n permissions: pickResourcePermission(resource, 'view'),\n },\n props: (route) => ({ slug, id: route.params.id }),\n },\n ]\n}\n\nfunction buildScreenRoute(\n screen: ManifestScreenMeta,\n components: RouteComponentResolver,\n): RouteRecordRaw {\n return {\n path: `/screens/${screen.slug}`,\n name: `admin.screen.${screen.slug}`,\n component: components.screen,\n meta: {\n requiresAuth: true,\n kind: 'screen',\n slug: screen.slug,\n title: screen.name,\n permissions: pickScreenPermission(screen),\n },\n }\n}\n\nfunction buildSettingsRoute(\n settings: ManifestSettingsMeta,\n components: RouteComponentResolver,\n): RouteRecordRaw {\n return {\n path: `/settings/${settings.slug}`,\n name: `admin.settings.${settings.slug}`,\n component: components.settings,\n meta: {\n requiresAuth: true,\n kind: 'settings',\n slug: settings.slug,\n title: settings.label,\n permissions: pickSettingsPermission(settings, 'view'),\n },\n }\n}\n\ninterface DashboardMeta {\n slug?: string\n label?: string\n permission?: string | string[] | null\n}\n\nfunction buildDashboardRoute(\n dashboard: DashboardMeta,\n components: RouteComponentResolver,\n): RouteRecordRaw | null {\n if (typeof dashboard.slug !== 'string' || dashboard.slug.length === 0) return null\n const permission = dashboard.permission\n const permissions = Array.isArray(permission)\n ? permission\n : typeof permission === 'string' && permission.length > 0\n ? [permission]\n : []\n return {\n path: `/dashboard/${dashboard.slug}`,\n name: `admin.dashboard.${dashboard.slug}`,\n component: components.dashboard,\n meta: {\n requiresAuth: true,\n kind: 'dashboard',\n slug: dashboard.slug,\n title: dashboard.label ?? 'Dashboard',\n permissions,\n },\n }\n}\n\nexport function buildRoutesFromManifest(\n manifest: AdminManifest | null,\n components: RouteComponentResolver,\n): RouteRecordRaw[] {\n if (manifest === null) return []\n\n const routes: RouteRecordRaw[] = []\n\n for (const resource of manifest.resources) {\n routes.push(...buildResourceRoutes(resource, components))\n }\n for (const screen of manifest.screens) {\n routes.push(buildScreenRoute(screen, components))\n }\n for (const s of manifest.settings) {\n routes.push(buildSettingsRoute(s, components))\n }\n for (const d of manifest.dashboards as DashboardMeta[]) {\n const route = buildDashboardRoute(d, components)\n if (route) routes.push(route)\n }\n\n return routes\n}\n","/**\n * Router-guards: auth + permissions.\n *\n * Логика:\n * 1. Если route.meta.requiresAuth и пользователь не залогинен → /login\n * с ?redirect=...\n * 2. Если у user'а есть pendingChallenge (2FA) — все защищённые роуты\n * редиректят на /login (challenge-form там).\n * 3. Если route.meta.permissions заданы — проверяем hasAnyPermission().\n * Нет ни одного → /forbidden (или роут с name='admin.forbidden').\n *\n * Guards используют useAuthStore — но НЕ берут client напрямую: всё через\n * permissions/isAuthenticated/pendingChallenge state. Stores должны быть\n * захайдрейчены до setup'а router'а.\n */\n\nimport type { RouteLocationNormalized, RouteLocationRaw } from 'vue-router'\nimport { useAuthStore } from '../stores/auth'\n\n/** Тип возвращаемого значения guard'а — true (passthrough) либо redirect-target. */\ntype GuardResult = boolean | RouteLocationRaw\n\n/**\n * Простая 3-арг функция (то что router.beforeEach принимает).\n * Не используем NavigationGuardWithThis<undefined>, т.к. она требует\n * `this: undefined` что неудобно для прямого вызова в тестах.\n */\ntype SimpleGuard = (\n to: RouteLocationNormalized,\n from: RouteLocationNormalized,\n next?: unknown,\n) => GuardResult\n\nexport interface AuthGuardOptions {\n /** Имя login-роута. По умолчанию 'admin.login'. */\n loginRouteName?: string\n /** Имя роута 403-страницы. По умолчанию 'admin.forbidden'. */\n forbiddenRouteName?: string\n /**\n * Имя query-параметра для возврата на исходную страницу после login.\n * По умолчанию 'redirect'.\n */\n redirectQueryKey?: string\n}\n\n/**\n * Создаёт beforeEach guard. Pinia должна быть activeInstance к моменту\n * вызова guard'а (router.beforeEach срабатывает на каждой навигации,\n * включая первую — Pinia уже должна быть установлена).\n */\nexport function createAuthGuard(opts: AuthGuardOptions = {}): SimpleGuard {\n const loginRouteName = opts.loginRouteName ?? 'admin.login'\n const forbiddenRouteName = opts.forbiddenRouteName ?? 'admin.forbidden'\n const redirectQueryKey = opts.redirectQueryKey ?? 'redirect'\n\n return (to: RouteLocationNormalized) => {\n // Login-роут всегда доступен.\n if (to.name === loginRouteName) {\n return true\n }\n\n const auth = useAuthStore()\n const requiresAuth = to.meta?.requiresAuth === true\n\n if (requiresAuth && !auth.isAuthenticated) {\n return {\n name: loginRouteName,\n query: { [redirectQueryKey]: to.fullPath },\n }\n }\n\n // Залогиненный, но в процессе 2FA — нельзя ходить никуда кроме login.\n if (auth.isChallengePending) {\n return {\n name: loginRouteName,\n query: { [redirectQueryKey]: to.fullPath },\n }\n }\n\n // Permission-check. ANY-логика (хотя бы одно permission совпало).\n const permissionsMeta = to.meta?.permissions\n if (Array.isArray(permissionsMeta) && permissionsMeta.length > 0) {\n const allowed = auth.hasAnyPermission(permissionsMeta as string[])\n if (!allowed) {\n return { name: forbiddenRouteName }\n }\n }\n\n return true\n }\n}\n\nexport interface TitleGuardOptions {\n /** Шаблон заголовка. {title} — meta.title, {brand} — название бренда. */\n template?: string\n /** Имя бренда. */\n brand?: string\n /** Default title если в meta нет. */\n fallback?: string\n}\n\n/**\n * Создаёт afterEach hook, обновляющий document.title.\n *\n * Шаблон по умолчанию: '{title} · {brand}' если оба, иначе один из.\n */\nexport function createTitleGuard(\n opts: TitleGuardOptions = {},\n): (to: RouteLocationNormalized, from?: RouteLocationNormalized, failure?: unknown) => void {\n const template = opts.template\n const brand = opts.brand ?? ''\n const fallback = opts.fallback ?? ''\n\n return (to) => {\n if (typeof document === 'undefined') return\n const t = (to.meta?.title as string | undefined) ?? fallback\n let title: string\n if (template) {\n title = template.replace('{title}', t).replace('{brand}', brand)\n } else if (t && brand) {\n title = `${t} · ${brand}`\n } else {\n title = t || brand\n }\n document.title = title\n }\n}\n","/**\n * createAdminRouter — фабрика admin-router'а.\n *\n * Использование:\n *\n * const router = createAdminRouter({\n * base: '/admin',\n * components: { ... },\n * brand: 'My App',\n * })\n * await router.replaceManifestRoutes(manifestStore.manifest)\n * app.use(router)\n *\n * Library намеренно не делает createWebHistory выбор за host'а — host передаёт\n * объект history (createWebHistory / createWebHashHistory).\n */\n\nimport {\n createRouter,\n createWebHistory,\n type Router,\n type RouteRecordRaw,\n type RouterHistory,\n} from 'vue-router'\nimport type { AdminManifest } from '../stores/manifest'\nimport { buildRoutesFromManifest, type RouteComponentResolver, type AdminRouteComponent } from './builder'\nimport { createAuthGuard, createTitleGuard, type AuthGuardOptions, type TitleGuardOptions } from './guards'\n\nexport interface AdminRouterOptions {\n /** Base URL admin-панели. По умолчанию '/admin'. */\n base?: string\n /** History-implementation. По умолчанию createWebHistory(base). */\n history?: RouterHistory\n /** Component resolver для resource/screen/settings/dashboard роутов. */\n components: RouteComponentResolver & {\n /** Login. */\n login: AdminRouteComponent\n /** Главная (либо overview-dashboard). */\n home: AdminRouteComponent\n /** 403 forbidden. */\n forbidden: AdminRouteComponent\n /** 404 not found. */\n notFound: AdminRouteComponent\n /** Страница профиля. */\n profile?: AdminRouteComponent\n /** Страница уведомлений. */\n notifications?: AdminRouteComponent\n }\n /** Дополнительные руты сверху динамики. */\n extraRoutes?: RouteRecordRaw[]\n /** Опции auth-guard. */\n authGuard?: AuthGuardOptions\n /** Опции title-guard. */\n titleGuard?: TitleGuardOptions\n}\n\n/**\n * Расширенный Router с возможностью пере-построить динамические роуты.\n */\nexport interface AdminRouter extends Router {\n /**\n * Пере-собрать динамические роуты из manifest'а.\n * Удаляет старые admin.resource.* / admin.screen.* / admin.settings.* / admin.dashboard.*\n * и заменяет на актуальные. Полезно при перезагрузке manifest'а.\n */\n replaceManifestRoutes(manifest: AdminManifest | null): void\n}\n\n/**\n * Префиксы dynamic-роутов которые подменяются при replaceManifestRoutes.\n */\nconst DYNAMIC_NAME_PREFIXES = [\n 'admin.resource.',\n 'admin.screen.',\n 'admin.settings.',\n 'admin.dashboard.',\n]\n\nfunction isDynamicRouteName(name: unknown): boolean {\n if (typeof name !== 'string') return false\n return DYNAMIC_NAME_PREFIXES.some((p) => name.startsWith(p))\n}\n\nexport function createAdminRouter(opts: AdminRouterOptions): AdminRouter {\n const base = opts.base ?? '/admin'\n const history = opts.history ?? createWebHistory(base)\n\n const staticRoutes: RouteRecordRaw[] = [\n {\n path: '/login',\n name: 'admin.login',\n component: opts.components.login,\n meta: { kind: 'auth', title: 'Вход' },\n },\n {\n path: '/',\n name: 'admin.home',\n component: opts.components.home,\n meta: { requiresAuth: true, kind: 'system', title: 'Главная' },\n },\n {\n path: '/forbidden',\n name: 'admin.forbidden',\n component: opts.components.forbidden,\n meta: { requiresAuth: true, kind: 'system', title: '403 — доступ запрещён' },\n },\n ]\n\n if (opts.components.profile) {\n staticRoutes.push({\n path: '/profile',\n name: 'admin.profile',\n component: opts.components.profile,\n meta: { requiresAuth: true, kind: 'system', title: 'Профиль' },\n })\n }\n\n if (opts.components.notifications) {\n staticRoutes.push({\n path: '/notifications',\n name: 'admin.notifications',\n component: opts.components.notifications,\n meta: { requiresAuth: true, kind: 'system', title: 'Уведомления' },\n })\n }\n\n // Catch-all 404 кладём в конец — vue-router matches in order и динамика\n // может быть добавлена позже через addRoute.\n const notFoundRoute: RouteRecordRaw = {\n path: '/:pathMatch(.*)*',\n name: 'admin.notFound',\n component: opts.components.notFound,\n meta: { kind: 'system', title: '404' },\n }\n\n const router = createRouter({\n history,\n routes: [...staticRoutes, ...(opts.extraRoutes ?? []), notFoundRoute],\n }) as AdminRouter\n\n router.beforeEach(createAuthGuard(opts.authGuard))\n router.afterEach(createTitleGuard(opts.titleGuard))\n\n router.replaceManifestRoutes = (manifest: AdminManifest | null): void => {\n // Удаляем все старые динамические роуты по name.\n const allRoutes = router.getRoutes()\n for (const route of allRoutes) {\n if (isDynamicRouteName(route.name)) {\n router.removeRoute(route.name as string)\n }\n }\n\n // Удаляем catch-all чтобы потом добавить его обратно последним.\n if (router.hasRoute('admin.notFound')) {\n router.removeRoute('admin.notFound')\n }\n\n const dynamic = buildRoutesFromManifest(manifest, opts.components)\n for (const route of dynamic) {\n router.addRoute(route)\n }\n router.addRoute(notFoundRoute)\n }\n\n return router\n}\n\nexport { buildRoutesFromManifest } from './builder'\nexport type { RouteComponentResolver, RouteMeta, AdminRouteComponent } from './builder'\nexport { createAuthGuard, createTitleGuard } from './guards'\nexport type { AuthGuardOptions, TitleGuardOptions } from './guards'\n","<script setup lang=\"ts\">\n/**\n * TextField — wrapper над UidInput из @dskripchenko/ui. Двусторонняя связь\n * с form-state через provideFormState/useFormState. Тип input'а (text/email/\n * url/password/tel/search) пробрасывается как `type`.\n */\nimport { computed } from 'vue'\nimport { UidInput } from '@dskripchenko/ui'\nimport { useFormState } from '../render/formState'\n\ninterface Props {\n name: string\n label?: string | null\n help?: string | null\n required?: boolean\n placeholder?: string | null\n inputType?: 'text' | 'email' | 'url' | 'password' | 'tel' | 'search'\n disabled?: boolean\n readonly?: boolean\n autocomplete?: string | null\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n label: null,\n help: null,\n placeholder: null,\n inputType: 'text',\n required: false,\n disabled: false,\n readonly: false,\n autocomplete: null,\n})\n\nconst form = useFormState()\nconst value = computed<string>(() => (form.getField(props.name) as string | null | undefined) ?? '')\nconst errorMsg = computed<string | undefined>(() => form.errors[props.name]?.[0])\n\nfunction onUpdate(next: string): void {\n form.setField(props.name, next)\n}\n</script>\n\n<template>\n <UidInput\n :model-value=\"value\"\n :type=\"inputType\"\n :label=\"label ?? undefined\"\n :hint=\"help ?? undefined\"\n :error=\"errorMsg\"\n :placeholder=\"placeholder ?? undefined\"\n :required=\"required\"\n :disabled=\"disabled\"\n :readonly=\"readonly\"\n :name=\"name\"\n :autocomplete=\"autocomplete ?? undefined\"\n @update:model-value=\"onUpdate\"\n />\n</template>\n","<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport { UidTextarea, UidFormField } from '@dskripchenko/ui'\nimport { useFormState } from '../render/formState'\n\ninterface Props {\n name: string\n label?: string | null\n help?: string | null\n required?: boolean\n placeholder?: string | null\n rows?: number\n disabled?: boolean\n readonly?: boolean\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n label: null,\n help: null,\n placeholder: null,\n rows: 4,\n required: false,\n disabled: false,\n readonly: false,\n})\n\nconst form = useFormState()\nconst value = computed<string>(() => (form.getField(props.name) as string | null | undefined) ?? '')\nconst errorMsg = computed<string | undefined>(() => form.errors[props.name]?.[0])\n\nfunction onUpdate(next: string): void {\n form.setField(props.name, next)\n}\n</script>\n\n<template>\n <UidFormField\n :label=\"label ?? undefined\"\n :hint=\"help ?? undefined\"\n :error=\"errorMsg\"\n :required=\"required\"\n :disabled=\"disabled\"\n >\n <UidTextarea\n :model-value=\"value\"\n :rows=\"rows\"\n :placeholder=\"placeholder ?? undefined\"\n :disabled=\"disabled\"\n :readonly=\"readonly\"\n :name=\"name\"\n @update:model-value=\"onUpdate\"\n />\n </UidFormField>\n</template>\n","<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport { UidNumberInput, UidFormField } from '@dskripchenko/ui'\nimport { useFormState } from '../render/formState'\n\ninterface Props {\n name: string\n label?: string | null\n help?: string | null\n required?: boolean\n placeholder?: string | null\n min?: number | null\n max?: number | null\n step?: number | null\n disabled?: boolean\n readonly?: boolean\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n label: null,\n help: null,\n placeholder: null,\n min: null,\n max: null,\n step: null,\n required: false,\n disabled: false,\n readonly: false,\n})\n\nconst form = useFormState()\nconst value = computed<number | null>(() => {\n const v = form.getField(props.name)\n if (v === null || v === undefined || v === '') return null\n return typeof v === 'number' ? v : Number(v)\n})\nconst errorMsg = computed<string | undefined>(() => form.errors[props.name]?.[0])\n\nfunction onUpdate(next: number | null): void {\n form.setField(props.name, next)\n}\n</script>\n\n<template>\n <UidFormField\n :label=\"label ?? undefined\"\n :hint=\"help ?? undefined\"\n :error=\"errorMsg\"\n :required=\"required\"\n :disabled=\"disabled\"\n >\n <UidNumberInput\n :model-value=\"value\"\n :min=\"min ?? undefined\"\n :max=\"max ?? undefined\"\n :step=\"step ?? undefined\"\n :placeholder=\"placeholder ?? undefined\"\n :disabled=\"disabled\"\n :readonly=\"readonly\"\n :name=\"name\"\n @update:model-value=\"onUpdate\"\n />\n </UidFormField>\n</template>\n","<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport { UidSelect, UidFormField } from '@dskripchenko/ui'\nimport { useFormState } from '../render/formState'\n\nexport interface SelectOption {\n value: string | number\n label: string\n disabled?: boolean\n}\n\ninterface Props {\n name: string\n options: SelectOption[]\n label?: string | null\n help?: string | null\n required?: boolean\n placeholder?: string | null\n disabled?: boolean\n searchable?: boolean\n clearable?: boolean\n size?: 'sm' | 'md' | 'lg'\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n label: null,\n help: null,\n placeholder: null,\n required: false,\n disabled: false,\n searchable: false,\n clearable: false,\n size: 'md',\n})\n\nconst form = useFormState()\nconst value = computed<string | number | null>(() => {\n const v = form.getField(props.name)\n if (v === null || v === undefined || v === '') return null\n return v as string | number\n})\nconst errorMsg = computed<string | undefined>(() => form.errors[props.name]?.[0])\n\nfunction onUpdate(next: string | number | null): void {\n form.setField(props.name, next)\n}\n</script>\n\n<template>\n <UidFormField\n :label=\"label ?? undefined\"\n :hint=\"help ?? undefined\"\n :error=\"errorMsg\"\n :required=\"required\"\n :disabled=\"disabled\"\n >\n <UidSelect\n :model-value=\"value\"\n :options=\"options\"\n :placeholder=\"placeholder ?? undefined\"\n :disabled=\"disabled\"\n :searchable=\"searchable\"\n :clearable=\"clearable\"\n :size=\"size\"\n @update:model-value=\"onUpdate\"\n />\n </UidFormField>\n</template>\n","<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport { UidCheckbox, UidFormField } from '@dskripchenko/ui'\nimport { useFormState } from '../render/formState'\n\ninterface Props {\n name: string\n label?: string | null\n help?: string | null\n required?: boolean\n inlineLabel?: string | null\n disabled?: boolean\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n label: null,\n help: null,\n inlineLabel: null,\n required: false,\n disabled: false,\n})\n\nconst form = useFormState()\nconst checked = computed<boolean>(() => Boolean(form.getField(props.name)))\nconst errorMsg = computed<string | undefined>(() => form.errors[props.name]?.[0])\n\nfunction onUpdate(next: boolean): void {\n form.setField(props.name, next)\n}\n</script>\n\n<template>\n <UidFormField\n :label=\"label ?? undefined\"\n :hint=\"help ?? undefined\"\n :error=\"errorMsg\"\n :required=\"required\"\n :disabled=\"disabled\"\n >\n <UidCheckbox\n :model-value=\"checked\"\n :disabled=\"disabled\"\n :name=\"name\"\n @update:model-value=\"onUpdate\"\n >\n <template v-if=\"inlineLabel\">{{ inlineLabel }}</template>\n </UidCheckbox>\n </UidFormField>\n</template>\n","<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport { UidDatePicker, UidFormField } from '@dskripchenko/ui'\nimport { useFormState } from '../render/formState'\n\ninterface Props {\n name: string\n label?: string | null\n help?: string | null\n required?: boolean\n /**\n * Тип input'а: 'date' (default), 'datetime-local', 'time'.\n * UidDatePicker внутри обрабатывает формат через свои props; для совместимости\n * со старым API оставляем prop.\n */\n inputType?: 'date' | 'datetime-local' | 'time'\n min?: string | null\n max?: string | null\n disabled?: boolean\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n label: null,\n help: null,\n inputType: 'date',\n min: null,\n max: null,\n required: false,\n disabled: false,\n})\n\nconst form = useFormState()\nconst value = computed<string | null>(() => {\n const v = form.getField(props.name)\n return v === null || v === undefined || v === '' ? null : String(v)\n})\nconst errorMsg = computed<string | undefined>(() => form.errors[props.name]?.[0])\n\nfunction onUpdate(next: string | null): void {\n form.setField(props.name, next)\n}\n</script>\n\n<template>\n <UidFormField\n :label=\"label ?? undefined\"\n :hint=\"help ?? undefined\"\n :error=\"errorMsg\"\n :required=\"required\"\n :disabled=\"disabled\"\n >\n <UidDatePicker\n :model-value=\"value\"\n :min=\"min ?? undefined\"\n :max=\"max ?? undefined\"\n :disabled=\"disabled\"\n :name=\"name\"\n @update:model-value=\"onUpdate\"\n />\n </UidFormField>\n</template>\n","<script setup lang=\"ts\">\n/**\n * Rows-layout — UidStack column.\n */\nimport { UidStack } from '@dskripchenko/ui'\nimport LayoutRenderer from '../render/LayoutRenderer.vue'\nimport type { LayoutNode } from '../render/LayoutRenderer.vue'\n\ninterface Props {\n items: LayoutNode[]\n /** CSS-зазор между элементами (token либо px), по умолчанию --uid-space-md. */\n gap?: string\n}\nwithDefaults(defineProps<Props>(), { gap: 'var(--uid-space-md)' })\n</script>\n\n<template>\n <UidStack direction=\"column\" :gap=\"gap\" align=\"stretch\">\n <LayoutRenderer v-for=\"(child, idx) in items\" :key=\"idx\" :node=\"child\" />\n </UidStack>\n</template>\n","<script setup lang=\"ts\">\n/**\n * Columns: 12-колоночный grid поверх UidGrid из @dskripchenko/ui.\n * Каждый item.span (1..cols) задаёт ширину; default равные доли.\n */\nimport { computed } from 'vue'\nimport { UidGrid } from '@dskripchenko/ui'\nimport LayoutRenderer from '../render/LayoutRenderer.vue'\nimport type { LayoutNode } from '../render/LayoutRenderer.vue'\n\ninterface Props {\n items: LayoutNode[]\n /** Зазор между ячейками (CSS, token или px). */\n gap?: string\n /** Сколько колонок в гриде (default 12). */\n cols?: number\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n gap: 'var(--uid-space-md)',\n cols: 12,\n})\n\nconst defaultSpan = computed(() => {\n if (props.items.length === 0) return props.cols\n return Math.max(1, Math.floor(props.cols / props.items.length))\n})\n\nfunction spanFor(item: LayoutNode): number {\n const s = (item as Record<string, unknown>).span\n if (typeof s === 'number' && s > 0) return Math.min(s, props.cols)\n return defaultSpan.value\n}\n</script>\n\n<template>\n <UidGrid :cols=\"cols\" :gap=\"gap\">\n <div\n v-for=\"(child, idx) in items\"\n :key=\"idx\"\n class=\"admin-columns__item\"\n :style=\"{ gridColumn: `span ${spanFor(child)} / span ${spanFor(child)}` }\"\n >\n <LayoutRenderer :node=\"child\" />\n </div>\n </UidGrid>\n</template>\n","<script setup lang=\"ts\">\n/**\n * Section/Block layout — UidCard с заголовком + опциональным описанием.\n */\nimport { UidCard } from '@dskripchenko/ui'\nimport LayoutRenderer from '../render/LayoutRenderer.vue'\nimport type { LayoutNode } from '../render/LayoutRenderer.vue'\n\ninterface Props {\n items: LayoutNode[]\n title?: string | null\n description?: string | null\n}\n\nwithDefaults(defineProps<Props>(), {\n title: null,\n description: null,\n})\n</script>\n\n<template>\n <UidCard padding=\"md\" class=\"admin-section\">\n <header v-if=\"title || description\" class=\"admin-section__header\">\n <h3 v-if=\"title\" class=\"admin-section__title\">{{ title }}</h3>\n <p v-if=\"description\" class=\"admin-section__description\">{{ description }}</p>\n </header>\n <div class=\"admin-section__body\">\n <LayoutRenderer v-for=\"(child, idx) in items\" :key=\"idx\" :node=\"child\" />\n </div>\n </UidCard>\n</template>\n\n<style>\n.admin-section { margin-bottom: var(--uid-space-md); }\n.admin-section__header { margin-bottom: var(--uid-space-sm); }\n.admin-section__title {\n margin: 0;\n font-size: var(--uid-font-size-sm);\n font-weight: var(--uid-font-weight-semibold);\n color: var(--uid-text-primary);\n}\n.admin-section__description {\n margin: var(--uid-space-2xs) 0 0;\n font-size: var(--uid-font-size-xs);\n color: var(--uid-text-tertiary);\n}\n.admin-section__body {\n display: flex;\n flex-direction: column;\n gap: var(--uid-space-sm);\n}\n</style>\n","<script setup lang=\"ts\">\n/**\n * TabsLayout поверх UidTabs/UidTab/UidTabPanel.\n * Активная вкладка двусторонне связана через v-model:active.\n */\nimport { ref } from 'vue'\nimport { UidTabs, UidTab, UidTabPanel } from '@dskripchenko/ui'\nimport LayoutRenderer from '../render/LayoutRenderer.vue'\nimport type { LayoutNode } from '../render/LayoutRenderer.vue'\n\nexport interface TabNode {\n /** Уникальный ключ вкладки. Если не задан — берётся индекс. */\n key?: string\n /** Текст вкладки. */\n label: string\n icon?: string | null\n items: LayoutNode[]\n}\n\ninterface Props {\n items: TabNode[]\n /** Активная вкладка (key либо индекс при отсутствии key). */\n active?: string | number\n}\n\nconst props = withDefaults(defineProps<Props>(), { active: 0 })\nconst emit = defineEmits<{ 'update:active': [value: string | number] }>()\n\nfunction tabKey(tab: TabNode, idx: number): string | number {\n return tab.key ?? idx\n}\n\nconst localActive = ref<string | number>(props.active ?? tabKey(props.items[0] ?? { label: '' }, 0))\n\nfunction onUpdate(value: string | number): void {\n localActive.value = value\n emit('update:active', value)\n}\n</script>\n\n<template>\n <UidTabs :model-value=\"localActive\" @update:model-value=\"onUpdate\">\n <template #list>\n <UidTab\n v-for=\"(tab, idx) in items\"\n :key=\"tabKey(tab, idx)\"\n :value=\"tabKey(tab, idx)\"\n >\n {{ tab.label }}\n </UidTab>\n </template>\n\n <UidTabPanel\n v-for=\"(tab, idx) in items\"\n :key=\"`panel-${tabKey(tab, idx)}`\"\n :value=\"tabKey(tab, idx)\"\n >\n <LayoutRenderer\n v-for=\"(child, cidx) in tab.items\"\n :key=\"cidx\"\n :node=\"child\"\n />\n </UidTabPanel>\n </UidTabs>\n</template>\n","/**\n * Default-bundle с минимальным набором builtin-компонентов.\n *\n * Использование:\n *\n * import { registerBuiltinComponents } from '@dskripchenko/laravel-admin'\n * registerBuiltinComponents()\n */\n\nimport { registerComponents } from './registry'\nimport TextField from '../fields/TextField.vue'\nimport TextAreaField from '../fields/TextAreaField.vue'\nimport NumberField from '../fields/NumberField.vue'\nimport SelectField from '../fields/SelectField.vue'\nimport CheckboxField from '../fields/CheckboxField.vue'\nimport DateField from '../fields/DateField.vue'\nimport RowsLayout from '../layouts/RowsLayout.vue'\nimport ColumnsLayout from '../layouts/ColumnsLayout.vue'\nimport SectionLayout from '../layouts/SectionLayout.vue'\nimport TabsLayout from '../layouts/TabsLayout.vue'\n\nexport function registerBuiltinComponents(): void {\n registerComponents({\n fields: {\n // Backend Field-классы из dskripchenko/laravel-admin отдают эти fieldType()\n // строки. Соответствие см. core/src/Field/{Input,TextArea,Select,...}.php.\n input: TextField,\n text: TextField,\n email: TextField,\n url: TextField,\n password: TextField,\n tel: TextField,\n search: TextField,\n slug: TextField,\n hidden: TextField,\n label: TextField,\n textarea: TextAreaField,\n // Fallback для wysiwyg/markdown/code — обычный TextAreaField.\n // Реальный rich-editor host подключает через subpath:\n // import { QuillField } from '@dskripchenko/laravel-admin/quill'\n // registerField('wysiwyg', QuillField)\n wysiwyg: TextAreaField,\n markdown: TextAreaField,\n code: TextAreaField,\n number: NumberField,\n slider: NumberField,\n rating: NumberField,\n select: SelectField,\n combobox: SelectField,\n radio: SelectField,\n tags: SelectField,\n 'morph-switcher': SelectField,\n relation: SelectField,\n cascader: SelectField,\n 'tree-select': SelectField,\n checkbox: CheckboxField,\n switcher: CheckboxField,\n boolean: CheckboxField,\n date: DateField,\n datetime: DateField,\n datepicker: DateField,\n 'date-range': DateField,\n time: DateField,\n 'time-picker': DateField,\n 'color-picker': TextField,\n },\n layouts: {\n rows: RowsLayout,\n columns: ColumnsLayout,\n section: SectionLayout,\n block: SectionLayout,\n tabs: TabsLayout,\n accordion: SectionLayout,\n group: RowsLayout,\n step: SectionLayout,\n wizard: SectionLayout,\n },\n })\n}\n","<script setup lang=\"ts\">\n/**\n * TextEntry — строковое read-only значение.\n *\n * Источник: prop.value либо record[name].\n * Для empty-state — placeholder («—» по умолчанию).\n */\nimport { computed } from 'vue'\nimport { tryUseRecord } from './recordContext'\n\ninterface Props {\n name?: string\n label?: string\n value?: string | number | null\n /** Заместитель пустого значения. */\n placeholder?: string\n /** Применить mono-font (например для ID/UUID). */\n mono?: boolean\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n name: '',\n label: '',\n value: undefined,\n placeholder: '—',\n mono: false,\n})\n\nconst record = tryUseRecord()\nconst display = computed<string>(() => {\n let v: unknown = props.value\n if (v === undefined && record && props.name) {\n v = record[props.name]\n }\n if (v === null || v === undefined || v === '') return props.placeholder\n return String(v)\n})\n</script>\n\n<template>\n <span :class=\"['admin-infolist-text', mono ? 'admin-infolist-text--mono' : '']\">\n {{ display }}\n </span>\n</template>\n\n<style>\n.admin-infolist-text {\n font-size: var(--uid-font-size-sm);\n color: var(--uid-text-primary);\n}\n.admin-infolist-text--mono {\n font-family: var(--uid-font-family-mono);\n font-size: var(--uid-font-size-xs);\n}\n</style>\n","<script setup lang=\"ts\">\n/**\n * BadgeEntry — строковое значение в виде UidBadge с variant'ом по value-mapping.\n *\n * Manifest:\n * { type: 'badge', name: 'status', label: 'Status',\n * map: { published: 'success', draft: 'warning', archived: 'danger' } }\n */\nimport { computed } from 'vue'\nimport { UidBadge } from '@dskripchenko/ui'\nimport { tryUseRecord } from './recordContext'\n\ntype BadgeVariant = 'default' | 'success' | 'warning' | 'danger' | 'info'\n\ninterface Props {\n name?: string\n label?: string\n value?: string | null\n /** map value → variant. Если не задан — default. */\n map?: Record<string, BadgeVariant>\n /** Принудительный variant. */\n variant?: BadgeVariant\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n name: '',\n label: '',\n value: undefined,\n map: () => ({}),\n variant: undefined,\n})\n\nconst record = tryUseRecord()\nconst value = computed<string>(() => {\n let v: unknown = props.value\n if (v === undefined && record && props.name) {\n v = record[props.name]\n }\n return v === null || v === undefined ? '' : String(v)\n})\nconst resolvedVariant = computed<BadgeVariant>(() => {\n if (props.variant) return props.variant\n return props.map[value.value] ?? 'default'\n})\n</script>\n\n<template>\n <UidBadge v-if=\"value\" :variant=\"resolvedVariant\">\n {{ value }}\n </UidBadge>\n <span v-else class=\"admin-infolist-text\">—</span>\n</template>\n","<script setup lang=\"ts\">\n/**\n * IconEntry — boolean-флаг как иконка (true → check, false → x).\n * Опционально labels: '{ true: \"Опубликовано\", false: \"Черновик\" }'.\n */\nimport { computed } from 'vue'\nimport { tryUseRecord } from './recordContext'\n\ninterface Props {\n name?: string\n label?: string\n value?: boolean | null\n /** Имя icon'и для true (lucide-key, например 'check-circle-2'). */\n trueIcon?: string\n /** Имя icon'и для false. */\n falseIcon?: string\n /** Текстовые подписи. */\n trueLabel?: string\n falseLabel?: string\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n name: '',\n label: '',\n value: undefined,\n trueIcon: 'check-circle-2',\n falseIcon: 'circle',\n trueLabel: '',\n falseLabel: '',\n})\n\nconst record = tryUseRecord()\nconst flag = computed<boolean>(() => {\n let v: unknown = props.value\n if (v === undefined && record && props.name) {\n v = record[props.name]\n }\n return Boolean(v)\n})\nconst displayLabel = computed(() => (flag.value ? props.trueLabel : props.falseLabel))\nconst iconName = computed(() => (flag.value ? props.trueIcon : props.falseIcon))\n</script>\n\n<template>\n <span :class=\"['admin-infolist-icon', flag ? 'admin-infolist-icon--on' : 'admin-infolist-icon--off']\">\n <span class=\"admin-infolist-icon__glyph\" :data-icon=\"iconName\" />\n <span v-if=\"displayLabel\">{{ displayLabel }}</span>\n </span>\n</template>\n\n<style>\n.admin-infolist-icon {\n display: inline-flex;\n align-items: center;\n gap: var(--uid-space-xs);\n font-size: var(--uid-font-size-sm);\n}\n.admin-infolist-icon--on { color: var(--uid-success); }\n.admin-infolist-icon--off { color: var(--uid-text-tertiary); }\n.admin-infolist-icon__glyph {\n display: inline-block;\n width: 14px;\n height: 14px;\n}\n</style>\n","<script setup lang=\"ts\">\n/**\n * KeyValueEntry — словарь {key: value} как UidDescriptionList.\n * Source: prop.value (Record) либо record[name].\n */\nimport { computed } from 'vue'\nimport { UidDescriptionList, UidDescriptionItem } from '@dskripchenko/ui'\nimport { tryUseRecord } from './recordContext'\n\ninterface Props {\n name?: string\n label?: string\n value?: Record<string, unknown>\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n name: '',\n label: '',\n value: undefined,\n})\n\nconst record = tryUseRecord()\nconst items = computed<Array<[string, unknown]>>(() => {\n let v: unknown = props.value\n if (v === undefined && record && props.name) {\n v = record[props.name]\n }\n if (v === null || v === undefined) return []\n if (typeof v !== 'object') return []\n return Object.entries(v as Record<string, unknown>)\n})\n\nfunction formatValue(v: unknown): string {\n if (v === null || v === undefined) return '—'\n if (typeof v === 'object') return JSON.stringify(v)\n return String(v)\n}\n</script>\n\n<template>\n <UidDescriptionList v-if=\"items.length > 0\" direction=\"vertical\" :columns=\"1\">\n <UidDescriptionItem\n v-for=\"[k, v] in items\"\n :key=\"k\"\n :label=\"k\"\n >\n {{ formatValue(v) }}\n </UidDescriptionItem>\n </UidDescriptionList>\n <span v-else class=\"admin-infolist-text\">—</span>\n</template>\n","/**\n * Default-bundle с минимальным набором builtin infolist-entry'ев.\n *\n * View-страница (ResourceViewPage) использует те же type-strings что и\n * form-page (ResourceFormPage) — backend Field::fieldType() возвращает\n * одинаковое имя в обоих контекстах. Поэтому infolist-mapping должен\n * покрывать те же типы что registerBuiltinComponents — fallback на\n * TextEntry для всех stdread-only представлений.\n */\n\nimport { registerInfolistEntries } from './registry'\nimport TextEntry from './TextEntry.vue'\nimport BadgeEntry from './BadgeEntry.vue'\nimport IconEntry from './IconEntry.vue'\nimport KeyValueEntry from './KeyValueEntry.vue'\n\nexport function registerBuiltinInfolistEntries(): void {\n registerInfolistEntries({\n // Дефолтные типы infolist (BadgeEntry::make() и т.п.).\n text: TextEntry,\n badge: BadgeEntry,\n icon: IconEntry,\n keyvalue: KeyValueEntry,\n 'key-value': KeyValueEntry,\n // Маппинг от backend Field::fieldType() → TextEntry для view-режима.\n // Host'ы могут перебить registerInfolistEntry('wysiwyg', WysiwygEntry).\n input: TextEntry,\n email: TextEntry,\n url: TextEntry,\n password: TextEntry,\n tel: TextEntry,\n search: TextEntry,\n slug: TextEntry,\n hidden: TextEntry,\n label: TextEntry,\n textarea: TextEntry,\n wysiwyg: TextEntry,\n markdown: TextEntry,\n code: TextEntry,\n number: TextEntry,\n slider: TextEntry,\n rating: TextEntry,\n select: TextEntry,\n combobox: TextEntry,\n radio: TextEntry,\n tags: TextEntry,\n 'morph-switcher': TextEntry,\n relation: TextEntry,\n cascader: TextEntry,\n 'tree-select': TextEntry,\n checkbox: TextEntry,\n switcher: TextEntry,\n boolean: TextEntry,\n date: TextEntry,\n datetime: TextEntry,\n datepicker: TextEntry,\n 'date-range': TextEntry,\n time: TextEntry,\n 'time-picker': TextEntry,\n 'color-picker': TextEntry,\n })\n}\n","/**\n * createAdminApp — фабрика-helper для host-проектов.\n *\n * Собирает Vue-app со всем нужным: Pinia, Router, AdminClient, hydrated\n * stores, built-in fields/layouts/widgets/infolist, default страницы.\n * Возвращает объект где `app` готов к `.mount('#admin-app')`.\n *\n * Минимальный пример (host's resources/js/admin.js):\n *\n * import { createAdminApp } from '@dskripchenko/laravel-admin'\n * import '@dskripchenko/laravel-admin/style.css'\n *\n * const { app } = createAdminApp(window.__ADMIN_BOOTSTRAP__)\n * app.mount('#admin-app')\n *\n * Расширенное использование с переопределением страниц:\n *\n * const { app } = createAdminApp(window.__ADMIN_BOOTSTRAP__, {\n * pages: { home: MyDashboard },\n * onAppCreated: (app) => app.use(SomePlugin),\n * })\n */\n\nimport { createApp, watch, type App, type Component } from 'vue'\nimport { createPinia } from 'pinia'\nimport { createWebHistory } from 'vue-router'\n\nimport AdminApp from './components/AdminApp.vue'\nimport HomePage from './components/HomePage.vue'\nimport ForbiddenPage from './components/ForbiddenPage.vue'\nimport NotFoundPage from './components/NotFoundPage.vue'\nimport SettingsPage from './components/SettingsPage.vue'\nimport UnknownScreenPage from './components/UnknownScreenPage.vue'\nimport { LoginPage } from './components/auth'\nimport {\n ResourceIndexPage,\n ResourceFormPage,\n ResourceViewPage,\n} from './components/resource'\nimport { ProfilePage } from './components/profile'\nimport { DashboardPage } from './components/dashboard'\n\nimport { createAdminClient, type AdminClient } from './api/client'\nimport { setAdminClient } from './stores'\nimport { useAuthStore } from './stores/auth'\nimport { useLocaleStore } from './stores/locale'\nimport { useThemeStore } from './stores/theme'\nimport { useNotificationsStore } from './stores/notifications'\nimport { useManifestStore } from './stores/manifest'\nimport { useMenuStore } from './stores/menu'\nimport { useNavigationStore } from './stores/navigation'\n\nimport { createAdminRouter, type AdminRouter, type AdminRouterOptions } from './router'\nimport { registerBuiltinComponents } from './components/render/builtin'\nimport { registerBuiltinWidgets } from './components/dashboard/builtin'\nimport { registerBuiltinInfolistEntries } from './components/infolist/builtin'\n\nimport type { AdminBootstrap } from './types/bootstrap'\n\nexport interface CreateAdminAppPages {\n /** Login page. По умолчанию core'овский LoginPage. */\n login?: Component\n /** Главная (после login). По умолчанию HomePage. */\n home?: Component\n /** 403. По умолчанию ForbiddenPage. */\n forbidden?: Component\n /** 404. По умолчанию NotFoundPage. */\n notFound?: Component\n /** Профиль. По умолчанию ProfilePage. */\n profile?: Component\n /** Resource index/form/view. По умолчанию core'овские. */\n resourceIndex?: Component\n resourceCreate?: Component\n resourceEdit?: Component\n resourceView?: Component\n /** Dashboard страница (для роутов admin.dashboard.*). */\n dashboard?: Component\n /** Settings page (для admin.settings.*). */\n settings?: Component\n /** Custom Screen page (для admin.screen.*). */\n screen?: Component\n}\n\nexport interface CreateAdminAppOptions {\n /**\n * Базовый URL admin-панели. По умолчанию берётся из bootstrap.baseUrl\n * (если он pathname вида '/admin'), иначе '/admin'.\n */\n base?: string\n /** Override отдельных страниц. */\n pages?: CreateAdminAppPages\n /** Дополнительные опции router'а (extraRoutes, history, guards). */\n router?: Partial<Omit<AdminRouterOptions, 'components'>>\n /** Hook для до-настройки app перед mount (app.use(plugin), app.provide(...)). */\n onAppCreated?: (app: App) => void\n /**\n * Не вызывать manifestStore.load() автоматически. По умолчанию false —\n * createAdminApp сам подгружает manifest и выстраивает динамические роуты.\n */\n skipManifestLoad?: boolean\n}\n\nexport interface AdminAppHandle {\n app: App\n router: AdminRouter\n client: AdminClient\n}\n\n/**\n * Создать Vue admin-app, готовый к `.mount('#admin-app')`.\n *\n * Шаги внутри:\n * 1. Pinia + AdminClient (axios через bootstrap.csrf/apiUrl).\n * 2. Hydrate auth/locale/theme/notifications stores из bootstrap.\n * 3. Регистрация built-in fields/layouts/widgets/infolist entries.\n * 4. Router со static-routes (login/home/profile/forbidden/notFound) +\n * async manifest load → replaceManifestRoutes для resource/screen/\n * settings/dashboard.\n * 5. Возврат `{ app, router, client }`. Host вызывает `app.mount(...)`.\n */\nexport function createAdminApp(\n bootstrap: AdminBootstrap,\n options: CreateAdminAppOptions = {},\n): AdminAppHandle {\n const pages = options.pages ?? {}\n const base = options.base ?? deriveBase(bootstrap.baseUrl) ?? '/admin'\n\n // 1. AdminClient\n const client = createAdminClient({\n baseURL: bootstrap.apiUrl,\n csrfToken: bootstrap.csrf,\n })\n setAdminClient(client)\n\n // 2. Vue app + Pinia\n const app = createApp(AdminApp)\n const pinia = createPinia()\n app.use(pinia)\n\n // 3. Pinia stores hydrate\n useAuthStore().hydrate(bootstrap)\n useLocaleStore().hydrate(bootstrap)\n useThemeStore().hydrate(bootstrap)\n useNotificationsStore().hydrate(bootstrap)\n\n // 4. Builtin field/layout/widget/infolist registries\n registerBuiltinComponents()\n registerBuiltinWidgets()\n registerBuiltinInfolistEntries()\n\n // 5. Router\n const router = createAdminRouter({\n base,\n history: options.router?.history ?? createWebHistory(base),\n components: {\n login: pages.login ?? LoginPage,\n home: pages.home ?? HomePage,\n forbidden: pages.forbidden ?? ForbiddenPage,\n notFound: pages.notFound ?? NotFoundPage,\n profile: pages.profile ?? ProfilePage,\n resourceIndex: pages.resourceIndex ?? ResourceIndexPage,\n resourceCreate: pages.resourceCreate ?? ResourceFormPage,\n resourceEdit: pages.resourceEdit ?? ResourceFormPage,\n resourceView: pages.resourceView ?? ResourceViewPage,\n dashboard: pages.dashboard ?? DashboardPage,\n settings: pages.settings ?? SettingsPage,\n screen: pages.screen ?? UnknownScreenPage,\n },\n extraRoutes: options.router?.extraRoutes,\n authGuard: options.router?.authGuard,\n titleGuard: options.router?.titleGuard,\n })\n app.use(router)\n\n // 5.1 Top loading-bar hooks: pending++ при старте навигации, pending--\n // при её завершении.\n const navStore = useNavigationStore()\n router.beforeEach((to, from, next) => {\n if (to.fullPath !== from.fullPath) navStore.start()\n next()\n })\n router.afterEach(() => {\n navStore.end()\n })\n router.onError(() => {\n navStore.end()\n })\n\n // 5.2 Pre-fetch resource data ДО mount страницы. Это держит navigation в\n // pending'е — старая страница остаётся в DOM пока новая загружает данные.\n // После resolve hook'а Vue Router монтирует новую страницу с уже\n // наполненным store'ом, что устраняет flash \"пустая страница →\n // данные приехали\" (без необходимости в Suspense).\n router.beforeResolve(async (to, _from, next) => {\n // Только resource.index роуты предзагружают свой dataset.\n const name = typeof to.name === 'string' ? to.name : null\n if (name && name.startsWith('admin.resource.') && name.endsWith('.index')) {\n const slug = (to.params.slug as string | undefined) ?? (to.meta.slug as string | undefined)\n if (slug) {\n try {\n // Lazy-import чтобы избежать circular в createAdminApp init.\n const { useResourceIndexStore } = await import('./stores/resourceIndex')\n const indexStore = useResourceIndexStore()\n if (indexStore.slug !== slug || indexStore.items.length === 0) {\n indexStore.setSlug(slug)\n await indexStore.load().catch(() => undefined)\n }\n } catch {\n // silent — page mount упадёт в свой error-state.\n }\n }\n }\n next()\n })\n\n // 6. Manifest async-load + dynamic routes (только если authenticated;\n // при появлении user после login — manifest подгружается автоматически).\n if (!options.skipManifestLoad) {\n const manifestStore = useManifestStore()\n const authStore = useAuthStore()\n\n const menuStore = useMenuStore()\n\n const loadAndApply = (): void => {\n // Параллельно с manifest'ом тянем sidebar-меню (от backend menu endpoint).\n void menuStore.load().catch(() => undefined)\n\n void manifestStore\n .load()\n .then((manifest) => {\n router.replaceManifestRoutes(manifest)\n // Если текущий route был разрешён в catch-all notFound (deep-link\n // на /r/articles/123/edit при первом mount, когда динамические\n // роуты ещё не были добавлены) — перерезолвим его теперь, когда\n // routes есть.\n const current = router.currentRoute.value\n if (current.name === 'admin.notFound' && current.fullPath !== '/') {\n void router.replace(current.fullPath)\n }\n })\n .catch((error: unknown) => {\n // Silent fail — host может перехватить через onAppCreated →\n // app.config.errorHandler. Manifest перезагрузится при следующем\n // появлении user (watch ниже).\n if (typeof console !== 'undefined') {\n console.error('[laravel-admin] manifest load failed:', error)\n }\n })\n }\n\n if (authStore.isAuthenticated) {\n // Inline-bootstrap уже принёс user'а — грузим сразу.\n loadAndApply()\n }\n // Если user'а ещё нет (login flow) либо появится позже —\n // подписываемся и грузим когда появится. immediate: false чтобы не\n // дублировать вызов при isAuthenticated=true выше.\n watch(\n () => authStore.user,\n (newUser, oldUser) => {\n if (newUser && !oldUser) {\n loadAndApply()\n }\n },\n )\n }\n\n // 7. host hook\n options.onAppCreated?.(app)\n\n return { app, router, client }\n}\n\n/**\n * Извлечь base path из bootstrap.baseUrl ('http://app.test/admin' → '/admin').\n */\nfunction deriveBase(baseUrl: string | undefined): string | null {\n if (!baseUrl) return null\n try {\n const url = new URL(baseUrl)\n return url.pathname || '/admin'\n } catch {\n return baseUrl.startsWith('/') ? baseUrl : null\n }\n}\n","/**\n * Загрузка bootstrap-payload'а в SPA.\n *\n * Поддерживает обе стратегии:\n * - 'inline' — читает window.__ADMIN_BOOTSTRAP__ (инжект через\n * shell.blade при strategy=inline).\n * - 'xhr' — fetch'ит /api/admin/system/bootstrap.\n *\n * Если оба способа не дали результата — throw'ит. SPA должна это поймать\n * и показать full-screen error.\n */\n\nimport type { AdminBootstrap } from '../types/bootstrap'\nimport type { AdminClient } from './client'\nimport { NetworkError } from './errors'\n\nexport interface LoadBootstrapOptions {\n /** Если задан client — fallback на xhr через него. */\n client?: AdminClient\n /** Override URL для xhr. Default: '/system/bootstrap'. */\n xhrUrl?: string\n}\n\n/**\n * Возвращает bootstrap или null если не загрузился.\n *\n * Порядок:\n * 1. window.__ADMIN_BOOTSTRAP__ (inline-strategy).\n * 2. xhr fetch если передан client.\n * 3. null — caller решает что делать (показать error-screen).\n */\nexport async function loadBootstrap(\n opts: LoadBootstrapOptions = {},\n): Promise<AdminBootstrap | null> {\n const inline = readInlineBootstrap()\n if (inline) {\n return inline\n }\n\n if (opts.client) {\n try {\n const url = opts.xhrUrl ?? '/system/bootstrap'\n return await opts.client.get<AdminBootstrap>(url)\n } catch (err) {\n if (err instanceof NetworkError) {\n // Network failure — caller должен показать offline-screen.\n return null\n }\n throw err\n }\n }\n\n return null\n}\n\n/**\n * Прочитать bootstrap из window — только в браузерном контексте.\n */\nexport function readInlineBootstrap(): AdminBootstrap | null {\n if (typeof window === 'undefined') return null\n return window.__ADMIN_BOOTSTRAP__ ?? null\n}\n\n/**\n * Прочитать CSRF-token из meta-tag (Blade-injection через `csrf_token()`).\n *\n * Используется как fallback если bootstrap.csrf отсутствует.\n */\nexport function readCsrfFromMeta(): string | null {\n if (typeof document === 'undefined') return null\n const meta = document.querySelector('meta[name=\"csrf-token\"]')\n return meta?.getAttribute('content') ?? null\n}\n","<script setup lang=\"ts\">\n/**\n * NotificationsDrawer — UidDrawer (right, 400px) с tabs (Все/Непрочитанные/\n * Прочитанные) и списком notification-items.\n *\n * Эталон handoff'а (screens-secondary.jsx → NotificationDrawer):\n * - Header: «Уведомления (3)» + actions (Прочитать все)\n * - Tabs: counts, активный tab подсвечен accent\n * - Item: kind-coloured icon (info/success/warning/error) +\n * title (bold если unread) + body + relative timestamp;\n * unread items имеют tinted background + dot слева\n * - Click на item → переход на data.url + auto markAsRead\n * - Hover показывает кнопку '×' (destroy)\n */\nimport { computed, watch } from 'vue'\nimport { UidButton, UidDrawer, UidTabs, UidTab, UidTabPanel } from '@dskripchenko/ui'\nimport { useNotificationsStore, type NotificationFilter, type NotificationItem } from '../../stores/notifications'\n\ninterface Props {\n /** v-model:open. */\n open: boolean\n}\n\nconst props = defineProps<Props>()\nconst emit = defineEmits<{\n 'update:open': [value: boolean]\n /** Click on notification item — host обрабатывает navigation на data.url. */\n 'select-item': [item: NotificationItem]\n}>()\n\nconst notifications = useNotificationsStore()\n\nfunction setOpen(v: boolean): void {\n emit('update:open', v)\n}\n\n// Загружаем при открытии.\nwatch(\n () => props.open,\n async (next) => {\n if (next) {\n await notifications.load(notifications.lastFilter ?? 'all', 1).catch(() => undefined)\n }\n },\n { immediate: true },\n)\n\nconst activeFilter = computed<NotificationFilter>(() => notifications.lastFilter ?? 'all')\n\nasync function setFilter(filter: NotificationFilter | string | number): Promise<void> {\n await notifications\n .load(filter as NotificationFilter, 1)\n .catch(() => undefined)\n}\n\nasync function markAllRead(): Promise<void> {\n await notifications.markAllAsRead().catch(() => undefined)\n}\n\nasync function onItemClick(item: NotificationItem): Promise<void> {\n emit('select-item', item)\n if (!item.read_at) {\n await notifications.markAsRead(item.id).catch(() => undefined)\n }\n}\n\nasync function onDestroy(item: NotificationItem, event: Event): Promise<void> {\n event.stopPropagation()\n await notifications.destroy(item.id).catch(() => undefined)\n}\n\nfunction itemKind(item: NotificationItem): 'info' | 'success' | 'warning' | 'danger' {\n const lvl = item.data.level\n if (lvl === 'success' || lvl === 'warning' || lvl === 'danger') return lvl\n return 'info'\n}\n\nfunction itemTitle(item: NotificationItem): string {\n return (item.data.title as string | undefined) ?? '—'\n}\n\nfunction itemBody(item: NotificationItem): string {\n return (item.data.body as string | undefined) ?? ''\n}\n\nfunction relTime(iso: string | null): string {\n if (!iso) return ''\n const dt = new Date(iso)\n const diff = Math.max(0, Date.now() - dt.getTime())\n const mins = Math.floor(diff / 60000)\n if (mins < 1) return 'только что'\n if (mins < 60) return `${mins} мин назад`\n const hours = Math.floor(mins / 60)\n if (hours < 24) return `${hours} ч назад`\n const days = Math.floor(hours / 24)\n if (days < 7) return `${days} д назад`\n return dt.toLocaleDateString('ru-RU')\n}\n</script>\n\n<template>\n <UidDrawer\n :model-value=\"open\"\n side=\"right\"\n width=\"400px\"\n title=\"Уведомления\"\n @update:model-value=\"setOpen\"\n >\n <template #header>\n <div class=\"admin-notifs__hd\">\n <h2 class=\"admin-notifs__title\">\n Уведомления\n <span v-if=\"notifications.unreadCount > 0\" class=\"admin-notifs__count\">\n ({{ notifications.unreadCount }})\n </span>\n </h2>\n <UidButton\n v-if=\"notifications.unreadCount > 0\"\n variant=\"ghost\"\n size=\"sm\"\n @click=\"markAllRead\"\n >\n Прочитать все\n </UidButton>\n </div>\n </template>\n\n <UidTabs :model-value=\"activeFilter\" @update:model-value=\"setFilter\">\n <template #list>\n <UidTab value=\"all\">Все</UidTab>\n <UidTab value=\"unread\">\n Непрочитанные<template v-if=\"notifications.unreadCount > 0\">\n ({{ notifications.unreadCount }})\n </template>\n </UidTab>\n <UidTab value=\"read\">Прочитанные</UidTab>\n </template>\n\n <UidTabPanel v-for=\"filter in (['all','unread','read'] as const)\" :key=\"filter\" :value=\"filter\">\n <ul class=\"admin-notifs__list\">\n <li v-if=\"notifications.loading\" class=\"admin-notifs__empty\">\n Загрузка…\n </li>\n <li v-else-if=\"notifications.items.length === 0\" class=\"admin-notifs__empty\">\n Нет уведомлений\n </li>\n <li\n v-for=\"item in notifications.items\"\n :key=\"item.id\"\n :class=\"[\n 'admin-notifs__item',\n `admin-notifs__item--${itemKind(item)}`,\n { 'admin-notifs__item--unread': !item.read_at },\n ]\"\n @click=\"onItemClick(item)\"\n >\n <span class=\"admin-notifs__icon\" :data-kind=\"itemKind(item)\" />\n <div class=\"admin-notifs__body\">\n <div class=\"admin-notifs__row1\">\n <strong v-if=\"!item.read_at\" class=\"admin-notifs__title-strong\">\n {{ itemTitle(item) }}\n </strong>\n <span v-else class=\"admin-notifs__title-soft\">{{ itemTitle(item) }}</span>\n <span class=\"admin-notifs__time\">{{ relTime(item.created_at) }}</span>\n </div>\n <p v-if=\"itemBody(item)\" class=\"admin-notifs__text\">{{ itemBody(item) }}</p>\n </div>\n <button\n type=\"button\"\n class=\"admin-notifs__close\"\n :aria-label=\"'Удалить'\"\n @click=\"onDestroy(item, $event)\"\n >\n ×\n </button>\n </li>\n </ul>\n </UidTabPanel>\n </UidTabs>\n </UidDrawer>\n</template>\n\n<style>\n.admin-notifs__hd {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--uid-space-sm);\n}\n.admin-notifs__title {\n margin: 0;\n font-size: var(--uid-font-size-md);\n font-weight: var(--uid-font-weight-semibold);\n}\n.admin-notifs__count {\n color: var(--uid-text-tertiary);\n font-weight: var(--uid-font-weight-regular);\n font-size: var(--uid-font-size-sm);\n}\n\n.admin-notifs__list {\n list-style: none;\n margin: 0;\n padding: 0;\n}\n.admin-notifs__empty {\n padding: var(--uid-space-xl) var(--uid-space-md);\n text-align: center;\n color: var(--uid-text-tertiary);\n font-size: var(--uid-font-size-sm);\n}\n.admin-notifs__item {\n position: relative;\n display: flex;\n gap: var(--uid-space-sm);\n padding: var(--uid-space-sm) var(--uid-space-md);\n cursor: pointer;\n border-bottom: 1px solid var(--uid-border-subtle);\n}\n.admin-notifs__item:hover { background: var(--uid-surface-hover); }\n.admin-notifs__item--unread {\n background: color-mix(in srgb, var(--uid-accent) 6%, transparent);\n}\n.admin-notifs__item--unread:hover {\n background: color-mix(in srgb, var(--uid-accent) 10%, transparent);\n}\n\n.admin-notifs__icon {\n width: 28px;\n height: 28px;\n border-radius: var(--uid-radius-md);\n flex: none;\n margin-top: 2px;\n}\n.admin-notifs__icon[data-kind='info'] {\n background: color-mix(in srgb, var(--uid-info) 14%, transparent);\n}\n.admin-notifs__icon[data-kind='success'] {\n background: color-mix(in srgb, var(--uid-success) 14%, transparent);\n}\n.admin-notifs__icon[data-kind='warning'] {\n background: color-mix(in srgb, var(--uid-warning) 14%, transparent);\n}\n.admin-notifs__icon[data-kind='danger'] {\n background: color-mix(in srgb, var(--uid-danger) 14%, transparent);\n}\n\n.admin-notifs__body { flex: 1; min-width: 0; }\n.admin-notifs__row1 {\n display: flex;\n align-items: baseline;\n gap: var(--uid-space-sm);\n margin-bottom: 2px;\n}\n.admin-notifs__title-strong {\n font-size: var(--uid-font-size-sm);\n font-weight: var(--uid-font-weight-semibold);\n color: var(--uid-text-primary);\n flex: 1;\n min-width: 0;\n}\n.admin-notifs__title-soft {\n font-size: var(--uid-font-size-sm);\n color: var(--uid-text-primary);\n flex: 1;\n min-width: 0;\n}\n.admin-notifs__time {\n font-size: 11px;\n color: var(--uid-text-tertiary);\n flex: none;\n font-variant-numeric: tabular-nums;\n}\n.admin-notifs__text {\n margin: 0;\n font-size: var(--uid-font-size-xs);\n color: var(--uid-text-secondary);\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n.admin-notifs__close {\n position: absolute;\n top: 6px;\n right: 8px;\n appearance: none;\n border: 0;\n background: transparent;\n color: var(--uid-text-tertiary);\n cursor: pointer;\n font-size: 18px;\n width: 22px;\n height: 22px;\n border-radius: var(--uid-radius-sm);\n opacity: 0;\n transition: opacity var(--uid-duration-fast, 100ms);\n}\n.admin-notifs__item:hover .admin-notifs__close { opacity: 1; }\n.admin-notifs__close:hover {\n background: var(--uid-surface-hover);\n color: var(--uid-text-primary);\n}\n</style>\n","<script setup lang=\"ts\">\n/**\n * ImportWizardPage — 4-step wizard для импорта данных в Resource.\n *\n * Эталон: docs/design_handoff_laravel_admin/screens-secondary.jsx (ImportWizard).\n *\n * Шаги:\n * 1. Загрузка файла — UidFileUpload (CSV/TSV/XLSX)\n * 2. Сопоставление колонок — header'ы файла → field-name'ы ресурса\n * 3. Предпросмотр — таблица первых N строк с warning'ами\n * 4. Импорт — progress-bar + KPI (created/updated/errors)\n *\n * Library предоставляет каркас + state. Конкретные API-вызовы (analyze\n * uploaded file → headers/sample, mapping submit → preview, run import →\n * progress events) — host реализует через emit'ы.\n */\nimport { computed, ref } from 'vue'\nimport {\n UidAlert,\n UidButton,\n UidCard,\n UidFileUpload,\n UidProgress,\n UidSelect,\n UidStat,\n UidStepper,\n UidTable,\n type UidTableColumn,\n} from '@dskripchenko/ui'\n\ninterface ColumnHeader {\n key: string\n label: string\n sample?: string\n}\n\ninterface Mapping {\n /** Header из файла. */\n source: string\n /** Field-name в ресурсе либо null = пропустить. */\n target: string | null\n}\n\ninterface PreviewRow extends Record<string, unknown> {\n __warning?: string | null\n}\n\ninterface ImportProgress {\n created: number\n updated: number\n errors: number\n total: number\n}\n\ninterface Props {\n /** Заголовок страницы. */\n title?: string\n /** Опции для select'а target field'а на step 2. */\n fieldOptions: Array<{ value: string; label: string }>\n /** Headers + sample из uploaded file (host передаёт после step 1). */\n headers?: ColumnHeader[]\n /** Preview rows с warning'ами (host передаёт после step 2 submit). */\n preview?: PreviewRow[]\n /** Preview-table columns (host передаёт). */\n previewColumns?: UidTableColumn[]\n /** Финальная сводка импорта. */\n progress?: ImportProgress | null\n /** Внешне controlled-mode current step (опц.). */\n step?: number\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n title: 'Импорт',\n headers: () => [],\n preview: () => [],\n previewColumns: () => [],\n progress: null,\n step: undefined,\n})\n\nconst emit = defineEmits<{\n /** Файл загружен — host анализирует, отдаёт headers через v-bind. */\n 'file-uploaded': [file: File]\n /** Mapping submit — host генерирует preview. */\n 'mapping-submit': [mapping: Mapping[]]\n /** Run import — host выполняет с реальной записью. */\n 'run-import': []\n /** Cancel wizard. */\n cancel: []\n}>()\n\nconst STEPS = [\n { label: 'Загрузка', description: 'CSV / TSV / XLSX' },\n { label: 'Сопоставление', description: 'Колонки файла → поля' },\n { label: 'Предпросмотр', description: 'Проверка первых строк' },\n { label: 'Импорт', description: 'Запуск + сводка' },\n]\n\nconst internalStep = ref(0)\nconst currentStep = computed(() => props.step ?? internalStep.value)\n\nfunction setStep(idx: number): void {\n if (props.step !== undefined) return // controlled mode — host сам сдвигает\n if (idx < 0 || idx >= STEPS.length) return\n internalStep.value = idx\n}\n\n// Step 1: file upload\nconst uploadedFiles = ref<Array<{ file: File; id: string }>>([])\nfunction onUpload(files: Array<{ file: File; id: string }>): void {\n uploadedFiles.value = files\n if (files.length > 0) {\n emit('file-uploaded', files[0].file)\n }\n}\n\n// Step 2: mapping\nconst mapping = ref<Record<string, string | null>>({})\n\nfunction setTarget(source: string, value: string | number | null): void {\n mapping.value[source] = value === null || value === '' ? null : String(value)\n}\n\nfunction buildMapping(): Mapping[] {\n return props.headers.map((h) => ({\n source: h.key,\n target: mapping.value[h.key] ?? null,\n }))\n}\n\nfunction onMappingSubmit(): void {\n emit('mapping-submit', buildMapping())\n setStep(2)\n}\n\n// Step 3 → 4\nfunction onConfirmRun(): void {\n emit('run-import')\n setStep(3)\n}\n\n// Кнопки навигации\nconst canGoBack = computed(() => currentStep.value > 0)\nconst canGoNext = computed(() => {\n switch (currentStep.value) {\n case 0: return uploadedFiles.value.length > 0\n case 1: return Object.values(mapping.value).some((v) => v !== null)\n case 2: return true\n default: return false\n }\n})\n\nconst fileOptions = computed<Array<{ value: string; label: string }>>(() => {\n return [\n { value: '', label: 'Не импортировать' },\n ...props.fieldOptions,\n ]\n})\n\nfunction onCancel(): void {\n emit('cancel')\n}\n</script>\n\n<template>\n <section class=\"admin-page admin-import-wizard\">\n <header class=\"admin-page__hd\">\n <div class=\"admin-page__title-wrap\">\n <h1 class=\"admin-page__title\">{{ title }}</h1>\n </div>\n <div class=\"admin-page__actions\">\n <UidButton variant=\"ghost\" @click=\"onCancel\">Отмена</UidButton>\n </div>\n </header>\n\n <UidStepper :steps=\"STEPS\" :current=\"currentStep\" />\n\n <!-- Step 1: Upload -->\n <UidCard v-if=\"currentStep === 0\" padding=\"md\" class=\"admin-import-wizard__card\">\n <header class=\"admin-import-wizard__card-hd\">\n <h3>1. Загрузите файл</h3>\n <p>CSV / TSV / XLSX, до 50 MB</p>\n </header>\n <UidFileUpload\n :model-value=\"uploadedFiles\"\n accept=\".csv,.tsv,.xlsx\"\n :max-size=\"50 * 1024 * 1024\"\n :max-files=\"1\"\n primary-text=\"Перетащите файл сюда или\"\n secondary-text=\"нажмите чтобы выбрать\"\n @update:model-value=\"onUpload\"\n />\n </UidCard>\n\n <!-- Step 2: Mapping -->\n <UidCard v-else-if=\"currentStep === 1\" padding=\"md\" class=\"admin-import-wizard__card\">\n <header class=\"admin-import-wizard__card-hd\">\n <h3>2. Сопоставьте колонки</h3>\n <p>Выберите поле ресурса для каждой колонки файла</p>\n </header>\n\n <div v-if=\"headers.length === 0\" class=\"admin-import-wizard__empty\">\n Нет данных — host ещё не отдал headers. Загрузите файл сначала.\n </div>\n\n <div v-else class=\"admin-import-wizard__mapping\">\n <div v-for=\"h in headers\" :key=\"h.key\" class=\"admin-import-wizard__map-row\">\n <div class=\"admin-import-wizard__map-source\">\n <strong>{{ h.label }}</strong>\n <span v-if=\"h.sample\" class=\"admin-import-wizard__map-sample\">\n «{{ h.sample }}»\n </span>\n </div>\n <span class=\"admin-import-wizard__map-arrow\">→</span>\n <UidSelect\n :model-value=\"mapping[h.key] ?? ''\"\n :options=\"fileOptions\"\n placeholder=\"Не импортировать\"\n @update:model-value=\"(v) => setTarget(h.key, v)\"\n />\n </div>\n </div>\n </UidCard>\n\n <!-- Step 3: Preview -->\n <UidCard v-else-if=\"currentStep === 2\" padding=\"md\" class=\"admin-import-wizard__card\">\n <header class=\"admin-import-wizard__card-hd\">\n <h3>3. Предпросмотр</h3>\n <p>Первые {{ preview.length }} строк перед импортом</p>\n </header>\n\n <UidAlert\n v-if=\"preview.some((r) => r.__warning)\"\n variant=\"warning\"\n style=\"margin-bottom: var(--uid-space-md);\"\n >\n Часть строк имеет предупреждения — проверьте перед импортом.\n </UidAlert>\n\n <UidTable\n v-if=\"previewColumns.length > 0\"\n :columns=\"previewColumns\"\n :data=\"preview\"\n />\n <div v-else class=\"admin-import-wizard__empty\">\n Host не передал previewColumns/preview.\n </div>\n </UidCard>\n\n <!-- Step 4: Run + Summary -->\n <UidCard v-else padding=\"md\" class=\"admin-import-wizard__card\">\n <header class=\"admin-import-wizard__card-hd\">\n <h3>4. Импорт</h3>\n </header>\n\n <div v-if=\"!progress\" class=\"admin-import-wizard__empty\">\n Запускается импорт…\n </div>\n <template v-else>\n <UidProgress\n v-if=\"progress.total > 0\"\n :model-value=\"progress.created + progress.updated + progress.errors\"\n :max=\"progress.total\"\n />\n <div class=\"admin-import-wizard__kpi\">\n <UidStat title=\"Создано\" :value=\"progress.created\" tone=\"success\" />\n <UidStat title=\"Обновлено\" :value=\"progress.updated\" tone=\"info\" />\n <UidStat title=\"Ошибки\" :value=\"progress.errors\" tone=\"danger\" />\n </div>\n </template>\n </UidCard>\n\n <!-- Navigation buttons -->\n <footer class=\"admin-import-wizard__nav\">\n <UidButton\n v-if=\"canGoBack\"\n variant=\"ghost\"\n @click=\"setStep(currentStep - 1)\"\n >\n Назад\n </UidButton>\n <span style=\"flex:1\" />\n <UidButton\n v-if=\"currentStep === 0\"\n variant=\"primary\"\n :disabled=\"!canGoNext\"\n @click=\"setStep(1)\"\n >\n Далее\n </UidButton>\n <UidButton\n v-else-if=\"currentStep === 1\"\n variant=\"primary\"\n :disabled=\"!canGoNext\"\n @click=\"onMappingSubmit\"\n >\n Подтвердить mapping\n </UidButton>\n <UidButton\n v-else-if=\"currentStep === 2\"\n variant=\"primary\"\n @click=\"onConfirmRun\"\n >\n Запустить импорт\n </UidButton>\n </footer>\n </section>\n</template>\n\n<style>\n.admin-import-wizard {\n max-width: 1100px;\n margin: 0 auto;\n}\n.admin-import-wizard__card {\n margin-top: var(--uid-space-md);\n}\n.admin-import-wizard__card-hd {\n margin-bottom: var(--uid-space-md);\n}\n.admin-import-wizard__card-hd h3 {\n margin: 0 0 var(--uid-space-2xs);\n font-size: var(--uid-font-size-md);\n font-weight: var(--uid-font-weight-semibold);\n}\n.admin-import-wizard__card-hd p {\n margin: 0;\n font-size: var(--uid-font-size-xs);\n color: var(--uid-text-tertiary);\n}\n.admin-import-wizard__empty {\n padding: var(--uid-space-md);\n text-align: center;\n color: var(--uid-text-tertiary);\n font-size: var(--uid-font-size-sm);\n}\n.admin-import-wizard__mapping {\n display: flex;\n flex-direction: column;\n gap: var(--uid-space-sm);\n}\n.admin-import-wizard__map-row {\n display: grid;\n grid-template-columns: 1fr auto 1fr;\n gap: var(--uid-space-md);\n align-items: center;\n}\n.admin-import-wizard__map-source {\n display: flex;\n align-items: center;\n gap: var(--uid-space-sm);\n}\n.admin-import-wizard__map-sample {\n color: var(--uid-text-tertiary);\n font-size: var(--uid-font-size-xs);\n font-style: italic;\n}\n.admin-import-wizard__map-arrow {\n color: var(--uid-text-tertiary);\n font-size: var(--uid-font-size-md);\n}\n.admin-import-wizard__kpi {\n display: grid;\n grid-template-columns: repeat(3, minmax(0, 1fr));\n gap: var(--uid-space-md);\n margin-top: var(--uid-space-md);\n}\n.admin-import-wizard__nav {\n display: flex;\n align-items: center;\n gap: var(--uid-space-sm);\n margin-top: var(--uid-space-md);\n}\n</style>\n","<script setup lang=\"ts\">\n/**\n * FieldGalleryPage — каталог field-компонентов.\n *\n * Эталон: docs/design_handoff_laravel_admin/screens-secondary.jsx (FieldGallery).\n *\n * 3-col grid из demo-cards. Каждая card:\n * - Group label (например \"Текстовые\")\n * - Тип поля (json type-key)\n * - Демо-компонент с sample-данными\n * - Краткое описание\n *\n * Используется как:\n * 1. Тестовая площадка для devs (визуально все Uid* fields на одной странице)\n * 2. Docs / referencer для host'ов\n *\n * Все секции рендерятся через FieldRenderer + provideFormState с локальной\n * state-mock'ой.\n */\nimport { reactive } from 'vue'\nimport { UidCard } from '@dskripchenko/ui'\nimport FieldRenderer, { type FieldNode } from '../render/FieldRenderer.vue'\nimport { provideFormState } from '../render/formState'\n\ninterface Demo {\n type: string\n group: string\n title: string\n description: string\n /** Demo node для FieldRenderer'а. */\n node: FieldNode\n /** Initial state для form-context. */\n initial: Record<string, unknown>\n}\n\nconst DEMOS: Demo[] = [\n // Текстовые\n {\n type: 'text',\n group: 'Текстовые',\n title: 'Input',\n description: 'Простой текстовый input. type=email/url/password/tel доступны через inputType.',\n node: { type: 'text', name: 'demo_text', label: 'Заголовок статьи', placeholder: 'Например: Введение в Laravel' },\n initial: { demo_text: 'Hello World' },\n },\n {\n type: 'textarea',\n group: 'Текстовые',\n title: 'Textarea',\n description: 'Многострочный input с настраиваемым числом rows.',\n node: { type: 'textarea', name: 'demo_textarea', label: 'Описание', rows: 4 },\n initial: { demo_textarea: 'Multi-line text...' },\n },\n {\n type: 'number',\n group: 'Текстовые',\n title: 'NumberInput',\n description: 'Числовой input. Empty/NaN автоматически конвертируются в null.',\n node: { type: 'number', name: 'demo_number', label: 'Цена', min: 0, max: 1000 },\n initial: { demo_number: 42 },\n },\n // Выбор\n {\n type: 'select',\n group: 'Выбор',\n title: 'Select',\n description: 'Single-select с options. Поддерживает searchable + clearable.',\n node: {\n type: 'select',\n name: 'demo_select',\n label: 'Категория',\n options: [\n { value: 'frontend', label: 'Frontend' },\n { value: 'backend', label: 'Backend' },\n { value: 'devops', label: 'DevOps' },\n ],\n },\n initial: { demo_select: 'backend' },\n },\n {\n type: 'checkbox',\n group: 'Выбор',\n title: 'Checkbox',\n description: 'Boolean toggle. inlineLabel рядом с боксом.',\n node: { type: 'checkbox', name: 'demo_checkbox', label: 'Опубликовать', inlineLabel: 'Сделать доступным всем' },\n initial: { demo_checkbox: true },\n },\n // Дата/время\n {\n type: 'date',\n group: 'Дата/время',\n title: 'DatePicker',\n description: 'date / datetime-local / time через inputType.',\n node: { type: 'date', name: 'demo_date', label: 'Дата публикации', inputType: 'date' },\n initial: { demo_date: '2026-05-01' },\n },\n]\n\n// Группируем для рендера.\nconst groupedDemos = DEMOS.reduce<Record<string, Demo[]>>((acc, d) => {\n if (!acc[d.group]) acc[d.group] = []\n acc[d.group].push(d)\n return acc\n}, {})\n\n// provideFormState на корневом уровне — все demo'и шарят один form-context\n// (имена не пересекаются благодаря demo_ префиксу).\nconst allInitial = reactive<Record<string, unknown>>(\n DEMOS.reduce<Record<string, unknown>>((acc, d) => Object.assign(acc, d.initial), {}),\n)\nprovideFormState(allInitial)\n</script>\n\n<template>\n <section class=\"admin-page admin-field-gallery\">\n <header class=\"admin-page__hd\">\n <div class=\"admin-page__title-wrap\">\n <h1 class=\"admin-page__title\">Field Gallery</h1>\n <div class=\"admin-page__count\">\n Каталог встроенных field-компонентов library + примеры использования\n </div>\n </div>\n </header>\n\n <section v-for=\"(items, group) in groupedDemos\" :key=\"group\" class=\"admin-gallery__group\">\n <h2 class=\"admin-gallery__group-title\">{{ group }}</h2>\n <div class=\"admin-gallery__grid\">\n <UidCard\n v-for=\"demo in items\"\n :key=\"demo.type + demo.title\"\n padding=\"md\"\n class=\"admin-gallery__card\"\n >\n <header class=\"admin-gallery__card-hd\">\n <h3 class=\"admin-gallery__card-title\">{{ demo.title }}</h3>\n <code class=\"admin-gallery__card-type\">type: {{ demo.type }}</code>\n </header>\n <p class=\"admin-gallery__card-desc\">{{ demo.description }}</p>\n <div class=\"admin-gallery__card-demo\">\n <FieldRenderer :node=\"demo.node\" />\n </div>\n </UidCard>\n </div>\n </section>\n </section>\n</template>\n\n<style>\n.admin-gallery__group {\n margin-bottom: var(--uid-space-2xl);\n}\n.admin-gallery__group-title {\n margin: 0 0 var(--uid-space-md);\n font-size: var(--uid-font-size-lg);\n font-weight: var(--uid-font-weight-semibold);\n color: var(--uid-text-primary);\n}\n.admin-gallery__grid {\n display: grid;\n grid-template-columns: repeat(3, minmax(0, 1fr));\n gap: var(--uid-space-md);\n}\n@media (max-width: 960px) {\n .admin-gallery__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }\n}\n@media (max-width: 640px) {\n .admin-gallery__grid { grid-template-columns: 1fr; }\n}\n.admin-gallery__card {\n display: flex;\n flex-direction: column;\n}\n.admin-gallery__card-hd {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--uid-space-sm);\n margin-bottom: var(--uid-space-xs);\n}\n.admin-gallery__card-title {\n margin: 0;\n font-size: var(--uid-font-size-sm);\n font-weight: var(--uid-font-weight-semibold);\n}\n.admin-gallery__card-type {\n font-family: var(--uid-font-family-mono);\n font-size: 11px;\n color: var(--uid-text-tertiary);\n background: var(--uid-surface-base);\n padding: 1px 6px;\n border-radius: var(--uid-radius-sm);\n border: 1px solid var(--uid-border-subtle);\n}\n.admin-gallery__card-desc {\n margin: 0 0 var(--uid-space-md);\n font-size: var(--uid-font-size-xs);\n color: var(--uid-text-tertiary);\n line-height: var(--uid-line-height-normal);\n}\n.admin-gallery__card-demo {\n flex: 1;\n display: flex;\n flex-direction: column;\n justify-content: flex-end;\n}\n</style>\n"],"names":["_client","setAdminClient","client","getAdminClient","clearAdminClient","hasAdminClient","useThemeStore","defineStore","current","ref","available","isDark","computed","hydrate","bootstrap","applyHtmlAttr","applyLocal","theme","setTheme","previous","err","iconName","ariaLabel","toggle","next","_createElementBlock","_createElementVNode","useLocaleStore","applySideEffects","locale","setLocale","pick","loc","_createBlock","_unref","UidMenu","_hoisted_1","_toDisplayString","_openBlock","_Fragment","_renderList","UidMenuItem","$event","_createTextVNode","useNotificationsStore","items","unreadCount","loading","lastFilter","meta","hasUnread","load","filter","page","result","loadUnread","markAsRead","id","item","n","markAllAsRead","now","destroy","index","wasUnread","notifications","display","RouterLink","ApiError","status","payload","UnauthenticatedError","ForbiddenError","NotFoundError","ValidationError","messages","NetworkError","message","toApiError","useAuthStore","user","permissions","pendingChallenge","isAuthenticated","isChallengePending","hasPermission","key","permission","prefix","hasAnyPermission","keys","hasAllPermissions","login","challengeToken","twoFactorChallenge","code","twoFactorRecovery","recoveryCode","cancelChallenge","logout","auth","router","useRouter","goProfile","_createVNode","UidAvatar","_cache","UidMenuSeparator","props","__props","emit","__emit","lastIdx","_hoisted_2","_renderSlot","_ctx","crumb","idx","_hoisted_3","_resolveDynamicComponent","_normalizeClass","NotificationBell","ThemeToggle","LocaleSwitcher","UserMenu","useMenuStore","error","isLoaded","visibleItems","it","filteredChildren","c","i","groupedItems","groups","groupKey","group","list","a","b","orderDiff","force","response","setItems","reset","menu","route","useRoute","isActive","iconSlot","name","h","itemTarget","UidSidebar","_createSlots","_hoisted_4","grp","UidSidebarGroup","UidSidebarItem","_hoisted_5","_hoisted_6","_hoisted_7","HTML_ATTR","onCollapseChange","value","exitImpersonation","watch","val","onBeforeUnmount","UidSidebarLayout","AdminSidebar","AdminTopBar","useNavigationStore","pending","isLoading","start","end","nav","visible","hideTimer","cls","useShell","AdminLoadingBar","AdminShell","_component_router_view","_withCtx","Component","_Transition","useManifestStore","manifest","version","resources","screens","settings","plugins","getResource","slug","r","getScreen","s","getSettings","userName","UidCard","UidButton","title","email","password","remember","submitting","generalError","fieldErrors","emailError","passwordError","submit","UidAlert","UidInput","UidCheckbox","mode","cells","cellRefs","remaining","totpCode","isValid","setCellRef","el","onCellInput","event","target","digit","nextTick","onCellKeydown","onPaste","digits","res","cancel","switchMode","_","redirectToHome","onMounted","_hoisted_8","TwoFactorForm","LoginForm","DEFAULT_META","useResourceIndexStore","slowLoading","slowLoadingTimer","SLOW_LOADING_DELAY","search","filters","sortKey","sortDirection","selection","isEmpty","selectedCount","hasSelection","hasError","selectionState","row","rowId","setSlug","buildParams","override","params","ss","sk","dir","f","filtersMap","k","v","body","setSearch","setFilter","clearFilters","setSort","direction","toggleSort","setPage","toggleRow","toggleAllOnPage","clearSelection","isSelected","DEFAULT_DATETIME","DEFAULT_DATE","ISO_DATETIME_RE","formatCell","preset","formatDateString","formatMoney","formatBoolean","formatBytes","input","format","date","pad","w","tokens","out","ch","currency","decimals","trueLabel","falseLabel","resourceMeta","displayTitle","columns","col","columnMeta","cols","renderCell","slotProps","m","rowFromSlot","hasActiveFilters","showFilterBar","totalLabel","t","loadWithProgress","prev","onSortKeyUpdate","onSortDirUpdate","onSelectionUpdate","onPageChange","onRowClick","bulkAction","action","retryLoad","$router","_hoisted_9","_withKeys","e","_hoisted_11","UidSkeleton","UidErrorState","UidEmptyState","_hoisted_12","UidTable","_hoisted_13","UidPagination","useResourceFormStore","recordId","state","initial","errors","saving","deleting","isCreate","isEdit","isView","isDirty","replaceObject","prepareCreate","resourceSlug","defaults","targetMode","setField","setErrors","clearErrors","save","url","newId","createComponentRegistry","store","type","bundle","fields","layouts","registerField","getField","hasField","listFields","registerLayout","getLayout","hasLayout","listLayouts","clearRegistry","registerComponents","component","fieldProps","_type","rest","_normalizeProps","_mergeProps","UnknownField","resolved","layoutComponent","layoutProps","_kind","fieldNode","FieldRenderer","form","ctx","provideFormState","layoutNodes","titleLabel","statusValue","statusBadgeVariant","nextSlug","nextId","onSave","onDelete","onCancel","UidBadge","node","LayoutRenderer","entries","registerInfolistEntry","getInfolistEntry","hasInfolistEntry","listInfolistEntries","clearInfolistRegistry","registerInfolistEntries","KNOWN_LAYOUTS","entry","entryProps","_t","_k","_i","sectionTitle","sectionDescription","tabsActive","tabsList","child","_component_InfolistRenderer","_normalizeStyle","tab","_hoisted_10","UnknownEntry","RecordKey","provideRecord","record","provide","useRecord","inject","tryUseRecord","onEdit","InfolistRenderer","navItems","localSection","selectSection","profile","localeOptions","l","themeOptions","onAvatarReplace","on2FADisable","on2FARegenerate","has2FA","_hoisted_14","_hoisted_15","UidSelect","_hoisted_16","_hoisted_17","_hoisted_18","_hoisted_19","_hoisted_20","_hoisted_21","widgets","registerWidget","getWidget","hasWidget","listWidgets","clearWidgetRegistry","registerWidgets","widgetProps","_span","UnknownWidget","dashboard","d","resolvedWidgets","resolvedTitle","resolvedSubtitle","spanFor","WidgetRenderer","TONE_MAP","uidTone","UidStat","maxValue","bars","barWidth","bar","PALETTE","total","x","slices","cumulative","startAngle","endAngle","cx","cy","x1","y1","x2","y2","largeArc","path","UidHeatmap","UidGauge","registerBuiltinWidgets","StatWidget","BarChartWidget","DonutChartWidget","RecentTableWidget","HeatmapWidget","GaugeWidget","MarkdownWidget","isSuccess","env","isError","createAdminClient","opts","instance","axios","config","xsrf","readCookie","apiError","wrap","method","wrapBody","data","match","escapeRegex","pickResourcePermission","resource","ability","perm","pickSettingsPermission","pickScreenPermission","buildResourceRoutes","components","base","buildScreenRoute","screen","buildSettingsRoute","buildDashboardRoute","buildRoutesFromManifest","routes","createAuthGuard","loginRouteName","forbiddenRouteName","redirectQueryKey","to","permissionsMeta","createTitleGuard","template","brand","fallback","DYNAMIC_NAME_PREFIXES","isDynamicRouteName","p","createAdminRouter","history","createWebHistory","staticRoutes","notFoundRoute","createRouter","allRoutes","dynamic","useFormState","errorMsg","onUpdate","UidFormField","UidTextarea","UidNumberInput","checked","UidDatePicker","UidStack","defaultSpan","UidGrid","tabKey","localActive","UidTabs","UidTab","UidTabPanel","cidx","registerBuiltinComponents","TextField","TextAreaField","NumberField","SelectField","CheckboxField","DateField","RowsLayout","ColumnsLayout","SectionLayout","TabsLayout","resolvedVariant","flag","displayLabel","formatValue","UidDescriptionList","UidDescriptionItem","registerBuiltinInfolistEntries","TextEntry","BadgeEntry","IconEntry","KeyValueEntry","createAdminApp","options","pages","deriveBase","app","createApp","AdminApp","pinia","createPinia","LoginPage","HomePage","ForbiddenPage","NotFoundPage","ProfilePage","ResourceIndexPage","ResourceFormPage","ResourceViewPage","DashboardPage","SettingsPage","UnknownScreenPage","navStore","from","_from","resourceIndex","indexStore","manifestStore","authStore","menuStore","loadAndApply","newUser","oldUser","baseUrl","loadBootstrap","inline","readInlineBootstrap","readCsrfFromMeta","setOpen","activeFilter","markAllRead","onItemClick","onDestroy","itemKind","lvl","itemTitle","itemBody","relTime","iso","dt","diff","mins","hours","days","UidDrawer","STEPS","internalStep","currentStep","setStep","uploadedFiles","onUpload","files","mapping","setTarget","source","buildMapping","onMappingSubmit","onConfirmRun","canGoBack","canGoNext","fileOptions","UidStepper","UidFileUpload","UidProgress","DEMOS","groupedDemos","acc","allInitial","reactive","demo"],"mappings":"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"}