@shopbite-de/storefront 1.12.0 → 1.14.3

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 (39) hide show
  1. package/.github/workflows/build.yaml +1 -1
  2. package/app/app.vue +10 -11
  3. package/app/components/Address/Detail.vue +40 -11
  4. package/app/components/Address/Fields.vue +1 -1
  5. package/app/components/Address/Form.vue +33 -25
  6. package/app/components/Category/Breadcrumb.vue +1 -1
  7. package/app/components/Category/Listing.vue +1 -7
  8. package/app/components/Checkout/LoginOrRegister.vue +0 -2
  9. package/app/components/Checkout/PaymentAndDelivery.vue +2 -2
  10. package/app/components/Checkout/Summary.vue +19 -4
  11. package/app/components/Footer.vue +32 -11
  12. package/app/components/Header/Body.vue +8 -20
  13. package/app/components/Header/Right.vue +77 -59
  14. package/app/components/Header.vue +3 -22
  15. package/app/components/Navigation/DesktopLeft2.vue +4 -9
  16. package/app/components/Navigation/MobileTop2.vue +3 -4
  17. package/app/components/Order/Detail.vue +44 -26
  18. package/app/components/SalesChannelSwitch.vue +2 -4
  19. package/app/components/User/Detail.vue +38 -5
  20. package/app/components/User/RegistrationForm.vue +9 -11
  21. package/app/composables/useCategory.ts +37 -0
  22. package/app/composables/useNavigation.ts +86 -0
  23. package/app/pages/anmelden.vue +1 -1
  24. package/app/pages/bestellung.vue +1 -9
  25. package/app/pages/konto/adressen.vue +10 -3
  26. package/app/pages/order/[id].vue +1 -1
  27. package/package.json +7 -6
  28. package/test/e2e/simple-checkout-as-recurring-customer.test.ts +67 -10
  29. package/test/nuxt/HeaderRight.test.ts +2 -14
  30. package/test/nuxt/PaymentAndDelivery.test.ts +1 -3
  31. package/test/nuxt/RegistrationForm.test.ts +90 -30
  32. package/app/components/Navigation/DesktopLeft.vue +0 -47
  33. package/app/components/Navigation/MobileTop.vue +0 -55
  34. package/app/layouts/listing.vue +0 -32
  35. package/app/pages/menu/[...all].vue +0 -52
  36. package/content/navigation.yml +0 -57
  37. /package/content/{unternehmen/agb.md → agb.md} +0 -0
  38. /package/content/{unternehmen/datenschutz.md → datenschutz.md} +0 -0
  39. /package/content/{unternehmen/zahlung-und-versand.md → zahlung-und-versand.md} +0 -0
@@ -66,7 +66,7 @@ jobs:
66
66
  - name: Install pnpm
67
67
  uses: pnpm/action-setup@v4
68
68
  with:
69
- version: 10.29.3
69
+ version: 10.30.1
70
70
 
71
71
  - name: Install dependencies
72
72
  run: pnpm install --frozen-lockfile
package/app/app.vue CHANGED
@@ -26,18 +26,17 @@ const { isClosedHoliday, refresh: refreshHolidays } = useHolidays();
26
26
 
27
27
  await Promise.all([refreshBusinessHours(), refreshHolidays()]);
28
28
 
29
- // Initialize session context
30
- const { data: sessionContextData } = await useAsyncData(
31
- "session-context",
32
- async () => {
33
- const response = await apiClient.invoke("readContext get /context");
34
- return response.data as Schemas["SalesChannelContext"];
35
- },
36
- );
29
+ const sessionContextData = ref<Schemas["SalesChannelContext"]>();
37
30
 
38
- if (sessionContextData.value) {
39
- useSessionContext(sessionContextData.value);
40
- }
31
+ const contextResponse = await apiClient
32
+ .invoke("readContext get /context")
33
+ .catch((error) => {
34
+ console.error("Error fetching session context data:", error);
35
+ return { data: undefined };
36
+ });
37
+
38
+ sessionContextData.value = contextResponse.data;
39
+ useSessionContext(sessionContextData.value);
41
40
 
