@shopbite-de/storefront 1.1.0

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 (136) hide show
  1. package/.dockerignore +28 -0
  2. package/.env.example +11 -0
  3. package/.github/workflows/build.yaml +48 -0
  4. package/.github/workflows/ci.yaml +102 -0
  5. package/.prettierignore +6 -0
  6. package/.prettierrc +1 -0
  7. package/api-types/storeApiSchema.json +13863 -0
  8. package/api-types/storeApiTypes.d.ts +7010 -0
  9. package/app/app.config.ts +18 -0
  10. package/app/app.vue +99 -0
  11. package/app/assets/css/main.css +60 -0
  12. package/app/assets/fonts/Courier_Prime/CourierPrime-Bold.ttf +0 -0
  13. package/app/assets/fonts/Courier_Prime/CourierPrime-BoldItalic.ttf +0 -0
  14. package/app/assets/fonts/Courier_Prime/CourierPrime-Italic.ttf +0 -0
  15. package/app/assets/fonts/Courier_Prime/CourierPrime-Regular.ttf +0 -0
  16. package/app/assets/fonts/Courier_Prime/OFL.txt +93 -0
  17. package/app/assets/fonts/Kalam/Kalam-Bold.ttf +0 -0
  18. package/app/assets/fonts/Kalam/Kalam-Light.ttf +0 -0
  19. package/app/assets/fonts/Kalam/Kalam-Regular.ttf +0 -0
  20. package/app/assets/fonts/Kalam/OFL.txt +93 -0
  21. package/app/assets/fonts/Marcellus/Marcellus-Regular.ttf +0 -0
  22. package/app/assets/fonts/Marcellus/OFL.txt +93 -0
  23. package/app/assets/fonts/Sora/OFL.txt +93 -0
  24. package/app/assets/fonts/Sora/README.txt +70 -0
  25. package/app/assets/fonts/Sora/Sora-VariableFont_wght.ttf +0 -0
  26. package/app/assets/fonts/Sora/static/Sora-Bold.ttf +0 -0
  27. package/app/assets/fonts/Sora/static/Sora-ExtraBold.ttf +0 -0
  28. package/app/assets/fonts/Sora/static/Sora-ExtraLight.ttf +0 -0
  29. package/app/assets/fonts/Sora/static/Sora-Light.ttf +0 -0
  30. package/app/assets/fonts/Sora/static/Sora-Medium.ttf +0 -0
  31. package/app/assets/fonts/Sora/static/Sora-Regular.ttf +0 -0
  32. package/app/assets/fonts/Sora/static/Sora-SemiBold.ttf +0 -0
  33. package/app/assets/fonts/Sora/static/Sora-Thin.ttf +0 -0
  34. package/app/components/AddToWishlist.vue +55 -0
  35. package/app/components/Address/Card.vue +32 -0
  36. package/app/components/Address/Detail.vue +22 -0
  37. package/app/components/Address/Form.vue +117 -0
  38. package/app/components/AnimatedSection.vue +77 -0
  39. package/app/components/BottomNavi.vue +63 -0
  40. package/app/components/Cart/Item.vue +112 -0
  41. package/app/components/Cart/QuickView.vue +55 -0
  42. package/app/components/Category/Header.vue +53 -0
  43. package/app/components/Category/Listing.vue +295 -0
  44. package/app/components/Checkout/DeliveryTimeSelect.vue +177 -0
  45. package/app/components/Checkout/LoginOrRegister.vue +43 -0
  46. package/app/components/Checkout/PaymentAndDelivery.vue +101 -0
  47. package/app/components/Checkout/PaymentMethod.vue +30 -0
  48. package/app/components/Checkout/ShippingMethod.vue +30 -0
  49. package/app/components/Checkout/Summary.vue +125 -0
  50. package/app/components/Cta.vue +34 -0
  51. package/app/components/Features.vue +36 -0
  52. package/app/components/Food/Marquee.vue +35 -0
  53. package/app/components/Food/MarqueeItem.vue +72 -0
  54. package/app/components/Footer.vue +51 -0
  55. package/app/components/Header.vue +160 -0
  56. package/app/components/Hero.vue +77 -0
  57. package/app/components/ImageGallery.vue +46 -0
  58. package/app/components/Loading.vue +29 -0
  59. package/app/components/Navigation/DesktopLeft.vue +51 -0
  60. package/app/components/Navigation/DesktopLeft2.vue +43 -0
  61. package/app/components/Navigation/MobileTop.vue +59 -0
  62. package/app/components/Navigation/MobileTop2.vue +42 -0
  63. package/app/components/Order/Detail.vue +84 -0
  64. package/app/components/Product/Card.vue +132 -0
  65. package/app/components/Product/Category.vue +153 -0
  66. package/app/components/Product/Configurator.vue +65 -0
  67. package/app/components/Product/CrossSelling.vue +95 -0
  68. package/app/components/Product/DeselectIngredient.vue +46 -0
  69. package/app/components/Product/Detail.vue +187 -0
  70. package/app/components/Product/SearchBar.vue +109 -0
  71. package/app/components/PublicAnnouncement.vue +17 -0
  72. package/app/components/Topseller.vue +43 -0
  73. package/app/components/User/Detail.vue +47 -0
  74. package/app/components/User/LoginForm.vue +105 -0
  75. package/app/components/User/RegistrationForm.vue +340 -0
  76. package/app/components/Wishlist.vue +102 -0
  77. package/app/composables/useDeliveryTime.ts +139 -0
  78. package/app/composables/useInterval.ts +15 -0
  79. package/app/composables/usePizzaToppings.ts +31 -0
  80. package/app/composables/useProductEvents.test.ts +111 -0
  81. package/app/composables/useProductEvents.ts +22 -0
  82. package/app/composables/useProductVariants.ts +61 -0
  83. package/app/composables/useScrollAnimation.ts +39 -0
  84. package/app/composables/useTopSellers.ts +34 -0
  85. package/app/error.vue +30 -0
  86. package/app/layouts/account.vue +74 -0
  87. package/app/layouts/default.vue +6 -0
  88. package/app/layouts/listing.vue +32 -0
  89. package/app/layouts/listing2.vue +8 -0
  90. package/app/middleware/trailing-slash.global.ts +19 -0
  91. package/app/pages/account/recover/password/index.vue +143 -0
  92. package/app/pages/anmelden.vue +32 -0
  93. package/app/pages/bestellung.vue +103 -0
  94. package/app/pages/c/[...all].vue +49 -0
  95. package/app/pages/index.vue +59 -0
  96. package/app/pages/konto/adressen.vue +135 -0
  97. package/app/pages/konto/bestellung/[id].vue +41 -0
  98. package/app/pages/konto/bestellungen.vue +53 -0
  99. package/app/pages/konto/index.vue +74 -0
  100. package/app/pages/konto/profil.vue +160 -0
  101. package/app/pages/merkliste.vue +11 -0
  102. package/app/pages/order/[id].vue +69 -0
  103. package/app/pages/passwort-vergessen.vue +103 -0
  104. package/app/pages/registrierung/bestaetigen.vue +44 -0
  105. package/app/pages/registrierung/index.vue +24 -0
  106. package/app/pages/speisekarte.vue +58 -0
  107. package/app/pages/unternehmen/[slug].vue +66 -0
  108. package/app/types/Association.d.ts +11 -0
  109. package/app/utils/businessHours.ts +119 -0
  110. package/app/utils/formatDate.ts +9 -0
  111. package/app/utils/holidays.ts +43 -0
  112. package/app/utils/storeHours.ts +8 -0
  113. package/app/utils/time.ts +20 -0
  114. package/app/validation/addressSchema.ts +34 -0
  115. package/app/validation/registrationSchema.ts +156 -0
  116. package/bun.dockerfile +60 -0
  117. package/compose.yml +17 -0
  118. package/container +7 -0
  119. package/content/index.yml +91 -0
  120. package/content/navigation.yml +67 -0
  121. package/content/unternehmen/agb.md +1 -0
  122. package/content/unternehmen/datenschutz.md +1 -0
  123. package/content/unternehmen/impressum.md +39 -0
  124. package/content.config.ts +134 -0
  125. package/eslint.config.mjs +8 -0
  126. package/node.dockerfile +33 -0
  127. package/nuxt.config.ts +153 -0
  128. package/package.json +70 -0
  129. package/public/dark/Logo.svg +32 -0
  130. package/public/favicon.ico +0 -0
  131. package/public/light/Logo.svg +32 -0
  132. package/renovate.json +4 -0
  133. package/server/tsconfig.json +3 -0
  134. package/shopware.d.ts +19 -0
  135. package/tsconfig.json +4 -0
  136. package/vitest.config.mts +26 -0
