From 3bb043821528a52ae1dab9997cd843a4911951bb Mon Sep 17 00:00:00 2001 From: Mathias Hurler Date: Thu, 10 Sep 2026 16:51:09 +0200 Subject: [PATCH] =?UTF-8?q?=20Revision=20vor=20Kunden=C3=BCbergabe:=20Plau?= =?UTF-8?q?sibilit=C3=A4t,=20SEO,=20A11y,=20OpenPanel?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 726 +++++--------------------------- package.json | 10 +- public/robots.txt | 8 + public/sitemap.xml | 23 + src/components/analytics.tsx | 10 + src/components/footer.tsx | 35 +- src/components/header.tsx | 55 ++- src/components/hero.tsx | 92 ++-- src/components/pricing.tsx | 296 ++++++++++++- src/components/public-shell.tsx | 21 + src/dev-component/Devtool.tsx | 1 + src/openpanel.ts | 20 + src/routes/__root.tsx | 69 ++- src/routes/_admin.tsx | 3 + src/routes/_authenticated.tsx | 3 + src/routes/datenschutz.tsx | 116 ++++- src/routes/impressum.tsx | 25 +- src/routes/index.tsx | 65 ++- src/routes/login.tsx | 6 + src/routes/termin.tsx | 13 +- src/styles.css | 38 +- 21 files changed, 839 insertions(+), 796 deletions(-) create mode 100644 public/robots.txt create mode 100644 public/sitemap.xml create mode 100644 src/components/analytics.tsx create mode 100644 src/components/public-shell.tsx create mode 100644 src/openpanel.ts diff --git a/package-lock.json b/package-lock.json index 1257064..69c7b3b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,8 +9,7 @@ "@calcom/embed-react": "^1.5.3", "@fontsource-variable/nunito-sans": "^5.3.0", "@fontsource-variable/public-sans": "^5.3.0", - "@react-three/drei": "^10.7.8", - "@react-three/fiber": "^9.7.0", + "@openpanel/web": "^1.4.1", "@tailwindcss/vite": "^4.1.18", "@tanstack/react-devtools": "latest", "@tanstack/react-router": "latest", @@ -19,7 +18,6 @@ "better-auth": "^1.5.3", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", - "drizzle-kit": "^0.31.10", "drizzle-orm": "^0.45.1", "lucide-react": "^0.577.0", "nitro": "3.0.260610-beta", @@ -30,7 +28,6 @@ "shadcn": "^4.19.0", "tailwind-merge": "^3.0.2", "tailwindcss": "^4.1.18", - "three": "^0.185.1", "tsx": "^4.21.0", "tw-animate-css": "^1.3.6" }, @@ -47,6 +44,7 @@ "@vitejs/plugin-react": "^6.0.1", "babel-plugin-react-compiler": "^1.0.0", "dotenv": "^17.3.1", + "drizzle-kit": "^0.31.10", "typescript": "^6.0.2", "vite": "^8.0.0" } @@ -420,15 +418,6 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/runtime": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.7.tgz", - "integrity": "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/template": { "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", @@ -811,12 +800,6 @@ "@calcom/embed-core": "1.5.3" } }, - "node_modules/@dimforge/rapier3d-compat": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/@dimforge/rapier3d-compat/-/rapier3d-compat-0.12.0.tgz", - "integrity": "sha512-uekIGetywIgopfD97oDL5PfeezkFpNhwlzlaEYNOA0N6ghdsOvh/HYjSMek5Q2O1PYvRSDFcqFVJl4r4ZBwOow==", - "license": "Apache-2.0" - }, "node_modules/@dotenvx/dotenvx": { "version": "1.75.1", "resolved": "https://registry.npmjs.org/@dotenvx/dotenvx/-/dotenvx-1.75.1.tgz", @@ -1026,6 +1009,7 @@ "version": "0.10.2", "resolved": "https://registry.npmjs.org/@drizzle-team/brocli/-/brocli-0.10.2.tgz", "integrity": "sha512-z33Il7l5dKjUgGULTqBsQBQwckHh5AbIuxhdsIxDDiZAzBOrZO6q9ogcWC65kU382AfynTfgNumVcNIjuIua6w==", + "devOptional": true, "license": "Apache-2.0" }, "node_modules/@emnapi/core": { @@ -1064,6 +1048,7 @@ "resolved": "https://registry.npmjs.org/@esbuild-kit/core-utils/-/core-utils-3.3.2.tgz", "integrity": "sha512-sPRAnw9CdSsRmEtnsl2WXWdyquogVpB3yZ3dgwJfe8zrOzTsV7cJvmwrKVa+0ma5BoiGJ+BoqkMvawbayKUsqQ==", "deprecated": "Merged into tsx: https://tsx.hirok.io", + "devOptional": true, "license": "MIT", "dependencies": { "esbuild": "~0.18.20", @@ -1426,6 +1411,7 @@ "version": "0.18.20", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz", "integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==", + "devOptional": true, "hasInstallScript": true, "license": "MIT", "bin": { @@ -1464,6 +1450,7 @@ "resolved": "https://registry.npmjs.org/@esbuild-kit/esm-loader/-/esm-loader-2.6.5.tgz", "integrity": "sha512-FxEMIkJKnodyA1OaCUoEvbYRkoZlLZ4d/eXFu9Fh8CbBBgP5EmZxrfTRyN0qpXZ4vOvqnE5YdRdcrmUUXuU+dA==", "deprecated": "Merged into tsx: https://tsx.hirok.io", + "devOptional": true, "license": "MIT", "dependencies": { "@esbuild-kit/core-utils": "^3.3.2", @@ -1999,12 +1986,6 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@mediapipe/tasks-vision": { - "version": "0.10.17", - "resolved": "https://registry.npmjs.org/@mediapipe/tasks-vision/-/tasks-vision-0.10.17.tgz", - "integrity": "sha512-CZWV/q6TTe8ta61cZXjfnnHsfWIdFhms03M9T7Cnd5y2mdpylJM0rF1qRq+wsQVRMLz1OYPVEBU9ph2Bx8cxrg==", - "license": "Apache-2.0" - }, "node_modules/@modelcontextprotocol/sdk": { "version": "1.30.0", "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.30.0.tgz", @@ -2045,18 +2026,6 @@ } } }, - "node_modules/@monogrid/gainmap-js": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/@monogrid/gainmap-js/-/gainmap-js-3.4.0.tgz", - "integrity": "sha512-2Z0FATFHaoYJ8b+Y4y4Hgfn3FRFwuU5zRrk+9dFWp4uGAdHGqVEdP7HP+gLA3X469KXHmfupJaUbKo1b/aDKIg==", - "license": "MIT", - "dependencies": { - "promise-worker-transferable": "^1.0.4" - }, - "peerDependencies": { - "three": ">= 0.159.0" - } - }, "node_modules/@napi-rs/wasm-runtime": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.2.3.tgz", @@ -2201,6 +2170,23 @@ "node": ">=20.0" } }, + "node_modules/@openpanel/sdk": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@openpanel/sdk/-/sdk-1.3.1.tgz", + "integrity": "sha512-mQ5xaBUGXnyRg3qYxwnbVaUYyW7w8u+munrWk/ClnqxEeR2j+FYPiA6noHbHMCFC2aZutYD5OoRzEvw3FBNFxw==", + "license": "MIT" + }, + "node_modules/@openpanel/web": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@openpanel/web/-/web-1.4.1.tgz", + "integrity": "sha512-DgUWeocZw+b57YiJjefZPg+6sceR7TdOF8x7Ut75lu3CwcwqGi5jZNPXjikNemGL37aNWXCB4buhcoNan2j7RA==", + "license": "MIT", + "dependencies": { + "@openpanel/sdk": "1.3.1", + "@rrweb/types": "2.0.0-alpha.20", + "rrweb": "2.0.0-alpha.20" + } + }, "node_modules/@opentelemetry/semantic-conventions": { "version": "1.43.0", "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.43.0.tgz", @@ -4080,94 +4066,6 @@ "integrity": "sha512-JtyZR+mqgBibTo8xea3B6ZRmzZiM/YeVBtUkas6zMuXjAlfIFIW2FgqeM9eLyvEaYX66vr6DJMK+4U6LV0KhNw==", "license": "MIT" }, - "node_modules/@react-three/drei": { - "version": "10.7.8", - "resolved": "https://registry.npmjs.org/@react-three/drei/-/drei-10.7.8.tgz", - "integrity": "sha512-rJXyuzLm2Xq0kafHuR47ajDGbOe/pEhzIr4m8E8zwzQs0iNjloFDqBwRhrXmP/w+onLeYyN3EYPFW/cwWK/4yA==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.26.0", - "@mediapipe/tasks-vision": "0.10.17", - "@monogrid/gainmap-js": "^3.0.6", - "@use-gesture/react": "^10.3.1", - "camera-controls": "^3.1.0", - "cross-env": "^7.0.3", - "detect-gpu": "^5.0.56", - "glsl-noise": "^0.0.0", - "hls.js": "^1.5.17", - "maath": "^0.10.8", - "meshline": "^3.3.1", - "stats-gl": "^2.2.8", - "stats.js": "^0.17.0", - "suspend-react": "^0.1.3", - "three-mesh-bvh": "^0.8.3", - "three-stdlib": "^2.35.6", - "troika-three-text": "^0.52.4", - "tunnel-rat": "^0.1.2", - "use-sync-external-store": "^1.4.0", - "utility-types": "^3.11.0", - "zustand": "^5.0.1" - }, - "peerDependencies": { - "@react-three/fiber": "^9.0.0", - "react": "^19", - "react-dom": "^19", - "three": ">=0.159" - }, - "peerDependenciesMeta": { - "react-dom": { - "optional": true - } - } - }, - "node_modules/@react-three/fiber": { - "version": "9.7.0", - "resolved": "https://registry.npmjs.org/@react-three/fiber/-/fiber-9.7.0.tgz", - "integrity": "sha512-EWm9FwcaOZQu/ExFW5rggoCMM1NJet5YbxVxKaOE+KSncrjU0Wx7017qSyGFvupviK89nMYGCWU3BIK4dI1clw==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.17.8", - "@types/webxr": "*", - "base64-js": "^1.5.1", - "buffer": "^6.0.3", - "its-fine": "^2.0.0", - "react-use-measure": "^2.1.7", - "scheduler": "^0.27.0", - "suspend-react": "^0.1.3", - "use-sync-external-store": "^1.4.0", - "zustand": "^5.0.3" - }, - "peerDependencies": { - "expo": ">=43.0", - "expo-asset": ">=8.4", - "expo-file-system": ">=11.0", - "expo-gl": ">=11.0", - "react": ">=19 <19.3", - "react-dom": ">=19 <19.3", - "react-native": ">=0.78", - "three": ">=0.156" - }, - "peerDependenciesMeta": { - "expo": { - "optional": true - }, - "expo-asset": { - "optional": true - }, - "expo-file-system": { - "optional": true - }, - "expo-gl": { - "optional": true - }, - "react-dom": { - "optional": true - }, - "react-native": { - "optional": true - } - } - }, "node_modules/@rolldown/binding-android-arm-eabi": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm-eabi/-/binding-android-arm-eabi-1.2.5.tgz", @@ -4463,6 +4361,18 @@ "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", "license": "MIT" }, + "node_modules/@rrweb/types": { + "version": "2.0.0-alpha.20", + "resolved": "https://registry.npmjs.org/@rrweb/types/-/types-2.0.0-alpha.20.tgz", + "integrity": "sha512-RbnDgKxA/odwB1R4gF7eUUj+rdSrq6ROQJsnMw7MIsGzlbSYvJeZN8YY4XqU0G6sKJvXI6bSzk7w/G94jNwzhw==", + "license": "MIT" + }, + "node_modules/@rrweb/utils": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@rrweb/utils/-/utils-2.1.4.tgz", + "integrity": "sha512-MSsJflObnJDwtSe9LPrwevf56xi4sVaranlpgXUhooQUf07/Dm8bs/55LETHzDxCjAzkyTgcpm8nOLS72RWNKw==", + "license": "MIT" + }, "node_modules/@sec-ant/readable-stream": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/@sec-ant/readable-stream/-/readable-stream-0.4.1.tgz", @@ -5549,12 +5459,6 @@ "path-browserify": "^1.0.1" } }, - "node_modules/@tweenjs/tween.js": { - "version": "23.1.3", - "resolved": "https://registry.npmjs.org/@tweenjs/tween.js/-/tween.js-23.1.3.tgz", - "integrity": "sha512-vJmvvwFxYuGnF2axRtPYocag6Clbb5YS7kLL+SO/TeVFzHqDIWrNKYtcsPMibjDx9O+bu+psAy9NKfWklassUA==", - "license": "MIT" - }, "node_modules/@tybys/wasm-util": { "version": "0.10.3", "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.3.tgz", @@ -5565,10 +5469,10 @@ "tslib": "^2.4.0" } }, - "node_modules/@types/draco3d": { - "version": "1.4.10", - "resolved": "https://registry.npmjs.org/@types/draco3d/-/draco3d-1.4.10.tgz", - "integrity": "sha512-AX22jp8Y7wwaBgAixaSvkoG4M/+PlAcm3Qs4OW8yT9DM4xUpWKeFhLueTAyZF39pviAdcDdeJoACapiAceqNcw==", + "node_modules/@types/css-font-loading-module": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/@types/css-font-loading-module/-/css-font-loading-module-0.0.7.tgz", + "integrity": "sha512-nl09VhutdjINdWyXxHWN/w9zlNCfr60JUqJbd24YXUuCwgeL0TpFSdElCwb6cxfB6ybE19Gjj4g0jsgkXxKv1Q==", "license": "MIT" }, "node_modules/@types/node": { @@ -5581,12 +5485,6 @@ "undici-types": "~6.21.0" } }, - "node_modules/@types/offscreencanvas": { - "version": "2019.7.3", - "resolved": "https://registry.npmjs.org/@types/offscreencanvas/-/offscreencanvas-2019.7.3.tgz", - "integrity": "sha512-ieXiYmgSRXUDeOntE1InxjWyvEelZGP63M+cGuquuRLuIKKT1osnkXjxev9B7d1nXSug5vpunx+gNlbVxMlC9A==", - "license": "MIT" - }, "node_modules/@types/pg": { "version": "8.23.1", "resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.23.1.tgz", @@ -5617,65 +5515,12 @@ "@types/react": "^19.2.0" } }, - "node_modules/@types/react-reconciler": { - "version": "0.28.9", - "resolved": "https://registry.npmjs.org/@types/react-reconciler/-/react-reconciler-0.28.9.tgz", - "integrity": "sha512-HHM3nxyUZ3zAylX8ZEyrDNd2XZOnQ0D5XfunJF5FLQnZbHHYq4UWvW1QfelQNXv1ICNkwYhfxjwfnqivYB6bFg==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*" - } - }, - "node_modules/@types/stats.js": { - "version": "0.17.4", - "resolved": "https://registry.npmjs.org/@types/stats.js/-/stats.js-0.17.4.tgz", - "integrity": "sha512-jIBvWWShCvlBqBNIZt0KAshWpvSjhkwkEu4ZUcASoAvhmrgAUI2t1dXrjSL4xXVLB4FznPrIsX3nKXFl/Dt4vA==", - "license": "MIT" - }, - "node_modules/@types/three": { - "version": "0.185.4", - "resolved": "https://registry.npmjs.org/@types/three/-/three-0.185.4.tgz", - "integrity": "sha512-gAsBIC07NIFrxjbf7tH2t71c38uulFfk/RFoC7FNBSjMRAQ8J1x/RBvusX0N5PJouaYFJawXQqfCQ0RKUx/1nA==", - "license": "MIT", - "dependencies": { - "@dimforge/rapier3d-compat": "~0.12.0", - "@tweenjs/tween.js": "~23.1.3", - "@types/stats.js": "*", - "@types/webxr": ">=0.5.17", - "fflate": "~0.8.2", - "meshoptimizer": "~1.1.1" - } - }, "node_modules/@types/validate-npm-package-name": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/@types/validate-npm-package-name/-/validate-npm-package-name-4.0.2.tgz", "integrity": "sha512-lrpDziQipxCEeK5kWxvljWYhUvOiB2A9izZd9B2AFarYAkqZshb4lPbRs7zKEic6eGtH8V/2qJW+dPp9OtF6bw==", "license": "MIT" }, - "node_modules/@types/webxr": { - "version": "0.5.24", - "resolved": "https://registry.npmjs.org/@types/webxr/-/webxr-0.5.24.tgz", - "integrity": "sha512-h8fgEd/DpoS9CBrjEQXR+dIDraopAEfu4wYVNY2tEPwk60stPWhvZMf4Foo5FakuQ7HFZoa8WceaWFervK2Ovg==", - "license": "MIT" - }, - "node_modules/@use-gesture/core": { - "version": "10.3.1", - "resolved": "https://registry.npmjs.org/@use-gesture/core/-/core-10.3.1.tgz", - "integrity": "sha512-WcINiDt8WjqBdUXye25anHiNxPc0VOrlT8F6LLkU6cycrOGUDyY/yyFmsg3k8i5OLvv25llc0QC45GhR/C8llw==", - "license": "MIT" - }, - "node_modules/@use-gesture/react": { - "version": "10.3.1", - "resolved": "https://registry.npmjs.org/@use-gesture/react/-/react-10.3.1.tgz", - "integrity": "sha512-Yy19y6O2GJq8f7CHf7L0nxL8bf4PZCPaVOCgJrusOeFHY1LvHgYXnmnXg6N5iwAnbgbZCDjo60SiM6IPJi9C5g==", - "license": "MIT", - "dependencies": { - "@use-gesture/core": "10.3.1" - }, - "peerDependencies": { - "react": ">= 16.8.0" - } - }, "node_modules/@vitejs/plugin-react": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-6.1.0.tgz", @@ -5706,6 +5551,12 @@ } } }, + "node_modules/@xstate/fsm": { + "version": "1.6.5", + "resolved": "https://registry.npmjs.org/@xstate/fsm/-/fsm-1.6.5.tgz", + "integrity": "sha512-b5o1I6aLNeYlU/3CPlj/Z91ybk1gUsKT+5NAJI+2W4UjvS5KLG28K9v5UvNoFVjHV8PajVZ00RH3vnjyQO7ZAw==", + "license": "MIT" + }, "node_modules/accepts": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", @@ -5865,25 +5716,14 @@ "node": "18 || 20 || >=22" } }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" + "node_modules/base64-arraybuffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz", + "integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + } }, "node_modules/baseline-browser-mapping": { "version": "2.11.17", @@ -6031,15 +5871,6 @@ "@noble/hashes": "^2.0.1" } }, - "node_modules/bidi-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/bidi-js/-/bidi-js-1.0.3.tgz", - "integrity": "sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==", - "license": "MIT", - "dependencies": { - "require-from-string": "^2.0.2" - } - }, "node_modules/body-parser": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.3.0.tgz", @@ -6134,34 +5965,11 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, - "node_modules/buffer": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", - "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.2.1" - } - }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "devOptional": true, "license": "MIT" }, "node_modules/bundle-name": { @@ -6226,19 +6034,6 @@ "node": ">=6" } }, - "node_modules/camera-controls": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/camera-controls/-/camera-controls-3.1.2.tgz", - "integrity": "sha512-xkxfpG2ECZ6Ww5/9+kf4mfg1VEYAoe9aDSY+IwF0UEs7qEzwy0aVRfs2grImIECs/PoBtWFrh7RXsQkwG922JA==", - "license": "MIT", - "engines": { - "node": ">=22.0.0", - "npm": ">=10.5.1" - }, - "peerDependencies": { - "three": ">=0.126.1" - } - }, "node_modules/caniuse-lite": { "version": "1.0.30001809", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001809.tgz", @@ -6547,24 +6342,6 @@ } } }, - "node_modules/cross-env": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", - "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==", - "license": "MIT", - "dependencies": { - "cross-spawn": "^7.0.1" - }, - "bin": { - "cross-env": "src/bin/cross-env.js", - "cross-env-shell": "src/bin/cross-env-shell.js" - }, - "engines": { - "node": ">=10.14", - "npm": ">=6", - "yarn": ">=1" - } - }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -6761,15 +6538,6 @@ "node": ">= 0.8" } }, - "node_modules/detect-gpu": { - "version": "5.0.70", - "resolved": "https://registry.npmjs.org/detect-gpu/-/detect-gpu-5.0.70.tgz", - "integrity": "sha512-bqerEP1Ese6nt3rFkwPnGbsUF9a4q+gMmpTVVOEzoCyeCc+y7/RvJnQZJx1JwhgQI5Ntg0Kgat8Uu7XpBqnz1w==", - "license": "MIT", - "dependencies": { - "webgl-constants": "^1.1.1" - } - }, "node_modules/detect-libc": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", @@ -6821,16 +6589,11 @@ "url": "https://dotenvx.com" } }, - "node_modules/draco3d": { - "version": "1.5.7", - "resolved": "https://registry.npmjs.org/draco3d/-/draco3d-1.5.7.tgz", - "integrity": "sha512-m6WCKt/erDXcw+70IJXnG7M3awwQPAsZvJGX5zY7beBqpELw6RDGkYVU0W43AFxye4pDZ5i2Lbyc/NNGqwjUVQ==", - "license": "Apache-2.0" - }, "node_modules/drizzle-kit": { "version": "0.31.10", "resolved": "https://registry.npmjs.org/drizzle-kit/-/drizzle-kit-0.31.10.tgz", "integrity": "sha512-7OZcmQUrdGI+DUNNsKBn1aW8qSoKuTH7d0mYgSP8bAzdFzKoovxEFnoGQp2dVs82EOJeYycqRtciopszwUf8bw==", + "devOptional": true, "license": "MIT", "dependencies": { "@drizzle-team/brocli": "^0.10.2", @@ -7262,6 +7025,7 @@ "version": "0.25.12", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", + "devOptional": true, "hasInstallScript": true, "license": "MIT", "bin": { @@ -7838,12 +7602,6 @@ "integrity": "sha512-YoZjBdafyLIop9lSxXVI33oLD5kN31q4Td+CasofLLYeLXRFeOsuOw0Uo+XNRi9PZlbfdlN2GmRtm4tCEQ9/KA==", "license": "MIT" }, - "node_modules/fflate": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.3.tgz", - "integrity": "sha512-tbZNuJrLwGUp3zshBtdy4W+ORxZuIh8a5ilyIEQDC5rY1f3U20JMry0Ll3WBzU58EZKsEuJFXhb5gwv8CsPvgA==", - "license": "MIT" - }, "node_modules/figures": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/figures/-/figures-6.1.0.tgz", @@ -8074,6 +7832,7 @@ "version": "4.14.3", "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.14.3.tgz", "integrity": "sha512-++QEw4DIY7WGoukz+/+A/8dGYPT9l9yIadnmSgZ8Rjr3YVSVDipQSO9CdnJo9ePqFqUUqh+wk9uIaoiAwsiPkA==", + "devOptional": true, "license": "MIT", "dependencies": { "resolve-pkg-maps": "^1.0.0" @@ -8094,12 +7853,6 @@ "node": ">= 6" } }, - "node_modules/glsl-noise": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/glsl-noise/-/glsl-noise-0.0.0.tgz", - "integrity": "sha512-b/ZCF6amfAUb7dJM/MxRs7AetQEahYzJ8PtgfrmEdtw6uyGOr+ZSGtgjFm6mfsBkxJ4d2W7kg+Nlqzqvn3Bc0w==", - "license": "MIT" - }, "node_modules/goober": { "version": "2.1.19", "resolved": "https://registry.npmjs.org/goober/-/goober-2.1.19.tgz", @@ -8212,16 +7965,10 @@ "node": ">= 0.4" } }, - "node_modules/hls.js": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/hls.js/-/hls.js-1.7.1.tgz", - "integrity": "sha512-DlzIkeBAS9IIQ432k3BUf3HlwbsR0+trB1i2lDdN2gUkNkrehFurh0/48M5c1/EjlDkdGng1gwZIpwyPxvdZ/g==", - "license": "Apache-2.0" - }, "node_modules/hono": { - "version": "4.13.4", - "resolved": "https://registry.npmjs.org/hono/-/hono-4.13.4.tgz", - "integrity": "sha512-AGEwKIyRMHRv1t8Wjwa3LHxQ61X5CqrdFT+4BRNTpqS5aJNnpl5WLjADb7vFlJzI/8uK7T5QLVApCMQKNa3LgQ==", + "version": "4.13.7", + "resolved": "https://registry.npmjs.org/hono/-/hono-4.13.7.tgz", + "integrity": "sha512-c8/gF9ac8Y78/agExVocyLevgR+JlpNB444Py0FSX8pJoPdYUfUzRcXtYEYGwt6l19qIlVZPN5Mfsw9jFShmQQ==", "license": "MIT", "engines": { "node": ">=16.9.0" @@ -8284,26 +8031,6 @@ "url": "https://opencollective.com/express" } }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "BSD-3-Clause" - }, "node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", @@ -8313,12 +8040,6 @@ "node": ">= 4" } }, - "node_modules/immediate": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", - "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", - "license": "MIT" - }, "node_modules/import-fresh": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", @@ -8483,12 +8204,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-promise": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", - "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", - "license": "MIT" - }, "node_modules/is-regexp": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-3.1.0.tgz", @@ -8555,18 +8270,6 @@ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "license": "ISC" }, - "node_modules/its-fine": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/its-fine/-/its-fine-2.0.0.tgz", - "integrity": "sha512-KLViCmWx94zOvpLwSlsx6yOCeMhZYaxrJV87Po5k/FoZzcPSahvK5qJ7fYhS61sZi5ikmh2S3Hz55A2l3U69ng==", - "license": "MIT", - "dependencies": { - "@types/react-reconciler": "^0.28.9" - }, - "peerDependencies": { - "react": "^19.0.0" - } - }, "node_modules/jiti": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.7.0.tgz", @@ -8592,9 +8295,9 @@ "license": "MIT" }, "node_modules/js-yaml": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.1.tgz", - "integrity": "sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.2.tgz", + "integrity": "sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA==", "funding": [ { "type": "github", @@ -8696,15 +8399,6 @@ "shell-quote": "^1.8.4" } }, - "node_modules/lie": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", - "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", - "license": "MIT", - "dependencies": { - "immediate": "~3.0.5" - } - }, "node_modules/lightningcss": { "version": "1.32.0", "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", @@ -9022,16 +8716,6 @@ "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, - "node_modules/maath": { - "version": "0.10.8", - "resolved": "https://registry.npmjs.org/maath/-/maath-0.10.8.tgz", - "integrity": "sha512-tRvbDF0Pgqz+9XUa4jjfgAQ8/aPKmQdWXilFu2tMy4GWj4NOsx99HlULO4IeREfbO3a0sA145DZYyvXPkybm0g==", - "license": "MIT", - "peerDependencies": { - "@types/three": ">=0.134.0", - "three": ">=0.134.0" - } - }, "node_modules/magic-string": { "version": "0.30.21", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", @@ -9090,21 +8774,6 @@ "node": ">= 8" } }, - "node_modules/meshline": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/meshline/-/meshline-3.3.1.tgz", - "integrity": "sha512-/TQj+JdZkeSUOl5Mk2J7eLcYTLiQm2IDzmlSvYm7ov15anEcDJ92GHqqazxTSreeNgfnYu24kiEvvv0WlbCdFQ==", - "license": "MIT", - "peerDependencies": { - "three": ">=0.137" - } - }, - "node_modules/meshoptimizer": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/meshoptimizer/-/meshoptimizer-1.1.1.tgz", - "integrity": "sha512-oRFNWJRDA/WTrVj7NWvqa5HqE1t9MYDj2VaWirQCzCCrAd2GHrqR/sQezCxiWATPNlKTcRaPRHPJwIRoPBAp5g==", - "license": "MIT" - }, "node_modules/micromatch": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", @@ -9200,6 +8869,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/mitt": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", + "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==", + "license": "MIT" + }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -9938,12 +9613,6 @@ "node": ">=0.10.0" } }, - "node_modules/potpack": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/potpack/-/potpack-1.0.2.tgz", - "integrity": "sha512-choctRBIV9EMT9WGAZHn3V7t0Z2pMQyl0EZE6pFc/6ml3ssw7Dlf/oAOvFwjm1HVsqfQN8GfeFyJ+d8tRzqueQ==", - "license": "ISC" - }, "node_modules/powershell-utils": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/powershell-utils/-/powershell-utils-0.2.0.tgz", @@ -9986,16 +9655,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/promise-worker-transferable": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/promise-worker-transferable/-/promise-worker-transferable-1.0.4.tgz", - "integrity": "sha512-bN+0ehEnrXfxV2ZQvU2PetO0n4gqBD4ulq3MI1WOPLgr7/Mg9yRQkX5+0v1vagr74ZTsl7XtzlaYDo2EuCeYJw==", - "license": "Apache-2.0", - "dependencies": { - "is-promise": "^2.1.0", - "lie": "^3.0.2" - } - }, "node_modules/prompts": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", @@ -10032,9 +9691,9 @@ } }, "node_modules/qs": { - "version": "6.15.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.3.tgz", - "integrity": "sha512-O9gl3zCl5h5blw1KGUzQKhA5oUXSl8rwUIM5o0S3nCXMliSvy5Dzx7/DJcI+SwgICv+IneSZwhBh1oSyEHA71A==", + "version": "6.16.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.16.0.tgz", + "integrity": "sha512-h6fhOIaRrID2CbEY2fqs+7t+UXZo+MLAnU5gRIq85uFtdiUPCdsApMlHhXogKVM4HM2DVbIjGNTTYH2OcmP1vA==", "license": "BSD-3-Clause", "dependencies": { "es-define-property": "^1.0.1", @@ -10262,21 +9921,6 @@ } } }, - "node_modules/react-use-measure": { - "version": "2.1.7", - "resolved": "https://registry.npmjs.org/react-use-measure/-/react-use-measure-2.1.7.tgz", - "integrity": "sha512-KrvcAo13I/60HpwGO5jpW7E9DfusKyLPLvuHlUyP5zqnmAPhNc6qTRjUQrdTADl0lpPpDVU2/Gg51UlOGHXbdg==", - "license": "MIT", - "peerDependencies": { - "react": ">=16.13", - "react-dom": ">=16.13" - }, - "peerDependenciesMeta": { - "react-dom": { - "optional": true - } - } - }, "node_modules/readdirp": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.1.1.tgz", @@ -10347,6 +9991,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "devOptional": true, "license": "MIT", "funding": { "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" @@ -10463,6 +10108,40 @@ "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", "license": "MIT" }, + "node_modules/rrdom": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/rrdom/-/rrdom-2.1.4.tgz", + "integrity": "sha512-YfEqKcmZHI20HJDZvA9a8XQVl0qMtodrz5BRZgj2H46ZnvwZEejASlwwWuyrzWdlsUPEFYrUqbA7lCkiePnpZg==", + "license": "MIT", + "dependencies": { + "rrweb-snapshot": "^2.1.4" + } + }, + "node_modules/rrweb": { + "version": "2.0.0-alpha.20", + "resolved": "https://registry.npmjs.org/rrweb/-/rrweb-2.0.0-alpha.20.tgz", + "integrity": "sha512-CZKDlm+j1VA50Ko3gnMbpvguCAleljsTNXPnVk9aeNP8o6T6kolRbISHyDZpqZ4G+bdDLlQOignPP3jEsXs8Gg==", + "license": "MIT", + "dependencies": { + "@rrweb/types": "^2.0.0-alpha.20", + "@rrweb/utils": "^2.0.0-alpha.20", + "@types/css-font-loading-module": "0.0.7", + "@xstate/fsm": "^1.4.0", + "base64-arraybuffer": "^1.0.1", + "mitt": "^3.0.0", + "rrdom": "^2.0.0-alpha.20", + "rrweb-snapshot": "^2.0.0-alpha.20" + } + }, + "node_modules/rrweb-snapshot": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/rrweb-snapshot/-/rrweb-snapshot-2.1.4.tgz", + "integrity": "sha512-Yo5H9PrvsC2roBaDWpb6d9aOridpUndS0eEhLQC7sbrL2Ie/l98d9bhAm7e+ZOHgdIweIqndS0R1Omz+i68Osw==", + "license": "MIT", + "dependencies": { + "postcss": "^8.4.38" + } + }, "node_modules/run-applescript": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.1.0.tgz", @@ -10868,6 +10547,7 @@ "version": "0.5.21", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "devOptional": true, "license": "MIT", "dependencies": { "buffer-from": "^1.0.0", @@ -10878,6 +10558,7 @@ "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "devOptional": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" @@ -10904,32 +10585,6 @@ "node": ">=20.16.0" } }, - "node_modules/stats-gl": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/stats-gl/-/stats-gl-2.4.2.tgz", - "integrity": "sha512-g5O9B0hm9CvnM36+v7SFl39T7hmAlv541tU81ME8YeSb3i1CIP5/QdDeSB3A0la0bKNHpxpwxOVRo2wFTYEosQ==", - "license": "MIT", - "dependencies": { - "@types/three": "*", - "three": "^0.170.0" - }, - "peerDependencies": { - "@types/three": "*", - "three": "*" - } - }, - "node_modules/stats-gl/node_modules/three": { - "version": "0.170.0", - "resolved": "https://registry.npmjs.org/three/-/three-0.170.0.tgz", - "integrity": "sha512-FQK+LEpYc0fBD+J8g6oSEyyNzjp+Q7Ks1C568WWaoMRLW+TkNNWmenWeGgJjV105Gd+p/2ql1ZcjYvNiPZBhuQ==", - "license": "MIT" - }, - "node_modules/stats.js": { - "version": "0.17.0", - "resolved": "https://registry.npmjs.org/stats.js/-/stats.js-0.17.0.tgz", - "integrity": "sha512-hNKz8phvYLPEcRkeG1rsGmV5ChMjKDAWU7/OJJdDErPBNChQXxCo3WZurGpnWc6gZhAzEPFad1aVgyOANH1sMw==", - "license": "MIT" - }, "node_modules/statuses": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", @@ -11028,15 +10683,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/suspend-react": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/suspend-react/-/suspend-react-0.1.3.tgz", - "integrity": "sha512-aqldKgX9aZqpoDp3e8/BZ8Dm7x1pJl+qI3ZKxDN0i/IQTWUwBx/ManmlVJ3wowqbno6c2bmiIfs+Um6LbsjJyQ==", - "license": "MIT", - "peerDependencies": { - "react": ">=17.0" - } - }, "node_modules/systeminformation": { "version": "5.33.1", "resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-5.33.1.tgz", @@ -11092,44 +10738,6 @@ "url": "https://opencollective.com/webpack" } }, - "node_modules/three": { - "version": "0.185.1", - "resolved": "https://registry.npmjs.org/three/-/three-0.185.1.tgz", - "integrity": "sha512-5aojFCXKwnjBRZvUnt3WFfEcvUJgkN5LlijRFN95hMy8WVkG4I0QNcJE+OuWvuJ0bOdStrbfXn0pkd6/QyiAlg==", - "license": "MIT" - }, - "node_modules/three-mesh-bvh": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/three-mesh-bvh/-/three-mesh-bvh-0.8.3.tgz", - "integrity": "sha512-4G5lBaF+g2auKX3P0yqx+MJC6oVt6sB5k+CchS6Ob0qvH0YIhuUk1eYr7ktsIpY+albCqE80/FVQGV190PmiAg==", - "license": "MIT", - "peerDependencies": { - "three": ">= 0.159.0" - } - }, - "node_modules/three-stdlib": { - "version": "2.36.1", - "resolved": "https://registry.npmjs.org/three-stdlib/-/three-stdlib-2.36.1.tgz", - "integrity": "sha512-XyGQrFmNQ5O/IoKm556ftwKsBg11TIb301MB5dWNicziQBEs2g3gtOYIf7pFiLa0zI2gUwhtCjv9fmjnxKZ1Cg==", - "license": "MIT", - "dependencies": { - "@types/draco3d": "^1.4.0", - "@types/offscreencanvas": "^2019.6.4", - "@types/webxr": "^0.5.2", - "draco3d": "^1.4.1", - "fflate": "^0.6.9", - "potpack": "^1.0.1" - }, - "peerDependencies": { - "three": ">=0.128.0" - } - }, - "node_modules/three-stdlib/node_modules/fflate": { - "version": "0.6.11", - "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.6.11.tgz", - "integrity": "sha512-3JyEFWGjFn7zHmoa9+zG1BmW7X2okcmAB+0Cnu9UFbVs/jCBnl2A8o065ZlXiw145K3eBM3uLuzrYXC0RK7eDg==", - "license": "MIT" - }, "node_modules/tiny-invariant": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", @@ -11173,36 +10781,6 @@ "node": ">=0.6" } }, - "node_modules/troika-three-text": { - "version": "0.52.5", - "resolved": "https://registry.npmjs.org/troika-three-text/-/troika-three-text-0.52.5.tgz", - "integrity": "sha512-Ry3jRhic9pzcY4JduSvRRyDmVOSqEW19gT4vtK+aCiPNVcDlmkxvGG0YbFd36RTDq1wExOupXnvNF/j1oiHHDA==", - "license": "MIT", - "dependencies": { - "bidi-js": "^1.0.2", - "troika-three-utils": "^0.52.5", - "troika-worker-utils": "^0.52.0", - "webgl-sdf-generator": "1.1.1" - }, - "peerDependencies": { - "three": ">=0.125.0" - } - }, - "node_modules/troika-three-utils": { - "version": "0.52.5", - "resolved": "https://registry.npmjs.org/troika-three-utils/-/troika-three-utils-0.52.5.tgz", - "integrity": "sha512-WsePbcX8RtfidRfsxK1eCZCjF81ZDzAKHH/evLs0hdV2wpoCb0vArGZHdzdOJrSS3k4zfdtbKDaBh8+phkrYnw==", - "license": "MIT", - "peerDependencies": { - "three": ">=0.125.0" - } - }, - "node_modules/troika-worker-utils": { - "version": "0.52.0", - "resolved": "https://registry.npmjs.org/troika-worker-utils/-/troika-worker-utils-0.52.0.tgz", - "integrity": "sha512-W1CpvTHykaPH5brv5VHLfQo9D1OYuo0cSBEUQFFT/nBUzM8iD6Lq2/tgG/f1OelbAS1WtaTPQzE5uM49egnngw==", - "license": "MIT" - }, "node_modules/ts-morph": { "version": "26.0.0", "resolved": "https://registry.npmjs.org/ts-morph/-/ts-morph-26.0.0.tgz", @@ -11251,43 +10829,6 @@ "fsevents": "~2.3.3" } }, - "node_modules/tunnel-rat": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/tunnel-rat/-/tunnel-rat-0.1.2.tgz", - "integrity": "sha512-lR5VHmkPhzdhrM092lI2nACsLO4QubF0/yoOhzX7c+wIpbN1GjHNzCc91QlpxBi+cnx8vVJ+Ur6vL5cEoQPFpQ==", - "license": "MIT", - "dependencies": { - "zustand": "^4.3.2" - } - }, - "node_modules/tunnel-rat/node_modules/zustand": { - "version": "4.5.7", - "resolved": "https://registry.npmjs.org/zustand/-/zustand-4.5.7.tgz", - "integrity": "sha512-CHOUy7mu3lbD6o6LJLfllpjkzhHXSBlX8B9+qPddUsIfeF5S/UZ5q0kmCsnRqT1UHFQZchNFDDzMbQsuesHWlw==", - "license": "MIT", - "dependencies": { - "use-sync-external-store": "^1.2.2" - }, - "engines": { - "node": ">=12.7.0" - }, - "peerDependencies": { - "@types/react": ">=16.8", - "immer": ">=9.0.6", - "react": ">=16.8" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "immer": { - "optional": true - }, - "react": { - "optional": true - } - } - }, "node_modules/tw-animate-css": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/tw-animate-css/-/tw-animate-css-1.4.0.tgz", @@ -11647,15 +11188,6 @@ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "license": "MIT" }, - "node_modules/utility-types": { - "version": "3.11.0", - "resolved": "https://registry.npmjs.org/utility-types/-/utility-types-3.11.0.tgz", - "integrity": "sha512-6Z7Ma2aVEWisaL6TvBCy7P8rm2LQoPv6dJ7ecIaIixHcwfbJ0x7mWdbcwlIM5IGQxPZSFYeqRCqlOOeKoJYMkw==", - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, "node_modules/validate-npm-package-name": { "version": "7.0.2", "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-7.0.2.tgz", @@ -12031,17 +11563,6 @@ } } }, - "node_modules/webgl-constants": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/webgl-constants/-/webgl-constants-1.1.1.tgz", - "integrity": "sha512-LkBXKjU5r9vAW7Gcu3T5u+5cvSvh5WwINdr0C+9jpzVB41cjQAP5ePArDtk/WHYdVj0GefCgM73BA7FlIiNtdg==" - }, - "node_modules/webgl-sdf-generator": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/webgl-sdf-generator/-/webgl-sdf-generator-1.1.1.tgz", - "integrity": "sha512-9Z0JcMTFxeE+b2x1LJTdnaT8rT8aEp7MVxkNwoycNmJWwPdzoXzMh0BjJSh/AEFP+KPYZUli814h8bJZFIZ2jA==", - "license": "MIT" - }, "node_modules/webpack-virtual-modules": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz", @@ -12249,35 +11770,6 @@ "peerDependencies": { "zod": "^3.25.28 || ^4" } - }, - "node_modules/zustand": { - "version": "5.0.15", - "resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.15.tgz", - "integrity": "sha512-MpSEjRiBkA9crSYeOUH32rJC7SVqAbm0Fqcqge/bUi2PPoLcBWKOsG+C8mevmpr8TwXHBVkChbbJiyvkE+i/3A==", - "license": "MIT", - "engines": { - "node": ">=12.20.0" - }, - "peerDependencies": { - "@types/react": ">=18.0.0", - "immer": ">=9.0.6", - "react": ">=18.0.0", - "use-sync-external-store": ">=1.2.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "immer": { - "optional": true - }, - "react": { - "optional": true - }, - "use-sync-external-store": { - "optional": true - } - } } } } diff --git a/package.json b/package.json index 58390a2..ec43cdd 100644 --- a/package.json +++ b/package.json @@ -26,8 +26,7 @@ "@calcom/embed-react": "^1.5.3", "@fontsource-variable/nunito-sans": "^5.3.0", "@fontsource-variable/public-sans": "^5.3.0", - "@react-three/drei": "^10.7.8", - "@react-three/fiber": "^9.7.0", + "@openpanel/web": "^1.4.1", "@tailwindcss/vite": "^4.1.18", "@tanstack/react-devtools": "latest", "@tanstack/react-router": "latest", @@ -36,7 +35,6 @@ "better-auth": "^1.5.3", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", - "drizzle-kit": "^0.31.10", "drizzle-orm": "^0.45.1", "lucide-react": "^0.577.0", "nitro": "3.0.260610-beta", @@ -47,9 +45,8 @@ "shadcn": "^4.19.0", "tailwind-merge": "^3.0.2", "tailwindcss": "^4.1.18", - "three": "^0.185.1", - "tw-animate-css": "^1.3.6", - "tsx": "^4.21.0" + "tsx": "^4.21.0", + "tw-animate-css": "^1.3.6" }, "devDependencies": { "@biomejs/biome": "2.4.5", @@ -64,6 +61,7 @@ "@vitejs/plugin-react": "^6.0.1", "babel-plugin-react-compiler": "^1.0.0", "dotenv": "^17.3.1", + "drizzle-kit": "^0.31.10", "typescript": "^6.0.2", "vite": "^8.0.0" }, diff --git a/public/robots.txt b/public/robots.txt new file mode 100644 index 0000000..a69bb2a --- /dev/null +++ b/public/robots.txt @@ -0,0 +1,8 @@ +User-agent: * +Allow: / +Disallow: /login +Disallow: /dashboard +Disallow: /admin +Disallow: /api/ + +Sitemap: https://webkulisse.de/sitemap.xml diff --git a/public/sitemap.xml b/public/sitemap.xml new file mode 100644 index 0000000..4b7fd48 --- /dev/null +++ b/public/sitemap.xml @@ -0,0 +1,23 @@ + + + + https://webkulisse.de/ + monthly + 1.0 + + + https://webkulisse.de/termin + monthly + 0.8 + + + https://webkulisse.de/impressum + yearly + 0.3 + + + https://webkulisse.de/datenschutz + yearly + 0.3 + + diff --git a/src/components/analytics.tsx b/src/components/analytics.tsx new file mode 100644 index 0000000..09d5003 --- /dev/null +++ b/src/components/analytics.tsx @@ -0,0 +1,10 @@ +import { useEffect } from "react"; + +// OpenPanel wird ausschließlich im Browser initialisiert. Ein dynamischer Import +// verhindert, dass der Konstruktor bereits beim Server-Rendering läuft. +export function Analytics() { + useEffect(() => { + void import("@/openpanel.ts"); + }, []); + return null; +} diff --git a/src/components/footer.tsx b/src/components/footer.tsx index 6cd3cf0..3341740 100644 --- a/src/components/footer.tsx +++ b/src/components/footer.tsx @@ -24,14 +24,25 @@ export const Footer = () => {
-
@@ -45,10 +56,10 @@ export const Footer = () => {
Placeholder Logo @@ -66,7 +77,7 @@ export const Footer = () => { Anbieter
- Mathias Hurler Webdesign + Hurler Webdesign
Untermagerbein 30
@@ -83,6 +94,8 @@ export const Footer = () => { info@webkulisse.de @@ -90,11 +103,13 @@ export const Footer = () => {
  • - +49 176 22222222 + +49 171 8084830
  • diff --git a/src/components/header.tsx b/src/components/header.tsx index 6877f1d..a523d6c 100644 --- a/src/components/header.tsx +++ b/src/components/header.tsx @@ -6,11 +6,11 @@ import { Button } from "@/components/ui/button.tsx"; import { authClient } from "@/lib/auth-client.ts"; const navLinks = [ - { href: "#zielgruppen", label: "Für wen" }, - { href: "#warum-wir", label: "Warum wir" }, - { href: "#ablauf", label: "Ablauf" }, - { href: "#pricing", label: "Angebote" }, - { href: "#kontakt", label: "Kontakt" }, + { hash: "zielgruppen", label: "Für wen" }, + { hash: "warum-wir", label: "Warum wir" }, + { hash: "ablauf", label: "Ablauf" }, + { hash: "pricing", label: "Angebote" }, + { hash: "kontakt", label: "Kontakt" }, ]; export default function Header() { @@ -52,7 +52,7 @@ export default function Header() {
    Logo Webkulisse @@ -89,7 +93,14 @@ export default function Header() { diff --git a/src/components/hero.tsx b/src/components/hero.tsx index 497bd1a..383e6be 100644 --- a/src/components/hero.tsx +++ b/src/components/hero.tsx @@ -10,58 +10,58 @@ const trustPoints = [ export default function Hero() { return ( -
    -
    -
    - - - Für Handwerk, Praxis und Therapie in Bayern - +
    +
    + + + Für Handwerk, Praxis und Therapie in Bayern + -

    - Eine Webseite, die{" "} - neue Kunden bringt - nicht nur gut aussieht. -

    +

    + Eine Webseite, die{" "} + neue Kunden bringt - nicht nur gut aussieht. +

    -

    - Damit neue Kunden Sie zuerst finden - nicht die Konkurrenz in der Nachbarschaft. -

    +

    + Damit neue Kunden Sie zuerst finden - nicht die Konkurrenz in der Nachbarschaft. +

    -
    - - - - -
    -

    - 30 Minuten, kostenlos - direkt online buchen, keine Warteschleifen. -

    - -
      - {trustPoints.map(({ icon: Icon, label }) => ( -
    • - - {label} -
    • - ))} -
    + +
    +

    + 30 Minuten, kostenlos - direkt online buchen, keine Warteschleifen. +

    -
    - Aufgeräumter Schreibtisch aus Holz mit Laptop -
    +
      + {trustPoints.map(({ icon: Icon, label }) => ( +
    • + + {label} +
    • + ))} +
    ); diff --git a/src/components/pricing.tsx b/src/components/pricing.tsx index d7810f6..3c79204 100644 --- a/src/components/pricing.tsx +++ b/src/components/pricing.tsx @@ -1,3 +1,4 @@ +import { useState } from "react"; import { Check, Sparkles } from "lucide-react"; import { Button } from "@/components/ui/button.tsx"; import { BookingDialog } from "@/components/booking-dialog.tsx"; @@ -5,6 +6,7 @@ import { BookingDialog } from "@/components/booking-dialog.tsx"; type PricingPlan = { id: number; name: string; + slug: string; description: string; price: number; features: string[]; @@ -12,16 +14,26 @@ type PricingPlan = { highlighted?: boolean; }; +type HostingPlan = { + id: number; + name: string; + description: string; + priceMonthly: number; + priceYearly: number; + features: string[]; + highlighted: boolean; +} + const offerlist: PricingPlan[] = [ { id: 1, name: "Das Kompakt-Paket", + slug: "kompakt", description: "Perfekt für die schnelle, moderne Präsentation. Ideal für Therapeuten, Berater und regionale Handwerker.", - price: 900, + price: 1800, features: [ "Alle wichtigen Infos auf einer Seite", - "Kontaktformular & Anfahrt", "Für Smartphone optimiert", "SSL-Verschlüsselung inklusive", "SEO-Grundlagen (Meta-Tags, schnelle Ladezeit)", @@ -31,40 +43,60 @@ const offerlist: PricingPlan[] = [ { id: 2, name: "Das Klassik-Paket", + slug: "klassik", description: "Für Praxen und Betriebe mit breitem Angebot. Maximale Übersicht für Ihre Besucher.", - price: 1700, + price: 2500, features: [ "Separate Leistungs- und Teamseiten", "Bildergalerie & Referenzen", "Erweiterte SEO-Optimierung", "Rechtstexte-Assistenz", - "3 Monate kostenloser Support", ], priceNote: "Aufpreise z. B. für zusätzliche Sprachen oder Shop-Anbindung.", highlighted: true, + } +]; + +const hostinglist: HostingPlan[] = [ + { + id: 1, + name: "Basis", + description: "", + priceMonthly: 79, + priceYearly: 790, + features: [ + "Premium-Hosting", + "SSL-Zertifikat", + "Uptime Monitoring", + "30 Minuten pro Monat für Textänderungen oder Anpassungen", + ], + highlighted: false, }, { - id: 3, - name: "Ihre neue Webapp", - description: - "Für digitale Lösungen mit echtem Mehrwert. Ideal für Unternehmen, die mehr als eine Website brauchen.", - price: 2500, + id: 2, + name: "Standard", + description: "", + priceMonthly: 149, + priceYearly: 1490, features: [ - "Login- und Nutzerbereich", - "Individuelle Funktionen", - "Terminbuchung oder Kundenportal", - "SEO-Grundlagen (Meta-Tags, schnelle Ladezeit)", - "Skalierbare Infrastruktur", + "Alles aus Basis", + "1 Stunde pro Monat für inhaltliche Pflege, z. B. neue Texte, Bilder, Teammitglieder", + "Monatlicher Performance-Report zu Besucherzahlen und Analytics", ], - priceNote: "Endpreis abhängig vom Funktionsumfang - Details im Erstgespräch.", - }, + highlighted: true, + } ]; const priceFormatter = new Intl.NumberFormat("de-DE"); +type Billing = "monthly" | "yearly"; + export const Pricing = () => { + const [billing, setBilling] = useState("monthly"); + return ( + <>
    Preise @@ -77,7 +109,7 @@ export const Pricing = () => {

    -
    +
    {offerlist.map((offer) => { const isHighlighted = offer.highlighted; return ( @@ -132,6 +164,8 @@ export const Pricing = () => { @@ -141,6 +175,234 @@ export const Pricing = () => { ); })}
    + +
    +
    + Hosting & Betreuung +

    + Rundum betreut - auch nach dem Launch. +

    +

    + Wir übernehmen Technik, Sicherheit und laufende Anpassungen - + damit Ihre Seite dauerhaft schnell, sicher und aktuell bleibt. +

    +
    + +
    +
    + + +
    +
    + +
    + {hostinglist.map((plan) => { + const isHighlighted = plan.highlighted; + const price = + billing === "monthly" ? plan.priceMonthly : plan.priceYearly; + const suffix = billing === "monthly" ? "/ Monat" : "/ Jahr"; + return ( +
    + {isHighlighted && ( + + + Empfehlung + + )} + +
    +

    + {plan.name} +

    + {plan.description && ( +

    + {plan.description} +

    + )} +
    + +
    + + {priceFormatter.format(price)} € + + + {suffix} + +
    +

    + zzgl. gesetzl. Umsatzsteuer +

    + +
      + {plan.features.map((feature) => ( +
    • + + {feature} +
    • + ))} +
    +
    + ); + })} +
    + +

    + Nicht genutzte Zeitkontingente verfallen zum Monatsende. + Kündbar zum Ende der jeweiligen Laufzeit. +

    +
    + +
    +
    +
    +
    + Für Startups +

    + Ohne Vorabkosten starten. +

    +

    + Als Startup steckt jeder Euro ins Wachstum. Wir übernehmen + die Website und finanzieren die Erstellung mit - Sie zahlen + von Tag eins nur einen festen Monatspreis. +

    +
      + {[ + "0 € Einmalkosten für die Erstellung", + "Klassik-Paket inkl. Hosting, SSL und laufender Pflege", + "1 Stunde inhaltliche Betreuung pro Monat inklusive", + "Mindestlaufzeit 24 Monate, danach monatlich kündbar", + ].map((feature) => ( +
    • + + {feature} +
    • + ))} +
    +

    + Für Unternehmen mit Gründung innerhalb der letzten 3 Jahre. + Nachweis über Handelsregister- oder Gewerbeanmeldung. +

    +
    + +
    +
    +
    +

    + Startup-Paket +

    +

    + Alles inklusive +

    +
    + + + Angebot + +
    + +
    + + 300 € + + / Monat +
    +

    + zzgl. gesetzl. Umsatzsteuer +

    + +
    +
    +
    + Einmalkosten +
    +
    + 0 € +
    +
    +
    +
    Laufzeit
    +
    + 24 Monate +
    +
    +
    + + + + +
    +
    +
    +
    + ); }; diff --git a/src/components/public-shell.tsx b/src/components/public-shell.tsx new file mode 100644 index 0000000..867429e --- /dev/null +++ b/src/components/public-shell.tsx @@ -0,0 +1,21 @@ +import type { ReactNode } from "react"; +import Header from "@/components/header.tsx"; +import { Footer } from "@/components/footer.tsx"; + +export function PublicShell({ children }: { children: ReactNode }) { + return ( +
    + + Direkt zum Hauptinhalt springen + +
    +
    + {children} +
    +
    +
    + ); +} diff --git a/src/dev-component/Devtool.tsx b/src/dev-component/Devtool.tsx index 51d5627..5226896 100644 --- a/src/dev-component/Devtool.tsx +++ b/src/dev-component/Devtool.tsx @@ -1,4 +1,5 @@ import { useEffect, useRef, useState, type ReactNode, type CSSProperties } from 'react'; +import './devtool.css'; interface CrosshairProps { children: ReactNode; diff --git a/src/openpanel.ts b/src/openpanel.ts new file mode 100644 index 0000000..59aaa0c --- /dev/null +++ b/src/openpanel.ts @@ -0,0 +1,20 @@ +import { OpenPanel } from '@openpanel/web'; + +// Do-Not-Track-Signal des Browsers respektieren. Wenn der Besucher DNT aktiv +// hat, wird das SDK deaktiviert – keine Events, keine Screen Views. Damit die +// Zusage in der Datenschutzerklärung technisch abgedeckt ist. +const respectDnt = + typeof navigator !== 'undefined' && + (navigator.doNotTrack === '1' || + // Legacy-Fallbacks für ältere Browser-Implementierungen. + (navigator as unknown as { msDoNotTrack?: string }).msDoNotTrack === '1' || + (window as unknown as { doNotTrack?: string }).doNotTrack === '1'); + +export const op = new OpenPanel({ + apiUrl: 'https://data.hurler-webdesign.de', + clientId: '40700ec3-9beb-45f9-9a2a-c9321d307d1a', + trackScreenViews: true, + trackOutgoingLinks: true, + trackAttributes: true, + disabled: respectDnt, +}); \ No newline at end of file diff --git a/src/routes/__root.tsx b/src/routes/__root.tsx index d57b38d..7f014b7 100644 --- a/src/routes/__root.tsx +++ b/src/routes/__root.tsx @@ -1,16 +1,38 @@ import { HeadContent, Scripts, createRootRouteWithContext } from '@tanstack/react-router' -import { TanStackRouterDevtoolsPanel } from '@tanstack/react-router-devtools' -import { TanStackDevtools } from '@tanstack/react-devtools' +import { lazy, Suspense } from 'react' import type { Session } from '#/lib/auth.ts' import { getSessionFn } from '#/lib/session.ts' +import { Analytics } from '#/components/analytics.tsx' import appCss from '../styles.css?url' export interface RouterAppContext { session: Session | null } -const themeItnitScript = ` +const DevtoolsPanel = import.meta.env.DEV + ? lazy(async () => { + const [{ TanStackDevtools }, { TanStackRouterDevtoolsPanel }] = await Promise.all([ + import('@tanstack/react-devtools'), + import('@tanstack/react-router-devtools'), + ]) + return { + default: () => ( + , + }, + ]} + /> + ), + } + }) + : null + +const themeInitScript = ` (function() { try { var stored = localStorage.getItem('theme'); @@ -57,19 +79,31 @@ export const Route = createRootRouteWithContext()({ content: 'Handgemachte Webseiten – blitzschnell, sicher und individuell.', }, - { property: 'og:image', content: '/img/logo.png' }, + { property: 'og:image', content: 'https://webkulisse.de/img/og-cover.png' }, + { property: 'og:image:width', content: '1200' }, + { property: 'og:image:height', content: '630' }, + { property: 'og:image:alt', content: 'webkulisse – Webdesign für Handwerk, Praxis & Therapie' }, + { property: 'og:url', content: 'https://webkulisse.de/' }, // Twitter/X Card - { name: 'twitter:card', content: 'summary' }, + { name: 'twitter:card', content: 'summary_large_image' }, { name: 'twitter:title', content: 'webkulisse' }, { name: 'twitter:description', content: 'Handgemachte Webseiten – blitzschnell, sicher und individuell.', }, - { name: 'twitter:image', content: '/img/logo.png' }, + { name: 'twitter:image', content: 'https://webkulisse.de/img/og-cover.png' }, ], links: [ { rel: 'stylesheet', href: appCss }, + // Variable-Font vorladen, damit erste Textausgabe nicht auf den System-Fallback rutscht. + { + rel: 'preload', + href: '/fonts/VendSans-VariableFont_wght.woff2', + as: 'font', + type: 'font/woff2', + crossOrigin: 'anonymous', + }, // Favicon – wird in Browser-Tabs, Bookmarks und PWA-Icons genutzt. { rel: 'icon', type: 'image/png', href: '/img/logo.png' }, { rel: 'apple-touch-icon', href: '/img/logo.png' }, @@ -78,7 +112,11 @@ export const Route = createRootRouteWithContext()({ // z. B. im Blog: { rel: 'canonical', href: `${SITE_URL}/blog/${slug}` }. { rel: 'canonical', href: 'https://webkulisse.de/' }, ], - scripts: [{ children: themeItnitScript }] + scripts: [ + { children: themeInitScript }, + // OpenPanel-Loader (self-hosted). Async, damit der Haupt-Thread nicht blockiert wird. + { src: 'https://hub.hurler-webdesign.de/op1.js', async: true, defer: true }, + ] }), shellComponent: RootDocument, }) @@ -91,17 +129,12 @@ function RootDocument({ children }: { children: React.ReactNode }) { {children} - , - }, - ]} - /> + + {DevtoolsPanel ? ( + + + + ) : null} diff --git a/src/routes/_admin.tsx b/src/routes/_admin.tsx index ff8171d..e7dcc13 100644 --- a/src/routes/_admin.tsx +++ b/src/routes/_admin.tsx @@ -13,5 +13,8 @@ export const Route = createFileRoute('/_admin')({ } return { session: context.session } }, + head: () => ({ + meta: [{ name: 'robots', content: 'noindex,nofollow' }], + }), component: () => , }) diff --git a/src/routes/_authenticated.tsx b/src/routes/_authenticated.tsx index fee52b7..3064629 100644 --- a/src/routes/_authenticated.tsx +++ b/src/routes/_authenticated.tsx @@ -10,5 +10,8 @@ export const Route = createFileRoute('/_authenticated')({ } return { session: context.session } }, + head: () => ({ + meta: [{ name: 'robots', content: 'noindex,nofollow' }], + }), component: () => , }) diff --git a/src/routes/datenschutz.tsx b/src/routes/datenschutz.tsx index 154cddc..17ab867 100644 --- a/src/routes/datenschutz.tsx +++ b/src/routes/datenschutz.tsx @@ -1,6 +1,5 @@ import { createFileRoute } from "@tanstack/react-router"; -import Header from "@/components/header.tsx"; -import { Footer } from "@/components/footer.tsx"; +import { PublicShell } from "@/components/public-shell.tsx"; export const Route = createFileRoute("/datenschutz")({ component: DatenschutzPage, @@ -19,10 +18,8 @@ export const Route = createFileRoute("/datenschutz")({ function DatenschutzPage() { return ( -
    -
    -
    -
    + +
    Rechtliches

    Datenschutzerklärung @@ -323,16 +320,105 @@ function DatenschutzPage() {

    + {/* + * TODO Datenschutz — vor Launch juristisch prüfen lassen. + * Die konkreten Zusagen dieser Ziffer 10 basieren auf den + * offiziellen OpenPanel-Angaben (openpanel.dev/for/gdpr-compliant, + * Stand September 2026) und der Default-Konfiguration der + * self-hosted Instanz auf data.hurler-webdesign.de: + * • Cookieless by default (kein Consent-Banner nötig). + * • Session-Kennung = täglich rotierender Hash aus IP + + * User-Agent; rohe IP wird nicht gespeichert. + * • Geo-Daten aus dem Hash abgeleitet, nicht aus der IP. + * • DNT-Signal wird respektiert – in src/openpanel.ts + * via `disabled: navigator.doNotTrack === '1'` gesetzt. + * • Retention aggregierter Statistiken: aktuell keine + * TTL auf ClickHouse konfiguriert – Daten bleiben + * dauerhaft. Wenn eine Frist zugesagt werden soll, + * ClickHouse-TTL setzen und Text hier anpassen. + * Empfehlung: BayLDA-Muster / Anwalt vor Kundenübergabe. + */}

    - 10. Keine externen Analyse- oder Marketingdienste + 10. Reichweitenmessung mit OpenPanel (selbst gehostet)

    - Wir setzen bewusst keine Analyse-Tools wie Google - Analytics, Matomo, Meta-Pixel oder ähnliche Werkzeuge zur - Nachverfolgung Ihres Nutzungsverhaltens ein. Es werden - keine Nutzerprofile erstellt und keine Daten an - Werbepartner übermittelt. + Zur bedarfsgerechten Gestaltung und laufenden Verbesserung + unseres Onlineangebots erfassen wir anonymisierte + Zugriffsstatistiken mit OpenPanel, einer + quelloffenen Analytics-Software. OpenPanel läuft auf einer + von uns selbst betriebenen Instanz unter der Subdomain{" "} + + data.hurler-webdesign.de + + . Das begleitende Ladeskript wird von{" "} + + hub.hurler-webdesign.de + {" "} + ausgeliefert - ebenfalls unsere eigene Infrastruktur. Es + handelt sich also nicht um einen externen Dienstleister + und nicht um einen Drittanbieter im Rechtssinne - die + Daten verlassen unsere eigene Infrastruktur in der + Europäischen Union nicht. Eine Übermittlung in ein + Drittland (insbesondere in die USA) findet nicht statt. +

    +

    + Verarbeitet werden ausschließlich aggregierte, nicht + personenbezogene Daten: +

    +
      +
    • aufgerufene Seiten und Zeitpunkt des Aufrufs
    • +
    • Referrer (zuvor besuchte Seite, sofern übermittelt)
    • +
    • Herkunftsland (aus dem Sitzungs-Hash abgeleitet)
    • +
    • verwendete Browser- und Geräteklasse
    • +
    • Bildschirmauflösung und Spracheinstellung
    • +
    • ausgehende Klicks auf externe Links
    • +
    +

    + Es werden keine Cookies zur + Wiedererkennung gesetzt, kein browserübergreifendes + Tracking durchgeführt und keine Nutzerprofile gebildet. + Zur Zusammenfassung mehrerer Aufrufe innerhalb eines + Besuchs bildet OpenPanel einen kurzlebigen Sitzungs- + schlüssel: einen Hashwert aus IP-Adresse und Browser- + Kennung, der sich täglich neu bildet. + Nach spätestens 24 Stunden lässt sich ein Besuch also + keiner bestimmten Kennung mehr zuordnen. Die + IP-Adresse selbst wird zu keinem Zeitpunkt + gespeichert; das Herkunftsland wird aus dem + Hashwert abgeleitet und die IP anschließend verworfen. + Eine Weitergabe an Werbepartner oder Dritte findet + nicht statt. +

    +

    + Rechtsgrundlage ist Art. 6 Abs. 1 lit. f DSGVO. Unser + berechtigtes Interesse liegt in der statistischen + Auswertung des Nutzungsverhaltens zur Verbesserung + unseres Angebots. Da nach 24 Stunden kein Bezug zu + einer einzelnen Sitzung mehr hergestellt werden kann, + werden die verbleibenden aggregierten Kennzahlen + (Seitenaufrufe, Ereignisse, Herkunftsland) unbefristet + zu statistischen Zwecken vorgehalten. Sie sind + anonym und lassen keinen Rückschluss auf einzelne + Personen zu. +

    +

    + Wir respektieren das Do-Not-Track-Signal{" "} + Ihres Browsers: Ist DNT aktiviert, wird die + Reichweitenmessung für Ihren Besuch vollständig + deaktiviert - es werden keinerlei Ereignisse an + unsere Instanz übermittelt. Alternativ können Sie + uns per E-Mail (siehe Ziffer 1) kontaktieren.

    @@ -350,13 +436,11 @@ function DatenschutzPage() {

    - Stand: August 2026 + Stand: September 2026

  • - -