@saasicat/ui-vue 0.16.0 → 0.17.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 (40) hide show
  1. package/README.md +12 -11
  2. package/dist/{messages-DetB75lX.d.ts → catalog-C4Gv2_KM.d.cts} +115 -40
  3. package/dist/{messages-DetB75lX.d.cts → catalog-C4Gv2_KM.d.ts} +115 -40
  4. package/dist/{chunk-MGKJCVDU.js → chunk-247RJPU4.js} +18 -18
  5. package/dist/{chunk-TZ2NGQXK.js → chunk-IZGFS5RS.js} +44 -8
  6. package/dist/{chunk-CRUUZMMN.js → chunk-XPSD5HKG.js} +30 -4
  7. package/dist/client/index.cjs +75 -10
  8. package/dist/client/index.d.cts +51 -5
  9. package/dist/client/index.d.ts +51 -5
  10. package/dist/client/index.js +12 -4
  11. package/dist/index.cjs +90 -22
  12. package/dist/index.d.cts +5 -5
  13. package/dist/index.d.ts +5 -5
  14. package/dist/index.js +13 -5
  15. package/dist/quasar/index.cjs +54 -20
  16. package/dist/quasar/index.d.cts +2 -2
  17. package/dist/quasar/index.d.ts +2 -2
  18. package/dist/quasar/index.js +2 -2
  19. package/dist/{use-super-admin-i18n-DokHhkS_.d.cts → use-super-admin-i18n-BdPqeTHl.d.cts} +29 -9
  20. package/dist/{use-super-admin-i18n-BPC-H9jz.d.ts → use-super-admin-i18n-uteRCL9q.d.ts} +29 -9
  21. package/package.json +8 -3
  22. package/src/client/i18n/catalog.ts +120 -0
  23. package/src/client/i18n/currency.ts +7 -2
  24. package/src/client/i18n/define.ts +2 -2
  25. package/src/client/i18n/index.ts +1 -0
  26. package/src/client/i18n/locale.ts +40 -11
  27. package/src/client/i18n/messages/bundles.ts +2 -3
  28. package/src/client/i18n/messages/marketing.ts +2 -2
  29. package/src/client/i18n/messages/nav.ts +3 -3
  30. package/src/client/i18n/messages.ts +7 -4
  31. package/src/client/index.ts +1 -0
  32. package/src/client/login-branding.ts +61 -0
  33. package/src/client/nav-builder.ts +33 -6
  34. package/src/components/LocaleSwitcher.vue +21 -12
  35. package/src/components/bundle-editor/bundle-version-status.ts +16 -8
  36. package/src/pages-standard/AdminLayout.vue +7 -3
  37. package/src/pages-standard/SuperAdminLoginPage.vue +8 -9
  38. package/src/pages-standard/discovery-page/discovery-ui.ts +8 -8
  39. package/src/pages-standard/plan-versions/format.ts +2 -2
  40. package/src/vue/use-super-admin-i18n.ts +59 -28
@@ -1,10 +1,7 @@
1
1
  import {
2
- DEFAULT_SA_LOCALE,
3
- SA_INTL_LOCALES,
4
- defaultKvStore,
5
- isSaLocale,
6
- resolveMessages
7
- } from "./chunk-TZ2NGQXK.js";
2
+ createSaCatalog,
3
+ defaultKvStore
4
+ } from "./chunk-IZGFS5RS.js";
8
5
 
9
6
  // src/vue/super-admin-context.ts
