@actuate-media/cms-admin 0.62.0 → 0.63.1

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 (49) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/AdminRoot.d.ts.map +1 -1
  3. package/dist/AdminRoot.js +2 -0
  4. package/dist/AdminRoot.js.map +1 -1
  5. package/dist/__tests__/hooks/useAppearanceBootstrap.test.d.ts +2 -0
  6. package/dist/__tests__/hooks/useAppearanceBootstrap.test.d.ts.map +1 -0
  7. package/dist/__tests__/hooks/useAppearanceBootstrap.test.js +55 -0
  8. package/dist/__tests__/hooks/useAppearanceBootstrap.test.js.map +1 -0
  9. package/dist/__tests__/lib/appearance-api.test.d.ts +2 -0
  10. package/dist/__tests__/lib/appearance-api.test.d.ts.map +1 -0
  11. package/dist/__tests__/lib/appearance-api.test.js +37 -0
  12. package/dist/__tests__/lib/appearance-api.test.js.map +1 -0
  13. package/dist/components/forms/FormSchemaDrawer.d.ts.map +1 -1
  14. package/dist/components/forms/FormSchemaDrawer.js +6 -3
  15. package/dist/components/forms/FormSchemaDrawer.js.map +1 -1
  16. package/dist/components/forms/NotificationsPanel.d.ts.map +1 -1
  17. package/dist/components/forms/NotificationsPanel.js +2 -3
  18. package/dist/components/forms/NotificationsPanel.js.map +1 -1
  19. package/dist/components/forms/WebhooksPanel.d.ts +5 -0
  20. package/dist/components/forms/WebhooksPanel.d.ts.map +1 -0
  21. package/dist/components/forms/WebhooksPanel.js +129 -0
  22. package/dist/components/forms/WebhooksPanel.js.map +1 -0
  23. package/dist/hooks/useAppearanceBootstrap.d.ts +8 -0
  24. package/dist/hooks/useAppearanceBootstrap.d.ts.map +1 -0
  25. package/dist/hooks/useAppearanceBootstrap.js +36 -0
  26. package/dist/hooks/useAppearanceBootstrap.js.map +1 -0
  27. package/dist/lib/appearance-api.d.ts +33 -0
  28. package/dist/lib/appearance-api.d.ts.map +1 -0
  29. package/dist/lib/appearance-api.js +42 -0
  30. package/dist/lib/appearance-api.js.map +1 -0
  31. package/dist/lib/forms-service.d.ts +40 -2
  32. package/dist/lib/forms-service.d.ts.map +1 -1
  33. package/dist/lib/forms-service.js +24 -0
  34. package/dist/lib/forms-service.js.map +1 -1
  35. package/dist/views/settings/useAppearanceSettings.d.ts +3 -9
  36. package/dist/views/settings/useAppearanceSettings.d.ts.map +1 -1
  37. package/dist/views/settings/useAppearanceSettings.js +6 -28
  38. package/dist/views/settings/useAppearanceSettings.js.map +1 -1
  39. package/package.json +2 -2
  40. package/src/AdminRoot.tsx +2 -0
  41. package/src/__tests__/hooks/useAppearanceBootstrap.test.ts +69 -0
  42. package/src/__tests__/lib/appearance-api.test.ts +41 -0
  43. package/src/components/forms/FormSchemaDrawer.tsx +9 -2
  44. package/src/components/forms/NotificationsPanel.tsx +5 -4
  45. package/src/components/forms/WebhooksPanel.tsx +311 -0
  46. package/src/hooks/useAppearanceBootstrap.ts +40 -0
  47. package/src/lib/appearance-api.ts +84 -0
  48. package/src/lib/forms-service.ts +81 -0
  49. package/src/views/settings/useAppearanceSettings.ts +14 -58
@@ -18,7 +18,14 @@ import {
18
18
  } from '@actuate-media/cms-core/appearance'
19
19
  import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
20
20
 
21
- import { useTheme, type AdminBrandCache } from '../../components/ThemeProvider.js'
21
+ import { useTheme } from '../../components/ThemeProvider.js'
22
+ import {
23
+ adminBrandToCache,
24
+ appearanceApiToSnapshot,
25
+ parseAppearanceAssets,
26
+ type AppearanceApiResponse,
27
+ type AssetPreview,
28
+ } from '../../lib/appearance-api.js'
22
29
  import { cmsApi } from '../../lib/api.js'
23
30
  import { BRAND_UPDATED_EVENT } from '../../lib/favicon.js'
24
31
  import type { SettingsSourceMetadata, ValidationIssue } from './useGeneralSettings.js'
@@ -67,14 +74,7 @@ export const FIELD_ROLE: Record<BrandAssetField, BrandAssetRole> = {
67
74
  faviconSourceAssetId: 'faviconSource',
68
75
  }
69
76
 
