@designcrowd/library.brand-page 6.1.6 → 6.1.7

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 (55) hide show
  1. package/lib/src/{CreatedOnBrandCrowd-de-de-COw1kYDh.js → CreatedOnBrandCrowd-de-de-Dh3Paq4X.js} +1 -1
  2. package/lib/src/{CreatedOnBrandCrowd-en-us-JRm1p0it.js → CreatedOnBrandCrowd-en-us-DLWYV4xe.js} +1 -1
  3. package/lib/src/{CreatedOnBrandCrowd-es-es-D-G9uI6b.js → CreatedOnBrandCrowd-es-es-CcjzRbm_.js} +1 -1
  4. package/lib/src/{CreatedOnBrandCrowd-fr-fr-DQCScohj.js → CreatedOnBrandCrowd-fr-ca-UuUNeB_L.js} +1 -1
  5. package/lib/src/{CreatedOnBrandCrowd-fr-ca-DQCScohj.js → CreatedOnBrandCrowd-fr-fr-UuUNeB_L.js} +1 -1
  6. package/lib/src/{CreatedOnBrandCrowd-pt-pt-4RazAfO7.js → CreatedOnBrandCrowd-pt-br-ZVYZ5AnV.js} +1 -1
  7. package/lib/src/{CreatedOnBrandCrowd-pt-br-4RazAfO7.js → CreatedOnBrandCrowd-pt-pt-ZVYZ5AnV.js} +1 -1
  8. package/lib/src/{CreatedOnDcom-de-de-DqvLTbhq.js → CreatedOnDcom-de-de-BPVyqOPL.js} +1 -1
  9. package/lib/src/{CreatedOnDcom-en-us-DG1X0ero.js → CreatedOnDcom-en-us-BUSRV01e.js} +1 -1
  10. package/lib/src/{CreatedOnDcom-es-es-BxHAIikP.js → CreatedOnDcom-es-es-BuABJnvQ.js} +1 -1
  11. package/lib/src/{CreatedOnDcom-fr-ca-BGXoViAC.js → CreatedOnDcom-fr-ca-sjHceLRY.js} +1 -1
  12. package/lib/src/{CreatedOnDcom-fr-fr-CsvmeK2T.js → CreatedOnDcom-fr-fr-D_qGXL3E.js} +1 -1
  13. package/lib/src/{CreatedOnDcom-pt-br-DvWm7MjO.js → CreatedOnDcom-pt-br-D3Sb_YEi.js} +1 -1
  14. package/lib/src/{CreatedOnDcom-pt-pt-Bhz2YEVP.js → CreatedOnDcom-pt-pt-BI47Hv58.js} +1 -1
  15. package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.mixin.d.ts +0 -1
  16. package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.mixin.js +1 -4
  17. package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.stories.js +9 -6
  18. package/lib/src/brand-page-maker/components/brandpage-maker-page/BrandPageMakerPage.mixin.js +7 -9
  19. package/lib/src/brand-page-maker/constants/sidebar-constant.d.ts +1 -0
  20. package/lib/src/brand-page-maker/constants/sidebar-constant.js +10 -1
  21. package/lib/src/css/library.brand-page-brandCrowd.min.css +27 -27
  22. package/lib/src/css/library.brand-page-brandPage.min.css +27 -27
  23. package/lib/src/css/library.brand-page-designCom.min.css +27 -27
  24. package/lib/src/css/library.brand-page-preview.min.css +27 -27
  25. package/lib/src/index.mjs +1 -1
  26. package/lib/src/{lib-Bg2K2ze6.js → lib-BBX3eBci.js} +13006 -13027
  27. package/lib/src/shared/content-settings/components/content-settings/ContentSettings.mixin.d.ts +10 -177
  28. package/lib/src/shared/content-settings/components/content-settings/ContentSettings.mixin.js +8 -15
  29. package/lib/src/shared/content-settings/components/content-settings/ReplaceImageSettingsForContent.mixin.d.ts +1 -1
  30. package/lib/src/shared/content-settings/store/content-settings-store.d.ts +0 -1
  31. package/lib/src/shared/content-settings/store/content-settings-store.js +0 -1
  32. package/lib/src/shared/page-settings/components/page-settings/PageSettings.mixin.d.ts +1 -12
  33. package/lib/src/shared/page-settings/components/page-settings/PageSettings.mixin.js +9 -24
  34. package/lib/src/shared/side-bar/components/SideBar.mixin.d.ts +1 -1
  35. package/lib/src/shared/side-bar/components/SideBar.mixin.js +6 -6
  36. package/lib/src/shared/side-bar/store/side-bar-store.js +15 -2
  37. package/package.json +1 -1
  38. package/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.mixin.ts +1 -4
  39. package/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.stories.ts +9 -10
  40. package/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.vue +2 -0
  41. package/src/brand-page-maker/components/brandpage-maker-page/BrandPageMakerPage.mixin.ts +8 -12
  42. package/src/brand-page-maker/components/brandpage-maker-page/BrandPageMakerPage.pages-tab.test.ts +78 -0
  43. package/src/brand-page-maker/constants/sidebar-constant.ts +10 -1
  44. package/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.test.ts +9 -4
  45. package/src/shared/content-settings/components/content-settings/ContentSettings.mixin.ts +7 -19
  46. package/src/shared/content-settings/components/content-settings/ContentSettings.pages-tab.test.ts +20 -0
  47. package/src/shared/content-settings/components/content-settings/ContentSettings.vue +1 -8
  48. package/src/shared/content-settings/store/content-settings-store.ts +0 -1
  49. package/src/shared/page-settings/components/page-settings/PageSettings.image-replace.test.ts +100 -0
  50. package/src/shared/page-settings/components/page-settings/PageSettings.mixin.ts +14 -31
  51. package/src/shared/page-settings/components/page-settings/PageSettings.vue +11 -7
  52. package/src/shared/side-bar/components/SideBar.landing-tab.test.ts +67 -0
  53. package/src/shared/side-bar/components/SideBar.mixin.ts +6 -6
  54. package/src/shared/side-bar/store/side-bar-store.test.ts +124 -0
  55. package/src/shared/side-bar/store/side-bar-store.ts +17 -2
