feat: Add new project components, implement Tailwind CSS, and update existing content and dependencies.

This commit is contained in:
Simon Altschäffl 2026-02-17 11:32:17 +01:00
parent 7b0be73de9
commit 97e1758b16
25 changed files with 2564 additions and 2042 deletions

3
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,3 @@
{
"css.lint.unknownAtRules": "ignore"
}

583
package-lock.json generated
View File

@ -21,6 +21,11 @@
"react-router-dom": "^7.5.2",
"react-scripts": "5.0.1",
"web-vitals": "^2.1.4"
},
"devDependencies": {
"autoprefixer": "^10.4.24",
"postcss": "^8.5.6",
"tailwindcss": "^3.4.19"
}
},
"node_modules/@adobe/css-tools": {
@ -82,7 +87,6 @@
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.10.tgz",
"integrity": "sha512-vMqyb7XCDMPvJFFOaT9kxtiRh42GwlZEg1/uIgtZshS5a/8OaduUfCi7kynKgc3Tw/6Uo2D+db9qBttghhmxwQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"@ampproject/remapping": "^2.2.0",
"@babel/code-frame": "^7.26.2",
@ -723,7 +727,6 @@
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.26.0.tgz",
"integrity": "sha512-B+O2DnPc0iG+YXFqOxv2WNuNU97ToWjOomUQ78DouOENWUaM5sVrmet9mcomUGQFwpJd//gvUagXBSdzO1fRKg==",
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.25.9"
},
@ -1588,7 +1591,6 @@
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.25.9.tgz",
"integrity": "sha512-s5XwpQYCqGerXl+Pu6VDL3x0j2d82eiV77UJ8a2mDHAW7j9SWRqQ2y1fNo1Z74CdcYipl5Z41zvjj4Nfzq36rw==",
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/helper-annotate-as-pure": "^7.25.9",
"@babel/helper-module-imports": "^7.25.9",
@ -2507,96 +2509,6 @@
"deprecated": "Use @eslint/object-schema instead",
"license": "BSD-3-Clause"
},
"node_modules/@isaacs/cliui": {
"version": "8.0.2",
"resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
"integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==",
"license": "ISC",
"dependencies": {
"string-width": "^5.1.2",
"string-width-cjs": "npm:string-width@^4.2.0",
"strip-ansi": "^7.0.1",
"strip-ansi-cjs": "npm:strip-ansi@^6.0.1",
"wrap-ansi": "^8.1.0",
"wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0"
},
"engines": {
"node": ">=12"
}
},
"node_modules/@isaacs/cliui/node_modules/ansi-regex": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz",
"integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==",
"license": "MIT",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/chalk/ansi-regex?sponsor=1"
}
},
"node_modules/@isaacs/cliui/node_modules/ansi-styles": {
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz",
"integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==",
"license": "MIT",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/@isaacs/cliui/node_modules/string-width": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
"integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
"license": "MIT",
"dependencies": {
"eastasianwidth": "^0.2.0",
"emoji-regex": "^9.2.2",
"strip-ansi": "^7.0.1"
},
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/@isaacs/cliui/node_modules/strip-ansi": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
"integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
"license": "MIT",
"dependencies": {
"ansi-regex": "^6.0.1"
},
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/chalk/strip-ansi?sponsor=1"
}
},
"node_modules/@isaacs/cliui/node_modules/wrap-ansi": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
"integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==",
"license": "MIT",
"dependencies": {
"ansi-styles": "^6.1.0",
"string-width": "^5.0.1",
"strip-ansi": "^7.0.1"
},
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
}
},
"node_modules/@istanbuljs/load-nyc-config": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz",
@ -3046,16 +2958,6 @@
"node": ">= 8"
}
},
"node_modules/@pkgjs/parseargs": {
"version": "0.11.0",
"resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
"integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==",
"license": "MIT",
"optional": true,
"engines": {
"node": ">=14"
}
},
"node_modules/@pmmmwh/react-refresh-webpack-plugin": {
"version": "0.5.16",
"resolved": "https://registry.npmjs.org/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.16.tgz",
@ -3109,7 +3011,6 @@
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
"integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==",
"license": "MIT",
"peer": true,
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/popperjs"
@ -3546,7 +3447,6 @@
"resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.0.tgz",
"integrity": "sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/code-frame": "^7.10.4",
"@babel/runtime": "^7.12.5",
@ -4002,7 +3902,6 @@
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.2.tgz",
"integrity": "sha512-oxLPMytKchWGbnQM9O7D67uPa9paTNxO7jVoNMXgkkErULBPhPARCfkKL9ytcIJJRGjbsVwW4ugJzyFFvm/Tiw==",
"license": "MIT",
"peer": true,
"dependencies": {
"csstype": "^3.0.2"
}
@ -4129,7 +4028,6 @@
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz",
"integrity": "sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==",
"license": "MIT",
"peer": true,
"dependencies": {
"@eslint-community/regexpp": "^4.4.0",
"@typescript-eslint/scope-manager": "5.62.0",
@ -4183,7 +4081,6 @@
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.62.0.tgz",
"integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==",
"license": "BSD-2-Clause",
"peer": true,
"dependencies": {
"@typescript-eslint/scope-manager": "5.62.0",
"@typescript-eslint/types": "5.62.0",
@ -4553,7 +4450,6 @@
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz",
"integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==",
"license": "MIT",
"peer": true,
"bin": {
"acorn": "bin/acorn"
},
@ -4640,7 +4536,6 @@
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
"license": "MIT",
"peer": true,
"dependencies": {
"fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0",
@ -5036,9 +4931,9 @@
}
},
"node_modules/autoprefixer": {
"version": "10.4.21",
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.21.tgz",
"integrity": "sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ==",
"version": "10.4.24",
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.24.tgz",
"integrity": "sha512-uHZg7N9ULTVbutaIsDRoUkoS8/h3bdsmVJYZ5l3wv8Cp/6UIIoRDm90hZ+BwxUj/hGBEzLxdHNSKuFpn8WOyZw==",
"funding": [
{
"type": "opencollective",
@ -5055,10 +4950,9 @@
],
"license": "MIT",
"dependencies": {
"browserslist": "^4.24.4",
"caniuse-lite": "^1.0.30001702",
"fraction.js": "^4.3.7",
"normalize-range": "^0.1.2",
"browserslist": "^4.28.1",
"caniuse-lite": "^1.0.30001766",
"fraction.js": "^5.3.4",
"picocolors": "^1.1.1",
"postcss-value-parser": "^4.2.0"
},
@ -5375,6 +5269,15 @@
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
"license": "MIT"
},
"node_modules/baseline-browser-mapping": {
"version": "2.9.19",
"resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.19.tgz",
"integrity": "sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg==",
"license": "Apache-2.0",
"bin": {
"baseline-browser-mapping": "dist/cli.js"
}
},
"node_modules/batch": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz",
@ -5539,9 +5442,9 @@
"license": "BSD-2-Clause"
},
"node_modules/browserslist": {
"version": "4.24.4",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.4.tgz",
"integrity": "sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==",
"version": "4.28.1",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz",
"integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==",
"funding": [
{
"type": "opencollective",
@ -5557,12 +5460,12 @@
}
],
"license": "MIT",
"peer": true,
"dependencies": {
"caniuse-lite": "^1.0.30001688",
"electron-to-chromium": "^1.5.73",
"node-releases": "^2.0.19",
"update-browserslist-db": "^1.1.1"
"baseline-browser-mapping": "^2.9.0",
"caniuse-lite": "^1.0.30001759",
"electron-to-chromium": "^1.5.263",
"node-releases": "^2.0.27",
"update-browserslist-db": "^1.2.0"
},
"bin": {
"browserslist": "cli.js"
@ -5707,9 +5610,9 @@
}
},
"node_modules/caniuse-lite": {
"version": "1.0.30001714",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001714.tgz",
"integrity": "sha512-mtgapdwDLSSBnCI3JokHM7oEQBLxiJKVRtg10AxM1AyeiKcM96f0Mkbqeq+1AbiCtvMcHRulAAEMu693JrSWqg==",
"version": "1.0.30001770",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001770.tgz",
"integrity": "sha512-x/2CLQ1jHENRbHg5PSId2sXq1CIO1CISvwWAj027ltMVG2UNgW+w9oH2+HzgEIRFembL8bUlXtfbBHR1fCg2xw==",
"funding": [
{
"type": "opencollective",
@ -6670,7 +6573,6 @@
"resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.33.1.tgz",
"integrity": "sha512-iJc4TwyANnOGR1OmWhsS9ayRS3s+XQ185FmuHObThD+5AeJCakAAbWv8KimMTt08xCCLNgneQwFp+JRJOr9qGQ==",
"license": "MIT",
"peer": true,
"engines": {
"node": ">=0.10"
}
@ -7053,7 +6955,6 @@
"resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz",
"integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==",
"license": "ISC",
"peer": true,
"engines": {
"node": ">=12"
}
@ -7662,12 +7563,6 @@
"integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==",
"license": "MIT"
},
"node_modules/eastasianwidth": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
"integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==",
"license": "MIT"
},
"node_modules/ee-first": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
@ -7690,9 +7585,9 @@
}
},
"node_modules/electron-to-chromium": {
"version": "1.5.138",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.138.tgz",
"integrity": "sha512-FWlQc52z1dXqm+9cCJ2uyFgJkESd+16j6dBEjsgDNuHjBpuIzL8/lRc0uvh1k8RNI6waGo6tcy2DvwkTBJOLDg==",
"version": "1.5.286",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.286.tgz",
"integrity": "sha512-9tfDXhJ4RKFNerfjdCcZfufu49vg620741MNs26a9+bhLThdB+plgMeou98CAaHu/WATj2iHOOHTp1hWtABj2A==",
"license": "ISC"
},
"node_modules/elkjs": {
@ -8019,7 +7914,6 @@
"integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==",
"deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.",
"license": "MIT",
"peer": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.6.1",
@ -9102,34 +8996,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/foreground-child": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz",
"integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==",
"license": "ISC",
"dependencies": {
"cross-spawn": "^7.0.6",
"signal-exit": "^4.0.1"
},
"engines": {
"node": ">=14"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/foreground-child/node_modules/signal-exit": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
"integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
"license": "ISC",
"engines": {
"node": ">=14"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/fork-ts-checker-webpack-plugin": {
"version": "6.5.3",
"resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-6.5.3.tgz",
@ -9260,15 +9126,15 @@
}
},
"node_modules/fraction.js": {
"version": "4.3.7",
"resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz",
"integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==",
"version": "5.3.4",
"resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-5.3.4.tgz",
"integrity": "sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==",
"license": "MIT",
"engines": {
"node": "*"
},
"funding": {
"type": "patreon",
"type": "github",
"url": "https://github.com/sponsors/rawify"
}
},
@ -10960,21 +10826,6 @@
"node": ">= 0.4"
}
},
"node_modules/jackspeak": {
"version": "3.4.3",
"resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz",
"integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==",
"license": "BlueOak-1.0.0",
"dependencies": {
"@isaacs/cliui": "^8.0.2"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
},
"optionalDependencies": {
"@pkgjs/parseargs": "^0.11.0"
}
},
"node_modules/jake": {
"version": "10.9.2",
"resolved": "https://registry.npmjs.org/jake/-/jake-10.9.2.tgz",
@ -10998,7 +10849,6 @@
"resolved": "https://registry.npmjs.org/jest/-/jest-27.5.1.tgz",
"integrity": "sha512-Yn0mADZB89zTtjkPJEXwrac3LHudkQMR+Paqa8uxJHCBr9agxztUifWCyiYrjhMPBoUVBjyny0I7XH6ozDr7QQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"@jest/core": "^27.5.1",
"import-local": "^3.0.2",
@ -13410,15 +13260,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/minipass": {
"version": "7.1.2",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
"integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==",
"license": "ISC",
"engines": {
"node": ">=16 || 14 >=14.17"
}
},
"node_modules/mkdirp": {
"version": "0.5.6",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
@ -13541,9 +13382,9 @@
"license": "MIT"
},
"node_modules/node-releases": {
"version": "2.0.19",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz",
"integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==",
"version": "2.0.27",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz",
"integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==",
"license": "MIT"
},
"node_modules/non-layered-tidy-tree-layout": {
@ -13561,15 +13402,6 @@
"node": ">=0.10.0"
}
},
"node_modules/normalize-range": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz",
"integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/normalize-url": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz",
@ -13908,12 +13740,6 @@
"node": ">=6"
}
},
"node_modules/package-json-from-dist": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz",
"integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==",
"license": "BlueOak-1.0.0"
},
"node_modules/param-case": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz",
@ -14030,28 +13856,6 @@
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
"license": "MIT"
},
"node_modules/path-scurry": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz",
"integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==",
"license": "BlueOak-1.0.0",
"dependencies": {
"lru-cache": "^10.2.0",
"minipass": "^5.0.0 || ^6.0.2 || ^7.0.0"
},
"engines": {
"node": ">=16 || 14 >=14.18"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/path-scurry/node_modules/lru-cache": {
"version": "10.4.3",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
"integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
"license": "ISC"
},
"node_modules/path-to-regexp": {
"version": "0.1.12",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz",
@ -14189,9 +13993,9 @@
}
},
"node_modules/postcss": {
"version": "8.5.3",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz",
"integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==",
"version": "8.5.6",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz",
"integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==",
"funding": [
{
"type": "opencollective",
@ -14207,9 +14011,8 @@
}
],
"license": "MIT",
"peer": true,
"dependencies": {
"nanoid": "^3.3.8",
"nanoid": "^3.3.11",
"picocolors": "^1.1.1",
"source-map-js": "^1.2.1"
},
@ -14637,9 +14440,19 @@
}
},
"node_modules/postcss-js": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz",
"integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==",
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.1.0.tgz",
"integrity": "sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==",
"funding": [
{
"type": "opencollective",
"url": "https://opencollective.com/postcss/"
},
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
],
"license": "MIT",
"dependencies": {
"camelcase-css": "^2.0.1"
@ -14647,10 +14460,6 @@
"engines": {
"node": "^12 || ^14 || >= 16"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/postcss/"
},
"peerDependencies": {
"postcss": "^8.4.21"
}
@ -14675,65 +14484,6 @@
"postcss": "^8.2"
}
},
"node_modules/postcss-load-config": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz",
"integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==",
"funding": [
{
"type": "opencollective",
"url": "https://opencollective.com/postcss/"
},
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
],
"license": "MIT",
"dependencies": {
"lilconfig": "^3.0.0",
"yaml": "^2.3.4"
},
"engines": {
"node": ">= 14"
},
"peerDependencies": {
"postcss": ">=8.0.9",
"ts-node": ">=9.0.0"
},
"peerDependenciesMeta": {
"postcss": {
"optional": true
},
"ts-node": {
"optional": true
}
}
},
"node_modules/postcss-load-config/node_modules/lilconfig": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz",
"integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==",
"license": "MIT",
"engines": {
"node": ">=14"
},
"funding": {
"url": "https://github.com/sponsors/antonk52"
}
},
"node_modules/postcss-load-config/node_modules/yaml": {
"version": "2.7.1",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.7.1.tgz",
"integrity": "sha512-10ULxpnOCQXxJvBgxsn9ptjq6uviG/htZKk9veJGhlqn3w/DxQ631zFF+nlQXLwmImeS5amR2dl2U8sg6U9jsQ==",
"license": "ISC",
"bin": {
"yaml": "bin.mjs"
},
"engines": {
"node": ">= 14"
}
},
"node_modules/postcss-loader": {
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-6.2.1.tgz",
@ -15395,7 +15145,6 @@
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz",
"integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==",
"license": "MIT",
"peer": true,
"dependencies": {
"cssesc": "^3.0.0",
"util-deprecate": "^1.0.2"
@ -15793,7 +15542,6 @@
"resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz",
"integrity": "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==",
"license": "MIT",
"peer": true,
"engines": {
"node": ">=0.10.0"
}
@ -15962,7 +15710,6 @@
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz",
"integrity": "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==",
"license": "MIT",
"peer": true,
"dependencies": {
"scheduler": "^0.26.0"
},
@ -16041,7 +15788,6 @@
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz",
"integrity": "sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A==",
"license": "MIT",
"peer": true,
"engines": {
"node": ">=0.10.0"
}
@ -16667,7 +16413,6 @@
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.2.tgz",
"integrity": "sha512-fS6iqSPZDs3dr/y7Od6y5nha8dW1YnbgtsyotCVvoFGKbERG++CVRFv1meyGDE1SNItQA8BrnCw7ScdAhRJ3XQ==",
"license": "MIT",
"peer": true,
"bin": {
"rollup": "dist/bin/rollup"
},
@ -16928,7 +16673,6 @@
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
"license": "MIT",
"peer": true,
"dependencies": {
"fast-deep-equal": "^3.1.3",
"fast-uri": "^3.0.1",
@ -17636,27 +17380,6 @@
"node": ">=8"
}
},
"node_modules/string-width-cjs": {
"name": "string-width",
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
"license": "MIT",
"dependencies": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
"strip-ansi": "^6.0.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/string-width-cjs/node_modules/emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
"license": "MIT"
},
"node_modules/string-width/node_modules/emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
@ -17796,19 +17519,6 @@
"node": ">=8"
}
},
"node_modules/strip-ansi-cjs": {
"name": "strip-ansi",
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
"license": "MIT",
"dependencies": {
"ansi-regex": "^5.0.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/strip-bom": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz",
@ -17908,17 +17618,17 @@
"license": "MIT"
},
"node_modules/sucrase": {
"version": "3.35.0",
"resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz",
"integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==",
"version": "3.35.1",
"resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.1.tgz",
"integrity": "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==",
"license": "MIT",
"dependencies": {
"@jridgewell/gen-mapping": "^0.3.2",
"commander": "^4.0.0",
"glob": "^10.3.10",
"lines-and-columns": "^1.1.6",
"mz": "^2.7.0",
"pirates": "^4.0.1",
"tinyglobby": "^0.2.11",
"ts-interface-checker": "^0.1.9"
},
"bin": {
@ -17929,15 +17639,6 @@
"node": ">=16 || 14 >=14.17"
}
},
"node_modules/sucrase/node_modules/brace-expansion": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
"license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0"
}
},
"node_modules/sucrase/node_modules/commander": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz",
@ -17947,41 +17648,6 @@
"node": ">= 6"
}
},
"node_modules/sucrase/node_modules/glob": {
"version": "10.4.5",
"resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz",
"integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==",
"license": "ISC",
"dependencies": {
"foreground-child": "^3.1.0",
"jackspeak": "^3.1.2",
"minimatch": "^9.0.4",
"minipass": "^7.1.2",
"package-json-from-dist": "^1.0.0",
"path-scurry": "^1.11.1"
},
"bin": {
"glob": "dist/esm/bin.mjs"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/sucrase/node_modules/minimatch": {
"version": "9.0.5",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
"integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
"license": "ISC",
"dependencies": {
"brace-expansion": "^2.0.1"
},
"engines": {
"node": ">=16 || 14 >=14.17"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
@ -18190,9 +17856,9 @@
"license": "MIT"
},
"node_modules/tailwindcss": {
"version": "3.4.17",
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.17.tgz",
"integrity": "sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og==",
"version": "3.4.19",
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.19.tgz",
"integrity": "sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==",
"license": "MIT",
"dependencies": {
"@alloc/quick-lru": "^5.2.0",
@ -18203,7 +17869,7 @@
"fast-glob": "^3.3.2",
"glob-parent": "^6.0.2",
"is-glob": "^4.0.3",
"jiti": "^1.21.6",
"jiti": "^1.21.7",
"lilconfig": "^3.1.3",
"micromatch": "^4.0.8",
"normalize-path": "^3.0.0",
@ -18212,7 +17878,7 @@
"postcss": "^8.4.47",
"postcss-import": "^15.1.0",
"postcss-js": "^4.0.1",
"postcss-load-config": "^4.0.2",
"postcss-load-config": "^4.0.2 || ^5.0 || ^6.0",
"postcss-nested": "^6.2.0",
"postcss-selector-parser": "^6.1.2",
"resolve": "^1.22.8",
@ -18238,6 +17904,48 @@
"url": "https://github.com/sponsors/antonk52"
}
},
"node_modules/tailwindcss/node_modules/postcss-load-config": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-6.0.1.tgz",
"integrity": "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==",
"funding": [
{
"type": "opencollective",
"url": "https://opencollective.com/postcss/"
},
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
],
"license": "MIT",
"dependencies": {
"lilconfig": "^3.1.1"
},
"engines": {
"node": ">= 18"
},
"peerDependencies": {
"jiti": ">=1.21.0",
"postcss": ">=8.0.9",
"tsx": "^4.8.1",
"yaml": "^2.4.2"
},
"peerDependenciesMeta": {
"jiti": {
"optional": true
},
"postcss": {
"optional": true
},
"tsx": {
"optional": true
},
"yaml": {
"optional": true
}
}
},
"node_modules/tapable": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz",
@ -18413,6 +18121,51 @@
"integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==",
"license": "MIT"
},
"node_modules/tinyglobby": {
"version": "0.2.15",
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz",
"integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==",
"license": "MIT",
"dependencies": {
"fdir": "^6.5.0",
"picomatch": "^4.0.3"
},
"engines": {
"node": ">=12.0.0"
},
"funding": {
"url": "https://github.com/sponsors/SuperchupuDev"
}
},
"node_modules/tinyglobby/node_modules/fdir": {
"version": "6.5.0",
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
"integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
"license": "MIT",
"engines": {
"node": ">=12.0.0"
},
"peerDependencies": {
"picomatch": "^3 || ^4"
},
"peerDependenciesMeta": {
"picomatch": {
"optional": true
}
}
},
"node_modules/tinyglobby/node_modules/picomatch": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"license": "MIT",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/jonschlinkert"
}
},
"node_modules/tmpl": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz",
@ -18609,7 +18362,6 @@
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz",
"integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==",
"license": "(MIT OR CC0-1.0)",
"peer": true,
"engines": {
"node": ">=10"
},
@ -18968,9 +18720,9 @@
}
},
"node_modules/update-browserslist-db": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz",
"integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==",
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz",
"integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==",
"funding": [
{
"type": "opencollective",
@ -19235,7 +18987,6 @@
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.99.6.tgz",
"integrity": "sha512-TJOLrJ6oeccsGWPl7ujCYuc0pIq2cNsuD6GZDma8i5o5Npvcco/z+NKvZSFsP0/x6SShVb0+X2JK/JHUjKY9dQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"@types/eslint-scope": "^3.7.7",
"@types/estree": "^1.0.6",
@ -19305,7 +19056,6 @@
"resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.15.2.tgz",
"integrity": "sha512-0XavAZbNJ5sDrCbkpWL8mia0o5WPOd2YGtxrEiZkBK9FjLppIUK2TgxK6qGD2P3hUXTJNNPVibrerKcx5WkR1g==",
"license": "MIT",
"peer": true,
"dependencies": {
"@types/bonjour": "^3.5.9",
"@types/connect-history-api-fallback": "^1.3.5",
@ -19718,7 +19468,6 @@
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
"license": "MIT",
"peer": true,
"dependencies": {
"fast-deep-equal": "^3.1.3",
"fast-uri": "^3.0.1",
@ -19970,24 +19719,6 @@
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
}
},
"node_modules/wrap-ansi-cjs": {
"name": "wrap-ansi",
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
"license": "MIT",
"dependencies": {
"ansi-styles": "^4.0.0",
"string-width": "^4.1.0",
"strip-ansi": "^6.0.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
}
},
"node_modules/wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",

View File

@ -8,11 +8,11 @@
"@testing-library/react": "^16.3.0",
"@testing-library/user-event": "^13.5.0",
"bootstrap": "^5.3.5",
"mermaid": "^10.9.1",
"react": "^19.1.0",
"react-bootstrap": "^2.10.9",
"react-dom": "^19.1.0",
"react-jupyter-notebook-viewer": "^1.1.13",
"mermaid": "^10.9.1",
"react-router-dom": "^7.5.2",
"react-scripts": "5.0.1",
"web-vitals": "^2.1.4"
@ -40,5 +40,10 @@
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"autoprefixer": "^10.4.24",
"postcss": "^8.5.6",
"tailwindcss": "^3.4.19"
}
}

