@designcrowd/library.brand-page 5.19.1-id-based-items-2 → 5.19.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 (116) hide show
  1. package/lib/src/{CreatedOnBrandCrowd-de-de-Ruu5Az32.js → CreatedOnBrandCrowd-de-de-Ekmn0O3s.js} +1 -1
  2. package/lib/src/{CreatedOnBrandCrowd-en-us-DGUJtvld.js → CreatedOnBrandCrowd-en-us-BjeXlKTS.js} +1 -1
  3. package/lib/src/{CreatedOnBrandCrowd-es-es-Dg-1uOfV.js → CreatedOnBrandCrowd-es-es-rpNINAMY.js} +1 -1
  4. package/lib/src/{CreatedOnBrandCrowd-fr-fr-CRKraZl8.js → CreatedOnBrandCrowd-fr-ca-BL4nSaLj.js} +1 -1
  5. package/lib/src/{CreatedOnBrandCrowd-fr-ca-CRKraZl8.js → CreatedOnBrandCrowd-fr-fr-BL4nSaLj.js} +1 -1
  6. package/lib/src/{CreatedOnBrandCrowd-pt-pt-bZ9VlEAu.js → CreatedOnBrandCrowd-pt-br-K0r4FyYq.js} +1 -1
  7. package/lib/src/{CreatedOnBrandCrowd-pt-br-bZ9VlEAu.js → CreatedOnBrandCrowd-pt-pt-K0r4FyYq.js} +1 -1
  8. package/lib/src/{CreatedOnDcom-de-de-CJYfwZx8.js → CreatedOnDcom-de-de-0XYyEKYc.js} +1 -1
  9. package/lib/src/{CreatedOnDcom-en-us-rzA1lVxH.js → CreatedOnDcom-en-us-E8hvwiMd.js} +1 -1
  10. package/lib/src/{CreatedOnDcom-es-es-CNwGPjik.js → CreatedOnDcom-es-es-pRuCd7xX.js} +1 -1
  11. package/lib/src/{CreatedOnDcom-fr-ca-DKw7OGIz.js → CreatedOnDcom-fr-ca-Bu4V3jpn.js} +1 -1
  12. package/lib/src/{CreatedOnDcom-fr-fr-WzOEaAZG.js → CreatedOnDcom-fr-fr-CCcrGNz2.js} +1 -1
  13. package/lib/src/{CreatedOnDcom-pt-br-DkualVhm.js → CreatedOnDcom-pt-br-1GTvaLKd.js} +1 -1
  14. package/lib/src/{CreatedOnDcom-pt-pt-w4Nnsdzq.js → CreatedOnDcom-pt-pt-CTIYW10X.js} +1 -1
  15. package/lib/src/brand-page/components/image-gallery/masonry/MasonryGallery.mixin.d.ts +1 -1
  16. package/lib/src/brand-page/models/index.d.ts +1 -12
  17. package/lib/src/brand-page/models/index.js +3 -0
  18. package/lib/src/brand-page/utils/personalisation.util.js +72 -14
  19. package/lib/src/brand-page-maker/components/action-bar/ActionBar.mixin.d.ts +1 -1
  20. package/lib/src/brand-page-maker/components/admin-background-settings/AdminBackgroundSettings.mixin.d.ts +6 -0
  21. package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.mixin.d.ts +12 -1
  22. package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.mixin.js +2 -0
  23. package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.stories.js +1 -0
  24. package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMakerTemplateSettings.mixin.d.ts +1 -1
  25. package/lib/src/brand-page-maker/components/brandpage-maker-page/BrandPageMakerPage.mixin.d.ts +1 -1
  26. package/lib/src/brand-page-maker/components/brandpage-settings/ReplaceImageSettingsForBrandPageSettings.mixin.d.ts +1 -1
  27. package/lib/src/brand-page-maker/components/seo-settings/SeoPageSettings.mixin.d.ts +1 -1
  28. package/lib/src/brand-page-maker/components/seo-settings/UrlSettings.mixin.d.ts +1 -1
  29. package/lib/src/brand-page-maker/components/social-share/SocialShare.mixin.d.ts +1 -1
  30. package/lib/src/brand-page-maker/components/template-preview/TemplatePreview.mixin.d.ts +2 -3
  31. package/lib/src/brand-page-maker/components/template-preview/TemplatePreview.mixin.js +16 -5
  32. package/lib/src/brand-page-maker/composables/ai-chat/useAiWebsiteBuilderChat.js +0 -5
  33. package/lib/src/brand-page-maker/stores/ai-checkpoint/ai-checkpoint-store.d.ts +6 -18
  34. package/lib/src/brand-page-maker/stores/brandpage-container/brand-page-container-store.d.ts +1 -0
  35. package/lib/src/brand-page-maker/stores/brandpage-container/brand-page-container-store.js +3 -0
  36. package/lib/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.d.ts +3 -1
  37. package/lib/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.js +5 -1
  38. package/lib/src/brand-page-maker/stores/ui/ui-store.d.ts +6 -0
  39. package/lib/src/brand-page-maker/stores/ui/ui-store.js +8 -0
  40. package/lib/src/clients/design-template-client.d.ts +3 -0
  41. package/lib/src/clients/models.d.ts +2 -0
  42. package/lib/src/css/library.brand-page-brandCrowd.min.css +19 -7
  43. package/lib/src/css/library.brand-page-brandPage.min.css +19 -7
  44. package/lib/src/css/library.brand-page-designCom.min.css +19 -7
  45. package/lib/src/css/library.brand-page-preview.min.css +19 -7
  46. package/lib/src/index.mjs +1 -1
  47. package/lib/src/{lib-Dy7MYyqz.js → lib-BfgUqu0B.js} +25060 -24791
  48. package/lib/src/metadata-builder/builders/footer-builder.js +44 -34
  49. package/lib/src/metadata-builder/builders/section-builders/image-gallery-builder.js +68 -57
  50. package/lib/src/metadata-builder/builders/section-builders/images-section-builder.js +93 -58
  51. package/lib/src/metadata-builder/builders/section-builders/shapes-section-builder.js +99 -66
  52. package/lib/src/metadata-builder/builders/section-builders/social-links-builder.js +17 -57
  53. package/lib/src/metadata-builder/builders/section-builders/testimonial-section-builder.js +85 -51
  54. package/lib/src/metadata-builder/builders/section-builders/text-section-builder.js +74 -49
  55. package/lib/src/metadata-builder/parsers/ai-toolcall-parser.d.ts +4 -13
  56. package/lib/src/metadata-builder/parsers/section-tool-arguments.d.ts +48 -66
  57. package/lib/src/shared/content-settings/components/content-settings/ContentSettings.mixin.d.ts +1 -1
  58. package/lib/src/shared/content-settings/components/content-settings/ReplaceImageSettingsForContent.mixin.d.ts +1 -1
  59. package/lib/src/shared/content-settings/components/content-settings-item/ContentSettingsItemField.mixin.d.ts +7 -1
  60. package/lib/src/shared/logo-settings/components/EditLogoSettings.mixin.d.ts +9 -0
  61. package/lib/src/shared/logo-settings/components/LogoSettings.mixin.d.ts +1 -1
  62. package/lib/src/shared/logo-versions/LogoVersions.mixin.d.ts +6 -0
  63. package/lib/src/shared/models.d.ts +2 -0
  64. package/lib/src/shared/my-designs/MyDesigns.mixin.d.ts +6 -0
  65. package/lib/src/shared/my-uploads/MyMedia.mixin.d.ts +6 -0
  66. package/lib/src/shared/my-uploads/MyUploads.mixin.d.ts +6 -0
  67. package/lib/src/shared/page-settings/components/page-settings/PageSettings.mixin.d.ts +7 -3
  68. package/lib/src/shared/page-settings/components/page-settings-section-styles/PageSettingsSectionStyles.mixin.d.ts +7 -3
  69. package/lib/src/shared/publish-brand-page-with-state/PublishBrandPageModalWithState.mixin.d.ts +1 -1
  70. package/lib/src/shared/style-settings/components/StyleSettings.mixin.d.ts +7 -1
  71. package/lib/src/shared/template-settings/components/TemplatesSettings.mixin.d.ts +10 -439
  72. package/lib/src/shared/template-settings/components/TemplatesSettings.mixin.js +2 -2
  73. package/lib/src/shared/template-settings/models.d.ts +1 -0
  74. package/lib/src/shared/template-settings/store/template-settings-store.d.ts +4 -0
  75. package/lib/src/shared/template-settings/store/template-settings-store.js +79 -11
  76. package/lib/src/shared/unsplash-library/UnsplashLibrary.mixin.d.ts +6 -0
  77. package/lib/src/utils/minify-brand-page-metadata.d.ts +0 -2
  78. package/lib/src/utils/minify-brand-page-metadata.js +1 -8
  79. package/package.json +1 -1
  80. package/src/brand-page/components/image-gallery/masonry/MasonryGallery.mixin.ts +1 -2
  81. package/src/brand-page/models/index.ts +4 -12
  82. package/src/brand-page/utils/__snapshots__/migration.util.test.ts.snap +3 -0
  83. package/src/brand-page/utils/__snapshots__/migration2.util.test.ts.snap +1 -0
  84. package/src/brand-page/utils/__snapshots__/model.util.test.ts.snap +2 -0
  85. package/src/brand-page/utils/personalisation.util.test.ts +35 -0
  86. package/src/brand-page/utils/personalisation.util.ts +119 -23
  87. package/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.mixin.ts +4 -0
  88. package/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.stories.ts +1 -0
  89. package/src/brand-page-maker/components/template-preview/TemplatePreview.mixin.ts +22 -8
  90. package/src/brand-page-maker/components/template-preview/TemplatePreview.vue +5 -10
  91. package/src/brand-page-maker/components/template-preview/TemplatePreviewAiBadge.vue +12 -0
  92. package/src/brand-page-maker/composables/ai-chat/useAiWebsiteBuilderChat.ts +0 -6
  93. package/src/brand-page-maker/stores/brandpage-container/brand-page-container-store.ts +5 -0
  94. package/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.ts +10 -0
  95. package/src/brand-page-maker/stores/ui/ui-store.ts +16 -0
  96. package/src/clients/design-template-client.ts +3 -0
  97. package/src/clients/models.ts +2 -0
  98. package/src/metadata-builder/builders/footer-builder.test.ts +0 -298
  99. package/src/metadata-builder/builders/footer-builder.ts +65 -56
  100. package/src/metadata-builder/builders/section-builders/image-gallery-builder.ts +88 -62
  101. package/src/metadata-builder/builders/section-builders/images-section-builder.ts +129 -66
  102. package/src/metadata-builder/builders/section-builders/shapes-section-builder.ts +160 -105
  103. package/src/metadata-builder/builders/section-builders/social-links-builder.ts +20 -65
  104. package/src/metadata-builder/builders/section-builders/testimonial-section-builder.ts +146 -83
  105. package/src/metadata-builder/builders/section-builders/text-section-builder.ts +122 -70
  106. package/src/metadata-builder/parsers/ai-toolcall-parser.ts +4 -13
  107. package/src/metadata-builder/parsers/section-tool-arguments.ts +48 -66
  108. package/src/shared/models.ts +6 -0
  109. package/src/shared/template-settings/components/TemplatesSettings.mixin.ts +2 -2
  110. package/src/shared/template-settings/models.ts +1 -0
  111. package/src/shared/template-settings/store/template-settings-store.ts +105 -18
  112. package/src/utils/minify-brand-page-metadata.ts +2 -14
  113. package/lib/src/metadata-builder/builders/item-id-utils.d.ts +0 -54
  114. package/lib/src/metadata-builder/builders/item-id-utils.js +0 -96
  115. package/src/metadata-builder/builders/item-id-utils.test.ts +0 -184
  116. package/src/metadata-builder/builders/item-id-utils.ts +0 -117
