@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.
- package/README.md +1 -1
- package/dist/{chunk-LY52T4N4.js → chunk-TQQMKWN6.js} +58 -1
- package/dist/{chunk-XMMFN2WJ.js → chunk-VYMTWCTT.js} +51 -1
- package/dist/client/index.cjs +57 -0
- package/dist/client/index.d.cts +58 -1
- package/dist/client/index.d.ts +58 -1
- package/dist/client/index.js +15 -1
- package/dist/index.cjs +321 -159
- package/dist/index.d.cts +67 -4
- package/dist/index.d.ts +67 -4
- package/dist/index.js +72 -2
- package/dist/quasar/index.cjs +116 -20
- package/dist/quasar/index.d.cts +48 -3
- package/dist/quasar/index.d.ts +48 -3
- package/dist/quasar/index.js +58 -3
- package/dist/{use-super-admin-i18n-CgTuNi8h.d.cts → use-sa-theme-B5t7oXph.d.cts} +51 -1
- package/dist/{use-super-admin-i18n-CHNdsSlm.d.ts → use-sa-theme-OUBlaqgl.d.ts} +51 -1
- package/package.json +5 -2
- package/src/client/identity-accents.ts +129 -0
- package/src/client/index.ts +1 -0
- package/src/components/BundleVersionPublishDialog.vue +17 -17
- package/src/components/KvBlock.vue +6 -6
- package/src/components/MarketingPromotionsTab.vue +84 -80
- package/src/components/MfaPromptDialog.vue +2 -2
- package/src/components/TenantActionConfirmDialog.vue +5 -5
- package/src/components/VersionDiffPreview.vue +18 -18
- package/src/components/bundle-editor/BundleCreatePanel.vue +52 -52
- package/src/components/bundle-editor/BundleFeaturesEditor.vue +20 -20
- package/src/components/bundle-editor/BundlePlanCompatPicker.vue +33 -33
- package/src/components/bundle-editor/BundleQuotasEditor.vue +26 -26
- package/src/components/bundle-editor/BundleStatusBanner.vue +21 -21
- package/src/components/bundle-editor/BundleVersionInlineEditor.vue +49 -49
- package/src/components/bundle-editor/BundleVersionStrip.vue +30 -30
- package/src/components/dialogs/PilotCreateDialog.vue +20 -20
- package/src/components/dialogs/PilotEditDialog.vue +6 -6
- package/src/components/dialogs/PromoCodeCreateDialog.vue +9 -9
- package/src/components/dialogs/PromoCodeDialogFields.vue +64 -63
- package/src/components/dialogs/PromoCodeEditDialog.vue +11 -11
- package/src/components/dialogs/pilot-dialog.css +48 -48
- package/src/components/plan/PlanCycleToggle.vue +9 -16
- package/src/components/plan/PlanGrid.vue +30 -34
- package/src/components/plan/PriceSummary.vue +35 -35
- package/src/components/plan/PromoCodeInput.vue +26 -26
- package/src/components/plan/PublicBundleGrid.vue +32 -28
- package/src/components/plan-create-dialog/PlanCreateDialog.vue +50 -50
- package/src/components/plan-detail/PlanDetail.vue +178 -157
- package/src/components/plan-detail/PlanTitleEdit.vue +11 -11
- package/src/components/plan-list/PlanList.vue +116 -100
- package/src/components/plan-matrix/PlanMatrix.vue +97 -114
- package/src/components/plan-review/PlanReview.vue +61 -57
- package/src/components/plan-version-editor/PlanVersionEditor.vue +246 -203
- package/src/components/wizard-stepper/WizardStepper.vue +17 -17
- package/src/index.ts +1 -0
- package/src/pages-standard/AdminLayout.vue +58 -37
- package/src/pages-standard/AdminManifestErrorPage.vue +6 -6
- package/src/pages-standard/AuditPage.vue +3 -3
- package/src/pages-standard/BundlesPage.vue +37 -37
- package/src/pages-standard/DashboardPage.vue +22 -19
- package/src/pages-standard/DiscoveryPage.vue +55 -49
- package/src/pages-standard/EmailHistoryPage.vue +53 -71
- package/src/pages-standard/MarketingCatalogPage.vue +245 -221
- package/src/pages-standard/PilotsPage.vue +7 -6
- package/src/pages-standard/PlatformEmailPage.vue +18 -18
- package/src/pages-standard/PromoCodeDetailPage.vue +3 -3
- package/src/pages-standard/PromoCodesPage.vue +10 -7
- package/src/pages-standard/SuperAdminLoginPage.vue +39 -25
- package/src/pages-standard/SuperAdminSetupWizard.vue +44 -33
- package/src/pages-standard/TenantDetailPage.vue +7 -7
- package/src/pages-standard/TenantsPage.vue +16 -50
- package/src/pages-standard/bundles-page/BundleAccordionList.vue +13 -13
- package/src/pages-standard/discovery-page/CatalogEntryTransPanel.vue +24 -24
- package/src/pages-standard/discovery-page/DiscoveryCapList.vue +22 -22
- package/src/pages-standard/discovery-page/DiscoveryFeatureCard.vue +39 -39
- package/src/pages-standard/discovery-page/DiscoveryQuotaCard.vue +26 -26
- package/src/pages-standard/discovery-page/DiscoveryStatusControl.vue +1 -1
- package/src/pages-standard/discovery-page/discovery-ui.ts +10 -7
- package/src/pages-standard/marketing-catalog/MarketingCatalogAdmin.vue +2 -5
- package/src/pages-standard/plan-versions/PlanDiffCard.vue +27 -20
- package/src/pages-standard/plan-versions/PlanVersionsDiff.vue +24 -16
- package/src/pages-standard/plan-versions/PlanVersionsTimeline.vue +45 -45
- package/src/pages-standard/plans-page/PlanBundleOverview.vue +21 -15
- package/src/pages-standard/plans-page/PlanPublishDialog.vue +4 -4
- package/src/pages-standard/plans-page/PlansPageToast.vue +6 -6
- package/src/pages-standard/sa-theme.css +9 -687
- package/src/pages-standard/tenants/StatusPill.vue +13 -13
- package/src/pages-standard/tenants/format.ts +11 -12
- package/src/pages-tenant/LimitsRow.vue +4 -4
- package/src/pages-tenant/MySubscriptionBundlesPage.vue +70 -61
- package/src/pages-tenant/OnboardingConfigurator.vue +25 -25
- package/src/pages-tenant/PackageSnapshotPanel.vue +10 -16
- package/src/pages-tenant/PendingVersionBanner.vue +12 -12
- package/src/pages-tenant/PlanChangeWizard.vue +22 -76
- package/src/pages-tenant/TenantPlanSection.vue +19 -69
- package/src/pages-tenant/UsageBar.vue +7 -7
- package/src/pages-tenant/default-i18n.ts +113 -0
- package/src/pages-tenant/tenant-plan-section/BundlePreviewDialog.vue +14 -14
- package/src/pages-tenant/tenant-plan-section/TenantBundleStore.vue +10 -10
- package/src/pages-tenant/tenant-plan-section/TenantFeatureMatrix.vue +2 -2
- package/src/quasar/create-super-admin-app.ts +96 -1
- package/src/quasar/dark-bridge.ts +66 -0
- package/src/quasar/index.ts +1 -0
- package/src/ui/theme/_breakpoints.scss +34 -0
- package/src/ui/theme/base.css +50 -0
- package/src/ui/theme/components/body.css +23 -0
- package/src/ui/theme/components/button.css +158 -0
- package/src/ui/theme/components/card.css +74 -0
- package/src/ui/theme/components/field.css +38 -0
- package/src/ui/theme/components/hero.css +46 -0
- package/src/ui/theme/components/paginator.css +63 -0
- package/src/ui/theme/components/section.css +67 -0
- package/src/ui/theme/components/statistics.css +189 -0
- package/src/ui/theme/components/table.css +60 -0
- package/src/ui/theme/index.css +42 -0
- package/src/ui/theme/tokens.legacy.css +147 -0
- package/src/ui/theme/tokens.primitive.css +112 -0
- package/src/ui/theme/tokens.scale.css +103 -0
- package/src/ui/theme/tokens.semantic.dark.css +185 -0
- package/src/ui/theme/tokens.semantic.light.css +242 -0
- package/src/vue/use-sa-theme.ts +154 -0
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
// The colour-scheme switch. Framework-neutral half: no Quasar import here, so
|
|
2
|
+
// the main entry stays free of an optional peer dependency (`src/quasar/
|
|
3
|
+
// dark-bridge.ts` is the half that talks to Quasar and the DOM).
|
|
4
|
+
//
|
|
5
|
+
// Three schemes, and `'system'` is the default because it is the only one that
|
|
6
|
+
// is right without being asked. `resolved` collapses it to the two the
|
|
7
|
+
// stylesheet knows about, so a caller never has to ask "and what does 'system'
|
|
8
|
+
// mean right now".
|
|
9
|
+
//
|
|
10
|
+
// Following the operating system lives HERE and not in the stylesheet, and
|
|
11
|
+
// that is load-bearing rather than tidy. The stylesheet paints the platform's
|
|
12
|
+
// surfaces; Quasar paints its own cards, dialogs and steppers, and follows only
|
|
13
|
+
// `body--dark`. A media query in the stylesheet moves one of them — measured on
|
|
14
|
+
// an embedded page with the OS set to dark, that meant a white Quasar card
|
|
15
|
+
// carrying near-white platform text. Only the application can move both, so
|
|
16
|
+
// only the application decides, and this is where it does.
|
|
17
|
+
|
|
18
|
+
import {
|
|
19
|
+
computed,
|
|
20
|
+
inject,
|
|
21
|
+
isRef,
|
|
22
|
+
ref,
|
|
23
|
+
watch,
|
|
24
|
+
type ComputedRef,
|
|
25
|
+
type InjectionKey,
|
|
26
|
+
type Ref,
|
|
27
|
+
} from 'vue';
|
|
28
|
+
|
|
29
|
+
import { defaultKvStore, type KvStore } from '../client/types.js';
|
|
30
|
+
|
|
31
|
+
export type SaColorScheme = 'light' | 'dark' | 'system';
|
|
32
|
+
export type SaResolvedScheme = 'light' | 'dark';
|
|
33
|
+
|
|
34
|
+
const SCHEMES: readonly SaColorScheme[] = ['light', 'dark', 'system'];
|
|
35
|
+
const STORAGE_KEY = 'saasicat.theme.scheme';
|
|
36
|
+
|
|
37
|
+
export interface SaTheme {
|
|
38
|
+
/** What the operator picked. Writable — assigning switches the theme. */
|
|
39
|
+
scheme: Ref<SaColorScheme>;
|
|
40
|
+
/** What that means right now: `'system'` resolved against the OS. */
|
|
41
|
+
resolved: ComputedRef<SaResolvedScheme>;
|
|
42
|
+
/**
|
|
43
|
+
* Releases the `prefers-color-scheme` subscription and the persistence
|
|
44
|
+
* watcher. Idempotent.
|
|
45
|
+
*
|
|
46
|
+
* Needed because this context outlives no component — nothing unmounts it.
|
|
47
|
+
* A second shell in the same document (hot reload, a micro-frontend, a
|
|
48
|
+
* second test file) would otherwise leave the first one subscribed, and the
|
|
49
|
+
* next change of the operating system's theme would drive TWO bridges, both
|
|
50
|
+
* writing `data-sa-theme` and Quasar's `Dark` onto the one document. The
|
|
51
|
+
* stale one can win, and then the new shell's explicit scheme is overruled
|
|
52
|
+
* by a context nobody holds a reference to any more.
|
|
53
|
+
*/
|
|
54
|
+
dispose: () => void;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export interface SaThemeOptions {
|
|
58
|
+
/** Starting scheme. Pass a `Ref` to keep the value in your own store. */
|
|
59
|
+
scheme?: SaColorScheme | Ref<SaColorScheme>;
|
|
60
|
+
/**
|
|
61
|
+
* Remember the operator's pick across reloads, default `true`. Ignored when
|
|
62
|
+
* `scheme` is a `Ref`: the app owns that value and persists it where it
|
|
63
|
+
* belongs. Same rule as the locale in `createSuperAdminI18n`.
|
|
64
|
+
*/
|
|
65
|
+
persist?: boolean;
|
|
66
|
+
/** Injection seam for tests. */
|
|
67
|
+
storage?: KvStore;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function isScheme(value: unknown): value is SaColorScheme {
|
|
71
|
+
return typeof value === 'string' && SCHEMES.includes(value as SaColorScheme);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Live `prefers-color-scheme`, as a ref that updates when the OS setting does,
|
|
76
|
+
* plus the handle that unsubscribes it.
|
|
77
|
+
*
|
|
78
|
+
* A one-time read would leave every open tab on the old theme when somebody
|
|
79
|
+
* flips their system to dark at sunset — which is exactly when they flip it.
|
|
80
|
+
* Returns a constant `'light'` where `matchMedia` does not exist (SSR, jsdom
|
|
81
|
+
* without a stub), because guessing dark for a missing API is worse than
|
|
82
|
+
* matching the CSS default.
|
|
83
|
+
*/
|
|
84
|
+
function systemScheme(): { value: Ref<SaResolvedScheme>; unsubscribe: () => void } {
|
|
85
|
+
const value = ref<SaResolvedScheme>('light');
|
|
86
|
+
if (typeof window === 'undefined' || typeof window.matchMedia !== 'function') {
|
|
87
|
+
return { value, unsubscribe: () => {} };
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const query = window.matchMedia('(prefers-color-scheme: dark)');
|
|
91
|
+
value.value = query.matches ? 'dark' : 'light';
|
|
92
|
+
const onChange = (event: MediaQueryListEvent) => {
|
|
93
|
+
value.value = event.matches ? 'dark' : 'light';
|
|
94
|
+
};
|
|
95
|
+
// `addEventListener` since Safari 14; no fallback to the deprecated
|
|
96
|
+
// `addListener`, because the package's Quasar peer needs a newer browser
|
|
97
|
+
// than that anyway.
|
|
98
|
+
query.addEventListener('change', onChange);
|
|
99
|
+
return { value, unsubscribe: () => query.removeEventListener('change', onChange) };
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Creates the theme context. `createSuperAdminApp()` makes one and the Quasar
|
|
104
|
+
* bridge mirrors it onto the document; call it directly only when bootstrapping
|
|
105
|
+
* by hand.
|
|
106
|
+
*/
|
|
107
|
+
export function createSaTheme(options: SaThemeOptions = {}): SaTheme {
|
|
108
|
+
const storage = options.storage ?? defaultKvStore();
|
|
109
|
+
const persist = options.persist !== false;
|
|
110
|
+
// `isRef`, like `createSuperAdminI18n` next door. Branched inline rather
|
|
111
|
+
// than through a boolean, because a boolean does not narrow the union and
|
|
112
|
+
// the version that went through one needed three casts to compile.
|
|
113
|
+
const provided = options.scheme;
|
|
114
|
+
const appOwnsIt = isRef(provided);
|
|
115
|
+
|
|
116
|
+
const stored = persist && !appOwnsIt ? storage.get(STORAGE_KEY) : null;
|
|
117
|
+
const scheme = isRef(provided)
|
|
118
|
+
? provided
|
|
119
|
+
: ref<SaColorScheme>(isScheme(stored) ? stored : (provided ?? 'system'));
|
|
120
|
+
const { value: system, unsubscribe } = systemScheme();
|
|
121
|
+
|
|
122
|
+
const stopPersisting =
|
|
123
|
+
persist && !appOwnsIt ? watch(scheme, (next) => storage.set(STORAGE_KEY, next)) : null;
|
|
124
|
+
|
|
125
|
+
return {
|
|
126
|
+
scheme,
|
|
127
|
+
resolved: computed(() => (scheme.value === 'system' ? system.value : scheme.value)),
|
|
128
|
+
dispose: () => {
|
|
129
|
+
unsubscribe();
|
|
130
|
+
stopPersisting?.();
|
|
131
|
+
},
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// `Symbol.for` — see super-admin-context.ts: dist- and src-imported module
|
|
136
|
+
// instances must resolve to the same injection key.
|
|
137
|
+
export const SA_THEME_KEY: InjectionKey<SaTheme> = Symbol.for('@saasicat/ui-vue/SA_THEME');
|
|
138
|
+
|
|
139
|
+
let fallbackTheme: SaTheme | null = null;
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* The shell's theme context, or a shared unpersisted one outside a shell.
|
|
143
|
+
*
|
|
144
|
+
* Same shape as `useSuperAdminI18n()`, and for the same reason: a component
|
|
145
|
+
* mounted in isolation must render rather than throw, and the fallback must not
|
|
146
|
+
* write to real storage or two tests in one process would decide each other's
|
|
147
|
+
* outcome.
|
|
148
|
+
*/
|
|
149
|
+
export function useSaTheme(): SaTheme {
|
|
150
|
+
const injected = inject(SA_THEME_KEY, null);
|
|
151
|
+
if (injected) return injected;
|
|
152
|
+
fallbackTheme ??= createSaTheme({ persist: false });
|
|
153
|
+
return fallbackTheme;
|
|
154
|
+
}
|