@revenexx/cover 0.1.4 → 0.1.5

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.
@@ -1,4 +1,9 @@
1
1
  <script setup lang="ts">
2
+ // app.config feature switch — lean storefronts ship without order lists.
3
+ const featureOrderLists = computed(() =>
4
+ ((useAppConfig().features ?? {}) as Record<string, boolean>).orderLists !== false,
5
+ );
6
+
2
7
  import { slugify } from "../../../composables/useProducts";
3
8
  import type { CalculatedCartLine } from "../../../interfaces/cart-calculation";
4
9
  import type { CartItem } from "../../../interfaces/cart-item";
@@ -339,7 +344,7 @@ const hintColor = (type: string) =>
339
344
  class="flex flex-col gap-0.5 shrink-0"
340
345
  >
341
346
  <UTooltip
342
- v-if="role"
347
+ v-if="role && featureOrderLists"
343
348
  :text="t('cart.bulk.saveToList')"
344
349
  >
345
350
  <UButton
@@ -1,4 +1,9 @@
1
1
  <script setup lang="ts">
2
+ // app.config feature switch — lean storefronts ship without order lists.
3
+ const featureOrderLists = computed(() =>
4
+ ((useAppConfig().features ?? {}) as Record<string, boolean>).orderLists !== false,
5
+ );
6
+
2
7
  /**
3
8
  * Sticky cart list header: three-state multi-selector and the bulk action
4
9
  * bar (visible from one selected position). The bulk actions mirror the
@@ -63,7 +68,7 @@ function bulkDelete(): void {
63
68
  @click="actions.open('texts', selection.selected.value)"
64
69
  />
65
70
  <UButton
66
- v-if="role"
71
+ v-if="role && featureOrderLists"
67
72
  :icon="icon('bookmark')"
68
73
  color="neutral"
69
74
  variant="ghost"
@@ -1,4 +1,7 @@
1
1
  <script setup lang="ts">
2
+ // Storefront feature switches (app.config `features`, default on).
3
+ const features = computed(() => (useAppConfig().features ?? {}) as Record<string, boolean>);
4
+
2
5
  import CartExportModal from "../actions/CartExportModal.vue";
3
6
  import CartCostCenterModal from "../actions/CartCostCenterModal.vue";
4
7
  import CartPositionTextsModal from "../actions/CartPositionTextsModal.vue";
@@ -100,7 +103,7 @@ const messageColor = (severity: string) =>
100
103
  <CartSwitcher class="print:hidden" />
101
104
  </div>
102
105
  <UButton
103
- v-if="!isEmpty"
106
+ v-if="!isEmpty && features.directOrder !== false"
104
107
  :icon="icon('direct-order')"
105
108
  color="neutral"
106
109
  variant="outline"
@@ -205,6 +208,7 @@ const messageColor = (severity: string) =>
205
208
  tabindex="0"
206
209
  />
207
210
  <UButton
211
+ v-if="features.directOrder !== false"
208
212
  color="neutral"
209
213
  variant="outline"
210
214
  :icon="icon('direct-order')"
@@ -213,6 +217,7 @@ const messageColor = (severity: string) =>
213
217
  tabindex="0"
214
218
  />
215
219
  <UButton
220
+ v-if="features.orderLists !== false"
216
221
  color="neutral"
217
222
  variant="outline"
218
223
  :icon="icon('order-list')"
@@ -226,7 +231,7 @@ const messageColor = (severity: string) =>
226
231
 
227
232
  <!-- The fastest paths back to an order -->
228
233
  <div class="mt-8 space-y-8">
229
- <CartReorderStrip />
234
+ <CartReorderStrip v-if="features.reorderStrip !== false" />
230
235
  <CartCrossSell popular />
231
236
  </div>
232
237
  </template>
@@ -266,7 +271,7 @@ const messageColor = (severity: string) =>
266
271
 
267
272
  <!-- Revenue strips: fast reorder + cross-sell -->
268
273
  <div class="mt-8 space-y-8">
269
- <CartReorderStrip />
274
+ <CartReorderStrip v-if="features.reorderStrip !== false" />
270
275
  <CartCrossSell />
271
276
  </div>
272
277
  </template>
@@ -283,7 +288,7 @@ const messageColor = (severity: string) =>
283
288
  @update:open="actions.close()"
284
289
  />
285
290
  <CartSaveToListModal
286
- :open="actions.action.value.type === 'save'"
291
+ :open="features.orderLists !== false && actions.action.value.type === 'save'"
287
292
  :line-keys="actions.action.value.lineKeys"
288
293
  @update:open="actions.close()"
289
294
  />
@@ -294,6 +299,7 @@ const messageColor = (severity: string) =>
294
299
 
295
300
  <!-- Quick entry: the full direct-order toolset in a wide lightbox -->
296
301
  <UModal
302
+ v-if="features.directOrder !== false"
297
303
  v-model:open="quickAddOpen"
298
304
  :title="t('directOrder.title')"
299
305
  :description="t('directOrder.description')"
@@ -1,5 +1,12 @@
1
1
  <script setup lang="ts">
2
- import { footerLinks, legalLinks, shopContact } from "../../../config/navigation";
2
+ import { footerLinks as defaultFooterLinks, legalLinks as defaultLegalLinks, shopContact } from "../../../config/navigation";
3
+
4
+ // Consumers can replace the footer link columns / legal links via
5
+ // app.config (`footerLinks`, `legalLinks`) — a lean storefront points
6
+ // them at pages it actually ships instead of the demo's full sitemap.
7
+ const appConfig = useAppConfig();
8
+ const footerLinks = computed(() => (appConfig.footerLinks as typeof defaultFooterLinks | undefined) ?? defaultFooterLinks);
9
+ const legalLinks = computed(() => (appConfig.legalLinks as typeof defaultLegalLinks | undefined) ?? defaultLegalLinks);
3
10
 
4
11
  const { icon } = useIcons();
5
12
 
@@ -1,4 +1,8 @@
1
1
  <script setup lang="ts">
2
+ // Storefront feature switches (app.config `features`, default: everything
3
+ // on) — lean themes turn off the surfaces their MVP does not ship.
4
+ const features = computed(() => (useAppConfig().features ?? {}) as Record<string, boolean>);
5
+
2
6
  const { icon } = useIcons();
3
7
 
4
8
  const { t } = useI18n();
@@ -59,6 +63,7 @@ const { navigateToSearch } = useSearch();
59
63
 
60
64
  <template #right>
61
65
  <LayoutHeaderActionItem
66
+ v-if="features.directOrder !== false"
62
67
  :icon="icon('direct-order')"
63
68
  :label="t('topbar.directOrder')"
64
69
  :to="localePath('/account/direct-order')"
@@ -1,5 +1,10 @@
1
1
  <script setup lang="ts">
2
- import { mainNavigation, mainNavigationSecondary } from "../../../config/navigation";
2
+ import { mainNavigation as defaultMainNav, mainNavigationSecondary as defaultSecondaryNav } from "../../../config/navigation";
3
+
4
+ // app.config override: lean storefronts link only to pages they ship.
5
+ const appConfig = useAppConfig();
6
+ const mainNavigation = computed(() => (appConfig.mainNavigation as typeof defaultMainNav | undefined) ?? defaultMainNav);
7
+ const mainNavigationSecondary = computed(() => (appConfig.mainNavigationSecondary as typeof defaultSecondaryNav | undefined) ?? defaultSecondaryNav);
3
8
 
4
9
  const { t } = useI18n();
5
10
  const localePath = useLocalePath();
@@ -1,5 +1,9 @@
1
1
  <script setup lang="ts">
2
- import { topbarQuickLinks, topbarUsps } from "../../../config/navigation";
2
+ import { topbarQuickLinks as defaultQuickLinks, topbarUsps } from "../../../config/navigation";
3
+
4
+ // app.config override: lean storefronts link only to pages they ship.
5
+ const appConfig = useAppConfig();
6
+ const topbarQuickLinks = computed(() => (appConfig.topbarQuickLinks as typeof defaultQuickLinks | undefined) ?? defaultQuickLinks);
3
7
 
4
8
  const { icon } = useIcons();
5
9
  const { t } = useI18n();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@revenexx/cover",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "description": "Cover \u2014 revenexx design system for Nuxt. Distributed as a Nuxt layer: generic UI components, theming tokens and stores shared by the demo shop, custom storefronts and the Blokkli theme.",
5
5
  "type": "module",
6
6
  "main": "./nuxt.config.ts",
@@ -15,19 +15,37 @@ import { MockCartCalculationService } from "../services/MockCartCalculationServi
15
15
  export const ORG_SETTINGS_COOKIE = "cover-org-settings";
16
16
 
17
17
  export function resolveOrgSettingsOverride(event?: H3Event): Partial<OrganizationSettings> | undefined {
18
- if (!event) {
19
- return undefined;
18
+ // Base layer: the app's own organization defaults (app.config
19
+ // `orgSettings`) — a lean storefront ships simple B2C-ish settings
20
+ // (no cost centers/approvals, no minimum order value) without giving
21
+ // up the demo data. The dev-panel cookie still wins on top.
22
+ const appDefaults = useAppConfig().orgSettings as Partial<OrganizationSettings> | undefined;
23
+
24
+ let cookieOverride: Partial<OrganizationSettings> | undefined;
25
+ const raw = event ? getCookie(event, ORG_SETTINGS_COOKIE) : undefined;
26
+ if (raw) {
27
+ try {
28
+ cookieOverride = JSON.parse(raw) as Partial<OrganizationSettings>;
29
+ }
30
+ catch { /* ignore malformed cookie */ }
20
31
  }
21
- const raw = getCookie(event, ORG_SETTINGS_COOKIE);
22
- if (!raw) {
23
- return undefined;
32
+
33
+ if (!appDefaults) {
34
+ return cookieOverride;
24
35
  }
25
- try {
26
- return JSON.parse(raw) as Partial<OrganizationSettings>;
36
+ if (!cookieOverride) {
37
+ return appDefaults;
27
38
  }
28
- catch {
29
- return undefined;
39
+ // Section-wise merge (the settings object is one level of sections
40
+ // with scalar leaves) — cookie sections win over app defaults.
41
+ const merged: Record<string, unknown> = { ...appDefaults };
42
+ for (const [key, value] of Object.entries(cookieOverride)) {
43
+ const base = (merged as Record<string, unknown>)[key];
44
+ merged[key] = (value && typeof value === "object" && base && typeof base === "object")
45
+ ? { ...base, ...value }
46
+ : value;
30
47
  }
48
+ return merged as Partial<OrganizationSettings>;
31
49
  }
32
50
 
33
51
  export function getB2BContextService(event?: H3Event): IB2BContextService {