@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
@@ -25,7 +25,7 @@ defineProps<{
25
25
  display: inline-flex;
26
26
  align-items: center;
27
27
  gap: 4px;
28
- font-size: 10.5px;
28
+ font-size: var(--sa-text-xs);
29
29
  font-weight: 700;
30
30
  letter-spacing: 0.04em;
31
31
  padding: 3px 8px;
@@ -36,27 +36,27 @@ defineProps<{
36
36
  color: inherit;
37
37
  }
38
38
  .sa-pill--positive {
39
- background: var(--sa-positive-soft, rgba(4, 120, 87, 0.1));
40
- color: var(--sa-positive, #047857);
39
+ background: var(--sa-color-positive-surface);
40
+ color: var(--sa-color-positive-fg);
41
41
  }
42
42
  .sa-pill--warning {
43
- background: var(--sa-warning-soft, rgba(245, 158, 11, 0.1));
44
- color: var(--sa-warning, #b45309);
43
+ background: var(--sa-color-warning-surface-strong);
44
+ color: var(--sa-color-warning-fg);
45
45
  }
46
46
  .sa-pill--negative {
47
- background: var(--sa-negative-soft, rgba(220, 38, 38, 0.08));
48
- color: var(--sa-negative, #dc2626);
47
+ background: var(--sa-color-negative-surface);
48
+ color: var(--sa-color-negative);
49
49
  }
50
50
  .sa-pill--muted {
51
- background: var(--sa-border-soft);
52
- color: var(--sa-muted, var(--sa-muted));
51
+ background: var(--sa-color-border-soft);
52
+ color: var(--sa-color-fg-muted);
53
53
  }
54
54
  .sa-pill--primary {
55
- background: var(--sa-primary-soft, rgba(63, 107, 255, 0.08));
56
- color: var(--sa-primary, #3f6bff);
55
+ background: var(--sa-color-accent-surface);
56
+ color: var(--sa-color-accent);
57
57
  }
58
58
  .sa-pill--accent {
59
- background: rgba(245, 158, 11, 0.16);
60
- color: #b45309;
59
+ background: var(--sa-color-warning-surface-strong);
60
+ color: var(--sa-color-warning-fg);
61
61
  }
62
62
  </style>
@@ -1,16 +1,15 @@
1
1
  // Formatting helpers for the tenants page.
2
2
  //
3
3
  // Shared between TenantsPage.vue and subcomponents (Avatar, Pill).
4
- // Apps with their own plan accents pass them through via the `planAccents` prop;
5
- // the default map covers the standard plan IDs (BASIC..ENTERPRISE).
4
+ // Apps with their own plan accents pass them through via the `planAccents` prop.
5
+ //
6
+ // The default map used to live here as five hex literals, and it disagreed with
7
+ // the two in `PlanList`/`PlanMatrix`: `STANDARD` was the brand blue on this page
8
+ // and a plain blue on the plans page, `ENTERPRISE` near-black here and teal
9
+ // there. Same plan, three colours, depending on which screen you were looking
10
+ // at. It now comes from the shared ramp, so the answer is one.
6
11
 
7
- export const DEFAULT_PLAN_ACCENTS: Record<string, string> = {
8
- BASIC: '#94a3b8',
9
- STANDARD: '#3f6bff',
10
- PROFESSIONAL: '#7c3aed',
11
- BUSINESS: '#0ea5e9',
12
- ENTERPRISE: '#0f172a',
13
- };
12
+ import { IDENTITY_NEUTRAL, identityAccentFor } from '../../client/identity-accents.js';
14
13
 
15
14
  export function tenantInitials(name: string | null | undefined): string {
16
15
  if (!name) return '?';
@@ -22,10 +21,10 @@ export function tenantInitials(name: string | null | undefined): string {
22
21
 
23
22
  export function planAccent(
24
23
  planId: string | null | undefined,
25
- accents: Record<string, string> = DEFAULT_PLAN_ACCENTS,
24
+ accents: Record<string, string> = {},
26
25
  ): string {
27
- if (!planId) return '#94a3b8';
28
- return accents[planId] ?? '#3f6bff';
26
+ if (!planId) return IDENTITY_NEUTRAL;
27
+ return identityAccentFor(planId, accents);
29
28
  }
30
29
 
31
30
  /** `locale` is a BCP-47 tag — pages pass `intlLocale.value` of the active UI locale. */
@@ -44,7 +44,7 @@ function formatMax(n: number): string {
44
44
 
45
45
  <style scoped>
46
46
  .sp-limits-row {
47
- border-bottom: 1px solid rgba(0, 0, 0, 0.06);
47
+ border-bottom: 1px solid var(--sa-color-border-soft);
48
48
  }
49
49
  .sp-limits-row td {
50
50
  padding: 8px 12px;
@@ -54,14 +54,14 @@ function formatMax(n: number): string {
54
54
  font-weight: 500;
55
55
  }
56
56
  .sp-limits-row__target--ok {
57
- color: var(--q-positive, #21ba45);
57
+ color: var(--sa-color-positive);
58
58
  font-weight: 600;
59
59
  }
60
60
  .sp-limits-row__target--bad {
61
- color: var(--q-negative, #c10015);
61
+ color: var(--sa-color-negative);
62
62
  font-weight: 600;
63
63
  }
64
64
  .sp-limits-row--exceeded {
65
- background: rgba(193, 0, 21, 0.05);
65
+ background: var(--sa-color-negative-surface);
66
66
  }
67
67
  </style>
@@ -188,6 +188,7 @@
188
188
  <script setup lang="ts">
189
189
  import { computed, onMounted, reactive, ref } from 'vue';
190
190
  import type { SubscriptionBundleRecord } from '@saasicat/types';
191
+ import type { HttpClient } from '../client/types.js';
191
192
 
192
193
  import { useSuperAdminI18n } from '../vue/use-super-admin-i18n.js';
193
194
  import { useTenantSubscriptionBundles } from '../vue/use-tenant-subscription-bundles.js';
@@ -213,6 +214,13 @@ interface BookableBundle {
213
214
  const props = withDefaults(
214
215
  defineProps<{
215
216
  billingEndpoint: string;
217
+ /**
218
+ * App-specific HTTP adapter, as every other tenant-facing component
219
+ * takes. Without it this page fell through to `defaultHttpClient()`,
220
+ * so an app using axios with an auth interceptor got a bare `fetch()`
221
+ * here and nowhere else — and no fixture could reach it either.
222
+ */
223
+ http?: HttpClient;
216
224
  /**
217
225
  * Mapping `bundleVersionId → BundleKey/Label` (the consumer can
218
226
  * preload this from the public catalog). Without a mapping we show the
@@ -253,6 +261,7 @@ const effectiveI18n = computed<TenantPlanSectionI18n>(() => ({
253
261
  const { bundles, loading, error, load, add, cancel } = useTenantSubscriptionBundles({
254
262
  billingEndpoint: props.billingEndpoint,
255
263
  getAuthToken: props.getAuthToken,
264
+ http: props.http,
256
265
  });
257
266
 
258
267
  onMounted(() => load());
@@ -400,7 +409,7 @@ function formatDate(date: Date | string | null | undefined): string {
400
409
  BlinkMacSystemFont,
401
410
  system-ui,
402
411
  sans-serif;
403
- color: var(--sa-heading);
412
+ color: var(--sa-color-fg-heading);
404
413
  }
405
414
  .msb-head {
406
415
  display: flex;
@@ -410,45 +419,45 @@ function formatDate(date: Date | string | null | undefined): string {
410
419
  }
411
420
  .msb-title {
412
421
  margin: 0;
413
- font-size: 20px;
422
+ font-size: var(--sa-text-xl);
414
423
  font-weight: 700;
415
424
  letter-spacing: -0.01em;
416
425
  }
417
426
  .msb-sub {
418
427
  margin: 4px 0 0;
419
- color: var(--sa-muted);
420
- font-size: 13px;
428
+ color: var(--sa-color-fg-muted);
429
+ font-size: var(--sa-text-md);
421
430
  max-width: 580px;
422
431
  line-height: 1.5;
423
432
  }
424
433
  .msb-loading {
425
434
  padding: 32px;
426
435
  text-align: center;
427
- color: var(--sa-muted);
436
+ color: var(--sa-color-fg-muted);
428
437
  }
429
438
  .msb-empty {
430
439
  padding: 32px 24px;
431
440
  text-align: center;
432
- background: #fff;
433
- border: 1px dashed #cbd5e1;
441
+ background: var(--sa-color-bg-surface);
442
+ border: 1px dashed var(--sa-color-border-strong);
434
443
  border-radius: 12px;
435
- color: var(--sa-muted-dark);
444
+ color: var(--sa-color-fg-secondary);
436
445
  }
437
446
  .msb-empty-link {
438
447
  background: transparent;
439
448
  border: 0;
440
- color: var(--sa-primary);
449
+ color: var(--sa-color-accent);
441
450
  cursor: pointer;
442
451
  font: inherit;
443
452
  text-decoration: underline;
444
453
  }
445
454
  .msb-error {
446
455
  padding: 10px 14px;
447
- background: #fef2f2;
448
- border: 1px solid #fecaca;
456
+ background: var(--sa-color-negative-surface);
457
+ border: 1px solid var(--sa-color-negative-border);
449
458
  border-radius: 8px;
450
- color: #b91c1c;
451
- font-size: 13px;
459
+ color: var(--sa-color-negative-fg);
460
+ font-size: var(--sa-text-md);
452
461
  }
453
462
  .msb-list {
454
463
  display: flex;
@@ -456,14 +465,14 @@ function formatDate(date: Date | string | null | undefined): string {
456
465
  gap: 10px;
457
466
  }
458
467
  .msb-card {
459
- background: #fff;
460
- border: 1px solid var(--sa-border);
468
+ background: var(--sa-color-bg-surface);
469
+ border: 1px solid var(--sa-color-border);
461
470
  border-radius: 12px;
462
471
  padding: 14px 18px;
463
472
  }
464
473
  .msb-card--canceled-pending {
465
- border-color: #fde68a;
466
- background: var(--sa-warning-bg);
474
+ border-color: var(--sa-color-warning-border);
475
+ background: var(--sa-color-warning-surface);
467
476
  }
468
477
  .msb-card--canceled {
469
478
  opacity: 0.65;
@@ -482,18 +491,18 @@ function formatDate(date: Date | string | null | undefined): string {
482
491
  }
483
492
  .msb-card-key {
484
493
  font:
485
- 700 13px 'JetBrains Mono',
494
+ 700 var(--sa-text-md) 'JetBrains Mono',
486
495
  ui-monospace,
487
496
  monospace;
488
497
  letter-spacing: 0.04em;
489
498
  }
490
499
  .msb-card-meta {
491
500
  margin-top: 4px;
492
- font-size: 12.5px;
493
- color: var(--sa-muted);
501
+ font-size: var(--sa-text-md);
502
+ color: var(--sa-color-fg-muted);
494
503
  }
495
504
  .msb-chip {
496
- font-size: 10.5px;
505
+ font-size: var(--sa-text-xs);
497
506
  font-weight: 700;
498
507
  text-transform: uppercase;
499
508
  letter-spacing: 0.06em;
@@ -501,25 +510,25 @@ function formatDate(date: Date | string | null | undefined): string {
501
510
  border-radius: 999px;
502
511
  }
503
512
  .msb-chip--active {
504
- background: #d1fae5;
505
- color: #065f46;
513
+ background: var(--sa-color-positive-surface-strong);
514
+ color: var(--sa-color-positive-fg);
506
515
  }
507
516
  .msb-chip--canceled-pending {
508
- background: #fef3c7;
509
- color: #92400e;
517
+ background: var(--sa-color-warning-surface-strong);
518
+ color: var(--sa-color-warning-fg);
510
519
  }
511
520
  .msb-chip--canceled {
512
- background: var(--sa-border);
513
- color: var(--sa-muted-dark);
521
+ background: var(--sa-color-border);
522
+ color: var(--sa-color-fg-secondary);
514
523
  }
515
524
  .msb-cancel-info {
516
525
  margin-top: 10px;
517
526
  padding: 8px 12px;
518
- background: var(--sa-warning-bg);
519
- border: 1px solid #fde68a;
527
+ background: var(--sa-color-warning-surface);
528
+ border: 1px solid var(--sa-color-warning-border);
520
529
  border-radius: 6px;
521
- color: #92400e;
522
- font-size: 12.5px;
530
+ color: var(--sa-color-warning-fg);
531
+ font-size: var(--sa-text-md);
523
532
  }
524
533
 
525
534
  .msb-btn {
@@ -527,51 +536,51 @@ function formatDate(date: Date | string | null | undefined): string {
527
536
  align-items: center;
528
537
  gap: 6px;
529
538
  padding: 7px 14px;
530
- background: #fff;
531
- border: 1px solid #cbd5e1;
539
+ background: var(--sa-color-bg-surface);
540
+ border: 1px solid var(--sa-color-border-strong);
532
541
  border-radius: 7px;
533
542
  cursor: pointer;
534
543
  font-family: inherit;
535
- font-size: 13px;
536
- color: var(--sa-heading);
544
+ font-size: var(--sa-text-md);
545
+ color: var(--sa-color-fg-heading);
537
546
  }
538
547
  .msb-btn:hover:not(:disabled) {
539
- background: var(--sa-bg-surface-2);
548
+ background: var(--sa-color-bg-sunken);
540
549
  }
541
550
  .msb-btn:disabled {
542
551
  cursor: not-allowed;
543
552
  opacity: 0.55;
544
553
  }
545
554
  .msb-btn--primary {
546
- background: var(--sa-primary);
547
- border-color: var(--sa-primary);
548
- color: #fff;
555
+ background: var(--sa-color-accent);
556
+ border-color: var(--sa-color-accent);
557
+ color: var(--sa-color-fg-on-accent);
549
558
  }
550
559
  .msb-btn--primary:hover:not(:disabled) {
551
- background: var(--sa-primary-strong);
560
+ background: var(--sa-color-accent-strong);
552
561
  }
553
562
  .msb-btn--ghost {
554
563
  background: transparent;
555
- border-color: #fca5a5;
556
- color: #b91c1c;
564
+ border-color: var(--sa-color-negative-border);
565
+ color: var(--sa-color-negative-fg);
557
566
  }
558
567
  .msb-btn--ghost:hover:not(:disabled) {
559
- background: #fef2f2;
568
+ background: var(--sa-color-negative-surface);
560
569
  }
561
570
 
562
571
  .msb-modal-bg {
563
572
  position: fixed;
564
573
  inset: 0;
565
- background: rgba(15, 23, 42, 0.55);
574
+ background: var(--sa-color-bg-overlay);
566
575
  display: grid;
567
576
  place-items: center;
568
577
  z-index: 1000;
569
578
  }
570
579
  .msb-modal {
571
580
  width: min(520px, 96vw);
572
- background: #fff;
581
+ background: var(--sa-color-bg-surface);
573
582
  border-radius: 12px;
574
- box-shadow: 0 20px 60px rgba(15, 23, 42, 0.25);
583
+ box-shadow: 0 20px 60px var(--sa-shadow-tint-4);
575
584
  display: flex;
576
585
  flex-direction: column;
577
586
  }
@@ -580,23 +589,23 @@ function formatDate(date: Date | string | null | undefined): string {
580
589
  align-items: center;
581
590
  justify-content: space-between;
582
591
  padding: 16px 20px 10px;
583
- border-bottom: 1px solid var(--sa-border);
592
+ border-bottom: 1px solid var(--sa-color-border);
584
593
  }
585
594
  .msb-modal-title {
586
- font-size: 16px;
595
+ font-size: var(--sa-text-lg);
587
596
  font-weight: 700;
588
597
  }
589
598
  .msb-modal-x {
590
599
  background: transparent;
591
600
  border: 0;
592
601
  cursor: pointer;
593
- color: var(--sa-muted);
602
+ color: var(--sa-color-fg-muted);
594
603
  padding: 4px;
595
604
  border-radius: 4px;
596
605
  }
597
606
  .msb-modal-x:hover {
598
- background: var(--sa-border-soft);
599
- color: var(--sa-heading);
607
+ background: var(--sa-color-border-soft);
608
+ color: var(--sa-color-fg-heading);
600
609
  }
601
610
  .msb-modal-body {
602
611
  padding: 16px 20px;
@@ -606,8 +615,8 @@ function formatDate(date: Date | string | null | undefined): string {
606
615
  }
607
616
  .msb-modal-foot {
608
617
  padding: 12px 20px;
609
- border-top: 1px solid var(--sa-border);
610
- background: var(--sa-bg-surface-2);
618
+ border-top: 1px solid var(--sa-color-border);
619
+ background: var(--sa-color-bg-sunken);
611
620
  border-radius: 0 0 12px 12px;
612
621
  display: flex;
613
622
  justify-content: flex-end;
@@ -619,21 +628,21 @@ function formatDate(date: Date | string | null | undefined): string {
619
628
  gap: 4px;
620
629
  }
621
630
  .msb-field-label {
622
- font-size: 12px;
631
+ font-size: var(--sa-text-sm);
623
632
  font-weight: 600;
624
- color: var(--sa-muted-dark);
633
+ color: var(--sa-color-fg-secondary);
625
634
  }
626
635
  .msb-field-hint {
627
- font-size: 11px;
628
- color: var(--sa-muted-light);
636
+ font-size: var(--sa-text-xs);
637
+ color: var(--sa-color-fg-subtle);
629
638
  }
630
639
  .msb-input {
631
640
  padding: 7px 10px;
632
- border: 1px solid #cbd5e1;
641
+ border: 1px solid var(--sa-color-border-strong);
633
642
  border-radius: 6px;
634
643
  font-family: inherit;
635
- font-size: 13px;
636
- color: var(--sa-heading);
637
- background: #fff;
644
+ font-size: var(--sa-text-md);
645
+ color: var(--sa-color-fg-heading);
646
+ background: var(--sa-color-bg-surface);
638
647
  }
639
648
  </style>
@@ -302,24 +302,24 @@ defineExpose({ draft });
302
302
  align-items: center;
303
303
  gap: 8px;
304
304
  font-family: 'SF Mono', Consolas, monospace;
305
- font-size: 11px;
305
+ font-size: var(--sa-text-xs);
306
306
  letter-spacing: 0.1em;
307
307
  text-transform: uppercase;
308
- color: var(--q-primary, #0f766e);
309
- background: rgba(15, 118, 110, 0.08);
308
+ color: var(--sa-color-accent);
309
+ background: var(--sa-color-accent-surface);
310
310
  padding: 6px 11px;
311
311
  border-radius: 999px;
312
- border: 1px solid rgba(15, 118, 110, 0.2);
312
+ border: 1px solid var(--sa-color-accent-border);
313
313
  }
314
314
  .sp-onb__header h1 {
315
315
  margin: 12px 0 8px;
316
- font-size: clamp(1.6rem, 3vw, 2.4rem);
316
+ font-size: var(--sa-text-4xl);
317
317
  line-height: 1.1;
318
318
  letter-spacing: -0.01em;
319
319
  }
320
320
  .sp-onb__header p {
321
321
  margin: 0;
322
- color: rgba(0, 0, 0, 0.6);
322
+ color: var(--sa-color-fg-secondary);
323
323
  max-width: 640px;
324
324
  }
325
325
  .sp-onb__layout {
@@ -328,7 +328,7 @@ defineExpose({ draft });
328
328
  gap: 24px;
329
329
  align-items: start;
330
330
  }
331
- @media (max-width: 1100px) {
331
+ @media (max-width: 1023.98px) {
332
332
  .sp-onb__layout {
333
333
  grid-template-columns: 1fr;
334
334
  }
@@ -339,26 +339,26 @@ defineExpose({ draft });
339
339
  gap: 20px;
340
340
  }
341
341
  .sp-onb__section {
342
- background: #fff;
343
- border: 1px solid rgba(0, 0, 0, 0.08);
342
+ background: var(--sa-color-bg-surface);
343
+ border: 1px solid var(--sa-color-border);
344
344
  border-radius: 22px;
345
345
  padding: 26px 28px 24px;
346
- box-shadow: 0 24px 80px rgba(31, 41, 51, 0.05);
346
+ box-shadow: 0 24px 80px var(--sa-shadow-tint-1);
347
347
  }
348
348
  .sp-onb__sec-head {
349
349
  padding-bottom: 14px;
350
350
  margin-bottom: 18px;
351
- border-bottom: 1px dashed rgba(0, 0, 0, 0.08);
351
+ border-bottom: 1px dashed var(--sa-color-border);
352
352
  }
353
353
  .sp-onb__sec-head h2 {
354
354
  margin: 6px 0 0;
355
- font-size: 1.4rem;
355
+ font-size: var(--sa-text-2xl);
356
356
  letter-spacing: -0.005em;
357
357
  }
358
358
  .sp-onb__sec-head p {
359
359
  margin: 4px 0 0;
360
- color: rgba(0, 0, 0, 0.55);
361
- font-size: 13px;
360
+ color: var(--sa-color-fg-muted);
361
+ font-size: var(--sa-text-md);
362
362
  max-width: 520px;
363
363
  }
364
364
  .sp-onb__sec-num {
@@ -366,22 +366,22 @@ defineExpose({ draft });
366
366
  align-items: center;
367
367
  gap: 8px;
368
368
  font-family: 'SF Mono', Consolas, monospace;
369
- font-size: 11px;
369
+ font-size: var(--sa-text-xs);
370
370
  letter-spacing: 0.16em;
371
371
  text-transform: uppercase;
372
- color: var(--q-primary, #0f766e);
372
+ color: var(--sa-color-accent);
373
373
  font-weight: 700;
374
374
  }
375
375
  .sp-onb__sec-num::before {
376
376
  content: '';
377
377
  width: 28px;
378
378
  height: 1px;
379
- background: var(--q-primary, #0f766e);
379
+ background: var(--sa-color-accent);
380
380
  }
381
381
  .sp-onb__loading {
382
382
  padding: 40px;
383
383
  text-align: center;
384
- color: rgba(0, 0, 0, 0.5);
384
+ color: var(--sa-color-fg-subtle);
385
385
  }
386
386
  .sp-onb__actions {
387
387
  display: flex;
@@ -392,22 +392,22 @@ defineExpose({ draft });
392
392
  }
393
393
  .sp-onb__back-btn {
394
394
  background: none;
395
- border: 1px solid rgba(0, 0, 0, 0.15);
395
+ border: 1px solid var(--sa-color-border-strong);
396
396
  border-radius: 10px;
397
397
  padding: 10px 16px;
398
398
  font-family: inherit;
399
- font-size: 13px;
399
+ font-size: var(--sa-text-md);
400
400
  cursor: pointer;
401
- color: rgba(0, 0, 0, 0.7);
401
+ color: var(--sa-color-fg-body);
402
402
  }
403
403
  .sp-onb__back-btn:hover {
404
- border-color: rgba(0, 0, 0, 0.4);
404
+ border-color: var(--sa-color-border-strong);
405
405
  }
406
406
  .sp-onb__error {
407
- color: #b91c1c;
408
- background: rgba(220, 38, 38, 0.08);
407
+ color: var(--sa-color-negative-fg);
408
+ background: var(--sa-color-negative-surface);
409
409
  padding: 10px 14px;
410
410
  border-radius: 8px;
411
- font-size: 13px;
411
+ font-size: var(--sa-text-md);
412
412
  }
413
413
  </style>
@@ -157,16 +157,10 @@ const rawJson = computed(() => {
157
157
 
158
158
  <style scoped>
159
159
  .sp-package-snapshot {
160
- --sp-text-muted: rgba(0, 0, 0, 0.55);
161
- --sp-text-strong: rgba(0, 0, 0, 0.85);
162
- --sp-border: rgba(0, 0, 0, 0.08);
163
- --sp-pre-bg: rgba(0, 0, 0, 0.04);
164
- }
165
- body.body--dark .sp-package-snapshot {
166
- --sp-text-muted: rgba(255, 255, 255, 0.62);
167
- --sp-text-strong: rgba(255, 255, 255, 0.85);
168
- --sp-border: rgba(255, 255, 255, 0.16);
169
- --sp-pre-bg: rgba(255, 255, 255, 0.06);
160
+ --sp-text-muted: var(--sa-color-fg-muted);
161
+ --sp-text-strong: var(--sa-color-fg-heading);
162
+ --sp-border: var(--sa-color-border);
163
+ --sp-pre-bg: var(--sa-color-bg-sunken);
170
164
  }
171
165
  .sp-package-snapshot__head {
172
166
  display: flex;
@@ -176,7 +170,7 @@ body.body--dark .sp-package-snapshot {
176
170
  flex-wrap: wrap;
177
171
  }
178
172
  .sp-package-snapshot__eyebrow {
179
- font-size: 12px;
173
+ font-size: var(--sa-text-sm);
180
174
  text-transform: uppercase;
181
175
  letter-spacing: 0.05em;
182
176
  color: var(--sp-text-muted);
@@ -186,11 +180,11 @@ body.body--dark .sp-package-snapshot {
186
180
  .sp-package-snapshot__sub {
187
181
  margin: 0;
188
182
  color: var(--sp-text-muted);
189
- font-size: 13px;
183
+ font-size: var(--sa-text-md);
190
184
  }
191
185
  .sp-package-snapshot__empty {
192
186
  color: var(--sp-text-muted);
193
- font-size: 13px;
187
+ font-size: var(--sa-text-md);
194
188
  font-style: italic;
195
189
  }
196
190
  .sp-package-snapshot__list {
@@ -210,7 +204,7 @@ body.body--dark .sp-package-snapshot {
210
204
  }
211
205
  .sp-package-snapshot__muted {
212
206
  color: var(--sp-text-muted);
213
- font-size: 13px;
207
+ font-size: var(--sa-text-md);
214
208
  }
215
209
  .sp-package-snapshot__bundles {
216
210
  margin: 0;
@@ -227,13 +221,13 @@ body.body--dark .sp-package-snapshot {
227
221
  padding: 12px;
228
222
  background: var(--sp-pre-bg);
229
223
  border-radius: 4px;
230
- font-size: 12px;
224
+ font-size: var(--sa-text-sm);
231
225
  overflow-x: auto;
232
226
  max-height: 320px;
233
227
  }
234
228
  code {
235
229
  font-family: 'SFMono-Regular', Menlo, Consolas, monospace;
236
- font-size: 12px;
230
+ font-size: var(--sa-text-sm);
237
231
  background: var(--sp-pre-bg);
238
232
  padding: 1px 4px;
239
233
  border-radius: 3px;
@@ -71,8 +71,8 @@ defineEmits<{ accept: [] }>();
71
71
 
72
72
  <style scoped>
73
73
  .sp-pending-version {
74
- border: 1px solid rgba(242, 192, 55, 0.4);
75
- background: rgba(242, 192, 55, 0.08);
74
+ border: 1px solid var(--sa-color-warning-border);
75
+ background: var(--sa-color-warning-surface);
76
76
  border-radius: 6px;
77
77
  padding: 12px 16px;
78
78
  display: flex;
@@ -87,35 +87,35 @@ defineEmits<{ accept: [] }>();
87
87
  .sp-pending-version__chip {
88
88
  padding: 2px 8px;
89
89
  border-radius: 12px;
90
- font-size: 12px;
90
+ font-size: var(--sa-text-sm);
91
91
  font-weight: 600;
92
92
  text-transform: uppercase;
93
93
  }
94
94
  .sp-pending-version__chip--good {
95
- background: rgba(33, 186, 69, 0.15);
96
- color: var(--q-positive, #21ba45);
95
+ background: var(--sa-color-positive-surface-strong);
96
+ color: var(--sa-color-positive);
97
97
  }
98
98
  .sp-pending-version__chip--warn {
99
- background: rgba(193, 0, 21, 0.15);
100
- color: var(--q-negative, #c10015);
99
+ background: var(--sa-color-negative-surface-strong);
100
+ color: var(--sa-color-negative);
101
101
  }
102
102
  .sp-pending-version__note {
103
103
  margin: 0;
104
- color: rgba(0, 0, 0, 0.75);
104
+ color: var(--sa-color-fg-body);
105
105
  }
106
106
  .sp-pending-version__effective,
107
107
  .sp-pending-version__accepted {
108
108
  margin: 0;
109
- font-size: 13px;
110
- color: rgba(0, 0, 0, 0.6);
109
+ font-size: var(--sa-text-md);
110
+ color: var(--sa-color-fg-secondary);
111
111
  }
112
112
  .sp-pending-version__btn {
113
113
  align-self: flex-start;
114
114
  padding: 6px 14px;
115
115
  border-radius: 4px;
116
116
  border: 0;
117
- background: var(--q-primary, #1976d2);
118
- color: white;
117
+ background: var(--sa-color-accent);
118
+ color: var(--sa-color-fg-on-accent);
119
119
  font-weight: 600;
120
120
  cursor: pointer;
121
121
  }