@saasicat/ui-vue 0.22.2 → 0.24.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 (119) hide show
  1. package/README.md +1 -1
  2. package/dist/{chunk-LY52T4N4.js → chunk-TQQMKWN6.js} +58 -1
  3. package/dist/{chunk-XMMFN2WJ.js → chunk-VYMTWCTT.js} +51 -1
  4. package/dist/client/index.cjs +57 -0
  5. package/dist/client/index.d.cts +58 -1
  6. package/dist/client/index.d.ts +58 -1
  7. package/dist/client/index.js +15 -1
  8. package/dist/index.cjs +321 -159
  9. package/dist/index.d.cts +67 -4
  10. package/dist/index.d.ts +67 -4
  11. package/dist/index.js +72 -2
  12. package/dist/quasar/index.cjs +116 -20
  13. package/dist/quasar/index.d.cts +48 -3
  14. package/dist/quasar/index.d.ts +48 -3
  15. package/dist/quasar/index.js +58 -3
  16. package/dist/{use-super-admin-i18n-CgTuNi8h.d.cts → use-sa-theme-B5t7oXph.d.cts} +51 -1
  17. package/dist/{use-super-admin-i18n-CHNdsSlm.d.ts → use-sa-theme-OUBlaqgl.d.ts} +51 -1
  18. package/package.json +5 -2
  19. package/src/client/identity-accents.ts +129 -0
  20. package/src/client/index.ts +1 -0
  21. package/src/components/BundleVersionPublishDialog.vue +17 -17
  22. package/src/components/KvBlock.vue +6 -6
  23. package/src/components/MarketingPromotionsTab.vue +84 -80
  24. package/src/components/MfaPromptDialog.vue +2 -2
  25. package/src/components/TenantActionConfirmDialog.vue +5 -5
  26. package/src/components/VersionDiffPreview.vue +18 -18
  27. package/src/components/bundle-editor/BundleCreatePanel.vue +52 -52
  28. package/src/components/bundle-editor/BundleFeaturesEditor.vue +20 -20
  29. package/src/components/bundle-editor/BundlePlanCompatPicker.vue +33 -33
  30. package/src/components/bundle-editor/BundleQuotasEditor.vue +26 -26
  31. package/src/components/bundle-editor/BundleStatusBanner.vue +21 -21
  32. package/src/components/bundle-editor/BundleVersionInlineEditor.vue +49 -49
  33. package/src/components/bundle-editor/BundleVersionStrip.vue +30 -30
  34. package/src/components/dialogs/PilotCreateDialog.vue +20 -20
  35. package/src/components/dialogs/PilotEditDialog.vue +6 -6
  36. package/src/components/dialogs/PromoCodeCreateDialog.vue +9 -9
  37. package/src/components/dialogs/PromoCodeDialogFields.vue +64 -63
  38. package/src/components/dialogs/PromoCodeEditDialog.vue +11 -11
  39. package/src/components/dialogs/pilot-dialog.css +48 -48
  40. package/src/components/plan/PlanCycleToggle.vue +9 -16
  41. package/src/components/plan/PlanGrid.vue +30 -34
  42. package/src/components/plan/PriceSummary.vue +35 -35
  43. package/src/components/plan/PromoCodeInput.vue +26 -26
  44. package/src/components/plan/PublicBundleGrid.vue +32 -28
  45. package/src/components/plan-create-dialog/PlanCreateDialog.vue +50 -50
  46. package/src/components/plan-detail/PlanDetail.vue +178 -157
  47. package/src/components/plan-detail/PlanTitleEdit.vue +11 -11
  48. package/src/components/plan-list/PlanList.vue +116 -100
  49. package/src/components/plan-matrix/PlanMatrix.vue +97 -114
  50. package/src/components/plan-review/PlanReview.vue +61 -57
  51. package/src/components/plan-version-editor/PlanVersionEditor.vue +246 -203
  52. package/src/components/wizard-stepper/WizardStepper.vue +17 -17
  53. package/src/index.ts +1 -0
  54. package/src/pages-standard/AdminLayout.vue +58 -37
  55. package/src/pages-standard/AdminManifestErrorPage.vue +6 -6
  56. package/src/pages-standard/AuditPage.vue +3 -3
  57. package/src/pages-standard/BundlesPage.vue +37 -37
  58. package/src/pages-standard/DashboardPage.vue +22 -19
  59. package/src/pages-standard/DiscoveryPage.vue +55 -49
  60. package/src/pages-standard/EmailHistoryPage.vue +53 -71
  61. package/src/pages-standard/MarketingCatalogPage.vue +245 -221
  62. package/src/pages-standard/PilotsPage.vue +7 -6
  63. package/src/pages-standard/PlatformEmailPage.vue +18 -18
  64. package/src/pages-standard/PromoCodeDetailPage.vue +3 -3
  65. package/src/pages-standard/PromoCodesPage.vue +10 -7
  66. package/src/pages-standard/SuperAdminLoginPage.vue +39 -25
  67. package/src/pages-standard/SuperAdminSetupWizard.vue +44 -33
  68. package/src/pages-standard/TenantDetailPage.vue +7 -7
  69. package/src/pages-standard/TenantsPage.vue +16 -50
  70. package/src/pages-standard/bundles-page/BundleAccordionList.vue +13 -13
  71. package/src/pages-standard/discovery-page/CatalogEntryTransPanel.vue +24 -24
  72. package/src/pages-standard/discovery-page/DiscoveryCapList.vue +22 -22
  73. package/src/pages-standard/discovery-page/DiscoveryFeatureCard.vue +39 -39
  74. package/src/pages-standard/discovery-page/DiscoveryQuotaCard.vue +26 -26
  75. package/src/pages-standard/discovery-page/DiscoveryStatusControl.vue +1 -1
  76. package/src/pages-standard/discovery-page/discovery-ui.ts +10 -7
  77. package/src/pages-standard/marketing-catalog/MarketingCatalogAdmin.vue +2 -5
  78. package/src/pages-standard/plan-versions/PlanDiffCard.vue +27 -20
  79. package/src/pages-standard/plan-versions/PlanVersionsDiff.vue +24 -16
  80. package/src/pages-standard/plan-versions/PlanVersionsTimeline.vue +45 -45
  81. package/src/pages-standard/plans-page/PlanBundleOverview.vue +21 -15
  82. package/src/pages-standard/plans-page/PlanPublishDialog.vue +4 -4
  83. package/src/pages-standard/plans-page/PlansPageToast.vue +6 -6
  84. package/src/pages-standard/sa-theme.css +9 -687
  85. package/src/pages-standard/tenants/StatusPill.vue +13 -13
  86. package/src/pages-standard/tenants/format.ts +11 -12
  87. package/src/pages-tenant/LimitsRow.vue +4 -4
  88. package/src/pages-tenant/MySubscriptionBundlesPage.vue +70 -61
  89. package/src/pages-tenant/OnboardingConfigurator.vue +25 -25
  90. package/src/pages-tenant/PackageSnapshotPanel.vue +10 -16
  91. package/src/pages-tenant/PendingVersionBanner.vue +12 -12
  92. package/src/pages-tenant/PlanChangeWizard.vue +22 -76
  93. package/src/pages-tenant/TenantPlanSection.vue +19 -69
  94. package/src/pages-tenant/UsageBar.vue +7 -7
  95. package/src/pages-tenant/default-i18n.ts +113 -0
  96. package/src/pages-tenant/tenant-plan-section/BundlePreviewDialog.vue +14 -14
  97. package/src/pages-tenant/tenant-plan-section/TenantBundleStore.vue +10 -10
  98. package/src/pages-tenant/tenant-plan-section/TenantFeatureMatrix.vue +2 -2
  99. package/src/quasar/create-super-admin-app.ts +96 -1
  100. package/src/quasar/dark-bridge.ts +66 -0
  101. package/src/quasar/index.ts +1 -0
  102. package/src/ui/theme/_breakpoints.scss +34 -0
  103. package/src/ui/theme/base.css +50 -0
  104. package/src/ui/theme/components/body.css +23 -0
  105. package/src/ui/theme/components/button.css +158 -0
  106. package/src/ui/theme/components/card.css +74 -0
  107. package/src/ui/theme/components/field.css +38 -0
  108. package/src/ui/theme/components/hero.css +46 -0
  109. package/src/ui/theme/components/paginator.css +63 -0
  110. package/src/ui/theme/components/section.css +67 -0
  111. package/src/ui/theme/components/statistics.css +189 -0
  112. package/src/ui/theme/components/table.css +60 -0
  113. package/src/ui/theme/index.css +42 -0
  114. package/src/ui/theme/tokens.legacy.css +147 -0
  115. package/src/ui/theme/tokens.primitive.css +112 -0
  116. package/src/ui/theme/tokens.scale.css +103 -0
  117. package/src/ui/theme/tokens.semantic.dark.css +185 -0
  118. package/src/ui/theme/tokens.semantic.light.css +242 -0
  119. package/src/vue/use-sa-theme.ts +154 -0