@@ -0,0 +1,78 @@
1
+ import { describe, test, expect, vi } from 'vitest';
2
+ import BrandPageMakerPageMixin from './BrandPageMakerPage.mixin';
3
+ import { SIDE_BAR_TAB_NAMES } from '@brand-page-maker/constants';
4
+ import { PAGE_SECTIONS } from '@shared/page-settings/models';
5
+
6
+ // Clicking the header/footer of the live preview jumps straight to the Pages tab
7
+ // and its matching section (BP-5855) — it must NOT push the old Content "pages"
8
+ // sub-mode, which no longer exists. Driving the handlers keeps the test light.
9
+ const { onPageHeaderContainerClick, onPageFooterContainerClick } = (
10
+ BrandPageMakerPageMixin as any
11
+ ).methods;
12
+
13
+ const createContext = () => ({
14
+ isInteractivePreviewEnabled: true,
15
+ sideBarStore: { setSelectedTabName: vi.fn() },
16
+ contentSettingsStore: {
17
+ _setSelectedItemId: vi.fn(),
18
+ pushMode: vi.fn(),
19
+ resetMode: vi.fn(),
20
+ },
21
+ pageSettingsStore: { setSelectedSectionName: vi.fn() },
22
+ isHeaderSelected: false,
23
+ isFooterSelected: false,
24
+ isContentSelected: false,
25
+ });
26
+
27
+ describe('BrandPageMakerPage — preview deep links open the Pages tab', () => {
28
+ test('header click opens the Pages tab at the header section', () => {
29
+ const context = createContext();
30
+
31
+ onPageHeaderContainerClick.call(context);
32
+
33
+ expect(context.sideBarStore.setSelectedTabName).toHaveBeenCalledWith({
34
+ tabName: SIDE_BAR_TAB_NAMES.PAGE_SETTINGS,
35
+ });
36
+ expect(
37
+ context.pageSettingsStore.setSelectedSectionName,
38
+ ).toHaveBeenCalledWith({ sectionName: PAGE_SECTIONS.header });
39
+ expect(context.contentSettingsStore.pushMode).not.toHaveBeenCalled();
40
+ expect(context.isHeaderSelected).toBe(true);
41
+ });
42
+
43
+ test('footer click opens the Pages tab at the footer section', () => {
44
+ const context = createContext();
45
+
46
+ onPageFooterContainerClick.call(context);
47
+
48
+ expect(context.sideBarStore.setSelectedTabName).toHaveBeenCalledWith({
49
+ tabName: SIDE_BAR_TAB_NAMES.PAGE_SETTINGS,
50
+ });
51
+ expect(
52
+ context.pageSettingsStore.setSelectedSectionName,
53
+ ).toHaveBeenCalledWith({ sectionName: PAGE_SECTIONS.footer });
54
+ expect(context.contentSettingsStore.pushMode).not.toHaveBeenCalled();
55
+ expect(context.isFooterSelected).toBe(true);
56
+ });
57
+
58
+ // BP-5855 regression: setSelectedTabName only resets a leftover mode on an
59
+ // actual tab change, so clicking the header/footer while ALREADY on the
60
+ // Pages tab (e.g. mid image-replace from a footer icon) needs its own
61
+ // explicit reset here, or the panel stays stuck on the picker instead of
62
+ // scrolling to the section.
63
+ test('header click clears a leftover mode explicitly, not just via the tab switch', () => {
64
+ const context = createContext();
65
+
66
+ onPageHeaderContainerClick.call(context);
67
+
68
+ expect(context.contentSettingsStore.resetMode).toHaveBeenCalled();
69
+ });
70
+
71
+ test('footer click clears a leftover mode explicitly, not just via the tab switch', () => {
72
+ const context = createContext();
73
+
74
+ onPageFooterContainerClick.call(context);
75
+
76
+ expect(context.contentSettingsStore.resetMode).toHaveBeenCalled();
77
+ });
78
+ });
@@ -1,9 +1,10 @@
1
1
  import type { SideBarTab } from '@shared/side-bar/models';
