@adobedjangir/commerce-admin-management 0.0.2

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 (48) hide show
  1. package/README.md +637 -0
  2. package/actions/commerce-creds.js +262 -0
  3. package/actions/configurations/commerce/index.js +41 -0
  4. package/actions/configurations/commerce-connection-save/index.js +53 -0
  5. package/actions/configurations/commerce-connection-status/index.js +27 -0
  6. package/actions/configurations/commerce-connection-test/index.js +47 -0
  7. package/actions/configurations/export-config/index.js +256 -0
  8. package/actions/configurations/ext.config.yaml +192 -0
  9. package/actions/configurations/import-config/index.js +541 -0
  10. package/actions/configurations/registration/index.js +37 -0
  11. package/actions/configurations/sync-store-mappings-from-commerce/index.js +190 -0
  12. package/actions/configurations/system-config-list/index.js +127 -0
  13. package/actions/configurations/system-config-save/index.js +160 -0
  14. package/actions/configurations/system-config-schema/index.js +327 -0
  15. package/actions/utils.js +73 -0
  16. package/package.json +80 -0
  17. package/scripts/build-web.js +58 -0
  18. package/scripts/setup.js +445 -0
  19. package/src/abdb-config.js +8 -0
  20. package/src/abdb-helper.js +8 -0
  21. package/src/index.js +22 -0
  22. package/src/oauth1a.js +8 -0
  23. package/src/system-config-crypto.js +8 -0
  24. package/src/system-config-shared.js +8 -0
  25. package/web/dist/index.css +305 -0
  26. package/web/dist/index.js +2986 -0
  27. package/web/index.js +7 -0
  28. package/web/src/components/App.js +54 -0
  29. package/web/src/components/AppSectionNav.js +49 -0
  30. package/web/src/components/CommerceSetupWizard.js +160 -0
  31. package/web/src/components/ExtensionRegistration.js +33 -0
  32. package/web/src/components/MainPage.js +147 -0
  33. package/web/src/components/SystemConfig.js +1464 -0
  34. package/web/src/components/SystemConfigSchemaEditor.js +459 -0
  35. package/web/src/hooks/useConfirm.js +355 -0
  36. package/web/src/hooks/useSystemConfig.js +238 -0
  37. package/web/src/hooks/useSystemConfigSchema.js +102 -0
  38. package/web/src/index.js +46 -0
  39. package/web/src/nav-icons.js +30 -0
  40. package/web/src/nav.json +10 -0
  41. package/web/src/pages/index.js +17 -0
  42. package/web/src/schema/systemConfigSchema.js +82 -0
  43. package/web/src/settings.js +101 -0
  44. package/web/src/styles/index.css +337 -0
  45. package/web/src/theme.js +104 -0
  46. package/web/src/utils/storeMappingsFromCommerceRest.js +73 -0
  47. package/web/src/utils.js +52 -0
  48. package/web/styles.css +337 -0