6
postcss.config.js Normal file
View File

@ -0,0 +1,6 @@
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}

View File

@ -2,85 +2,96 @@ import React from "react";
function AboutPage() {
return (
<section>
<div className="content-group">
<h1>&Uuml;ber mich</h1>
<div style={{ marginTop: "1.5em" }}>
<section className="max-w-4xl mx-auto px-4 py-12 font-sans text-slate-800">
<div className="mb-12">
<h1 className="text-4xl font-extrabold text-slate-900 mb-8 text-center">&Uuml;ber mich</h1>
<div className="mt-6 text-lg leading-relaxed text-slate-700 bg-slate-50 p-6 rounded-xl border border-slate-100 shadow-sm">
<p>
<b>
Willkommen auf meiner Seite! Als angehender Data Scientist mit
Hintergrund in Wirtschaftsinformatik chte ich Ihnen hier meine
Leidenschaft für die Datenanalyse und künstliche Intelligenz
näherbringen. Mein Ziel ist es, durch die Analyse komplexer
Datensätze wertvolle Erkenntnisse zu gewinnen und innovative
Lösungen zu entwickeln.
Willkommen auf meiner Seite! Als angehender Wirtschaftsinformatiker
m&ouml;chte ich Ihnen hier meine Leidenschaft f&uuml;r die Softwareentwicklung
und Data Science n&auml;herbringen. Mein Ziel ist es, innovative Anwendungen
zu entwickeln und durch die Analyse komplexer Daten wertvolle
Erkenntnisse zu gewinnen. Die Kombination aus technischer Umsetzung
und analytischem Denken treibt mich dabei an.
</b>
</p>
<h2>Meine Vision in Data Science</h2>
<h3>Der Weg zur Datenanalyse</h3>
<p>
Meine Reise in die Welt der Daten begann mit der Entdeckung der
Programmierung und entwickelte sich schnell zu einer Faszination für
die Möglichkeiten der Datenanalyse. Was als allgemeines Interesse
an Computern begann, hat sich zu einer gezielten Spezialisierung
im Bereich Data Science entwickelt. Die Fähigkeit, aus rohen Daten
wertvolle Erkenntnisse zu gewinnen und diese für fundierte
Entscheidungen zu nutzen, treibt mich besonders an.
</p>
<h3>Meine Spezialisierung in Data Science</h3>
<p>
Meine Begeisterung für Data Science wurde durch den{" "}
<b>CS50X</b> <em>(Harvard University)</em> Kurs geweckt, wo ich die
Grundlagen der Datenverarbeitung kennenlernte. Der intensive{" "}
<b>IBM Data Science Professional Certificate</b> vertiefte diese
Faszination und gab mir praktische Einblicke in Machine Learning
und prädiktive Analysen. Besonders die Möglichkeit, durch
Datenmodelle neue Erkenntnisse zu gewinnen und Vorhersagen zu
treffen, hat mich überzeugt, dass dies der richtige Weg für mich
ist.
</p>
<h3>Technische Infrastruktur und Tools</h3>
<p>
Um meine Data Science Projekte optimal umzusetzen, habe ich eine
eigene technische Infrastruktur aufgebaut, zu der auch dieser
Server gehört. Er bietet mir eine <b>JupyterHub-Umgebung</b> für
Datenanalysen und Machine Learning Experimente. Die{" "}
<em>Server-Administration</em> und DevOps-Kenntnisse sehe ich als
wichtige Ergänzung zu meinen Data Science Fähigkeiten, da sie mir
ermöglichen, meine Analysen und Modelle effizient zu
deployen und zu skalieren.
</p>
</div>
<div>
<h2>Expertise und Weiterbildung</h2>
<h3>Fundierte Ausbildung in Data Science</h3>
<p>
Meine Expertise basiert auf einer Kombination aus strukturierter
Ausbildung und praktischer Erfahrung. An der EDV-Schule Plattling
erhalte ich eine solide Grundlage in Wirtschaftsinformatik, die ich
gezielt durch spezialisierte Kurse wie <b>CS50X</b> und den{" "}
<b>IBM Data Science Professional Certificate</b> in Richtung Data
Science ausbaue. Diese Kombination ermöglicht mir, sowohl die
technischen Aspekte der Datenanalyse als auch deren
wirtschaftliche Anwendungen zu verstehen.
</p>
<h3>Aktuelle Projekte und Karriereziele</h3>
<p>
Aktuell arbeite ich an drei spannenden Projekten, die verschiedene
Aspekte der Softwareentwicklung abdecken. Mein <b>ABAP-Abschlussprojekt</b>
ist eine Plattform für Wohnungssuche und Mitfahrgelegenheiten, die
praktische Alltagsprobleme löst. Parallel entwickle ich in einem
<b>Java-Projekt</b> ein Online-Casino, das mir tiefere Einblicke in
Backend-Entwicklung und Datenverwaltung ermöglicht. Besonders
faszinierend ist mein privates <b>KI-Projekt</b> - ein Krimi-Dinner
mit einem KI-Gamemaster, bei dem ich mich intensiv mit
Prompt-Engineering und der praktischen Anwendung von Large Language
Models beschäftige. Diese Erfahrungen im Bereich KI und Prompting
sehe ich als wichtige Grundlage für meinen angestrebten Einstieg in
die Data Science, da sie mir ein tiefes Verständnis für die
Möglichkeiten und Grenzen von KI-Systemen vermitteln.
</p>
<div className="mt-12 space-y-8">
<h2 className="text-2xl font-bold text-slate-900 border-b pb-2">Meine Vision in der Informatik</h2>
<div>
<h3 className="text-xl font-semibold text-slate-800 mb-3">Der Weg in die IT</h3>
<p className="text-slate-600 leading-relaxed">
Meine Reise in die Welt der Technologie begann mit der Entdeckung der
Programmierung und entwickelte sich schnell zu einer Faszination f&uuml;r
die vielf&auml;ltigen M&ouml;glichkeiten der IT. Was als allgemeines Interesse
an Computern begann, hat sich zu einer gezielten Spezialisierung
sowohl im Bereich der Applikationsentwicklung als auch in Data Science
entwickelt. Die F&auml;higkeit, Probleme durch Code zu l&ouml;sen und Daten
nutzbar zu machen, begeistert mich jeden Tag aufs Neue.
</p>
</div>
<div>
<h3 className="text-xl font-semibold text-slate-800 mb-3">Meine Spezialisierung</h3>
<p className="text-slate-600 leading-relaxed">
Meine Begeisterung f&uuml;r die Informatik wird durch ein breites Spektrum
an Interessen getragen. Durch den <b>CS50X</b> <em>(Harvard University)</em> Kurs
habe ich ein tiefes Verst&auml;ndnis f&uuml;r die Grundlagen der Informatik erlangt.
Gleichzeitig vertiefte der <b>IBM Data Science Professional Certificate</b> mein
Wissen in Machine Learning und Datenanalyse. Ich sehe mich als Entwickler,
der sowohl backend-seitige Logik und Datenbanken beherrscht, als auch
moderne KI-Modelle integrieren und nutzen kann.
</p>
</div>
<div>
<h3 className="text-xl font-semibold text-slate-800 mb-3">Technische Infrastruktur und Tools</h3>
<p className="text-slate-600 leading-relaxed">
Um meine Projekte optimal umzusetzen, nutze ich eine vielseitige
Infrastruktur. Dazu geh&ouml;rt mein eigener Server, auf dem ich Dienste
hoste und Experimente durchf&uuml;hre. Er bietet mir unter anderem eine{" "}
<b>JupyterHub-Umgebung</b> f&uuml;r Datenanalysen. Kenntnisse in{" "}
<em>Server-Administration</em>, Deployment und DevOps sehe ich als
essentiell an, um robuste und skalierbare Anwendungen zu entwickeln,
die &uuml;ber den reinen Code hinausgehen.
</p>
</div>
</div>
<div className="mt-12 space-y-8">
<h2 className="text-2xl font-bold text-slate-900 border-b pb-2">Expertise und Weiterbildung</h2>
<div>
<h3 className="text-xl font-semibold text-slate-800 mb-3">Fundierte Ausbildung in Data Science</h3>
<p className="text-slate-600 leading-relaxed">
Meine Expertise basiert auf einer Kombination aus strukturierter
Ausbildung und praktischer Erfahrung. An der EDV-Schule Plattling
erhalte ich eine solide Grundlage in Wirtschaftsinformatik, die ich
gezielt durch spezialisierte Kurse wie <b>CS50X</b> und den{" "}
<b>IBM Data Science Professional Certificate</b> in Richtung Data
Science ausbaue. Diese Kombination erm&ouml;glicht mir, sowohl die
technischen Aspekte der Datenanalyse als auch deren
wirtschaftliche Anwendungen zu verstehen.
</p>
</div>
<div>
<h3 className="text-xl font-semibold text-slate-800 mb-3">Aktuelle Projekte</h3>
<p className="text-slate-600 leading-relaxed">
Aktuell fokussiere ich mich auf meine Abschlussprojekte an der EDV-Schule:
Ein <b>ABAP-Projekt</b> (Plattform f&uuml;r Wohnungssuche) und ein{" "}
<b>Java-Projekt</b> (Online-Casino), welche mir fundierte Kenntnisse in
Softwarearchitektur und Datenbanken vermitteln.
Besonders am Herzen liegt mir mein privates Projekt: Ein <b>KI-Sprachenlern-Roleplay</b>.
Hier verbinde ich moderne Webtechnologien mit Large Language Models, um
ein interaktives Lernerlebnis zu schaffen. Dieses Projekt demonstriert
meine F&auml;higkeit, komplexe KI-Systeme in nutzerfreundliche Anwendungen
zu integrieren.
</p>
</div>
</div>
</div>
</section>

View File

@ -13,6 +13,8 @@ import LanguagestudyPage from "./projects/languageStudy";
import OnlineCasinoPage from "./finalprojects/onlineCasino";
import WohnungUndFahrgemeinschaftenPage from "./finalprojects/wohnungUndFahrgemeinschaften";
import KrimiDinnerPage from "./projects/krimiDinner";
import LanguageRoleplayPage from "./projects/languageRoleplay";
import TdotPage from "./projects/tdot";
function Home() {
return <HomePage />;
@ -35,8 +37,8 @@ function Impressum() {
return <ImpressumSide />;
}
function Privacy(){
return <PrivacyPage />;
function Privacy() {
return <PrivacyPage />;
}
function LanguageStudy() {
@ -59,6 +61,14 @@ function KrimiDinner() {
return <KrimiDinnerPage />
}
function LanguageRoleplay() {
return <LanguageRoleplayPage />
}
function Tdot() {
return <TdotPage />
}
function App() {
return (
<Router>
@ -76,6 +86,8 @@ function App() {
<Route path="/finalprojects/onlineCasino" element={<OnlineCasino />} />
<Route path="/finalprojects/wufg" element={<WohnungUndFahrgemeinschaften />} />
<Route path="/projects/crime-dinner" element={<KrimiDinner />} />
<Route path="/projects/language-roleplay" element={<LanguageRoleplay />} />
<Route path="/projects/tdot" element={<Tdot />} />
</Routes>
</div>
<FooterSection />

View File

@ -2,19 +2,19 @@ import React from "react";
function ContactPage() {
return (
<section className="centered">
<h1>Kontakt</h1>
<div>
<p>
<section className="max-w-3xl mx-auto px-4 py-12 text-center font-sans text-slate-800">
<h1 className="text-4xl font-extrabold text-slate-900 mb-8">Kontakt</h1>
<div className="bg-white p-8 rounded-xl border border-slate-200 shadow-sm max-w-xl mx-auto">
<p className="text-lg leading-relaxed text-slate-700 mb-6">
Sie erreichen mich am besten per E-Mail unter{" "}
<a href="mailto:info@simonaltschaeffl.de">
<a href="mailto:info@simonaltschaeffl.de" className="text-blue-600 hover:text-blue-800 font-medium hover:underline">
info@simonaltschaeffl.de
</a>{" "}
<br /> oder per Telefon unter{" "}
<a href="tel:+4915157852478">+49 1515 7852478</a>. <br />
<a href="tel:+4915157852478" className="text-blue-600 hover:text-blue-800 font-medium hover:underline">+49 1515 7852478</a>. <br />
</p>
<p style={{ marginTop: '1.5em' }}>
<em>Bitte beachten Sie</em>, dass es w&auml;hrend meiner Schulzeiten zu <br />
<p className="text-slate-600 p-4 bg-slate-50 rounded-lg border border-slate-100 text-sm">
<em className="font-semibold not-italic text-slate-800">Bitte beachten Sie</em>, dass es w&auml;hrend meiner Schulzeiten zu <br />
Verz&ouml;gerungen bei der Beantwortung kommen kann. Ich bem&uuml;he mich <br />
jedoch, Ihre Anfrage <b>so schnell wie m&ouml;glich</b> zu beantworten.
</p>

View File

@ -1,33 +1,151 @@
import React from "react";
import React, { useEffect } from "react";
import mermaid from "mermaid";
function OnlineCasinoPage() {
return (
<section className="content-group">
<h1 className="project-header">Online Casino</h1>
<p className="centered" style={{ marginTop: '1em' }}>
<em>Dieses Projekt ist derzeit in der Planungsphase.</em>
</p>
<div>
<h2 style={{ marginTop: '2em' }}>Worum geht es in diesem Projekt?</h2>
<p>
Dieses Projekt ist mein Abschlussprojekt. Das Ziel ist es, ein Online-Casino von Grund auf zu entwickeln.
Weitere Details zum Projekt werden hinzugefügt, sobald die Planungsphase abgeschlossen ist.
</p>
const Wireframe = ({ title, children }) => (
<div className="w-full md:w-1/2 lg:w-1/3 px-2 mb-4">
<div className="h-full bg-white rounded-lg shadow-sm border border-slate-200 overflow-hidden flex flex-col">
<div className="bg-slate-50 px-4 py-2 border-b border-slate-200">
<h5 className="text-center font-semibold text-slate-700 m-0 text-sm md:text-base">{title}</h5>
</div>
<div>
<h2 style={{ marginTop: '2em' }}>
Welche Techniken, Technologien und Bibliotheken werde ich verwenden?
</h2>
<div className="list-display">
<ul className="key-points">
<li>
<b>Programmiersprache</b>: Java
</li>
</ul>
<div className="p-2 flex-grow flex justify-center items-center overflow-hidden bg-slate-100">
<div className="bg-white w-full h-full border border-slate-200 rounded-lg shadow-inner p-3 flex flex-col overflow-hidden relative" style={{ aspectRatio: '9 / 19.5' }}>
{children}
</div>
</div>
</section>
</div>
</div>
);
function OnlineCasino() {
useEffect(() => {
const initMermaid = async () => {
try {
mermaid.initialize({ startOnLoad: false, theme: 'neutral' });
const mermaidEls = document.querySelectorAll('.mermaid');
if (mermaidEls.length > 0) {
await mermaid.run();
}
} catch (err) {
console.error("Mermaid initialization or run error:", err);
}
};
// Slight delay to ensure DOM is ready
const timer = setTimeout(() => {
initMermaid();
}, 100);
return () => clearTimeout(timer);
}, []);
return (
<div className="bg-slate-50 min-h-screen py-8 font-sans text-slate-800">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<header className="text-center border-b border-slate-200 pb-8 mb-12">
<h1 className="text-3xl md:text-5xl font-extrabold text-slate-900 mb-6 tracking-tight">Online Casino (Abschlussprojekt)</h1>
<div className="mt-6 flex flex-wrap justify-center gap-4">
<div className="bg-white px-4 py-2 rounded-full border border-slate-200 shadow-sm flex items-center space-x-2">
<span className="bg-slate-200 text-slate-700 text-xs font-bold px-2 py-0.5 rounded uppercase tracking-wide">Status</span>
<span className="text-sm font-medium text-slate-600">In Entwicklung</span>
</div>
<div className="bg-white px-4 py-2 rounded-full border border-slate-200 shadow-sm flex items-center space-x-2">
<span className="bg-slate-200 text-slate-700 text-xs font-bold px-2 py-0.5 rounded uppercase tracking-wide">Team</span>
<span className="text-sm font-medium text-slate-600">5 Personen</span>
</div>
<div className="bg-white px-4 py-2 rounded-full border border-slate-200 shadow-sm flex items-center space-x-2">
<span className="bg-slate-200 text-slate-700 text-xs font-bold px-2 py-0.5 rounded uppercase tracking-wide">Rolle</span>
<span className="text-sm font-medium text-slate-600">Lead Poker (Full Stack Vertical)</span>
</div>
</div>
</header>
<section className="mb-16">
<h2 className="text-2xl font-bold text-slate-900 mb-6 border-l-4 border-indigo-500 pl-4">1. Projektübersicht</h2>
<div className="bg-white p-6 rounded-xl border border-slate-200 shadow-sm space-y-4">
<p className="text-lg leading-relaxed text-slate-700">
Dieses fiktive Online-Casino entsteht als Abschlussprojekt in einem 5-köpfigen Team.
Ziel ist die Entwicklung einer skalierbaren Plattform mit verschiedenen Glücksspielen (ohne Echtgeldeinsatz),
einem Admin-Dashboard und simulierten Finanztransaktionen.
</p>
</div>
</section>
<section className="mb-16">
<h2 className="text-2xl font-bold text-slate-900 mb-6 border-l-4 border-indigo-500 pl-4">2. Mein Verantwortungsbereich: Der gesamte Poker-Stack</h2>
<div className="grid grid-cols-1 md:grid-cols-2 gap-6 mt-6">
<div className="h-full">
<div className="h-full bg-white rounded-xl border border-slate-200 shadow-sm p-6 hover:shadow-md transition-shadow flex flex-col">
<h3 className="text-xl font-bold text-slate-800 mb-4 pb-2 border-b border-slate-100">Backend, DB & Engine</h3>
<ul className="list-disc pl-5 space-y-2 text-slate-700 flex-grow">
<li><strong>Poker Engine (Core):</strong> Modulare Java-Library für die komplette Spiellogik (Runden, Pötte, Gewinner).</li>
<li><strong>API Layer:</strong> Implementierung der WebSocket-Controller für Echtzeit-Kommunikation.</li>
<li><strong>Datenbank:</strong> Design und Implementierung der JPA-Entities und Repositories für alle Poker-bezogenen Daten.</li>
</ul>
<div className="mt-4 pt-4 border-t border-slate-100">
<a href="https://github.com/simon-266/poker-engine" target="_blank" rel="noopener noreferrer" className="text-indigo-600 hover:text-indigo-800 font-bold inline-flex items-center">
<svg className="w-4 h-4 mr-2" fill="currentColor" viewBox="0 0 24 24" aria-hidden="true"><path fillRule="evenodd" d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z" clipRule="evenodd"></path></svg>
GitHub Repository
</a>
</div>
</div>
</div>
<div className="h-full">
<div className="h-full bg-white rounded-xl border border-slate-200 shadow-sm p-6 hover:shadow-md transition-shadow">
<h3 className="text-xl font-bold text-slate-800 mb-4 pb-2 border-b border-slate-100">Frontend & UI</h3>
<ul className="list-disc pl-5 space-y-2 text-slate-700">
<li><strong>React Implementation:</strong> Entwicklung des kompletten Poker-Interfaces im Browser.</li>
<li><strong>Echtzeit-Updates:</strong> Verarbeitung der WebSocket-Events zur sofortigen Anzeige von Spielzügen.</li>
<li><strong>UX/UI:</strong> Design der Tische, Kartenanimationen und Bedienelemente.</li>
</ul>
</div>
</div>
</div>
</section>
<section className="mb-16">
<h2 className="text-2xl font-bold text-slate-900 mb-6 border-l-4 border-indigo-500 pl-4">3. Technische Architektur</h2>
<div className="bg-white p-6 rounded-xl border border-slate-200 shadow-sm overflow-x-auto">
<div className="mermaid flex justify-center">
{`graph TD
subgraph "Mein Verantwortungsbereich (Poker Vertical)"
Frontend[React Poker UI]
WS_Endpoint[WebSocket Controller]
Service[Poker Service Layer]
Engine["Poker Engine (Library)"]
Repo[JPA Repository]
DB[(Poker Database Tables)]
end
Other[Andere Casino Module]
Frontend -- "WebSocket Messages" --> WS_Endpoint
WS_Endpoint -- "Delegiert an" --> Service
Service -- "Steuert" --> Engine
Engine -- "Eventhandler" --> Service
Service -- "Pusht Updates" --> Frontend
Service -- "Persistiert" --> Repo
Repo --> DB`}
</div>
</div>
</section>
<section className="mb-16">
<h2 className="text-2xl font-bold text-slate-900 mb-6 border-l-4 border-indigo-500 pl-4">4. Tech Stack</h2>
<div className="bg-slate-50 p-6 rounded-xl border border-slate-200">
<div className="grid grid-cols-2 md:grid-cols-4 gap-4">
<div className="bg-white p-4 rounded shadow-sm text-center font-semibold text-slate-700">Java</div>
<div className="bg-white p-4 rounded shadow-sm text-center font-semibold text-slate-700">Spring Boot</div>
<div className="bg-white p-4 rounded shadow-sm text-center font-semibold text-slate-700">JPA / Hibernate</div>
<div className="bg-white p-4 rounded shadow-sm text-center font-semibold text-slate-700">WebSockets</div>
<div className="bg-white p-4 rounded shadow-sm text-center font-semibold text-slate-700">React</div>
<div className="bg-white p-4 rounded shadow-sm text-center font-semibold text-slate-700">Maven</div>
</div>
</div>
</section>
</div>
</div>
);
}
export default OnlineCasinoPage;
export default OnlineCasino;

View File

@ -2,42 +2,203 @@ import React from "react";
function WohnungUndFahrgemeinschaftenPage() {
return (
<section className="content-group">
<h1 className="project-header">Wohnungs- und Fahrgemeinschaften (SAP Fiori)</h1>
<p className="centered" style={{ marginTop: '1em' }}>
<em>Dieses Projekt ist mein ABAP-Abschlussprojekt für die Schule und befindet sich in der Planungsphase.</em>
</p>
<div>
<h2 style={{ marginTop: '2em' }}>Projektziel</h2>
<p>
Ziel ist die Entwicklung einer SAP-Fiori-Anwendung, die es Benutzern ermöglicht, Wohnungsangebote und Fahrgemeinschaften einfach zu verwalten. Die Applikation wird als SAP-RAP-Backend mit einem Fiori-Frontend umgesetzt.
</p>
<div className="bg-slate-50 min-h-screen py-8 font-sans text-slate-800">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
{/* --- HEADER --- */}
<header className="text-center border-b border-slate-200 pb-8 mb-12">
<h1 className="text-3xl md:text-5xl font-extrabold text-slate-900 mb-6 tracking-tight">
Zenith Marketplace
</h1>
<p className="text-xl text-slate-600 max-w-3xl mx-auto mb-6">
Schulinterne Börse für Wohnungen & Fahrgemeinschaften (SAP Fiori)
</p>
<div className="mt-6 flex flex-wrap justify-center gap-4">
<div className="bg-white px-4 py-2 rounded-full border border-slate-200 shadow-sm flex items-center space-x-2">
<span className="bg-slate-200 text-slate-700 text-xs font-bold px-2 py-0.5 rounded uppercase tracking-wide">Status</span>
<span className="text-sm font-medium text-slate-600">In Entwicklung (Alpha)</span>
</div>
<div className="bg-white px-4 py-2 rounded-full border border-slate-200 shadow-sm flex items-center space-x-2">
<span className="bg-slate-200 text-slate-700 text-xs font-bold px-2 py-0.5 rounded uppercase tracking-wide">Typ</span>
<span className="text-sm font-medium text-slate-600">Abschlussprojekt (SAP)</span>
</div>
<div className="bg-white px-4 py-2 rounded-full border border-slate-200 shadow-sm flex items-center space-x-2">
<span className="bg-slate-200 text-slate-700 text-xs font-bold px-2 py-0.5 rounded uppercase tracking-wide">Rolle</span>
<span className="text-sm font-medium text-slate-600">Full Stack (RAP & Fiori)</span>
</div>
</div>
</header>
{/* --- PROJEKTÜBERSICHT --- */}
<section className="mb-16">
<h2 className="text-2xl font-bold text-slate-900 mb-6 border-l-4 border-indigo-500 pl-4">1. Projektübersicht</h2>
<div className="bg-white p-6 rounded-xl border border-slate-200 shadow-sm space-y-4">
<p className="text-lg leading-relaxed text-slate-700">
Dieses Abschlussprojekt digitalisiert das "Schwarze Brett" unserer Schule.
Die Anwendung <strong>Zenith Marketplace</strong> ermöglicht Schülern und Lehrern,
Wohnungsangebote zu inserieren und Fahrgemeinschaften zu organisieren.
</p>
<p className="text-lg leading-relaxed text-slate-700">
Dabei liegt der technische Fokus auf einer modernen <strong>SAP Fiori UX</strong> und einem robusten <strong>RAP-Backend</strong>.
</p>
</div>
</section>
{/* --- PFLICHTENHEFT & UI --- */}
<section className="mb-16">
<h2 className="text-2xl font-bold text-slate-900 mb-6 border-l-4 border-indigo-500 pl-4">2. Pflichtenheft & UI Konzept</h2>
<div className="bg-slate-50 border border-slate-200 rounded-xl p-4 mb-8 text-center shadow-sm">
<div className="w-full h-[600px] bg-white rounded-lg border border-slate-100 overflow-hidden mb-3">
<object
data="/assets/projects/wohnungenUndFahrgemeinschaften/pflichtenheft.pdf"
type="application/pdf"
className="w-full h-full"
>
<div className="flex flex-col items-center justify-center h-full p-4 text-center bg-slate-50">
<p className="mb-2 text-slate-600 font-medium">Vorschau nicht verfügbar</p>
<p className="mb-4 text-sm text-slate-500">Ihr Browser kann dieses PDF nicht direkt anzeigen.</p>
<a
href="/assets/projects/wohnungenUndFahrgemeinschaften/pflichtenheft.pdf"
target="_blank"
rel="noopener noreferrer"
className="inline-flex items-center px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 transition-colors shadow-sm"
>
Pflichtenheft Herunterladen
</a>
</div>
</object>
</div>
<p className="text-sm text-slate-500 italic">
Auszug aus dem Pflichtenheft mit UI/UX Entwürfen und Anforderungen.
</p>
</div>
<div className="grid md:grid-cols-2 gap-6">
{/* Card: Fahrgemeinschaften */}
<div className="bg-white p-6 rounded-xl shadow-sm border border-slate-200 hover:shadow-md transition-shadow">
<div className="flex items-center space-x-3 mb-4 border-b border-slate-100 pb-2">
<span className="text-2xl">🚗</span>
<h3 className="text-xl font-bold text-slate-800">Fahrgemeinschaften</h3>
</div>
<p className="text-slate-600 mb-4">
Intelligente Vermittlung von Fahrern und Mitfahrern. Das System unterscheidet technisch komplex zwischen:
</p>
<ul className="space-y-2 text-sm text-slate-600 pl-4 list-disc">
<li>
<strong>Einmalige Fahrten:</strong> Für feste Termine mit spezifischem Datum & Uhrzeit.
</li>
<li>
<strong>Pendler-Modus:</strong> Über eine Bitmaske (z.B. Mo/Mi/Fr) lassen sich wiederkehrende Fahrten einfach verwalten.
</li>
<li>
<strong>Status-Update:</strong> Die Verfügbarkeit von freien Plätzen wird in Echtzeit angezeigt.
</li>
</ul>
</div>
{/* Card: Wohnungsmarkt */}
<div className="bg-white p-6 rounded-xl shadow-sm border border-slate-200 hover:shadow-md transition-shadow">
<div className="flex items-center space-x-3 mb-4 border-b border-slate-100 pb-2">
<span className="text-2xl">🏠</span>
<h3 className="text-xl font-bold text-slate-800">Wohnungsmarkt</h3>
</div>
<p className="text-slate-600 mb-4">
Marktplatz für WG-Zimmer und Apartments. Fokus auf einfache Bedienbarkeit und klare Datenstruktur.
</p>
<ul className="space-y-2 text-sm text-slate-600 pl-4 list-disc">
<li>
<strong>Smarte Filter:</strong> Suche nach Preis, Zimmeranzahl, Größe und Standort.
</li>
<li>
<strong>Verwaltung:</strong> Einfaches Erstellen und Bearbeiten der eigenen Inserate.
</li>
<li>
<strong>Kontakt:</strong> Interessenten werden automatisch mit den hinterlegten Kontaktdaten verknüpft.
</li>
</ul>
</div>
</div>
</section>
{/* --- ARCHITEKTUR --- */}
<section className="mb-16">
<h2 className="text-2xl font-bold text-slate-900 mb-6 border-l-4 border-indigo-500 pl-4">3. Technische Architektur & Daten</h2>
<div className="bg-slate-50 border border-slate-200 rounded-xl p-4 mb-8 text-center shadow-sm">
<div className="w-full h-[600px] bg-white rounded-lg border border-slate-100 overflow-hidden mb-3">
<object
data="/assets/projects/wohnungenUndFahrgemeinschaften/datenbankentwurf.pdf"
type="application/pdf"
className="w-full h-full"
>
<div className="flex flex-col items-center justify-center h-full p-4 text-center bg-slate-50">
<p className="mb-2 text-slate-600 font-medium">Vorschau nicht verfügbar</p>
<p className="mb-4 text-sm text-slate-500">Ihr Browser kann dieses PDF nicht direkt anzeigen.</p>
<a
href="/assets/projects/wohnungenUndFahrgemeinschaften/datenbankentwurf.pdf"
target="_blank"
rel="noopener noreferrer"
className="inline-flex items-center px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 transition-colors shadow-sm"
>
PDF Herunterladen
</a>
</div>
</object>
</div>
<p className="text-sm text-slate-500 italic">
Auszug aus dem Core Data Services (CDS) Datenmodell.
</p>
</div>
<div className="grid md:grid-cols-2 gap-6">
<div className="bg-white p-6 rounded-xl border border-slate-200 shadow-sm">
<h3 className="text-lg font-bold text-slate-800 mb-2">ABAP RAP Backend</h3>
<p className="text-slate-600 leading-relaxed">
Das Backend basiert auf dem <strong>RESTful ABAP Programming Model</strong>.
Ein integriertes <strong>AuditLog</strong> protokolliert alle Änderungen (Erstellen, Bearbeiten, Löschen)
an Inseraten revisionssicher für Administratoren.
</p>
</div>
<div className="bg-white p-6 rounded-xl border border-slate-200 shadow-sm">
<h3 className="text-lg font-bold text-slate-800 mb-2">Hybrid-Architektur (Images)</h3>
<p className="text-slate-600 leading-relaxed">
Um die SAP HANA Datenbank performant zu halten, habe ich eine entkoppelte Lösung gewählt:
Bilder werden über einen <strong>Python-Microservice</strong> in einer externen <strong>SQLite-Datenbank</strong>
gespeichert und im Hauptsystem nur über UUIDs referenziert.
</p>
</div>
</div>
</section>
{/* --- TECH STACK --- */}
<section className="mb-16">
<h2 className="text-2xl font-bold text-slate-900 mb-6 border-l-4 border-indigo-500 pl-4">4. Tech Stack</h2>
<div className="bg-slate-50 p-6 rounded-xl border border-slate-200">
<div className="flex flex-wrap gap-3">
{['SAP RAP', 'ABAP CDS', 'SAP Fiori Elements', 'OData V4', 'Python', 'SQLite', 'Audit Logging'].map((tech) => (
<span key={tech} className="bg-white px-4 py-2 rounded shadow-sm text-center font-semibold text-slate-700 border border-slate-100">
{tech}
</span>
))}
</div>
</div>
</section>
{/* --- ROADMAP --- */}
<section className="mb-16">
<h2 className="text-2xl font-bold text-slate-900 mb-6 border-l-4 border-indigo-500 pl-4">5. Roadmap & Ausblick</h2>
<div className="bg-indigo-50 rounded-xl p-6 border border-indigo-100">
<p className="text-indigo-900 leading-relaxed">
Aktuell befinde ich mich mitten in der <strong>Implementierungsphase</strong> der Kernfunktionen.
Sollte es der Zeitplan zulassen, ist als nächster Schritt die Integration von <strong>OpenStreetMap</strong> geplant,
um Start- und Zielorte der Fahrten direkt auf einer Karte visualisieren zu können.
</p>
</div>
</section>
</div>
<div>
<h2 style={{ marginTop: '2em' }}>Kernfunktionen</h2>
<div className="list-display">
<ul className="key-points">
<li><b>Wohnungsangebote:</b> Erstellen, Anzeigen, Bearbeiten und Löschen von Angeboten mit bis zu 5 Bildern.</li>
<li><b>Fahrgemeinschaften:</b> Erstellen, Suchen (Listen- & Kartenansicht), Bearbeiten und Löschen von Fahrten.</li>
<li><b>Nutzerverwaltung:</b> Anmeldung via SAP-Login mit Rollen für Schüler und Administratoren (Lehrer/Verwaltung).</li>
<li><b>Moderation:</b> Administratoren können alle Einträge verwalten und moderieren.</li>
</ul>
</div>
</div>
<div>
<h2 style={{ marginTop: '2em' }}>Technologie-Stack</h2>
<div className="list-display">
<ul className="key-points">
<li><b>Backend:</b> SAP RAP (RESTful ABAP Programming Model)</li>
<li><b>Frontend:</b> SAP Fiori (UI5)</li>
<li><b>Datenmodell:</b> Core Data Services (CDS)</li>
<li><b>API:</b> OData</li>
<li><b>Authentifizierung:</b> SAP Single Sign-On (SSO)</li>
<li><b>Kartenintegration:</b> OpenStreetMap</li>
</ul>
</div>
</div>
</section>
</div>
);
}

View File

@ -2,10 +2,10 @@ import React from "react";
function FooterSection() {
return (
<footer>
<footer className="bg-slate-800 text-slate-100 min-h-[80px] flex justify-center items-center py-5 mt-10 text-center">
<nav>
<a href="/impressum" className="foot-links">Impressum</a>
<a href="/privacy" className="foot-links">Datenschutz</a>
<a href="/impressum" className="text-slate-400 hover:text-white mx-4 no-underline transition-colors">Impressum</a>
<a href="/privacy" className="text-slate-400 hover:text-white mx-4 no-underline transition-colors">Datenschutz</a>
</nav>
</footer>
);

View File

@ -2,42 +2,45 @@ import React from "react";
function GoalsPage() {
return (
<section className="content-group">
<h1>Meine Ziele</h1>
<div>
<h2>Derzeitige Ziele</h2>
<div className="list-display">
<ul className="key-points">
<section className="max-w-4xl mx-auto px-4 py-12 font-sans text-slate-800">
<h1 className="text-4xl font-extrabold text-slate-900 mb-8 text-center">Meine Ziele</h1>
<div className="mb-12">
<h2 className="text-2xl font-bold text-slate-900 border-b pb-2 mb-4">Derzeitige Ziele</h2>
<div className="bg-slate-50 p-6 rounded-xl border border-slate-100 shadow-sm">
<ul className="list-disc pl-5 space-y-3 text-slate-700 leading-relaxed">
<li>
Meinen Fokus auf die Schule richten, um dem Pensum der Schule
gerecht zu werden
Meinen Fokus auf die Schule richten, um die Abschlusspr&uuml;fungen
bestm&ouml;glich zu bestehen
</li>
<li>
Vertiefung meiner Kenntnisse in <b>Python f&uuml;r Data Science</b> (z.B.
Pandas, TensorFlow, NumPy, Scikit-learn)
Pandas, TensorFlow) sowie in der <b>Full-Stack Webentwicklung</b>
</li>
<li>
Entwicklung von Data Science Projekten mit Fokus auf <em>vollst&auml;ndige
Applikationen</em> (Frontend: React; Backend Flask, FastAPI; Forschung:
JupyterNotebook)
Entwicklung von Softwareprojekten mit Fokus auf <em>moderne
Architekturen</em> und die Integration von KI-Komponenten
in nutzerfreundliche Anwendungen
</li>
</ul>
</div>
</div>
<div>
<h2>Ziele der n&auml;chsten Jahre</h2>
<p>
F&uuml;r meine Ziele in den n&auml;chsten Jahren strebe ich einen <b>guten
Abschluss</b> an meiner derzeitigen Schule zum Staatlich gepr&uuml;ften
Wirtschaftsinformatiker und anschlie&szlig;end ein <em>(duales) Studium im
Bereich Data Science</em> an. Durch diese Ziele habe ich vor, ein Fundament
aufzubauen, welches mir helfen wird, die auf mich zukommenden
Schwierigkeiten zu bew&auml;ltigen.
<div className="mb-12">
<h2 className="text-2xl font-bold text-slate-900 border-b pb-2 mb-4">Ziele der n&auml;chsten Jahre</h2>
<p className="text-slate-700 leading-relaxed">
F&uuml;r meine berufliche Zukunft strebe ich nach meinem Abschluss zum
Staatlich gepr&uuml;ften Wirtschaftsinformatiker den direkten <b>Berufseinstieg</b> an.
Mein Ziel ist eine Position, in der ich meine F&auml;higkeiten sowohl in der{" "}
<b>Softwareentwicklung</b> als auch in <b>Data Science</b> einbringen und
weiterentwickeln kann. Ich suche nach Herausforderungen, an denen ich
praktisch wachsen und einen echten Mehrwert schaffen kann.
</p>
</div>
<div>
<h2>Langfristige Ziele</h2>
<p>
<h2 className="text-2xl font-bold text-slate-900 border-b pb-2 mb-4">Langfristige Ziele</h2>
<p className="text-slate-700 leading-relaxed">
Langfristig plane ich, meine Kenntnisse immer weiter auszubauen und
diese auch an die Welt und deren Anforderungen, vor allem in dieser
sich schnell entwickelnden Zeit, anzupassen. Ich w&uuml;rde derzeit auch

View File

@ -9,25 +9,29 @@ function HomePage() {
age--;
}
return (
<section className="centered">
<section className="max-w-3xl mx-auto px-4 py-12 text-center font-sans text-slate-800">
<div>
<h1>Startseite</h1>
<p style={{ marginTop: '1.5em' }}>
<h1 className="text-4xl font-extrabold text-slate-900 mb-6">Startseite</h1>
<p className="mt-6 text-lg leading-relaxed text-slate-700">
<b>
Hallo und danke f&uuml;rs Daraufklicken! Ich bin Simon Altsch&auml;ffl, {age}<span> </span>
Jahre alt und derzeit Sch&uuml;ler f&uuml;r Wirtschaftsinformatik an der EDV-Schule
Plattling.
</b>
</p>
<img src="assets/img/picture.jpg" alt="Mein Foto" className="center-image"/>
<p>
<img
src="assets/img/picture.jpg"
alt="Mein Foto"
className="mx-auto rounded-lg shadow-lg my-8 max-w-full h-auto border border-slate-200"
/>
<p className="text-lg leading-relaxed text-slate-600 mb-4">
<em>Willkommen auf meiner Website!</em> Hier stelle ich mich detailliert vor,
pr&auml;sentiere meine Projekte und teile meine Erfahrung in der
Informatik.
</p>
<p>
Entdecken Sie gerne meine Projekte, die bereits abgeschlossen sind oder derzeit noch in Entwicklung sind. Erfahren Sie auch mehr &uuml;ber mich und meine Ziele, au&szlig;erdem k&ouml;nnen Sie gerne mit mir Kontakt aufnehmen.
<p className="text-lg leading-relaxed text-slate-600">
Entdecken Sie gerne meine Projekte, die bereits abgeschlossen sind oder derzeit noch in Entwicklung sind. Erfahren Sie auch mehr &uuml;ber mich und meine Ziele, au&szlig;erdem k&ouml;nnen Sie gerne mit mir Kontakt aufnehmen.
</p>
</div>
</section>

View File

@ -2,25 +2,25 @@ import React from "react";
function ImpressumSide() {
return (
<section className="centered">
<h1>Impressum nach &sect; 5 TMG</h1>
<section className="max-w-3xl mx-auto px-4 py-12 text-center font-sans text-slate-800">
<h1 className="text-4xl font-extrabold text-slate-900 mb-8">Impressum nach &sect; 5 TMG</h1>
<div>
<h2 style={{ marginTop: '1.5em' }}>Betreiber und Administrator</h2>
<p>
<div className="mb-12">
<h2 className="text-2xl font-bold text-slate-900 mb-4 mt-8 border-b pb-2 inline-block">Betreiber und Administrator</h2>
<p className="text-lg leading-relaxed text-slate-700 mt-4">
<b>Simon Altsch&auml;ffl</b> <br />
Sammern 6b <br />
94554 Moos
</p>
</div>
<div>
<h2>Kontakt</h2>
<p>
<b>Telefon:&nbsp;</b>
<a href="tel:+4915157852478">+49 1515 7852478</a>
<br />
<b>Email:</b>
<a href="mailto:info@simonaltschaeffl.de">info@simonaltschaeffl.de</a>
<h2 className="text-2xl font-bold text-slate-900 mb-4 border-b pb-2 inline-block">Kontakt</h2>
<p className="text-lg leading-relaxed text-slate-700 mt-4">
<b className="font-semibold">Telefon:&nbsp;</b>
<a href="tel:+4915157852478" className="text-blue-600 hover:underline hover:text-blue-800 transition-colors">+49 1515 7852478</a>
<br />
<b className="font-semibold">Email:</b>
<a href="mailto:info@simonaltschaeffl.de" className="text-blue-600 hover:underline hover:text-blue-800 transition-colors">info@simonaltschaeffl.de</a>
</p>
</div>
</section>

View File

@ -1,46 +1,228 @@
import React from "react";
import { Navbar, Nav, NavDropdown } from "react-bootstrap";
import React, { useState } from "react";
const MAIN_LINKS = [
{ name: "Startseite", href: "/" },
{ name: "Über mich", href: "/about-me" },
{ name: "Ziele", href: "/goals" },
{ name: "Kontakt", href: "/contact" },
];
const PROJECT_LINKS = [
{
category: "Fertige Projekte",
items: [
{ name: "Sprachstudie Wikipedia", href: "/projects/languagestudy" },
{ name: "Server Architektur", href: "/projects/server" },
{ name: "TDoT AI Demo", href: "/projects/tdot" },
],
},
{
category: "In Arbeit",
items: [
{ name: "KI Sprachenlern Roleplay", href: "/projects/language-roleplay" },
],
},
{
category: "Pausiert",
items: [
{ name: "Krimi Dinner mit KI", href: "/projects/crime-dinner" },
],
},
{
category: "Abschlussprojekte",
items: [
{ name: "Wohnungssuche und Fahrgemeinschaften", href: "/finalprojects/wufg" },
{ name: "Online Casino", href: "/finalprojects/onlineCasino" },
],
},
];
function Navigation() {
const [isOpen, setIsOpen] = useState(false);
const [dropdownOpen, setDropdownOpen] = useState(false);
const toggleMenu = () => {
setIsOpen(!isOpen);
};
const toggleDropdown = () => {
setDropdownOpen(!dropdownOpen);
};
return (
<div className="navigation">
<Navbar bg="light" expand="lg" className="py-0">
<Navbar.Brand href="/" className="my-name">Simon Altsch&auml;ffl</Navbar.Brand>
<Navbar.Toggle aria-controls="basic-navbar-nav" />
<Navbar.Collapse
id="basic-navbar-nav"
className="justify-content-between"
>
<Nav className="mr-auto">
<Nav.Link href="/">Startseite</Nav.Link>
<Nav.Link href="/about-me">&Uuml;ber mich</Nav.Link>
<Nav.Link href="/goals">Ziele</Nav.Link>
<Nav.Link href="/contact">Kontakt</Nav.Link>
<NavDropdown title="Projekte" id="basic-nav-dropdown">
<NavDropdown.ItemText>Fertige Projekte</NavDropdown.ItemText>
<NavDropdown.Item href="/projects/languagestudy">
Sprachstudie Wikipedia
</NavDropdown.Item>
<NavDropdown.Item href="/projects/server">
Server Architektur
</NavDropdown.Item>
<NavDropdown.Divider />
<NavDropdown.ItemText>In Arbeit</NavDropdown.ItemText>
<NavDropdown.Item href="/projects/crime-dinner">
Krimi Dinner mit KI
</NavDropdown.Item>
<NavDropdown.ItemText>Abschlussprojekte in Arbeit</NavDropdown.ItemText>
<NavDropdown.Item href="/finalprojects/wufg">
Wohnungssuche und Fahrgemeinschaften
</NavDropdown.Item>
<NavDropdown.Item href="/finalprojects/onlineCasino">
Online Casino
</NavDropdown.Item>
</NavDropdown>
</Nav>
</Navbar.Collapse>
</Navbar>
</div>
<nav className="bg-white border-b border-gray-200">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="flex justify-between h-16">
<div className="flex">
<div className="flex-shrink-0 flex items-center">
<a
href="/"
className="text-xl font-bold text-gray-800 hover:text-gray-900"
>
Simon Altschäffl
</a>
</div>
</div>
{/* Desktop Menu */}
<div className="hidden md:flex md:items-center md:space-x-4">
{MAIN_LINKS.map((link) => (
<a
key={link.name}
href={link.href}
className="text-gray-600 hover:text-gray-900 px-3 py-2 rounded-md text-sm font-medium"
>
{link.name}
</a>
))}
{/* Dropdown */}
<div className="relative">
<button
onClick={toggleDropdown}
onMouseEnter={() => setDropdownOpen(true)}
className="text-gray-600 hover:text-gray-900 px-3 py-2 rounded-md text-sm font-medium inline-flex items-center focus:outline-none"
>
<span>Projekte</span>
<svg
className="ml-1 h-5 w-5"
fill="currentColor"
viewBox="0 0 20 20"
>
<path
fillRule="evenodd"
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
clipRule="evenodd"
/>
</svg>
</button>
{dropdownOpen && (
<div
className="absolute right-0 mt-2 w-64 rounded-md shadow-lg bg-white ring-1 ring-black ring-opacity-5 z-50"
onMouseLeave={() => setDropdownOpen(false)}
>
<div className="py-1" role="menu" aria-orientation="vertical">
{PROJECT_LINKS.map((section, index) => (
<React.Fragment key={section.category}>
{index > 0 && (
<div className="border-t border-gray-100 my-1"></div>
)}
<span className="block px-4 py-2 text-xs font-semibold text-gray-400 uppercase tracking-wider">
{section.category}
</span>
{section.items.map((item) => (
<a
key={item.name}
href={item.href}
className="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100"
role="menuitem"
>
{item.name}
</a>
))}
</React.Fragment>
))}
</div>
</div>
)}
</div>
</div>
{/* Mobile menu button */}
<div className="flex md:hidden items-center">
<button
onClick={toggleMenu}
type="button"
className="inline-flex items-center justify-center p-2 rounded-md text-gray-400 hover:text-gray-500 hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-indigo-500"
aria-controls="mobile-menu"
aria-expanded="false"
>
<span className="sr-only">Open main menu</span>
{!isOpen ? (
<svg
className="block h-6 w-6"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
aria-hidden="true"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
d="M4 6h16M4 12h16M4 18h16"
/>
</svg>
) : (
<svg
className="block h-6 w-6"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
aria-hidden="true"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
d="M6 18L18 6M6 6l12 12"
/>
</svg>
)}
</button>
</div>
</div>
</div>
{/* Mobile Menu */}
{isOpen && (
<div className="md:hidden" id="mobile-menu">
<div className="px-2 pt-2 pb-3 space-y-1 sm:px-3">
{MAIN_LINKS.map((link) => (
<a
key={link.name}
href={link.href}
className="block px-3 py-2 rounded-md text-base font-medium text-gray-700 hover:text-gray-900 hover:bg-gray-50"
>
{link.name}
</a>
))}
<div className="border-t border-gray-200 pt-4 pb-3">
<div className="flex items-center px-5">
<div className="flex-shrink-0">
<span className="font-medium text-gray-500">Projekte</span>
</div>
</div>
<div className="mt-3 px-2 space-y-1">
{PROJECT_LINKS.map((section, index) => (
<React.Fragment key={section.category}>
<span
className={`block px-3 py-2 text-xs font-bold text-gray-400 uppercase ${index > 0 ? "mt-2" : ""
}`}
>
{section.category}
</span>
{section.items.map((item) => (
<a
key={item.name}
href={item.href}
className="block px-3 py-2 rounded-md text-base font-medium text-gray-600 hover:text-gray-900 hover:bg-gray-50"
>
{item.name}
</a>
))}
</React.Fragment>
))}
</div>
</div>
</div>
</div>
)}
</nav>
);
}

View File

@ -2,490 +2,492 @@ import React, { Component } from "react";
function PrivacyPage() {
return (
<section>
<h1>Datenschutz&shy;erkl&auml;rung</h1>
<h2>1. Datenschutz auf einen Blick</h2>
<h3>Allgemeine Hinweise</h3>{" "}
<p>
Die folgenden Hinweise geben einen einfachen &Uuml;berblick
dar&uuml;ber, was mit Ihren personenbezogenen Daten passiert, wenn Sie
diese Website besuchen. Personenbezogene Daten sind alle Daten, mit
denen Sie pers&ouml;nlich identifiziert werden k&ouml;nnen.
Ausf&uuml;hrliche Informationen zum Thema Datenschutz entnehmen Sie
unserer unter diesem Text aufgef&uuml;hrten Datenschutzerkl&auml;rung.
</p>
<h3>Datenerfassung auf dieser Website</h3>{" "}
<h4>
Wer ist verantwortlich f&uuml;r die Datenerfassung auf dieser Website?
</h4>{" "}
<p>
Die Datenverarbeitung auf dieser Website erfolgt durch den
Websitebetreiber. Dessen Kontaktdaten k&ouml;nnen Sie dem Abschnitt
&bdquo;Hinweis zur Verantwortlichen Stelle&ldquo; in dieser
Datenschutzerkl&auml;rung entnehmen.
</p>{" "}
<h4>Wie erfassen wir Ihre Daten?</h4>{" "}
<p>
Ihre Daten werden zum einen dadurch erhoben, dass Sie uns diese
mitteilen. Hierbei kann es sich z.&nbsp;B. um Daten handeln, die Sie in
ein Kontaktformular eingeben.
</p>{" "}
<p>
Andere Daten werden automatisch oder nach Ihrer Einwilligung beim Besuch
der Website durch unsere IT-Systeme erfasst. Das sind vor allem
technische Daten (z.&nbsp;B. Internetbrowser, Betriebssystem oder
Uhrzeit des Seitenaufrufs). Die Erfassung dieser Daten erfolgt
automatisch, sobald Sie diese Website betreten.
</p>{" "}
<h4>Wof&uuml;r nutzen wir Ihre Daten?</h4>{" "}
<p>
Ein Teil der Daten wird erhoben, um eine fehlerfreie Bereitstellung der
Website zu gew&auml;hrleisten. Andere Daten k&ouml;nnen zur Analyse
Ihres Nutzerverhaltens verwendet werden. Sofern &uuml;ber die Website
Vertr&auml;ge geschlossen oder angebahnt werden k&ouml;nnen, werden die
&uuml;bermittelten Daten auch f&uuml;r Vertragsangebote, Bestellungen
oder sonstige Auftragsanfragen verarbeitet.
</p>{" "}
<h4>Welche Rechte haben Sie bez&uuml;glich Ihrer Daten?</h4>
<p>
Sie haben jederzeit das Recht, unentgeltlich Auskunft &uuml;ber
Herkunft, Empf&auml;nger und Zweck Ihrer gespeicherten personenbezogenen
Daten zu erhalten. Sie haben au&szlig;erdem ein Recht, die Berichtigung
oder L&ouml;schung dieser Daten zu verlangen. Wenn Sie eine Einwilligung
zur Datenverarbeitung erteilt haben, k&ouml;nnen Sie diese Einwilligung
jederzeit f&uuml;r die Zukunft widerrufen. Au&szlig;erdem haben Sie das
Recht, unter bestimmten Umst&auml;nden die Einschr&auml;nkung der
Verarbeitung Ihrer personenbezogenen Daten zu verlangen. Des Weiteren
steht Ihnen ein Beschwerderecht bei der zust&auml;ndigen
Aufsichtsbeh&ouml;rde zu.
</p>{" "}
<p>
Hierzu sowie zu weiteren Fragen zum Thema Datenschutz k&ouml;nnen Sie
sich jederzeit an uns wenden.
</p>
<h2>2. Hosting</h2>
<p>Wir hosten die Inhalte unserer Website bei folgendem Anbieter:</p>
<h3>Externes Hosting</h3>{" "}
<p>
Diese Website wird extern gehostet. Die personenbezogenen Daten, die auf
dieser Website erfasst werden, werden auf den Servern des Hosters / der
Hoster gespeichert. Hierbei kann es sich v.&nbsp;a. um IP-Adressen,
Kontaktanfragen, Meta- und Kommunikationsdaten, Vertragsdaten,
Kontaktdaten, Namen, Websitezugriffe und sonstige Daten, die &uuml;ber
eine Website generiert werden, handeln.
</p>{" "}
<p>
Das externe Hosting erfolgt zum Zwecke der Vertragserf&uuml;llung
gegen&uuml;ber unseren potenziellen und bestehenden Kunden (Art. 6 Abs.
1 lit. b DSGVO) und im Interesse einer sicheren, schnellen und
effizienten Bereitstellung unseres Online-Angebots durch einen
professionellen Anbieter (Art. 6 Abs. 1 lit. f DSGVO). Sofern eine
entsprechende Einwilligung abgefragt wurde, erfolgt die Verarbeitung
ausschlie&szlig;lich auf Grundlage von Art. 6 Abs. 1 lit. a DSGVO und
&sect; 25 Abs. 1 TDDDG, soweit die Einwilligung die Speicherung von
Cookies oder den Zugriff auf Informationen im Endger&auml;t des Nutzers
(z.&nbsp;B. Device-Fingerprinting) im Sinne des TDDDG umfasst. Die
Einwilligung ist jederzeit widerrufbar.
</p>{" "}
<p>
Unser(e) Hoster wird bzw. werden Ihre Daten nur insoweit verarbeiten,
wie dies zur Erf&uuml;llung seiner Leistungspflichten erforderlich ist
und unsere Weisungen in Bezug auf diese Daten befolgen.
</p>{" "}
<p>Wir setzen folgende(n) Hoster ein:</p>
<p>
netcup GmbH
<br />
Vertretungsberechtigter Gesellschafter: Eberhard Gericke
(Komplement&auml;r)
<br />
<br />
Telefon: +49 721 / 7540755 - 0
<br />
Mail: mail@netcup.de
<br />
Web: <a href="www.netcup.com">www.netcup.com</a>
<br />
<br />
Postanschrift:
<br />
Emmy-Noether-Straße 10
<br />
D-76131 Karlsruhe
<br />
Deutschland
</p>
<h2>3. Allgemeine Hinweise und Pflicht&shy;informationen</h2>
<h3>Datenschutz</h3>{" "}
<p>
Die Betreiber dieser Seiten nehmen den Schutz Ihrer pers&ouml;nlichen
Daten sehr ernst. Wir behandeln Ihre personenbezogenen Daten vertraulich
und entsprechend den gesetzlichen Datenschutzvorschriften sowie dieser
Datenschutzerkl&auml;rung.
</p>{" "}
<p>
Wenn Sie diese Website benutzen, werden verschiedene personenbezogene
Daten erhoben. Personenbezogene Daten sind Daten, mit denen Sie
pers&ouml;nlich identifiziert werden k&ouml;nnen. Die vorliegende
Datenschutzerkl&auml;rung erl&auml;utert, welche Daten wir erheben und
wof&uuml;r wir sie nutzen. Sie erl&auml;utert auch, wie und zu welchem
Zweck das geschieht.
</p>{" "}
<p>
Wir weisen darauf hin, dass die Daten&uuml;bertragung im Internet
(z.&nbsp;B. bei der Kommunikation per E-Mail) Sicherheitsl&uuml;cken
aufweisen kann. Ein l&uuml;ckenloser Schutz der Daten vor dem Zugriff
durch Dritte ist nicht m&ouml;glich.
</p>
<h3>Hinweis zur verantwortlichen Stelle</h3>{" "}
<p>
Die verantwortliche Stelle f&uuml;r die Datenverarbeitung auf dieser
Website ist:
</p>{" "}
<p>
Simon Altsch&auml;ffl
<br />
Sammern 6b
<br />
94554 Moos
</p>
<p>
Telefon: +49 15157 852478
<br />
E-Mail: info@simonaltschaeffl.de
</p>
<p>
Verantwortliche Stelle ist die nat&uuml;rliche oder juristische Person,
die allein oder gemeinsam mit anderen &uuml;ber die Zwecke und Mittel
der Verarbeitung von personenbezogenen Daten (z.&nbsp;B. Namen, E-Mail-
Adressen o. &Auml;.) entscheidet.
</p>
<h3>Speicherdauer</h3>{" "}
<p>
Soweit innerhalb dieser Datenschutzerkl&auml;rung keine speziellere
Speicherdauer genannt wurde, verbleiben Ihre personenbezogenen Daten bei
uns, bis der Zweck f&uuml;r die Datenverarbeitung entf&auml;llt. Wenn
Sie ein berechtigtes L&ouml;schersuchen geltend machen oder eine
Einwilligung zur Datenverarbeitung widerrufen, werden Ihre Daten
gel&ouml;scht, sofern wir keine anderen rechtlich zul&auml;ssigen
Gr&uuml;nde f&uuml;r die Speicherung Ihrer personenbezogenen Daten haben
(z.&nbsp;B. steuer- oder handelsrechtliche Aufbewahrungsfristen); im
letztgenannten Fall erfolgt die L&ouml;schung nach Fortfall dieser
Gr&uuml;nde.
</p>
<h3>
Allgemeine Hinweise zu den Rechtsgrundlagen der Datenverarbeitung auf
dieser Website
</h3>{" "}
<p>
Sofern Sie in die Datenverarbeitung eingewilligt haben, verarbeiten wir
Ihre personenbezogenen Daten auf Grundlage von Art. 6 Abs. 1 lit. a
DSGVO bzw. Art. 9 Abs. 2 lit. a DSGVO, sofern besondere Datenkategorien
nach Art. 9 Abs. 1 DSGVO verarbeitet werden. Im Falle einer
ausdr&uuml;cklichen Einwilligung in die &Uuml;bertragung
personenbezogener Daten in Drittstaaten erfolgt die Datenverarbeitung
au&szlig;erdem auf Grundlage von Art. 49 Abs. 1 lit. a DSGVO. Sofern Sie
in die Speicherung von Cookies oder in den Zugriff auf Informationen in
Ihr Endger&auml;t (z.&nbsp;B. via Device-Fingerprinting) eingewilligt
haben, erfolgt die Datenverarbeitung zus&auml;tzlich auf Grundlage von
&sect; 25 Abs. 1 TDDDG. Die Einwilligung ist jederzeit widerrufbar. Sind
Ihre Daten zur Vertragserf&uuml;llung oder zur Durchf&uuml;hrung
vorvertraglicher Ma&szlig;nahmen erforderlich, verarbeiten wir Ihre
Daten auf Grundlage des Art. 6 Abs. 1 lit. b DSGVO. Des Weiteren
verarbeiten wir Ihre Daten, sofern diese zur Erf&uuml;llung einer
rechtlichen Verpflichtung erforderlich sind auf Grundlage von Art. 6
Abs. 1 lit. c DSGVO. Die Datenverarbeitung kann ferner auf Grundlage
unseres berechtigten Interesses nach Art. 6 Abs. 1 lit. f DSGVO
erfolgen. &Uuml;ber die jeweils im Einzelfall einschl&auml;gigen
Rechtsgrundlagen wird in den folgenden Abs&auml;tzen dieser
Datenschutzerkl&auml;rung informiert.
</p>
<h3>Empf&auml;nger von personenbezogenen Daten</h3>{" "}
<p>
Im Rahmen unserer Gesch&auml;ftst&auml;tigkeit arbeiten wir mit
verschiedenen externen Stellen zusammen. Dabei ist teilweise auch eine
&Uuml;bermittlung von personenbezogenen Daten an diese externen Stellen
erforderlich. Wir geben personenbezogene Daten nur dann an externe
Stellen weiter, wenn dies im Rahmen einer Vertragserf&uuml;llung
erforderlich ist, wenn wir gesetzlich hierzu verpflichtet sind
(z.&nbsp;B. Weitergabe von Daten an Steuerbeh&ouml;rden), wenn wir ein
berechtigtes Interesse nach Art. 6 Abs. 1 lit. f DSGVO an der Weitergabe
haben oder wenn eine sonstige Rechtsgrundlage die Datenweitergabe
erlaubt. Beim Einsatz von Auftragsverarbeitern geben wir
personenbezogene Daten unserer Kunden nur auf Grundlage eines
g&uuml;ltigen Vertrags &uuml;ber Auftragsverarbeitung weiter. Im Falle
einer gemeinsamen Verarbeitung wird ein Vertrag &uuml;ber gemeinsame
Verarbeitung geschlossen.
</p>
<h3>Widerruf Ihrer Einwilligung zur Datenverarbeitung</h3>{" "}
<p>
Viele Datenverarbeitungsvorg&auml;nge sind nur mit Ihrer
ausdr&uuml;cklichen Einwilligung m&ouml;glich. Sie k&ouml;nnen eine
bereits erteilte Einwilligung jederzeit widerrufen. Die
Rechtm&auml;&szlig;igkeit der bis zum Widerruf erfolgten
Datenverarbeitung bleibt vom Widerruf unber&uuml;hrt.
</p>
<h3>
Widerspruchsrecht gegen die Datenerhebung in besonderen F&auml;llen
sowie gegen Direktwerbung (Art. 21 DSGVO)
</h3>{" "}
<p>
WENN DIE DATENVERARBEITUNG AUF GRUNDLAGE VON ART. 6 ABS. 1 LIT. E ODER F
DSGVO ERFOLGT, HABEN SIE JEDERZEIT DAS RECHT, AUS GR&Uuml;NDEN, DIE SICH
AUS IHRER BESONDEREN SITUATION ERGEBEN, GEGEN DIE VERARBEITUNG IHRER
PERSONENBEZOGENEN DATEN WIDERSPRUCH EINZULEGEN; DIES GILT AUCH F&Uuml;R
EIN AUF DIESE BESTIMMUNGEN GEST&Uuml;TZTES PROFILING. DIE JEWEILIGE
RECHTSGRUNDLAGE, AUF DENEN EINE VERARBEITUNG BERUHT, ENTNEHMEN SIE
DIESER DATENSCHUTZERKL&Auml;RUNG. WENN SIE WIDERSPRUCH EINLEGEN, WERDEN
WIR IHRE BETROFFENEN PERSONENBEZOGENEN DATEN NICHT MEHR VERARBEITEN, ES
SEI DENN, WIR K&Ouml;NNEN ZWINGENDE SCHUTZW&Uuml;RDIGE GR&Uuml;NDE
F&Uuml;R DIE VERARBEITUNG NACHWEISEN, DIE IHRE INTERESSEN, RECHTE UND
FREIHEITEN &Uuml;BERWIEGEN ODER DIE VERARBEITUNG DIENT DER
GELTENDMACHUNG, AUS&Uuml;BUNG ODER VERTEIDIGUNG VON
RECHTSANSPR&Uuml;CHEN (WIDERSPRUCH NACH ART. 21 ABS. 1 DSGVO).
</p>{" "}
<p>
WERDEN IHRE PERSONENBEZOGENEN DATEN VERARBEITET, UM DIREKTWERBUNG ZU
BETREIBEN, SO HABEN SIE DAS RECHT, JEDERZEIT WIDERSPRUCH GEGEN DIE
VERARBEITUNG SIE BETREFFENDER PERSONENBEZOGENER DATEN ZUM ZWECKE
DERARTIGER WERBUNG EINZULEGEN; DIES GILT AUCH F&Uuml;R DAS PROFILING,
SOWEIT ES MIT SOLCHER DIREKTWERBUNG IN VERBINDUNG STEHT. WENN SIE
WIDERSPRECHEN, WERDEN IHRE PERSONENBEZOGENEN DATEN ANSCHLIESSEND NICHT
MEHR ZUM ZWECKE DER DIREKTWERBUNG VERWENDET (WIDERSPRUCH NACH ART. 21
ABS. 2 DSGVO).
</p>
<h3>
Beschwerde&shy;recht bei der zust&auml;ndigen Aufsichts&shy;beh&ouml;rde
</h3>{" "}
<p>
Im Falle von Verst&ouml;&szlig;en gegen die DSGVO steht den Betroffenen
ein Beschwerderecht bei einer Aufsichtsbeh&ouml;rde, insbesondere in dem
Mitgliedstaat ihres gew&ouml;hnlichen Aufenthalts, ihres Arbeitsplatzes
oder des Orts des mutma&szlig;lichen Versto&szlig;es zu. Das
Beschwerderecht besteht unbeschadet anderweitiger verwaltungsrechtlicher
oder gerichtlicher Rechtsbehelfe.
</p>
<h3>Recht auf Daten&shy;&uuml;bertrag&shy;barkeit</h3>{" "}
<p>
Sie haben das Recht, Daten, die wir auf Grundlage Ihrer Einwilligung
oder in Erf&uuml;llung eines Vertrags automatisiert verarbeiten, an sich
oder an einen Dritten in einem g&auml;ngigen, maschinenlesbaren Format
aush&auml;ndigen zu lassen. Sofern Sie die direkte &Uuml;bertragung der
Daten an einen anderen Verantwortlichen verlangen, erfolgt dies nur,
soweit es technisch machbar ist.
</p>
<h3>Auskunft, Berichtigung und L&ouml;schung</h3>{" "}
<p>
Sie haben im Rahmen der geltenden gesetzlichen Bestimmungen jederzeit
das Recht auf unentgeltliche Auskunft &uuml;ber Ihre gespeicherten
personenbezogenen Daten, deren Herkunft und Empf&auml;nger und den Zweck
der Datenverarbeitung und ggf. ein Recht auf Berichtigung oder
L&ouml;schung dieser Daten. Hierzu sowie zu weiteren Fragen zum Thema
personenbezogene Daten k&ouml;nnen Sie sich jederzeit an uns wenden.
</p>
<h3>Recht auf Einschr&auml;nkung der Verarbeitung</h3>{" "}
<p>
Sie haben das Recht, die Einschr&auml;nkung der Verarbeitung Ihrer
personenbezogenen Daten zu verlangen. Hierzu k&ouml;nnen Sie sich
jederzeit an uns wenden. Das Recht auf Einschr&auml;nkung der
Verarbeitung besteht in folgenden F&auml;llen:
</p>{" "}
<ul>
{" "}
<li>
Wenn Sie die Richtigkeit Ihrer bei uns gespeicherten personenbezogenen
Daten bestreiten, ben&ouml;tigen wir in der Regel Zeit, um dies zu
&uuml;berpr&uuml;fen. F&uuml;r die Dauer der Pr&uuml;fung haben Sie
das Recht, die Einschr&auml;nkung der Verarbeitung Ihrer
personenbezogenen Daten zu verlangen.
</li>{" "}
<li>
Wenn die Verarbeitung Ihrer personenbezogenen Daten
unrechtm&auml;&szlig;ig geschah/geschieht, k&ouml;nnen Sie statt der
L&ouml;schung die Einschr&auml;nkung der Datenverarbeitung verlangen.
</li>{" "}
<li>
Wenn wir Ihre personenbezogenen Daten nicht mehr ben&ouml;tigen, Sie
sie jedoch zur Aus&uuml;bung, Verteidigung oder Geltendmachung von
Rechtsanspr&uuml;chen ben&ouml;tigen, haben Sie das Recht, statt der
L&ouml;schung die Einschr&auml;nkung der Verarbeitung Ihrer
personenbezogenen Daten zu verlangen.
</li>{" "}
<li>
Wenn Sie einen Widerspruch nach Art. 21 Abs. 1 DSGVO eingelegt haben,
muss eine Abw&auml;gung zwischen Ihren und unseren Interessen
vorgenommen werden. Solange noch nicht feststeht, wessen Interessen
&uuml;berwiegen, haben Sie das Recht, die Einschr&auml;nkung der
Verarbeitung Ihrer personenbezogenen Daten zu verlangen.
</li>{" "}
</ul>
<p>
Wenn Sie die Verarbeitung Ihrer personenbezogenen Daten
eingeschr&auml;nkt haben, d&uuml;rfen diese Daten &ndash; von ihrer
Speicherung abgesehen &ndash; nur mit Ihrer Einwilligung oder zur
Geltendmachung, Aus&uuml;bung oder Verteidigung von
Rechtsanspr&uuml;chen oder zum Schutz der Rechte einer anderen
nat&uuml;rlichen oder juristischen Person oder aus Gr&uuml;nden eines
wichtigen &ouml;ffentlichen Interesses der Europ&auml;ischen Union oder
eines Mitgliedstaats verarbeitet werden.
</p>
<h3>SSL- bzw. TLS-Verschl&uuml;sselung</h3>{" "}
<p>
Diese Seite nutzt aus Sicherheitsgr&uuml;nden und zum Schutz der
&Uuml;bertragung vertraulicher Inhalte, wie zum Beispiel Bestellungen
oder Anfragen, die Sie an uns als Seitenbetreiber senden, eine SSL- bzw.
TLS-Verschl&uuml;sselung. Eine verschl&uuml;sselte Verbindung erkennen
Sie daran, dass die Adresszeile des Browsers von &bdquo;http://&ldquo;
auf &bdquo;https://&ldquo; wechselt und an dem Schloss-Symbol in Ihrer
Browserzeile.
</p>{" "}
<p>
Wenn die SSL- bzw. TLS-Verschl&uuml;sselung aktiviert ist, k&ouml;nnen
die Daten, die Sie an uns &uuml;bermitteln, nicht von Dritten mitgelesen
werden.
</p>
<h2>4. Plugins und Tools</h2>
<h3>YouTube</h3>{" "}
<p>
Diese Website bindet Videos der Website YouTube ein. Betreiber der
Website ist die Google Ireland Limited (&bdquo;Google&ldquo;), Gordon
House, Barrow Street, Dublin 4, Irland.
</p>{" "}
<p>
Wenn Sie eine unserer Webseiten besuchen, auf denen YouTube eingebunden
ist, wird eine Verbindung zu den Servern von YouTube hergestellt. Dabei
wird dem YouTube-Server mitgeteilt, welche unserer Seiten Sie besucht
haben.
</p>
<p>
Des Weiteren kann YouTube verschiedene Cookies auf Ihrem Endger&auml;t
speichern oder vergleichbare Technologien zur Wiedererkennung verwenden
(z.&nbsp;B. Device-Fingerprinting). Auf diese Weise kann YouTube
Informationen &uuml;ber Besucher dieser Website erhalten. Diese
Informationen werden u.&nbsp;a. verwendet, um Videostatistiken zu
erfassen, die Anwenderfreundlichkeit zu verbessern und Betrugsversuchen
vorzubeugen. Des Weiteren werden die erfassten Daten im
Google-Werbenetzwerk verarbeitet.
</p>{" "}
<p>
Wenn Sie in Ihrem YouTube-Account eingeloggt sind, erm&ouml;glichen Sie
YouTube, Ihr Surfverhalten direkt Ihrem pers&ouml;nlichen Profil
zuzuordnen. Dies k&ouml;nnen Sie verhindern, indem Sie sich aus Ihrem
YouTube-Account ausloggen.
</p>{" "}
<p>
Die Nutzung von YouTube erfolgt im Interesse einer ansprechenden
Darstellung unserer Online- Angebote. Dies stellt ein berechtigtes
Interesse im Sinne von Art. 6 Abs. 1 lit. f DSGVO dar. Sofern eine
entsprechende Einwilligung abgefragt wurde, erfolgt die Verarbeitung
ausschlie&szlig;lich auf Grundlage von Art. 6 Abs. 1 lit. a DSGVO und
&sect; 25 Abs. 1 TDDDG, soweit die Einwilligung die Speicherung von
Cookies oder den Zugriff auf Informationen im Endger&auml;t des Nutzers
(z.&nbsp;B. Device-Fingerprinting) im Sinne des TDDDG umfasst. Die
Einwilligung ist jederzeit widerrufbar.
</p>{" "}
<p>
Weitere Informationen zum Umgang mit Nutzerdaten finden Sie in der
Datenschutzerkl&auml;rung von YouTube unter:{" "}
<a
href="https://policies.google.com/privacy?hl=de"
target="_blank"
rel="noopener
<section className="max-w-4xl mx-auto px-4 py-12 font-sans text-slate-800">
<h1 className="text-4xl font-extrabold text-slate-900 mb-8 border-b pb-4">Datenschutz&shy;erkl&auml;rung</h1>
<div className="space-y-8">
<h2 className="text-2xl font-bold text-slate-900 mt-8 mb-4">1. Datenschutz auf einen Blick</h2>
<h3>Allgemeine Hinweise</h3>{" "}
<p>
Die folgenden Hinweise geben einen einfachen &Uuml;berblick
dar&uuml;ber, was mit Ihren personenbezogenen Daten passiert, wenn Sie
diese Website besuchen. Personenbezogene Daten sind alle Daten, mit
denen Sie pers&ouml;nlich identifiziert werden k&ouml;nnen.
Ausf&uuml;hrliche Informationen zum Thema Datenschutz entnehmen Sie
unserer unter diesem Text aufgef&uuml;hrten Datenschutzerkl&auml;rung.
</p>
<h3>Datenerfassung auf dieser Website</h3>{" "}
<h4>
Wer ist verantwortlich f&uuml;r die Datenerfassung auf dieser Website?
</h4>{" "}
<p>
Die Datenverarbeitung auf dieser Website erfolgt durch den
Websitebetreiber. Dessen Kontaktdaten k&ouml;nnen Sie dem Abschnitt
&bdquo;Hinweis zur Verantwortlichen Stelle&ldquo; in dieser
Datenschutzerkl&auml;rung entnehmen.
</p>{" "}
<h4>Wie erfassen wir Ihre Daten?</h4>{" "}
<p>
Ihre Daten werden zum einen dadurch erhoben, dass Sie uns diese
mitteilen. Hierbei kann es sich z.&nbsp;B. um Daten handeln, die Sie in
ein Kontaktformular eingeben.
</p>{" "}
<p>
Andere Daten werden automatisch oder nach Ihrer Einwilligung beim Besuch
der Website durch unsere IT-Systeme erfasst. Das sind vor allem
technische Daten (z.&nbsp;B. Internetbrowser, Betriebssystem oder
Uhrzeit des Seitenaufrufs). Die Erfassung dieser Daten erfolgt
automatisch, sobald Sie diese Website betreten.
</p>{" "}
<h4>Wof&uuml;r nutzen wir Ihre Daten?</h4>{" "}
<p>
Ein Teil der Daten wird erhoben, um eine fehlerfreie Bereitstellung der
Website zu gew&auml;hrleisten. Andere Daten k&ouml;nnen zur Analyse
Ihres Nutzerverhaltens verwendet werden. Sofern &uuml;ber die Website
Vertr&auml;ge geschlossen oder angebahnt werden k&ouml;nnen, werden die
&uuml;bermittelten Daten auch f&uuml;r Vertragsangebote, Bestellungen
oder sonstige Auftragsanfragen verarbeitet.
</p>{" "}
<h4>Welche Rechte haben Sie bez&uuml;glich Ihrer Daten?</h4>
<p>
Sie haben jederzeit das Recht, unentgeltlich Auskunft &uuml;ber
Herkunft, Empf&auml;nger und Zweck Ihrer gespeicherten personenbezogenen
Daten zu erhalten. Sie haben au&szlig;erdem ein Recht, die Berichtigung
oder L&ouml;schung dieser Daten zu verlangen. Wenn Sie eine Einwilligung
zur Datenverarbeitung erteilt haben, k&ouml;nnen Sie diese Einwilligung
jederzeit f&uuml;r die Zukunft widerrufen. Au&szlig;erdem haben Sie das
Recht, unter bestimmten Umst&auml;nden die Einschr&auml;nkung der
Verarbeitung Ihrer personenbezogenen Daten zu verlangen. Des Weiteren
steht Ihnen ein Beschwerderecht bei der zust&auml;ndigen
Aufsichtsbeh&ouml;rde zu.
</p>{" "}
<p>
Hierzu sowie zu weiteren Fragen zum Thema Datenschutz k&ouml;nnen Sie
sich jederzeit an uns wenden.
</p>
<h2 className="text-2xl font-bold text-slate-900 mt-8 mb-4">2. Hosting</h2>
<p>Wir hosten die Inhalte unserer Website bei folgendem Anbieter:</p>
<h3>Externes Hosting</h3>{" "}
<p>
Diese Website wird extern gehostet. Die personenbezogenen Daten, die auf
dieser Website erfasst werden, werden auf den Servern des Hosters / der
Hoster gespeichert. Hierbei kann es sich v.&nbsp;a. um IP-Adressen,
Kontaktanfragen, Meta- und Kommunikationsdaten, Vertragsdaten,
Kontaktdaten, Namen, Websitezugriffe und sonstige Daten, die &uuml;ber
eine Website generiert werden, handeln.
</p>{" "}
<p>
Das externe Hosting erfolgt zum Zwecke der Vertragserf&uuml;llung
gegen&uuml;ber unseren potenziellen und bestehenden Kunden (Art. 6 Abs.
1 lit. b DSGVO) und im Interesse einer sicheren, schnellen und
effizienten Bereitstellung unseres Online-Angebots durch einen
professionellen Anbieter (Art. 6 Abs. 1 lit. f DSGVO). Sofern eine
entsprechende Einwilligung abgefragt wurde, erfolgt die Verarbeitung
ausschlie&szlig;lich auf Grundlage von Art. 6 Abs. 1 lit. a DSGVO und
&sect; 25 Abs. 1 TDDDG, soweit die Einwilligung die Speicherung von
Cookies oder den Zugriff auf Informationen im Endger&auml;t des Nutzers
(z.&nbsp;B. Device-Fingerprinting) im Sinne des TDDDG umfasst. Die
Einwilligung ist jederzeit widerrufbar.
</p>{" "}
<p>
Unser(e) Hoster wird bzw. werden Ihre Daten nur insoweit verarbeiten,
wie dies zur Erf&uuml;llung seiner Leistungspflichten erforderlich ist
und unsere Weisungen in Bezug auf diese Daten befolgen.
</p>{" "}
<p>Wir setzen folgende(n) Hoster ein:</p>
<p>
netcup GmbH
<br />
Vertretungsberechtigter Gesellschafter: Eberhard Gericke
(Komplement&auml;r)
<br />
<br />
Telefon: +49 721 / 7540755 - 0
<br />
Mail: mail@netcup.de
<br />
Web: <a href="www.netcup.com">www.netcup.com</a>
<br />
<br />
Postanschrift:
<br />
Emmy-Noether-Straße 10
<br />
D-76131 Karlsruhe
<br />
Deutschland
</p>
<h2 className="text-2xl font-bold text-slate-900 mt-8 mb-4">3. Allgemeine Hinweise und Pflicht&shy;informationen</h2>
<h3>Datenschutz</h3>{" "}
<p>
Die Betreiber dieser Seiten nehmen den Schutz Ihrer pers&ouml;nlichen
Daten sehr ernst. Wir behandeln Ihre personenbezogenen Daten vertraulich
und entsprechend den gesetzlichen Datenschutzvorschriften sowie dieser
Datenschutzerkl&auml;rung.
</p>{" "}
<p>
Wenn Sie diese Website benutzen, werden verschiedene personenbezogene
Daten erhoben. Personenbezogene Daten sind Daten, mit denen Sie
pers&ouml;nlich identifiziert werden k&ouml;nnen. Die vorliegende
Datenschutzerkl&auml;rung erl&auml;utert, welche Daten wir erheben und
wof&uuml;r wir sie nutzen. Sie erl&auml;utert auch, wie und zu welchem
Zweck das geschieht.
</p>{" "}
<p>
Wir weisen darauf hin, dass die Daten&uuml;bertragung im Internet
(z.&nbsp;B. bei der Kommunikation per E-Mail) Sicherheitsl&uuml;cken
aufweisen kann. Ein l&uuml;ckenloser Schutz der Daten vor dem Zugriff
durch Dritte ist nicht m&ouml;glich.
</p>
<h3>Hinweis zur verantwortlichen Stelle</h3>{" "}
<p>
Die verantwortliche Stelle f&uuml;r die Datenverarbeitung auf dieser
Website ist:
</p>{" "}
<p>
Simon Altsch&auml;ffl
<br />
Sammern 6b
<br />
94554 Moos
</p>
<p>
Telefon: +49 15157 852478
<br />
E-Mail: info@simonaltschaeffl.de
</p>
<p>
Verantwortliche Stelle ist die nat&uuml;rliche oder juristische Person,
die allein oder gemeinsam mit anderen &uuml;ber die Zwecke und Mittel
der Verarbeitung von personenbezogenen Daten (z.&nbsp;B. Namen, E-Mail-
Adressen o. &Auml;.) entscheidet.
</p>
<h3>Speicherdauer</h3>{" "}
<p>
Soweit innerhalb dieser Datenschutzerkl&auml;rung keine speziellere
Speicherdauer genannt wurde, verbleiben Ihre personenbezogenen Daten bei
uns, bis der Zweck f&uuml;r die Datenverarbeitung entf&auml;llt. Wenn
Sie ein berechtigtes L&ouml;schersuchen geltend machen oder eine
Einwilligung zur Datenverarbeitung widerrufen, werden Ihre Daten
gel&ouml;scht, sofern wir keine anderen rechtlich zul&auml;ssigen
Gr&uuml;nde f&uuml;r die Speicherung Ihrer personenbezogenen Daten haben
(z.&nbsp;B. steuer- oder handelsrechtliche Aufbewahrungsfristen); im
letztgenannten Fall erfolgt die L&ouml;schung nach Fortfall dieser
Gr&uuml;nde.
</p>
<h3>
Allgemeine Hinweise zu den Rechtsgrundlagen der Datenverarbeitung auf
dieser Website
</h3>{" "}
<p>
Sofern Sie in die Datenverarbeitung eingewilligt haben, verarbeiten wir
Ihre personenbezogenen Daten auf Grundlage von Art. 6 Abs. 1 lit. a
DSGVO bzw. Art. 9 Abs. 2 lit. a DSGVO, sofern besondere Datenkategorien
nach Art. 9 Abs. 1 DSGVO verarbeitet werden. Im Falle einer
ausdr&uuml;cklichen Einwilligung in die &Uuml;bertragung
personenbezogener Daten in Drittstaaten erfolgt die Datenverarbeitung
au&szlig;erdem auf Grundlage von Art. 49 Abs. 1 lit. a DSGVO. Sofern Sie
in die Speicherung von Cookies oder in den Zugriff auf Informationen in
Ihr Endger&auml;t (z.&nbsp;B. via Device-Fingerprinting) eingewilligt
haben, erfolgt die Datenverarbeitung zus&auml;tzlich auf Grundlage von
&sect; 25 Abs. 1 TDDDG. Die Einwilligung ist jederzeit widerrufbar. Sind
Ihre Daten zur Vertragserf&uuml;llung oder zur Durchf&uuml;hrung
vorvertraglicher Ma&szlig;nahmen erforderlich, verarbeiten wir Ihre
Daten auf Grundlage des Art. 6 Abs. 1 lit. b DSGVO. Des Weiteren
verarbeiten wir Ihre Daten, sofern diese zur Erf&uuml;llung einer
rechtlichen Verpflichtung erforderlich sind auf Grundlage von Art. 6
Abs. 1 lit. c DSGVO. Die Datenverarbeitung kann ferner auf Grundlage
unseres berechtigten Interesses nach Art. 6 Abs. 1 lit. f DSGVO
erfolgen. &Uuml;ber die jeweils im Einzelfall einschl&auml;gigen
Rechtsgrundlagen wird in den folgenden Abs&auml;tzen dieser
Datenschutzerkl&auml;rung informiert.
</p>
<h3>Empf&auml;nger von personenbezogenen Daten</h3>{" "}
<p>
Im Rahmen unserer Gesch&auml;ftst&auml;tigkeit arbeiten wir mit
verschiedenen externen Stellen zusammen. Dabei ist teilweise auch eine
&Uuml;bermittlung von personenbezogenen Daten an diese externen Stellen
erforderlich. Wir geben personenbezogene Daten nur dann an externe
Stellen weiter, wenn dies im Rahmen einer Vertragserf&uuml;llung
erforderlich ist, wenn wir gesetzlich hierzu verpflichtet sind
(z.&nbsp;B. Weitergabe von Daten an Steuerbeh&ouml;rden), wenn wir ein
berechtigtes Interesse nach Art. 6 Abs. 1 lit. f DSGVO an der Weitergabe
haben oder wenn eine sonstige Rechtsgrundlage die Datenweitergabe
erlaubt. Beim Einsatz von Auftragsverarbeitern geben wir
personenbezogene Daten unserer Kunden nur auf Grundlage eines
g&uuml;ltigen Vertrags &uuml;ber Auftragsverarbeitung weiter. Im Falle
einer gemeinsamen Verarbeitung wird ein Vertrag &uuml;ber gemeinsame
Verarbeitung geschlossen.
</p>
<h3>Widerruf Ihrer Einwilligung zur Datenverarbeitung</h3>{" "}
<p>
Viele Datenverarbeitungsvorg&auml;nge sind nur mit Ihrer
ausdr&uuml;cklichen Einwilligung m&ouml;glich. Sie k&ouml;nnen eine
bereits erteilte Einwilligung jederzeit widerrufen. Die
Rechtm&auml;&szlig;igkeit der bis zum Widerruf erfolgten
Datenverarbeitung bleibt vom Widerruf unber&uuml;hrt.
</p>
<h3>
Widerspruchsrecht gegen die Datenerhebung in besonderen F&auml;llen
sowie gegen Direktwerbung (Art. 21 DSGVO)
</h3>{" "}
<p>
WENN DIE DATENVERARBEITUNG AUF GRUNDLAGE VON ART. 6 ABS. 1 LIT. E ODER F
DSGVO ERFOLGT, HABEN SIE JEDERZEIT DAS RECHT, AUS GR&Uuml;NDEN, DIE SICH
AUS IHRER BESONDEREN SITUATION ERGEBEN, GEGEN DIE VERARBEITUNG IHRER
PERSONENBEZOGENEN DATEN WIDERSPRUCH EINZULEGEN; DIES GILT AUCH F&Uuml;R
EIN AUF DIESE BESTIMMUNGEN GEST&Uuml;TZTES PROFILING. DIE JEWEILIGE
RECHTSGRUNDLAGE, AUF DENEN EINE VERARBEITUNG BERUHT, ENTNEHMEN SIE
DIESER DATENSCHUTZERKL&Auml;RUNG. WENN SIE WIDERSPRUCH EINLEGEN, WERDEN
WIR IHRE BETROFFENEN PERSONENBEZOGENEN DATEN NICHT MEHR VERARBEITEN, ES
SEI DENN, WIR K&Ouml;NNEN ZWINGENDE SCHUTZW&Uuml;RDIGE GR&Uuml;NDE
F&Uuml;R DIE VERARBEITUNG NACHWEISEN, DIE IHRE INTERESSEN, RECHTE UND
FREIHEITEN &Uuml;BERWIEGEN ODER DIE VERARBEITUNG DIENT DER
GELTENDMACHUNG, AUS&Uuml;BUNG ODER VERTEIDIGUNG VON
RECHTSANSPR&Uuml;CHEN (WIDERSPRUCH NACH ART. 21 ABS. 1 DSGVO).
</p>{" "}
<p>
WERDEN IHRE PERSONENBEZOGENEN DATEN VERARBEITET, UM DIREKTWERBUNG ZU
BETREIBEN, SO HABEN SIE DAS RECHT, JEDERZEIT WIDERSPRUCH GEGEN DIE
VERARBEITUNG SIE BETREFFENDER PERSONENBEZOGENER DATEN ZUM ZWECKE
DERARTIGER WERBUNG EINZULEGEN; DIES GILT AUCH F&Uuml;R DAS PROFILING,
SOWEIT ES MIT SOLCHER DIREKTWERBUNG IN VERBINDUNG STEHT. WENN SIE
WIDERSPRECHEN, WERDEN IHRE PERSONENBEZOGENEN DATEN ANSCHLIESSEND NICHT
MEHR ZUM ZWECKE DER DIREKTWERBUNG VERWENDET (WIDERSPRUCH NACH ART. 21
ABS. 2 DSGVO).
</p>
<h3>
Beschwerde&shy;recht bei der zust&auml;ndigen Aufsichts&shy;beh&ouml;rde
</h3>{" "}
<p>
Im Falle von Verst&ouml;&szlig;en gegen die DSGVO steht den Betroffenen
ein Beschwerderecht bei einer Aufsichtsbeh&ouml;rde, insbesondere in dem
Mitgliedstaat ihres gew&ouml;hnlichen Aufenthalts, ihres Arbeitsplatzes
oder des Orts des mutma&szlig;lichen Versto&szlig;es zu. Das
Beschwerderecht besteht unbeschadet anderweitiger verwaltungsrechtlicher
oder gerichtlicher Rechtsbehelfe.
</p>
<h3>Recht auf Daten&shy;&uuml;bertrag&shy;barkeit</h3>{" "}
<p>
Sie haben das Recht, Daten, die wir auf Grundlage Ihrer Einwilligung
oder in Erf&uuml;llung eines Vertrags automatisiert verarbeiten, an sich
oder an einen Dritten in einem g&auml;ngigen, maschinenlesbaren Format
aush&auml;ndigen zu lassen. Sofern Sie die direkte &Uuml;bertragung der
Daten an einen anderen Verantwortlichen verlangen, erfolgt dies nur,
soweit es technisch machbar ist.
</p>
<h3>Auskunft, Berichtigung und L&ouml;schung</h3>{" "}
<p>
Sie haben im Rahmen der geltenden gesetzlichen Bestimmungen jederzeit
das Recht auf unentgeltliche Auskunft &uuml;ber Ihre gespeicherten
personenbezogenen Daten, deren Herkunft und Empf&auml;nger und den Zweck
der Datenverarbeitung und ggf. ein Recht auf Berichtigung oder
L&ouml;schung dieser Daten. Hierzu sowie zu weiteren Fragen zum Thema
personenbezogene Daten k&ouml;nnen Sie sich jederzeit an uns wenden.
</p>
<h3>Recht auf Einschr&auml;nkung der Verarbeitung</h3>{" "}
<p>
Sie haben das Recht, die Einschr&auml;nkung der Verarbeitung Ihrer
personenbezogenen Daten zu verlangen. Hierzu k&ouml;nnen Sie sich
jederzeit an uns wenden. Das Recht auf Einschr&auml;nkung der
Verarbeitung besteht in folgenden F&auml;llen:
</p>{" "}
<ul>
{" "}
<li>
Wenn Sie die Richtigkeit Ihrer bei uns gespeicherten personenbezogenen
Daten bestreiten, ben&ouml;tigen wir in der Regel Zeit, um dies zu
&uuml;berpr&uuml;fen. F&uuml;r die Dauer der Pr&uuml;fung haben Sie
das Recht, die Einschr&auml;nkung der Verarbeitung Ihrer
personenbezogenen Daten zu verlangen.
</li>{" "}
<li>
Wenn die Verarbeitung Ihrer personenbezogenen Daten
unrechtm&auml;&szlig;ig geschah/geschieht, k&ouml;nnen Sie statt der
L&ouml;schung die Einschr&auml;nkung der Datenverarbeitung verlangen.
</li>{" "}
<li>
Wenn wir Ihre personenbezogenen Daten nicht mehr ben&ouml;tigen, Sie
sie jedoch zur Aus&uuml;bung, Verteidigung oder Geltendmachung von
Rechtsanspr&uuml;chen ben&ouml;tigen, haben Sie das Recht, statt der
L&ouml;schung die Einschr&auml;nkung der Verarbeitung Ihrer
personenbezogenen Daten zu verlangen.
</li>{" "}
<li>
Wenn Sie einen Widerspruch nach Art. 21 Abs. 1 DSGVO eingelegt haben,
muss eine Abw&auml;gung zwischen Ihren und unseren Interessen
vorgenommen werden. Solange noch nicht feststeht, wessen Interessen
&uuml;berwiegen, haben Sie das Recht, die Einschr&auml;nkung der
Verarbeitung Ihrer personenbezogenen Daten zu verlangen.
</li>{" "}
</ul>
<p>
Wenn Sie die Verarbeitung Ihrer personenbezogenen Daten
eingeschr&auml;nkt haben, d&uuml;rfen diese Daten &ndash; von ihrer
Speicherung abgesehen &ndash; nur mit Ihrer Einwilligung oder zur
Geltendmachung, Aus&uuml;bung oder Verteidigung von
Rechtsanspr&uuml;chen oder zum Schutz der Rechte einer anderen
nat&uuml;rlichen oder juristischen Person oder aus Gr&uuml;nden eines
wichtigen &ouml;ffentlichen Interesses der Europ&auml;ischen Union oder
eines Mitgliedstaats verarbeitet werden.
</p>
<h3>SSL- bzw. TLS-Verschl&uuml;sselung</h3>{" "}
<p>
Diese Seite nutzt aus Sicherheitsgr&uuml;nden und zum Schutz der
&Uuml;bertragung vertraulicher Inhalte, wie zum Beispiel Bestellungen
oder Anfragen, die Sie an uns als Seitenbetreiber senden, eine SSL- bzw.
TLS-Verschl&uuml;sselung. Eine verschl&uuml;sselte Verbindung erkennen
Sie daran, dass die Adresszeile des Browsers von &bdquo;http://&ldquo;
auf &bdquo;https://&ldquo; wechselt und an dem Schloss-Symbol in Ihrer
Browserzeile.
</p>{" "}
<p>
Wenn die SSL- bzw. TLS-Verschl&uuml;sselung aktiviert ist, k&ouml;nnen
die Daten, die Sie an uns &uuml;bermitteln, nicht von Dritten mitgelesen
werden.
</p>
<h2 className="text-2xl font-bold text-slate-900 mt-8 mb-4">4. Plugins und Tools</h2>
<h3>YouTube</h3>{" "}
<p>
Diese Website bindet Videos der Website YouTube ein. Betreiber der
Website ist die Google Ireland Limited (&bdquo;Google&ldquo;), Gordon
House, Barrow Street, Dublin 4, Irland.
</p>{" "}
<p>
Wenn Sie eine unserer Webseiten besuchen, auf denen YouTube eingebunden
ist, wird eine Verbindung zu den Servern von YouTube hergestellt. Dabei
wird dem YouTube-Server mitgeteilt, welche unserer Seiten Sie besucht
haben.
</p>
<p>
Des Weiteren kann YouTube verschiedene Cookies auf Ihrem Endger&auml;t
speichern oder vergleichbare Technologien zur Wiedererkennung verwenden
(z.&nbsp;B. Device-Fingerprinting). Auf diese Weise kann YouTube
Informationen &uuml;ber Besucher dieser Website erhalten. Diese
Informationen werden u.&nbsp;a. verwendet, um Videostatistiken zu
erfassen, die Anwenderfreundlichkeit zu verbessern und Betrugsversuchen
vorzubeugen. Des Weiteren werden die erfassten Daten im
Google-Werbenetzwerk verarbeitet.
</p>{" "}
<p>
Wenn Sie in Ihrem YouTube-Account eingeloggt sind, erm&ouml;glichen Sie
YouTube, Ihr Surfverhalten direkt Ihrem pers&ouml;nlichen Profil
zuzuordnen. Dies k&ouml;nnen Sie verhindern, indem Sie sich aus Ihrem
YouTube-Account ausloggen.
</p>{" "}
<p>
Die Nutzung von YouTube erfolgt im Interesse einer ansprechenden
Darstellung unserer Online- Angebote. Dies stellt ein berechtigtes
Interesse im Sinne von Art. 6 Abs. 1 lit. f DSGVO dar. Sofern eine
entsprechende Einwilligung abgefragt wurde, erfolgt die Verarbeitung
ausschlie&szlig;lich auf Grundlage von Art. 6 Abs. 1 lit. a DSGVO und
&sect; 25 Abs. 1 TDDDG, soweit die Einwilligung die Speicherung von
Cookies oder den Zugriff auf Informationen im Endger&auml;t des Nutzers
(z.&nbsp;B. Device-Fingerprinting) im Sinne des TDDDG umfasst. Die
Einwilligung ist jederzeit widerrufbar.
</p>{" "}
<p>
Weitere Informationen zum Umgang mit Nutzerdaten finden Sie in der
Datenschutzerkl&auml;rung von YouTube unter:{" "}
<a
href="https://policies.google.com/privacy?hl=de"
target="_blank"
rel="noopener
noreferrer"
>
https://policies.google.com/privacy?hl=de
</a>
.
</p>
<p>
Das Unternehmen verf&uuml;gt &uuml;ber eine Zertifizierung nach dem
&bdquo;EU-US Data Privacy Framework&ldquo; (DPF). Der DPF ist ein
&Uuml;bereinkommen zwischen der Europ&auml;ischen Union und den USA, der
die Einhaltung europ&auml;ischer Datenschutzstandards bei
Datenverarbeitungen in den USA gew&auml;hrleisten soll. Jedes nach dem
DPF zertifizierte Unternehmen verpflichtet sich, diese
Datenschutzstandards einzuhalten. Weitere Informationen hierzu erhalten
Sie vom Anbieter unter folgendem Link:
<a
href="https://www.dataprivacyframework.gov/participant/5780"
target="_blank"
rel="noopener
>
https://policies.google.com/privacy?hl=de
</a>
.
</p>
<p>
Das Unternehmen verf&uuml;gt &uuml;ber eine Zertifizierung nach dem
&bdquo;EU-US Data Privacy Framework&ldquo; (DPF). Der DPF ist ein
&Uuml;bereinkommen zwischen der Europ&auml;ischen Union und den USA, der
die Einhaltung europ&auml;ischer Datenschutzstandards bei
Datenverarbeitungen in den USA gew&auml;hrleisten soll. Jedes nach dem
DPF zertifizierte Unternehmen verpflichtet sich, diese
Datenschutzstandards einzuhalten. Weitere Informationen hierzu erhalten
Sie vom Anbieter unter folgendem Link:
<a
href="https://www.dataprivacyframework.gov/participant/5780"
target="_blank"
rel="noopener
noreferrer"
>
https://www.dataprivacyframework.gov/participant/5780
</a>
</p>
<h3>
{" "}
<strong>GitHub</strong>
<br />
</h3>
<p>
Diese Website bindet Inhalte der Website GitHub ein.
<br />
Betreiber der Website ist GitHub, Inc., 88 Colin P Kelly Jr Street, San
Francisco, CA 94107, USA.
</p>
<p>
Wenn Sie eine unserer Webseiten besuchen, auf denen GitHub-Inhalte
eingebunden sind (z.B. eingebettete Gists, Code-Beispiele), wird
möglicherweise eine Verbindung zu den Servern von GitHub hergestellt.
Dabei kann dem GitHub-Server mitgeteilt werden, welche unserer Seiten
Sie besucht haben.
</p>
<p>
Des Weiteren kann GitHub verschiedene Cookies auf Ihrem Endgerät
speichern oder vergleichbare Technologien zur Wiedererkennung verwenden
(z.B. Browser-Fingerprinting). Auf diese Weise kann GitHub Informationen
über Besucher dieser Website erhalten, die mit den eingebetteten
Inhalten interagieren. Diese Informationen können u.a. verwendet werden,
um die Funktionalität der eingebetteten Inhalte zu gewährleisten und
statistische Daten über deren Nutzung zu erfassen. Des Weiteren werden
die erfassten Daten möglicherweise im Rahmen der Dienste von GitHub
verarbeitet.
</p>
<p>
Wenn Sie in Ihrem GitHub-Account eingeloggt sind, ermöglicht dies GitHub
unter Umständen, Ihre Interaktion mit den eingebetteten Inhalten direkt
Ihrem persönlichen Profil zuzuordnen. Dies können Sie verhindern, indem
Sie sich aus Ihrem GitHub-Account ausloggen, bevor Sie unsere Seite
besuchen.
</p>
<p>
Die Nutzung von GitHub-Inhalten erfolgt im Interesse einer ansprechenden
Darstellung unserer Online-Angebote und der Bereitstellung nützlicher
Informationen und Ressourcen. Dies stellt ein berechtigtes Interesse im
Sinne von Art. 6 Abs. 1 lit. f DSGVO dar. Sofern eine entsprechende
Einwilligung abgefragt wurde, erfolgt die Verarbeitung ausschließlich
auf Grundlage von Art. 6 Abs. 1 lit. a DSGVO und § 25 Abs. 1 TDDDG,
soweit die Einwilligung die Speicherung von Cookies oder den Zugriff auf
Informationen im Endgerät des Nutzers (z.B. Device-Fingerprinting) im
Sinne des TDDDG umfasst. Die Einwilligung ist jederzeit widerrufbar.
</p>
<p>
Weitere Informationen zum Umgang mit Nutzerdaten finden Sie in der
Datenschutzerklärung von GitHub unter:
<a href="https://docs.github.com/de/site-policy/privacy-policies/github-general-privacy-statement">
https://docs.github.com/de/site-policy/privacy-policies/github-general-privacy-statement
</a>
.
</p>
<p>
Das Unternehmen verfügt über eine Zertifizierung nach dem EU-US Data
Privacy Framework (DPF). Der DPF ist ein Übereinkommen zwischen der
Europäischen Union und den USA, das die Einhaltung europäischer
Datenschutzstandards bei Datenverarbeitungen in den USA gewährleisten
soll. Jedes nach dem DPF zertifizierte Unternehmen verpflichtet sich,
diese Datenschutzstandards einzuhalten. Weitere Informationen hierzu
erhalten Sie vom Anbieter unter folgendem Link:
<a href="https://www.dataprivacyframework.gov/">
https://www.dataprivacyframework.gov/
</a>
</p>
<p>
Quelle: <a href="https://www.e-recht24.de">https://www.e-recht24.de</a>
</p>
>
https://www.dataprivacyframework.gov/participant/5780
</a>
</p>
<h3>
{" "}
<strong>GitHub</strong>
<br />
</h3>
<p>
Diese Website bindet Inhalte der Website GitHub ein.
<br />
Betreiber der Website ist GitHub, Inc., 88 Colin P Kelly Jr Street, San
Francisco, CA 94107, USA.
</p>
<p>
Wenn Sie eine unserer Webseiten besuchen, auf denen GitHub-Inhalte
eingebunden sind (z.B. eingebettete Gists, Code-Beispiele), wird
möglicherweise eine Verbindung zu den Servern von GitHub hergestellt.
Dabei kann dem GitHub-Server mitgeteilt werden, welche unserer Seiten
Sie besucht haben.
</p>
<p>
Des Weiteren kann GitHub verschiedene Cookies auf Ihrem Endgerät
speichern oder vergleichbare Technologien zur Wiedererkennung verwenden
(z.B. Browser-Fingerprinting). Auf diese Weise kann GitHub Informationen
über Besucher dieser Website erhalten, die mit den eingebetteten
Inhalten interagieren. Diese Informationen können u.a. verwendet werden,
um die Funktionalität der eingebetteten Inhalte zu gewährleisten und
statistische Daten über deren Nutzung zu erfassen. Des Weiteren werden
die erfassten Daten möglicherweise im Rahmen der Dienste von GitHub
verarbeitet.
</p>
<p>
Wenn Sie in Ihrem GitHub-Account eingeloggt sind, ermöglicht dies GitHub
unter Umständen, Ihre Interaktion mit den eingebetteten Inhalten direkt
Ihrem persönlichen Profil zuzuordnen. Dies können Sie verhindern, indem
Sie sich aus Ihrem GitHub-Account ausloggen, bevor Sie unsere Seite
besuchen.
</p>
<p>
Die Nutzung von GitHub-Inhalten erfolgt im Interesse einer ansprechenden
Darstellung unserer Online-Angebote und der Bereitstellung nützlicher
Informationen und Ressourcen. Dies stellt ein berechtigtes Interesse im
Sinne von Art. 6 Abs. 1 lit. f DSGVO dar. Sofern eine entsprechende
Einwilligung abgefragt wurde, erfolgt die Verarbeitung ausschließlich
auf Grundlage von Art. 6 Abs. 1 lit. a DSGVO und § 25 Abs. 1 TDDDG,
soweit die Einwilligung die Speicherung von Cookies oder den Zugriff auf
Informationen im Endgerät des Nutzers (z.B. Device-Fingerprinting) im
Sinne des TDDDG umfasst. Die Einwilligung ist jederzeit widerrufbar.
</p>
<p>
Weitere Informationen zum Umgang mit Nutzerdaten finden Sie in der
Datenschutzerklärung von GitHub unter:
<a href="https://docs.github.com/de/site-policy/privacy-policies/github-general-privacy-statement">
https://docs.github.com/de/site-policy/privacy-policies/github-general-privacy-statement
</a>
.
</p>
<p>
Das Unternehmen verfügt über eine Zertifizierung nach dem EU-US Data
Privacy Framework (DPF). Der DPF ist ein Übereinkommen zwischen der
Europäischen Union und den USA, das die Einhaltung europäischer
Datenschutzstandards bei Datenverarbeitungen in den USA gewährleisten
soll. Jedes nach dem DPF zertifizierte Unternehmen verpflichtet sich,
diese Datenschutzstandards einzuhalten. Weitere Informationen hierzu
erhalten Sie vom Anbieter unter folgendem Link:
<a href="https://www.dataprivacyframework.gov/">
https://www.dataprivacyframework.gov/
</a>
</p>
<p>
Quelle: <a href="https://www.e-recht24.de">https://www.e-recht24.de</a>
</p>
</div>
</section>
);
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,170 @@
import React, { useEffect } from "react";
import mermaid from "mermaid";
const Wireframe = ({ title, children }) => (
<div className="w-full md:w-1/2 lg:w-1/3 px-2 mb-4">
<div className="h-full bg-white rounded-lg shadow-sm border border-slate-200 overflow-hidden flex flex-col">
<div className="bg-slate-50 px-4 py-2 border-b border-slate-200">
<h5 className="text-center font-semibold text-slate-700 m-0 text-sm md:text-base">{title}</h5>
</div>
<div className="p-2 flex-grow flex justify-center items-center overflow-hidden bg-slate-100">
<div className="bg-white w-full h-full border border-slate-200 rounded-lg shadow-inner p-3 flex flex-col overflow-hidden relative" style={{ aspectRatio: '9 / 19.5' }}>
{children}
</div>
</div>
</div>
</div>
);
function LanguageRoleplay() {
useEffect(() => {
const initMermaid = async () => {
try {
mermaid.initialize({ startOnLoad: false, theme: 'neutral' });
const mermaidEls = document.querySelectorAll('.mermaid');
if (mermaidEls.length > 0) {
await mermaid.run();
}
} catch (err) {
console.error("Mermaid initialization or run error:", err);
}
};
// Slight delay to ensure DOM is ready
const timer = setTimeout(() => {
initMermaid();
}, 100);
return () => clearTimeout(timer);
}, []);
return (
<div className="bg-slate-50 min-h-screen py-8 font-sans text-slate-800">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<header className="text-center border-b border-slate-200 pb-8 mb-12">
<h1 className="text-3xl md:text-5xl font-extrabold text-slate-900 mb-6 tracking-tight">KI Sprachenlern Roleplay</h1>
<div className="mt-6 flex flex-wrap justify-center gap-4">
<div className="bg-white px-4 py-2 rounded-full border border-slate-200 shadow-sm flex items-center space-x-2">
<span className="bg-slate-200 text-slate-700 text-xs font-bold px-2 py-0.5 rounded uppercase tracking-wide">Status</span>
<span className="text-sm font-medium text-slate-600">In Arbeit</span>
</div>
<div className="bg-white px-4 py-2 rounded-full border border-slate-200 shadow-sm flex items-center space-x-2">
<span className="bg-slate-200 text-slate-700 text-xs font-bold px-2 py-0.5 rounded uppercase tracking-wide">Autor</span>
<span className="text-sm font-medium text-slate-600">Simon Altschäffl</span>
</div>
</div>
</header>
<section className="mb-16">
<h2 className="text-2xl font-bold text-slate-900 mb-6 border-l-4 border-indigo-500 pl-4">1. Philosophie: Learning by Doing</h2>
<div className="bg-white p-6 rounded-xl border border-slate-200 shadow-sm space-y-4">
<p className="text-lg leading-relaxed text-slate-700">
Der Fokus dieses Projekts liegt nicht auf grammatikalischer Perfektion, sondern auf der
Anwendung der Sprache in realistischen Situationen. Es geht darum, die Angst vor dem Sprechen
zu verlieren und durch "Learning by Doing" Sicherheit zu gewinnen.
</p>
<p className="text-lg leading-relaxed text-slate-700">
Die KI agiert dabei als geduldiger, natrlich wirkender Gesprächspartner, der ermutigt
statt nur zu korrigieren. Ziel ist ein flüssiger Dialog, bei dem der Nutzer spielerisch lernt.
</p>
</div>
</section>
<section className="mb-16">
<h2 className="text-2xl font-bold text-slate-900 mb-6 border-l-4 border-indigo-500 pl-4">2. Geplante Features & Gamification</h2>
<div className="grid grid-cols-1 md:grid-cols-2 gap-6 mt-6">
<div className="h-full">
<div className="h-full bg-white rounded-xl border border-slate-200 shadow-sm p-6 hover:shadow-md transition-shadow">
<h3 className="text-xl font-bold text-slate-800 mb-4 pb-2 border-b border-slate-100">Spielerisches Lernen</h3>
<ul className="list-disc pl-5 space-y-2 text-slate-700">
<li><strong>Lern-Level:</strong> Progression von einfachen Anfnger-Szenarien zu komplexen Diskussionen.</li>
<li><strong>Szenario-Ziele:</strong> Klare Aufgaben pro Chat (z.B. "Bestelle einen Kaffee", "Handle einen Rabatt aus"), die das Gefühl eines Spiels vermitteln.</li>
<li><strong>Dynamische Handlung:</strong> Die KI reagiert spontan auf Nutzerentscheidungen.</li>
</ul>
</div>
</div>
<div className="h-full">
<div className="h-full bg-white rounded-xl border border-slate-200 shadow-sm p-6 hover:shadow-md transition-shadow">
<h3 className="text-xl font-bold text-slate-800 mb-4 pb-2 border-b border-slate-100">Unterstützende KI</h3>
<ul className="list-disc pl-5 space-y-2 text-slate-700">
<li>Natürliche, ermutigende Reaktionen.</li>
<li>Kontextbezogene Hilfestellungen statt stumpfer Korrekturen.</li>
<li>Adaptive Schwierigkeit basierend auf dem Nutzerverhalten.</li>
</ul>
</div>
</div>
</div>
</section>
<section className="mb-16">
<h2 className="text-2xl font-bold text-slate-900 mb-6 border-l-4 border-indigo-500 pl-4">3. Aktueller technischer Status</h2>
<div className="bg-white p-6 rounded-xl border border-slate-200 shadow-sm space-y-4">
<div className="flex items-start space-x-3 text-slate-700">
<span className="text-amber-500 text-xl"></span>
<p><strong>Work in Progress:</strong> Das Projekt befindet sich in der aktiven Entwicklung.</p>
</div>
<ul className="list-disc pl-5 space-y-2 text-slate-700">
<li><strong>Authentifizierung:</strong> Derzeit noch nicht implementiert. Jeder kann sofort loslegen.</li>
<li><strong>Datenhaltung:</strong> Speicherung des Fortschritts erfolgt aktuell ausschließlich lokal im Browser (LocalStorage). Es gibt noch keine persistente Datenbank.</li>
</ul>
</div>
</section>
<section className="mb-16">
<h2 className="text-2xl font-bold text-slate-900 mb-6 border-l-4 border-indigo-500 pl-4">4. UI Konzept (Work in Progress)</h2>
<p className="text-lg text-slate-700 mb-8">Erste Entwürfe für die Benutzeroberfläche.</p>
<div className="flex flex-wrap -mx-2 justify-center">
<Wireframe title="Szenario-Auswahl">
<div className="text-center pt-4 pb-3">
<h4 className="font-bold text-lg text-slate-800">Wähle ein Abenteuer</h4>
</div>
<div className="px-3 flex-grow flex flex-col space-y-3 overflow-y-auto">
<div className="p-3 border rounded-lg bg-blue-50 border-blue-200 cursor-pointer hover:bg-blue-100">
<h5 className="font-bold text-sm text-blue-800">Im Café in Paris</h5>
<p className="text-xs text-blue-600">Bestelle Kaffee und Croissants auf Französisch.</p>
</div>
<div className="p-3 border rounded-lg bg-green-50 border-green-200 cursor-pointer hover:bg-green-100">
<h5 className="font-bold text-sm text-green-800">Markt in Madrid</h5>
<p className="text-xs text-green-600">Kaufe frisches Obst und Gemüse auf Spanisch.</p>
</div>
<div className="p-3 border rounded-lg bg-gray-50 border-gray-200 cursor-pointer hover:bg-gray-100 opacity-70">
<h5 className="font-bold text-sm text-gray-800">Bahnhof in Berlin</h5>
<p className="text-xs text-gray-600">Kaufe ein Ticket und finde das richtige Gleis.</p>
</div>
</div>
</Wireframe>
<Wireframe title="Chat-Interface">
<div className="flex flex-col h-full">
<div className="bg-slate-100 p-2 border-b text-center text-xs font-bold">
Café-Besitzer (KI)
</div>
<div className="flex-grow p-2 overflow-y-auto space-y-2">
<div className="bg-white p-2 rounded-lg rounded-tl-none border border-slate-200 text-xs self-start max-w-[80%]">
Bonjour! Was möchten Sie bestellen?
</div>
<div className="bg-blue-100 p-2 rounded-lg rounded-tr-none text-xs self-end max-w-[80%] ml-auto">
Je voudrais un croissant, s'il vous plaît.
</div>
<div className="bg-white p-2 rounded-lg rounded-tl-none border border-slate-200 text-xs self-start max-w-[80%]">
Sehr gerne. Möchten Sie auch einen Kaffee dazu?
</div>
</div>
<div className="p-2 border-t bg-white">
<div className="flex gap-1">
<input type="text" className="w-full border rounded px-2 py-1 text-xs" placeholder="Antwort eingeben..." />
<button className="bg-blue-500 text-white rounded px-2 py-1 text-xs"></button>
</div>
</div>
</div>
</Wireframe>
</div>
</section>
</div>
</div>
);
}
export default LanguageRoleplay;

View File

@ -2,48 +2,63 @@ import React from "react";
function LanguagestudyPage() {
return (
<section className="content-group">
<h1 className="project-header">Wikipedia Sprachstudie</h1>
<p className="centered" style={{ marginTop: '1em' }}>
<em>Dieses Projekt war mein Abschlussprojekt f&uuml;r den Kurs &bdquo;CS50x&ldquo;.</em>
<section className="max-w-4xl mx-auto px-4 py-12 font-sans text-slate-800">
<h1 className="text-3xl md:text-4xl font-extrabold text-slate-900 mb-8 pb-4 border-b border-slate-200 text-center">Wikipedia Sprachstudie</h1>
<p className="text-center text-lg text-slate-600 mt-4 italic">
Dieses Projekt war mein Abschlussprojekt f&uuml;r den Kurs &bdquo;CS50x&ldquo;.
</p>
<div className="centered" style={{ marginTop: '2em' }}>
<h3>GitHub</h3>
<a href="https://github.com/simon-266/WikiDictionaryResearch">
<div className="text-center mt-8 p-4 bg-slate-50 rounded-lg border border-slate-100 inline-block w-full">
<h3 className="text-lg font-bold text-slate-800 mb-2">GitHub Repository</h3>
<a
href="https://github.com/simon-266/WikiDictionaryResearch"
className="text-blue-600 hover:text-blue-800 hover:underline break-all"
target="_blank"
rel="noopener noreferrer"
>
https://github.com/simon-266/WikiDictionaryResearch
</a>
</div>
<div>
<h2 style={{ marginTop: '2em' }}>Worum geht es in dieser Sprachstudie?</h2>
<p>
<div className="mt-12">
<h2 className="text-2xl font-bold text-slate-900 mb-4">Worum geht es in dieser Sprachstudie?</h2>
<p className="text-slate-700 leading-relaxed mb-6">
Ziel dieser Sprachstudie ist es, einem oft geh&ouml;rten Fakt beim
Sprachenlernen nachzugehen und ihn zu beweisen oder zu widerlegen. Der
Fakt lautet:{" "}
<b>
<span className="block my-4 p-4 bg-amber-50 border-l-4 border-amber-400 text-amber-900 font-medium rounded-r">
&bdquo;Die 1000 h&auml;ufigsten W&ouml;rter machen etwa 80 % des gesprochenen
Wortschatzes aus.&ldquo;
</b>
</span>
Um dies zu untersuchen, habe ich ein Skript programmiert, welches 15.000
Wikipedia-Seiten durchsucht und die englischen W&ouml;rter darin z&auml;hlt.
Zus&auml;tzlich habe ich einige Diagramme zu meinen Ergebnissen in einem
Jupyter Notebook erstellt:
</p>
<div className="image-container">
<img
src="/assets/projects/languageStudy/images/top1000.png"
alt="Kreisdiagramm: Die Top 1000 W&ouml;rter im Vergleich zum Rest"
className="center-image"
/>
<img
src="/assets/projects/languageStudy/images/stats.png"
alt="Kreisdiagramm: Vergleiche der Vorkommen"
className="center-image"
/>
<div className="flex flex-wrap justify-center gap-8 my-10">
<div className="w-full md:w-5/12">
<img
src="/assets/projects/languageStudy/images/top1000.png"
alt="Kreisdiagramm: Die Top 1000 W&ouml;rter im Vergleich zum Rest"
className="w-full h-auto rounded-lg shadow-md border border-slate-200"
/>
<p className="text-sm text-center text-slate-500 mt-2">Top 1000 W&ouml;rter vs. Rest</p>
</div>
<div className="w-full md:w-5/12">
<img
src="/assets/projects/languageStudy/images/stats.png"
alt="Kreisdiagramm: Vergleiche der Vorkommen"
className="w-full h-auto rounded-lg shadow-md border border-slate-200"
/>
<p className="text-sm text-center text-slate-500 mt-2">H&auml;ufigkeitsverteilung</p>
</div>
</div>
</div>
<div>
<h2 style={{ marginTop: '2em' }}>Ergebnisse</h2>
<p>
<div className="mt-12">
<h2 className="text-2xl font-bold text-slate-900 mb-4">Ergebnisse</h2>
<p className="text-slate-700 leading-relaxed">
Die Ergebnisse zeigen deutlich, dass die Top 1000 W&ouml;rter tats&auml;chlich
einen sehr gro&szlig;en Anteil ausmachen &ndash; auch wenn es nicht ganz 80 %,
sondern <em>knapp 70 %</em> sind. Daraus l&auml;sst sich schlussfolgern, dass es sich
@ -52,12 +67,12 @@ function LanguagestudyPage() {
</p>
</div>
<div>
<h2 style={{ marginTop: '2em' }}>
<div className="mt-12">
<h2 className="text-2xl font-bold text-slate-900 mb-6">
Welche Techniken, Technologien und Bibliotheken habe ich verwendet?
</h2>
<div className="list-display">
<ul className="key-points">
<div className="bg-slate-50 p-6 rounded-xl border border-slate-100 shadow-sm">
<ul className="list-disc pl-5 space-y-3 text-slate-700">
<li>
<b>Programmiersprachen</b>: Python, IPython
</li>
@ -66,7 +81,7 @@ function LanguagestudyPage() {
</li>
<li>
<b>Multithreading und Batchverarbeitung</b>: Mithilfe der <em>Future
Library</em> konnte ich das Z&auml;hlen der W&ouml;rter auf mehrere Threads
Library</em> konnte ich das Z&auml;hlen der W&ouml;rter auf mehrere Threads
verteilen. Durch einfache Schleifen konnte ich den ben&ouml;tigten
Arbeitsspeicher begrenzen, indem ich die 15.000 Seiten in kleinere
Batches aufteilte, diese vorab zusammenf&uuml;hrte und am Ende zum
@ -88,10 +103,11 @@ function LanguagestudyPage() {
</ul>
</div>
</div>
<div>
<h2 style={{ marginTop: '2em' }}>Fazit</h2>
<div className="list-display">
<ul className="key-points">
<div className="mt-12">
<h2 className="text-2xl font-bold text-slate-900 mb-4">Fazit</h2>
<div className="bg-slate-50 p-6 rounded-xl border border-slate-100 shadow-sm">
<ul className="list-disc pl-5 space-y-3 text-slate-700">
<li>
<b>Neues Wissen</b>: Durch dieses Projekt konnte ich mich zum ersten
Mal intensiv mit den Themen Webscraping (auch wenn es &uuml;ber eine

View File

@ -2,136 +2,154 @@ import React from "react";
function ServerPage() {
return (
<section className="content-group">
<h1 className="project-header">Struktur dieses Servers</h1>
<img
src="/assets/projects/server/images/server.png"
alt="Server Struktur Diagramm"
className="center-image"
/>
<div className="list-display" style={{ marginTop: '2em' }}>
<h2>Welche Kernaufgaben erf&uuml;llt dieser Server?</h2>
<ul className="key-points">
<li>Die Bereitstellung dieser Website über Nginx</li>
<li>Die Bereitstellung des JupyterHub-Servers für Data Science und Machine Learning</li>
<li>
Automatische Aktualisierung der React-Applikation durch GitHub-Webhooks
über die Flask-App
</li>
<li>Sichere Remote-Verbindung über WireGuard VPN und SSH</li>
<li>Zentrales Routing und Load Balancing durch Traefik</li>
</ul>
<section className="max-w-4xl mx-auto px-4 py-12 font-sans text-slate-800">
<h1 className="text-3xl md:text-4xl font-extrabold text-slate-900 mb-8 pb-4 border-b border-slate-200 text-center">Struktur dieses Servers</h1>
<div className="bg-white p-4 rounded-xl border border-slate-200 shadow-sm mb-12">
<img
src="/assets/projects/server/images/server.png"
alt="Server Struktur Diagramm"
className="w-full h-auto rounded-lg"
/>
</div>
<div className="list-display" style={{ marginTop: '2em' }}>
<h3>Wichtige Kerntechnologien</h3>
<ul className="key-points">
<li>
<b>Docker und Docker-Compose</b>: Jeder Service läuft in einem eigenen Container,
was die Modularität und Wartbarkeit erhöht. Die Container-Architektur
ermöglicht eine klare Trennung der Dienste und vereinfacht das Deployment
sowie Updates.
</li>
<li>
<b>Traefik</b>: Fungiert als zentraler Reverse Proxy und Load Balancer.
Traefik übernimmt das Routing der Anfragen zu den entsprechenden Services,
verwaltet SSL-Zertifikate automatisch und ermöglicht eine einfache
Integration neuer Dienste durch Docker-Labels.
</li>
<li>
<b>Nginx</b>: Dient als Webserver für die React-App und stellt die
statischen Inhalte bereit.
</li>
<li>
<b>JupyterHub</b>: Ermöglicht die Verwaltung von Jupyter-Notebooks
für Data Science und Machine Learning. Benutzer können ihre eigenen
JupyterLab-Umgebungen über jupyter.simonaltschaeffl.de aufrufen.
</li>
<li>
<b>Flask</b>: Verarbeitet GitHub-Webhooks und triggert automatische
Updates der React-App. Die Flask-Anwendung verifiziert die Webhook-
Authentizität und stößt den Update-Prozess an.
</li>
<li>
<b>WireGuard VPN & SSH</b>: Bietet sicheren Remote-Zugriff auf den
Server. WireGuard ermöglicht eine moderne, schnelle VPN-Verbindung,
während der SSH-Server sichere Terminal-Verbindungen bereitstellt.
</li>
</ul>
<div className="mb-12">
<h2 className="text-2xl font-bold text-slate-900 mb-4 border-b pb-2">Welche Kernaufgaben erf&uuml;llt dieser Server?</h2>
<div className="bg-slate-50 p-6 rounded-xl border border-slate-100 shadow-sm mt-4">
<ul className="list-disc pl-5 space-y-2 text-slate-700">
<li>Die Bereitstellung dieser Website über Nginx</li>
<li>Die Bereitstellung des JupyterHub-Servers für Data Science und Machine Learning</li>
<li>
Automatische Aktualisierung der React-Applikation durch GitHub-Webhooks
über die Flask-App
</li>
<li>Sichere Remote-Verbindung über WireGuard VPN und SSH</li>
<li>Zentrales Routing und Load Balancing durch Traefik</li>
</ul>
</div>
</div>
<div style={{ marginTop: '2em' }}>
<h3>Routing und Zugriff</h3>
<p>
Alle Anfragen werden zunächst von Traefik empfangen und basierend auf der
Domain an die entsprechenden Services weitergeleitet. Die Website ist unter
simonaltschaeffl.de erreichbar, wobei Traefik die Anfragen an den
Nginx-Container weiterleitet, der die React-Applikation bereitstellt.
</p>
<h3>JupyterHub &amp; JupyterLab</h3>
<p>
Der JupyterHub-Service ist über jupyter.simonaltschaeffl.de erreichbar.
Traefik leitet die Anfragen an den JupyterHub-Container weiter, der die
Benutzerauthentifizierung und Container-Verwaltung übernimmt. Nach erfolgreicher
Anmeldung wird ein persönlicher JupyterLab-Container mit Data-Science-Tools
wie Pandas, TensorFlow, NumPy etc. gestartet, der für Machine Learning
Experimente und Datenanalysen genutzt werden kann.
</p>
<h3>Sicherheit und Remote-Zugriff</h3>
<p>
Der sichere Remote-Zugriff wird durch eine Kombination aus WireGuard VPN
und SSH gewährleistet. WireGuard bietet eine moderne, effiziente
VPN-Lösung, während der SSH-Server sichere Terminal-Verbindungen für
Wartungsarbeiten ermöglicht. Die Verwaltung erfolgt über einen
dedizierten Admin-Zugang.
</p>
<div className="mb-12">
<h3 className="text-xl font-bold text-slate-800 mb-4">Wichtige Kerntechnologien</h3>
<div className="bg-slate-50 p-6 rounded-xl border border-slate-100 shadow-sm">
<ul className="list-disc pl-5 space-y-4 text-slate-700">
<li>
<b>Docker und Docker-Compose</b>: Jeder Service läuft in einem eigenen Container,
was die Modularität und Wartbarkeit erhöht. Die Container-Architektur
ermöglicht eine klare Trennung der Dienste und vereinfacht das Deployment
sowie Updates.
</li>
<li>
<b>Traefik</b>: Fungiert als zentraler Reverse Proxy und Load Balancer.
Traefik übernimmt das Routing der Anfragen zu den entsprechenden Services,
verwaltet SSL-Zertifikate automatisch und ermöglicht eine einfache
Integration neuer Dienste durch Docker-Labels.
</li>
<li>
<b>Nginx</b>: Dient als Webserver für die React-App und stellt die
statischen Inhalte bereit.
</li>
<li>
<b>JupyterHub</b>: Ermöglicht die Verwaltung von Jupyter-Notebooks
für Data Science und Machine Learning. Benutzer können ihre eigenen
JupyterLab-Umgebungen über jupyter.simonaltschaeffl.de aufrufen.
</li>
<li>
<b>Flask</b>: Verarbeitet GitHub-Webhooks und triggert automatische
Updates der React-App. Die Flask-Anwendung verifiziert die Webhook-
Authentizität und stößt den Update-Prozess an.
</li>
<li>
<b>WireGuard VPN & SSH</b>: Bietet sicheren Remote-Zugriff auf den
Server. WireGuard ermöglicht eine moderne, schnelle VPN-Verbindung,
während der SSH-Server sichere Terminal-Verbindungen bereitstellt.
</li>
</ul>
</div>
</div>
<div className="list-display" style={{ marginTop: '2em' }}>
<h2>Mein Fazit</h2>
<ul className="key-points">
<li>
<b>Umfangreiches Lernen</b>: Das Projekt bot eine gro&szlig;artige M&ouml;glichkeit, neue Technologien wie
Docker und React von Grund auf zu lernen.
</li>
<li>
<b>Lernkurve war es wert</b>: Auch wenn das Verst&auml;ndnis der neuen Technologien Zeit brauchte, war
der Erkenntnisgewinn immens.
</li>
<li>
<b>Produktionsvorteile von Docker</b>: Das Projekt hat das Verst&auml;ndnis f&uuml;r die Bedeutung von Docker in
Produktionsumgebungen deutlich gemacht und wird die
Serverkonfiguration zuk&uuml;nftiger Projekte erleichtern.
</li>
<li>
<b>Effizienz von JavaScript-Bibliotheken (React)</b>: Die Einfachheit und Geschwindigkeit, mit der komplexe Webseiten mit
React erstellt werden k&ouml;nnen, hat positiv &uuml;berrascht und wird in
Zukunft h&auml;ufiger eingesetzt werden.
</li>
</ul>
<div className="mb-12 space-y-8">
<div>
<h3 className="text-xl font-bold text-slate-800 mb-2">Routing und Zugriff</h3>
<p className="text-slate-700 leading-relaxed">
Alle Anfragen werden zunächst von Traefik empfangen und basierend auf der
Domain an die entsprechenden Services weitergeleitet. Die Website ist unter
simonaltschaeffl.de erreichbar, wobei Traefik die Anfragen an den
Nginx-Container weiterleitet, der die React-Applikation bereitstellt.
</p>
</div>
<div>
<h3 className="text-xl font-bold text-slate-800 mb-2">JupyterHub &amp; JupyterLab</h3>
<p className="text-slate-700 leading-relaxed">
Der JupyterHub-Service ist über jupyter.simonaltschaeffl.de erreichbar.
Traefik leitet die Anfragen an den JupyterHub-Container weiter, der die
Benutzerauthentifizierung und Container-Verwaltung übernimmt. Nach erfolgreicher
Anmeldung wird ein persönlicher JupyterLab-Container mit Data-Science-Tools
wie Pandas, TensorFlow, NumPy etc. gestartet, der für Machine Learning
Experimente und Datenanalysen genutzt werden kann.
</p>
</div>
<div>
<h3 className="text-xl font-bold text-slate-800 mb-2">Sicherheit und Remote-Zugriff</h3>
<p className="text-slate-700 leading-relaxed">
Der sichere Remote-Zugriff wird durch eine Kombination aus WireGuard VPN
und SSH gewährleistet. WireGuard bietet eine moderne, effiziente
VPN-Lösung, während der SSH-Server sichere Terminal-Verbindungen für
Wartungsarbeiten ermöglicht. Die Verwaltung erfolgt über einen
dedizierten Admin-Zugang.
</p>
</div>
</div>
<div style={{ marginTop: '2em' }}>
<h3>Rolle von LLMs in der Konfiguration</h3>
<p>
Ich habe Chatbots in verschiedenen Bereichen eingesetzt, vor allem im
Bereich <em>Debugging und Rechtschreibung</em>. Viele Fehler, vor allem bei
Dockerfiles oder Docker-Compose-Dateien, konnten durch den Einsatz von
Chatbots effizient behoben werden.
</p>
<div className="mb-12">
<h2 className="text-2xl font-bold text-slate-900 mb-4 border-b pb-2">Mein Fazit</h2>
<div className="bg-slate-50 p-6 rounded-xl border border-slate-100 shadow-sm mt-4">
<ul className="list-disc pl-5 space-y-3 text-slate-700">
<li>
<b>Umfangreiches Lernen</b>: Das Projekt bot eine gro&szlig;artige M&ouml;glichkeit, neue Technologien wie
Docker und React von Grund auf zu lernen.
</li>
<li>
<b>Lernkurve war es wert</b>: Auch wenn das Verst&auml;ndnis der neuen Technologien Zeit brauchte, war
der Erkenntnisgewinn immens.
</li>
<li>
<b>Produktionsvorteile von Docker</b>: Das Projekt hat das Verst&auml;ndnis f&uuml;r die Bedeutung von Docker in
Produktionsumgebungen deutlich gemacht und wird die
Serverkonfiguration zuk&uuml;nftiger Projekte erleichtern.
</li>
<li>
<b>Effizienz von JavaScript-Bibliotheken (React)</b>: Die Einfachheit und Geschwindigkeit, mit der komplexe Webseiten mit
React erstellt werden k&ouml;nnen, hat positiv &uuml;berrascht und wird in
Zukunft h&auml;ufiger eingesetzt werden.
</li>
</ul>
</div>
</div>
<div className="list-display" style={{ marginTop: '2em' }}>
<h2>Ideen f&uuml;r die Zukunft des Servers</h2>
<ul className="key-points">
<li>Integration weiterer Dienste durch einfache Erweiterung der Traefik-Konfiguration</li>
<li>Implementierung eines Monitoring-Systems für bessere Überwachung der Services</li>
<li>Automatisierung der Backups und Disaster Recovery Prozesse</li>
<li>Erweiterung der JupyterHub-Umgebung mit zusätzlichen Data Science Tools</li>
</ul>
<div className="mb-12">
<h3 className="text-xl font-bold text-slate-800 mb-2">Rolle von LLMs in der Konfiguration</h3>
<div className="bg-indigo-50 p-6 rounded-xl border border-indigo-100 text-indigo-900">
<p>
Ich habe Chatbots in verschiedenen Bereichen eingesetzt, vor allem im
Bereich <em>Debugging und Rechtschreibung</em>. Viele Fehler, vor allem bei
Dockerfiles oder Docker-Compose-Dateien, konnten durch den Einsatz von
Chatbots effizient behoben werden.
</p>
</div>
</div>
<div>
<h2 className="text-2xl font-bold text-slate-900 mb-4 border-b pb-2">Ideen f&uuml;r die Zukunft des Servers</h2>
<div className="bg-emerald-50 p-6 rounded-xl border border-emerald-100 text-emerald-900">
<ul className="list-disc pl-5 space-y-2">
<li>Integration weiterer Dienste durch einfache Erweiterung der Traefik-Konfiguration</li>
<li>Implementierung eines Monitoring-Systems für bessere Überwachung der Services</li>
<li>Automatisierung der Backups und Disaster Recovery Prozesse</li>
<li>Erweiterung der JupyterHub-Umgebung mit zusätzlichen Data Science Tools</li>
</ul>
</div>
</div>
</section>
);

View File

@ -0,0 +1,206 @@
import React, { useEffect } from "react";
import mermaid from "mermaid";
const Wireframe = ({ title, children }) => (
<div className="w-full md:w-1/2 lg:w-1/3 px-2 mb-4">
<div className="h-full bg-white rounded-lg shadow-sm border border-slate-200 overflow-hidden flex flex-col">
<div className="bg-slate-50 px-4 py-2 border-b border-slate-200">
<h5 className="text-center font-semibold text-slate-700 m-0 text-sm md:text-base">{title}</h5>
</div>
<div className="p-2 flex-grow flex justify-center items-center overflow-hidden bg-slate-100">
<div className="bg-white w-full h-full border border-slate-200 rounded-lg shadow-inner p-3 flex flex-col overflow-hidden relative" style={{ aspectRatio: '9 / 12' }}>
{children}
</div>
</div>
</div>
</div>
);
function TdotPage() {
useEffect(() => {
const initMermaid = async () => {
try {
mermaid.initialize({ startOnLoad: false, theme: 'neutral' });
const mermaidEls = document.querySelectorAll('.mermaid');
if (mermaidEls.length > 0) {
await mermaid.run();
}
} catch (err) {
console.error("Mermaid initialization or run error:", err);
}
};
// Slight delay to ensure DOM is ready
const timer = setTimeout(() => {
initMermaid();
}, 100);
return () => clearTimeout(timer);
}, []);
return (
<div className="bg-slate-50 min-h-screen py-8 font-sans text-slate-800">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<header className="text-center border-b border-slate-200 pb-8 mb-12">
<h1 className="text-3xl md:text-5xl font-extrabold text-slate-900 mb-6 tracking-tight">TDoT - Schere Stein Papier AI</h1>
<p className="text-xl text-slate-600 max-w-3xl mx-auto mb-6">
Eine interaktive KI-Demo für den Tag der offenen Tür, die Computer Vision greifbar macht.
</p>
<div className="mt-6 flex flex-wrap justify-center gap-4">
<div className="bg-white px-4 py-2 rounded-full border border-slate-200 shadow-sm flex items-center space-x-2">
<span className="bg-slate-200 text-slate-700 text-xs font-bold px-2 py-0.5 rounded uppercase tracking-wide">Status</span>
<span className="text-sm font-medium text-slate-600">Abgeschlossen</span>
</div>
<div className="bg-white px-4 py-2 rounded-full border border-slate-200 shadow-sm flex items-center space-x-2">
<span className="bg-slate-200 text-slate-700 text-xs font-bold px-2 py-0.5 rounded uppercase tracking-wide">Typ</span>
<span className="text-sm font-medium text-slate-600">Live Demo / Showcase</span>
</div>
</div>
</header>
<section className="mb-16">
<h2 className="text-2xl font-bold text-slate-900 mb-6 border-l-4 border-indigo-500 pl-4">1. Projektübersicht</h2>
<div className="bg-white p-6 rounded-xl border border-slate-200 shadow-sm space-y-4">
<p className="text-lg leading-relaxed text-slate-700">
Dieses Projekt wurde speziell für den Tag der offenen Tür der EDV-Schule Plattling entwickelt.
Ziel war es, Besuchern auf spielerische Weise zu zeigen, wie moderne <strong>Computer Vision</strong> funktioniert.
</p>
<p className="text-lg leading-relaxed text-slate-700">
Die Anwendung nutzt eine Webcam, um Handgesten (Schere, Stein, Papier) in Echtzeit zu erkennen und ermöglicht es,
gegen eine KI oder einen anderen Spieler anzutreten.
</p>
<div className="mt-4 pt-4 border-t border-slate-100">
<a href="https://github.com/simon-266/tdot_programm" target="_blank" rel="noopener noreferrer" className="text-indigo-600 hover:text-indigo-800 font-bold inline-flex items-center">
<svg className="w-4 h-4 mr-2" fill="currentColor" viewBox="0 0 24 24" aria-hidden="true"><path fillRule="evenodd" d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z" clipRule="evenodd"></path></svg>
GitHub Repository
</a>
</div>
</div>
</section>
<section className="mb-16">
<h2 className="text-2xl font-bold text-slate-900 mb-6 border-l-4 border-indigo-500 pl-4">2. Features & Modi</h2>
<div className="grid grid-cols-1 md:grid-cols-3 gap-6 mt-6">
<div className="h-full">
<div className="h-full bg-white rounded-xl border border-slate-200 shadow-sm p-6 hover:shadow-md transition-shadow">
<h3 className="text-xl font-bold text-slate-800 mb-4 pb-2 border-b border-slate-100">Singleplayer</h3>
<p className="text-slate-700">
Der Spieler tritt gegen den Computer an. Nach einem Countdown erkennt die KI die Geste des Spielers
und wählt zufällig einenegene Geste. Der Gewinner wird sofort angezeigt.
</p>
</div>
</div>
<div className="h-full">
<div className="h-full bg-white rounded-xl border border-slate-200 shadow-sm p-6 hover:shadow-md transition-shadow">
<h3 className="text-xl font-bold text-slate-800 mb-4 pb-2 border-b border-slate-100">Multiplayer</h3>
<p className="text-slate-700">
Zwei Personen halten ihre Hände gleichzeitig in die Kamera. Die KI erkennt beide Gesten, ordnet sie
den Spielern (Links/Rechts) zu und ermittelt den Gewinner.
</p>
</div>
</div>
<div className="h-full">
<div className="h-full bg-white rounded-xl border border-slate-200 shadow-sm p-6 hover:shadow-md transition-shadow">
<h3 className="text-xl font-bold text-slate-800 mb-4 pb-2 border-b border-slate-100">Scan All (Debug)</h3>
<p className="text-slate-700">
Ein offener Modus, der alle erkannten Objekte und die Konfidenz (Sicherheit) der KI visualisiert.
Ideal, um die Grenzen des Modells zu testen.
</p>
</div>
</div>
</div>
</section>
<section className="mb-16">
<h2 className="text-2xl font-bold text-slate-900 mb-6 border-l-4 border-indigo-500 pl-4">3. Technische Architektur</h2>
<div className="bg-white p-6 rounded-xl border border-slate-200 shadow-sm overflow-x-auto">
<div className="mermaid flex justify-center">
{`graph LR
Webcam[Webcam Video] --> OpenCV
OpenCV -- "Frames" --> YOLO[YOLO AI Model]
YOLO -- "Detections (Box & Label)" --> Logic[Game Logic]
Logic -- "Overlay (Winner/Graphics)" --> Streamlit
Streamlit -- "UI Display" --> User((User))`}
</div>
</div>
</section>
<section className="mb-16">
<h2 className="text-2xl font-bold text-slate-900 mb-6 border-l-4 border-indigo-500 pl-4">4. KI Training & Performance</h2>
<div className="bg-white p-6 rounded-xl border border-slate-200 shadow-sm space-y-4">
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<h3 className="text-lg font-bold text-slate-800 mb-2">Training & Daten</h3>
<ul className="list-disc pl-5 space-y-2 text-slate-700">
<li><strong>Datensatz:</strong> Trainiert mit Bildern von <a href="https://roboflow.com/" target="_blank" rel="noopener noreferrer" className="text-indigo-600 hover:underline">Roboflow</a>.</li>
<li><strong>Mixed Precision:</strong> Nutzung von 16-bit Precision (<code>amp=True</code>) um das Training auf der GPU zu beschleunigen.</li>
</ul>
</div>
<div>
<h3 className="text-lg font-bold text-slate-800 mb-2">Inferenz Optimierung</h3>
<ul className="list-disc pl-5 space-y-2 text-slate-700">
<li><strong>Hardware-Anpassung:</strong> Optimiert für Schul-PCs mittels ONNX und OpenVINO.</li>
<li><strong>Half-Precision:</strong> Export mit <code>half=True</code> (FP16) für maximale Performance.</li>
</ul>
</div>
</div>
</div>
</section>
<section className="mb-16">
<h2 className="text-2xl font-bold text-slate-900 mb-6 border-l-4 border-indigo-500 pl-4">5. Tech Stack</h2>
<div className="bg-slate-50 p-6 rounded-xl border border-slate-200">
<div className="grid grid-cols-2 md:grid-cols-4 gap-4">
<div className="bg-white p-4 rounded shadow-sm text-center font-semibold text-slate-700">Python 3.9+</div>
<div className="bg-white p-4 rounded shadow-sm text-center font-semibold text-slate-700">Ultralytics YOLO</div>
<div className="bg-white p-4 rounded shadow-sm text-center font-semibold text-slate-700">OpenCV</div>
<div className="bg-white p-4 rounded shadow-sm text-center font-semibold text-slate-700">Streamlit</div>
<div className="bg-white p-4 rounded shadow-sm text-center font-semibold text-slate-700">NumPy</div>
</div>
</div>
</section>
<section className="mb-16">
<h2 className="text-2xl font-bold text-slate-900 mb-6 border-l-4 border-indigo-500 pl-4">6. UI Konzept</h2>
<div className="flex flex-wrap -mx-2 justify-center">
<Wireframe title="Game Overlay">
<div className="relative w-full h-full bg-slate-800 rounded flex flex-col items-center justify-center text-white overflow-hidden">
<div className="absolute top-4 left-4 text-xs font-mono text-green-400">FPS: 30</div>
<div className="text-4xl font-bold mb-2">SCHERE...</div>
<div className="w-32 h-32 border-4 border-dashed border-white/30 rounded-lg flex items-center justify-center mb-4">
<span className="text-xs text-white/50">Hand hier</span>
</div>
<div className="absolute bottom-10 left-0 right-0 text-center">
<div className="inline-block px-4 py-2 bg-black/50 rounded text-sm">
Warte auf Geste...
</div>
</div>
</div>
</Wireframe>
<Wireframe title="Settings Sidebar">
<div className="p-4 flex flex-col space-y-4">
<div className="space-y-1">
<div className="text-xs font-bold text-slate-500 uppercase">Kamera</div>
<div className="h-8 bg-white border rounded px-2 flex items-center text-xs text-slate-700 shadow-sm">Integrated Webcam</div>
</div>
<div className="space-y-1">
<div className="text-xs font-bold text-slate-500 uppercase">Modus</div>
<div className="flex space-x-2">
<div className="flex-1 h-8 bg-indigo-100 border border-indigo-300 rounded flex items-center justify-center text-xs font-bold text-indigo-700">Single</div>
<div className="flex-1 h-8 bg-white border rounded flex items-center justify-center text-xs text-slate-600">Multi</div>
</div>
</div>
<div className="pt-4 border-t">
<button className="w-full py-2 bg-red-500 text-white rounded font-bold text-xs shadow hover:bg-red-600">SPIEL STARTEN</button>
</div>
</div>
</Wireframe>
</div>
</section>
</div>
</div>
);
}
export default TdotPage;

View File

@ -1,6 +1,5 @@
import React from "react";
import ReactDOM from "react-dom/client";
import "bootstrap/dist/css/bootstrap.min.css";
import './styles/styles.css';
import App from "./components/app";
@ -15,7 +14,7 @@ window.addEventListener('unhandledrejection', (event) => {
});
root.render(
<React.StrictMode>
<div className="app-container">
<div className="min-h-screen flex flex-col bg-slate-50 font-sans text-slate-800 antialiased overflow-x-hidden w-full">
<App />
</div>
</React.StrictMode>

View File

@ -1,221 +1,8 @@
body {
font-family: 'Open Sans', Arial, sans-serif;
background-color: #f4f7f6;
color: #333;
line-height: 1.6;
margin: 0;
padding: 0;
overflow-x: hidden;
width: 100%;
max-width: 100vw;
box-sizing: border-box;
}
.app-container {
display: flex;
flex-direction: column;
min-height: 100vh;
background-color: #ffffff;
}
.content {
flex-grow: 1;
padding: 20px;
max-width: 1000px;
margin: 0 auto;
}
h1, h2, h3, h4, h5, h6 {
font-family: 'Lato', Arial, sans-serif;
color: #2c3e50;
margin-top: 1.8em;
margin-bottom: 0.6em;
}
h1 {
font-size: 2.4em;
text-align: center;
margin-bottom: 1em;
}
h2 {
font-size: 1.9em;
border-bottom: 1px solid #e0e0e0;
padding-bottom: 0.3em;
margin-top: 2em;
}
h3 {
font-size: 1.5em;
color: #34495e;
}
p {
margin-bottom: 1.2em;
font-size: 1em;
}
a {
color: #007bff;
text-decoration: none;
}
code {
overflow-x: auto;
word-break: break-all;
max-width: 100%;
}
pre {
overflow-x: auto;
max-width: 100%;
word-wrap: break-word;
white-space: pre-wrap;
}
.navigation {
display: flex;
justify-content: center;
background-color: #ffffff;
border-bottom: 1px solid #dee2e6;
box-shadow: 0 2px 4px rgba(0,0,0,0.05);
position: sticky;
top: 0;
z-index: 1000;
width: 100%;
}
.navigation .navbar {
padding-top: 0.8rem;
padding-bottom: 0.8rem;
width: 100%;
max-width: 1000px;
}
.my-name {
color: #007bff !important;
font-family:'Lato', 'Trebuchet MS', 'Lucida Sans Unicode', 'Lucida Grande', 'Lucida Sans', Arial, sans-serif;
font-weight: bold;
font-size: 1.6rem;
}
.my-name:hover {
color: #0056b3 !important;
}
.navigation .nav-link {
color: #343a40 !important;
padding: 0.5rem 1rem !important;
font-size: 1rem;
}
.navigation .nav-link:hover,
.navigation .nav-link.active {
color: #007bff !important;
}
.dropdown-item-text {
font-weight: bold;
color: #495057;
padding: 0.25rem 1.5rem;
}
footer {
min-height: 80px;
background-color: #343a40;
color: #f8f9fa;
display: flex;
justify-content: center;
align-items: center;
padding: 20px;
text-align: center;
margin-top: 40px;
}
.foot-links {
text-decoration: none;
color: #adb5bd;
margin: 0 15px;
}
.foot-links:hover {
color: #ffffff;
text-decoration: none;
}
section {
padding: 10px 0;
}
.centered {
text-align: center;
}
.content-group h1, .content-group h2, .content-group h3 {
text-align: center;
}
.list-display {
text-align: center;
margin-top: 1em;
margin-bottom: 1em;
}
.key-points {
display: inline-block;
text-align: left;
list-style-position: outside;
padding-left: 20px;
}
.key-points li {
margin-bottom: 0.6em;
}
.center-image {
display: block;
margin: 25px auto;
max-width: 90%;
max-height: 450px;
height: auto;
width: auto;
border-radius: 5px;
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
}
.image-container {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
gap: 20px;
flex-wrap: wrap;
margin-top: 20px;
margin-bottom: 30px;
}
.project-header {
border-bottom: 1px solid #dee2e6;
}
.project-page {
overflow-x: hidden;
width: 100%;
box-sizing: border-box;
}
@tailwind base;
@tailwind components;
@tailwind utilities;
/* Mermaid Diagram Styles */
.mermaid {
overflow: hidden !important;
text-align: center;
@ -228,4 +15,4 @@ section {
.mermaid svg {
max-width: 100% !important;
height: auto !important;
}
}

10
tailwind.config.js Normal file
View File

@ -0,0 +1,10 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
"./src/**/*.{js,jsx,ts,tsx}",
],
theme: {
extend: {},
},
plugins: [],
}