@dskripchenko/laravel-admin 1.26.0 → 1.27.0

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.
Files changed (104) hide show
  1. package/dist/api/bootstrap.d.ts +18 -17
  2. package/dist/api/client.d.ts +12 -11
  3. package/dist/api/envelope.d.ts +3 -3
  4. package/dist/api/errors.d.ts +7 -7
  5. package/dist/components/ScreenPage.vue.d.ts +1 -1
  6. package/dist/components/auth/LoginForm.vue.d.ts +2 -2
  7. package/dist/components/auth/LoginPage.vue.d.ts +5 -5
  8. package/dist/components/auth/index.d.ts +1 -1
  9. package/dist/components/createComponentRegistry.d.ts +6 -5
  10. package/dist/components/dashboard/ChartWidget.vue.d.ts +2 -2
  11. package/dist/components/dashboard/GaugeWidget.vue.d.ts +2 -2
  12. package/dist/components/dashboard/HeatmapWidget.vue.d.ts +2 -2
  13. package/dist/components/dashboard/IframeWidget.vue.d.ts +4 -3
  14. package/dist/components/dashboard/RecentTableWidget.vue.d.ts +4 -3
  15. package/dist/components/dashboard/StatWidget.vue.d.ts +8 -7
  16. package/dist/components/dashboard/TableWidget.vue.d.ts +3 -2
  17. package/dist/components/dashboard/WidgetConfigDialog.vue.d.ts +4 -4
  18. package/dist/components/dashboard/WidgetRenderer.vue.d.ts +1 -1
  19. package/dist/components/dashboard/builtin.d.ts +5 -4
  20. package/dist/components/dashboard/index.d.ts +1 -1
  21. package/dist/components/dashboard/registry.d.ts +5 -5
  22. package/dist/components/fields/BuilderField.vue.d.ts +1 -1
  23. package/dist/components/fields/DateField.vue.d.ts +3 -3
  24. package/dist/components/fields/GeneratedField.vue.d.ts +3 -3
  25. package/dist/components/fields/SelectField.vue.d.ts +3 -2
  26. package/dist/components/fields/TagsField.vue.d.ts +6 -6
  27. package/dist/components/fields/TranslatableField.vue.d.ts +2 -2
  28. package/dist/components/fields/WysiwygField.vue.d.ts +2 -2
  29. package/dist/components/fields/wysiwyg/quill/QuillField.vue.d.ts +3 -3
  30. package/dist/components/fields/wysiwyg/quill/index.d.ts +3 -3
  31. package/dist/components/fields/wysiwyg/tinymce/TinymceField.vue.d.ts +6 -5
  32. package/dist/components/fields/wysiwyg/tinymce/index.d.ts +3 -3
  33. package/dist/components/import/ImportWizardPage.vue.d.ts +9 -9
  34. package/dist/components/infolist/BadgeEntry.vue.d.ts +4 -4
  35. package/dist/components/infolist/InfolistRenderer.vue.d.ts +1 -1
  36. package/dist/components/infolist/TextEntry.vue.d.ts +3 -3
  37. package/dist/components/infolist/builtin.d.ts +6 -6
  38. package/dist/components/infolist/index.d.ts +1 -1
  39. package/dist/components/infolist/recordContext.d.ts +3 -3
  40. package/dist/components/infolist/registry.d.ts +7 -7
  41. package/dist/components/layouts/ColumnsLayout.vue.d.ts +2 -2
  42. package/dist/components/layouts/RowsLayout.vue.d.ts +1 -1
  43. package/dist/components/layouts/TabsLayout.vue.d.ts +12 -11
  44. package/dist/components/notifications/index.d.ts +5 -5
  45. package/dist/components/profile/ProfilePage.vue.d.ts +3 -3
  46. package/dist/components/profile/TwoFactorSetup.vue.d.ts +1 -1
  47. package/dist/components/render/builtin.d.ts +2 -2
  48. package/dist/components/render/formState.d.ts +18 -15
  49. package/dist/components/render/index.d.ts +1 -1
  50. package/dist/components/render/registry.d.ts +9 -9
  51. package/dist/components/resource/AdminFilterToolbar.vue.d.ts +3 -3
  52. package/dist/components/resource/AuditTimeline.vue.d.ts +4 -4
  53. package/dist/components/resource/FilterEditor.d.ts +4 -3
  54. package/dist/components/resource/InlineEditCell.vue.d.ts +4 -4
  55. package/dist/components/resource/ResourceFormPage.vue.d.ts +4 -4
  56. package/dist/components/resource/ResourceIndexPage.vue.d.ts +5 -5
  57. package/dist/components/resource/ResourceViewPage.vue.d.ts +7 -7
  58. package/dist/components/resource/cellFormat.d.ts +14 -12
  59. package/dist/components/resource/index.d.ts +1 -1
  60. package/dist/components/resource/statusLabel.d.ts +14 -13
  61. package/dist/components/shell/AdminShell.vue.d.ts +7 -7
  62. package/dist/components/shell/AdminSidebar.vue.d.ts +7 -7
  63. package/dist/components/shell/AdminSidebarNode.vue.d.ts +2 -2
  64. package/dist/components/shell/AdminTopBar.vue.d.ts +2 -2
  65. package/dist/components/shell/BrandLogo.vue.d.ts +3 -3
  66. package/dist/components/shell/iconRegistry.d.ts +10 -9
  67. package/dist/components/shell/index.d.ts +2 -2
  68. package/dist/composables/useAppReady.d.ts +12 -11
  69. package/dist/composables/useBrand.d.ts +4 -3
  70. package/dist/createAdminApp.d.ts +34 -33
  71. package/dist/formState-DeRZBwWH.js.map +1 -1
  72. package/dist/formState-yUTD6wAR.cjs.map +1 -1
  73. package/dist/i18n-BCRWWhHE.cjs.map +1 -1
  74. package/dist/i18n-DXndsABq.js.map +1 -1
  75. package/dist/index.cjs +4 -4
  76. package/dist/index.cjs.map +1 -1
  77. package/dist/index.d.ts +12 -10
  78. package/dist/index.mjs +3789 -3774
  79. package/dist/index.mjs.map +1 -1
  80. package/dist/quill.cjs.map +1 -1
  81. package/dist/quill.mjs.map +1 -1
  82. package/dist/router/builder.d.ts +15 -14
  83. package/dist/router/guards.d.ts +28 -27
  84. package/dist/router/index.d.ts +20 -18
  85. package/dist/stores/auth.d.ts +10 -10
  86. package/dist/stores/dashboard.d.ts +33 -32
  87. package/dist/stores/i18n.d.ts +5 -4
  88. package/dist/stores/index.d.ts +2 -2
  89. package/dist/stores/locale.d.ts +7 -6
  90. package/dist/stores/manifest.d.ts +64 -61
  91. package/dist/stores/menu.d.ts +58 -57
  92. package/dist/stores/navigation.d.ts +5 -5
  93. package/dist/stores/notifications.d.ts +5 -4
  94. package/dist/stores/registry.d.ts +7 -7
  95. package/dist/stores/resourceForm.d.ts +12 -10
  96. package/dist/stores/resourceIndex.d.ts +12 -10
  97. package/dist/stores/screen.d.ts +15 -12
  98. package/dist/stores/theme.d.ts +4 -3
  99. package/dist/stores/toast.d.ts +3 -2
  100. package/dist/style.css +1 -1
  101. package/dist/tinymce.cjs.map +1 -1
  102. package/dist/tinymce.mjs.map +1 -1
  103. package/dist/types/bootstrap.d.ts +9 -9
  104. package/package.json +1 -1
@@ -1,23 +1,24 @@
1
1
  import type { LayoutNode } from '../render/LayoutRenderer.vue';
2
2
  /**
3
- * Подпись статуса для шапки формы ресурса.
3
+ * The status label in the header of a resource's form.
4
4
  *
5
- * Шапка печатала СЫРОЕ значение (`active`) рядом с полностью русской формой,
6
- * хотя select двумя строками ниже показывал «Активен». Подписи приходят в
7
- * манифесте уже переведёнными (`Localize::options`) — переводить нечего,
8
- * достаточно в них заглянуть.
5
+ * The header printed the RAW value (`active`) beside a fully translated form,
6
+ * while the select two lines below showed "Active". The labels arrive in the
7
+ * manifest already translated, by `Localize::options` — there is nothing to
8
+ * translate, one only has to look at them.
9
9
  *
10
- * Живёт отдельным модулем, а не внутри SFC, чтобы проверяться тестом: внутри
11
- * компонента логика была непроверяемой, так дефект и уехал.
10
+ * It lives in a module of its own rather than inside the SFC so that a test
11
+ * can reach it: inside the component the logic was uncheckable, which is how
12
+ * the defect shipped.
12
13
  */
13
- /** Ищет поле по имени в дереве произвольной вложенности (вкладки → строки → поля). */
14
+ /** Finds a field by name in a tree of any depth: tabs → rows → fields. */
14
15
  export declare function findFieldNode(nodes: LayoutNode[], name: string): Record<string, unknown> | null;
