@saasicat/ui-vue 0.19.0 → 0.22.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 (145) hide show
  1. package/dist/{catalog-JXdKdIqG.d.cts → catalog-DJcfm5N2.d.cts} +21 -7
  2. package/dist/{catalog-JXdKdIqG.d.ts → catalog-DJcfm5N2.d.ts} +21 -7
  3. package/dist/{chunk-DPTIOQXX.js → chunk-F7NRM6KI.js} +56 -28
  4. package/dist/{chunk-RVG6LQHL.js → chunk-LY52T4N4.js} +21 -2
  5. package/dist/{chunk-ORX3ZG47.js → chunk-XMMFN2WJ.js} +74 -3
  6. package/dist/client/index.cjs +134 -29
  7. package/dist/client/index.d.cts +53 -3
  8. package/dist/client/index.d.ts +53 -3
  9. package/dist/client/index.js +14 -2
  10. package/dist/index.cjs +321 -162
  11. package/dist/index.d.cts +30 -8
  12. package/dist/index.d.ts +30 -8
  13. package/dist/index.js +176 -133
  14. package/dist/quasar/index.cjs +78 -29
  15. package/dist/quasar/index.d.cts +2 -2
  16. package/dist/quasar/index.d.ts +2 -2
  17. package/dist/quasar/index.js +6 -2
  18. package/dist/testing-e2e/admin-pages-suite.d.cts +37 -0
  19. package/dist/testing-e2e/admin-pages-suite.d.ts +37 -0
  20. package/dist/{use-super-admin-i18n-BlqcD0N7.d.ts → use-super-admin-i18n-CHNdsSlm.d.ts} +34 -7
  21. package/dist/{use-super-admin-i18n-1nCOkvgi.d.cts → use-super-admin-i18n-CgTuNi8h.d.cts} +34 -7
  22. package/package.json +18 -8
  23. package/src/client/i18n/messages/bundles.ts +0 -2
  24. package/src/client/i18n/messages/common.ts +24 -0
  25. package/src/client/i18n/messages/discovery.ts +2 -2
  26. package/src/client/i18n/messages/marketing.ts +2 -4
  27. package/src/client/i18n/messages/plan-detail.ts +0 -4
  28. package/src/client/i18n/messages/plans.ts +20 -8
  29. package/src/client/i18n/messages/tenants.ts +0 -2
  30. package/src/client/index.ts +1 -0
  31. package/src/client/manifest-loader.ts +1 -1
  32. package/src/client/resolve-plans.ts +144 -0
  33. package/src/components/BundleVersionPublishDialog.vue +6 -6
  34. package/src/components/KvBlock.vue +4 -4
  35. package/src/components/MarketingPromotionsTab.vue +34 -48
  36. package/src/components/MfaPromptDialog.vue +8 -2
  37. package/src/components/TenantActionConfirmDialog.vue +4 -4
  38. package/src/components/VersionDiffPreview.vue +7 -7
  39. package/src/components/admin-page/AdminBody.vue +40 -0
  40. package/src/components/admin-page/AdminFilters.vue +12 -0
  41. package/src/components/admin-page/AdminHero.vue +49 -0
  42. package/src/components/admin-page/AdminKpi.vue +84 -0
  43. package/src/components/admin-page/AdminPage.vue +16 -0
  44. package/src/components/admin-page/AdminPaginator.vue +195 -0
  45. package/src/components/admin-page/AdminRefreshBtn.vue +39 -0
  46. package/src/components/admin-page/AdminSection.vue +53 -0
  47. package/src/components/admin-page/AdminStatistics.vue +40 -0
  48. package/src/components/admin-page/AdminTable.vue +175 -0
  49. package/src/components/bundle-editor/BundleCreatePanel.vue +23 -23
  50. package/src/components/bundle-editor/BundleFeaturesEditor.vue +7 -7
  51. package/src/components/bundle-editor/BundlePlanCompatPicker.vue +9 -9
  52. package/src/components/bundle-editor/BundleQuotasEditor.vue +11 -11
  53. package/src/components/bundle-editor/BundleStatusBanner.vue +6 -6
  54. package/src/components/bundle-editor/BundleVersionInlineEditor.vue +18 -18
  55. package/src/components/bundle-editor/BundleVersionStrip.vue +12 -12
  56. package/src/components/dialogs/PilotCreateDialog.vue +12 -12
  57. package/src/components/dialogs/PilotEditDialog.vue +7 -7
  58. package/src/components/dialogs/PromoCodeCreateDialog.vue +8 -8
  59. package/src/components/dialogs/PromoCodeDialogFields.vue +33 -19
  60. package/src/components/dialogs/PromoCodeEditDialog.vue +10 -10
  61. package/src/components/plan/PlanGrid.vue +1 -1
  62. package/src/components/plan-create-dialog/PlanCreateDialog.vue +34 -46
  63. package/src/components/plan-detail/PlanAuditLog.vue +7 -8
  64. package/src/components/plan-detail/PlanDetail.vue +95 -292
  65. package/src/components/plan-detail/PlanDetailKpis.vue +22 -27
  66. package/src/components/plan-detail/PlanTitleEdit.vue +133 -0
  67. package/src/components/plan-detail/PlanVersionDiffPanel.vue +5 -8
  68. package/src/components/plan-detail/PlanVersionsPanel.vue +9 -11
  69. package/src/components/plan-list/PlanList.vue +206 -457
  70. package/src/components/plan-matrix/PlanMatrix.vue +66 -183
  71. package/src/components/plan-review/PlanReview.vue +191 -275
  72. package/src/components/plan-version-editor/PlanCatalogPreview.vue +7 -5
  73. package/src/components/plan-version-editor/PlanVersionEditor.vue +200 -295
  74. package/src/components/plan-version-editor/PlanVersionEditorHeader.vue +23 -55
  75. package/src/index.ts +1 -0
  76. package/src/pages-standard/AdminLayout.vue +38 -12
  77. package/src/pages-standard/AdminManifestErrorPage.vue +79 -9
  78. package/src/pages-standard/AuditPage.vue +65 -109
  79. package/src/pages-standard/BundlesPage.vue +146 -179
  80. package/src/pages-standard/DashboardPage.vue +59 -154
  81. package/src/pages-standard/DiscoveryPage.vue +172 -227
  82. package/src/pages-standard/EmailHistoryPage.vue +118 -159
  83. package/src/pages-standard/MarketingCatalogPage.vue +399 -440
  84. package/src/pages-standard/PilotsPage.vue +69 -117
  85. package/src/pages-standard/PlansPage.vue +240 -112
  86. package/src/pages-standard/PlatformEmailPage.vue +56 -91
  87. package/src/pages-standard/PromoCodeDetailPage.vue +49 -74
  88. package/src/pages-standard/PromoCodesPage.vue +95 -128
  89. package/src/pages-standard/SubscriptionsPage.vue +19 -52
  90. package/src/pages-standard/SuperAdminLoginPage.vue +12 -12
  91. package/src/pages-standard/SuperAdminSetupWizard.vue +22 -18
  92. package/src/pages-standard/TenantDetailPage.vue +100 -191
  93. package/src/pages-standard/TenantsPage.vue +190 -295
  94. package/src/pages-standard/UsersPage.vue +89 -157
  95. package/src/pages-standard/bundles-page/BundleAccordionList.vue +20 -17
  96. package/src/pages-standard/bundles-page/BundlesKpis.vue +13 -22
  97. package/src/pages-standard/bundles-page/BundlesToolbar.vue +63 -0
  98. package/src/pages-standard/discovery-page/CatalogEntryTransPanel.vue +10 -10
  99. package/src/pages-standard/discovery-page/DiscoveryCapList.vue +5 -5
  100. package/src/pages-standard/discovery-page/DiscoveryFeatureCard.vue +16 -16
  101. package/src/pages-standard/discovery-page/DiscoveryKpis.vue +31 -27
  102. package/src/pages-standard/discovery-page/DiscoveryQuotaCard.vue +7 -7
  103. package/src/pages-standard/marketing-catalog/MarketingCatalogAdmin.vue +111 -73
  104. package/src/pages-standard/marketing-catalog/MarketingCatalogHeader.vue +43 -62
  105. package/src/pages-standard/marketing-catalog/MarketingCatalogPreview.vue +53 -35
  106. package/src/pages-standard/marketing-catalog/MarketingCatalogToolbar.vue +7 -7
  107. package/src/pages-standard/plan-versions/PlanDiffCard.vue +6 -6
  108. package/src/pages-standard/plan-versions/PlanVersionsDiff.vue +6 -6
  109. package/src/pages-standard/plan-versions/PlanVersionsTimeline.vue +16 -16
  110. package/src/pages-standard/plans-page/PlanBundleOverview.vue +14 -29
  111. package/src/pages-standard/plans-page/PlanPublishDialog.vue +1 -1
  112. package/src/pages-standard/plans-page/PlansPageToast.vue +6 -6
  113. package/src/pages-standard/sa-theme.css +552 -86
  114. package/src/pages-standard/tenant-detail/TenantMasterData.vue +28 -0
  115. package/src/pages-standard/tenant-detail/TenantUsage.vue +31 -0
  116. package/src/pages-standard/tenant-detail/TenantUsers.vue +15 -0
  117. package/src/pages-standard/tenant-detail/types.ts +38 -0
  118. package/src/pages-standard/tenants/StatusPill.vue +2 -2
  119. package/src/pages-tenant/MySubscriptionBundlesPage.vue +25 -25
  120. package/src/pages-tenant/OnboardingConfigurator.vue +1 -5
  121. package/src/pages-tenant/PackageSnapshotPanel.vue +1 -1
  122. package/src/pages-tenant/TenantPlanSection.vue +12 -20
  123. package/src/quasar/create-super-admin-app.ts +4 -0
  124. package/src/vue/entitlement-provider.ts +0 -1
  125. package/src/vue/feature-router-guard.ts +0 -1
  126. package/src/vue/super-admin-context.ts +106 -1
  127. package/src/vue/use-api-list.ts +2 -1
  128. package/src/vue/use-mfa-prompt.ts +72 -0
  129. package/src/vue/use-pagination.ts +63 -0
  130. package/src/vue/use-plans.ts +1 -2
  131. package/src/vue/use-sign-out.ts +90 -0
  132. package/src/vue/use-tenant-billing.ts +1 -1
  133. package/src/vue/use-tenant-manifest.ts +0 -1
  134. package/src/components/KpiCard.vue +0 -53
  135. package/src/components/plan-cockpit/PlanCockpit.vue +0 -1012
  136. package/src/components/plan-cockpit/PlanCockpitAuditLog.vue +0 -72
  137. package/src/components/plan-cockpit/PlanCockpitDiffPanel.vue +0 -100
  138. package/src/components/plan-cockpit/PlanCockpitHeader.vue +0 -101
  139. package/src/components/plan-cockpit/PlanCockpitImpactPanel.vue +0 -112
  140. package/src/components/plan-cockpit/PlanCockpitKpis.vue +0 -68
  141. package/src/components/plan-cockpit/PlanCockpitVersions.vue +0 -251
  142. package/src/components/plan-cockpit/types.ts +0 -72
  143. package/src/components/plan-detail/PlanDetailHeader.vue +0 -194
  144. package/src/pages-standard/bundles-page/BundlesHeader.vue +0 -68
  145. package/src/pages-standard/discovery-page/DiscoveryHeader.vue +0 -34