42
41
  // Toast configuration
43
42
  const TOAST_CONFIG = {
@@ -1,22 +1,51 @@
1
1
  <script setup lang="ts">
2
2
  import type { Schemas } from "#shopware";
3
3
 
4
- const props = defineProps<{
4
+ defineProps<{
5
5
  address: Schemas["CustomerAddress"] | undefined | null;
6
+ withEditButton?: boolean;
6
7
  }>();
7
8
 
8
- const { address } = toRefs(props);
9
+ const emit = defineEmits<{
10
+ "update:address": [address: Schemas["CustomerAddress"]];
11
+ }>();
12
+
13
+ const editMode = ref(false);
14
+
15
+ function onSubmit(updatedAddress: Schemas["CustomerAddress"] | undefined) {
16
+ if (!updatedAddress) return;
17
+
18
+ emit("update:address", updatedAddress);
19
+ editMode.value = false;
20
+ }
9
21
  </script>
10
22
 
11
23
  <template>
12
- <div v-if="address">
13
- <div>{{ address.firstName }} {{ address.lastName }}</div>
14
- <div>{{ address.phoneNumber }}</div>
15
- <div>{{ address.company }}</div>
16
- <div>{{ address.department }}</div>
17
- <div>{{ address.additionalAddressLine1 }}</div>
18
- <div>{{ address.additionalAddressLine2 }}</div>
19
- <div>{{ address.street }}</div>
20
- <div>{{ address.zipcode }} {{ address.city }}</div>
24
+ <div v-if="address" class="flex flex-col gap-2">
25
+ <div v-if="!editMode" class="flex flex-col gap-2">
26
+ <div>{{ address.firstName }} {{ address.lastName }}</div>
27
+ <div>{{ address.phoneNumber }}</div>
28
+ <div v-if="address.company">{{ address.company }}</div>
29
+ <div v-if="address.department">{{ address.department }}</div>
30
+ <div v-if="address.additionalAddressLine1">
31
+ {{ address.additionalAddressLine1 }}
32
+ </div>
33
+ <div v-if="address.additionalAddressLine2">
34
+ {{ address.additionalAddressLine2 }}
35
+ </div>
36
+ <div>{{ address.street }}</div>
37
+ <div>{{ address.zipcode }} {{ address.city }}</div>
38
+ <UButton
39
+ v-if="withEditButton"
40
+ variant="subtle"
41
+ icon="i-lucide-pen"
42
+ label="Bearbeiten"
43
+ block
44
+ @click="editMode = true"
45
+ />
46
+ </div>
47
+ <div v-else>
48
+ <AddressForm :address="address" @submit-success="onSubmit" />
49
+ </div>
21
50
  </div>
22
51
  </template>
@@ -109,7 +109,7 @@ defineExpose({
109
109
  >
110
110
  <template #title>
111
111
  An diese Adresse können wir leider nicht liefern.
112
- <ULink to="/unternehmen/zahlung-und-versand">Weitere Infos.</ULink>
112
+ <ULink to="/zahlung-und-versand">Weitere Infos.</ULink>
113
113
  </template>
114
114
  </UAlert>
115
115
 
@@ -10,23 +10,21 @@ const props = defineProps<{
10
10
  address?: Schemas["CustomerAddress"] | undefined;
11
11
  }>();
12
12
 
13
- const { address } = toRefs(props);
14
-
13
+ const config = useRuntimeConfig();
15
14
  const { updateCustomerAddress, createCustomerAddress } = useAddress();
16
15
 
17
16
  const state = reactive({
18
- id: address.value.id,
19
- accountType: "privat",
20
- firstName: address.value.firstName ?? undefined,
21
- lastName: address.value.lastName ?? undefined,
22
- company: address.value.company ?? undefined,
23
- department: address.value.department ?? undefined,
24
- additionalAddressLine1: address.value.additionalAddressLine1 ?? undefined,
25
- phoneNumber: address.value.phoneNumber ?? undefined,
26
- street: address.value.street ?? undefined,
27
- zipcode: address.value.zipcode ?? undefined,
28
- city: address.value.city ?? undefined,
29
- countryId: "018d9f162ade709b9ccc92929b44d236",
17
+ id: props.address?.id,
18
+ firstName: props.address?.firstName ?? undefined,
19
+ lastName: props.address?.lastName ?? undefined,
20
+ company: props.address?.company ?? undefined,
21
+ department: props.address?.department ?? undefined,
22
+ additionalAddressLine1: props.address?.additionalAddressLine1 ?? undefined,
23
+ phoneNumber: props.address?.phoneNumber ?? undefined,
24
+ street: props.address?.street ?? undefined,
25
+ zipcode: props.address?.zipcode ?? undefined,
26
+ city: props.address?.city ?? undefined,
27
+ countryId: config.public.site.countryId,
30
28
  });
31
29
 
32
30
  const schema = computed(() => createAddressSchema(state));
@@ -34,23 +32,33 @@ const schema = computed(() => createAddressSchema(state));
34
32
  const toast = useToast();
35
33
 
36
34
  async function onSubmit(event: FormSubmitEvent<AddressSchema>) {
37
- if (event.data.id) {
38
- await updateCustomerAddress(event.data);
39
- } else {
40
- await createCustomerAddress(event.data);
35
+ try {
36
+ let response: undefined | Schemas["CustomerAddress"] = undefined;
37
+ if (event.data.id) {
38
+ response = await updateCustomerAddress(event.data);
39
+ } else {
40
+ response = await createCustomerAddress(event.data);
41
+ }
42
+
43
+ toast.add({
44
+ title: "Erfolgreich gespeichert",
45
+ color: "success",
46
+ });
47
+ emit("submit-success", response);
48
+ } catch (error) {
49
+ console.error("Address save failed:", error);
50
+ toast.add({
51
+ title: "Speichern fehlgeschlagen",
52
+ description: "Bitte versuchen Sie es erneut.",
53
+ color: "error",
54
+ });
41
55
  }
42
-
43
- toast.add({
44
- title: "Erfolgreich gespeichert",
45
- color: "success",
46
- });
47
- emit("submit-success", event.data);
48
56
  }
49
57
 
50
58
  const accountType = ref("privat");
51
59
 
52
60
  const emit = defineEmits<{
53
- "submit-success": [data: AddressSchema];
61
+ "submit-success": [data: Schemas["CustomerAddress"]];
54
62
  }>();
55
63
  </script>
56
64
 
@@ -40,7 +40,7 @@ const { data } = await useAsyncData(cacheKey, async () => {
40
40
  });
41
41
 
42
42
  const items = computed<BreadcrumbItem[]>(() => {
43
- if (!data.value) return [];
43
+ if (!data.value) return [{ label: "Kategorie", to: "#" }];
44
44
  return data.value?.map((item: Schemas["Breadcrumb"]) => {
45
45
  return {
46
46
  label: item.name,
@@ -58,13 +58,7 @@ const {
58
58
  defaultSearchCriteria: searchCriteria,
59
59
  });
60
60
 
61
- const { search: categorySearch } = useCategorySearch();
62
-
63
- const categoryCacheKey = computed(() => `category-${categoryId.value}`);
64
-
65
- const { data: category } = await useAsyncData(categoryCacheKey, async () => {
66
- return await categorySearch(categoryId.value);
67
- });
61
+ const { category } = useCategory(categoryId);
68
62
 
69
63
  useCategorySeo(category);
70
64
 
@@ -1,7 +1,6 @@
1
1
  <script setup lang="ts">
2
2
  import type { TabsItem } from "@nuxt/ui";
3
3
 
4
- const { refreshUser } = useUser();
5
4
  const items = [
6
5
  {
7
6
  label: "Daten erfassen",
@@ -18,7 +17,6 @@ const toast = useToast();
18
17
  const { mergeWishlistProducts } = useWishlist();
19
18
 
20
19
  async function handleLoginSuccess() {
21
- await refreshUser();
22
20
  mergeWishlistProducts();
23
21
  toast.add({
24
22
  title: "Wilkommen!",
@@ -89,7 +89,7 @@ watch(
89
89
  <UIcon name="i-lucide-badge-euro" class="size-8" />
90
90
  <h2 class="text-2xl text-blackish my-8">Zahlungsarten</h2>
91
91
  <UButton
92
- to="/unternehmen/zahlung-und-versand"
92
+ to="/zahlung-und-versand"
93
93
  size="md"
94
94
  variant="ghost"
95
95
  icon="i-lucide-circle-question-mark"
@@ -106,7 +106,7 @@ watch(
106
106
  <UIcon name="i-lucide-car" class="size-8" />
107
107
  <h2 class="text-2xl text-blackish my-8">Versandarten</h2>
108
108
  <UButton
109
- to="/unternehmen/zahlung-und-versand"
109
+ to="/zahlung-und-versand"
110
110
  size="md"
111
111
  variant="ghost"
112
112
  icon="i-lucide-circle-question-mark"
@@ -2,10 +2,10 @@
2
2
  import QuickView from "~/components/Cart/QuickView.vue";
3
3
  import { useIntervalFn } from "@vueuse/core";
4
4
 
5
- const { selectedPaymentMethod, selectedShippingMethod } = useCheckout();
6
- const { createOrder } = useCheckout();
5
+ const { createOrder, selectedPaymentMethod, selectedShippingMethod } =
6
+ useCheckout();
7
7
  const { refreshCart } = useCart();
8
- const { isLoggedIn, isGuestSession } = useUser();
8
+ const { isLoggedIn, isGuestSession, refreshUser } = useUser();
9
9
  const { isCheckoutEnabled, refresh } = useShopBiteConfig();
10
10
  const { trackOrder } = useTrackEvent();
11
11
 
@@ -13,6 +13,14 @@ const toast = useToast();
13
13
 
14
14
  onMounted(() => {
15
15
  refresh();
16
+ refreshUser({
17
+ associations: {
18
+ defaultShippingAddress: {},
19
+ defaultBillingAddress: {},
20
+ activeShippingAddress: {},
21
+ activeBillingAddress: {},
22
+ },
23
+ });
16
24
  });
17
25
 
18
26
  watch(isCheckoutEnabled, () => console.log(isCheckoutEnabled.value));
@@ -40,9 +48,16 @@ const customerDataAvailable = computed<boolean>(
40
48
  () => isLoggedIn.value || isGuestSession.value,
41
49
  );
42
50
 
51
+ const shippingAndPaymentSet = computed(
52
+ () => selectedPaymentMethod.value && selectedShippingMethod.value,
53
+ );
54
+
43
55
  const isValidToProceed = computed(
44
56
  () =>
45
- customerDataAvailable.value && isCheckoutEnabled.value && isValidTime.value,
57
+ customerDataAvailable.value &&
58
+ isCheckoutEnabled.value &&
59
+ isValidTime.value &&
60
+ shippingAndPaymentSet.value,
46
61
  );
47
62
 
48
63
  const selectedDeliveryTime = ref("");
@@ -1,12 +1,33 @@
1
1
  <script setup lang="ts">
2
- const { data: navigationData } = await useAsyncData("navigation:footer", () =>
3
- queryCollection("navigation").first(),
4
- );
2
+ import { useNavigation } from "~/composables/useNavigation";
3
+ import type {
4
+ FooterColumn,
5
+ FooterColumnLink,
6
+ NavigationMenuItem,
7
+ } from "@nuxt/ui";
8
+
9
+ const { footerMenu } = useNavigation(true);
5
10
 
6
- const columns = computed(() => {
7
- if (!navigationData.value?.footer.columns) return [];
8
- return navigationData.value.footer.columns;
11
+ const menuItemToFooterColumnLink = (
12
+ item: NavigationMenuItem,
13
+ ): FooterColumnLink => ({
14
+ label: item.label ?? "",
15
+ to: item.to as string | undefined,
16
+ target: item.target as string | undefined,
17
+ icon: item.icon,
9
18
  });
19
+
20
+ const menuItemsToFooterColumns = (
21
+ items: NavigationMenuItem[],
22
+ ): FooterColumn[] =>
23
+ items.map((item) => ({
24
+ label: item.label ?? "",
25
+ children: item.children?.map(menuItemToFooterColumnLink) ?? [],
26
+ }));
27
+
28
+ const footerColumns = computed<FooterColumn[]>(() =>
29
+ menuItemsToFooterColumns(footerMenu.value),
30
+ );
10
31
  </script>
11
32
 
12
33
  <template>
@@ -15,7 +36,7 @@ const columns = computed(() => {
15
36
  <UFooter :ui="{ top: 'border-b border-default' }">
16
37
  <template #top>
17
38
  <UContainer>
18
- <UFooterColumns :columns="columns" />
39
+ <UFooterColumns :columns="footerColumns" />
19
40
  </UContainer>
20
41
  </template>
21
42
 
@@ -29,15 +50,15 @@ const columns = computed(() => {
29
50
  </NuxtLink>
30
51
  </template>
31
52
 
32
- <p v-if="navigationData?.footer.text" class="text-muted text-sm">
33
- {{ navigationData.footer.text }}
53
+ <p class="text-muted text-sm">
54
+ Alle Preise inkl. gesetzlicher Mehrwertsteuer zzgl. Versandkosten, wenn
55
+ nicht anders beschrieben
34
56
  </p>
35
57
 
36
58
  <template #right>
37
- <UColorModeButton v-if="navigationData?.footer.withColorModeSwitch" />
59
+ <UColorModeButton />
38
60
 
39
61
  <UButton
40
- v-if="navigationData?.footer.withGithubLink"
41
62
  to="https://github.com/shopbite-de/storefront"
42
63
  target="_blank"
43
64
  icon="i-simple-icons-github"
@@ -1,36 +1,24 @@
1
1
  <script setup lang="ts">
2
- import type { NavigationMenuItem } from "@nuxt/ui";
2
+ import { useNavigation } from "~/composables/useNavigation";
3
3
 
4
- const route = useRoute();
4
+ const config = useRuntimeConfig();
5
5
 
6
- const { data: navigationData } = useAsyncData("navigation", () =>
7
- queryCollection("navigation").first(),
6
+ const multiChannelEnabled = computed(
7
+ () => config.public.shopBite.feature.multiChannel === "true",
8
8
  );
9
9
 
10
- const navi = computed<NavigationMenuItem[]>(() => {
11
- if (!navigationData.value?.main) return [];
12
-
13
- return navigationData.value.main.map((item) => ({
14
- label: item.label,
15
- icon: item.icon,
16
- to: item.to,
17
- target: item.target,
18
- active:
19
- item.to === "/"
20
- ? route.path.length === 1
21
- : route.path.startsWith(item.to),
22
- }));
23
- });
10
+ console.log(multiChannelEnabled.value);
11
+ const { mainMenu } = useNavigation(false);
24
12
  </script>
25
13
 
26
14
  <template>
27
15
  <UNavigationMenu
28
16
  color="primary"
29
- :items="navi"
17
+ :items="mainMenu"
30
18
  orientation="vertical"
31
19
  class="-mx-2.5"
32
20
  />
33
- <div class="my-4">
21
+ <div v-if="multiChannelEnabled" class="my-4">
34
22
  <SalesChannelSwitch />
35
23
  </div>
36
24
  </template>
@@ -3,9 +3,10 @@ import { useUser } from "@shopware/composables";
3
3
  import type { DropdownMenuItem } from "@nuxt/ui";
4
4
 
5
5
  const cartQuickViewOpen = ref(false);
6
- const { count } = useCart();
6
+ const { count: cartCount } = useCart();
7
+ const { count: wishListCount } = useWishlist();
7
8
  const { isCheckoutEnabled } = useShopBiteConfig();
8
- const { isLoggedIn, isGuestSession, user, logout } = useUser();
9
+ const { isLoggedIn, isGuestSession, logout } = useUser();
9
10
  const toast = useToast();
10
11
 
11
12
  const logoutHandler = () => {
@@ -17,50 +18,58 @@ const logoutHandler = () => {
17
18
  });
18
19
  };
19
20
 
20
- const { data: navigationData } = await useAsyncData("navigation:right", () =>
21
- queryCollection("navigation").first(),
22
- );
23
-
24
- const accountHoverText = computed(() => {
25
- return isLoggedIn.value || isGuestSession.value
26
- ? `${user.value?.firstName} ${user.value?.lastName}`
27
- : "Hallo";
28
- });
29
-
30
- const loggedInDropDown = computed<DropdownMenuItem[][]>(() => {
31
- if (!navigationData.value?.account.loggedIn) return [];
32
-
33
- return navigationData.value.account.loggedIn
34
- .map((group) =>
35
- group
36
- .filter((item) => {
37
- if (isGuestSession.value) {
38
- return item.type === "label" || item.action === "logout";
39
- }
40
- return true;
41
- })
42
- .map((item) => ({
43
- label: item.type === "label" ? accountHoverText.value : item.label,
44
- type: item.type,
45
- icon: item.icon,
46
- to: item.to,
47
- onSelect: item.action === "logout" ? logoutHandler : undefined,
48
- })),
49
- )
50
- .filter((group) => group.length > 0);
51
- });
52
-
53
- const loggedOutDropDown = computed<DropdownMenuItem[][]>(() => {
54
- if (!navigationData.value?.account.loggedOut) return [];
55
-
56
- return navigationData.value.account.loggedOut.map((group) =>
57
- group.map((item) => ({
58
- label: item.label,
59
- type: item.type,
60
- icon: item.icon,
61
- to: item.to,
62
- })),
63
- );
21
+ const dropDownMenu = computed<DropdownMenuItem[][]>(() => {
22
+ if (isLoggedIn.value) {
23
+ return [
24
+ [
25
+ {
26
+ label: "Mein Konto",
27
+ type: "label",
28
+ },
29
+ {
30
+ label: "Übersicht",
31
+ icon: "i-lucide-user",
32
+ to: "/konto",
33
+ },
34
+ {
35
+ label: "Bestellungen",
36
+ icon: "i-lucide-pizza",
37
+ to: "/konto/bestellungen",
38
+ },
39
+ {
40
+ label: "Adressen",
41
+ icon: "i-lucide-house",
42
+ to: "/konto/adressen",
43
+ },
44
+ ],
45
+ [
46
+ {
47
+ label: "Abmelden",
48
+ icon: "i-lucide-log-out",
49
+ onSelect: () => logoutHandler(),
50
+ },
51
+ ],
52
+ ];
53
+ } else {
54
+ return [
55
+ [
56
+ {
57
+ label: "Mein Konto",
58
+ type: "label",
59
+ },
60
+ {
61
+ label: "Anmelden",
62
+ icon: "i-lucide-user",
63
+ to: "/anmelden",
64
+ },
65
+ {
66
+ label: "Registrieren",
67
+ icon: "i-lucide-user-plus",
68
+ to: "/registrierung",
69
+ },
70
+ ],
71
+ ];
72
+ }
64
73
  });
65
74
  </script>
66
75
 
@@ -73,9 +82,7 @@ const loggedOutDropDown = computed<DropdownMenuItem[][]>(() => {
73
82
  icon="i-lucide-phone"
74
83
  aria-label="Anrufen"
75
84
  />
76
- <UDropdownMenu
77
- :items="isLoggedIn || isGuestSession ? loggedInDropDown : loggedOutDropDown"
78
- >
85
+ <UDropdownMenu :items="dropDownMenu">
79
86
  <UChip v-if="isLoggedIn || isGuestSession" size="3xl" text="✓">
80
87
  <UButton
81
88
  aria-label="Konto Dropdown öffnen"
@@ -89,29 +96,42 @@ const loggedOutDropDown = computed<DropdownMenuItem[][]>(() => {
89
96
  aria-label="Konto Dropdown öffnen"
90
97
  icon="i-lucide-user"
91
98
  color="neutral"
92
- variant="outline"
99
+ variant="ghost"
93
100
  />
94
101
  </UDropdownMenu>
102
+ <div>
103
+ <UChip :text="wishListCount" size="3xl">
104
+ <UButton
105
+ aria-label="Zur Merkliste"
106
+ color="neutral"
107
+ variant="ghost"
108
+ to="/merkliste"
109
+ icon="i-lucide-heart"
110
+ />
111
+ </UChip>
112
+ </div>
95
113
  <UDrawer
96
114
  v-if="isCheckoutEnabled"
97
115
  v-model:open="cartQuickViewOpen"
98
116
  title="Warenkorb"
99
117
  direction="right"
100
118
  >
101
- <UChip :text="count" size="3xl">
119
+ <UChip :text="cartCount" size="3xl">
102
120
  <UButton
103
121
  aria-label="Zum Warenkorb"
104
122
  color="neutral"
105
- variant="outline"
106
- icon="i-lucide-shopping-cart"
123
+ variant="ghost"
124
+ icon="i-lucide-shopping-bag"
107
125
  />
108
126
  </UChip>
109
127
 
110
128
  <template #header>
111
- <h2 class="text-3xl md:text-4xl mt-8 mb-3 pb-2">
112
- <UIcon name="i-lucide-shopping-cart" class="size-8" color="primary" />
113
- Warenkorb
114
- </h2>
129
+ <div class="h-full flex flex-col justify-center">
130
+ <h2 class="flex items-center gap-2 text-3xl md:text-4xl mt-8 mb-3 pb-2">
131
+ <UIcon name="i-lucide-shopping-bag" class="size-8" color="primary" />
132
+ Warenkorb
133
+ </h2>
134
+ </div>
115
135
  </template>
116
136
  <template #body>
117
137
  <CartQuickView
@@ -122,5 +142,3 @@ const loggedOutDropDown = computed<DropdownMenuItem[][]>(() => {
122
142
  </template>
123
143
  </UDrawer>
124
144
  </template>
125
-
126
- <style scoped></style>
@@ -1,26 +1,7 @@
1
1
  <script setup lang="ts">
2
- import type { NavigationMenuItem } from "@nuxt/ui";
2
+ import { useNavigation } from "~/composables/useNavigation";
3
3
 
4
- const route = useRoute();
5
-
6
- const { data: navigationData } = await useAsyncData("navigation", () =>
7
- queryCollection("navigation").first(),
8
- );
9
-
10
- const navi = computed<NavigationMenuItem[]>(() => {
11
- if (!navigationData.value?.main) return [];
12
-
13
- return navigationData.value.main.map((item) => ({
14
- label: item.label,
15
- icon: item.icon,
16
- to: item.to,
17
- target: item.target,
18
- active:
19
- item.to === "/"
20
- ? route.path.length === 1
21
- : route.path.startsWith(item.to),
22
- }));
23
- });
4
+ const { mainMenu } = useNavigation(false);
24
5
 
25
6
  const loginSlide = ref(false);
26
7
  </script>
@@ -31,7 +12,7 @@ const loginSlide = ref(false);
31
12
  <HeaderTitle />
32
13
  </template>
33
14
 
34
- <UNavigationMenu color="primary" variant="pill" :items="navi" />
15
+ <UNavigationMenu color="primary" variant="pill" :items="mainMenu" />
35
16
 
36
17
  <template #right>
37
18
  <HeaderRight />