70
- export interface AssetPreview {
71
- id: string
72
- url: string
73
- mimeType: string
74
- width?: number
75
- height?: number
76
- shape: LogoShape
77
- }
77
+ export type { AssetPreview } from '../../lib/appearance-api.js'
78
78
 
79
79
  /** An existing media-library asset chosen for a brand field via the picker. */
80
80
  export interface SelectedBrandAsset {
@@ -163,20 +163,6 @@ function snapshot(a: AppearanceForm, b: BrandForm): string {
163
163
  return JSON.stringify({ a, b })
164
164
  }
165
165
 
166
- interface AppearanceApiResponse {
167
- appearance: {
168
- adminColorModeDefault: ColorMode
169
- adminAccentColor: string
170
- sidebarDensity: SidebarDensity
171
- contentFont: string
172
- reduceMotion: boolean
173
- }
174
- brand: BrandSettings
175
- resolved: { admin: { initials: string } }
176
- assets: BrandAssetLike[]
177
- siteTitle: string | null
178
- }
179
-
180
166
  /** Read an uploaded image's shape client-side (raster via Image, SVG via XML). */
181
167
  async function detectShape(file: File): Promise<LogoShape> {
182
168
  if (file.type === 'image/svg+xml') {
@@ -213,26 +199,6 @@ async function detectShape(file: File): Promise<LogoShape> {
213
199
  }
214
200
  }
215
201
 
216
- function assetToCache(
217
- brand: BrandForm,
218
- assets: Record<string, AssetPreview>,
219
- siteTitle: string | null,
220
- ): AdminBrandCache {
221
- const map = new Map<string, BrandAssetLike>(
222
- Object.values(assets).map((a) => [
223
- a.id,
224
- { id: a.id, publicUrl: a.url, mimeType: a.mimeType, width: a.width, height: a.height },
225
- ]),
226
- )
227
- const resolved = resolveAdminBrand(brand as BrandSettings, map, siteTitle)
228
- return {
229
- primaryUrl: resolved.primary?.url ?? null,
230
- markUrl: resolved.mark?.url ?? null,
231
- darkUrl: resolved.dark?.url ?? null,
232
- initials: resolved.initials,
233
- }
234
- }
235
-
236
202
  export function useAppearanceSettings(
237
203
  canEdit: boolean,
238
204
  config?: Record<string, unknown>,
@@ -283,7 +249,7 @@ export function useAppearanceSettings(
283
249
  density: a.density,
284
250
  font: a.font,
285
251
  reduceMotion: a.reduceMotion,
286
- adminBrand: assetToCache(b, assetMap, siteTitleRef.current),
252
+ adminBrand: adminBrandToCache(b as BrandSettings, assetMap, siteTitleRef.current),
287
253
  })
288
254
  },
289
255
  [applyAppearance],
@@ -307,27 +273,17 @@ export function useAppearanceSettings(
307
273
  reduceMotion: d.appearance.reduceMotion,
308
274
  }
309
275
  const nextBrand: BrandForm = { ...d.brand, mode: d.brand?.mode ?? 'inheritPublicBrand' }
310
- const nextAssets: Record<string, AssetPreview> = {}
311
- for (const a of d.assets ?? []) {
312
- nextAssets[a.id] = {
313
- id: a.id,
314
- url: a.publicUrl,
315
- mimeType: a.mimeType,
316
- width: a.width ?? undefined,
317
- height: a.height ?? undefined,
318
- shape: classifyLogoShape(a.width ?? undefined, a.height ?? undefined),
319
- }
320
- }
276
+ const nextAssets = parseAppearanceAssets(d.assets ?? [])
321
277
  siteTitleRef.current = d.siteTitle ?? null
322
278
  setAppearance(nextAppearance)
323
279
  setBrand(nextBrand)
324
280
  setAssets(nextAssets)
325
281
  if (nextBrand.adminLogoMarkAssetId || nextBrand.publicLogoMarkAssetId) setShowAdvanced(true)
326
282
  baselineRef.current = snapshot(nextAppearance, nextBrand)
327
- pushLive(nextAppearance, nextBrand, nextAssets)
283
+ applyAppearance(appearanceApiToSnapshot(d))
328
284
  setSaveState('idle')
329
285
  setLoading(false)
330
- }, [pushLive])
286
+ }, [applyAppearance])
331
287
 
332
288
  useEffect(() => {
333
289
  void load()
@@ -548,7 +504,7 @@ export function useAppearanceSettings(
548
504
  return
549
505
  }
550
506
  baselineRef.current = snapshot(appearance, brand)
551
- setAdminBrand(assetToCache(brand, assets, siteTitleRef.current))
507
+ setAdminBrand(adminBrandToCache(brand as BrandSettings, assets, siteTitleRef.current))
552
508
  // Notify live surfaces (browser-tab favicon) to refresh from the saved
553
509
  // brand without a full reload.
554
510
  if (typeof window !== 'undefined') {