2
- import { constantsTr } from '@src/composables/useTranslate';
2
+ import { constantsTr, pageSettingsTr } from '@src/composables/useTranslate';
3
3
 
4
4
  export const SIDE_BAR_TAB_NAMES = {
5
5
  PREVIEW: 'Preview',
6
6
  TEMPLATE_SETTINGS: 'TemplatesSettings',
7
+ PAGE_SETTINGS: 'PageSettings',
7
8
  CONTENT_SETTINGS: 'ContentSettings',
8
9
  BACKGROUND_SETTINGS: 'BackgroundSettings',
9
10
  ADMIN_BACKGROUND_SETTINGS: 'AdminBackgroundSettings',
@@ -31,6 +32,14 @@ export const DEFAULT_SIDE_BAR_TABS = (): SideBarTab[] => [
31
32
  isDisabledForAdmin: false,
32
33
  isVisible: true,
33
34
  },
35
+ {
36
+ name: SIDE_BAR_TAB_NAMES.PAGE_SETTINGS,
37
+ displayName: pageSettingsTr(`pages`),
38
+ iconName: 'page-blank',
39
+ accessibleDisplayName: 'Pages',
40
+ isDisabledForAdmin: false,
41
+ isVisible: true,
42
+ },
34
43
  {
35
44
  name: SIDE_BAR_TAB_NAMES.CONTENT_SETTINGS,
36
45
  displayName: constantsTr(`contentDisplayName`),
@@ -839,17 +839,22 @@ describe('brand page maker store module', () => {
839
839
 
840
840
  await makerStore.initialise(INITIALISE_PAYLOAD);
841
841
 
842
- // Simulate the user opening a content item's focused settings.
842
+ // Simulate the user opening a content item's focused settings. Tab first,
843
+ // then mode — focusing an item is only possible once already on the
844
+ // Content tab (setSelectedTabName resets a leftover mode on an actual tab
845
+ // change, so pushing the mode before landing on the tab would be
846
+ // backwards from how this happens for real, and would immediately wipe
847
+ // it here too).
843
848
  const orphanItemId = 'orphan-content-id-not-in-snapshot';
844
849
 
850
+ sideBarStore.setSelectedTabName({
851
+ tabName: SIDE_BAR_TAB_NAMES.CONTENT_SETTINGS,
852
+ });
845
853
  contentSettingsStore.pushMode({
846
854
  mode: CONTENT_SETTINGS_MODES.focusedContentItem,
847
855
  selectedItemId: orphanItemId,
848
856
  });
849
857
  contentSettingsStore.selectedItemId = orphanItemId;
850
- sideBarStore.setSelectedTabName({
851
- tabName: SIDE_BAR_TAB_NAMES.CONTENT_SETTINGS,
852
- });
853
858
 
854
859
  // Pre-condition: panel is showing the focused content item.
855
860
  expect(contentSettingsStore.mode).toBe(
@@ -4,14 +4,12 @@ import type { Content } from '@brand-page';
4
4
  import type { ItemCategory } from '@brand-page-maker/models';
5
5
  import { ITEM_CATEGORIES, ITEM_CATEGORY_NAMES } from '@brand-page-maker/models';
6
6
  import { UI_EVENT_SOURCES } from '../../../models';
7
- import {
8
- PAGE_SETTINGS_SECTIONS,
9
- useUiPageSettingsStore,
10
- } from '../../../page-settings/store';
7
+ import { useUiPageSettingsStore } from '../../../page-settings/store';
8
+ import { useUiSideBarStore } from '../../../side-bar/store';
9
+ import { SIDE_BAR_TAB_NAMES } from '@brand-page-maker/constants';
11
10
  import { useUiContentSettingsStore } from '../../store';
12
11
  import { CONTENT_SETTINGS_MODES } from '../../store';
13
12
  import {
14
- useBrandPageMakerStore,
15
13
  useBrandPageMakerUserStore,
16
14
  useBrandPageContainerStore,
17
15
  } from '@brand-page-maker/stores';
@@ -39,11 +37,11 @@ interface CategoryTab {
39
37
  export default defineComponent({
40
38
  emits: ['capture-preview-snapshot'],
41
39
  setup() {
42
- const brandPageMakerStore = useBrandPageMakerStore();
43
40
  const contentSettingsStore = useUiContentSettingsStore();
44
41
  const pageSettingsStore = useUiPageSettingsStore();
45
42
  const pageNavigationStore = usePageNavigationStore();
46
43
  const styleSettingsStore = useUiStyleSettingsStore();
44
+ const sideBarStore = useUiSideBarStore();
47
45
  const userStore = useBrandPageMakerUserStore();
48
46
  const containerStore = useBrandPageContainerStore();
49
47
  const eventTracker = useEventTracker();
@@ -52,10 +50,8 @@ export default defineComponent({
52
50
 
53
51
  return {
54
52
  mode: computed(() => contentSettingsStore.mode),
55
- pages: computed(() => pageSettingsStore.pages),
56
53
  activePageId: computed(() => pageNavigationStore.activePageId),
57
54
  activeCategoryTab: computed(() => contentSettingsStore.activeCategoryTab),
58
- isBrandSite: computed(() => brandPageMakerStore.isBrandSite),
59
55
  contentSettingsSelectedItemId: computed(
60
56
  () => contentSettingsStore.selectedItemId,
61
57
  ),
@@ -63,10 +59,10 @@ export default defineComponent({
63
59
  canUseRichTextEditor: computed(
64
60
  () => userStore.features.canUseRichTextEditor,
65
61
  ),
66
- brandPageMakerStore,
67
62
  contentSettingsStore,
68
63
  pageNavigationStore,
69
64
  pageSettingsStore,
65
+ sideBarStore,
70
66
  styleSettingsStore,
71
67
  eventTracker,
72
68
  historyStore,
@@ -81,7 +77,6 @@ export default defineComponent({
81
77
  label: ITEM_CATEGORY_NAMES()[c].displayName,
82
78
  })),
83
79
  ] as CategoryTab[],
84
- isAddPageModalVisible: false,
85
80
  };
86
81
  },
87
82
  mounted() {
@@ -99,9 +94,6 @@ export default defineComponent({
99
94
  showPageControls(): boolean {
100
95
  return true;
101
96
  },
102
- isManagePagesButtonVisible(): boolean {
103
- return this.isBrandSite || this.pageSettingsStore.pages.length > 1;
104
- },
105
97
  visibleCategoryTabs(): CategoryTab[] {
106
98
  return this.categoryTabs.filter(
107
99
  (t) =>
@@ -223,12 +215,8 @@ export default defineComponent({
223
215
  );
224
216
  },
225
217
  onManagePageButtonClick(): void {
226
- this.contentSettingsStore.pushMode({
227
- mode: CONTENT_SETTINGS_MODES.pages,
228
- });
229
-
230
- this.pageSettingsStore.setSelectedSectionName({
231
- sectionName: PAGE_SETTINGS_SECTIONS.pages,
218
+ this.sideBarStore.setSelectedTabName({
219
+ tabName: SIDE_BAR_TAB_NAMES.PAGE_SETTINGS,
232
220
  });
233
221
  },
234
222
  onAddPageButtonClick(): void {
@@ -0,0 +1,20 @@
1
+ import { describe, test, expect, vi } from 'vitest';
2
+ import ContentSettingsMixin from './ContentSettings.mixin';
3
+ import { SIDE_BAR_TAB_NAMES } from '@brand-page-maker/constants';
4
+
5
+ // The Content tab's "Manage Pages" dropdown item and gear icon both redirect to
6
+ // the dedicated Pages tab (BP-5855) — they no longer open a nested sub-mode.
7
+ // Driving the handler keeps the test light.
8
+ const { onManagePageButtonClick } = (ContentSettingsMixin as any).methods;
9
+
10
+ describe('ContentSettings — Manage Pages redirects to the Pages tab', () => {
11
+ test('onManagePageButtonClick switches to the Pages tab', () => {
12
+ const context = { sideBarStore: { setSelectedTabName: vi.fn() } };
13
+
14
+ onManagePageButtonClick.call(context);
15
+
16
+ expect(context.sideBarStore.setSelectedTabName).toHaveBeenCalledWith({
17
+ tabName: SIDE_BAR_TAB_NAMES.PAGE_SETTINGS,
18
+ });
19
+ });
20
+ });
@@ -37,7 +37,6 @@
37
37
  @on-click.stop="onAddNewPageSelected()"
38
38
  />
39
39
  <Button
40
- v-if="isManagePagesButtonVisible"
41
40
  data-test-tag="manage-pages"
42
41
  icon="settings"
43
42
  icon-size="md"
@@ -134,10 +133,6 @@
134
133
  />
135
134
  <!-- End of Image mode -->
136
135
 
137
- <!-- Start of Page mode -->
138
- <PageSettings v-if="mode === CONTENT_SETTINGS_MODES.pages" />
139
- <!-- End of Page mode -->
140
-
141
136
  <!-- Start of Single Content Item Settings -->
142
137
  <FocusedContentItemSettings
143
138
  v-if="mode === CONTENT_SETTINGS_MODES.focusedContentItem"
@@ -145,7 +140,7 @@
145
140
  />
146
141
  <!-- End of Single Content Item Settings -->
147
142
 
148
- <NewPageModal :visible="isAddPageModalVisible" />
143
+ <NewPageModal />
149
144
  </div>
150
145
  </template>
151
146
  <script>
@@ -158,7 +153,6 @@ import ReplaceImageSettingsForContent from './ReplaceImageSettingsForContent.vue
158
153
  import ContentSettingsButton from './ContentSettingsButton.vue';
159
154
  import ContentSettingsLockedButton from './ContentSettingsLockedButton.vue';
160
155
  import NewPageModal from '../../../page-settings/components/new-page-modal/NewPageModal.vue';
161
- import PageSettings from '../../../page-settings/components/page-settings/PageSettings.vue';
162
156
  import FocusedContentItemSettings from '../focused-content-item-settings/FocusedContentItemSettings.vue';
163
157
  import { CONTENT_SETTINGS_MODES } from '../../store';
164
158
  import { contentSettingsTr } from '@src/composables/useTranslate';
@@ -175,7 +169,6 @@ export default {
175
169
  ReorderableList,
176
170
  ReplaceImageSettingsForContent,
177
171
  NewPageModal,
178
- PageSettings,
179
172
  PageSelectorDropDown,
180
173
  },
181
174
  mixins: [ContentSettingsMixin],
@@ -93,7 +93,6 @@ export const CONTENT_SETTINGS_MODES = {
93
93
  edit: 'edit',
94
94
  add: 'add',
95
95
  images: 'images',
96
- pages: 'pages',
97
96
  focusedContentItem: 'focusedContentItem',
98
97
  } as const;
99
98
 
@@ -0,0 +1,100 @@
1
+ import { describe, test, expect, beforeEach } from 'vitest';
2
+ import { createPinia, setActivePinia } from 'pinia';
3
+ import { shallowMount } from '@vue/test-utils';
4
+ import PageSettings from './PageSettings.vue';
5
+ import ReplaceImageSettingsForContent from '../../../content-settings/components/content-settings/ReplaceImageSettingsForContent.vue';
6
+ import { useUiContentSettingsStore } from '../../../content-settings/store';
7
+ import { UI_EVENT_SOURCES } from '../../../models';
8
+
9
+ // Regression coverage for BP-5855: a header/footer image-replace intent (e.g. a social
10
+ // link icon) used to push the shared content-settings image-picker mode while
11
+ // PageSettings was still nested inside ContentSettings — pushing that mode swapped the
12
+ // panel in place. Now that PageSettings renders as its own sidebar tab
13
+ // (`<component :is="selectedTabName">` in BrandPageMaker.vue), the picker never mounted
14
+ // and the mode leaked into the next Content-tab visit. PageSettings must render the
15
+ // picker itself when the intent came from page settings, and hide the pages body while
16
+ // it's open.
17
+ describe('PageSettings — header/footer image-replace intent', () => {
18
+ let contentSettingsStore: ReturnType<typeof useUiContentSettingsStore>;
19
+
20
+ beforeEach(() => {
21
+ setActivePinia(createPinia());
22
+ contentSettingsStore = useUiContentSettingsStore();
23
+ });
24
+
25
+ const mountPageSettings = () => shallowMount(PageSettings);
26
+
27
+ const pagesBodyIsVisible = (
28
+ wrapper: ReturnType<typeof mountPageSettings>,
29
+ ): boolean =>
30
+ (
31
+ wrapper.find('[data-component="page-settings"] > div')
32
+ .element as HTMLElement
33
+ ).style.display !== 'none';
34
+
35
+ test('by default: no picker, pages body visible', () => {
36
+ const wrapper = mountPageSettings();
37
+
38
+ expect(wrapper.findComponent(ReplaceImageSettingsForContent).exists()).toBe(
39
+ false,
40
+ );
41
+ expect(pagesBodyIsVisible(wrapper)).toBe(true);
42
+ });
43
+
44
+ test('a page-settings image-replace intent opens the picker and hides the pages body', async () => {
45
+ const wrapper = mountPageSettings();
46
+
47
+ contentSettingsStore.setSelectedItemAndFieldName({
48
+ id: 'footer',
49
+ name: 'socialLinks',
50
+ index: 0,
51
+ eventSource: UI_EVENT_SOURCES.pageSettings,
52
+ });
53
+ contentSettingsStore.pushMode({ mode: 'images' });
54
+ await wrapper.vm.$nextTick();
55
+
56
+ expect(wrapper.findComponent(ReplaceImageSettingsForContent).exists()).toBe(
57
+ true,
58
+ );
59
+ expect(pagesBodyIsVisible(wrapper)).toBe(false);
60
+ });
61
+
62
+ test('does not open the picker for a content-settings-sourced image intent', async () => {
63
+ const wrapper = mountPageSettings();
64
+
65
+ contentSettingsStore.setSelectedItemAndFieldName({
66
+ id: 'some-content-item',
67
+ name: 'image',
68
+ index: 0,
69
+ eventSource: UI_EVENT_SOURCES.contentSettings,
70
+ });
71
+ contentSettingsStore.pushMode({ mode: 'images' });
72
+ await wrapper.vm.$nextTick();
73
+
74
+ expect(wrapper.findComponent(ReplaceImageSettingsForContent).exists()).toBe(
75
+ false,
76
+ );
77
+ expect(pagesBodyIsVisible(wrapper)).toBe(true);
78
+ });
79
+
80
+ test('popping the mode after picking an image restores the pages body', async () => {
81
+ const wrapper = mountPageSettings();
82
+
83
+ contentSettingsStore.setSelectedItemAndFieldName({
84
+ id: 'footer',
85
+ name: 'socialLinks',
86
+ index: 0,
87
+ eventSource: UI_EVENT_SOURCES.pageSettings,
88
+ });
89
+ contentSettingsStore.pushMode({ mode: 'images' });
90
+ await wrapper.vm.$nextTick();
91
+
92
+ contentSettingsStore.popMode();
93
+ await wrapper.vm.$nextTick();
94
+
95
+ expect(wrapper.findComponent(ReplaceImageSettingsForContent).exists()).toBe(
96
+ false,
97
+ );
98
+ expect(pagesBodyIsVisible(wrapper)).toBe(true);
99
+ });
100
+ });
@@ -16,7 +16,11 @@ import {
16
16
  PAGE_SECTION_STYLE_OPTIONS,
17
17
  type PageSectionStyleOption,
18
18
  } from '@brand-page-maker/models/page-section-style.model';
19
- import { useUiContentSettingsStore } from '../../../content-settings/store';
19
+ import {
20
+ CONTENT_SETTINGS_MODES,
21
+ useUiContentSettingsStore,
22
+ } from '../../../content-settings/store';
23
+ import { UI_EVENT_SOURCES } from '../../../models';
20
24
  import {
21
25
  PAGE_SETTINGS_SECTIONS,
22
26
  type PageSettingsSection,
@@ -47,13 +51,6 @@ export interface PageField {
47
51
  page: ContentPage;
48
52
  }
49
53
 
50
- const PAGE_SETTINGS_PAGES = {
51
- page: 'page',
52
- logo: 'logo',
53
- } as const;
54
-
55
- type PageSettingsPage = keyof typeof PAGE_SETTINGS_PAGES;
56
-
57
54
  const isRouteNestedInOrders = (
58
55
  orders: NavOrder[],
59
56
  routeId: string,
@@ -274,8 +271,6 @@ export default defineComponent({
274
271
  isDeleteModalVisible: false,
275
272
  deleteModalPageId: undefined as string | undefined,
276
273
  deleteModalPageTitle: undefined as string | undefined,
277
- currentPageNo: PAGE_SETTINGS_PAGES.page as PageSettingsPage,
278
- PAGE_SETTINGS_PAGES,
279
274
  PAGE_SETTINGS_SECTIONS,
280
275
  ALIGN_LEFT_ALIGNED,
281
276
  ALIGN_CENTERED,
@@ -334,6 +329,15 @@ export default defineComponent({
334
329
  showFooterSettings(): boolean {
335
330
  return this.isBrandSite;
336
331
  },
332
+ // Header/footer image-replace intents (e.g. a social link icon) route through the
333
+ // shared content-settings image picker rather than duplicating it here.
334
+ isReplacingPageSettingsImage(): boolean {
335
+ return (
336
+ this.contentSettingsStore.mode === CONTENT_SETTINGS_MODES.images &&
337
+ this.contentSettingsStore.selectedItemEventSource ===
338
+ UI_EVENT_SOURCES.pageSettings
339
+ );
340
+ },
337
341
  hideText() {
338
342
  return this.isDesignCom
339
343
  ? styleSettingsTr(`hideDesignLogo`)
@@ -474,33 +478,12 @@ export default defineComponent({
474
478
  onCancelDeletePage() {
475
479
  this.isDeleteModalVisible = false;
476
480
  },
477
- onLogoVariationSelected(value: string) {
478
- if (!this.selectedSectionName) {
479
- return;
480
- }
481
-
482
- const sectionName = this.selectedSectionName;
483
-
484
- this.pageSettingsStore.setPageSettingsSectionValue({
485
- sectionName,
486
- propName: 'logoImageUrl',
487
- value,
488
- viewport: this.viewport,
489
- });
490
-
491
- this.currentPageNo = PAGE_SETTINGS_PAGES.page;
492
-
493
- this.pageSettingsStore.setSelectedSectionName({ sectionName });
494
- },
495
481
  onPageTitleInput(pageId: string, title: string) {
496
482
  this.pageSettingsStore.setPageTitle({
497
483
  pageId,
498
484
  pageTitle: title,
499
485
  });
500
486
  },
501
- onBackButtonClick() {
502
- this.contentSettingsStore.popMode();
503
- },
504
487
  scrollToPageSettingsSection(sectionName: PageSettingsSection) {
505
488
  this.$nextTick(() => {
506
489
  const $sideBarContent = document.querySelector(
@@ -1,12 +1,11 @@
1
1
  <template>
2
2
  <div data-component="page-settings">
3
+ <!-- Header/footer image-replace intent (e.g. a social link icon) — shares the
4
+ content-settings image picker instead of duplicating it. -->
5
+ <ReplaceImageSettingsForContent v-if="isReplacingPageSettingsImage" />
3
6
  <!-- start page settings -->
4
- <div v-show="currentPageNo === PAGE_SETTINGS_PAGES.page">
5
- <SideBarSettingsHeader
6
- :title="pageSettingsTr('managePages')"
7
- :show-back-button="true"
8
- @on-back="onBackButtonClick"
9
- />
7
+ <div v-show="!isReplacingPageSettingsImage">
8
+ <SideBarSettingsHeader :title="pageSettingsTr('managePages')" />
10
9
  <p class="tw-font-sans tw-text-sm tw-text-grayscale-600 tw-mb-3">
11
10
  {{ pageSettingsTr('addPagesDescription') }}
12
11
  </p>
@@ -19,7 +18,6 @@
19
18
  <SideBarSectionTitle :title="pageSettingsTr('addPages')" />
20
19
  <!-- Nested draggable section for visible pages -->
21
20
  <NestedDraggable
22
- v-if="!parentRouteId"
23
21
  :orders="pageNavigationStore.orders"
24
22
  :is-dragging-page="isDraggingPage"
25
23
  :is-design-com="isDesignCom"
@@ -105,6 +103,8 @@
105
103
  @cancel="onCancelDeletePage"
106
104
  @confirm="onConfirmDeletePage"
107
105
  />
106
+
107
+ <NewPageModal />
108
108
  </div>
109
109
  <!-- end page settings -->
110
110
  </div>
@@ -115,7 +115,9 @@ import SideBarSettingsHeader from '../../../common/SideBarSettingsHeader.vue';
115
115
  import PageSettingsMixin from './PageSettings.mixin.ts';
116
116
  import SideBarSectionTitle from '../../../common/SideBarSectionTitle.vue';
117
117
  import DeletePageModal from '../delete-page-modal/DeletePageModal.vue';
118
+ import NewPageModal from '../new-page-modal/NewPageModal.vue';
118
119
  import PageSettingsSectionStyles from '../page-settings-section-styles/PageSettingsSectionStyles.vue';
120
+ import ReplaceImageSettingsForContent from '../../../content-settings/components/content-settings/ReplaceImageSettingsForContent.vue';
119
121
  import NestedDraggable from './NestedDraggable.vue';
120
122
  import { useBrandPageContainerStore } from '@brand-page-maker/stores';
121
123
  import { pageSettingsTr, styleSettingsTr } from '@src/composables/useTranslate';
@@ -129,7 +131,9 @@ export default {
129
131
  SideBarSectionTitle,
130
132
  NestedDraggable,
131
133
  DeletePageModal,
134
+ NewPageModal,
132
135
  PageSettingsSectionStyles,
136
+ ReplaceImageSettingsForContent,
133
137
  },
134
138
  mixins: [PageSettingsMixin],
135
139
  setup(_props, _context) {
@@ -0,0 +1,67 @@
1
+ import { describe, test, expect, vi } from 'vitest';
2
+ import SideBarMixin from './SideBar.mixin';
3
+ import { SIDE_BAR_TAB_NAMES } from '@src/brand-page-maker/constants/sidebar-constant';
4
+
5
+ // The desktop landing tab is chosen by NAME, not list position — inserting the
6
+ // Pages tab between Templates and Content must not change where an editor opens
7
+ // (BP-5855). Driving update() directly keeps the guard cheap.
8
+ const update = (SideBarMixin as any).methods.update;
9
+
10
+ const createContext = (
11
+ overrides: {
12
+ isMobileScreenSize?: boolean;
13
+ isPublished?: boolean;
14
+ isUserDraft?: boolean;
15
+ mobileTabName?: string;
16
+ } = {},
17
+ ) => ({
18
+ isMobileScreenSize: overrides.isMobileScreenSize ?? false,
19
+ mobileTabName: overrides.mobileTabName ?? SIDE_BAR_TAB_NAMES.PREVIEW,
20
+ brandPageContainerStore: {
21
+ isPublished: overrides.isPublished ?? false,
22
+ isUserDraft: overrides.isUserDraft ?? false,
23
+ },
24
+ sideBarStore: { setSelectedTabName: vi.fn() },
25
+ });
26
+
27
+ describe('SideBar.update — default landing tab', () => {
28
+ test('a published site opens on Content', () => {
29
+ const context = createContext({ isPublished: true });
30
+
31
+ update.call(context);
32
+
33
+ expect(context.sideBarStore.setSelectedTabName).toHaveBeenCalledWith({
34
+ tabName: SIDE_BAR_TAB_NAMES.CONTENT_SETTINGS,
35
+ });
36
+ });
37
+
38
+ test('an existing user draft opens on Content', () => {
39
+ const context = createContext({ isUserDraft: true });
40
+
41
+ update.call(context);
42
+
43
+ expect(context.sideBarStore.setSelectedTabName).toHaveBeenCalledWith({
44
+ tabName: SIDE_BAR_TAB_NAMES.CONTENT_SETTINGS,
45
+ });
46
+ });
47
+
48
+ test('a brand-new site opens on Templates', () => {
49
+ const context = createContext();
50
+
51
+ update.call(context);
52
+
53
+ expect(context.sideBarStore.setSelectedTabName).toHaveBeenCalledWith({
54
+ tabName: SIDE_BAR_TAB_NAMES.TEMPLATE_SETTINGS,
55
+ });
56
+ });
57
+
58
+ test('mobile opens on the preview tab', () => {
59
+ const context = createContext({ isMobileScreenSize: true });
60
+
61
+ update.call(context);
62
+
63
+ expect(context.sideBarStore.setSelectedTabName).toHaveBeenCalledWith({
64
+ tabName: SIDE_BAR_TAB_NAMES.PREVIEW,
65
+ });
66
+ });
67
+ });
@@ -73,15 +73,15 @@ export default defineComponent({
73
73
  methods: {
74
74
  update() {
75
75
  if (this.isMobileScreenSize === false) {
76
- const index =
76
+ // Land on Content for returning editors, Templates for new sites.
77
+ // Select by name, not list position — the tab order is not fixed.
78
+ const tabName =
77
79
  this.brandPageContainerStore.isPublished ||
78
80
  this.brandPageContainerStore.isUserDraft
79
- ? 1
80
- : 0;
81
+ ? SIDE_BAR_TAB_NAMES.CONTENT_SETTINGS
82
+ : SIDE_BAR_TAB_NAMES.TEMPLATE_SETTINGS;
81
83
 
82
- this.sideBarStore.setSelectedTabName({
83
- tabName: this.tabs.filter((x) => !x.isMobileOnly)[index].name,
84
- });
84
+ this.sideBarStore.setSelectedTabName({ tabName });
85
85
  } else {
86
86
  this.sideBarStore.setSelectedTabName({ tabName: this.mobileTabName });
87
87
  }