@@ -0,0 +1,156 @@
1
+ // schemas/registrationSchema.ts
2
+ import * as z from "zod";
3
+
4
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
5
+ export const createRegistrationSchema = (state: any) =>
6
+ z.object({
7
+ accountType: z.string(),
8
+ email: z.string().email("Invalid email"),
9
+ firstName: z.string().min(1),
10
+ lastName: z.string().min(1),
11
+ guest: z.boolean(),
12
+ password: z
13
+ .string()
14
+ .optional()
15
+ .refine(
16
+ (val) => {
17
+ return state.guest || (val && val.length >= 8);
18
+ },
19
+ {
20
+ message: "Password muss mindestens 8 Zeichen lang sein.",
21
+ },
22
+ ),
23
+ passwordConfirm: z
24
+ .string()
25
+ .optional()
26
+ .refine(
27
+ (val) => {
28
+ return state.guest || val === state.password;
29
+ },
30
+ {
31
+ message: "Password stimmt nicht überein.",
32
+ },
33
+ ),
34
+ billingAddress: z.object({
35
+ firstName: z.string().min(1).optional(),
36
+ lastName: z.string().min(1).optional(),
37
+ company: z
38
+ .string()
39
+ .optional()
40
+ .refine(
41
+ (val) => {
42
+ return (
43
+ state.accountType !== "commercial" ||
44
+ (val !== undefined && val !== "")
45
+ );
46
+ },
47
+ {
48
+ message: "Als Geschäftskunde ist dieses Feld pflicht.",
49
+ },
50
+ ),
51
+ department: z.string().optional(),
52
+ street: z.string().min(1),
53
+ zipcode: z.string().min(1).optional(),
54
+ city: z.string().min(1, {
55
+ message: "Bitte geben Sie den Ort an.",
56
+ }),
57
+ countryId: z.string().min(1),
58
+ phoneNumber: z.string().min(7),
59
+ }),
60
+ shippingAddress: z.object({
61
+ firstName: z
62
+ .string()
63
+ .min(1)
64
+ .optional()
65
+ .refine(
66
+ (val) => {
67
+ return (
68
+ !state.isShippingAddressDifferent ||
69
+ (val !== undefined && val !== "")
70
+ );
71
+ },
72
+ {
73
+ message: "Erforderlich.",
74
+ },
75
+ ),
76
+ lastName: z
77
+ .string()
78
+ .min(1)
79
+ .optional()
80
+ .refine(
81
+ (val) => {
82
+ return (
83
+ !state.isShippingAddressDifferent ||
84
+ (val !== undefined && val !== "")
85
+ );
86
+ },
87
+ {
88
+ message: "Erforderlich.",
89
+ },
90
+ ),
91
+ company: z
92
+ .string()
93
+ .min(1)
94
+ .optional()
95
+ .refine(
96
+ (val) => {
97
+ return (
98
+ !state.isShippingAddressDifferent ||
99
+ (val !== undefined && val !== "")
100
+ );
101
+ },
102
+ {
103
+ message: "Erforderlich.",
104
+ },
105
+ ),
106
+ department: z.string().optional(),
107
+ phoneNumber: z
108
+ .string()
109
+ .optional()
110
+ .refine(
111
+ (val) => {
112
+ return (
113
+ !state.isShippingAddressDifferent ||
114
+ (val !== undefined && val !== "")
115
+ );
116
+ },
117
+ {
118
+ message: "Erforderlich.",
119
+ },
120
+ ),
121
+ street: z
122
+ .string()
123
+ .optional()
124
+ .refine(
125
+ (val) => {
126
+ return (
127
+ !state.isShippingAddressDifferent ||
128
+ (val !== undefined && val !== "")
129
+ );
130
+ },
131
+ {
132
+ message: "Erforderlich.",
133
+ },
134
+ ),
135
+ zipcode: z.string().min(1).optional(),
136
+ city: z
137
+ .string()
138
+ .optional()
139
+ .refine(
140
+ (val) => {
141
+ return (
142
+ !state.isShippingAddressDifferent ||
143
+ (val !== undefined && val !== "")
144
+ );
145
+ },
146
+ {
147
+ message: "Erforderlich.",
148
+ },
149
+ ),
150
+ countryId: z.string().min(1),
151
+ }),
152
+ });
153
+
154
+ export type RegistrationSchema = z.infer<
155
+ ReturnType<typeof createRegistrationSchema>
156
+ >;
package/bun.dockerfile ADDED
@@ -0,0 +1,60 @@
1
+ FROM oven/bun:1-alpine AS build
2
+
3
+ ARG NUXT_PUBLIC_SHOPWARE_ENDPOINT='https://my.shop/store-api'
4
+ ARG NUXT_PUBLIC_SHOPWARE_ACCESS_TOKEN='TOKEN'
5
+
6
+ ENV NUXT_PUBLIC_SHOPWARE_ENDPOINT=${NUXT_PUBLIC_SHOPWARE_ENDPOINT}
7
+ ENV NUXT_PUBLIC_SHOPWARE_ACCESS_TOKEN=${NUXT_PUBLIC_SHOPWARE_ACCESS_TOKEN}
8
+ ENV NODE_ENV=production
9
+ ENV BUN_INSTALL_BIN=/usr/local/bin
10
+
11
+ WORKDIR /app
12
+
13
+ COPY --chown=bun:bun package.json bun.lock ./
14
+
15
+ USER bun
16
+
17
+ COPY package.json bun.lock ./
18
+
19
+ RUN bun install --frozen-lockfile --production --ignore-scripts
20
+
21
+ COPY . .
22
+
23
+ RUN bun run build
24
+
25
+ FROM oven/bun:1-alpine AS dev
26
+
27
+ ENV BUN_INSTALL_BIN=/usr/local/bin
28
+
29
+ WORKDIR /app
30
+
31
+ RUN chown -R bun:bun /app
32
+
33
+ USER bun
34
+
35
+ WORKDIR /app
36
+
37
+ COPY --chown=bun:bun package.json bun.lock ./
38
+
39
+ RUN bun install --frozen-lockfile --ignore-scripts
40
+
41
+ COPY --chown=bun:bun . .
42
+
43
+ EXPOSE 3000
44
+ EXPOSE 24678
45
+
46
+ CMD [ "bun", "run", "dev" ]
47
+
48
+ FROM oven/bun:1-alpine AS production
49
+
50
+ WORKDIR /app
51
+
52
+ COPY --from=build --chown=bun:bun /app/.output /app/.output
53
+
54
+ RUN chown -R bun:bun /app
55
+
56
+ USER bun
57
+
58
+ EXPOSE 3000
59
+
60
+ CMD [ "bun", ".output/server/index.mjs" ]
package/compose.yml ADDED
@@ -0,0 +1,17 @@
1
+ services:
2
+ app:
3
+ build:
4
+ dockerfile: node.dockerfile
5
+ context: .
6
+ args:
7
+ NUXT_PUBLIC_SHOPWARE_ENDPOINT: ${NUXT_PUBLIC_SHOPWARE_ENDPOINT:-https://my.shop/store-api}
8
+ NUXT_PUBLIC_SHOPWARE_ACCESS_TOKEN: ${NUXT_PUBLIC_SHOPWARE_ACCESS_TOKEN:-TOKEN}
9
+ user: node
10
+ env_file:
11
+ - .env
12
+ volumes:
13
+ - ".:/app"
14
+ - "/app/node_modules"
15
+ ports:
16
+ - '3000:3000'
17
+ - '24678:24678'
package/container ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env bash
2
+
3
+ if [ $# = 0 ]; then
4
+ echo "try './container pnpm -v'"
5
+ else
6
+ docker compose exec app "$@"
7
+ fi
@@ -0,0 +1,91 @@
1
+ seo:
2
+ title: ShopBite – Kostenloses Online-Bestellsystem für Gastronomie
3
+ description: Dein eigenes Bestellsystem ohne Provisionen, ohne monatliche Kosten – 100% Open Source und individuell anpassbar. Perfekt für Pizzerien, Imbisse und Lieferdienste.
4
+ title: Pizzeria La Fattoria
5
+ description: Italienisch-deutsche Küche in Obertshausen seit 1997.
6
+ hero:
7
+ backgroundVideo: https://shopware.shopbite.de/media/10/59/96/1762465181/background.mp4
8
+ headline: ALTE SCHMIEDE
9
+ usps:
10
+ - title: 4.5 ⭐
11
+ subtitle: 720+ Reviews
12
+ icon: i-simple-icons-google
13
+ link: https://www.google.com/maps/place/?q=place_id:ChIJJ-6VNfcTvUcR2r7Sax3SN2s
14
+ - title: 28 Jahre
15
+ subtitle: in Obertshausen
16
+ icon: i-lucide-award
17
+ - title: Lieferservice
18
+ subtitle: Schnell & zuverlässig
19
+ icon: i-lucide-bike
20
+ links:
21
+ - label: Speisekarte
22
+ icon: i-lucide-arrow-right
23
+ trailing: true
24
+ color: primary
25
+ to: /speisekarte
26
+ size: xl
27
+ - label: Tisch reservieren
28
+ icon: i-lucide-phone
29
+ size: xl
30
+ color: neutral
31
+ variant: outline
32
+ to: 'tel:+490610474127'
33
+ target: _blank
34
+ features:
35
+ title: Alle [Informationen]{.text-primary} auf einen Blick
36
+ description: Sie können Speisen und Getränke abholen, liefern lassen, oder vor Ort in unserem Restaurant genießen.
37
+ headline: ALTE SCHMIEDE
38
+ features:
39
+ - title: Öffnungszeiten
40
+ description: Von 11:30 - 14:30 und 17:30 - 23:00 Uhr. Samstags von 17:30 - 23:30 Uhr. Dienstag ist Ruhetag.
41
+ icon: i-lucide-clock
42
+ ui:
43
+ leading: bg-accented/50 p-2 rounded-md border border-muted border-dashed
44
+ - title: Lieferung
45
+ description: Wir liefern nach Obertshausen und Lämmerspiel. Ab 15€ liefern wir frei Haus, darunter berechnen wir lediglich 1€. Die Lieferzeit beträgt bei normaler Auslastung ca. 30 min
46
+ icon: i-lucide-truck
47
+ ui:
48
+ leading: bg-accented/50 p-2 rounded-md border border-muted border-dashed
49
+ - title: Reservierungen und Bestellungen
50
+ description: Reservierungen nehmen wir ausschließlich telefonisch entgegen. Bestellungen nehmen wir gerne telefonisch oder online entgegen.
51
+ icon: i-lucide-pizza
52
+ ui:
53
+ leading: bg-accented/50 p-2 rounded-md border border-muted border-dashed
54
+ marquee:
55
+ title: Das lieben unsere Kunden
56
+ description: Kundenbilder
57
+ headline: ALTE SCHMIEDE
58
+ items:
59
+ - productId: 019a4f2e717b7df7a349761a56c43ac3
60
+ image: https://shopware.shopbite.de/media/e4/82/55/1762465420/72.webp
61
+ - productId: 019a4f4552ff7251a1fa20a2e1a3a707
62
+ image: https://shopware.shopbite.de/media/5f/43/cc/1762465330/131.webp
63
+ - productId: 019a4ea153e671c6ba20810b541e1455
64
+ image: https://shopware.shopbite.de/media/f1/53/f9/1762465329/35.webp
65
+ - productId: 019a4ea153e671c6ba20810b541e1455
66
+ image: https://shopware.shopbite.de/media/5f/c7/ec/1762465330/122.webp
67
+ gallery:
68
+ title: Restaurant
69
+ description: Genießen Sie leckeres Essen in einem rustikalen und gemütlichen Ambiente.
70
+ headline: ALTE SCHMIEDE
71
+ links:
72
+ - label: Tisch reservieren
73
+ to: tel:+49610471427
74
+ color: primary
75
+ variant: subtle
76
+ trailingIcon: i-lucide-phone
77
+ images:
78
+ - image: https://shopware.shopbite.de/media/71/2a/1a/1762465670/restaurant1.webp
79
+ alt: La Fattoria Restaurant Innenbereich 1
80
+ - image: https://shopware.shopbite.de/media/61/ea/77/1762465670/restaurant2.webp
81
+ alt: La Fattoria Restaurant Innenbereich 2
82
+ - image: https://shopware.shopbite.de/media/6d/ac/ca/1762465670/restaurant3.webp
83
+ alt: La Fattoria Restaurant Innenbereich 3
84
+ - image: https://shopware.shopbite.de/media/af/d6/da/1762465670/restaurant4.webp
85
+ alt: La Fattoria Restaurant Innenbereich 4
86
+ - image: https://shopware.shopbite.de/media/6a/ff/e2/1762465670/restaurant5.webp
87
+ alt: La Fattoria Restaurant Innenbereich 5
88
+ - image: https://shopware.shopbite.de/media/80/76/d0/1762465670/restaurant6.webp
89
+ alt: La Fattoria Restaurant Innenbereich 6
90
+ - image: https://nbg1.your-objectstorage.com/lafattoria-public/media/30/f7/76/1763383122/restaurant10.webp
91
+ alt: La Fattoria Restaurant Innenbereich 10
@@ -0,0 +1,67 @@
1
+ main:
2
+ - label: Start
3
+ icon: i-lucide-home
4
+ to: /
5
+ - label: Speisekarte
6
+ icon: i-lucide-utensils
7
+ to: /speisekarte
8
+ - label: Speisekarte 2
9
+ icon: i-lucide-utensils
10
+ to: /c/Pizza/
11
+ - label: Routenplaner
12
+ icon: i-lucide-map-pinned
13
+ to: https://www.openstreetmap.org/directions?from=&to=50.080610%2C8.863783#map=19/50.080323/8.864079
14
+ target: _blank
15
+ - label: Merkliste
16
+ icon: i-lucide-book-heart
17
+ to: /merkliste
18
+
19
+ account:
20
+ loggedIn:
21
+ - - label: Mein Konto
22
+ type: label
23
+ - - label: Konto
24
+ icon: i-lucide-user
25
+ to: /konto
26
+ - label: Bestellungen
27
+ icon: i-lucide-pizza
28
+ to: /konto/bestellungen
29
+ - label: Adressen
30
+ icon: i-lucide-house
31
+ to: /konto/adressen
32
+ - - label: Abmelden
33
+ icon: i-lucide-log-out
34
+ action: logout
35
+ loggedOut:
36
+ - - label: Jetzt anmelden
37
+ type: label
38
+ - - label: Zur Anmeldung
39
+ icon: i-lucide-user
40
+ to: /anmelden
41
+
42
+ footer:
43
+ withGithubLink: true
44
+ withColorModeSwitch: true
45
+ text: Alle Preise inkl. gesetzlicher Mehrwertsteuer zzgl. Versandkosten, wenn nicht anders beschrieben
46
+ columns:
47
+ - label: Informationen
48
+ children:
49
+ - label: Impressum
50
+ to: /impressum
51
+ - label: Datenschutz
52
+ to: /datenschutz
53
+ - label: AGB
54
+ to: /agb
55
+ - label: Top Kategorien
56
+ children:
57
+ - label: Pizza
58
+ to: /c/Pizza/
59
+ - label: Nudeln
60
+ to: /c/Nudeln/
61
+ - label: Fleischgerichte
62
+ to: /c/Fleischgerichte/
63
+ - label: Unternehmen
64
+ children:
65
+ - label: 'Tel: 06104 71427'
66
+ - label: Kantstraße 6
67
+ - label: 631679 Oberthsuasen
@@ -0,0 +1 @@
1
+ # AGB
@@ -0,0 +1 @@
1
+ # Datenschutz
@@ -0,0 +1,39 @@
1
+ # Impressum
2
+
3
+ ## Angaben gemäß § 5 TMG
4
+
5
+ Bekim Veliu und Cefajet Veliu GbR
6
+
7
+ Kantstr. 6<br>63179 Obertshausen<br>Deutschland
8
+
9
+ **Vertreten durch:**<br>Bekim Veliu
10
+
11
+ **Kontakt:**<br>Telefon: +49 6104 71427<br>E-Mail: service@pizzeria-lafattoria.de
12
+
13
+ ## Umsatzsteuer-ID
14
+
15
+ Umsatzsteuer-Identifikationsnummer gemäß § 27 a Umsatzsteuergesetz:
16
+
17
+ ## Verantwortlich für den Inhalt nach § 55 Abs. 2 RStV
18
+
19
+ Bekim Veliu<br>Kantstr. 6<br>63179 Obertshausen
20
+
21
+ ## Administrator und technischer Ansprechpartner dieser Seite
22
+
23
+ Lirim Veliu<br>lirim@veliu.net
24
+
25
+ ## Haftungshinweis
26
+
27
+ Trotz sorgfältiger inhaltlicher Kontrolle übernehmen wir keine Haftung für die Inhalte externer Links. Für den Inhalt
28
+ der verlinkten Seiten sind ausschließlich deren Betreiber verantwortlich.
29
+
30
+ ## Streitbeilegung
31
+
32
+ Die Europäische Kommission stellt eine Plattform zur Online-Streitbeilegung (OS) bereit: https://ec.europa.eu/consumers/odr/
33
+ Wir sind nicht bereit oder verpflichtet, an Streitbeilegungsverfahren vor einer Verbraucherschlichtungsstelle teilzunehmen.
34
+
35
+ ## Urheberrecht
36
+
37
+ Die durch die Seitenbetreiber erstellten Inhalte und Werke auf diesen Seiten unterliegen dem deutschen Urheberrecht.
38
+ Die Vervielfältigung, Bearbeitung, Verbreitung und jede Art der Verwertung außerhalb der Grenzen des Urheberrechtes
39
+ bedürfen der schriftlichen Zustimmung des jeweiligen Autors bzw. Erstellers.
@@ -0,0 +1,134 @@
1
+ import { defineCollection, defineContentConfig } from "@nuxt/content";
2
+ import { z } from "zod";
3
+
4
+ const createEnum = (options: [string, ...string[]]) => z.enum(options);
5
+
6
+ const createLinkSchema = () =>
7
+ z.object({
8
+ label: z.string().nonempty(),
9
+ to: z.string().nonempty(),
10
+ icon: z.string().optional().editor({ input: "icon" }),
11
+ size: createEnum(["xs", "sm", "md", "lg", "xl"]),
12
+ trailing: z.boolean().optional(),
13
+ target: createEnum(["_blank", "_self"]),
14
+ color: createEnum([
15
+ "primary",
16
+ "secondary",
17
+ "neutral",
18
+ "error",
19
+ "warning",
20
+ "success",
21
+ "info",
22
+ ]),
23
+ variant: createEnum([
24
+ "solid",
25
+ "outline",
26
+ "subtle",
27
+ "soft",
28
+ "ghost",
29
+ "link",
30
+ ]),
31
+ });
32
+
33
+ const createBaseSchema = () =>
34
+ z.object({
35
+ title: z.string().nonempty(),
36
+ description: z.string().nonempty(),
37
+ headline: z.string().optional(),
38
+ });
39
+
40
+ const createFeatureSchema = () =>
41
+ createBaseSchema().extend({
42
+ icon: z.string().editor({ input: "icon" }),
43
+ ui: z
44
+ .object({
45
+ leading: z.string().optional(),
46
+ })
47
+ .editor({ hidden: true }),
48
+ });
49
+
50
+ const createNavigationItemSchema = () =>
51
+ z.object({
52
+ label: z.string().nonempty(),
53
+ icon: z.string().optional().editor({ input: "icon" }),
54
+ to: z.string().nonempty(),
55
+ target: createEnum(["_blank", "_self"]),
56
+ type: createEnum(["label", "item"]).optional(),
57
+ action: z.string().optional(),
58
+ });
59
+
60
+ const createFooterColumnSchema = () =>
61
+ z.object({
62
+ label: z.string().nonempty(),
63
+ children: z.array(
64
+ z.object({
65
+ label: z.string().nonempty(),
66
+ to: z.string().optional(),
67
+ }),
68
+ ),
69
+ });
70
+
71
+ export default defineContentConfig({
72
+ collections: {
73
+ home: defineCollection({
74
+ source: "index.yml",
75
+ type: "page",
76
+ schema: z.object({
77
+ hero: z.object({
78
+ backgroundVideo: z.string().optional(),
79
+ headline: z.string().optional(),
80
+ links: z.array(createLinkSchema()),
81
+ usps: z.array(
82
+ z.object({
83
+ title: z.string().optional(),
84
+ subtitle: z.string().optional(),
85
+ icon: z.string().optional(),
86
+ link: z.string().optional(),
87
+ }),
88
+ ),
89
+ }),
90
+ features: createBaseSchema().extend({
91
+ features: z.array(createFeatureSchema()),
92
+ }),
93
+ marquee: createBaseSchema().extend({
94
+ items: z.array(
95
+ z.object({
96
+ image: z.string().nonempty(),
97
+ productId: z.string().nonempty(),
98
+ }),
99
+ ),
100
+ }),
101
+ gallery: createBaseSchema().extend({
102
+ images: z.array(
103
+ z.object({
104
+ image: z.string().nonempty(),
105
+ alt: z.string().nonempty(),
106
+ }),
107
+ ),
108
+ links: z.array(createLinkSchema()),
109
+ }),
110
+ }),
111
+ }),
112
+ navigation: defineCollection({
113
+ source: "navigation.yml",
114
+ type: "page",
115
+ schema: z.object({
116
+ main: z.array(createNavigationItemSchema()),
117
+ account: z.object({
118
+ loggedIn: z.array(z.array(createNavigationItemSchema())),
119
+ loggedOut: z.array(z.array(createNavigationItemSchema())),
120
+ }),
121
+ footer: z.object({
122
+ withGithubLink: z.boolean(),
123
+ withColorModeSwitch: z.boolean(),
124
+ text: z.string().optional(),
125
+ columns: z.array(createFooterColumnSchema()),
126
+ }),
127
+ }),
128
+ }),
129
+ unternehmen: defineCollection({
130
+ source: "unternehmen/*.md",
131
+ type: "page",
132
+ }),
133
+ },
134
+ });
@@ -0,0 +1,8 @@
1
+ // @ts-check
2
+ import withNuxt from './.nuxt/eslint.config.mjs'
3
+
4
+ export default withNuxt({
5
+ rules: {
6
+ 'vue/multi-word-component-names': 'off'
7
+ }
8
+ })
@@ -0,0 +1,33 @@
1
+ FROM node:24-alpine AS build
2
+
3
+ ARG PNPM_VERSION=10.20.0
4
+ ARG NUXT_PUBLIC_SHOPWARE_ENDPOINT='https://my.shop/store-api'
5
+ ARG NUXT_PUBLIC_SHOPWARE_ACCESS_TOKEN='TOKEN'
6
+
7
+ ENV PNPM_VERSION=${PNPM_VERSION}
8
+ ENV NUXT_PUBLIC_SHOPWARE_ENDPOINT=${NUXT_PUBLIC_SHOPWARE_ENDPOINT}
9
+ ENV NUXT_PUBLIC_SHOPWARE_ACCESS_TOKEN=${NUXT_PUBLIC_SHOPWARE_ACCESS_TOKEN}
10
+ ENV NODE_ENV=production
11
+ ENV NODE_OPTIONS="--max-old-space-size=4096"
12
+
13
+ WORKDIR /app
14
+
15
+ RUN npm install -g pnpm@${PNPM_VERSION}
16
+
17
+ COPY . .
18
+
19
+ RUN pnpm install --frozen-lockfile --prefer-offline --production
20
+
21
+ RUN pnpm build
22
+
23
+ FROM node:24-alpine AS production
24
+
25
+ WORKDIR /app
26
+
27
+ ENV NODE_ENV=production
28
+
29
+ COPY --from=build /app/.output /app/.output
30
+
31
+ EXPOSE 3000
32
+
33
+ CMD [ "node", ".output/server/index.mjs" ]