img:first-child]:pt-0 data-[size=sm]:[--card-spacing:--spacing(4)] dark:ring-foreground/10 *:[img:first-child]:rounded-t-4xl *:[img:last-child]:rounded-b-4xl",
+ className
+ )}
+ {...props}
+ />
+ )
+}
+
+function CardHeader({ className, ...props }: React.ComponentProps<"div">) {
+ return (
+
+ )
+}
+
+function CardTitle({ className, ...props }: React.ComponentProps<"div">) {
+ return (
+
+ )
+}
+
+function CardDescription({ className, ...props }: React.ComponentProps<"div">) {
+ return (
+
+ )
+}
+
+function CardAction({ className, ...props }: React.ComponentProps<"div">) {
+ return (
+
+ )
+}
+
+function CardContent({ className, ...props }: React.ComponentProps<"div">) {
+ return (
+
+ )
+}
+
+function CardFooter({ className, ...props }: React.ComponentProps<"div">) {
+ return (
+
+ )
+}
+
+export {
+ Card,
+ CardHeader,
+ CardFooter,
+ CardTitle,
+ CardAction,
+ CardDescription,
+ CardContent,
+}
diff --git a/frontend-starter/lib/ai/model.ts b/frontend-starter/lib/ai/model.ts
deleted file mode 100644
index 7427a2d..0000000
--- a/frontend-starter/lib/ai/model.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-// Muster C: Provider und Modell an einer Stelle.
-// Der Standard-Provider liest ANTHROPIC_API_KEY aus der Umgebung.
-import { anthropic } from "@ai-sdk/anthropic";
-
-// Ein günstiges Modell, weil jeder Aufruf Geld kostet (Claude Sonnet 5: 2 $ Input / 10 $ Output pro 1 Mio. Tokens).
-export const getModel = () => anthropic("claude-sonnet-5");
diff --git a/frontend-starter/lib/n8n.ts b/frontend-starter/lib/n8n.ts
deleted file mode 100644
index edf72c5..0000000
--- a/frontend-starter/lib/n8n.ts
+++ /dev/null
@@ -1,30 +0,0 @@
-// Muster A: n8n-Webhook aus dem Frontend aufrufen.
-// Die Basis-Adresse wird beim Bauen eingesetzt (NEXT_PUBLIC_*). Ohne Angabe gilt die E&P-n8n.
-
-const BASE = (process.env.NEXT_PUBLIC_N8N_BASE || "https://n8n.ep-reisen.app").replace(/\/+$/, "");
-
-export function webhookUrl(path: string): string {
- const clean = path.replace(/^\/+/, "");
- return `${BASE}/webhook/${clean}`;
-}
-
-export async function postWebhook
(
- path: string,
- body: unknown,
-): Promise {
- const res = await fetch(webhookUrl(path), {
- method: "POST",
- headers: { "Content-Type": "application/json" },
- body: JSON.stringify(body),
- });
- if (!res.ok) {
- throw new Error(`Webhook-Fehler ${res.status}: ${await res.text()}`);
- }
- // n8n kann JSON oder Text zurückgeben:
- const text = await res.text();
- try {
- return JSON.parse(text) as T;
- } catch {
- return text as T;
- }
-}
diff --git a/frontend-starter/lib/utils.ts b/frontend-starter/lib/utils.ts
index f815ded..bd0c391 100644
--- a/frontend-starter/lib/utils.ts
+++ b/frontend-starter/lib/utils.ts
@@ -1 +1,6 @@
-export { cn } from "cn"
+import { clsx, type ClassValue } from "clsx"
+import { twMerge } from "tailwind-merge"
+
+export function cn(...inputs: ClassValue[]) {
+ return twMerge(clsx(inputs))
+}
diff --git a/frontend-starter/next-env.d.ts b/frontend-starter/next-env.d.ts
index 9edff1c..c4b7818 100644
--- a/frontend-starter/next-env.d.ts
+++ b/frontend-starter/next-env.d.ts
@@ -1,6 +1,6 @@
///
///
-import "./.next/types/routes.d.ts";
+import "./.next/dev/types/routes.d.ts";
// NOTE: This file should not be edited
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
diff --git a/frontend-starter/package-lock.json b/frontend-starter/package-lock.json
index b13ff4d..9dade2f 100644
--- a/frontend-starter/package-lock.json
+++ b/frontend-starter/package-lock.json
@@ -8,17 +8,15 @@
"name": "frontend-starter",
"version": "0.1.0",
"dependencies": {
- "@ai-sdk/anthropic": "^3.0.0",
- "@ai-sdk/react": "^3.0.0",
"@base-ui/react": "^1.9.0",
- "ai": "^6.0.0",
"class-variance-authority": "^0.7.1",
- "cn": "^0.5.0",
+ "clsx": "^2.1.1",
"lucide-react": "^1.63.0",
"next": "^16.2.0",
"react": "^19.2.0",
"react-dom": "^19.2.0",
"shadcn": "^4.23.0",
+ "tailwind-merge": "^3.7.0",
"tw-animate-css": "^1.4.0"
},
"devDependencies": {
@@ -30,86 +28,6 @@
"typescript": "^5.9.0"
}
},
- "node_modules/@ai-sdk/anthropic": {
- "version": "3.0.81",
- "resolved": "https://registry.npmjs.org/@ai-sdk/anthropic/-/anthropic-3.0.81.tgz",
- "integrity": "sha512-B1JDd9Ugq9R5AgIaW3674lhGCMMYJcPUxnrZh8fzbGojgg4QvHFRv6eZahGQAUsmGHbcf74G9bdSBDLWQGY2GA==",
- "license": "Apache-2.0",
- "dependencies": {
- "@ai-sdk/provider": "3.0.10",
- "@ai-sdk/provider-utils": "4.0.27"
- },
- "engines": {
- "node": ">=18"
- },
- "peerDependencies": {
- "zod": "^3.25.76 || ^4.1.8"
- }
- },
- "node_modules/@ai-sdk/gateway": {
- "version": "3.0.124",
- "resolved": "https://registry.npmjs.org/@ai-sdk/gateway/-/gateway-3.0.124.tgz",
- "integrity": "sha512-h8CrmbSG+8X0C+M/E1M4oiDHYevqwbzAPN+uLRHS0eJaatF2MZ+juNtOHXNOjk7Bsk9mD2RjYMjJO9dFkb9I7Q==",
- "license": "Apache-2.0",
- "dependencies": {
- "@ai-sdk/provider": "3.0.10",
- "@ai-sdk/provider-utils": "4.0.27",
- "@vercel/oidc": "3.2.0"
- },
- "engines": {
- "node": ">=18"
- },
- "peerDependencies": {
- "zod": "^3.25.76 || ^4.1.8"
- }
- },
- "node_modules/@ai-sdk/provider": {
- "version": "3.0.10",
- "resolved": "https://registry.npmjs.org/@ai-sdk/provider/-/provider-3.0.10.tgz",
- "integrity": "sha512-Q3BZ27qfpYqnCYGvE3vt+Qi6LGOF9R5Nmzn+9JoM1lCRsD9mYaIhfJLkSunN48nfGXJ6n+XNV0J/XVpqGQl7Dw==",
- "license": "Apache-2.0",
- "dependencies": {
- "json-schema": "^0.4.0"
- },
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@ai-sdk/provider-utils": {
- "version": "4.0.27",
- "resolved": "https://registry.npmjs.org/@ai-sdk/provider-utils/-/provider-utils-4.0.27.tgz",
- "integrity": "sha512-ubkAJ+xODouwtmN1tYlvTPphH1hPOBfZaEQe8U7skGvFAnIRs9PPpsq57bC2+Ky/MB4yzhd6YOsxTAx9sGpazw==",
- "license": "Apache-2.0",
- "dependencies": {
- "@ai-sdk/provider": "3.0.10",
- "@standard-schema/spec": "^1.1.0",
- "eventsource-parser": "^3.0.8"
- },
- "engines": {
- "node": ">=18"
- },
- "peerDependencies": {
- "zod": "^3.25.76 || ^4.1.8"
- }
- },
- "node_modules/@ai-sdk/react": {
- "version": "3.0.198",
- "resolved": "https://registry.npmjs.org/@ai-sdk/react/-/react-3.0.198.tgz",
- "integrity": "sha512-ozlxMidzvKXAefvnq95Y34rJ5MipXABIv1bg2RLEnWUBxGrKxNHrYl0fTfi6grTN88wSXMZYaMY2oHMCHDFuJw==",
- "license": "Apache-2.0",
- "dependencies": {
- "@ai-sdk/provider-utils": "4.0.27",
- "ai": "6.0.196",
- "swr": "^2.2.5",
- "throttleit": "2.1.0"
- },
- "engines": {
- "node": ">=18"
- },
- "peerDependencies": {
- "react": "^18 || ~19.0.1 || ~19.1.2 || ^19.2.1"
- }
- },
"node_modules/@alloc/quick-lru": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz",
@@ -1503,6 +1421,8 @@
"resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.1.tgz",
"integrity": "sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q==",
"license": "Apache-2.0",
+ "optional": true,
+ "peer": true,
"engines": {
"node": ">=8.0.0"
}
@@ -1567,12 +1487,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/@standard-schema/spec": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz",
- "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==",
- "license": "MIT"
- },
"node_modules/@swc/helpers": {
"version": "0.5.15",
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz",
@@ -1898,33 +1812,6 @@
"resolved": "https://registry.npmjs.org/@types/validate-npm-package-name/-/validate-npm-package-name-4.0.2.tgz",
"integrity": "sha512-lrpDziQipxCEeK5kWxvljWYhUvOiB2A9izZd9B2AFarYAkqZshb4lPbRs7zKEic6eGtH8V/2qJW+dPp9OtF6bw=="
},
- "node_modules/@vercel/oidc": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/@vercel/oidc/-/oidc-3.2.0.tgz",
- "integrity": "sha512-UycprH3T6n3jH0k44NHMa7pnFHGu/N05MjojYr+Mc6I7obkoLIJujSWwin1pCvdy/eOxrI/l3uDLQsmcrOb4ug==",
- "license": "Apache-2.0",
- "engines": {
- "node": ">= 20"
- }
- },
- "node_modules/ai": {
- "version": "6.0.196",
- "resolved": "https://registry.npmjs.org/ai/-/ai-6.0.196.tgz",
- "integrity": "sha512-2T45UeqKL4a11KQ14I5i1YYHOvCFrMF478E1k6PVjlQSGUvXSv4xrxIaQbUL4qgv91DADSbddwv3oR49pPAK3g==",
- "license": "Apache-2.0",
- "dependencies": {
- "@ai-sdk/gateway": "3.0.124",
- "@ai-sdk/provider": "3.0.10",
- "@ai-sdk/provider-utils": "4.0.27",
- "@opentelemetry/api": "^1.9.0"
- },
- "engines": {
- "node": ">=18"
- },
- "peerDependencies": {
- "zod": "^3.25.76 || ^4.1.8"
- }
- },
"node_modules/ajv": {
"version": "8.20.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz",
@@ -2154,21 +2041,11 @@
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
"integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==",
+ "license": "MIT",
"engines": {
"node": ">=6"
}
},
- "node_modules/cn": {
- "version": "0.5.0",
- "resolved": "https://registry.npmjs.org/cn/-/cn-0.5.0.tgz",
- "integrity": "sha512-JGEixZEpfFXm1P5uXwvEobOFLlHwIWi5v4tjd1ZwfiYmcEilkuD2l+054rvJcYCR1B+uVThHeUbgmNz1FwuxuA==",
- "bin": {
- "cn": "bin/cn.mjs"
- },
- "engines": {
- "node": ">=22"
- }
- },
"node_modules/code-block-writer": {
"version": "13.0.3",
"resolved": "https://registry.npmjs.org/code-block-writer/-/code-block-writer-13.0.3.tgz",
@@ -2348,15 +2225,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/dequal": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
- "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==",
- "license": "MIT",
- "engines": {
- "node": ">=6"
- }
- },
"node_modules/detect-libc": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
@@ -2464,15 +2332,6 @@
"node": ">=4"
}
},
- "node_modules/eventsource-parser": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.1.0.tgz",
- "integrity": "sha512-kJezFj9YFAMLeORyi7aCLxLbD5/qWMQnoMVlVPyHIll7lgRJCc3JVln9Vgl9nwQi0YkMnhdGTMNn7CkRRAptMg==",
- "license": "MIT",
- "engines": {
- "node": ">=18.0.0"
- }
- },
"node_modules/execa": {
"version": "9.6.1",
"resolved": "https://registry.npmjs.org/execa/-/execa-9.6.1.tgz",
@@ -2877,12 +2736,6 @@
"node": ">=6"
}
},
- "node_modules/json-schema": {
- "version": "0.4.0",
- "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz",
- "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==",
- "license": "(AFL-2.1 OR BSD-3-Clause)"
- },
"node_modules/json-schema-traverse": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
@@ -4204,19 +4057,6 @@
}
}
},
- "node_modules/swr": {
- "version": "2.4.1",
- "resolved": "https://registry.npmjs.org/swr/-/swr-2.4.1.tgz",
- "integrity": "sha512-2CC6CiKQtEwaEeNiqWTAw9PGykW8SR5zZX8MZk6TeAvEAnVS7Visz8WzphqgtQ8v2xz/4Q5K+j+SeMaKXeeQIA==",
- "license": "MIT",
- "dependencies": {
- "dequal": "^2.0.3",
- "use-sync-external-store": "^1.6.0"
- },
- "peerDependencies": {
- "react": "^16.11.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
- }
- },
"node_modules/systeminformation": {
"version": "5.33.18",
"resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-5.33.18.tgz",
@@ -4242,6 +4082,16 @@
"url": "https://www.buymeacoffee.com/systeminfo"
}
},
+ "node_modules/tailwind-merge": {
+ "version": "3.7.0",
+ "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.7.0.tgz",
+ "integrity": "sha512-XPPUyAc+cvspz3lHTcR/QgPfW2A0lv/xQNIjX3HGhLR+Nq2lHaLq5MtTesHn8GUr3W3DguT2KT5x3NVgRtYwmA==",
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/dcastil"
+ }
+ },
"node_modules/tailwindcss": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.3.0.tgz",
@@ -4263,18 +4113,6 @@
"url": "https://opencollective.com/webpack"
}
},
- "node_modules/throttleit": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-2.1.0.tgz",
- "integrity": "sha512-nt6AMGKW1p/70DF/hGBdJB57B8Tspmbp5gfJ8ilhLnt7kkr2ye7hzD6NVG8GGErk2HWF34igrL2CXmNIkzKqKw==",
- "license": "MIT",
- "engines": {
- "node": ">=18"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
"node_modules/tiny-invariant": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz",
diff --git a/frontend-starter/package.json b/frontend-starter/package.json
index 27ad6ac..3bd47ac 100644
--- a/frontend-starter/package.json
+++ b/frontend-starter/package.json
@@ -8,17 +8,15 @@
"start": "next start -p 3000"
},
"dependencies": {
- "@ai-sdk/anthropic": "^3.0.0",
- "@ai-sdk/react": "^3.0.0",
"@base-ui/react": "^1.9.0",
- "ai": "^6.0.0",
"class-variance-authority": "^0.7.1",
- "cn": "^0.5.0",
+ "clsx": "^2.1.1",
"lucide-react": "^1.63.0",
"next": "^16.2.0",
"react": "^19.2.0",
"react-dom": "^19.2.0",
"shadcn": "^4.23.0",
+ "tailwind-merge": "^3.7.0",
"tw-animate-css": "^1.4.0"
},
"devDependencies": {
@@ -29,4 +27,4 @@
"tailwindcss": "^4.3.0",
"typescript": "^5.9.0"
}
-}
\ No newline at end of file
+}