15
16
  /**
16
- * Формат подписей допускает и карту `value => label`, и список
17
- * `[{value, label}]` — поддержаны оба, иначе часть ресурсов осталась бы с
18
- * машинным значением.
17
+ * The labels may come either as a `value => label` map or as a list of
18
+ * `[{value, label}]` — both are supported, or some resources would be left
19
+ * with the machine value.
19
20
  *
20
- * Без подходящей подписи возвращается само значение: машинное слово в шапке
21
- * лучше пустоты — по нему хотя бы видно, в каком состоянии запись.
21
+ * With no matching label the value itself is returned: a machine word in the
22
+ * header beats emptiness, since it at least shows what state the record is in.
22
23
  */
23
24
  export declare function resolveStatusLabel(nodes: LayoutNode[], value: string | null): string | null;
@@ -1,11 +1,11 @@
1
1
  interface ImpersonationData {
2
- /** Имя того, в кого вошли. */
2
+ /** Whom we are logged in as. */
3
3
  asName: string;
4
4
  }
5
5
  interface BrandData {
6
6
  name?: string;
7
7
  logo?: string | null;
8
- /** Короткий текстовый mark (1-2 символа) — если нет картинки-logo. */
8
+ /** A short textual mark (1-2 characters), used when there is no logo image. */
9
9
  mark?: string | null;
10
10
  favicon?: string | null;
11
11
  copyright?: string | null;
@@ -13,14 +13,14 @@ interface BrandData {
13
13
  }
14
14
  interface Props {
15
15
  /**
16
- * v-model:collapsed — состояние сворачивания. Опционально: если host
17
- * не передаёт, AdminShell использует internal ref'ом, чтобы collapse
18
- * toggle работал out-of-the-box.
16
+ * v-model:collapsed — the collapse state. Optional: when the host does not
17
+ * pass it, AdminShell keeps an internal ref so that the collapse toggle
18
+ * works out of the box.
19
19
  */
20
20
  collapsed?: boolean;
21
- /** Если задано — показывает amber-banner и сдвигает контент. */
21
+ /** When set, shows the amber banner and shifts the content down. */
22
22
  impersonation?: ImpersonationData | null;
23
- /** Брендинг (name/logo/copyright) из config('admin.brand') (BL-12). */
23
+ /** Branding (name/logo/copyright) from config('admin.brand'). */
24
24
  brand?: BrandData | null;
25
25
  }
26
26
  declare var __VLS_9: {}, __VLS_14: {
@@ -1,22 +1,22 @@
1
1
  interface Props {
2
2
  collapsed?: boolean;
3
- /** Заголовок бренда. */
3
+ /** The brand's title. */
4
4
  brandName?: string;
5
5
  /**
6
- * Custom mark (если задан — рендерится вместо BrandLogo). Полезно
7
- * host-проекту с собственным логотипом.
6
+ * A custom mark; when set it is rendered instead of BrandLogo. Useful to a
7
+ * host project with a logo of its own.
8
8
  */
9
9
  brandMark?: string | null;
10
- /** URL картинки-логотипа (приоритетнее brandMark/BrandLogo). */
10
+ /** The logo image's URL; it wins over brandMark and BrandLogo. */
11
11
  brandLogo?: string | null;
12
- /** Named-route для click'а по brand-row. */
12
+ /** The named route a click on the brand row leads to. */
13
13
  homeRouteName?: string;
14
- /** Тенант / workspace — опционально показывается под брендом. */
14
+ /** The tenant or workspace, optionally shown below the brand. */
15
15
  tenant?: {
16
16
  label: string;
17
17
  name: string;
18
18
  } | null;
19
- /** Версия + ссылка на docs в footer'е. */
19
+ /** The version and the docs link in the footer. */
20
20
  version?: string | null;
21
21
  docsUrl?: string | null;
22
22
  }
@@ -3,9 +3,9 @@ interface Props {
3
3
  item: MenuItem;
4
4
  depth?: number;
5
5
  collapsed?: boolean;
6
- /** Глубина, после которой включается stripe-режим (вместо роста indent). */
6
+ /** The depth past which the stripe mode replaces a growing indent. */
7
7
  stripeAt?: number;
8
- /** Шаг indent в px на каждый уровень (до stripeAt). */
8
+ /** How many pixels each level indents by, up to stripeAt. */
9
9
  indentStep?: number;
10
10
  }
11
11
  declare const _default: import("vue").DefineComponent<Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<Props> & Readonly<{}>, {
@@ -3,9 +3,9 @@ interface Crumb {
3
3
  to?: string | Record<string, unknown> | null;
4
4
  }
5
5
  interface Props {
6
- /** Хлебные крошки. Последний элемент — текущая страница (без to). */
6
+ /** The breadcrumbs. The last one is the current page and carries no `to`. */
7
7
  breadcrumbs?: Crumb[];
8
- /** Показывать кнопку collapse сайдбара (только в shell-layout'е). */
8
+ /** Whether to show the sidebar's collapse button; only inside the shell layout. */
9
9
  showCollapseToggle?: boolean;
10
10
  }
11
11
  declare var __VLS_5: {}, __VLS_11: {}, __VLS_17: {};
@@ -1,9 +1,9 @@
1
1
  interface Props {
2
- /** Сторона квадрата в px. */
2
+ /** The square's side, in pixels. */
3
3
  size?: number;
4
- /** Мигающий курсор. */
4
+ /** The blinking cursor. */
5
5
  animated?: boolean;
6
- /** color = бренд-палитра, mono = single-tone через currentColor. */
6
+ /** color uses the brand palette, mono a single tone through currentColor. */
7
7
  variant?: 'color' | 'mono';
8
8
  title?: string;
9
9
  }
@@ -1,18 +1,19 @@
1
1
  /**
2
- * Резолвер kebab-имени lucide-иконки → Vue-компонент.
2
+ * Resolves a lucide icon's kebab-case name into a Vue component.
3
3
  *
4
- * MenuItem.icon приходит из backend'а строкой (например 'file-text', 'users').
5
- * Чтобы не тащить весь lucide-vue-next в bundle — держим whitelist
6
- * популярных имён. Host может расширить через registerIcon(name, comp).
4
+ * MenuItem.icon arrives from the backend as a string — 'file-text', 'users'.
5
+ * So as not to drag the whole of lucide-vue-next into the bundle, we keep a
6
+ * whitelist of the popular names, and a host extends it through
7
+ * registerIcon(name, comp).
7
8
  *
8
- * Не найденное имя возвращает fallback (Box) — sidebar item никогда не
9
- * рендерится без иконки.
9
+ * A name that is not found falls back to Box, so a sidebar item is never
10
+ * rendered without an icon.
10
11
  */
11
12
  import type { Component } from 'vue';
12
13
  /**
13
- * Найти иконку по имени. Не найдена — null (вызывающий код решает рендерить
14
- * fallback или ничего).
14
+ * Finds an icon by name, returning null when there is none — the caller
15
+ * decides between the fallback and nothing at all.
15
16
  */
16
17
  export declare function resolveIcon(name: string | null | undefined): Component | null;
17
- /** Зарегистрировать дополнительную иконку (host-проект). */
18
+ /** Registers an extra icon, from a host project. */
18
19
  export declare function registerIcon(name: string, component: Component): void;
@@ -1,7 +1,7 @@
1
1
  /**
2
- * Public exports SFC-каркаса admin-панели.
2
+ * The public exports of the admin panel's SFC shell.
3
3
  *
4
- * Использование (host-проект):
4
+ * Usage, from a host project:
5
5
  *
6
6
  * import { AdminShell } from '@dskripchenko/laravel-admin'
7
7
  *
@@ -1,18 +1,19 @@
1
1
  import { type ComputedRef } from 'vue';
2
2
  /**
3
- * Один гейт готовности каркаса: меню и страница появляются вместе.
3
+ * One readiness gate for the whole shell: the menu and the page appear
4
+ * together.
4
5
  *
5
- * Замер на живом стенде показал двухтактную загрузку: на 236 мс отрисован
6
- * топбар с пустым сайдбаром и страница, которой в этой установке нет
7
- * (HomePage-заглушка «зарегистрируйте DashboardScreen»), и только на 510 мс
8
- * приходит manifest — меню наполняется, страница подменяется настоящей.
9
- * Четверть секунды пользователь смотрел на чужой экран, а потом всё
10
- * скачком переставлялось.
6
+ * Measured on the live stand, the load came in two beats: at 236 ms a topbar
7
+ * with an empty sidebar and a page that does not exist in this installation
8
+ * (the HomePage placeholder saying "register a DashboardScreen"), and only at
9
+ * 510 ms the manifest — the menu fills in and the real page replaces the
10
+ * placeholder. For a quarter of a second one looked at the wrong screen, and
11
+ * then everything jumped into place.
11
12
  *
12
- * Манифест и меню запрашиваются параллельно, поэтому ждать оба дешевле, чем
13
- * показывать полусобранный интерфейс. Гейт открывается по готовности обоих —
14
- * либо по страховочному таймауту: зависший запрос меню не имеет права
15
- * держать страницу вечно.
13
+ * The manifest and the menu are fetched in parallel, so waiting for both costs
14
+ * less than showing a half-assembled interface. The gate opens when both are
15
+ * ready — or on a safety timeout, since a hung menu request has no right to
16
+ * hold the page forever.
16
17
  */
17
18
  export declare const BOOT_GATE_TIMEOUT_MS = 1500;
18
19
  export declare function useAppReady(): ComputedRef<boolean>;
@@ -1,9 +1,10 @@
1
1
  import { type InjectionKey } from 'vue';
2
2
  import type { AdminBrand } from '../types/bootstrap';
3
3
  /**
4
- * Брендинг панели (name/logo/favicon/copyright) из bootstrap.brand
5
- * (config('admin.brand')). Провайдится в createAdminApp, потребляется
6
- * shell'ом. Host кастомизирует чисто через config — без патча библиотеки.
4
+ * The panel's branding — name, logo, favicon, copyright — from bootstrap.brand
5
+ * (config('admin.brand')). It is provided in createAdminApp and consumed by
6
+ * the shell. A host customizes it through the config alone, with no patching
7
+ * of the library.
7
8
  */
8
9
  export declare const BRAND_KEY: InjectionKey<AdminBrand>;
9
10
  export declare function useBrand(): AdminBrand;
@@ -1,11 +1,12 @@
1
1
  /**
2
- * createAdminApp — фабрика-helper для host-проектов.
2
+ * createAdminApp — the factory helper for host projects.
3
3
  *
4
- * Собирает Vue-app со всем нужным: Pinia, Router, AdminClient, hydrated
5
- * stores, built-in fields/layouts/widgets/infolist, default страницы.
6
- * Возвращает объект где `app` готов к `.mount('#admin-app')`.
4
+ * Assembles a Vue app with everything it needs: Pinia, the router, AdminClient,
5
+ * hydrated stores, the built-in fields/layouts/widgets/infolist entries and the
6
+ * default pages. Returns an object whose `app` is ready for
7
+ * `.mount('#admin-app')`.
7
8
  *
8
- * Минимальный пример (host's resources/js/admin.js):
9
+ * The minimal example, in a host's resources/js/admin.js:
9
10
  *
10
11
  * import { createAdminApp } from '@dskripchenko/laravel-admin'
11
12
  * import '@dskripchenko/laravel-admin/style.css'
@@ -13,7 +14,7 @@
13
14
  * const { app } = createAdminApp(window.__ADMIN_BOOTSTRAP__)
14
15
  * app.mount('#admin-app')
15
16
  *
16
- * Расширенное использование с переопределением страниц:
17
+ * A fuller example, with pages overridden:
17
18
  *
18
19
  * const { app } = createAdminApp(window.__ADMIN_BOOTSTRAP__, {
19
20
  * pages: { home: MyDashboard },
@@ -25,48 +26,48 @@ import { type AdminClient } from './api/client';
25
26
  import { type AdminRouter, type AdminRouterOptions } from './router';
26
27
  import type { AdminBootstrap } from './types/bootstrap';
27
28
  export interface CreateAdminAppPages {
28
- /** Login page. По умолчанию core'овский LoginPage. */
29
+ /** The login page; the library's LoginPage by default. */
29
30
  login?: Component;
30
- /** Главная (после login). По умолчанию HomePage. */
31
+ /** The landing page after login; HomePage by default. */
31
32
  home?: Component;
32
- /** 403. По умолчанию ForbiddenPage. */
33
+ /** 403; ForbiddenPage by default. */
33
34
  forbidden?: Component;
34
- /** 404. По умолчанию NotFoundPage. */
35
+ /** 404; NotFoundPage by default. */
35
36
  notFound?: Component;
36
- /** Уведомления. По умолчанию NotificationsPage. */
37
+ /** Notifications; NotificationsPage by default. */
37
38
  notifications?: Component;
38
- /** Профиль. По умолчанию ProfilePage. */
39
+ /** The profile; ProfilePage by default. */
39
40
  profile?: Component;
40
- /** Auth: forgot/reset password. По умолчанию core'овские. */
41
+ /** Auth: forgot and reset password; the library's own by default. */
41
42
  forgotPassword?: Component;
42
43
  resetPassword?: Component;
43
- /** Resource index/form/view. По умолчанию core'овские. */
44
+ /** Resource index/form/view; the library's own by default. */
44
45
  resourceIndex?: Component;
45
46
  resourceCreate?: Component;
46
47
  resourceEdit?: Component;
47
48
  resourceView?: Component;
48
- /** Dashboard страница (для роутов admin.dashboard.*). */
49
+ /** The dashboard page, behind the admin.dashboard.* routes. */
49
50
  dashboard?: Component;
50
- /** Settings page (для admin.settings.*). */
51
+ /** The settings page, behind admin.settings.*. */
51
52
  settings?: Component;
52
- /** Custom Screen page (для admin.screen.*). */
53
+ /** The custom screen page, behind admin.screen.*. */
53
54
  screen?: Component;
54
55
  }
55
56
  export interface CreateAdminAppOptions {
56
57
  /**
57
- * Базовый URL admin-панели. По умолчанию берётся из bootstrap.baseUrl
58
- * (если он pathname вида '/admin'), иначе '/admin'.
58
+ * Base URL of the admin panel. Taken from bootstrap.baseUrl when that is a
59
+ * pathname such as '/admin', otherwise '/admin'.
59
60
  */
60
61
  base?: string;
61
- /** Override отдельных страниц. */
62
+ /** Overrides for individual pages. */
62
63
  pages?: CreateAdminAppPages;
63
- /** Дополнительные опции router'а (extraRoutes, history, guards). */
64
+ /** Extra router options: extraRoutes, history, guards. */
64
65
  router?: Partial<Omit<AdminRouterOptions, 'components'>>;
65
- /** Hook для до-настройки app перед mount (app.use(plugin), app.provide(...)). */
66
+ /** A hook to finish configuring the app before mount: app.use(plugin), app.provide(…). */
66
67
  onAppCreated?: (app: App) => void;
67
68
  /**
68
- * Не вызывать manifestStore.load() автоматически. По умолчанию false —
69
- * createAdminApp сам подгружает manifest и выстраивает динамические роуты.
69
+ * Do not call manifestStore.load() automatically. False by default:
70
+ * createAdminApp loads the manifest itself and builds the dynamic routes.
70
71
  */
71
72
  skipManifestLoad?: boolean;
72
73
  }
@@ -76,15 +77,15 @@ export interface AdminAppHandle {
76
77
  client: AdminClient;
77
78
  }
78
79
  /**
79
- * Создать Vue admin-app, готовый к `.mount('#admin-app')`.
80
+ * Creates the Vue admin app, ready for `.mount('#admin-app')`.
80
81
  *
81
- * Шаги внутри:
82
- * 1. Pinia + AdminClient (axios через bootstrap.csrf/apiUrl).
83
- * 2. Hydrate auth/locale/theme/notifications stores из bootstrap.
84
- * 3. Регистрация built-in fields/layouts/widgets/infolist entries.
85
- * 4. Router со static-routes (login/home/profile/forbidden/notFound) +
86
- * async manifest load → replaceManifestRoutes для resource/screen/
87
- * settings/dashboard.
88
- * 5. Возврат `{ app, router, client }`. Host вызывает `app.mount(...)`.
82
+ * What happens inside:
83
+ * 1. Pinia and AdminClient — axios wired to bootstrap.csrf and apiUrl.
84
+ * 2. The auth/locale/theme/notifications stores are hydrated from bootstrap.
85
+ * 3. The built-in fields, layouts, widgets and infolist entries register.
86
+ * 4. The router is created with the static routes (login, home, profile,
87
+ * forbidden, notFound); the manifest then loads asynchronously and
88
+ * replaceManifestRoutes adds the resource/screen/settings/dashboard ones.
89
+ * 5. `{ app, router, client }` is returned; the host calls `app.mount(…)`.
89
90
  */
90
91
  export declare function createAdminApp(bootstrap: AdminBootstrap, options?: CreateAdminAppOptions): AdminAppHandle;
@@ -1 +1 @@
1
- {"version":3,"file":"formState-DeRZBwWH.js","sources":["../resources/ts/components/render/formState.ts"],"sourcesContent":["/**\n * Composable для form-state: предоставляет state + ошибки через provide/inject.\n *\n * Контейнер (Resource form / Settings page) вызывает `provideFormState()`,\n * Field-компоненты в дереве — `useFormState()` для чтения значения и\n * мутации поля.\n *\n * State — reactive proxy; setField мутирует ключ. Errors — отдельный\n * reactive Map (field-name → string[] messages).\n */\n\nimport { inject, provide, reactive, type InjectionKey } from 'vue'\n\nexport interface FormStateContext {\n state: Record<string, unknown>\n errors: Record<string, string[]>\n /** Контекст формы: FieldRenderer скрывает поля с visibility[mode]=false. */\n mode?: 'create' | 'update' | 'view'\n setField: (name: string, value: unknown) => void\n getField: (name: string) => unknown\n setError: (name: string, messages: string[] | null) => void\n setErrors: (next: Record<string, string[]>) => void\n clearErrors: () => void\n}\n\nconst FormStateKey: InjectionKey<FormStateContext> = Symbol('admin.form-state')\n\n/**\n * Создаёт form-context и provid'ит его потомкам.\n *\n * Переданный `initial`-object оборачивается в `reactive()` — мутации stora\n * видны и снаружи (caller владеет state'ом и может его читать после submit'а).\n *\n * @param initial Начальные значения state'а.\n * @param initialErrors Начальные ошибки (для повторного render'а после\n * ValidationError).\n */\nexport function provideFormState(\n initial: Record<string, unknown> = {},\n initialErrors: Record<string, string[]> = {},\n mode?: 'create' | 'update' | 'view',\n): FormStateContext {\n const state = reactive(initial)\n const errors = reactive<Record<string, string[]>>({ ...initialErrors })\n\n const ctx: FormStateContext = {\n state,\n errors,\n mode,\n setField(name, value) {\n ;(state as Record<string, unknown>)[name] = value\n // Очистить ошибки этого поля при изменении — стандартный UX.\n if (errors[name]) {\n delete errors[name]\n }\n },\n getField(name) {\n return (state as Record<string, unknown>)[name]\n },\n setError(name, messages) {\n if (messages === null || messages.length === 0) {\n delete errors[name]\n } else {\n errors[name] = messages\n }\n },\n setErrors(next) {\n for (const key of Object.keys(errors)) delete errors[key]\n Object.assign(errors, next)\n },\n clearErrors() {\n for (const key of Object.keys(errors)) delete errors[key]\n },\n }\n\n provide(FormStateKey, ctx)\n return ctx\n}\n\n/**\n * Получить form-context. Throws, если не вызван внутри `provideFormState()`.\n */\nexport function useFormState(): FormStateContext {\n const ctx = inject(FormStateKey)\n if (!ctx) {\n throw new Error('useFormState() called outside of provideFormState() scope')\n }\n return ctx\n}\n\n/** Опционально получить (null если нет). */\nexport function tryUseFormState(): FormStateContext | null {\n return inject(FormStateKey, null)\n}\n"],"names":["FormStateKey","provideFormState","initial","initialErrors","mode","state","reactive","errors","ctx","name","value","messages","next","key","provide","useFormState","inject","tryUseFormState"],"mappings":";AAyBA,MAAMA,2BAAsD,kBAAkB;AAYvE,SAASC,EACdC,IAAmC,CAAA,GACnCC,IAA0C,CAAA,GAC1CC,GACkB;AAClB,QAAMC,IAAQC,EAASJ,CAAO,GACxBK,IAASD,EAAmC,EAAE,GAAGH,GAAe,GAEhEK,IAAwB;AAAA,IAC5B,OAAAH;AAAA,IACA,QAAAE;AAAA,IACA,MAAAH;AAAA,IACA,SAASK,GAAMC,GAAO;AAClB,MAAAL,EAAkCI,CAAI,IAAIC,GAExCH,EAAOE,CAAI,KACb,OAAOF,EAAOE,CAAI;AAAA,IAEtB;AAAA,IACA,SAASA,GAAM;AACb,aAAQJ,EAAkCI,CAAI;AAAA,IAChD;AAAA,IACA,SAASA,GAAME,GAAU;AACvB,MAAIA,MAAa,QAAQA,EAAS,WAAW,IAC3C,OAAOJ,EAAOE,CAAI,IAElBF,EAAOE,CAAI,IAAIE;AAAA,IAEnB;AAAA,IACA,UAAUC,GAAM;AACd,iBAAWC,KAAO,OAAO,KAAKN,CAAM,EAAG,QAAOA,EAAOM,CAAG;AACxD,aAAO,OAAON,GAAQK,CAAI;AAAA,IAC5B;AAAA,IACA,cAAc;AACZ,iBAAWC,KAAO,OAAO,KAAKN,CAAM,EAAG,QAAOA,EAAOM,CAAG;AAAA,IAC1D;AAAA,EAAA;AAGF,SAAAC,EAAQd,GAAcQ,CAAG,GAClBA;AACT;AAKO,SAASO,IAAiC;AAC/C,QAAMP,IAAMQ,EAAOhB,CAAY;AAC/B,MAAI,CAACQ;AACH,UAAM,IAAI,MAAM,2DAA2D;AAE7E,SAAOA;AACT;AAGO,SAASS,IAA2C;AACzD,SAAOD,EAAOhB,GAAc,IAAI;AAClC;"}
1
+ {"version":3,"file":"formState-DeRZBwWH.js","sources":["../resources/ts/components/render/formState.ts"],"sourcesContent":["/**\n * The form-state composable: it exposes the state and the errors through\n * provide/inject.\n *\n * The container — a resource form, a settings page — calls\n * `provideFormState()`, and the field components in the tree call\n * `useFormState()` to read a value and change a field.\n *\n * The state is a reactive proxy that setField mutates by key; the errors are a\n * separate reactive map of field name → string[] messages.\n */\n\nimport { inject, provide, reactive, type InjectionKey } from 'vue'\n\nexport interface FormStateContext {\n state: Record<string, unknown>\n errors: Record<string, string[]>\n /** The form's context: FieldRenderer hides the fields with visibility[mode]=false. */\n mode?: 'create' | 'update' | 'view'\n setField: (name: string, value: unknown) => void\n getField: (name: string) => unknown\n setError: (name: string, messages: string[] | null) => void\n setErrors: (next: Record<string, string[]>) => void\n clearErrors: () => void\n}\n\nconst FormStateKey: InjectionKey<FormStateContext> = Symbol('admin.form-state')\n\n/**\n * Creates the form context and provides it to the descendants.\n *\n * The `initial` object given is wrapped into `reactive()`, so the mutations are\n * visible from outside too: the caller owns the state and may read it after a\n * submit.\n *\n * @param initial The state's initial values.\n * @param initialErrors The initial errors, for a re-render after a\n * ValidationError.\n */\nexport function provideFormState(\n initial: Record<string, unknown> = {},\n initialErrors: Record<string, string[]> = {},\n mode?: 'create' | 'update' | 'view',\n): FormStateContext {\n const state = reactive(initial)\n const errors = reactive<Record<string, string[]>>({ ...initialErrors })\n\n const ctx: FormStateContext = {\n state,\n errors,\n mode,\n setField(name, value) {\n ;(state as Record<string, unknown>)[name] = value\n // Clear that field's errors as it changes, as one expects.\n if (errors[name]) {\n delete errors[name]\n }\n },\n getField(name) {\n return (state as Record<string, unknown>)[name]\n },\n setError(name, messages) {\n if (messages === null || messages.length === 0) {\n delete errors[name]\n } else {\n errors[name] = messages\n }\n },\n setErrors(next) {\n for (const key of Object.keys(errors)) delete errors[key]\n Object.assign(errors, next)\n },\n clearErrors() {\n for (const key of Object.keys(errors)) delete errors[key]\n },\n }\n\n provide(FormStateKey, ctx)\n return ctx\n}\n\n/**\n * Returns the form context. It throws when called outside a\n * `provideFormState()`.\n */\nexport function useFormState(): FormStateContext {\n const ctx = inject(FormStateKey)\n if (!ctx) {\n throw new Error('useFormState() called outside of provideFormState() scope')\n }\n return ctx\n}\n\n/** The optional form: null when there is none. */\nexport function tryUseFormState(): FormStateContext | null {\n return inject(FormStateKey, null)\n}\n"],"names":["FormStateKey","provideFormState","initial","initialErrors","mode","state","reactive","errors","ctx","name","value","messages","next","key","provide","useFormState","inject","tryUseFormState"],"mappings":";AA0BA,MAAMA,2BAAsD,kBAAkB;AAavE,SAASC,EACdC,IAAmC,CAAA,GACnCC,IAA0C,CAAA,GAC1CC,GACkB;AAClB,QAAMC,IAAQC,EAASJ,CAAO,GACxBK,IAASD,EAAmC,EAAE,GAAGH,GAAe,GAEhEK,IAAwB;AAAA,IAC5B,OAAAH;AAAA,IACA,QAAAE;AAAA,IACA,MAAAH;AAAA,IACA,SAASK,GAAMC,GAAO;AAClB,MAAAL,EAAkCI,CAAI,IAAIC,GAExCH,EAAOE,CAAI,KACb,OAAOF,EAAOE,CAAI;AAAA,IAEtB;AAAA,IACA,SAASA,GAAM;AACb,aAAQJ,EAAkCI,CAAI;AAAA,IAChD;AAAA,IACA,SAASA,GAAME,GAAU;AACvB,MAAIA,MAAa,QAAQA,EAAS,WAAW,IAC3C,OAAOJ,EAAOE,CAAI,IAElBF,EAAOE,CAAI,IAAIE;AAAA,IAEnB;AAAA,IACA,UAAUC,GAAM;AACd,iBAAWC,KAAO,OAAO,KAAKN,CAAM,EAAG,QAAOA,EAAOM,CAAG;AACxD,aAAO,OAAON,GAAQK,CAAI;AAAA,IAC5B;AAAA,IACA,cAAc;AACZ,iBAAWC,KAAO,OAAO,KAAKN,CAAM,EAAG,QAAOA,EAAOM,CAAG;AAAA,IAC1D;AAAA,EAAA;AAGF,SAAAC,EAAQd,GAAcQ,CAAG,GAClBA;AACT;AAMO,SAASO,IAAiC;AAC/C,QAAMP,IAAMQ,EAAOhB,CAAY;AAC/B,MAAI,CAACQ;AACH,UAAM,IAAI,MAAM,2DAA2D;AAE7E,SAAOA;AACT;AAGO,SAASS,IAA2C;AACzD,SAAOD,EAAOhB,GAAc,IAAI;AAClC;"}
@@ -1 +1 @@
1
- {"version":3,"file":"formState-yUTD6wAR.cjs","sources":["../resources/ts/components/render/formState.ts"],"sourcesContent":["/**\n * Composable для form-state: предоставляет state + ошибки через provide/inject.\n *\n * Контейнер (Resource form / Settings page) вызывает `provideFormState()`,\n * Field-компоненты в дереве — `useFormState()` для чтения значения и\n * мутации поля.\n *\n * State — reactive proxy; setField мутирует ключ. Errors — отдельный\n * reactive Map (field-name → string[] messages).\n */\n\nimport { inject, provide, reactive, type InjectionKey } from 'vue'\n\nexport interface FormStateContext {\n state: Record<string, unknown>\n errors: Record<string, string[]>\n /** Контекст формы: FieldRenderer скрывает поля с visibility[mode]=false. */\n mode?: 'create' | 'update' | 'view'\n setField: (name: string, value: unknown) => void\n getField: (name: string) => unknown\n setError: (name: string, messages: string[] | null) => void\n setErrors: (next: Record<string, string[]>) => void\n clearErrors: () => void\n}\n\nconst FormStateKey: InjectionKey<FormStateContext> = Symbol('admin.form-state')\n\n/**\n * Создаёт form-context и provid'ит его потомкам.\n *\n * Переданный `initial`-object оборачивается в `reactive()` — мутации stora\n * видны и снаружи (caller владеет state'ом и может его читать после submit'а).\n *\n * @param initial Начальные значения state'а.\n * @param initialErrors Начальные ошибки (для повторного render'а после\n * ValidationError).\n */\nexport function provideFormState(\n initial: Record<string, unknown> = {},\n initialErrors: Record<string, string[]> = {},\n mode?: 'create' | 'update' | 'view',\n): FormStateContext {\n const state = reactive(initial)\n const errors = reactive<Record<string, string[]>>({ ...initialErrors })\n\n const ctx: FormStateContext = {\n state,\n errors,\n mode,\n setField(name, value) {\n ;(state as Record<string, unknown>)[name] = value\n // Очистить ошибки этого поля при изменении — стандартный UX.\n if (errors[name]) {\n delete errors[name]\n }\n },\n getField(name) {\n return (state as Record<string, unknown>)[name]\n },\n setError(name, messages) {\n if (messages === null || messages.length === 0) {\n delete errors[name]\n } else {\n errors[name] = messages\n }\n },\n setErrors(next) {\n for (const key of Object.keys(errors)) delete errors[key]\n Object.assign(errors, next)\n },\n clearErrors() {\n for (const key of Object.keys(errors)) delete errors[key]\n },\n }\n\n provide(FormStateKey, ctx)\n return ctx\n}\n\n/**\n * Получить form-context. Throws, если не вызван внутри `provideFormState()`.\n */\nexport function useFormState(): FormStateContext {\n const ctx = inject(FormStateKey)\n if (!ctx) {\n throw new Error('useFormState() called outside of provideFormState() scope')\n }\n return ctx\n}\n\n/** Опционально получить (null если нет). */\nexport function tryUseFormState(): FormStateContext | null {\n return inject(FormStateKey, null)\n}\n"],"names":["FormStateKey","provideFormState","initial","initialErrors","mode","state","reactive","errors","ctx","name","value","messages","next","key","provide","useFormState","inject","tryUseFormState"],"mappings":"oCAyBMA,SAAsD,kBAAkB,EAYvE,SAASC,EACdC,EAAmC,CAAA,EACnCC,EAA0C,CAAA,EAC1CC,EACkB,CAClB,MAAMC,EAAQC,EAAAA,SAASJ,CAAO,EACxBK,EAASD,EAAAA,SAAmC,CAAE,GAAGH,EAAe,EAEhEK,EAAwB,CAC5B,MAAAH,EACA,OAAAE,EACA,KAAAH,EACA,SAASK,EAAMC,EAAO,CAClBL,EAAkCI,CAAI,EAAIC,EAExCH,EAAOE,CAAI,GACb,OAAOF,EAAOE,CAAI,CAEtB,EACA,SAASA,EAAM,CACb,OAAQJ,EAAkCI,CAAI,CAChD,EACA,SAASA,EAAME,EAAU,CACnBA,IAAa,MAAQA,EAAS,SAAW,EAC3C,OAAOJ,EAAOE,CAAI,EAElBF,EAAOE,CAAI,EAAIE,CAEnB,EACA,UAAUC,EAAM,CACd,UAAWC,KAAO,OAAO,KAAKN,CAAM,EAAG,OAAOA,EAAOM,CAAG,EACxD,OAAO,OAAON,EAAQK,CAAI,CAC5B,EACA,aAAc,CACZ,UAAWC,KAAO,OAAO,KAAKN,CAAM,EAAG,OAAOA,EAAOM,CAAG,CAC1D,CAAA,EAGFC,OAAAA,EAAAA,QAAQd,EAAcQ,CAAG,EAClBA,CACT,CAKO,SAASO,GAAiC,CAC/C,MAAMP,EAAMQ,EAAAA,OAAOhB,CAAY,EAC/B,GAAI,CAACQ,EACH,MAAM,IAAI,MAAM,2DAA2D,EAE7E,OAAOA,CACT,CAGO,SAASS,GAA2C,CACzD,OAAOD,EAAAA,OAAOhB,EAAc,IAAI,CAClC"}
1
+ {"version":3,"file":"formState-yUTD6wAR.cjs","sources":["../resources/ts/components/render/formState.ts"],"sourcesContent":["/**\n * The form-state composable: it exposes the state and the errors through\n * provide/inject.\n *\n * The container — a resource form, a settings page — calls\n * `provideFormState()`, and the field components in the tree call\n * `useFormState()` to read a value and change a field.\n *\n * The state is a reactive proxy that setField mutates by key; the errors are a\n * separate reactive map of field name → string[] messages.\n */\n\nimport { inject, provide, reactive, type InjectionKey } from 'vue'\n\nexport interface FormStateContext {\n state: Record<string, unknown>\n errors: Record<string, string[]>\n /** The form's context: FieldRenderer hides the fields with visibility[mode]=false. */\n mode?: 'create' | 'update' | 'view'\n setField: (name: string, value: unknown) => void\n getField: (name: string) => unknown\n setError: (name: string, messages: string[] | null) => void\n setErrors: (next: Record<string, string[]>) => void\n clearErrors: () => void\n}\n\nconst FormStateKey: InjectionKey<FormStateContext> = Symbol('admin.form-state')\n\n/**\n * Creates the form context and provides it to the descendants.\n *\n * The `initial` object given is wrapped into `reactive()`, so the mutations are\n * visible from outside too: the caller owns the state and may read it after a\n * submit.\n *\n * @param initial The state's initial values.\n * @param initialErrors The initial errors, for a re-render after a\n * ValidationError.\n */\nexport function provideFormState(\n initial: Record<string, unknown> = {},\n initialErrors: Record<string, string[]> = {},\n mode?: 'create' | 'update' | 'view',\n): FormStateContext {\n const state = reactive(initial)\n const errors = reactive<Record<string, string[]>>({ ...initialErrors })\n\n const ctx: FormStateContext = {\n state,\n errors,\n mode,\n setField(name, value) {\n ;(state as Record<string, unknown>)[name] = value\n // Clear that field's errors as it changes, as one expects.\n if (errors[name]) {\n delete errors[name]\n }\n },\n getField(name) {\n return (state as Record<string, unknown>)[name]\n },\n setError(name, messages) {\n if (messages === null || messages.length === 0) {\n delete errors[name]\n } else {\n errors[name] = messages\n }\n },\n setErrors(next) {\n for (const key of Object.keys(errors)) delete errors[key]\n Object.assign(errors, next)\n },\n clearErrors() {\n for (const key of Object.keys(errors)) delete errors[key]\n },\n }\n\n provide(FormStateKey, ctx)\n return ctx\n}\n\n/**\n * Returns the form context. It throws when called outside a\n * `provideFormState()`.\n */\nexport function useFormState(): FormStateContext {\n const ctx = inject(FormStateKey)\n if (!ctx) {\n throw new Error('useFormState() called outside of provideFormState() scope')\n }\n return ctx\n}\n\n/** The optional form: null when there is none. */\nexport function tryUseFormState(): FormStateContext | null {\n return inject(FormStateKey, null)\n}\n"],"names":["FormStateKey","provideFormState","initial","initialErrors","mode","state","reactive","errors","ctx","name","value","messages","next","key","provide","useFormState","inject","tryUseFormState"],"mappings":"oCA0BMA,SAAsD,kBAAkB,EAavE,SAASC,EACdC,EAAmC,CAAA,EACnCC,EAA0C,CAAA,EAC1CC,EACkB,CAClB,MAAMC,EAAQC,EAAAA,SAASJ,CAAO,EACxBK,EAASD,EAAAA,SAAmC,CAAE,GAAGH,EAAe,EAEhEK,EAAwB,CAC5B,MAAAH,EACA,OAAAE,EACA,KAAAH,EACA,SAASK,EAAMC,EAAO,CAClBL,EAAkCI,CAAI,EAAIC,EAExCH,EAAOE,CAAI,GACb,OAAOF,EAAOE,CAAI,CAEtB,EACA,SAASA,EAAM,CACb,OAAQJ,EAAkCI,CAAI,CAChD,EACA,SAASA,EAAME,EAAU,CACnBA,IAAa,MAAQA,EAAS,SAAW,EAC3C,OAAOJ,EAAOE,CAAI,EAElBF,EAAOE,CAAI,EAAIE,CAEnB,EACA,UAAUC,EAAM,CACd,UAAWC,KAAO,OAAO,KAAKN,CAAM,EAAG,OAAOA,EAAOM,CAAG,EACxD,OAAO,OAAON,EAAQK,CAAI,CAC5B,EACA,aAAc,CACZ,UAAWC,KAAO,OAAO,KAAKN,CAAM,EAAG,OAAOA,EAAOM,CAAG,CAC1D,CAAA,EAGFC,OAAAA,EAAAA,QAAQd,EAAcQ,CAAG,EAClBA,CACT,CAMO,SAASO,GAAiC,CAC/C,MAAMP,EAAMQ,EAAAA,OAAOhB,CAAY,EAC/B,GAAI,CAACQ,EACH,MAAM,IAAI,MAAM,2DAA2D,EAE7E,OAAOA,CACT,CAGO,SAASS,GAA2C,CACzD,OAAOD,EAAAA,OAAOhB,EAAc,IAAI,CAClC"}
@@ -1 +1 @@
1
- {"version":3,"file":"i18n-BCRWWhHE.cjs","sources":["../resources/ts/stores/i18n.ts"],"sourcesContent":["/**\n * i18n store — простой message-bag + t() helper.\n *\n * Backend кладёт translations bag в `bootstrap.translations` (Record<key, string>).\n * При смене локали (`/system/setLocale`) bootstrap переподнимается либо\n * helper зовёт `loadLocale(locale)`, который POST'ит messages.\n *\n * Формат:\n * t('admin.dashboard.add_widget') // 'Add widget'\n * t('admin.records.count', { n: 42 }) // 'Записей: 42' (interpolation :n)\n *\n * Fallback: если ключ не найден — возвращает сам ключ (помогает быстро\n * увидеть отсутствующие переводы во время разработки).\n */\nimport { defineStore } from 'pinia'\nimport { computed, ref } from 'vue'\nimport type { AdminBootstrap } from '../types/bootstrap'\n\n/**\n * Standalone-обёртка над store.tr() для компонентов: не падает без активной\n * Pinia (unit-тесты, SSR-edge) — возвращает исходную строку.\n */\nexport function trSafe(text: string): string {\n try {\n return useI18nStore().tr(text)\n } catch {\n return text\n }\n}\n\nexport const useI18nStore = defineStore('admin-i18n', () => {\n const messages = ref<Record<string, string>>({})\n const locale = ref<string>('ru')\n\n function hydrate(bootstrap: AdminBootstrap): void {\n // Backend кладёт translations в bootstrap (опционально).\n const t = (bootstrap as unknown as { translations?: Record<string, string> }).translations\n if (t && typeof t === 'object') {\n messages.value = { ...t }\n }\n locale.value = bootstrap.locale ?? 'ru'\n }\n\n function setMessages(next: Record<string, string>): void {\n messages.value = { ...next }\n }\n\n /**\n * Translate. Поддерживает interpolation вида `:name` (Laravel-стиль).\n * Если ключ отсутствует — возвращается сам ключ (visible-fallback).\n */\n function t(key: string, replace: Record<string, string | number> = {}): string {\n let str = messages.value[key] ?? key\n for (const [k, v] of Object.entries(replace)) {\n str = str.replace(new RegExp(`:${k}`, 'g'), String(v))\n }\n return str\n }\n\n const has = (key: string): boolean => key in messages.value\n\n /**\n * Перевод по строке-ключу (JSON-стиль, ключ = исходная строка на языке\n * разработки). Backend подмешивает в bag JSON-переводы текущей локали\n * (lang/{locale}.json хоста) — BL-11. Без перевода строка возвращается\n * как есть, интерполяция не применяется.\n */\n function tr(text: string): string {\n return messages.value[text] ?? text\n }\n\n return {\n messages,\n locale,\n hydrate,\n setMessages,\n t,\n tr,\n has,\n keys: computed(() => Object.keys(messages.value)),\n }\n})\n\n/**\n * Convenience: глобальный t() для не-Vue контекстов (utils, services).\n * В Vue-компонентах предпочтительнее `const { t } = useI18nStore()`.\n */\nexport function tRaw(key: string, replace?: Record<string, string | number>): string {\n try {\n return useI18nStore().t(key, replace ?? {})\n } catch {\n // Без активной Pinia (юнит-тесты, отрисовка до инициализации) — исходная\n // строка с подставленными значениями. Раньше здесь летело исключение и\n // роняло компонент целиком: строка без перевода лучше пустой страницы.\n let str = key\n for (const [k, v] of Object.entries(replace ?? {})) {\n str = str.replace(new RegExp(`:${k}`, 'g'), String(v))\n }\n\n return str\n }\n}\n"],"names":["trSafe","text","useI18nStore","defineStore","messages","ref","locale","hydrate","bootstrap","t","setMessages","next","key","replace","str","k","v","has","tr","computed","tRaw"],"mappings":"uDAsBO,SAASA,EAAOC,EAAsB,CAC3C,GAAI,CACF,OAAOC,EAAA,EAAe,GAAGD,CAAI,CAC/B,MAAQ,CACN,OAAOA,CACT,CACF,CAEO,MAAMC,EAAeC,EAAAA,YAAY,aAAc,IAAM,CAC1D,MAAMC,EAAWC,EAAAA,IAA4B,EAAE,EACzCC,EAASD,EAAAA,IAAY,IAAI,EAE/B,SAASE,EAAQC,EAAiC,CAEhD,MAAMC,EAAKD,EAAmE,aAC1EC,GAAK,OAAOA,GAAM,WACpBL,EAAS,MAAQ,CAAE,GAAGK,CAAAA,GAExBH,EAAO,MAAQE,EAAU,QAAU,IACrC,CAEA,SAASE,EAAYC,EAAoC,CACvDP,EAAS,MAAQ,CAAE,GAAGO,CAAA,CACxB,CAMA,SAASF,EAAEG,EAAaC,EAA2C,GAAY,CAC7E,IAAIC,EAAMV,EAAS,MAAMQ,CAAG,GAAKA,EACjC,SAAW,CAACG,EAAGC,CAAC,IAAK,OAAO,QAAQH,CAAO,EACzCC,EAAMA,EAAI,QAAQ,IAAI,OAAO,IAAIC,CAAC,GAAI,GAAG,EAAG,OAAOC,CAAC,CAAC,EAEvD,OAAOF,CACT,CAEA,MAAMG,EAAOL,GAAyBA,KAAOR,EAAS,MAQtD,SAASc,EAAGjB,EAAsB,CAChC,OAAOG,EAAS,MAAMH,CAAI,GAAKA,CACjC,CAEA,MAAO,CACL,SAAAG,EACA,OAAAE,EACA,QAAAC,EACA,YAAAG,EACA,EAAAD,EACA,GAAAS,EACA,IAAAD,EACA,KAAME,EAAAA,SAAS,IAAM,OAAO,KAAKf,EAAS,KAAK,CAAC,CAAA,CAEpD,CAAC,EAMM,SAASgB,EAAKR,EAAaC,EAAmD,CACnF,GAAI,CACF,OAAOX,IAAe,EAAEU,EAAKC,GAAW,CAAA,CAAE,CAC5C,MAAQ,CAIN,IAAIC,EAAMF,EACV,SAAW,CAACG,EAAGC,CAAC,IAAK,OAAO,QAAQH,GAAW,CAAA,CAAE,EAC/CC,EAAMA,EAAI,QAAQ,IAAI,OAAO,IAAIC,CAAC,GAAI,GAAG,EAAG,OAAOC,CAAC,CAAC,EAGvD,OAAOF,CACT,CACF"}
1
+ {"version":3,"file":"i18n-BCRWWhHE.cjs","sources":["../resources/ts/stores/i18n.ts"],"sourcesContent":["/**\n * The i18n store — a plain message bag plus the t() helper.\n *\n * The backend puts the bag into `bootstrap.translations`, a\n * Record<key, string>. When the locale changes (`/system/setLocale`) either\n * the bootstrap is raised again or the helper calls `loadLocale(locale)`,\n * which POSTs for the messages.\n *\n * The form:\n * t('admin.dashboard.add_widget') // 'Add widget'\n * t('admin.records.count', { n: 42 }) // 'Records: 42', interpolating :n\n *\n * The fallback: a key that is not found is returned as it is, which makes\n * missing translations easy to spot during development.\n */\nimport { defineStore } from 'pinia'\nimport { computed, ref } from 'vue'\nimport type { AdminBootstrap } from '../types/bootstrap'\n\n/**\n * A standalone wrapper around store.tr() for the components: it does not fall\n * over without an active Pinia (unit tests, SSR edges) and returns the source\n * string instead.\n */\nexport function trSafe(text: string): string {\n try {\n return useI18nStore().tr(text)\n } catch {\n return text\n }\n}\n\nexport const useI18nStore = defineStore('admin-i18n', () => {\n const messages = ref<Record<string, string>>({})\n const locale = ref<string>('ru')\n\n function hydrate(bootstrap: AdminBootstrap): void {\n // The backend may put the translations into the bootstrap.\n const t = (bootstrap as unknown as { translations?: Record<string, string> }).translations\n if (t && typeof t === 'object') {\n messages.value = { ...t }\n }\n locale.value = bootstrap.locale ?? 'ru'\n }\n\n function setMessages(next: Record<string, string>): void {\n messages.value = { ...next }\n }\n\n /**\n * Translates, supporting Laravel-style `:name` interpolation. A missing key\n * is returned as it is, which makes the gap visible.\n */\n function t(key: string, replace: Record<string, string | number> = {}): string {\n let str = messages.value[key] ?? key\n for (const [k, v] of Object.entries(replace)) {\n str = str.replace(new RegExp(`:${k}`, 'g'), String(v))\n }\n return str\n }\n\n const has = (key: string): boolean => key in messages.value\n\n /**\n * Translates by a string key, JSON-style, where the key is the source string\n * in the development language. The backend mixes the current locale's JSON\n * translations — the host's lang/{locale}.json — into the bag. Without a\n * translation the string comes back untouched, with no interpolation.\n */\n function tr(text: string): string {\n return messages.value[text] ?? text\n }\n\n return {\n messages,\n locale,\n hydrate,\n setMessages,\n t,\n tr,\n has,\n keys: computed(() => Object.keys(messages.value)),\n }\n})\n\n/**\n * A convenience: the global t() for non-Vue contexts — utilities, services. In\n * a Vue component prefer `const { t } = useI18nStore()`.\n */\nexport function tRaw(key: string, replace?: Record<string, string | number>): string {\n try {\n return useI18nStore().t(key, replace ?? {})\n } catch {\n // Without an active Pinia — unit tests, a render before the\n // initialization — we return the source string with the values\n // substituted. This used to throw and take the whole component down: an\n // untranslated string beats an empty page.\n let str = key\n for (const [k, v] of Object.entries(replace ?? {})) {\n str = str.replace(new RegExp(`:${k}`, 'g'), String(v))\n }\n\n return str\n }\n}\n"],"names":["trSafe","text","useI18nStore","defineStore","messages","ref","locale","hydrate","bootstrap","t","setMessages","next","key","replace","str","k","v","has","tr","computed","tRaw"],"mappings":"uDAwBO,SAASA,EAAOC,EAAsB,CAC3C,GAAI,CACF,OAAOC,EAAA,EAAe,GAAGD,CAAI,CAC/B,MAAQ,CACN,OAAOA,CACT,CACF,CAEO,MAAMC,EAAeC,EAAAA,YAAY,aAAc,IAAM,CAC1D,MAAMC,EAAWC,EAAAA,IAA4B,EAAE,EACzCC,EAASD,EAAAA,IAAY,IAAI,EAE/B,SAASE,EAAQC,EAAiC,CAEhD,MAAMC,EAAKD,EAAmE,aAC1EC,GAAK,OAAOA,GAAM,WACpBL,EAAS,MAAQ,CAAE,GAAGK,CAAAA,GAExBH,EAAO,MAAQE,EAAU,QAAU,IACrC,CAEA,SAASE,EAAYC,EAAoC,CACvDP,EAAS,MAAQ,CAAE,GAAGO,CAAA,CACxB,CAMA,SAASF,EAAEG,EAAaC,EAA2C,GAAY,CAC7E,IAAIC,EAAMV,EAAS,MAAMQ,CAAG,GAAKA,EACjC,SAAW,CAACG,EAAGC,CAAC,IAAK,OAAO,QAAQH,CAAO,EACzCC,EAAMA,EAAI,QAAQ,IAAI,OAAO,IAAIC,CAAC,GAAI,GAAG,EAAG,OAAOC,CAAC,CAAC,EAEvD,OAAOF,CACT,CAEA,MAAMG,EAAOL,GAAyBA,KAAOR,EAAS,MAQtD,SAASc,EAAGjB,EAAsB,CAChC,OAAOG,EAAS,MAAMH,CAAI,GAAKA,CACjC,CAEA,MAAO,CACL,SAAAG,EACA,OAAAE,EACA,QAAAC,EACA,YAAAG,EACA,EAAAD,EACA,GAAAS,EACA,IAAAD,EACA,KAAME,EAAAA,SAAS,IAAM,OAAO,KAAKf,EAAS,KAAK,CAAC,CAAA,CAEpD,CAAC,EAMM,SAASgB,EAAKR,EAAaC,EAAmD,CACnF,GAAI,CACF,OAAOX,IAAe,EAAEU,EAAKC,GAAW,CAAA,CAAE,CAC5C,MAAQ,CAKN,IAAIC,EAAMF,EACV,SAAW,CAACG,EAAGC,CAAC,IAAK,OAAO,QAAQH,GAAW,CAAA,CAAE,EAC/CC,EAAMA,EAAI,QAAQ,IAAI,OAAO,IAAIC,CAAC,GAAI,GAAG,EAAG,OAAOC,CAAC,CAAC,EAGvD,OAAOF,CACT,CACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"i18n-DXndsABq.js","sources":["../resources/ts/stores/i18n.ts"],"sourcesContent":["/**\n * i18n store — простой message-bag + t() helper.\n *\n * Backend кладёт translations bag в `bootstrap.translations` (Record<key, string>).\n * При смене локали (`/system/setLocale`) bootstrap переподнимается либо\n * helper зовёт `loadLocale(locale)`, который POST'ит messages.\n *\n * Формат:\n * t('admin.dashboard.add_widget') // 'Add widget'\n * t('admin.records.count', { n: 42 }) // 'Записей: 42' (interpolation :n)\n *\n * Fallback: если ключ не найден — возвращает сам ключ (помогает быстро\n * увидеть отсутствующие переводы во время разработки).\n */\nimport { defineStore } from 'pinia'\nimport { computed, ref } from 'vue'\nimport type { AdminBootstrap } from '../types/bootstrap'\n\n/**\n * Standalone-обёртка над store.tr() для компонентов: не падает без активной\n * Pinia (unit-тесты, SSR-edge) — возвращает исходную строку.\n */\nexport function trSafe(text: string): string {\n try {\n return useI18nStore().tr(text)\n } catch {\n return text\n }\n}\n\nexport const useI18nStore = defineStore('admin-i18n', () => {\n const messages = ref<Record<string, string>>({})\n const locale = ref<string>('ru')\n\n function hydrate(bootstrap: AdminBootstrap): void {\n // Backend кладёт translations в bootstrap (опционально).\n const t = (bootstrap as unknown as { translations?: Record<string, string> }).translations\n if (t && typeof t === 'object') {\n messages.value = { ...t }\n }\n locale.value = bootstrap.locale ?? 'ru'\n }\n\n function setMessages(next: Record<string, string>): void {\n messages.value = { ...next }\n }\n\n /**\n * Translate. Поддерживает interpolation вида `:name` (Laravel-стиль).\n * Если ключ отсутствует — возвращается сам ключ (visible-fallback).\n */\n function t(key: string, replace: Record<string, string | number> = {}): string {\n let str = messages.value[key] ?? key\n for (const [k, v] of Object.entries(replace)) {\n str = str.replace(new RegExp(`:${k}`, 'g'), String(v))\n }\n return str\n }\n\n const has = (key: string): boolean => key in messages.value\n\n /**\n * Перевод по строке-ключу (JSON-стиль, ключ = исходная строка на языке\n * разработки). Backend подмешивает в bag JSON-переводы текущей локали\n * (lang/{locale}.json хоста) — BL-11. Без перевода строка возвращается\n * как есть, интерполяция не применяется.\n */\n function tr(text: string): string {\n return messages.value[text] ?? text\n }\n\n return {\n messages,\n locale,\n hydrate,\n setMessages,\n t,\n tr,\n has,\n keys: computed(() => Object.keys(messages.value)),\n }\n})\n\n/**\n * Convenience: глобальный t() для не-Vue контекстов (utils, services).\n * В Vue-компонентах предпочтительнее `const { t } = useI18nStore()`.\n */\nexport function tRaw(key: string, replace?: Record<string, string | number>): string {\n try {\n return useI18nStore().t(key, replace ?? {})\n } catch {\n // Без активной Pinia (юнит-тесты, отрисовка до инициализации) — исходная\n // строка с подставленными значениями. Раньше здесь летело исключение и\n // роняло компонент целиком: строка без перевода лучше пустой страницы.\n let str = key\n for (const [k, v] of Object.entries(replace ?? {})) {\n str = str.replace(new RegExp(`:${k}`, 'g'), String(v))\n }\n\n return str\n }\n}\n"],"names":["trSafe","text","useI18nStore","defineStore","messages","ref","locale","hydrate","bootstrap","t","setMessages","next","key","replace","str","k","v","has","tr","computed","tRaw"],"mappings":";;AAsBO,SAASA,EAAOC,GAAsB;AAC3C,MAAI;AACF,WAAOC,EAAA,EAAe,GAAGD,CAAI;AAAA,EAC/B,QAAQ;AACN,WAAOA;AAAA,EACT;AACF;AAEO,MAAMC,IAAeC,EAAY,cAAc,MAAM;AAC1D,QAAMC,IAAWC,EAA4B,EAAE,GACzCC,IAASD,EAAY,IAAI;AAE/B,WAASE,EAAQC,GAAiC;AAEhD,UAAMC,IAAKD,EAAmE;AAC9E,IAAIC,KAAK,OAAOA,KAAM,aACpBL,EAAS,QAAQ,EAAE,GAAGK,EAAAA,IAExBH,EAAO,QAAQE,EAAU,UAAU;AAAA,EACrC;AAEA,WAASE,EAAYC,GAAoC;AACvD,IAAAP,EAAS,QAAQ,EAAE,GAAGO,EAAA;AAAA,EACxB;AAMA,WAASF,EAAEG,GAAaC,IAA2C,IAAY;AAC7E,QAAIC,IAAMV,EAAS,MAAMQ,CAAG,KAAKA;AACjC,eAAW,CAACG,GAAGC,CAAC,KAAK,OAAO,QAAQH,CAAO;AACzC,MAAAC,IAAMA,EAAI,QAAQ,IAAI,OAAO,IAAIC,CAAC,IAAI,GAAG,GAAG,OAAOC,CAAC,CAAC;AAEvD,WAAOF;AAAA,EACT;AAEA,QAAMG,IAAM,CAACL,MAAyBA,KAAOR,EAAS;AAQtD,WAASc,EAAGjB,GAAsB;AAChC,WAAOG,EAAS,MAAMH,CAAI,KAAKA;AAAA,EACjC;AAEA,SAAO;AAAA,IACL,UAAAG;AAAA,IACA,QAAAE;AAAA,IACA,SAAAC;AAAA,IACA,aAAAG;AAAA,IACA,GAAAD;AAAA,IACA,IAAAS;AAAA,IACA,KAAAD;AAAA,IACA,MAAME,EAAS,MAAM,OAAO,KAAKf,EAAS,KAAK,CAAC;AAAA,EAAA;AAEpD,CAAC;AAMM,SAASgB,EAAKR,GAAaC,GAAmD;AACnF,MAAI;AACF,WAAOX,IAAe,EAAEU,GAAKC,KAAW,CAAA,CAAE;AAAA,EAC5C,QAAQ;AAIN,QAAIC,IAAMF;AACV,eAAW,CAACG,GAAGC,CAAC,KAAK,OAAO,QAAQH,KAAW,CAAA,CAAE;AAC/C,MAAAC,IAAMA,EAAI,QAAQ,IAAI,OAAO,IAAIC,CAAC,IAAI,GAAG,GAAG,OAAOC,CAAC,CAAC;AAGvD,WAAOF;AAAA,EACT;AACF;"}
1
+ {"version":3,"file":"i18n-DXndsABq.js","sources":["../resources/ts/stores/i18n.ts"],"sourcesContent":["/**\n * The i18n store — a plain message bag plus the t() helper.\n *\n * The backend puts the bag into `bootstrap.translations`, a\n * Record<key, string>. When the locale changes (`/system/setLocale`) either\n * the bootstrap is raised again or the helper calls `loadLocale(locale)`,\n * which POSTs for the messages.\n *\n * The form:\n * t('admin.dashboard.add_widget') // 'Add widget'\n * t('admin.records.count', { n: 42 }) // 'Records: 42', interpolating :n\n *\n * The fallback: a key that is not found is returned as it is, which makes\n * missing translations easy to spot during development.\n */\nimport { defineStore } from 'pinia'\nimport { computed, ref } from 'vue'\nimport type { AdminBootstrap } from '../types/bootstrap'\n\n/**\n * A standalone wrapper around store.tr() for the components: it does not fall\n * over without an active Pinia (unit tests, SSR edges) and returns the source\n * string instead.\n */\nexport function trSafe(text: string): string {\n try {\n return useI18nStore().tr(text)\n } catch {\n return text\n }\n}\n\nexport const useI18nStore = defineStore('admin-i18n', () => {\n const messages = ref<Record<string, string>>({})\n const locale = ref<string>('ru')\n\n function hydrate(bootstrap: AdminBootstrap): void {\n // The backend may put the translations into the bootstrap.\n const t = (bootstrap as unknown as { translations?: Record<string, string> }).translations\n if (t && typeof t === 'object') {\n messages.value = { ...t }\n }\n locale.value = bootstrap.locale ?? 'ru'\n }\n\n function setMessages(next: Record<string, string>): void {\n messages.value = { ...next }\n }\n\n /**\n * Translates, supporting Laravel-style `:name` interpolation. A missing key\n * is returned as it is, which makes the gap visible.\n */\n function t(key: string, replace: Record<string, string | number> = {}): string {\n let str = messages.value[key] ?? key\n for (const [k, v] of Object.entries(replace)) {\n str = str.replace(new RegExp(`:${k}`, 'g'), String(v))\n }\n return str\n }\n\n const has = (key: string): boolean => key in messages.value\n\n /**\n * Translates by a string key, JSON-style, where the key is the source string\n * in the development language. The backend mixes the current locale's JSON\n * translations — the host's lang/{locale}.json — into the bag. Without a\n * translation the string comes back untouched, with no interpolation.\n */\n function tr(text: string): string {\n return messages.value[text] ?? text\n }\n\n return {\n messages,\n locale,\n hydrate,\n setMessages,\n t,\n tr,\n has,\n keys: computed(() => Object.keys(messages.value)),\n }\n})\n\n/**\n * A convenience: the global t() for non-Vue contexts — utilities, services. In\n * a Vue component prefer `const { t } = useI18nStore()`.\n */\nexport function tRaw(key: string, replace?: Record<string, string | number>): string {\n try {\n return useI18nStore().t(key, replace ?? {})\n } catch {\n // Without an active Pinia — unit tests, a render before the\n // initialization — we return the source string with the values\n // substituted. This used to throw and take the whole component down: an\n // untranslated string beats an empty page.\n let str = key\n for (const [k, v] of Object.entries(replace ?? {})) {\n str = str.replace(new RegExp(`:${k}`, 'g'), String(v))\n }\n\n return str\n }\n}\n"],"names":["trSafe","text","useI18nStore","defineStore","messages","ref","locale","hydrate","bootstrap","t","setMessages","next","key","replace","str","k","v","has","tr","computed","tRaw"],"mappings":";;AAwBO,SAASA,EAAOC,GAAsB;AAC3C,MAAI;AACF,WAAOC,EAAA,EAAe,GAAGD,CAAI;AAAA,EAC/B,QAAQ;AACN,WAAOA;AAAA,EACT;AACF;AAEO,MAAMC,IAAeC,EAAY,cAAc,MAAM;AAC1D,QAAMC,IAAWC,EAA4B,EAAE,GACzCC,IAASD,EAAY,IAAI;AAE/B,WAASE,EAAQC,GAAiC;AAEhD,UAAMC,IAAKD,EAAmE;AAC9E,IAAIC,KAAK,OAAOA,KAAM,aACpBL,EAAS,QAAQ,EAAE,GAAGK,EAAAA,IAExBH,EAAO,QAAQE,EAAU,UAAU;AAAA,EACrC;AAEA,WAASE,EAAYC,GAAoC;AACvD,IAAAP,EAAS,QAAQ,EAAE,GAAGO,EAAA;AAAA,EACxB;AAMA,WAASF,EAAEG,GAAaC,IAA2C,IAAY;AAC7E,QAAIC,IAAMV,EAAS,MAAMQ,CAAG,KAAKA;AACjC,eAAW,CAACG,GAAGC,CAAC,KAAK,OAAO,QAAQH,CAAO;AACzC,MAAAC,IAAMA,EAAI,QAAQ,IAAI,OAAO,IAAIC,CAAC,IAAI,GAAG,GAAG,OAAOC,CAAC,CAAC;AAEvD,WAAOF;AAAA,EACT;AAEA,QAAMG,IAAM,CAACL,MAAyBA,KAAOR,EAAS;AAQtD,WAASc,EAAGjB,GAAsB;AAChC,WAAOG,EAAS,MAAMH,CAAI,KAAKA;AAAA,EACjC;AAEA,SAAO;AAAA,IACL,UAAAG;AAAA,IACA,QAAAE;AAAA,IACA,SAAAC;AAAA,IACA,aAAAG;AAAA,IACA,GAAAD;AAAA,IACA,IAAAS;AAAA,IACA,KAAAD;AAAA,IACA,MAAME,EAAS,MAAM,OAAO,KAAKf,EAAS,KAAK,CAAC;AAAA,EAAA;AAEpD,CAAC;AAMM,SAASgB,EAAKR,GAAaC,GAAmD;AACnF,MAAI;AACF,WAAOX,IAAe,EAAEU,GAAKC,KAAW,CAAA,CAAE;AAAA,EAC5C,QAAQ;AAKN,QAAIC,IAAMF;AACV,eAAW,CAACG,GAAGC,CAAC,KAAK,OAAO,QAAQH,KAAW,CAAA,CAAE;AAC/C,MAAAC,IAAMA,EAAI,QAAQ,IAAI,OAAO,IAAIC,CAAC,IAAI,GAAG,GAAG,OAAOC,CAAC,CAAC;AAGvD,WAAOF;AAAA,EACT;AACF;"}