@saasicat/ui-vue 0.16.0 → 0.18.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 (46) hide show
  1. package/README.md +12 -11
  2. package/dist/{messages-DetB75lX.d.ts → catalog-JXdKdIqG.d.cts} +104 -40
  3. package/dist/{messages-DetB75lX.d.cts → catalog-JXdKdIqG.d.ts} +104 -40
  4. package/dist/{chunk-TZ2NGQXK.js → chunk-CC4WK3DC.js} +40 -8
  5. package/dist/{chunk-CRUUZMMN.js → chunk-VRCVJTY4.js} +30 -4
  6. package/dist/{chunk-MGKJCVDU.js → chunk-Y5MWMWMD.js} +18 -18
  7. package/dist/client/index.cjs +70 -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 +10 -4
  11. package/dist/index.cjs +85 -22
  12. package/dist/index.d.cts +5 -5
  13. package/dist/index.d.ts +5 -5
  14. package/dist/index.js +11 -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-1nCOkvgi.d.cts} +29 -9
  20. package/dist/{use-super-admin-i18n-BPC-H9jz.d.ts → use-super-admin-i18n-BlqcD0N7.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 +23 -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/BundleVersionStrip.vue +1 -1
  36. package/src/components/bundle-editor/bundle-version-status.ts +18 -11
  37. package/src/pages-standard/AdminLayout.vue +7 -3
  38. package/src/pages-standard/DiscoveryPage.vue +1 -1
  39. package/src/pages-standard/SuperAdminLoginPage.vue +8 -9
  40. package/src/pages-standard/bundles-page/BundleAccordionList.vue +2 -3
  41. package/src/pages-standard/discovery-page/CatalogEntryTransPanel.vue +4 -4
  42. package/src/pages-standard/discovery-page/DiscoveryStatusControl.vue +7 -7
  43. package/src/pages-standard/discovery-page/discovery-ui.ts +24 -15
  44. package/src/pages-standard/plan-versions/PlanVersionsTimeline.vue +2 -3
  45. package/src/pages-standard/plan-versions/format.ts +7 -8
  46. package/src/vue/use-super-admin-i18n.ts +59 -28
@@ -53,7 +53,7 @@ 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
59
 
@@ -93,7 +93,7 @@ function formatterFor(locale, currency, decimals) {
93
93
  const key = `${locale}:${currency}:${decimals}`;
94
94
  let formatter = formatters.get(key);
95
95
  if (!formatter) {
96
- formatter = new Intl.NumberFormat(SA_INTL_LOCALES[locale], {
96
+ formatter = new Intl.NumberFormat(SA_INTL_LOCALES[locale] ?? locale, {
97
97
  style: "currency",
98
98
  currency,
99
99
  minimumFractionDigits: decimals,
@@ -259,7 +259,7 @@ var bundlesMessages = defineMessages(
259
259
  bundleKeyHint: "API-stabil \xB7 wird aus dem Label erzeugt",
260
260
  errorKeyFormat: "Nur A-Z, 0-9, Underscore; muss mit Buchstabe beginnen.",
261
261
  errorKeyExists: "Dieser Bundle-Key existiert bereits.",
262
- descriptionPlaceholder: "z. B. Kampagnen, WhatsApp und Korrespondenz f\xFCr aktive Vereine.",
262
+ descriptionPlaceholder: "z. B. Kampagnen, WhatsApp und Korrespondenz.",
263
263
  sectionPricing: "v1 \xB7 Pricing & G\xFCltigkeit",
264
264
  pricingHint: "Monats- & Jahrespreis sowie Datum, ab dem das Bundle verkaufbar wird.",
265
265
  validFromImmediate: "\u2713 Bundle ist nach Anlage sofort live und verkaufbar.",
@@ -471,7 +471,7 @@ var bundlesMessages = defineMessages(
471
471
  bundleKeyHint: "API-stable \xB7 derived from the label",
472
472
  errorKeyFormat: "Only A-Z, 0-9, underscore; must start with a letter.",
473
473
  errorKeyExists: "This bundle key already exists.",
474
- descriptionPlaceholder: "e.g. Campaigns, WhatsApp and correspondence for active clubs.",
474
+ descriptionPlaceholder: "e.g. Campaigns, WhatsApp and correspondence.",
475
475
  sectionPricing: "v1 \xB7 pricing & validity",
476
476
  pricingHint: "Monthly & yearly price plus the date from which the bundle becomes sellable.",
477
477
  validFromImmediate: "\u2713 The bundle is live and sellable right after creation.",
@@ -1145,7 +1145,7 @@ var marketingMessages = defineMessages(
1145
1145
  ctaOverrideLabel: "CTA-Text \xFCberschreiben (optional)",
1146
1146
  ctaOverrideHint: "leer lassen f\xFCr Auto-Text",
1147
1147
  topFeatureCount: "{count} Eintr\xE4ge",
1148
- featureLabelPlaceholder: "z. B. Beitragsverwaltung",
1148
+ featureLabelPlaceholder: "z. B. Erweiterte Berichte",
1149
1149
  featureStrongPlaceholder: "Highlight, z. B. bis 100",
1150
1150
  moveUp: "Nach oben",
1151
1151
  moveDown: "Nach unten",
@@ -1273,7 +1273,7 @@ var marketingMessages = defineMessages(
1273
1273
  ctaOverrideLabel: "Override CTA text (optional)",
1274
1274
  ctaOverrideHint: "leave empty for the auto text",
1275
1275
  topFeatureCount: "{count} entries",
1276
- featureLabelPlaceholder: "e.g. Membership management",
1276
+ featureLabelPlaceholder: "e.g. Advanced reporting",
1277
1277
  featureStrongPlaceholder: "Highlight, e.g. up to 100",
1278
1278
  moveUp: "Move up",
1279
1279
  moveDown: "Move down",
@@ -3109,6 +3109,37 @@ function resolveMessages(locale, overrides) {
3109
3109
  return mergeMessages(SA_MESSAGES[locale], overrides);
3110
3110
  }
3111
3111
 
3112
+ // src/client/i18n/catalog.ts
3113
+ function createSaCatalog(options = {}) {
3114
+ const additional = options.additionalLocales ?? {};
3115
+ const known = /* @__PURE__ */ new Set([...SA_LOCALES, ...Object.keys(additional)]);
3116
+ const requested = options.locales?.filter((code) => known.has(code));
3117
+ const offered = requested && requested.length > 0 ? requested : [...SA_LOCALES, ...Object.keys(additional)];
3118
+ const labelFor = (locale) => additional[locale]?.label ?? (isSaBuiltinLocale(locale) ? SA_LOCALE_LABELS[locale] : locale);
3119
+ const cache = /* @__PURE__ */ new Map();
3120
+ const messagesFor = (locale) => {
3121
+ const hit = cache.get(locale);
3122
+ if (hit) return hit;
3123
+ const definition = additional[locale];
3124
+ const base = SA_MESSAGES[definition?.basedOn ?? (isSaBuiltinLocale(locale) ? locale : "en")];
3125
+ const translated = definition ? mergeMessages(base, definition.messages) : base;
3126
+ const resolved = mergeMessages(translated, options.overrides?.[locale]);
3127
+ cache.set(locale, resolved);
3128
+ return resolved;
3129
+ };
3130
+ const offeredSet = new Set(offered);
3131
+ return {
3132
+ locales: offered.map((code) => ({ code, label: labelFor(code) })),
3133
+ has: (locale) => offeredSet.has(locale),
3134
+ // The app's first offered locale beats the platform default: an app
3135
+ // shipping English only must not start in German.
3136
+ defaultLocale: offered.includes(DEFAULT_SA_LOCALE) ? DEFAULT_SA_LOCALE : offered[0],
3137
+ messagesFor,
3138
+ intlLocaleFor: (locale) => additional[locale]?.intlLocale ?? (isSaBuiltinLocale(locale) ? SA_INTL_LOCALES[locale] : locale),
3139
+ labelFor
3140
+ };
3141
+ }
3142
+
3112
3143
  export {
3113
3144
  defaultKvStore,
3114
3145
  defaultHttpClient,
@@ -3116,12 +3147,13 @@ export {
3116
3147
  DEFAULT_SA_LOCALE,
3117
3148
  SA_INTL_LOCALES,
3118
3149
  SA_LOCALE_LABELS,
3119
- isSaLocale,
3150
+ isSaBuiltinLocale,
3120
3151
  defineMessages,
3121
3152
  mergeMessages,
3122
3153
  navMessages,
3123
3154
  formatMessage,
3124
3155
  formatCurrency,
3125
3156
  SA_MESSAGES,
3126
- resolveMessages
3157
+ resolveMessages,
3158
+ createSaCatalog
3127
3159
  };
@@ -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-CC4WK3DC.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
  };
@@ -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-CC4WK3DC.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;
@@ -40,6 +40,7 @@ __export(client_exports, {
40
40
  buildRoutes: () => buildRoutes,
41
41
  buildSidebar: () => buildSidebar,
42
42
  createAdminResourceClient: () => createAdminResourceClient,
43
+ createSaCatalog: () => createSaCatalog,
43
44
  defaultHttpClient: () => defaultHttpClient,
44
45
  defaultKvStore: () => defaultKvStore,
45
46
  defaultSectionOrder: () => defaultSectionOrder,
@@ -47,10 +48,12 @@ __export(client_exports, {
47
48
  formatCurrency: () => formatCurrency,
48
49
  formatMessage: () => formatMessage,
49
50
  getJson: () => getJson,
50
- isSaLocale: () => isSaLocale,
51
+ isProductionBoot: () => isProductionBoot,
52
+ isSaBuiltinLocale: () => isSaBuiltinLocale,
51
53
  mergeMessages: () => mergeMessages,
52
54
  postJson: () => postJson,
53
55
  resolveExtension: () => resolveExtension,
56
+ resolveLoginBranding: () => resolveLoginBranding,
54
57
  resolveMessages: () => resolveMessages,
55
58
  trimTrailingSlashes: () => trimTrailingSlashes
56
59
  });
@@ -270,7 +273,7 @@ var SA_LOCALE_LABELS = {
270
273
  de: "Deutsch",
271
274
  en: "English"
272
275
  };
273
- function isSaLocale(value) {
276
+ function isSaBuiltinLocale(value) {
274
277
  return typeof value === "string" && SA_LOCALES.includes(value);
275
278
  }
276
279
 
@@ -394,15 +397,21 @@ var PAGE_SECTIONS = {
394
397
  platformEmail: "system",
395
398
  platformEmailHistory: "system"
396
399
  };
400
+ function resolveNav(options) {
401
+ return options.nav ?? builtinNav(options.locale);
402
+ }
403
+ function builtinNav(locale) {
404
+ return navMessages[isSaBuiltinLocale(locale) ? locale : DEFAULT_SA_LOCALE];
405
+ }
397
406
  function defaultSectionOrder(locale = DEFAULT_SA_LOCALE) {
398
- const sections = navMessages[locale].sections;
407
+ const sections = typeof locale === "string" ? builtinNav(locale).sections : locale.sections;
399
408
  return [sections.overview, sections.catalog, sections.customers, sections.system];
400
409
  }
401
410
  function buildRoutes(manifest, options = {}) {
402
411
  const routes = [];
403
412
  const capabilities = manifest.capabilities ?? {};
404
413
  const standard = manifest.navigation?.standardPages ?? {};
405
- const nav = navMessages[options.locale ?? DEFAULT_SA_LOCALE];
414
+ const nav = resolveNav(options);
406
415
  const defaultNavSections = Object.fromEntries(
407
416
  Object.entries(PAGE_SECTIONS).map(([page, section]) => [page, nav.sections[section]])
408
417
  );
@@ -737,7 +746,7 @@ function formatterFor(locale, currency, decimals) {
737
746
  const key = `${locale}:${currency}:${decimals}`;
738
747
  let formatter = formatters.get(key);
739
748
  if (!formatter) {
740
- formatter = new Intl.NumberFormat(SA_INTL_LOCALES[locale], {
749
+ formatter = new Intl.NumberFormat(SA_INTL_LOCALES[locale] ?? locale, {
741
750
  style: "currency",
742
751
  currency,
743
752
  minimumFractionDigits: decimals,
@@ -903,7 +912,7 @@ var bundlesMessages = defineMessages(
903
912
  bundleKeyHint: "API-stabil \xB7 wird aus dem Label erzeugt",
904
913
  errorKeyFormat: "Nur A-Z, 0-9, Underscore; muss mit Buchstabe beginnen.",
905
914
  errorKeyExists: "Dieser Bundle-Key existiert bereits.",
906
- descriptionPlaceholder: "z. B. Kampagnen, WhatsApp und Korrespondenz f\xFCr aktive Vereine.",
915
+ descriptionPlaceholder: "z. B. Kampagnen, WhatsApp und Korrespondenz.",
907
916
  sectionPricing: "v1 \xB7 Pricing & G\xFCltigkeit",
908
917
  pricingHint: "Monats- & Jahrespreis sowie Datum, ab dem das Bundle verkaufbar wird.",
909
918
  validFromImmediate: "\u2713 Bundle ist nach Anlage sofort live und verkaufbar.",
@@ -1115,7 +1124,7 @@ var bundlesMessages = defineMessages(
1115
1124
  bundleKeyHint: "API-stable \xB7 derived from the label",
1116
1125
  errorKeyFormat: "Only A-Z, 0-9, underscore; must start with a letter.",
1117
1126
  errorKeyExists: "This bundle key already exists.",
1118
- descriptionPlaceholder: "e.g. Campaigns, WhatsApp and correspondence for active clubs.",
1127
+ descriptionPlaceholder: "e.g. Campaigns, WhatsApp and correspondence.",
1119
1128
  sectionPricing: "v1 \xB7 pricing & validity",
1120
1129
  pricingHint: "Monthly & yearly price plus the date from which the bundle becomes sellable.",
1121
1130
  validFromImmediate: "\u2713 The bundle is live and sellable right after creation.",
@@ -1789,7 +1798,7 @@ var marketingMessages = defineMessages(
1789
1798
  ctaOverrideLabel: "CTA-Text \xFCberschreiben (optional)",
1790
1799
  ctaOverrideHint: "leer lassen f\xFCr Auto-Text",
1791
1800
  topFeatureCount: "{count} Eintr\xE4ge",
1792
- featureLabelPlaceholder: "z. B. Beitragsverwaltung",
1801
+ featureLabelPlaceholder: "z. B. Erweiterte Berichte",
1793
1802
  featureStrongPlaceholder: "Highlight, z. B. bis 100",
1794
1803
  moveUp: "Nach oben",
1795
1804
  moveDown: "Nach unten",
@@ -1917,7 +1926,7 @@ var marketingMessages = defineMessages(
1917
1926
  ctaOverrideLabel: "Override CTA text (optional)",
1918
1927
  ctaOverrideHint: "leave empty for the auto text",
1919
1928
  topFeatureCount: "{count} entries",
1920
- featureLabelPlaceholder: "e.g. Membership management",
1929
+ featureLabelPlaceholder: "e.g. Advanced reporting",
1921
1930
  featureStrongPlaceholder: "Highlight, e.g. up to 100",
1922
1931
  moveUp: "Move up",
1923
1932
  moveDown: "Move down",
@@ -3702,6 +3711,54 @@ function resolveMessages(locale, overrides) {
3702
3711
  if (!overrides) return SA_MESSAGES[locale];
3703
3712
  return mergeMessages(SA_MESSAGES[locale], overrides);
3704
3713
  }
3714
+
3715
+ // src/client/i18n/catalog.ts
3716
+ function createSaCatalog(options = {}) {
3717
+ const additional = options.additionalLocales ?? {};
3718
+ const known = /* @__PURE__ */ new Set([...SA_LOCALES, ...Object.keys(additional)]);
3719
+ const requested = options.locales?.filter((code) => known.has(code));
3720
+ const offered = requested && requested.length > 0 ? requested : [...SA_LOCALES, ...Object.keys(additional)];
3721
+ const labelFor = (locale) => additional[locale]?.label ?? (isSaBuiltinLocale(locale) ? SA_LOCALE_LABELS[locale] : locale);
3722
+ const cache = /* @__PURE__ */ new Map();
3723
+ const messagesFor = (locale) => {
3724
+ const hit = cache.get(locale);
3725
+ if (hit) return hit;
3726
+ const definition = additional[locale];
3727
+ const base = SA_MESSAGES[definition?.basedOn ?? (isSaBuiltinLocale(locale) ? locale : "en")];
3728
+ const translated = definition ? mergeMessages(base, definition.messages) : base;
3729
+ const resolved = mergeMessages(translated, options.overrides?.[locale]);
3730
+ cache.set(locale, resolved);
3731
+ return resolved;
3732
+ };
3733
+ const offeredSet = new Set(offered);
3734
+ return {
3735
+ locales: offered.map((code) => ({ code, label: labelFor(code) })),
3736
+ has: (locale) => offeredSet.has(locale),
3737
+ // The app's first offered locale beats the platform default: an app
3738
+ // shipping English only must not start in German.
3739
+ defaultLocale: offered.includes(DEFAULT_SA_LOCALE) ? DEFAULT_SA_LOCALE : offered[0],
3740
+ messagesFor,
3741
+ intlLocaleFor: (locale) => additional[locale]?.intlLocale ?? (isSaBuiltinLocale(locale) ? SA_INTL_LOCALES[locale] : locale),
3742
+ labelFor
3743
+ };
3744
+ }
3745
+
3746
+ // src/client/login-branding.ts
3747
+ var DEFAULT_TAG = "SuperAdmin";
3748
+ function resolveLoginBranding(boot, fallback = {}) {
3749
+ const project = boot?.project ?? null;
3750
+ const environment = project?.environment ?? null;
3751
+ return {
3752
+ name: project?.displayName || fallback.name || "",
3753
+ tag: project?.label || fallback.tag || DEFAULT_TAG,
3754
+ icon: project?.icon || fallback.logoText || "",
3755
+ logoUrl: project?.logoUrl || null,
3756
+ environment: environment && environment !== "production" ? environment : null
3757
+ };
3758
+ }
3759
+ function isProductionBoot(boot) {
3760
+ return boot?.project?.environment === "production";
3761
+ }
3705
3762
  // Annotate the CommonJS export names for ESM import in node:
3706
3763
  0 && (module.exports = {
3707
3764
  ADMIN_UI_VERSION,
@@ -3724,6 +3781,7 @@ function resolveMessages(locale, overrides) {
3724
3781
  buildRoutes,
3725
3782
  buildSidebar,
3726
3783
  createAdminResourceClient,
3784
+ createSaCatalog,
3727
3785
  defaultHttpClient,
3728
3786
  defaultKvStore,
3729
3787
  defaultSectionOrder,
@@ -3731,10 +3789,12 @@ function resolveMessages(locale, overrides) {
3731
3789
  formatCurrency,
3732
3790
  formatMessage,
3733
3791
  getJson,
3734
- isSaLocale,
3792
+ isProductionBoot,
3793
+ isSaBuiltinLocale,
3735
3794
  mergeMessages,
3736
3795
  postJson,
3737
3796
  resolveExtension,
3797
+ resolveLoginBranding,
3738
3798
  resolveMessages,
3739
3799
  trimTrailingSlashes
3740
3800
  });
@@ -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, w as SaNavMessages } from '../catalog-JXdKdIqG.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 createSaCatalog, q as defaultHttpClient, r as defaultKvStore, s as defineMessages, t as isSaBuiltinLocale, u as mergeMessages, v as resolveMessages } from '../catalog-JXdKdIqG.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, w as SaNavMessages } from '../catalog-JXdKdIqG.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 createSaCatalog, q as defaultHttpClient, r as defaultKvStore, s as defineMessages, t as isSaBuiltinLocale, u as mergeMessages, v as resolveMessages } from '../catalog-JXdKdIqG.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,28 @@ 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-VRCVJTY4.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
+ createSaCatalog,
29
32
  defaultHttpClient,
30
33
  defaultKvStore,
31
34
  defineMessages,
32
35
  formatCurrency,
33
36
  formatMessage,
34
- isSaLocale,
37
+ isSaBuiltinLocale,
35
38
  mergeMessages,
36
39
  resolveMessages
37
- } from "../chunk-TZ2NGQXK.js";
40
+ } from "../chunk-CC4WK3DC.js";
38
41
  export {
39
42
  ADMIN_UI_VERSION,
40
43
  ActionDefNotInManifestError,
@@ -56,6 +59,7 @@ export {
56
59
  buildRoutes,
57
60
  buildSidebar,
58
61
  createAdminResourceClient,
62
+ createSaCatalog,
59
63
  defaultHttpClient,
60
64
  defaultKvStore,
61
65
  defaultSectionOrder,
@@ -63,10 +67,12 @@ export {
63
67
  formatCurrency,
64
68
  formatMessage,
65
69
  getJson,
66
- isSaLocale,
70
+ isProductionBoot,
71
+ isSaBuiltinLocale,
67
72
  mergeMessages,
68
73
  postJson,
69
74
  resolveExtension,
75
+ resolveLoginBranding,
70
76
  resolveMessages,
71
77
  trimTrailingSlashes
72
78
  };