10
7
  var SUPER_ADMIN_BRAND_KEY = /* @__PURE__ */ Symbol.for(
@@ -72,27 +69,30 @@ var SUPER_ADMIN_I18N_KEY = /* @__PURE__ */ Symbol.for(
72
69
  "@saasicat/ui-vue/SUPER_ADMIN_I18N"
73
70
  );
74
71
  function createSuperAdminI18n(options = {}) {
75
- const locale = isRef(options.locale) ? options.locale : createOwnedLocale(options);
76
- const messages = computed(
77
- () => resolveMessages(locale.value, options.overrides?.[locale.value])
72
+ const catalog = createSaCatalog(options);
73
+ const locale = isRef(options.locale) ? options.locale : createOwnedLocale(options, catalog);
74
+ const active = computed(
75
+ () => catalog.has(locale.value) ? locale.value : catalog.defaultLocale
78
76
  );
79
- const intlLocale = computed(() => SA_INTL_LOCALES[locale.value]);
77
+ const messages = computed(() => catalog.messagesFor(active.value));
78
+ const intlLocale = computed(() => catalog.intlLocaleFor(active.value));
80
79
  const writable = !isReadonly(locale);
81
80
  return {
82
81
  locale,
83
82
  messages,
84
83
  intlLocale,
85
- switcherEnabled: (options.switcher ?? true) && writable
84
+ switcherEnabled: (options.switcher ?? true) && writable && catalog.locales.length > 1,
85
+ availableLocales: catalog.locales
86
86
  };
87
87
  }
88
- function createOwnedLocale(options) {
89
- if (options.persist === false) {
90
- return ref(options.locale ?? DEFAULT_SA_LOCALE);
91
- }
88
+ function createOwnedLocale(options, catalog) {
89
+ const initial = options.locale ?? catalog.defaultLocale;
90
+ if (options.persist === false) return ref(initial);
92
91
  const storage = options.storage ?? defaultKvStore();
93
- const stored = storage.get(SA_LOCALE_STORAGE_KEY);
94
- const locale = ref(isSaLocale(stored) ? stored : options.locale ?? DEFAULT_SA_LOCALE);
95
- watch(locale, (next) => storage.set(SA_LOCALE_STORAGE_KEY, next));
92
+ const key = `${options.storageKeyPrefix ?? ""}${SA_LOCALE_STORAGE_KEY}`;
93
+ const stored = storage.get(key);
94
+ const locale = ref(stored && catalog.has(stored) ? stored : initial);
95
+ watch(locale, (next) => storage.set(key, next));
96
96
  return locale;
97
97
  }
98
98
  var fallbackI18n = null;
@@ -53,9 +53,12 @@ var SA_LOCALE_LABELS = {
53
53
  de: "Deutsch",
54
54
  en: "English"
55
55
  };
56
- function isSaLocale(value) {
56
+ function isSaBuiltinLocale(value) {
57
57
  return typeof value === "string" && SA_LOCALES.includes(value);
58
58
  }
59
+ function builtinLocaleOf(locale, fallback = DEFAULT_SA_LOCALE) {
60
+ return isSaBuiltinLocale(locale) ? locale : fallback;
61
+ }
59
62
 
60
63
  // src/client/i18n/define.ts
61
64
  function defineMessages(de, en) {
@@ -93,7 +96,7 @@ function formatterFor(locale, currency, decimals) {
93
96
  const key = `${locale}:${currency}:${decimals}`;
94
97
  let formatter = formatters.get(key);
95
98
  if (!formatter) {
96
- formatter = new Intl.NumberFormat(SA_INTL_LOCALES[locale], {
99
+ formatter = new Intl.NumberFormat(SA_INTL_LOCALES[locale] ?? locale, {
97
100
  style: "currency",
98
101
  currency,
99
102
  minimumFractionDigits: decimals,
@@ -259,7 +262,7 @@ var bundlesMessages = defineMessages(
259
262
  bundleKeyHint: "API-stabil \xB7 wird aus dem Label erzeugt",
260
263
  errorKeyFormat: "Nur A-Z, 0-9, Underscore; muss mit Buchstabe beginnen.",
261
264
  errorKeyExists: "Dieser Bundle-Key existiert bereits.",
262
- descriptionPlaceholder: "z. B. Kampagnen, WhatsApp und Korrespondenz f\xFCr aktive Vereine.",
265
+ descriptionPlaceholder: "z. B. Kampagnen, WhatsApp und Korrespondenz.",
263
266
  sectionPricing: "v1 \xB7 Pricing & G\xFCltigkeit",
264
267
  pricingHint: "Monats- & Jahrespreis sowie Datum, ab dem das Bundle verkaufbar wird.",
265
268
  validFromImmediate: "\u2713 Bundle ist nach Anlage sofort live und verkaufbar.",
@@ -471,7 +474,7 @@ var bundlesMessages = defineMessages(
471
474
  bundleKeyHint: "API-stable \xB7 derived from the label",
472
475
  errorKeyFormat: "Only A-Z, 0-9, underscore; must start with a letter.",
473
476
  errorKeyExists: "This bundle key already exists.",
474
- descriptionPlaceholder: "e.g. Campaigns, WhatsApp and correspondence for active clubs.",
477
+ descriptionPlaceholder: "e.g. Campaigns, WhatsApp and correspondence.",
475
478
  sectionPricing: "v1 \xB7 pricing & validity",
476
479
  pricingHint: "Monthly & yearly price plus the date from which the bundle becomes sellable.",
477
480
  validFromImmediate: "\u2713 The bundle is live and sellable right after creation.",
@@ -1145,7 +1148,7 @@ var marketingMessages = defineMessages(
1145
1148
  ctaOverrideLabel: "CTA-Text \xFCberschreiben (optional)",
1146
1149
  ctaOverrideHint: "leer lassen f\xFCr Auto-Text",
1147
1150
  topFeatureCount: "{count} Eintr\xE4ge",
1148
- featureLabelPlaceholder: "z. B. Beitragsverwaltung",
1151
+ featureLabelPlaceholder: "z. B. Erweiterte Berichte",
1149
1152
  featureStrongPlaceholder: "Highlight, z. B. bis 100",
1150
1153
  moveUp: "Nach oben",
1151
1154
  moveDown: "Nach unten",
@@ -1273,7 +1276,7 @@ var marketingMessages = defineMessages(
1273
1276
  ctaOverrideLabel: "Override CTA text (optional)",
1274
1277
  ctaOverrideHint: "leave empty for the auto text",
1275
1278
  topFeatureCount: "{count} entries",
1276
- featureLabelPlaceholder: "e.g. Membership management",
1279
+ featureLabelPlaceholder: "e.g. Advanced reporting",
1277
1280
  featureStrongPlaceholder: "Highlight, e.g. up to 100",
1278
1281
  moveUp: "Move up",
1279
1282
  moveDown: "Move down",
@@ -3109,6 +3112,37 @@ function resolveMessages(locale, overrides) {
3109
3112
  return mergeMessages(SA_MESSAGES[locale], overrides);
3110
3113
  }
3111
3114
 
3115
+ // src/client/i18n/catalog.ts
3116
+ function createSaCatalog(options = {}) {
3117
+ const additional = options.additionalLocales ?? {};
3118
+ const known = /* @__PURE__ */ new Set([...SA_LOCALES, ...Object.keys(additional)]);
3119
+ const requested = options.locales?.filter((code) => known.has(code));
3120
+ const offered = requested && requested.length > 0 ? requested : [...SA_LOCALES, ...Object.keys(additional)];
3121
+ const labelFor = (locale) => additional[locale]?.label ?? (isSaBuiltinLocale(locale) ? SA_LOCALE_LABELS[locale] : locale);
3122
+ const cache = /* @__PURE__ */ new Map();
3123
+ const messagesFor = (locale) => {
3124
+ const hit = cache.get(locale);
3125
+ if (hit) return hit;
3126
+ const definition = additional[locale];
3127
+ const base = SA_MESSAGES[definition?.basedOn ?? (isSaBuiltinLocale(locale) ? locale : "en")];
3128
+ const translated = definition ? mergeMessages(base, definition.messages) : base;
3129
+ const resolved = mergeMessages(translated, options.overrides?.[locale]);
3130
+ cache.set(locale, resolved);
3131
+ return resolved;
3132
+ };
3133
+ const offeredSet = new Set(offered);
3134
+ return {
3135
+ locales: offered.map((code) => ({ code, label: labelFor(code) })),
3136
+ has: (locale) => offeredSet.has(locale),
3137
+ // The app's first offered locale beats the platform default: an app
3138
+ // shipping English only must not start in German.
3139
+ defaultLocale: offered.includes(DEFAULT_SA_LOCALE) ? DEFAULT_SA_LOCALE : offered[0],
3140
+ messagesFor,
3141
+ intlLocaleFor: (locale) => additional[locale]?.intlLocale ?? (isSaBuiltinLocale(locale) ? SA_INTL_LOCALES[locale] : locale),
3142
+ labelFor
3143
+ };
3144
+ }
3145
+
3112
3146
  export {
3113
3147
  defaultKvStore,
3114
3148
  defaultHttpClient,
@@ -3116,12 +3150,14 @@ export {
3116
3150
  DEFAULT_SA_LOCALE,
3117
3151
  SA_INTL_LOCALES,
3118
3152
  SA_LOCALE_LABELS,
3119
- isSaLocale,
3153
+ isSaBuiltinLocale,
3154
+ builtinLocaleOf,
3120
3155
  defineMessages,
3121
3156
  mergeMessages,
3122
3157
  navMessages,
3123
3158
  formatMessage,
3124
3159
  formatCurrency,
3125
3160
  SA_MESSAGES,
3126
- resolveMessages
3161
+ resolveMessages,
3162
+ createSaCatalog
3127
3163
  };
@@ -2,8 +2,9 @@ import {
2
2
  DEFAULT_SA_LOCALE,
3
3
  defaultHttpClient,
4
4
  defaultKvStore,
5
+ isSaBuiltinLocale,
5
6
  navMessages
6
- } from "./chunk-TZ2NGQXK.js";
7
+ } from "./chunk-IZGFS5RS.js";
7
8
 
8
9
  // src/client/version.ts
9
10
  var ADMIN_UI_VERSION = "1.2.0";
@@ -213,15 +214,21 @@ var PAGE_SECTIONS = {
213
214
  platformEmail: "system",
214
215
  platformEmailHistory: "system"
215
216
  };
217
+ function resolveNav(options) {
218
+ return options.nav ?? builtinNav(options.locale);
219
+ }
220
+ function builtinNav(locale) {
221
+ return navMessages[isSaBuiltinLocale(locale) ? locale : DEFAULT_SA_LOCALE];
222
+ }
216
223
  function defaultSectionOrder(locale = DEFAULT_SA_LOCALE) {
217
- const sections = navMessages[locale].sections;
224
+ const sections = typeof locale === "string" ? builtinNav(locale).sections : locale.sections;
218
225
  return [sections.overview, sections.catalog, sections.customers, sections.system];
219
226
  }
220
227
  function buildRoutes(manifest, options = {}) {
221
228
  const routes = [];
222
229
  const capabilities = manifest.capabilities ?? {};
223
230
  const standard = manifest.navigation?.standardPages ?? {};
224
- const nav = navMessages[options.locale ?? DEFAULT_SA_LOCALE];
231
+ const nav = resolveNav(options);
225
232
  const defaultNavSections = Object.fromEntries(
226
233
  Object.entries(PAGE_SECTIONS).map(([page, section]) => [page, nav.sections[section]])
227
234
  );
@@ -541,6 +548,23 @@ function queryString(params) {
541
548
  return value ? `?${value}` : "";
542
549
  }
543
550
 
551
+ // src/client/login-branding.ts
552
+ var DEFAULT_TAG = "SuperAdmin";
553
+ function resolveLoginBranding(boot, fallback = {}) {
554
+ const project = boot?.project ?? null;
555
+ const environment = project?.environment ?? null;
556
+ return {
557
+ name: project?.displayName || fallback.name || "",
558
+ tag: project?.label || fallback.tag || DEFAULT_TAG,
559
+ icon: project?.icon || fallback.logoText || "",
560
+ logoUrl: project?.logoUrl || null,
561
+ environment: environment && environment !== "production" ? environment : null
562
+ };
563
+ }
564
+ function isProductionBoot(boot) {
565
+ return boot?.project?.environment === "production";
566
+ }
567
+
544
568
  export {
545
569
  ADMIN_UI_VERSION,
546
570
  HttpJsonError,
@@ -561,5 +585,7 @@ export {
561
585
  ActionRegistry,
562
586
  BatchColumnDriftError,
563
587
  BatchColumnFetcher,
564
- createAdminResourceClient
588
+ createAdminResourceClient,
589
+ resolveLoginBranding,
590
+ isProductionBoot
565
591
  };
@@ -39,7 +39,9 @@ __export(client_exports, {
39
39
  SA_MESSAGES: () => SA_MESSAGES,
40
40
  buildRoutes: () => buildRoutes,
41
41
  buildSidebar: () => buildSidebar,
42
+ builtinLocaleOf: () => builtinLocaleOf,
42
43
  createAdminResourceClient: () => createAdminResourceClient,
44
+ createSaCatalog: () => createSaCatalog,
43
45
  defaultHttpClient: () => defaultHttpClient,
44
46
  defaultKvStore: () => defaultKvStore,
45
47
  defaultSectionOrder: () => defaultSectionOrder,
@@ -47,10 +49,12 @@ __export(client_exports, {
47
49
  formatCurrency: () => formatCurrency,
48
50
  formatMessage: () => formatMessage,
49
51
  getJson: () => getJson,
50
- isSaLocale: () => isSaLocale,
52
+ isProductionBoot: () => isProductionBoot,
53
+ isSaBuiltinLocale: () => isSaBuiltinLocale,
51
54
  mergeMessages: () => mergeMessages,
52
55
  postJson: () => postJson,
53
56
  resolveExtension: () => resolveExtension,
57
+ resolveLoginBranding: () => resolveLoginBranding,
54
58
  resolveMessages: () => resolveMessages,
55
59
  trimTrailingSlashes: () => trimTrailingSlashes
56
60
  });
@@ -270,9 +274,12 @@ var SA_LOCALE_LABELS = {
270
274
  de: "Deutsch",
271
275
  en: "English"
272
276
  };
273
- function isSaLocale(value) {
277
+ function isSaBuiltinLocale(value) {
274
278
  return typeof value === "string" && SA_LOCALES.includes(value);
275
279
  }
280
+ function builtinLocaleOf(locale, fallback = DEFAULT_SA_LOCALE) {
281
+ return isSaBuiltinLocale(locale) ? locale : fallback;
282
+ }
276
283
 
277
284
  // src/client/i18n/define.ts
278
285
  function defineMessages(de, en) {
@@ -394,15 +401,21 @@ var PAGE_SECTIONS = {
394
401
  platformEmail: "system",
395
402
  platformEmailHistory: "system"
396
403
  };
404
+ function resolveNav(options) {
405
+ return options.nav ?? builtinNav(options.locale);
406
+ }
407
+ function builtinNav(locale) {
408
+ return navMessages[isSaBuiltinLocale(locale) ? locale : DEFAULT_SA_LOCALE];
409
+ }
397
410
  function defaultSectionOrder(locale = DEFAULT_SA_LOCALE) {
398
- const sections = navMessages[locale].sections;
411
+ const sections = typeof locale === "string" ? builtinNav(locale).sections : locale.sections;
399
412
  return [sections.overview, sections.catalog, sections.customers, sections.system];
400
413
  }
401
414
  function buildRoutes(manifest, options = {}) {
402
415
  const routes = [];
403
416
  const capabilities = manifest.capabilities ?? {};
404
417
  const standard = manifest.navigation?.standardPages ?? {};
405
- const nav = navMessages[options.locale ?? DEFAULT_SA_LOCALE];
418
+ const nav = resolveNav(options);
406
419
  const defaultNavSections = Object.fromEntries(
407
420
  Object.entries(PAGE_SECTIONS).map(([page, section]) => [page, nav.sections[section]])
408
421
  );
@@ -737,7 +750,7 @@ function formatterFor(locale, currency, decimals) {
737
750
  const key = `${locale}:${currency}:${decimals}`;
738
751
  let formatter = formatters.get(key);
739
752
  if (!formatter) {
740
- formatter = new Intl.NumberFormat(SA_INTL_LOCALES[locale], {
753
+ formatter = new Intl.NumberFormat(SA_INTL_LOCALES[locale] ?? locale, {
741
754
  style: "currency",
742
755
  currency,
743
756
  minimumFractionDigits: decimals,
@@ -903,7 +916,7 @@ var bundlesMessages = defineMessages(
903
916
  bundleKeyHint: "API-stabil \xB7 wird aus dem Label erzeugt",
904
917
  errorKeyFormat: "Nur A-Z, 0-9, Underscore; muss mit Buchstabe beginnen.",
905
918
  errorKeyExists: "Dieser Bundle-Key existiert bereits.",
906
- descriptionPlaceholder: "z. B. Kampagnen, WhatsApp und Korrespondenz f\xFCr aktive Vereine.",
919
+ descriptionPlaceholder: "z. B. Kampagnen, WhatsApp und Korrespondenz.",
907
920
  sectionPricing: "v1 \xB7 Pricing & G\xFCltigkeit",
908
921
  pricingHint: "Monats- & Jahrespreis sowie Datum, ab dem das Bundle verkaufbar wird.",
909
922
  validFromImmediate: "\u2713 Bundle ist nach Anlage sofort live und verkaufbar.",
@@ -1115,7 +1128,7 @@ var bundlesMessages = defineMessages(
1115
1128
  bundleKeyHint: "API-stable \xB7 derived from the label",
1116
1129
  errorKeyFormat: "Only A-Z, 0-9, underscore; must start with a letter.",
1117
1130
  errorKeyExists: "This bundle key already exists.",
1118
- descriptionPlaceholder: "e.g. Campaigns, WhatsApp and correspondence for active clubs.",
1131
+ descriptionPlaceholder: "e.g. Campaigns, WhatsApp and correspondence.",
1119
1132
  sectionPricing: "v1 \xB7 pricing & validity",
1120
1133
  pricingHint: "Monthly & yearly price plus the date from which the bundle becomes sellable.",
1121
1134
  validFromImmediate: "\u2713 The bundle is live and sellable right after creation.",
@@ -1789,7 +1802,7 @@ var marketingMessages = defineMessages(
1789
1802
  ctaOverrideLabel: "CTA-Text \xFCberschreiben (optional)",
1790
1803
  ctaOverrideHint: "leer lassen f\xFCr Auto-Text",
1791
1804
  topFeatureCount: "{count} Eintr\xE4ge",
1792
- featureLabelPlaceholder: "z. B. Beitragsverwaltung",
1805
+ featureLabelPlaceholder: "z. B. Erweiterte Berichte",
1793
1806
  featureStrongPlaceholder: "Highlight, z. B. bis 100",
1794
1807
  moveUp: "Nach oben",
1795
1808
  moveDown: "Nach unten",
@@ -1917,7 +1930,7 @@ var marketingMessages = defineMessages(
1917
1930
  ctaOverrideLabel: "Override CTA text (optional)",
1918
1931
  ctaOverrideHint: "leave empty for the auto text",
1919
1932
  topFeatureCount: "{count} entries",
1920
- featureLabelPlaceholder: "e.g. Membership management",
1933
+ featureLabelPlaceholder: "e.g. Advanced reporting",
1921
1934
  featureStrongPlaceholder: "Highlight, e.g. up to 100",
1922
1935
  moveUp: "Move up",
1923
1936
  moveDown: "Move down",
@@ -3702,6 +3715,54 @@ function resolveMessages(locale, overrides) {
3702
3715
  if (!overrides) return SA_MESSAGES[locale];
3703
3716
  return mergeMessages(SA_MESSAGES[locale], overrides);
3704
3717
  }
3718
+
3719
+ // src/client/i18n/catalog.ts
3720
+ function createSaCatalog(options = {}) {
3721
+ const additional = options.additionalLocales ?? {};
3722
+ const known = /* @__PURE__ */ new Set([...SA_LOCALES, ...Object.keys(additional)]);
3723
+ const requested = options.locales?.filter((code) => known.has(code));
3724
+ const offered = requested && requested.length > 0 ? requested : [...SA_LOCALES, ...Object.keys(additional)];
3725
+ const labelFor = (locale) => additional[locale]?.label ?? (isSaBuiltinLocale(locale) ? SA_LOCALE_LABELS[locale] : locale);
3726
+ const cache = /* @__PURE__ */ new Map();
3727
+ const messagesFor = (locale) => {
3728
+ const hit = cache.get(locale);
3729
+ if (hit) return hit;
3730
+ const definition = additional[locale];
3731
+ const base = SA_MESSAGES[definition?.basedOn ?? (isSaBuiltinLocale(locale) ? locale : "en")];
3732
+ const translated = definition ? mergeMessages(base, definition.messages) : base;
3733
+ const resolved = mergeMessages(translated, options.overrides?.[locale]);
3734
+ cache.set(locale, resolved);
3735
+ return resolved;
3736
+ };
3737
+ const offeredSet = new Set(offered);
3738
+ return {
3739
+ locales: offered.map((code) => ({ code, label: labelFor(code) })),
3740
+ has: (locale) => offeredSet.has(locale),
3741
+ // The app's first offered locale beats the platform default: an app
3742
+ // shipping English only must not start in German.
3743
+ defaultLocale: offered.includes(DEFAULT_SA_LOCALE) ? DEFAULT_SA_LOCALE : offered[0],
3744
+ messagesFor,
3745
+ intlLocaleFor: (locale) => additional[locale]?.intlLocale ?? (isSaBuiltinLocale(locale) ? SA_INTL_LOCALES[locale] : locale),
3746
+ labelFor
3747
+ };
3748
+ }
3749
+
3750
+ // src/client/login-branding.ts
3751
+ var DEFAULT_TAG = "SuperAdmin";
3752
+ function resolveLoginBranding(boot, fallback = {}) {
3753
+ const project = boot?.project ?? null;
3754
+ const environment = project?.environment ?? null;
3755
+ return {
3756
+ name: project?.displayName || fallback.name || "",
3757
+ tag: project?.label || fallback.tag || DEFAULT_TAG,
3758
+ icon: project?.icon || fallback.logoText || "",
3759
+ logoUrl: project?.logoUrl || null,
3760
+ environment: environment && environment !== "production" ? environment : null
3761
+ };
3762
+ }
3763
+ function isProductionBoot(boot) {
3764
+ return boot?.project?.environment === "production";
3765
+ }
3705
3766
  // Annotate the CommonJS export names for ESM import in node:
3706
3767
  0 && (module.exports = {
3707
3768
  ADMIN_UI_VERSION,
@@ -3723,7 +3784,9 @@ function resolveMessages(locale, overrides) {
3723
3784
  SA_MESSAGES,
3724
3785
  buildRoutes,
3725
3786
  buildSidebar,
3787
+ builtinLocaleOf,
3726
3788
  createAdminResourceClient,
3789
+ createSaCatalog,
3727
3790
  defaultHttpClient,
3728
3791
  defaultKvStore,
3729
3792
  defaultSectionOrder,
@@ -3731,10 +3794,12 @@ function resolveMessages(locale, overrides) {
3731
3794
  formatCurrency,
3732
3795
  formatMessage,
3733
3796
  getJson,
3734
- isSaLocale,
3797
+ isProductionBoot,
3798
+ isSaBuiltinLocale,
3735
3799
  mergeMessages,
3736
3800
  postJson,
3737
3801
  resolveExtension,
3802
+ resolveLoginBranding,
3738
3803
  resolveMessages,
3739
3804
  trimTrailingSlashes
3740
3805
  });
@@ -1,5 +1,5 @@
1
- import { H as HttpClient, K as KvStore, S as SaLocale } from '../messages-DetB75lX.cjs';
2
- export { d as ActionDefNotInManifestError, A as ActionHandler, c as ActionRegistry, D as DEFAULT_SA_LOCALE, e as HttpResponse, M as MessageTree, f as MissingHandlerError, P as PartialMessages, R as ResolvedAction, g as SA_INTL_LOCALES, h as SA_LOCALES, i as SA_LOCALE_LABELS, j as SA_MESSAGES, a as SaMessages, b as SaMessagesOverrides, T as TranslationOf, k as defaultHttpClient, l as defaultKvStore, m as defineMessages, n as isSaLocale, o as mergeMessages, r as resolveMessages } from '../messages-DetB75lX.cjs';
1
+ import { H as HttpClient, K as KvStore, S as SaLocale, x as SaNavMessages } from '../catalog-C4Gv2_KM.cjs';
2
+ export { f as ActionDefNotInManifestError, A as ActionHandler, e as ActionRegistry, D as DEFAULT_SA_LOCALE, g as HttpResponse, M as MessageTree, h as MissingHandlerError, P as PartialMessages, R as ResolvedAction, i as SA_INTL_LOCALES, j as SA_LOCALES, k as SA_LOCALE_LABELS, l as SA_MESSAGES, m as SaBuiltinLocale, n as SaCatalog, o as SaCatalogOptions, c as SaLocaleDefinition, b as SaLocaleOption, a as SaMessages, d as SaMessagesOverrides, T as TranslationOf, p as builtinLocaleOf, q as createSaCatalog, r as defaultHttpClient, s as defaultKvStore, t as defineMessages, u as isSaBuiltinLocale, v as mergeMessages, w as resolveMessages } from '../catalog-C4Gv2_KM.cjs';
3
3
  import { PublicBootResponse, AdminManifest, StandardPageKey, TenantColumnDef, PromoCodeRecord, AdminTenantDetail, AdminUserListFilter, AdminUserListRow, AdminAuditListFilter, AuditEntry, AdminSubscriptionListRow } from '@saasicat/types';
4
4
 
5
5
  declare const ADMIN_UI_VERSION = "1.2.0";
@@ -122,8 +122,17 @@ interface NavBuilderOptions {
122
122
  * UI locale for the default labels and section names, default `'de'`.
123
123
  * Pass the same locale to `buildSidebar()`'s `sectionOrder` (via
124
124
  * `defaultSectionOrder(locale)`) — section names are compared as strings.
125
+ *
126
+ * Only resolves the two catalogs the platform ships. Prefer `nav`, which
127
+ * carries app overrides and app-supplied languages as well.
125
128
  */
126
129
  locale?: SaLocale;
130
+ /**
131
+ * Resolved `nav` namespace, as `useSuperAdminI18n().messages.value.nav`
132
+ * hands it out. Wins over `locale`, and is the only way the sidebar sees
133
+ * `i18n.overrides` or a language the app added itself.
134
+ */
135
+ nav?: SaNavMessages;
127
136
  /**
128
137
  * Optional: overrides the default routes for certain standard pages.
129
138
  * Consumers set this if they want an alternative URL structure.
@@ -149,9 +158,11 @@ interface NavBuilderOptions {
149
158
  /**
150
159
  * Localized default section names in drawer order (Übersicht → Produktkatalog
151
160
  * → Kunden → System). Pass the result to `buildSidebar()` when building routes
152
- * with a non-default locale.
161
+ * with a non-default locale, or hand it the resolved `nav` catalog directly —
162
+ * section names are compared as strings, so both sides must come from the same
163
+ * source.
153
164
  */
154
- declare function defaultSectionOrder(locale?: SaLocale): readonly string[];
165
+ declare function defaultSectionOrder(locale?: SaLocale | SaNavMessages): readonly string[];
155
166
  /**
156
167
  * Returns the list of all routes defined by the current manifest —
157
168
  * filtered to the capabilities that the logged-in user has.
@@ -293,4 +304,39 @@ declare function formatMessage(template: string, params: MessageParams): string;
293
304
  */
294
305
  declare function formatCurrency(amount: number | string | null | undefined, locale?: SaLocale, currency?: string): string;
295
306
 
296
- export { ADMIN_UI_VERSION, type AdminPromoListFilter, type AdminPromoListRow, type AdminResourceClientOptions, type BatchColumnData, BatchColumnDriftError, BatchColumnFetcher, type BatchColumnFetcherOptions, type BatchColumnRow, type BatchColumnValue, BootLoadError, BootLoader, type BootLoaderOptions, type BuildRouteEntry, type CachedManifestEntry, DEFAULT_STANDARD_PAGE_ROUTES, HttpClient, HttpJsonError, KvStore, ManifestLoadError, ManifestLoader, type ManifestLoaderOptions, type MessageParams, type NavBuilderOptions, type ParamStyle, SaLocale, type SidebarItem, type SidebarSection, buildRoutes, buildSidebar, createAdminResourceClient, defaultSectionOrder, formatCurrency, formatMessage, getJson, postJson, resolveExtension, trimTrailingSlashes };
307
+ /** The slice of the public boot response these cards read. */
308
+ interface LoginBootProject {
309
+ displayName?: string | null;
310
+ label?: string | null;
311
+ icon?: string | null;
312
+ logoUrl?: string | null;
313
+ environment?: string | null;
314
+ }
315
+ /** App-configured branding, used wherever boot says nothing. */
316
+ interface LoginBrandFallback {
317
+ name?: string;
318
+ tag?: string;
319
+ logoText?: string;
320
+ }
321
+ interface LoginBranding {
322
+ name: string;
323
+ tag: string;
324
+ icon: string;
325
+ logoUrl: string | null;
326
+ /** Environment worth showing, i.e. anything but production. `null` hides it. */
327
+ environment: string | null;
328
+ }
329
+ /**
330
+ * `boot` is whatever the endpoint returned — possibly `null`, possibly an
331
+ * object without `project`. Both are treated as "boot said nothing" rather
332
+ * than as a reason to fail.
333
+ */
334
+ declare function resolveLoginBranding(boot: {
335
+ project?: LoginBootProject | null;
336
+ } | null | undefined, fallback?: LoginBrandFallback): LoginBranding;
337
+ /** Test credentials must never be printed in production, whatever boot omits. */
338
+ declare function isProductionBoot(boot: {
339
+ project?: LoginBootProject | null;
340
+ } | null | undefined): boolean;
341
+
342
+ export { ADMIN_UI_VERSION, type AdminPromoListFilter, type AdminPromoListRow, type AdminResourceClientOptions, type BatchColumnData, BatchColumnDriftError, BatchColumnFetcher, type BatchColumnFetcherOptions, type BatchColumnRow, type BatchColumnValue, BootLoadError, BootLoader, type BootLoaderOptions, type BuildRouteEntry, type CachedManifestEntry, DEFAULT_STANDARD_PAGE_ROUTES, HttpClient, HttpJsonError, KvStore, type LoginBootProject, type LoginBrandFallback, type LoginBranding, ManifestLoadError, ManifestLoader, type ManifestLoaderOptions, type MessageParams, type NavBuilderOptions, type ParamStyle, SaLocale, type SidebarItem, type SidebarSection, buildRoutes, buildSidebar, createAdminResourceClient, defaultSectionOrder, formatCurrency, formatMessage, getJson, isProductionBoot, postJson, resolveExtension, resolveLoginBranding, trimTrailingSlashes };
@@ -1,5 +1,5 @@
1
- import { H as HttpClient, K as KvStore, S as SaLocale } from '../messages-DetB75lX.js';
2
- export { d as ActionDefNotInManifestError, A as ActionHandler, c as ActionRegistry, D as DEFAULT_SA_LOCALE, e as HttpResponse, M as MessageTree, f as MissingHandlerError, P as PartialMessages, R as ResolvedAction, g as SA_INTL_LOCALES, h as SA_LOCALES, i as SA_LOCALE_LABELS, j as SA_MESSAGES, a as SaMessages, b as SaMessagesOverrides, T as TranslationOf, k as defaultHttpClient, l as defaultKvStore, m as defineMessages, n as isSaLocale, o as mergeMessages, r as resolveMessages } from '../messages-DetB75lX.js';
1
+ import { H as HttpClient, K as KvStore, S as SaLocale, x as SaNavMessages } from '../catalog-C4Gv2_KM.js';
2
+ export { f as ActionDefNotInManifestError, A as ActionHandler, e as ActionRegistry, D as DEFAULT_SA_LOCALE, g as HttpResponse, M as MessageTree, h as MissingHandlerError, P as PartialMessages, R as ResolvedAction, i as SA_INTL_LOCALES, j as SA_LOCALES, k as SA_LOCALE_LABELS, l as SA_MESSAGES, m as SaBuiltinLocale, n as SaCatalog, o as SaCatalogOptions, c as SaLocaleDefinition, b as SaLocaleOption, a as SaMessages, d as SaMessagesOverrides, T as TranslationOf, p as builtinLocaleOf, q as createSaCatalog, r as defaultHttpClient, s as defaultKvStore, t as defineMessages, u as isSaBuiltinLocale, v as mergeMessages, w as resolveMessages } from '../catalog-C4Gv2_KM.js';
3
3
  import { PublicBootResponse, AdminManifest, StandardPageKey, TenantColumnDef, PromoCodeRecord, AdminTenantDetail, AdminUserListFilter, AdminUserListRow, AdminAuditListFilter, AuditEntry, AdminSubscriptionListRow } from '@saasicat/types';
4
4
 
5
5
  declare const ADMIN_UI_VERSION = "1.2.0";
@@ -122,8 +122,17 @@ interface NavBuilderOptions {
122
122
  * UI locale for the default labels and section names, default `'de'`.
123
123
  * Pass the same locale to `buildSidebar()`'s `sectionOrder` (via
124
124
  * `defaultSectionOrder(locale)`) — section names are compared as strings.
125
+ *
126
+ * Only resolves the two catalogs the platform ships. Prefer `nav`, which
127
+ * carries app overrides and app-supplied languages as well.
125
128
  */
126
129
  locale?: SaLocale;
130
+ /**
131
+ * Resolved `nav` namespace, as `useSuperAdminI18n().messages.value.nav`
132
+ * hands it out. Wins over `locale`, and is the only way the sidebar sees
133
+ * `i18n.overrides` or a language the app added itself.
134
+ */
135
+ nav?: SaNavMessages;
127
136
  /**
128
137
  * Optional: overrides the default routes for certain standard pages.
129
138
  * Consumers set this if they want an alternative URL structure.
@@ -149,9 +158,11 @@ interface NavBuilderOptions {
149
158
  /**
150
159
  * Localized default section names in drawer order (Übersicht → Produktkatalog
151
160
  * → Kunden → System). Pass the result to `buildSidebar()` when building routes
152
- * with a non-default locale.
161
+ * with a non-default locale, or hand it the resolved `nav` catalog directly —
162
+ * section names are compared as strings, so both sides must come from the same
163
+ * source.
153
164
  */
154
- declare function defaultSectionOrder(locale?: SaLocale): readonly string[];
165
+ declare function defaultSectionOrder(locale?: SaLocale | SaNavMessages): readonly string[];
155
166
  /**
156
167
  * Returns the list of all routes defined by the current manifest —
157
168
  * filtered to the capabilities that the logged-in user has.
@@ -293,4 +304,39 @@ declare function formatMessage(template: string, params: MessageParams): string;
293
304
  */
294
305
  declare function formatCurrency(amount: number | string | null | undefined, locale?: SaLocale, currency?: string): string;
295
306
 
296
- export { ADMIN_UI_VERSION, type AdminPromoListFilter, type AdminPromoListRow, type AdminResourceClientOptions, type BatchColumnData, BatchColumnDriftError, BatchColumnFetcher, type BatchColumnFetcherOptions, type BatchColumnRow, type BatchColumnValue, BootLoadError, BootLoader, type BootLoaderOptions, type BuildRouteEntry, type CachedManifestEntry, DEFAULT_STANDARD_PAGE_ROUTES, HttpClient, HttpJsonError, KvStore, ManifestLoadError, ManifestLoader, type ManifestLoaderOptions, type MessageParams, type NavBuilderOptions, type ParamStyle, SaLocale, type SidebarItem, type SidebarSection, buildRoutes, buildSidebar, createAdminResourceClient, defaultSectionOrder, formatCurrency, formatMessage, getJson, postJson, resolveExtension, trimTrailingSlashes };
307
+ /** The slice of the public boot response these cards read. */
308
+ interface LoginBootProject {
309
+ displayName?: string | null;
310
+ label?: string | null;
311
+ icon?: string | null;
312
+ logoUrl?: string | null;
313
+ environment?: string | null;
314
+ }
315
+ /** App-configured branding, used wherever boot says nothing. */
316
+ interface LoginBrandFallback {
317
+ name?: string;
318
+ tag?: string;
319
+ logoText?: string;
320
+ }
321
+ interface LoginBranding {
322
+ name: string;
323
+ tag: string;
324
+ icon: string;
325
+ logoUrl: string | null;
326
+ /** Environment worth showing, i.e. anything but production. `null` hides it. */
327
+ environment: string | null;
328
+ }
329
+ /**
330
+ * `boot` is whatever the endpoint returned — possibly `null`, possibly an
331
+ * object without `project`. Both are treated as "boot said nothing" rather
332
+ * than as a reason to fail.
333
+ */
334
+ declare function resolveLoginBranding(boot: {
335
+ project?: LoginBootProject | null;
336
+ } | null | undefined, fallback?: LoginBrandFallback): LoginBranding;
337
+ /** Test credentials must never be printed in production, whatever boot omits. */
338
+ declare function isProductionBoot(boot: {
339
+ project?: LoginBootProject | null;
340
+ } | null | undefined): boolean;
341
+
342
+ export { ADMIN_UI_VERSION, type AdminPromoListFilter, type AdminPromoListRow, type AdminResourceClientOptions, type BatchColumnData, BatchColumnDriftError, BatchColumnFetcher, type BatchColumnFetcherOptions, type BatchColumnRow, type BatchColumnValue, BootLoadError, BootLoader, type BootLoaderOptions, type BuildRouteEntry, type CachedManifestEntry, DEFAULT_STANDARD_PAGE_ROUTES, HttpClient, HttpJsonError, KvStore, type LoginBootProject, type LoginBrandFallback, type LoginBranding, ManifestLoadError, ManifestLoader, type ManifestLoaderOptions, type MessageParams, type NavBuilderOptions, type ParamStyle, SaLocale, type SidebarItem, type SidebarSection, buildRoutes, buildSidebar, createAdminResourceClient, defaultSectionOrder, formatCurrency, formatMessage, getJson, isProductionBoot, postJson, resolveExtension, resolveLoginBranding, trimTrailingSlashes };
@@ -16,25 +16,29 @@ import {
16
16
  createAdminResourceClient,
17
17
  defaultSectionOrder,
18
18
  getJson,
19
+ isProductionBoot,
19
20
  postJson,
20
21
  resolveExtension,
22
+ resolveLoginBranding,
21
23
  trimTrailingSlashes
22
- } from "../chunk-CRUUZMMN.js";
24
+ } from "../chunk-XPSD5HKG.js";
23
25
  import {
24
26
  DEFAULT_SA_LOCALE,
25
27
  SA_INTL_LOCALES,
26
28
  SA_LOCALES,
27
29
  SA_LOCALE_LABELS,
28
30
  SA_MESSAGES,
31
+ builtinLocaleOf,
32
+ createSaCatalog,
29
33
  defaultHttpClient,
30
34
  defaultKvStore,
31
35
  defineMessages,
32
36
  formatCurrency,
33
37
  formatMessage,
34
- isSaLocale,
38
+ isSaBuiltinLocale,
35
39
  mergeMessages,
36
40
  resolveMessages
37
- } from "../chunk-TZ2NGQXK.js";
41
+ } from "../chunk-IZGFS5RS.js";
38
42
  export {
39
43
  ADMIN_UI_VERSION,
40
44
  ActionDefNotInManifestError,
@@ -55,7 +59,9 @@ export {
55
59
  SA_MESSAGES,
56
60
  buildRoutes,
57
61
  buildSidebar,
62
+ builtinLocaleOf,
58
63
  createAdminResourceClient,
64
+ createSaCatalog,
59
65
  defaultHttpClient,
60
66
  defaultKvStore,
61
67
  defaultSectionOrder,
@@ -63,10 +69,12 @@ export {
63
69
  formatCurrency,
64
70
  formatMessage,
65
71
  getJson,
66
- isSaLocale,
72
+ isProductionBoot,
73
+ isSaBuiltinLocale,
67
74
  mergeMessages,
68
75
  postJson,
69
76
  resolveExtension,
77
+ resolveLoginBranding,
70
78
  resolveMessages,
71
79
  trimTrailingSlashes
72
80
  };