@@ -269,7 +269,7 @@ function coverage(locale: string): number {
269
269
 
270
270
  <style scoped>
271
271
  .sa-fc {
272
- border: 1px solid #e2e8f0;
272
+ border: 1px solid var(--sa-border);
273
273
  border-radius: 10px;
274
274
  background: #fff;
275
275
  overflow: hidden;
@@ -286,7 +286,7 @@ function coverage(locale: string): number {
286
286
  cursor: pointer;
287
287
  }
288
288
  .sa-fc__icon {
289
- color: #475569;
289
+ color: var(--sa-muted-dark);
290
290
  flex-shrink: 0;
291
291
  }
292
292
  .sa-fc__main {
@@ -302,8 +302,8 @@ function coverage(locale: string): number {
302
302
  .sa-fc__key {
303
303
  font-size: 11px;
304
304
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
305
- background: #f1f5f9;
306
- color: #475569;
305
+ background: var(--sa-border-soft);
306
+ color: var(--sa-muted-dark);
307
307
  padding: 2px 6px;
308
308
  border-radius: 5px;
309
309
  white-space: nowrap;
@@ -311,7 +311,7 @@ function coverage(locale: string): number {
311
311
  .sa-fc__label {
312
312
  font-size: 13px;
313
313
  font-weight: 600;
314
- color: #0f172a;
314
+ color: var(--sa-heading);
315
315
  }
316
316
  .sa-fc__flag {
317
317
  font-size: 10px;
@@ -337,7 +337,7 @@ function coverage(locale: string): number {
337
337
  }
338
338
  .sa-fc__sub {
339
339
  font-size: 11px;
340
- color: #64748b;
340
+ color: var(--sa-muted);
341
341
  margin-top: 1px;
342
342
  }
343
343
  .sa-fc__dot {
@@ -356,16 +356,16 @@ function coverage(locale: string): number {
356
356
  flex-shrink: 0;
357
357
  }
358
358
  .sa-fc__chev {
359
- color: #94a3b8;
359
+ color: var(--sa-muted-light);
360
360
  transition: transform 0.15s;
361
361
  }
362
362
  .sa-fc__chev.open {
363
363
  transform: rotate(90deg);
364
364
  }
365
365
  .sa-fc__body {
366
- border-top: 1px solid #f1f5f9;
366
+ border-top: 1px solid var(--sa-border-soft);
367
367
  padding: 12px;
368
- background: #f8fafc;
368
+ background: var(--sa-bg-surface-2);
369
369
  }
370
370
  .sa-fc__banner {
371
371
  display: flex;
@@ -377,18 +377,18 @@ function coverage(locale: string): number {
377
377
  margin-bottom: 10px;
378
378
  }
379
379
  .sa-fc__banner.warn {
380
- background: #fffbeb;
380
+ background: var(--sa-warning-bg);
381
381
  border: 1px solid #fde68a;
382
382
  color: #92400e;
383
383
  }
384
384
  .sa-fc__banner.mute {
385
- background: #f1f5f9;
386
- border: 1px solid #e2e8f0;
387
- color: #475569;
385
+ background: var(--sa-border-soft);
386
+ border: 1px solid var(--sa-border);
387
+ color: var(--sa-muted-dark);
388
388
  }
389
389
  .sa-fc__subtabs {
390
390
  margin-bottom: 12px;
391
- border-bottom: 1px solid #e2e8f0;
391
+ border-bottom: 1px solid var(--sa-border);
392
392
  }
393
393
  .sa-fc__split {
394
394
  display: grid;
@@ -400,7 +400,7 @@ function coverage(locale: string): number {
400
400
  font-weight: 700;
401
401
  text-transform: uppercase;
402
402
  letter-spacing: 0.5px;
403
- color: #94a3b8;
403
+ color: var(--sa-muted-light);
404
404
  margin-bottom: 8px;
405
405
  }
406
406
  .sa-fc__split-count {
@@ -424,6 +424,6 @@ function coverage(locale: string): number {
424
424
  font-size: 11px;
425
425
  font-weight: 600;
426
426
  text-transform: uppercase;
427
- color: #94a3b8;
427
+ color: var(--sa-muted-light);
428
428
  }
429
429
  </style>
@@ -1,36 +1,40 @@
1
1
  <template>
2
- <div class="sa-discovery__kpis">
3
- <div class="sa-discovery__kpi">
4
- <div class="sa-discovery__kpi-label">{{ msg.kpi.featuresTotal }}</div>
5
- <div class="sa-discovery__kpi-value">{{ featuresCount }}</div>
6
- <div class="sa-discovery__kpi-sub">{{ featuresTotalSub }}</div>
7
- </div>
8
- <div class="sa-discovery__kpi good">
9
- <div class="sa-discovery__kpi-label">{{ msg.kpi.approved }}</div>
10
- <div class="sa-discovery__kpi-value">{{ approvedCount }}</div>
11
- <div class="sa-discovery__kpi-sub">{{ msg.kpi.approvedSub }}</div>
12
- </div>
13
- <div class="sa-discovery__kpi" :class="{ warn: pendingCount > 0 }">
14
- <div class="sa-discovery__kpi-label">{{ msg.kpi.pending }}</div>
15
- <div class="sa-discovery__kpi-value">{{ pendingCount }}</div>
16
- <div class="sa-discovery__kpi-sub">{{ msg.kpi.pendingSub }}</div>
17
- </div>
18
- <div class="sa-discovery__kpi">
19
- <div class="sa-discovery__kpi-label">{{ msg.kpi.outdated }}</div>
20
- <div class="sa-discovery__kpi-value">{{ outdatedCount + obsoleteCount }}</div>
21
- <div class="sa-discovery__kpi-sub">{{ outdatedSub }}</div>
22
- </div>
23
- <div class="sa-discovery__kpi" :class="{ bad: orphanCount > 0 }">
24
- <div class="sa-discovery__kpi-label">{{ msg.kpi.orphans }}</div>
25
- <div class="sa-discovery__kpi-value">{{ orphanCount }}</div>
26
- <div class="sa-discovery__kpi-sub">{{ msg.orphansTitle }}</div>
27
- </div>
28
- </div>
2
+ <AdminStatistics :columns="5">
3
+ <AdminKpi :label="msg.kpi.featuresTotal" :value="featuresCount" :sub="featuresTotalSub" />
4
+ <AdminKpi
5
+ :label="msg.kpi.approved"
6
+ :value="approvedCount"
7
+ :sub="msg.kpi.approvedSub"
8
+ tone="positive"
9
+ />
10
+ <AdminKpi
11
+ :label="msg.kpi.pending"
12
+ :value="pendingCount"
13
+ :sub="msg.kpi.pendingSub"
14
+ :tone="pendingCount > 0 ? 'warn' : 'neutral'"
15
+ emphasis="surface"
16
+ />
17
+ <AdminKpi
18
+ :label="msg.kpi.outdated"
19
+ :value="outdatedCount + obsoleteCount"
20
+ :sub="outdatedSub"
21
+ />
22
+ <AdminKpi
23
+ :label="msg.kpi.orphans"
24
+ :value="orphanCount"
25
+ :sub="msg.orphansTitle"
26
+ :tone="orphanCount > 0 ? 'danger' : 'neutral'"
27
+ emphasis="surface"
28
+ />
29
+ </AdminStatistics>
29
30
  </template>
30
31
 
31
32
  <script setup lang="ts">
32
33
  import { computed } from 'vue';
33
34
 
35
+ import AdminKpi from '../../components/admin-page/AdminKpi.vue';
36
+ import AdminStatistics from '../../components/admin-page/AdminStatistics.vue';
37
+
34
38
  import { formatMessage } from '../../client/i18n/format.js';
35
39
  import { useSaMessages } from '../../vue/use-super-admin-i18n.js';
36
40
 
@@ -154,7 +154,7 @@ function coverage(locale: string): number {
154
154
 
155
155
  <style scoped>
156
156
  .sa-qc {
157
- border: 1px solid #e2e8f0;
157
+ border: 1px solid var(--sa-border);
158
158
  border-radius: 10px;
159
159
  background: #fff;
160
160
  overflow: hidden;
@@ -192,7 +192,7 @@ function coverage(locale: string): number {
192
192
  .sa-qc__label {
193
193
  font-weight: 600;
194
194
  font-size: 13px;
195
- color: #0f172a;
195
+ color: var(--sa-heading);
196
196
  }
197
197
  .sa-qc__key {
198
198
  font-size: 11px;
@@ -213,7 +213,7 @@ function coverage(locale: string): number {
213
213
  }
214
214
  .sa-qc__sub {
215
215
  font-size: 11px;
216
- color: #64748b;
216
+ color: var(--sa-muted);
217
217
  margin-top: 2px;
218
218
  }
219
219
  .sa-qc__missing {
@@ -231,16 +231,16 @@ function coverage(locale: string): number {
231
231
  flex-shrink: 0;
232
232
  }
233
233
  .sa-qc__chev {
234
- color: #94a3b8;
234
+ color: var(--sa-muted-light);
235
235
  transition: transform 0.15s;
236
236
  }
237
237
  .sa-qc__chev.open {
238
238
  transform: rotate(90deg);
239
239
  }
240
240
  .sa-qc__body {
241
- border-top: 1px solid #f1f5f9;
241
+ border-top: 1px solid var(--sa-border-soft);
242
242
  padding: 12px;
243
- background: #f8fafc;
243
+ background: var(--sa-bg-surface-2);
244
244
  }
245
245
  .sa-qc__banner {
246
246
  display: flex;
@@ -250,7 +250,7 @@ function coverage(locale: string): number {
250
250
  border-radius: 8px;
251
251
  padding: 8px 12px;
252
252
  margin-bottom: 10px;
253
- background: #fffbeb;
253
+ background: var(--sa-warning-bg);
254
254
  border: 1px solid #fde68a;
255
255
  color: #92400e;
256
256
  }
@@ -1,14 +1,14 @@
1
1
  <template>
2
- <div class="mc-admin">
3
- <div class="mc-admin-head">
2
+ <div class="sa-marketing-admin">
3
+ <div class="sa-marketing-admin-head">
4
4
  <div style="flex: 1">
5
- <div class="mc-admin-title">{{ msg.tabs.admin }}</div>
6
- <div class="mc-admin-sub">{{ msg.admin.subtitle }}</div>
5
+ <div class="sa-marketing-admin-title">{{ msg.tabs.admin }}</div>
6
+ <div class="sa-marketing-admin-sub">{{ msg.admin.subtitle }}</div>
7
7
  </div>
8
8
  </div>
9
9
 
10
- <div class="mc-admin-grid">
11
- <div class="mc-admin-thead">
10
+ <div class="sa-marketing-admin-grid">
11
+ <div class="sa-marketing-admin-thead">
12
12
  <div>{{ msg.admin.colPlan }}</div>
13
13
  <div>{{ msg.admin.colVisible }}</div>
14
14
  <div>{{ msg.admin.colBadge }}</div>
@@ -18,11 +18,14 @@
18
18
  </div>
19
19
 
20
20
  <template v-for="row in adminRows" :key="row.plan.id">
21
- <div class="mc-admin-row" :class="{ 'mc-admin-row--disabled': !row.liveVersion }">
21
+ <div
22
+ class="sa-marketing-admin-row"
23
+ :class="{ 'sa-marketing-admin-row--disabled': !row.liveVersion }"
24
+ >
22
25
  <div>
23
- <div class="mc-plan-cell">
26
+ <div class="sa-marketing-plan-cell">
24
27
  <div
25
- class="mc-plan-mark"
28
+ class="sa-marketing-plan-mark"
26
29
  :style="{
27
30
  background: row.accent + '15',
28
31
  color: row.accent,
@@ -32,15 +35,15 @@
32
35
  {{ row.plan.planKey.slice(0, 3) }}
33
36
  </div>
34
37
  <div>
35
- <div class="mc-plan-label">
38
+ <div class="sa-marketing-plan-label">
36
39
  {{ row.m.displayLabel || row.plan.label }}
37
40
  </div>
38
- <div class="mc-plan-key">{{ row.plan.planKey }}</div>
41
+ <div class="sa-marketing-plan-key">{{ row.plan.planKey }}</div>
39
42
  </div>
40
43
  </div>
41
44
  <div
42
45
  v-if="row.publishedVersions.length > 1"
43
- class="mc-version-tabs"
46
+ class="sa-marketing-version-tabs"
44
47
  role="tablist"
45
48
  :aria-label="
46
49
  formatMessage(msg.admin.versionTabsLabel, { plan: row.plan.label })
@@ -51,8 +54,11 @@
51
54
  :key="v.id"
52
55
  type="button"
53
56
  role="tab"
54
- class="mc-version-tab"
55
- :class="{ 'mc-version-tab--active': row.liveVersion?.id === v.id }"
57
+ class="sa-marketing-version-tab"
58
+ :class="{
59
+ 'sa-marketing-version-tab--active':
60
+ row.liveVersion?.id === v.id,
61
+ }"
56
62
  :title="formatVersionTitle(v)"
57
63
  @click="$emit('select-version', row.plan, v.id)"
58
64
  >
@@ -61,7 +67,7 @@
61
67
  </div>
62
68
  </div>
63
69
  <div>
64
- <label class="mc-toggle" :class="{ disabled: !row.liveVersion }">
70
+ <label class="sa-marketing-toggle" :class="{ disabled: !row.liveVersion }">
65
71
  <input
66
72
  type="checkbox"
67
73
  :checked="row.m.visible"
@@ -73,7 +79,7 @@
73
79
  </div>
74
80
  <div>
75
81
  <input
76
- class="mc-field"
82
+ class="sa-marketing-field"
77
83
  style="max-width: 120px"
78
84
  placeholder="—"
79
85
  :value="row.m.badge"
@@ -86,7 +92,7 @@
86
92
  type="number"
87
93
  min="0"
88
94
  max="9999"
89
- class="mc-field"
95
+ class="sa-marketing-field"
90
96
  style="max-width: 72px"
91
97
  :value="row.m.priority"
92
98
  :disabled="!row.liveVersion || busy"
@@ -94,7 +100,7 @@
94
100
  />
95
101
  </div>
96
102
  <div>
97
- <label class="mc-toggle" :class="{ disabled: !row.liveVersion }">
103
+ <label class="sa-marketing-toggle" :class="{ disabled: !row.liveVersion }">
98
104
  <input
99
105
  type="checkbox"
100
106
  :checked="row.m.highlight"
@@ -104,21 +110,32 @@
104
110
  <span />
105
111
  </label>
106
112
  </div>
107
- <div class="mc-admin-row-end">
108
- <span v-if="!row.liveVersion" class="mc-chip mc-chip--muted">
113
+ <div class="sa-marketing-admin-row-end">
114
+ <span
115
+ v-if="!row.liveVersion"
116
+ class="sa-marketing-chip sa-marketing-chip--muted"
117
+ >
109
118
  {{ msg.admin.noLiveVersion }}
110
119
  </span>
111
- <span v-else-if="!row.m.visible" class="mc-chip mc-chip--muted">
120
+ <span
121
+ v-else-if="!row.m.visible"
122
+ class="sa-marketing-chip sa-marketing-chip--muted"
123
+ >
112
124
  {{ msg.admin.hidden }}
113
125
  </span>
114
- <span v-else-if="row.m.highlight" class="mc-chip mc-chip--featured">
126
+ <span
127
+ v-else-if="row.m.highlight"
128
+ class="sa-marketing-chip sa-marketing-chip--featured"
129
+ >
115
130
  {{ msg.admin.featured }}
116
131
  </span>
117
- <span v-else class="mc-chip mc-chip--live">{{ msg.admin.live }}</span>
132
+ <span v-else class="sa-marketing-chip sa-marketing-chip--live">{{
133
+ msg.admin.live
134
+ }}</span>
118
135
  <button
119
136
  v-if="row.liveVersion"
120
137
  type="button"
121
- class="mc-expand-btn"
138
+ class="sa-marketing-expand-btn"
122
139
  :title="
123
140
  expandedKey === row.plan.planKey
124
141
  ? common.close
@@ -127,7 +144,7 @@
127
144
  @click="$emit('toggle-expand', row)"
128
145
  >
129
146
  <span
130
- class="mc-chev"
147
+ class="sa-marketing-chev"
131
148
  :class="{ open: expandedKey === row.plan.planKey }"
132
149
  >
133
150
  <svg
@@ -145,17 +162,17 @@
145
162
  </div>
146
163
  </div>
147
164
 
148
- <div v-if="expandedKey === row.plan.planKey" class="mc-admin-expand">
149
- <div class="mc-expand-grid">
150
- <div class="mc-expand-col">
151
- <div class="mc-expand-sec">
152
- <div class="mc-field-head">
153
- <label class="mc-expand-label">
165
+ <div v-if="expandedKey === row.plan.planKey" class="sa-marketing-admin-expand">
166
+ <div class="sa-marketing-expand-grid">
167
+ <div class="sa-marketing-expand-col">
168
+ <div class="sa-marketing-expand-sec">
169
+ <div class="sa-marketing-field-head">
170
+ <label class="sa-marketing-expand-label">
154
171
  {{ msg.admin.planNameLabel }}
155
172
  </label>
156
173
  <span
157
174
  v-if="activeLocale !== defaultLocale"
158
- class="mc-source-hint"
175
+ class="sa-marketing-source-hint"
159
176
  >
160
177
  {{ defaultLocale.toUpperCase() }}:
161
178
  <em>
@@ -167,15 +184,18 @@
167
184
  </em>
168
185
  </span>
169
186
  </div>
170
- <div v-if="activeLocale === defaultLocale" class="mc-locked-value">
187
+ <div
188
+ v-if="activeLocale === defaultLocale"
189
+ class="sa-marketing-locked-value"
190
+ >
171
191
  <span>{{ row.plan.label }}</span>
172
- <span class="mc-locked-hint">
192
+ <span class="sa-marketing-locked-hint">
173
193
  {{ msg.admin.planNameLocked }}
174
194
  </span>
175
195
  </div>
176
196
  <input
177
197
  v-else
178
- class="mc-field"
198
+ class="sa-marketing-field"
179
199
  :placeholder="row.plan.label"
180
200
  :value="row.m.displayLabel"
181
201
  :disabled="busy"
@@ -183,7 +203,7 @@
183
203
  />
184
204
  <div
185
205
  v-if="activeLocale !== defaultLocale && !row.m.displayLabel"
186
- class="mc-expand-hint"
206
+ class="sa-marketing-expand-hint"
187
207
  >
188
208
  {{
189
209
  formatMessage(msg.admin.planNameFallbackHint, {
@@ -193,10 +213,12 @@
193
213
  </div>
194
214
  </div>
195
215
 
196
- <div class="mc-expand-sec">
197
- <label class="mc-expand-label">{{ msg.admin.teaserLabel }}</label>
216
+ <div class="sa-marketing-expand-sec">
217
+ <label class="sa-marketing-expand-label">{{
218
+ msg.admin.teaserLabel
219
+ }}</label>
198
220
  <textarea
199
- class="mc-field mc-field--area"
221
+ class="sa-marketing-field sa-marketing-field--area"
200
222
  rows="2"
201
223
  :placeholder="msg.admin.teaserPlaceholder"
202
224
  :value="row.m.description"
@@ -205,13 +227,17 @@
205
227
  $emit('patch', row, { description: textValue($event) })
206
228
  "
207
229
  />
208
- <div class="mc-expand-hint">{{ msg.admin.teaserHint }}</div>
230
+ <div class="sa-marketing-expand-hint">
231
+ {{ msg.admin.teaserHint }}
232
+ </div>
209
233
  </div>
210
234
 
211
- <div class="mc-expand-sec">
212
- <label class="mc-expand-label">{{ msg.admin.trialLabel }}</label>
213
- <div class="mc-trial-row">
214
- <label class="mc-toggle">
235
+ <div class="sa-marketing-expand-sec">
236
+ <label class="sa-marketing-expand-label">{{
237
+ msg.admin.trialLabel
238
+ }}</label>
239
+ <div class="sa-marketing-trial-row">
240
+ <label class="sa-marketing-toggle">
215
241
  <input
216
242
  type="checkbox"
217
243
  :checked="row.m.trialEnabled"
@@ -224,19 +250,19 @@
224
250
  />
225
251
  <span />
226
252
  </label>
227
- <span class="mc-trial-label">
253
+ <span class="sa-marketing-trial-label">
228
254
  {{
229
255
  row.m.trialEnabled
230
256
  ? msg.admin.trialOn
231
257
  : msg.admin.trialOff
232
258
  }}
233
259
  </span>
234
- <span class="mc-trial-days">
260
+ <span class="sa-marketing-trial-days">
235
261
  <input
236
262
  type="number"
237
263
  min="1"
238
264
  max="365"
239
- class="mc-field"
265
+ class="sa-marketing-field"
240
266
  style="max-width: 72px"
241
267
  :value="row.m.trialDays"
242
268
  :disabled="!row.m.trialEnabled || busy"
@@ -246,20 +272,20 @@
246
272
  })
247
273
  "
248
274
  />
249
- <span class="mc-trial-unit">
275
+ <span class="sa-marketing-trial-unit">
250
276
  {{ msg.admin.trialDaysUnit }}
251
277
  </span>
252
278
  </span>
253
279
  </div>
254
- <div class="mc-expand-hint">{{ trialCtaHint(row) }}</div>
280
+ <div class="sa-marketing-expand-hint">{{ trialCtaHint(row) }}</div>
255
281
  </div>
256
282
 
257
- <div class="mc-expand-sec">
258
- <label class="mc-expand-label">
283
+ <div class="sa-marketing-expand-sec">
284
+ <label class="sa-marketing-expand-label">
259
285
  {{ msg.admin.ctaOverrideLabel }}
260
286
  </label>
261
287
  <input
262
- class="mc-field"
288
+ class="sa-marketing-field"
263
289
  :placeholder="autoCtaText(row)"
264
290
  :value="row.m.ctaLabel ?? ''"
265
291
  :disabled="busy"
@@ -269,17 +295,22 @@
269
295
  })
270
296
  "
271
297
  />
272
- <div class="mc-expand-hint">{{ msg.admin.ctaOverrideHint }}</div>
298
+ <div class="sa-marketing-expand-hint">
299
+ {{ msg.admin.ctaOverrideHint }}
300
+ </div>
273
301
  </div>
274
302
  </div>
275
303
 
276
- <div class="mc-expand-col">
277
- <div class="mc-expand-sec">
278
- <div class="mc-tf-head">
279
- <label class="mc-expand-label" style="margin: 0">
304
+ <div class="sa-marketing-expand-col">
305
+ <div class="sa-marketing-expand-sec">
306
+ <div class="sa-marketing-tf-head">
307
+ <label class="sa-marketing-expand-label" style="margin: 0">
280
308
  {{ msg.topFeatures }}
281
309
  </label>
282
- <span class="mc-expand-hint" style="margin-left: auto">
310
+ <span
311
+ class="sa-marketing-expand-hint"
312
+ style="margin-left: auto"
313
+ >
283
314
  {{
284
315
  formatMessage(msg.admin.topFeatureCount, {
285
316
  count: editFeatures.length,
@@ -288,11 +319,15 @@
288
319
  </span>
289
320
  </div>
290
321
 
291
- <div class="mc-tf-list">
292
- <div v-for="(f, i) in editFeatures" :key="i" class="mc-tf-row">
293
- <span class="mc-tf-num">{{ i + 1 }}</span>
322
+ <div class="sa-marketing-tf-list">
323
+ <div
324
+ v-for="(f, i) in editFeatures"
325
+ :key="i"
326
+ class="sa-marketing-tf-row"
327
+ >
328
+ <span class="sa-marketing-tf-num">{{ i + 1 }}</span>
294
329
  <input
295
- class="mc-field mc-tf-label"
330
+ class="sa-marketing-field sa-marketing-tf-label"
296
331
  :placeholder="
297
332
  f.key
298
333
  ? resolveComponentLabel(f.key)
@@ -306,7 +341,7 @@
306
341
  @change="$emit('persist-features', row)"
307
342
  />
308
343
  <input
309
- class="mc-field mc-tf-strong"
344
+ class="sa-marketing-field sa-marketing-tf-strong"
310
345
  :placeholder="msg.admin.featureStrongPlaceholder"
311
346
  :value="f.strong"
312
347
  :disabled="busy"
@@ -315,10 +350,10 @@
315
350
  "
316
351
  @change="$emit('persist-features', row)"
317
352
  />
318
- <div class="mc-tf-actions">
353
+ <div class="sa-marketing-tf-actions">
319
354
  <button
320
355
  type="button"
321
- class="mc-iconbtn"
356
+ class="sa-marketing-iconbtn"
322
357
  :title="msg.admin.moveUp"
323
358
  :disabled="i === 0 || busy"
324
359
  @click="$emit('move-feature', row, i, -1)"
@@ -327,7 +362,7 @@
327
362
  </button>
328
363
  <button
329
364
  type="button"
330
- class="mc-iconbtn"
365
+ class="sa-marketing-iconbtn"
331
366
  :title="msg.admin.moveDown"
332
367
  :disabled="i === editFeatures.length - 1 || busy"
333
368
  @click="$emit('move-feature', row, i, 1)"
@@ -336,7 +371,7 @@
336
371
  </button>
337
372
  <button
338
373
  type="button"
339
- class="mc-iconbtn mc-iconbtn--danger"
374
+ class="sa-marketing-iconbtn sa-marketing-iconbtn--danger"
340
375
  :title="common.remove"
341
376
  :disabled="busy"
342
377
  @click="$emit('remove-feature', row, i)"
@@ -354,15 +389,18 @@
354
389
  </button>
355
390
  </div>
356
391
  </div>
357
- <div v-if="editFeatures.length === 0" class="mc-tf-empty">
392
+ <div
393
+ v-if="editFeatures.length === 0"
394
+ class="sa-marketing-tf-empty"
395
+ >
358
396
  {{ msg.admin.topFeaturesEmpty }}
359
397
  </div>
360
398
  </div>
361
399
 
362
- <div class="mc-tf-add">
400
+ <div class="sa-marketing-tf-add">
363
401
  <button
364
402
  type="button"
365
- class="mc-btn mc-btn--sm"
403
+ class="sa-btn sa-btn--sm"
366
404
  :disabled="busy"
367
405
  @click="$emit('add-feature', row)"
368
406
  >
@@ -380,16 +418,16 @@
380
418
  </button>
381
419
  <div
382
420
  v-if="suggestionsFor(row).length > 0"
383
- class="mc-tf-suggestions"
421
+ class="sa-marketing-tf-suggestions"
384
422
  >
385
- <span class="mc-expand-hint">
423
+ <span class="sa-marketing-expand-hint">
386
424
  {{ msg.admin.suggestionsLabel }}
387
425
  </span>
388
426
  <button
389
427
  v-for="(s, i) in suggestionsFor(row)"
390
428
  :key="i"
391
429
  type="button"
392
- class="mc-tf-chip"
430
+ class="sa-marketing-tf-chip"
393
431
  :disabled="busy"
394
432
  :title="
395
433
  formatMessage(msg.admin.addSuggestionTitle, {