@@ -1,184 +0,0 @@
1
- import { describe, it, expect } from 'vitest';
2
- import {
3
- END_ITEM_ANCHOR,
4
- ensureBrandPageItemIds,
5
- ensureItemIds,
6
- generateItemId,
7
- removeItemsByIds,
8
- repositionItemByAnchor,
9
- } from './item-id-utils';
10
- import type { BrandPageModel } from '../../brand-page/models';
11
-
12
- type Item = { id?: string; label: string };
13
-
14
- const UUID_RE =
15
- /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
16
-
17
- const items = (...labels: string[]): Item[] =>
18
- labels.map((label) => ({ id: label, label }));
19
-
20
- const labels = (list: Item[]): string[] => list.map((i) => i.label);
21
-
22
- describe('generateItemId', () => {
23
- it('returns unique uuid-shaped ids', () => {
24
- const a = generateItemId();
25
- const b = generateItemId();
26
-
27
- expect(a).not.toBe(b);
28
- expect(a).toMatch(
29
- /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,
30
- );
31
- });
32
- });
33
-
34
- describe('ensureItemIds', () => {
35
- it('backfills only the items missing an id, preserving existing ones', () => {
36
- const list: Item[] = [
37
- { id: 'keep', label: 'a' },
38
- { label: 'b' },
39
- { id: '', label: 'c' },
40
- ];
41
-
42
- ensureItemIds(list);
43
-
44
- expect(list[0].id).toBe('keep');
45
- expect(list[1].id).toBeTruthy();
46
- expect(list[2].id).toBeTruthy();
47
- expect(new Set(list.map((i) => i.id)).size).toBe(3);
48
- });
49
-
50
- it('is a no-op for undefined', () => {
51
- expect(() => ensureItemIds(undefined)).not.toThrow();
52
- });
53
- });
54
-
55
- describe('removeItemsByIds', () => {
56
- it('removes by id regardless of order (no index shifting)', () => {
57
- const result = removeItemsByIds(items('a', 'b', 'c', 'd'), ['c', 'a']);
58
-
59
- expect(labels(result)).toEqual(['b', 'd']);
60
- });
61
-
62
- it('returns the list unchanged when no ids given', () => {
63
- const list = items('a', 'b');
64
-
65
- expect(removeItemsByIds(list, undefined)).toBe(list);
66
- expect(removeItemsByIds(list, [])).toBe(list);
67
- });
68
-
69
- it('returns [] for undefined items', () => {
70
- expect(removeItemsByIds(undefined, ['x'])).toEqual([]);
71
- });
72
- });
73
-
74
- describe('repositionItemByAnchor', () => {
75
- it('appends a new item when no anchor is given', () => {
76
- const list = items('a', 'b');
77
-
78
- repositionItemByAnchor(list, { id: 'new', label: 'new' }, undefined);
79
-
80
- expect(labels(list)).toEqual(['a', 'b', 'new']);
81
- });
82
-
83
- it('leaves an existing item in place when no anchor is given', () => {
84
- const list = items('a', 'b', 'c');
85
-
86
- repositionItemByAnchor(list, list[1], undefined);
87
-
88
- expect(labels(list)).toEqual(['a', 'b', 'c']);
89
- });
90
-
91
- it('inserts a new item before the anchor id', () => {
92
- const list = items('a', 'b', 'c');
93
-
94
- repositionItemByAnchor(list, { id: 'new', label: 'new' }, 'b');
95
-
96
- expect(labels(list)).toEqual(['a', 'new', 'b', 'c']);
97
- });
98
-
99
- it('moves an existing item before the anchor id', () => {
100
- const list = items('a', 'b', 'c', 'd');
101
-
102
- // move 'd' before 'b'
103
- repositionItemByAnchor(list, list[3], 'b');
104
-
105
- expect(labels(list)).toEqual(['a', 'd', 'b', 'c']);
106
- });
107
-
108
- it('moves an existing item to the end with the __end__ sentinel', () => {
109
- const list = items('a', 'b', 'c');
110
-
111
- repositionItemByAnchor(list, list[0], END_ITEM_ANCHOR);
112
-
113
- expect(labels(list)).toEqual(['b', 'c', 'a']);
114
- });
115
-
116
- it('falls through to the end when the anchor id is not found', () => {
117
- const list = items('a', 'b');
118
-
119
- repositionItemByAnchor(list, { id: 'new', label: 'new' }, 'missing');
120
-
121
- expect(labels(list)).toEqual(['a', 'b', 'new']);
122
- });
123
- });
124
-
125
- describe('ensureBrandPageItemIds', () => {
126
- const makeModel = (): BrandPageModel =>
127
- ({
128
- pages: [
129
- {
130
- contents: [
131
- {
132
- type: 'image-gallery',
133
- images: [{ imageUrl: 'a' }, { imageUrl: 'b' }],
134
- },
135
- {
136
- type: 'testimonial-section',
137
- items: [{ id: 'keep-me', name: 'X' }, { name: 'Y' }],
138
- },
139
- { type: 'text', textItems: [{ text: 'hi' }] },
140
- { type: 'social-links', links: [{ url: 'u' }] },
141
- { type: 'divider-section' }, // no item arrays — must not throw
142
- ],
143
- },
144
- ],
145
- pageFooterDesktop: { socialLinks: [{ url: 'f' }] },
146
- pageFooterMobile: { socialLinks: [{ url: 'm' }] },
147
- }) as unknown as BrandPageModel;
148
-
149
- it('stamps a uuid id onto every id-less nested item across sections + footer', () => {
150
- const model = makeModel();
151
-
152
- ensureBrandPageItemIds(model);
153
-
154
- const c = model.pages[0].contents as any[];
155
-
156
- expect(c[0].images[0].id).toMatch(UUID_RE);
157
- expect(c[0].images[1].id).toMatch(UUID_RE);
158
- expect(c[1].items[1].id).toMatch(UUID_RE);
159
- expect(c[2].textItems[0].id).toMatch(UUID_RE);
160
- expect(c[3].links[0].id).toMatch(UUID_RE);
161
- expect((model.pageFooterDesktop as any).socialLinks[0].id).toMatch(UUID_RE);
162
- expect((model.pageFooterMobile as any).socialLinks[0].id).toMatch(UUID_RE);
163
- });
164
-
165
- it('preserves existing ids (idempotent)', () => {
166
- const model = makeModel();
167
-
168
- ensureBrandPageItemIds(model);
169
- const first = (model.pages[0].contents as any[])[1].items[0].id;
170
-
171
- ensureBrandPageItemIds(model);
172
- const second = (model.pages[0].contents as any[])[1].items[0].id;
173
-
174
- expect(first).toBe('keep-me');
175
- expect(second).toBe('keep-me');
176
- });
177
-
178
- it('does not throw on an empty / partial model', () => {
179
- expect(() => ensureBrandPageItemIds({} as BrandPageModel)).not.toThrow();
180
- expect(() =>
181
- ensureBrandPageItemIds({ pages: [] } as unknown as BrandPageModel),
182
- ).not.toThrow();
183
- });
184
- });
@@ -1,117 +0,0 @@
1
- import { v4 as uuidv4 } from 'uuid';
2
- import type { BrandPageModel } from '../../brand-page/models';
3
-
4
- /**
5
- * Sentinel anchor meaning "the end of the list", mirroring the section-level
6
- * `move_before_content_id: "__end__"` convention used in base-section-builder.
7
- */
8
- export const END_ITEM_ANCHOR = '__end__';
9
-
10
- /** Generate a stable item id. Mirrors section-level `uuid.v4()` id generation. */
11
- export const generateItemId = (): string => uuidv4();
12
-
13
- /**
14
- * Walk an entire BrandPageModel and backfill a stable uuid `id` onto every
15
- * nested array item that lacks one (gallery images, images/shapes/testimonial
16
- * items, text items, social links, and footer social links).
17
- *
18
- * BP-5603: this must run BEFORE the model is minified for the AI, so the same
19
- * id the AI is shown (and copies into `item_id`) is the one the executor later
20
- * matches. The maker holds a single live model instance for both the minify
21
- * and the apply step, so mutating it here makes the ids round-trip; they then
22
- * persist on the next save. Idempotent — existing ids are preserved.
23
- */
24
- export const ensureBrandPageItemIds = (model: BrandPageModel): void => {
25
- const ensureContentItemIds = (content: Record<string, unknown>): void => {
26
- // Every array field that the minifier surfaces as a list of items.
27
- for (const field of ['images', 'items', 'textItems', 'links'] as const) {
28
- const arr = content[field];
29
-
30
- if (Array.isArray(arr)) ensureItemIds(arr as { id?: string }[]);
31
- }
32
- };
33
-
34
- for (const page of model.pages ?? []) {
35
- for (const content of page.contents ?? []) {
36
- ensureContentItemIds(content as unknown as Record<string, unknown>);
37
- }
38
- }
39
-
40
- ensureItemIds(model.pageFooterDesktop?.socialLinks);
41
- ensureItemIds(model.pageFooterMobile?.socialLinks);
42
- };
43
-
44
- /**
45
- * Backfill ids onto any items missing one. Per BP-5603 this runs in the
46
- * metadata builder when a section is processed, so the persisted metadata
47
- * returned to the client gains stable ids that subsequent AI tool calls can
48
- * reference. Mutates in place.
49
- */
50
- export const ensureItemIds = <T extends { id?: string }>(
51
- items: T[] | undefined,
52
- ): void => {
53
- if (!items) return;
54
-
55
- for (const item of items) {
56
- if (!item.id) item.id = generateItemId();
57
- }
58
- };
59
-
60
- /**
61
- * Remove items whose id appears in `ids`. Order-independent (no descending
62
- * index sort needed) — the whole point of the id-based migration. Items
63
- * without an id are never removed by id.
64
- */
65
- export const removeItemsByIds = <T extends { id?: string }>(
66
- items: T[] | undefined,
67
- ids: string[] | undefined,
68
- ): T[] => {
69
- if (!items?.length) return items ?? [];
70
-
71
- if (!ids?.length) return items;
72
-
73
- const toRemove = new Set(ids);
74
-
75
- return items.filter((item) => !item.id || !toRemove.has(item.id));
76
- };
77
-
78
- /**
79
- * Position `item` within `items` relative to an anchor id — the item-level
80
- * mirror of base-section-builder's `moveContent`:
81
- *
82
- * - `moveBeforeItemId === undefined` → leave an existing item where it is;
83
- * append a new (not-yet-present) item to the end.
84
- * - `moveBeforeItemId === "__end__"` → move/insert at the very end.
85
- * - anchor id found → insert immediately before it.
86
- * - anchor id not found → fall through to the end (same
87
- * forgiving behaviour as `moveContent`).
88
- *
89
- * Mutates `items` in place. `item` may be an existing element of `items`
90
- * (a move) or a brand-new object (an insert).
91
- */
92
- export const repositionItemByAnchor = <T extends { id?: string }>(
93
- items: T[],
94
- item: T,
95
- moveBeforeItemId: string | undefined,
96
- ): void => {
97
- const currentIndex = items.indexOf(item);
98
-
99
- if (moveBeforeItemId === undefined) {
100
- if (currentIndex === -1) items.push(item);
101
-
102
- return;
103
- }
104
-
105
- if (currentIndex !== -1) items.splice(currentIndex, 1);
106
-
107
- const anchorIndex =
108
- moveBeforeItemId === END_ITEM_ANCHOR
109
- ? -1
110
- : items.findIndex((i) => i.id === moveBeforeItemId);
111
-
112
- if (anchorIndex !== -1) {
113
- items.splice(anchorIndex, 0, item);
114
- } else {
115
- items.push(item);
116
- }
117
- };