@@ -465,12 +465,18 @@ onMounted(() => {
465
465
  flex-direction: column;
466
466
  gap: 14px;
467
467
  }
468
+ .sa-discovery__panel {
469
+ display: flex;
470
+ flex-direction: column;
471
+ background-color: var(--sa-color-bg-surface);
472
+ padding: 16px 0 0;
473
+ }
468
474
  .sa-discovery__banner {
469
475
  display: flex;
470
476
  justify-content: space-between;
471
477
  align-items: center;
472
- background: var(--sa-heading);
473
- color: var(--sa-border);
478
+ background: var(--sa-color-inverse-bg);
479
+ color: var(--sa-color-inverse-fg-muted);
474
480
  border-radius: 12px;
475
481
  padding: 14px 18px;
476
482
  }
@@ -481,30 +487,30 @@ onMounted(() => {
481
487
  }
482
488
  .sa-discovery__banner-name {
483
489
  font-weight: 700;
484
- font-size: 14px;
490
+ font-size: var(--sa-text-lg);
485
491
  }
486
492
  .sa-discovery__banner-meta {
487
- font-size: 11px;
488
- color: var(--sa-muted-light);
493
+ font-size: var(--sa-text-xs);
494
+ color: var(--sa-color-fg-subtle);
489
495
  }
490
496
  .sa-discovery__banner-time {
491
497
  text-align: right;
492
498
  }
493
499
  .sa-discovery__banner-time-lbl {
494
- font-size: 10px;
500
+ font-size: var(--sa-text-2xs);
495
501
  text-transform: uppercase;
496
502
  letter-spacing: 0.5px;
497
- color: var(--sa-muted-light);
503
+ color: var(--sa-color-fg-subtle);
498
504
  }
499
505
  .sa-discovery__banner-time-val {
500
- font-size: 13px;
506
+ font-size: var(--sa-text-md);
501
507
  font-weight: 600;
502
508
  }
503
509
  .sa-discovery__error {
504
- border-left: 4px solid #dc2626;
510
+ border-left: 4px solid var(--sa-color-negative);
505
511
  }
506
512
  .sa-discovery__tabs {
507
- border-bottom: 1px solid var(--sa-border);
513
+ border-bottom: 1px solid var(--sa-color-border);
508
514
  }
509
515
  .sa-discovery__search {
510
516
  flex: 1;
@@ -521,100 +527,100 @@ onMounted(() => {
521
527
  margin-bottom: 16px;
522
528
  }
523
529
  .sa-discovery__group--orphan .sa-section__title {
524
- color: #b45309;
530
+ color: var(--sa-color-warning-fg);
525
531
  }
526
532
  .sa-discovery__group-count {
527
- font-size: 10px;
533
+ font-size: var(--sa-text-2xs);
528
534
  font-weight: 700;
529
- background: var(--sa-border);
530
- color: var(--sa-muted-dark);
535
+ background: var(--sa-color-border);
536
+ color: var(--sa-color-fg-secondary);
531
537
  padding: 1px 7px;
532
538
  border-radius: 8px;
533
539
  }
534
540
  .sa-discovery__orphan-hint {
535
541
  margin: 0 0 8px;
536
- font-size: 11px;
537
- color: #b45309;
542
+ font-size: var(--sa-text-xs);
543
+ color: var(--sa-color-warning-fg);
538
544
  }
539
545
  .sa-discovery__orphan-hint code {
540
- font-size: 10px;
541
- background: var(--sa-warning-bg);
546
+ font-size: var(--sa-text-2xs);
547
+ background: var(--sa-color-warning-surface);
542
548
  padding: 1px 4px;
543
549
  border-radius: 4px;
544
550
  }
545
551
  .sa-discovery__empty-row {
546
552
  padding: 36px;
547
553
  text-align: center;
548
- color: var(--sa-muted-light);
549
- font-size: 13px;
550
- border: 1px dashed #cbd5e1;
554
+ color: var(--sa-color-fg-subtle);
555
+ font-size: var(--sa-text-md);
556
+ border: 1px dashed var(--sa-color-border-strong);
551
557
  border-radius: 12px;
552
558
  }
553
559
  .sa-muted {
554
- color: var(--sa-muted-light);
560
+ color: var(--sa-color-fg-subtle);
555
561
  margin-right: 3px;
556
562
  }
557
563
  /* Status badge (review lifecycle) — shared by feature and quota card. */
558
564
  .sa-review {
559
- font-size: 10px;
565
+ font-size: var(--sa-text-2xs);
560
566
  font-weight: 700;
561
567
  text-transform: uppercase;
562
568
  padding: 3px 8px;
563
569
  border-radius: 6px;
564
- background: var(--sa-border-soft);
565
- color: var(--sa-muted-dark);
570
+ background: var(--sa-color-border-soft);
571
+ color: var(--sa-color-fg-secondary);
566
572
  flex-shrink: 0;
567
573
  }
568
574
  .sa-review--pending {
569
- background: #fef3c7;
570
- color: #92400e;
575
+ background: var(--sa-color-warning-surface-strong);
576
+ color: var(--sa-color-warning-fg);
571
577
  }
572
578
  .sa-review--approved {
573
- background: #dcfce7;
574
- color: #166534;
579
+ background: var(--sa-color-positive-surface-strong);
580
+ color: var(--sa-color-positive-fg);
575
581
  }
576
582
  .sa-review--outdated {
577
- background: #fee2e2;
578
- color: #b91c1c;
583
+ background: var(--sa-color-negative-surface-strong);
584
+ color: var(--sa-color-negative-fg);
579
585
  }
580
586
  .sa-review--obsolete {
581
- background: var(--sa-border);
582
- color: var(--sa-muted);
587
+ background: var(--sa-color-border);
588
+ color: var(--sa-color-fg-muted);
583
589
  }
584
590
  .sa-chip {
585
- font-size: 10px;
591
+ font-size: var(--sa-text-2xs);
586
592
  font-weight: 600;
587
593
  padding: 2px 7px;
588
594
  border-radius: 6px;
589
- background: var(--sa-border-soft);
590
- color: var(--sa-muted-dark);
595
+ background: var(--sa-color-border-soft);
596
+ color: var(--sa-color-fg-secondary);
591
597
  }
592
598
  /* i18n coverage pill — shared by feature and quota card. */
593
599
  .sa-cov-pill {
594
600
  display: inline-flex;
595
601
  align-items: center;
596
602
  gap: 4px;
597
- font-size: 10px;
603
+ font-size: var(--sa-text-2xs);
598
604
  font-weight: 700;
599
605
  padding: 2px 7px;
600
606
  border-radius: 8px;
601
- border: 1px solid var(--sa-border);
602
- background: var(--sa-bg-surface-2);
603
- color: var(--sa-muted-dark);
607
+ border: 1px solid var(--sa-color-border);
608
+ background: var(--sa-color-bg-sunken);
609
+ color: var(--sa-color-fg-secondary);
604
610
  }
605
611
  .sa-cov-pill.complete {
606
- border-color: #a7f3d0;
607
- background: var(--sa-positive-bg);
608
- color: #047857;
612
+ border-color: var(--sa-color-positive-border);
613
+ background: var(--sa-color-positive-surface);
614
+ color: var(--sa-color-positive-fg);
609
615
  }
610
616
  .sa-cov-pill.warn {
611
- border-color: #fde68a;
612
- background: var(--sa-warning-bg);
613
- color: #b45309;
617
+ border-color: var(--sa-color-warning-border);
618
+ background: var(--sa-color-warning-surface);
619
+ color: var(--sa-color-warning-fg);
614
620
  }
615
621
  .sa-cov-pill.low {
616
- border-color: #fecaca;
617
- background: #fef2f2;
618
- color: #b91c1c;
622
+ border-color: var(--sa-color-negative-border);
623
+ background: var(--sa-color-negative-surface);
624
+ color: var(--sa-color-negative-fg);
619
625
  }
620
626
  </style>
@@ -7,8 +7,8 @@
7
7
  </AdminHero>
8
8
 
9
9
  <AdminBody>
10
- <AdminSection class="sa-emh__body">
11
- <div class="sa-emh__filter">
10
+ <AdminSection>
11
+ <AdminFilters class="q-mb-lg">
12
12
  <q-input
13
13
  v-model="filter.search"
14
14
  outlined
@@ -50,53 +50,51 @@
50
50
  :label="common.to"
51
51
  @update:model-value="applyFilter"
52
52
  />
53
- </div>
54
-
55
- <div class="sa-emh__card">
56
- <AdminTable
57
- server-side
58
- :rows="rows"
59
- :columns="columns"
60
- :loading="loading"
61
- :page="pagination.page"
62
- :rows-per-page="pagination.rowsPerPage"
63
- :total="pagination.rowsNumber"
64
- storage-key="email-history"
65
- @row-click="(_evt: Event, row: EmailHistoryRow) => openDetail(row)"
66
- @update:page="onPageChange"
67
- @update:rows-per-page="onRowsPerPageChange"
68
- >
69
- <template #body-cell-status="{ row }">
70
- <q-td>
71
- <q-badge
72
- :color="statusColor(row.status)"
73
- :label="statusLabel(row.status)"
74
- />
75
- </q-td>
76
- </template>
77
- <template #row-actions="{ row }">
78
- <q-btn
79
- flat
80
- dense
81
- icon="send"
82
- color="primary"
83
- :title="msg.history.resend"
84
- @click.stop="onResend(row.id)"
85
- />
86
- <q-btn
87
- flat
88
- dense
89
- icon="delete"
90
- color="negative"
91
- :title="msg.history.removeFromHistory"
92
- @click.stop="askDelete(row.id)"
53
+ </AdminFilters>
54
+
55
+ <AdminTable
56
+ server-side
57
+ :rows="rows"
58
+ :columns="columns"
59
+ :loading="loading"
60
+ :page="pagination.page"
61
+ :rows-per-page="pagination.rowsPerPage"
62
+ :total="pagination.rowsNumber"
63
+ storage-key="email-history"
64
+ @row-click="(_evt: Event, row: EmailHistoryRow) => openDetail(row)"
65
+ @update:page="onPageChange"
66
+ @update:rows-per-page="onRowsPerPageChange"
67
+ >
68
+ <template #body-cell-status="{ row }">
69
+ <q-td>
70
+ <q-badge
71
+ :color="statusColor(row.status)"
72
+ :label="statusLabel(row.status)"
93
73
  />
94
- </template>
95
- <template #no-data>
96
- <div class="sa-emh__empty">{{ msg.history.empty }}</div>
97
- </template>
98
- </AdminTable>
99
- </div>
74
+ </q-td>
75
+ </template>
76
+ <template #row-actions="{ row }">
77
+ <button
78
+ type="button"
79
+ class="sa-icon-btn"
80
+ :title="msg.history.resend"
81
+ @click.stop="onResend(row.id)"
82
+ >
83
+ <q-icon name="send" size="18px" />
84
+ </button>
85
+ <button
86
+ type="button"
87
+ class="sa-icon-btn sa-icon-btn--negative"
88
+ :title="msg.history.removeFromHistory"
89
+ @click.stop="askDelete(row.id)"
90
+ >
91
+ <q-icon name="delete" size="18px" />
92
+ </button>
93
+ </template>
94
+ <template #no-data>
95
+ <div class="sa-emh__empty">{{ msg.history.empty }}</div>
96
+ </template>
97
+ </AdminTable>
100
98
  </AdminSection>
101
99
  </AdminBody>
102
100
 
@@ -222,6 +220,7 @@ import { computed, reactive, ref } from 'vue';
222
220
  import { useMfaPrompt } from '../vue/use-mfa-prompt.js';
223
221
  import AdminRefreshBtn from '../components/admin-page/AdminRefreshBtn.vue';
224
222
  import AdminBody from '../components/admin-page/AdminBody.vue';
223
+ import AdminFilters from '../components/admin-page/AdminFilters.vue';
225
224
  import AdminHero from '../components/admin-page/AdminHero.vue';
226
225
  import AdminSection from '../components/admin-page/AdminSection.vue';
227
226
  import AdminPage from '../components/admin-page/AdminPage.vue';
@@ -506,27 +505,10 @@ function formatTs(iso: string | null | undefined): string {
506
505
  </script>
507
506
 
508
507
  <style scoped>
509
- .sa-emh__filter {
510
- display: flex;
511
- gap: 10px;
512
- margin-bottom: 12px;
513
- flex-wrap: wrap;
514
- }
515
- .sa-emh__filter > * {
516
- flex: 1;
517
- min-width: 180px;
518
- }
519
- .sa-emh__card {
520
- background: #fff;
521
- border: 1px solid var(--sa-border, var(--sa-border));
522
- border-radius: 12px;
523
- overflow: hidden;
524
- padding: 8px 0;
525
- }
526
508
  .sa-emh__empty {
527
509
  width: 100%;
528
510
  text-align: center;
529
- color: var(--sa-muted-dark, var(--sa-muted));
511
+ color: var(--sa-color-fg-secondary, var(--sa-color-fg-muted));
530
512
  padding: 24px 0;
531
513
  }
532
514
  .sa-emh__detail {
@@ -544,17 +526,17 @@ function formatTs(iso: string | null | undefined): string {
544
526
  width: 100%;
545
527
  min-height: 320px;
546
528
  max-height: 60vh;
547
- border: 1px solid var(--sa-border, var(--sa-border));
529
+ border: 1px solid var(--sa-color-border);
548
530
  border-radius: 8px;
549
- background: #fff;
531
+ background: var(--sa-color-bg-surface);
550
532
  }
551
533
  .sa-emh__text,
552
534
  .sa-emh__smtp {
553
- background: var(--sa-bg-surface-2);
554
- border: 1px solid var(--sa-border, var(--sa-border));
535
+ background: var(--sa-color-bg-sunken);
536
+ border: 1px solid var(--sa-color-border);
555
537
  border-radius: 8px;
556
538
  padding: 12px;
557
- font-size: 12px;
539
+ font-size: var(--sa-text-sm);
558
540
  margin: 4px 0 0;
559
541
  overflow-x: auto;
560
542
  max-height: 50vh;