@@ -0,0 +1,104 @@
1
+ /*
2
+ Copyright 2025 Adobe. All rights reserved.
3
+ This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License. You may obtain a copy
5
+ of the License at http://www.apache.org/licenses/LICENSE-2.0
6
+ */
7
+
8
+ /**
9
+ * JS facade for the design tokens defined in `index.css`.
10
+ *
11
+ * Every value here is a CSS `var()` reference. Use these in inline styles
12
+ * (`style={{ color: THEME.color.accent }}`) so the rendered value resolves
13
+ * through CSS at runtime — changing the variable in `web/src/styles/index.css` re-skins
14
+ * everything that uses this object without touching any JS.
15
+ *
16
+ * Naming mirrors the CSS variable structure: --sm-color-accent → color.accent.
17
+ */
18
+ export const THEME = {
19
+ color: {
20
+ bg: 'var(--sm-color-bg)',
21
+ surface: 'var(--sm-color-surface)',
22
+ surfaceMuted: 'var(--sm-color-surface-muted)',
23
+ surfaceSubtle: 'var(--sm-color-surface-subtle)',
24
+ border: 'var(--sm-color-border)',
25
+ borderStrong: 'var(--sm-color-border-strong)',
26
+ text: 'var(--sm-color-text)',
27
+ textMuted: 'var(--sm-color-text-muted)',
28
+ textStrong: 'var(--sm-color-text-strong)',
29
+ textSoft: 'var(--sm-color-text-soft)',
30
+ textInverse: 'var(--sm-color-text-inverse)',
31
+ surfacePanel: 'var(--sm-color-surface-panel)',
32
+ accent: 'var(--sm-color-accent)',
33
+ accentHover: 'var(--sm-color-accent-hover)',
34
+ accentSoft: 'var(--sm-color-accent-soft)',
35
+ accentTint: 'var(--sm-color-accent-tint)',
36
+ success: 'var(--sm-color-success)',
37
+ successHover: 'var(--sm-color-success-hover)',
38
+ successSoft: 'var(--sm-color-success-soft)',
39
+ warning: 'var(--sm-color-warning)',
40
+ warningHover: 'var(--sm-color-warning-hover)',
41
+ warningSoft: 'var(--sm-color-warning-soft)',
42
+ warningBorder: 'var(--sm-color-warning-border)',
43
+ warningText: 'var(--sm-color-warning-text)',
44
+ warningTint: 'var(--sm-color-warning-tint)',
45
+ danger: 'var(--sm-color-danger)',
46
+ dangerHover: 'var(--sm-color-danger-hover)',
47
+ dangerSoft: 'var(--sm-color-danger-soft)',
48
+ dangerTint: 'var(--sm-color-danger-tint)',
49
+ neutralSoft: 'var(--sm-color-neutral-soft)',
50
+ neutralText: 'var(--sm-color-neutral-text)',
51
+ overlay: 'var(--sm-color-overlay)'
52
+ },
53
+ radius: {
54
+ sm: 'var(--sm-radius-sm)',
55
+ md: 'var(--sm-radius-md)',
56
+ lg: 'var(--sm-radius-lg)',
57
+ xl: 'var(--sm-radius-xl)',
58
+ xxl: 'var(--sm-radius-2xl)',
59
+ pill: 'var(--sm-radius-pill)'
60
+ },
61
+ space: {
62
+ 1: 'var(--sm-space-1)',
63
+ 2: 'var(--sm-space-2)',
64
+ 3: 'var(--sm-space-3)',
65
+ 4: 'var(--sm-space-4)',
66
+ 5: 'var(--sm-space-5)',
67
+ 6: 'var(--sm-space-6)'
68
+ },
69
+ shadow: {
70
+ xs: 'var(--sm-shadow-xs)',
71
+ sm: 'var(--sm-shadow-sm)',
72
+ md: 'var(--sm-shadow-md)',
73
+ pill: 'var(--sm-shadow-pill)',
74
+ floating: 'var(--sm-shadow-floating)',
75
+ dropdown: 'var(--sm-shadow-dropdown)',
76
+ modal: 'var(--sm-shadow-modal)',
77
+ inset: 'var(--sm-shadow-inset)'
78
+ },
79
+ font: {
80
+ family: 'var(--sm-font-family)',
81
+ mono: 'var(--sm-font-mono)',
82
+ sizeXs: 'var(--sm-font-size-xs)',
83
+ sizeSm: 'var(--sm-font-size-sm)',
84
+ sizeMd: 'var(--sm-font-size-md)',
85
+ sizeLg: 'var(--sm-font-size-lg)',
86
+ weightRegular: 'var(--sm-font-weight-regular)',
87
+ weightMedium: 'var(--sm-font-weight-medium)',
88
+ weightSemi: 'var(--sm-font-weight-semibold)',
89
+ weightBold: 'var(--sm-font-weight-bold)'
90
+ }
91
+ }
92
+
93
+ /**
94
+ * Flat alias of `THEME.color` — every colour token reachable as `PALETTE.x`.
95
+ *
96
+ * Components should use this for inline styles so there is exactly one
97
+ * facade for the design system: change a CSS variable in `web/src/styles/index.css` →
98
+ * every reference here resolves to the new value at runtime.
99
+ */
100
+ export const PALETTE = { ...THEME.color }
101
+ export const RADIUS = { ...THEME.radius }
102
+ export const SHADOW = { ...THEME.shadow }
103
+ export const SPACE = { ...THEME.space }
104
+ export const FONT = { ...THEME.font }
@@ -0,0 +1,73 @@
1
+ /*
2
+ Copyright 2025 Adobe. All rights reserved.
3
+ This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License. You may obtain a copy
5
+ of the License at http://www.apache.org/licenses/LICENSE-2.0
6
+ */
7
+
8
+ /** @param {string} locale e.g. en_US → en */
9
+ function localeToLanguageCode (locale) {
10
+ if (locale == null || locale === '') return null
11
+ const s = String(locale).trim()
12
+ const head = s.split(/[-_]/u)[0]
13
+ if (head && /^[a-zA-Z]{2,8}$/.test(head)) return head.toLowerCase()
14
+ return null
15
+ }
16
+
17
+ /** e.g. en_ch → en, de_ch → de */
18
+ function inferLanguageFromStoreCode (code) {
19
+ if (typeof code !== 'string') return null
20
+ const m = /^([a-z]{2})[-_]/i.exec(code)
21
+ return m ? m[1].toLowerCase() : null
22
+ }
23
+
24
+ /**
25
+ * Build `general/settings/store_mappings` shape from Commerce REST payloads
26
+ * (same shape as server middleware expects: keyed by store view id string).
27
+ *
28
+ * @param {object[]|null|undefined} websitesRaw from `store/websites`
29
+ * @param {object[]|null|undefined} storeViewsRaw from `store/storeViews`
30
+ * @param {object[]|null|undefined} storeConfigsRaw from `store/storeConfigs` (optional)
31
+ * @returns {Record<string, { code: string, language_code: string, website_code: string, website_id: string }>}
32
+ */
33
+ export function buildStoreMappingsFromCommercePayload (websitesRaw, storeViewsRaw, storeConfigsRaw) {
34
+ const websiteIdToCode = new Map()
35
+ if (Array.isArray(websitesRaw)) {
36
+ for (const w of websitesRaw) {
37
+ if (w && w.id != null && w.code != null) {
38
+ websiteIdToCode.set(String(w.id), String(w.code))
39
+ }
40
+ }
41
+ }
42
+
43
+ const storeCodeToLocale = new Map()
44
+ if (Array.isArray(storeConfigsRaw)) {
45
+ for (const cfg of storeConfigsRaw) {
46
+ if (cfg && cfg.code != null && cfg.locale != null) {
47
+ storeCodeToLocale.set(String(cfg.code), String(cfg.locale))
48
+ }
49
+ }
50
+ }
51
+
52
+ const mappings = {}
53
+ if (!Array.isArray(storeViewsRaw)) return mappings
54
+
55
+ for (const s of storeViewsRaw) {
56
+ if (!s || s.id == null || s.code == null) continue
57
+ const id = String(s.id)
58
+ const code = String(s.code)
59
+ const websiteId = s.website_id != null ? String(s.website_id) : ''
60
+ const websiteCode = websiteIdToCode.get(websiteId) || ''
61
+ const languageCode =
62
+ localeToLanguageCode(storeCodeToLocale.get(code)) ||
63
+ inferLanguageFromStoreCode(code) ||
64
+ 'en'
65
+ mappings[id] = {
66
+ code,
67
+ language_code: languageCode,
68
+ website_code: websiteCode,
69
+ website_id: websiteId
70
+ }
71
+ }
72
+ return mappings
73
+ }
@@ -0,0 +1,52 @@
1
+ /*
2
+ Copyright 2025 Adobe. All rights reserved.
3
+ This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License. You may obtain a copy
5
+ of the License at http://www.apache.org/licenses/LICENSE-2.0
6
+
7
+ Unless required by applicable law or agreed to in writing, software distributed under
8
+ the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9
+ OF ANY KIND, either express or implied. See the License for the specific language
10
+ governing permissions and limitations under the License.
11
+ */
12
+
13
+ import { getActionUrl } from './settings'
14
+
15
+ export async function callAction (props, action, operation, body = {}) {
16
+ const url = getActionUrl(action)
17
+ if (!url) {
18
+ throw new Error(`Action ${action} is not configured. Call configureWeb({ actionUrls }) with deploy-time URLs.`)
19
+ }
20
+ const res = await fetch(url, {
21
+ method: 'POST',
22
+ headers: {
23
+ 'Content-Type': 'application/json',
24
+ 'x-gw-ims-org-id': (props.ims && props.ims.org) || '',
25
+ authorization: `Bearer ${(props.ims && props.ims.token) || ''}`
26
+ },
27
+ body: JSON.stringify({
28
+ operation,
29
+ ...body
30
+ })
31
+ })
32
+
33
+ const text = await res.text()
34
+ let parsed
35
+ try {
36
+ parsed = JSON.parse(text)
37
+ } catch (e) {
38
+ throw new Error(`Invalid response from ${action}: ${text.slice(0, 200)}`)
39
+ }
40
+ if (!res.ok) {
41
+ const msg =
42
+ parsed?.error ||
43
+ parsed?.body?.error ||
44
+ parsed?.message ||
45
+ `Action ${action} failed with HTTP ${res.status}`
46
+ const err = new Error(typeof msg === 'string' ? msg : JSON.stringify(msg))
47
+ err.status = res.status
48
+ err.response = parsed
49
+ throw err
50
+ }
51
+ return parsed
52
+ }
package/web/styles.css ADDED
@@ -0,0 +1,337 @@
1
+ /*
2
+ Copyright 2025 Adobe. All rights reserved.
3
+ This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License. You may obtain a copy
5
+ of the License at http://www.apache.org/licenses/LICENSE-2.0
6
+ */
7
+
8
+ /* =========================================================================
9
+ sync-management — single source of truth for the UI theme.
10
+
11
+ To re-skin the app, change values under :root. Components consume these
12
+ tokens either directly via CSS classes (.sm-*) or via the JS facade in
13
+ `web-src/src/theme.js` which re-exports them as `var(--sm-*)` strings.
14
+
15
+ Token naming:
16
+ --sm-color-* colors
17
+ --sm-radius-* border radii
18
+ --sm-space-* spacing scale
19
+ --sm-shadow-* elevation
20
+ --sm-font-* typography
21
+ --sm-control-* interactive control sizing
22
+ ========================================================================= */
23
+
24
+ :root {
25
+ /* ---- Colors --------------------------------------------------------- */
26
+ --sm-color-bg: #f7f8fa;
27
+ --sm-color-surface: #ffffff;
28
+ --sm-color-surface-muted: #f3f4f6;
29
+ --sm-color-surface-subtle: #fafbfc;
30
+ --sm-color-border: #e5e7eb;
31
+ --sm-color-border-strong: #d1d5db;
32
+ --sm-color-text: #111827;
33
+ --sm-color-text-muted: #6b7280;
34
+ --sm-color-text-inverse: #ffffff;
35
+
36
+ --sm-color-accent: #1473e6;
37
+ --sm-color-accent-hover: #0f5fc4;
38
+ --sm-color-accent-soft: #e8f1fc;
39
+
40
+ --sm-color-success: #22863a;
41
+ --sm-color-success-hover: #1a6e2f;
42
+ --sm-color-success-soft: #ecfdf5;
43
+ --sm-color-warning: #b58105;
44
+ --sm-color-warning-hover: #946c04;
45
+ --sm-color-warning-soft: #fff7ed;
46
+ --sm-color-warning-border: #fde68a;
47
+ --sm-color-warning-text: #92400e;
48
+ --sm-color-warning-tint: #fef3c7;
49
+ --sm-color-danger: #c0392b;
50
+ --sm-color-danger-hover: #a32d20;
51
+ --sm-color-danger-soft: #fef2f2;
52
+ --sm-color-danger-tint: #fee2e2;
53
+ --sm-color-accent-tint: #dbeafe;
54
+
55
+ --sm-color-neutral-soft: #eef2f7;
56
+ --sm-color-neutral-text: #374151;
57
+
58
+ /* Surfaces used by the modal scaffolding (header text, body text, panel). */
59
+ --sm-color-text-strong: #1f2937;
60
+ --sm-color-text-soft: #475569;
61
+ --sm-color-surface-panel: #f9fafb;
62
+
63
+ /* Modal / overlay scrim */
64
+ --sm-color-overlay: rgba(15, 23, 42, 0.45);
65
+
66
+ /* ---- Radii ---------------------------------------------------------- */
67
+ --sm-radius-sm: 4px;
68
+ --sm-radius-md: 8px;
69
+ --sm-radius-lg: 10px;
70
+ --sm-radius-xl: 12px;
71
+ --sm-radius-2xl: 14px;
72
+ --sm-radius-pill: 999px;
73
+
74
+ /* ---- Spacing -------------------------------------------------------- */
75
+ --sm-space-1: 4px;
76
+ --sm-space-2: 8px;
77
+ --sm-space-3: 12px;
78
+ --sm-space-4: 16px;
79
+ --sm-space-5: 20px;
80
+ --sm-space-6: 24px;
81
+
82
+ /* ---- Shadows -------------------------------------------------------- */
83
+ --sm-shadow-xs: 0 1px 2px rgba(15, 23, 42, 0.03);
84
+ --sm-shadow-sm: 0 1px 4px rgba(15, 23, 42, 0.04);
85
+ --sm-shadow-md: 0 1px 3px rgba(15, 23, 42, 0.12), 0 1px 1px rgba(15, 23, 42, 0.06);
86
+ --sm-shadow-pill: 0 1px 3px rgba(15, 23, 42, 0.10), 0 1px 1px rgba(15, 23, 42, 0.06);
87
+ --sm-shadow-floating: 0 4px 14px rgba(15, 23, 42, 0.08);
88
+ --sm-shadow-dropdown: 0 12px 28px rgba(15, 23, 42, 0.16), 0 2px 4px rgba(15, 23, 42, 0.06);
89
+ --sm-shadow-modal: 0 24px 60px rgba(15, 23, 42, 0.25), 0 2px 8px rgba(15, 23, 42, 0.08);
90
+ --sm-shadow-inset: inset 0 1px 2px rgba(15, 23, 42, 0.04);
91
+
92
+ /* ---- Typography ----------------------------------------------------- */
93
+ --sm-font-family: adobe-clean, 'Source Sans Pro', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
94
+ --sm-font-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
95
+ --sm-font-size-xs: 11px;
96
+ --sm-font-size-sm: 12px;
97
+ --sm-font-size-md: 13px;
98
+ --sm-font-size-lg: 14px;
99
+ --sm-font-weight-regular: 400;
100
+ --sm-font-weight-medium: 500;
101
+ --sm-font-weight-semibold:600;
102
+ --sm-font-weight-bold: 700;
103
+
104
+ /* ---- Control sizing ------------------------------------------------- */
105
+ --sm-control-height-sm: 28px;
106
+ --sm-control-height-md: 32px;
107
+ --sm-control-height-lg: 40px;
108
+ --sm-control-padding-x: 16px;
109
+
110
+ /* ---- Z-index -------------------------------------------------------- */
111
+ --sm-z-nav: 30;
112
+ --sm-z-sticky: 20;
113
+ --sm-z-modal: 100;
114
+
115
+ /* =====================================================================
116
+ Spectrum token overrides — re-skin React-Spectrum widgets without
117
+ forking the theme. Keep these in sync with the --sm-* tokens above
118
+ so default Buttons / TextField / Picker pick up our accent automatically.
119
+ ===================================================================== */
120
+ --spectrum-accent-color-900: var(--sm-color-accent);
121
+ --spectrum-accent-color-1000: var(--sm-color-accent-hover);
122
+ /* Text colours are left to Spectrum so secondary/quiet buttons keep
123
+ their proper contrast on both light and dark surfaces. */
124
+
125
+ color-scheme: light;
126
+ }
127
+
128
+ /* =========================================================================
129
+ Base
130
+ ========================================================================= */
131
+ html,
132
+ body,
133
+ #root {
134
+ margin: 0;
135
+ min-height: 100%;
136
+ background: var(--sm-color-bg);
137
+ color: var(--sm-color-text);
138
+ font-family: var(--sm-font-family);
139
+ }
140
+
141
+ /* React-Spectrum's <Provider> wraps its tree in a div. We mark it with
142
+ `UNSAFE_className="sm-provider"` and set its background here so the page
143
+ bg fills the whole iframe — but we only paint the wrapper, NOT any
144
+ descendants. Painting descendants stomps on inputs / buttons / pickers. */
145
+ .sm-provider {
146
+ background: var(--sm-color-bg);
147
+ min-height: 100vh;
148
+ }
149
+
150
+ /* =========================================================================
151
+ Cards
152
+ ========================================================================= */
153
+ .sm-card {
154
+ background: var(--sm-color-surface);
155
+ border: 1px solid var(--sm-color-border);
156
+ border-radius: var(--sm-radius-lg);
157
+ box-shadow: var(--sm-shadow-xs);
158
+ padding: var(--sm-space-5);
159
+ }
160
+ .sm-card--flush { padding: 0; }
161
+
162
+ /* =========================================================================
163
+ Pills
164
+ ========================================================================= */
165
+ .sm-pill {
166
+ display: inline-flex;
167
+ align-items: center;
168
+ gap: var(--sm-space-1);
169
+ padding: 2px var(--sm-space-2);
170
+ border-radius: var(--sm-radius-pill);
171
+ background: var(--sm-color-neutral-soft);
172
+ color: var(--sm-color-neutral-text);
173
+ font-size: var(--sm-font-size-xs);
174
+ font-weight: var(--sm-font-weight-semibold);
175
+ line-height: 16px;
176
+ letter-spacing: 0.2px;
177
+ white-space: nowrap;
178
+ }
179
+ .sm-pill--accent { background: var(--sm-color-accent-soft); color: var(--sm-color-accent); }
180
+ .sm-pill--success { background: var(--sm-color-success-soft); color: var(--sm-color-success); }
181
+ .sm-pill--warning { background: var(--sm-color-warning-soft); color: var(--sm-color-warning); }
182
+ .sm-pill--danger { background: var(--sm-color-danger-soft); color: var(--sm-color-danger); }
183
+
184
+ /* =========================================================================
185
+ Tab bar (used by AppSectionNav)
186
+ ========================================================================= */
187
+ .sm-tab-bar {
188
+ position: sticky;
189
+ top: 0;
190
+ z-index: var(--sm-z-nav);
191
+ background: var(--sm-color-surface);
192
+ border-bottom: 1px solid var(--sm-color-border);
193
+ padding: 10px var(--sm-space-4);
194
+ box-shadow: var(--sm-shadow-sm);
195
+ box-sizing: border-box;
196
+ max-width: 100%;
197
+ display: flex;
198
+ align-items: center;
199
+ justify-content: space-between;
200
+ flex-wrap: nowrap;
201
+ gap: var(--sm-space-3);
202
+ }
203
+ .sm-tab-bar__actions {
204
+ display: inline-flex;
205
+ align-items: center;
206
+ gap: var(--sm-space-2);
207
+ flex-shrink: 0;
208
+ }
209
+ .sm-tab-bar__track {
210
+ display: inline-flex;
211
+ padding: var(--sm-space-1);
212
+ background: var(--sm-color-surface-muted);
213
+ border: 1px solid var(--sm-color-border);
214
+ border-radius: var(--sm-radius-pill);
215
+ box-shadow: var(--sm-shadow-inset);
216
+ gap: 2px;
217
+ font-family: var(--sm-font-family);
218
+ }
219
+ .sm-tab {
220
+ display: inline-flex;
221
+ align-items: center;
222
+ gap: var(--sm-space-2);
223
+ padding: var(--sm-space-2) var(--sm-control-padding-x);
224
+ border: 0;
225
+ border-radius: var(--sm-radius-pill);
226
+ background: transparent;
227
+ color: var(--sm-color-neutral-text);
228
+ font-size: var(--sm-font-size-md);
229
+ font-weight: var(--sm-font-weight-semibold);
230
+ letter-spacing: 0.1px;
231
+ cursor: pointer;
232
+ transition: background 140ms ease, color 140ms ease, box-shadow 140ms ease;
233
+ }
234
+ .sm-tab:hover {
235
+ background: var(--sm-color-surface);
236
+ color: var(--sm-color-text);
237
+ }
238
+ .sm-tab.is-active {
239
+ background: var(--sm-color-surface);
240
+ color: var(--sm-color-accent);
241
+ font-weight: var(--sm-font-weight-bold);
242
+ box-shadow: var(--sm-shadow-pill);
243
+ cursor: default;
244
+ }
245
+ .sm-tab__icon { display: inline-flex; opacity: 0.75; }
246
+ .sm-tab.is-active .sm-tab__icon { opacity: 1; }
247
+
248
+ /* =========================================================================
249
+ Spectrum textareas inside the system-config field renderer
250
+ ========================================================================= */
251
+ .sm-textarea textarea {
252
+ height: 160px !important;
253
+ max-height: 160px !important;
254
+ min-height: 160px !important;
255
+ overflow-y: auto !important;
256
+ resize: none !important;
257
+ font-family: var(--sm-font-mono);
258
+ font-size: var(--sm-font-size-sm);
259
+ }
260
+
261
+ /* =========================================================================
262
+ Note banner (used by ComingSoon, info callouts, etc.)
263
+ ========================================================================= */
264
+ .sm-note {
265
+ margin-top: var(--sm-space-3);
266
+ padding: var(--sm-space-3);
267
+ border-radius: var(--sm-radius-md);
268
+ background: var(--sm-color-surface-muted);
269
+ border: 1px solid var(--sm-color-border);
270
+ color: var(--sm-color-text);
271
+ font-size: var(--sm-font-size-md);
272
+ white-space: pre-line;
273
+ font-family: var(--sm-font-mono);
274
+ }
275
+ .sm-note--warning {
276
+ background: var(--sm-color-warning-soft);
277
+ border-color: var(--sm-color-warning-border);
278
+ color: var(--sm-color-warning-text);
279
+ font-family: var(--sm-font-family);
280
+ }
281
+
282
+ /* =========================================================================
283
+ Animations (used by progress / status indicators)
284
+ ========================================================================= */
285
+ @keyframes sm-pulse {
286
+ 0%, 100% { opacity: 1; }
287
+ 50% { opacity: 0.3; }
288
+ }
289
+ @keyframes sm-indeterminate {
290
+ 0% { left: -40%; width: 40%; }
291
+ 50% { left: 30%; width: 40%; }
292
+ 100% { left: 100%; width: 40%; }
293
+ }
294
+ @keyframes sm-fade-in {
295
+ from { opacity: 0; }
296
+ to { opacity: 1; }
297
+ }
298
+ @keyframes sm-pop-in {
299
+ from { opacity: 0; transform: translateY(8px) scale(0.98); }
300
+ to { opacity: 1; transform: translateY(0) scale(1); }
301
+ }
302
+
303
+ /* =========================================================================
304
+ Legacy SideNav classes (kept for backwards compat with any remaining
305
+ menu markup; safe to delete once nothing references them).
306
+ ========================================================================= */
307
+ .SideNav {
308
+ list-style-type: none;
309
+ margin: 0;
310
+ padding: 0;
311
+ outline: none;
312
+ height: 100%;
313
+ }
314
+ .SideNav-item {
315
+ list-style-type: none;
316
+ margin: var(--spectrum-global-dimension-size-50) 0;
317
+ }
318
+ .SideNav-itemLink {
319
+ position: relative;
320
+ display: inline-flex;
321
+ align-items: center;
322
+ box-sizing: border-box;
323
+ width: 100%;
324
+ padding: var(--sm-space-2) var(--sm-space-3);
325
+ border-radius: var(--sm-radius-sm);
326
+ font-size: var(--sm-font-size-lg);
327
+ font-weight: var(--sm-font-weight-regular);
328
+ text-decoration: none;
329
+ word-break: break-word;
330
+ cursor: pointer;
331
+ background: transparent;
332
+ color: var(--sm-color-text);
333
+ }
334
+ .SideNav-itemLink.is-selected {
335
+ color: var(--sm-color-accent);
336
+ background: var(--sm-color-accent-soft);
337
+ }