diff --git a/06_react/unterricht/tag34/04_reusable-components.zip b/06_react/unterricht/tag34/04_reusable-components.zip
deleted file mode 100644
index d397089..0000000
Binary files a/06_react/unterricht/tag34/04_reusable-components.zip and /dev/null differ
diff --git a/06_react/unterricht/tag35/01_reusable-components/.gitignore b/06_react/unterricht/tag35/01_reusable-components/.gitignore
new file mode 100644
index 0000000..a547bf3
--- /dev/null
+++ b/06_react/unterricht/tag35/01_reusable-components/.gitignore
@@ -0,0 +1,24 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+lerna-debug.log*
+
+node_modules
+dist
+dist-ssr
+*.local
+
+# Editor directories and files
+.vscode/*
+!.vscode/extensions.json
+.idea
+.DS_Store
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
diff --git a/06_react/unterricht/tag35/01_reusable-components/.oxlintrc.json b/06_react/unterricht/tag35/01_reusable-components/.oxlintrc.json
new file mode 100644
index 0000000..1255078
--- /dev/null
+++ b/06_react/unterricht/tag35/01_reusable-components/.oxlintrc.json
@@ -0,0 +1,8 @@
+{
+ "$schema": "./node_modules/oxlint/configuration_schema.json",
+ "plugins": ["react", "oxc"],
+ "rules": {
+ "react/rules-of-hooks": "error",
+ "react/only-export-components": ["warn", { "allowConstantExport": true }]
+ }
+}
diff --git a/06_react/unterricht/tag35/01_reusable-components/README.md b/06_react/unterricht/tag35/01_reusable-components/README.md
new file mode 100644
index 0000000..d937833
--- /dev/null
+++ b/06_react/unterricht/tag35/01_reusable-components/README.md
@@ -0,0 +1,16 @@
+# React + Vite
+
+This template provides a minimal setup to get React working in Vite with HMR and some Oxlint rules.
+
+Currently, two official plugins are available:
+
+- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Oxc](https://oxc.rs)
+- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/)
+
+## React Compiler
+
+The React Compiler is not enabled on this template because of its impact on dev & build performances. To add it, see [this documentation](https://react.dev/learn/react-compiler/installation).
+
+## Expanding the Oxlint configuration
+
+If you are developing a production application, we recommend using TypeScript with type-aware lint rules enabled. Check out the [TS template](https://github.com/vitejs/vite/tree/main/packages/create-vite/template-react-ts) for information on how to integrate TypeScript and Oxlint's TypeScript related rules in your project.
diff --git a/06_react/unterricht/tag35/01_reusable-components/index.html b/06_react/unterricht/tag35/01_reusable-components/index.html
new file mode 100644
index 0000000..196c435
--- /dev/null
+++ b/06_react/unterricht/tag35/01_reusable-components/index.html
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+ 04_reusable-components
+
+
+
+
+
+
diff --git a/06_react/unterricht/tag34/04_reusable-components/package-lock.json b/06_react/unterricht/tag35/01_reusable-components/package-lock.json
similarity index 98%
rename from 06_react/unterricht/tag34/04_reusable-components/package-lock.json
rename to 06_react/unterricht/tag35/01_reusable-components/package-lock.json
index 7b8c3b0..68ea610 100644
--- a/06_react/unterricht/tag34/04_reusable-components/package-lock.json
+++ b/06_react/unterricht/tag35/01_reusable-components/package-lock.json
@@ -1,32 +1,33 @@
{
- "name": "04_reusable-components",
- "version": "0.0.0",
+ "name": "reusable-components",
+ "version": "0.1.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
- "name": "04_reusable-components",
- "version": "0.0.0",
+ "name": "reusable-components",
+ "version": "0.1.0",
"dependencies": {
"bootstrap": "^5.3.8",
"react": "^19.3.1",
"react-dom": "^19.3.1",
"react-icons": "^5.7.0",
- "sass-embedded": "^1.106.1",
"styled-components": "^6.6.0"
},
"devDependencies": {
"@types/react": "^19.3.0",
"@types/react-dom": "^19.3.0",
"@vitejs/plugin-react": "^6.1.2",
- "oxlint": "^1.88.0",
- "vite": "^8.3.4"
+ "oxlint": "^1.89.0",
+ "sass-embedded": "^1.106.1",
+ "vite": "^8.3.5"
}
},
"node_modules/@bufbuild/protobuf": {
"version": "2.16.0",
"resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-2.16.0.tgz",
"integrity": "sha512-FWa0sPlqYGJgpTs6OxBRcL/AW4JT0OIO+W1ajerluoTVh8CV0B7XM1qsNCRgnkSCkRCgOICKHRQlY17jrsm0+Q==",
+ "dev": true,
"license": "(Apache-2.0 AND BSD-3-Clause)"
},
"node_modules/@emotion/is-prop-valid": {
@@ -405,6 +406,7 @@
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.6.0.tgz",
"integrity": "sha512-7FNeNl8NCE7aINx7WXiKQrPYZWC/hvrTsmk6zmxbI7LTXE7hVek/n8AfVgpe2y82zl3w0HvCHN0bVKMBoJcC0w==",
+ "dev": true,
"hasInstallScript": true,
"license": "MIT",
"optional": true,
@@ -443,6 +445,7 @@
"cpu": [
"arm64"
],
+ "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -463,6 +466,7 @@
"cpu": [
"arm64"
],
+ "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -483,6 +487,7 @@
"cpu": [
"x64"
],
+ "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -503,6 +508,7 @@
"cpu": [
"x64"
],
+ "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -523,6 +529,7 @@
"cpu": [
"arm"
],
+ "dev": true,
"libc": [
"glibc"
],
@@ -546,6 +553,7 @@
"cpu": [
"arm"
],
+ "dev": true,
"libc": [
"musl"
],
@@ -569,6 +577,7 @@
"cpu": [
"arm64"
],
+ "dev": true,
"libc": [
"glibc"
],
@@ -592,6 +601,7 @@
"cpu": [
"arm64"
],
+ "dev": true,
"libc": [
"musl"
],
@@ -615,6 +625,7 @@
"cpu": [
"x64"
],
+ "dev": true,
"libc": [
"glibc"
],
@@ -638,6 +649,7 @@
"cpu": [
"x64"
],
+ "dev": true,
"libc": [
"musl"
],
@@ -661,6 +673,7 @@
"cpu": [
"arm64"
],
+ "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -681,6 +694,7 @@
"cpu": [
"x64"
],
+ "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1073,6 +1087,7 @@
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz",
"integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==",
+ "dev": true,
"license": "MIT",
"optional": true,
"dependencies": {
@@ -1089,6 +1104,7 @@
"version": "0.7.1",
"resolved": "https://registry.npmjs.org/colorjs.io/-/colorjs.io-0.7.1.tgz",
"integrity": "sha512-LY7OHnJZxHwT5UlzNa9bbhHHDbzB6yE5+3MIPwJEQKRvSCt/T4G7epsj+9j2BExUIIfXFIJGsIXUKdfrK9Q5tA==",
+ "dev": true,
"license": "MIT",
"funding": {
"type": "opencollective",
@@ -1125,7 +1141,7 @@
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
"integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
- "devOptional": true,
+ "dev": true,
"license": "Apache-2.0",
"engines": {
"node": ">=8"
@@ -1168,6 +1184,7 @@
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true,
"license": "MIT",
"engines": {
"node": ">=8"
@@ -1177,12 +1194,14 @@
"version": "5.1.9",
"resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.9.tgz",
"integrity": "sha512-m8nVez3rwrgmWxtLMt1ZYXB2Lv7OKYn/disyxAlSDYAlKSlFoPPfIAmAM/M5xqL4m4C/wAPw7S2/CNaUii1Hxg==",
+ "dev": true,
"license": "MIT"
},
"node_modules/is-extglob": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
"integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+ "dev": true,
"license": "MIT",
"optional": true,
"engines": {
@@ -1193,6 +1212,7 @@
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+ "dev": true,
"license": "MIT",
"optional": true,
"dependencies": {
@@ -1498,6 +1518,7 @@
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz",
"integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==",
+ "dev": true,
"license": "MIT",
"optional": true
},
@@ -1561,7 +1582,7 @@
"version": "4.0.7",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz",
"integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==",
- "devOptional": true,
+ "dev": true,
"license": "MIT",
"engines": {
"node": ">=12"
@@ -1639,6 +1660,7 @@
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.1.1.tgz",
"integrity": "sha512-Kko+Y5XQ6fM+Ce3dq3m9YGxnacYZYl9cA1wZjaF3Vbry2L3i1qVg8+CAgNPsXRArPMUMCaOR7oa9Nqntc43JKA==",
+ "dev": true,
"license": "MIT",
"optional": true,
"engines": {
@@ -1687,6 +1709,7 @@
"version": "7.8.2",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz",
"integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==",
+ "dev": true,
"license": "Apache-2.0",
"dependencies": {
"tslib": "^2.1.0"
@@ -1696,6 +1719,7 @@
"version": "1.106.1",
"resolved": "https://registry.npmjs.org/sass/-/sass-1.106.1.tgz",
"integrity": "sha512-kD+Gi66vycZcbJt+42NC4z4PXNMcCajVrJPhqoKKXy5cOBMmJQt052CxIBcRjwYXeImHYOpu/ydWWGZQIenl7A==",
+ "dev": true,
"license": "MIT",
"optional": true,
"dependencies": {
@@ -1717,6 +1741,7 @@
"version": "1.106.1",
"resolved": "https://registry.npmjs.org/sass-embedded/-/sass-embedded-1.106.1.tgz",
"integrity": "sha512-OoaTjMm7PcQnCo/AZNSKM/KdAeaX57edhmOp2bH8hcGNph2VDIg404gOSMZxGKNL+lbc7Ng0S/IYLAbs0YmgfA==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@bufbuild/protobuf": "^2.5.0",
@@ -1764,6 +1789,7 @@
"!riscv64",
"!x64"
],
+ "dev": true,
"license": "MIT",
"optional": true,
"dependencies": {
@@ -1777,6 +1803,7 @@
"cpu": [
"arm"
],
+ "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1793,6 +1820,7 @@
"cpu": [
"arm64"
],
+ "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1809,6 +1837,7 @@
"cpu": [
"riscv64"
],
+ "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1825,6 +1854,7 @@
"cpu": [
"x64"
],
+ "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1841,6 +1871,7 @@
"cpu": [
"arm64"
],
+ "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1857,6 +1888,7 @@
"cpu": [
"x64"
],
+ "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1873,6 +1905,7 @@
"cpu": [
"arm"
],
+ "dev": true,
"libc": "glibc",
"license": "MIT",
"optional": true,
@@ -1890,6 +1923,7 @@
"cpu": [
"arm64"
],
+ "dev": true,
"libc": "glibc",
"license": "MIT",
"optional": true,
@@ -1907,6 +1941,7 @@
"cpu": [
"arm"
],
+ "dev": true,
"libc": "musl",
"license": "MIT",
"optional": true,
@@ -1924,6 +1959,7 @@
"cpu": [
"arm64"
],
+ "dev": true,
"libc": "musl",
"license": "MIT",
"optional": true,
@@ -1941,6 +1977,7 @@
"cpu": [
"riscv64"
],
+ "dev": true,
"libc": "musl",
"license": "MIT",
"optional": true,
@@ -1958,6 +1995,7 @@
"cpu": [
"x64"
],
+ "dev": true,
"libc": "musl",
"license": "MIT",
"optional": true,
@@ -1975,6 +2013,7 @@
"cpu": [
"riscv64"
],
+ "dev": true,
"libc": "glibc",
"license": "MIT",
"optional": true,
@@ -1992,6 +2031,7 @@
"cpu": [
"x64"
],
+ "dev": true,
"libc": "glibc",
"license": "MIT",
"optional": true,
@@ -2006,6 +2046,7 @@
"version": "1.106.1",
"resolved": "https://registry.npmjs.org/sass-embedded-unknown-all/-/sass-embedded-unknown-all-1.106.1.tgz",
"integrity": "sha512-uaeOeGCaHnhqpfZnjy5wGMcuyYbnDyXhzWCniGctqCj/Inlst4eDZaweowo+sJLExRvmToBhQ8seZyEvfGMQ4g==",
+ "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -2025,6 +2066,7 @@
"cpu": [
"arm64"
],
+ "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -2041,6 +2083,7 @@
"cpu": [
"x64"
],
+ "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -2060,7 +2103,7 @@
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.2.tgz",
"integrity": "sha512-KGj/8Y43x35aZVDtt+J4mK1hoLGHULMYfSkODJNQjNDC3oW1PqPoxMwo0pLUsWM/UEGzON/NxeHywEfNXNP3Vw==",
- "devOptional": true,
+ "dev": true,
"license": "BSD-3-Clause",
"engines": {
"node": ">=0.10.0"
@@ -2113,6 +2156,7 @@
"version": "8.1.1",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
"integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"has-flag": "^4.0.0"
@@ -2128,6 +2172,7 @@
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/sync-child-process/-/sync-child-process-1.1.0.tgz",
"integrity": "sha512-1LMf/x0kU0CKFSesh5DfYktvj1KhiqYi5LAh5HU2G4SkKk1TGDhsMFBOL47g/E+mNfYpgs365pVNlIYOIHPvlQ==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"sync-message-port": "^1.0.0"
@@ -2140,6 +2185,7 @@
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/sync-message-port/-/sync-message-port-1.2.0.tgz",
"integrity": "sha512-gAQ9qrUN/UCypHtGFbbe7Rc/f9bzO88IwrG8TDo/aMKAApKyD6E3W4Cm0EfhfBb6Z6SKt59tTCTfD+n1xmAvMg==",
+ "dev": true,
"license": "MIT",
"engines": {
"node": ">=16.0.0"
@@ -2166,12 +2212,14 @@
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
+ "dev": true,
"license": "0BSD"
},
"node_modules/varint": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/varint/-/varint-6.0.0.tgz",
"integrity": "sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==",
+ "dev": true,
"license": "MIT"
},
"node_modules/vite": {
diff --git a/06_react/unterricht/tag35/01_reusable-components/package.json b/06_react/unterricht/tag35/01_reusable-components/package.json
new file mode 100644
index 0000000..7a728d4
--- /dev/null
+++ b/06_react/unterricht/tag35/01_reusable-components/package.json
@@ -0,0 +1,27 @@
+{
+ "name": "reusable-components",
+ "private": true,
+ "version": "0.1.0",
+ "type": "module",
+ "scripts": {
+ "dev": "vite",
+ "build": "vite build",
+ "lint": "oxlint",
+ "preview": "vite preview"
+ },
+ "dependencies": {
+ "bootstrap": "^5.3.8",
+ "react": "^19.3.1",
+ "react-dom": "^19.3.1",
+ "react-icons": "^5.7.0",
+ "styled-components": "^6.6.0"
+ },
+ "devDependencies": {
+ "@types/react": "^19.3.0",
+ "@types/react-dom": "^19.3.0",
+ "@vitejs/plugin-react": "^6.1.2",
+ "sass-embedded": "^1.106.1",
+ "oxlint": "^1.89.0",
+ "vite": "^8.3.5"
+ }
+}
diff --git a/06_react/unterricht/tag35/01_reusable-components/public/favicon.svg b/06_react/unterricht/tag35/01_reusable-components/public/favicon.svg
new file mode 100644
index 0000000..6893eb1
--- /dev/null
+++ b/06_react/unterricht/tag35/01_reusable-components/public/favicon.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/06_react/unterricht/tag35/01_reusable-components/public/icons.svg b/06_react/unterricht/tag35/01_reusable-components/public/icons.svg
new file mode 100644
index 0000000..e952219
--- /dev/null
+++ b/06_react/unterricht/tag35/01_reusable-components/public/icons.svg
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/06_react/unterricht/tag35/01_reusable-components/public/logo-js.min.svg b/06_react/unterricht/tag35/01_reusable-components/public/logo-js.min.svg
new file mode 100644
index 0000000..4acd335
--- /dev/null
+++ b/06_react/unterricht/tag35/01_reusable-components/public/logo-js.min.svg
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/06_react/unterricht/tag35/01_reusable-components/src/App.jsx b/06_react/unterricht/tag35/01_reusable-components/src/App.jsx
new file mode 100644
index 0000000..b835297
--- /dev/null
+++ b/06_react/unterricht/tag35/01_reusable-components/src/App.jsx
@@ -0,0 +1,25 @@
+import Button from './components/buttons/Button';
+import HeaderMain from './components/headers/HeaderMain';
+import InputAmount from './components/inputs/InputAmount';
+
+function App(props) {
+ // const { } = props;
+
+ return (
+ <>
+
+
+
Reusable Components
+
+
+
+ New Styled Button
+
+ Button 2
+
+ Button 3
+
+ >
+ );
+}
+export default App;
diff --git a/06_react/unterricht/tag35/01_reusable-components/src/components/buttons/Button.css b/06_react/unterricht/tag35/01_reusable-components/src/components/buttons/Button.css
new file mode 100644
index 0000000..9765d3f
--- /dev/null
+++ b/06_react/unterricht/tag35/01_reusable-components/src/components/buttons/Button.css
@@ -0,0 +1,15 @@
+.btn-custom {
+ background-color: #f0f0f0;
+ color: #333;
+ border: 1px solid #ccc;
+ padding: 8px 16px;
+ border-radius: 0px;
+ margin: 3px;
+}
+
+.btn-custom:hover,
+.btn-custom:focus {
+ background-color: #e0e0e0;
+ color: #333;
+ border: 1px solid #ccc;
+}
diff --git a/06_react/unterricht/tag35/01_reusable-components/src/components/buttons/Button.jsx b/06_react/unterricht/tag35/01_reusable-components/src/components/buttons/Button.jsx
new file mode 100644
index 0000000..539528d
--- /dev/null
+++ b/06_react/unterricht/tag35/01_reusable-components/src/components/buttons/Button.jsx
@@ -0,0 +1,45 @@
+// CSS oder SCSS Import
+//import './Button.css';
+//import './Button.scss';
+
+// CSS Module Import
+// import styles from './Button.module.css';
+
+// import von Modul, welches SFC (Single File Component) ermöglicht.
+// import styled from 'styled-components';
+
+// const StyledButton = styled.button`
+// color: #333;
+// border: 1px solid #ccc;
+// padding: 8px 16px;
+// border-radius: 0px;
+// margin: 3px;
+// background-color: ${(props) => props.bgColor || '#f0f0f0'};
+// &:hover,
+// &:focus {
+// background-color: #e0e0e0;
+// color: #333;
+// border: 1px solid #ccc;
+// }
+// `;
+
+const Button = (props) => {
+ const { variant = 'secondary', children } = props;
+
+ // component logic...
+
+ return {children || 'Click Me'} ;
+
+ // Styled Component (SFC)
+ // return {children || 'Click Me'} ;
+
+ // CSS Module Import
+ // return {children || 'Click Me'} ;
+
+ // CSS import
+ // return {children || 'Click Me'} ;
+
+ // CSS Klassenzuweisung (classic)
+ // return {children || 'Click Me'} ;
+};
+export default Button;
diff --git a/06_react/unterricht/tag35/01_reusable-components/src/components/buttons/Button.module.css b/06_react/unterricht/tag35/01_reusable-components/src/components/buttons/Button.module.css
new file mode 100644
index 0000000..9765d3f
--- /dev/null
+++ b/06_react/unterricht/tag35/01_reusable-components/src/components/buttons/Button.module.css
@@ -0,0 +1,15 @@
+.btn-custom {
+ background-color: #f0f0f0;
+ color: #333;
+ border: 1px solid #ccc;
+ padding: 8px 16px;
+ border-radius: 0px;
+ margin: 3px;
+}
+
+.btn-custom:hover,
+.btn-custom:focus {
+ background-color: #e0e0e0;
+ color: #333;
+ border: 1px solid #ccc;
+}
diff --git a/06_react/unterricht/tag35/01_reusable-components/src/components/buttons/Button.scss b/06_react/unterricht/tag35/01_reusable-components/src/components/buttons/Button.scss
new file mode 100644
index 0000000..d5fd70e
--- /dev/null
+++ b/06_react/unterricht/tag35/01_reusable-components/src/components/buttons/Button.scss
@@ -0,0 +1,14 @@
+.btn-custom {
+ background-color: #f0f0f0;
+ color: #333;
+ border: 1px solid #ccc;
+ padding: 8px 16px;
+ border-radius: 0px;
+ margin: 3px;
+ &:hover,
+ &:focus {
+ background-color: #e0e0e0;
+ color: #333;
+ border: 1px solid #ccc;
+ }
+}
diff --git a/06_react/unterricht/tag35/01_reusable-components/src/components/headers/HeaderMain.jsx b/06_react/unterricht/tag35/01_reusable-components/src/components/headers/HeaderMain.jsx
new file mode 100644
index 0000000..acbddb2
--- /dev/null
+++ b/06_react/unterricht/tag35/01_reusable-components/src/components/headers/HeaderMain.jsx
@@ -0,0 +1,12 @@
+import LogoMain from '../logos/LogoMain';
+
+const HeaderMain = () => {
+ return (
+
+ );
+};
+export default HeaderMain;
diff --git a/06_react/unterricht/tag35/01_reusable-components/src/components/icons/Logo.jsx b/06_react/unterricht/tag35/01_reusable-components/src/components/icons/Logo.jsx
new file mode 100644
index 0000000..dd3b6f0
--- /dev/null
+++ b/06_react/unterricht/tag35/01_reusable-components/src/components/icons/Logo.jsx
@@ -0,0 +1,48 @@
+const Logo = () => {
+ return (
+
+
+
+
+
+
+
+
+ );
+};
+export default Logo;
diff --git a/06_react/unterricht/tag35/01_reusable-components/src/components/inputs/InputAmount.jsx b/06_react/unterricht/tag35/01_reusable-components/src/components/inputs/InputAmount.jsx
new file mode 100644
index 0000000..652c779
--- /dev/null
+++ b/06_react/unterricht/tag35/01_reusable-components/src/components/inputs/InputAmount.jsx
@@ -0,0 +1,26 @@
+import { FaMinus, FaPlus } from 'react-icons/fa6';
+
+const InputAmount = (props) => {
+ // const { } = props;
+
+ return (
+
+
+
+
+
+ Decrement
+
+
+
+
+
+
+ Increment
+
+
+
+
+ );
+};
+export default InputAmount;
diff --git a/06_react/unterricht/tag35/01_reusable-components/src/components/logos/LogoMain.jsx b/06_react/unterricht/tag35/01_reusable-components/src/components/logos/LogoMain.jsx
new file mode 100644
index 0000000..2649b9e
--- /dev/null
+++ b/06_react/unterricht/tag35/01_reusable-components/src/components/logos/LogoMain.jsx
@@ -0,0 +1,15 @@
+import Logo from '../icons/Logo';
+
+// import Logo from '/logo-js.min.svg';
+const LogoMain = (props) => {
+ // const { } = props;
+
+ return (
+
+ {/* */}
+
+ Firmen Slogan
+
+ );
+};
+export default LogoMain;
diff --git a/06_react/unterricht/tag35/01_reusable-components/src/main.jsx b/06_react/unterricht/tag35/01_reusable-components/src/main.jsx
new file mode 100644
index 0000000..1d66d55
--- /dev/null
+++ b/06_react/unterricht/tag35/01_reusable-components/src/main.jsx
@@ -0,0 +1,14 @@
+import { StrictMode } from 'react';
+import { createRoot } from 'react-dom/client';
+
+// CSS Bootstrap
+// import 'bootstrap/dist/css/bootstrap.min.css';
+import './styles/main.scss';
+
+import App from './App.jsx';
+
+createRoot(document.getElementById('root')).render(
+
+
+ ,
+);
diff --git a/06_react/unterricht/tag35/01_reusable-components/src/styles/01_frameworks/_index.scss b/06_react/unterricht/tag35/01_reusable-components/src/styles/01_frameworks/_index.scss
new file mode 100644
index 0000000..42edceb
--- /dev/null
+++ b/06_react/unterricht/tag35/01_reusable-components/src/styles/01_frameworks/_index.scss
@@ -0,0 +1,3 @@
+// Bootstrap 5.3.8 or 6 (6.0.0-alpha.1) straight from node_modules.
+// @forward 'bootstrap/scss/bootstrap-grid'
+@forward 'bootstrap/scss/bootstrap';
diff --git a/06_react/unterricht/tag35/01_reusable-components/src/styles/02_fonts/_gloria-hallelujah-v24-latin.scss b/06_react/unterricht/tag35/01_reusable-components/src/styles/02_fonts/_gloria-hallelujah-v24-latin.scss
new file mode 100644
index 0000000..f46eba2
--- /dev/null
+++ b/06_react/unterricht/tag35/01_reusable-components/src/styles/02_fonts/_gloria-hallelujah-v24-latin.scss
@@ -0,0 +1,8 @@
+// gloria-hallelujah-regular - latin
+@font-face {
+ font-display: swap;
+ font-family: 'Gloria Hallelujah';
+ font-style: normal;
+ font-weight: 400;
+ src: url('../../assets/fonts/gloria-hallelujah-v24-latin/gloria-hallelujah-v24-latin-regular.woff2') format('woff2');
+}
diff --git a/06_react/unterricht/tag35/01_reusable-components/src/styles/02_fonts/_index.scss b/06_react/unterricht/tag35/01_reusable-components/src/styles/02_fonts/_index.scss
new file mode 100644
index 0000000..d377888
--- /dev/null
+++ b/06_react/unterricht/tag35/01_reusable-components/src/styles/02_fonts/_index.scss
@@ -0,0 +1,3 @@
+// @forward 'gloria-hallelujah-v24-latin';
+// @forward 'lato-v25-latin';
+// @forward 'source-sans-3-v19-latin';
diff --git a/06_react/unterricht/tag35/01_reusable-components/src/styles/02_fonts/_lato-v25-latin.scss b/06_react/unterricht/tag35/01_reusable-components/src/styles/02_fonts/_lato-v25-latin.scss
new file mode 100644
index 0000000..522cfda
--- /dev/null
+++ b/06_react/unterricht/tag35/01_reusable-components/src/styles/02_fonts/_lato-v25-latin.scss
@@ -0,0 +1,89 @@
+// lato-100 - latin
+@font-face {
+ font-display: swap;
+ font-family: 'Lato';
+ font-style: normal;
+ font-weight: 100;
+ src: url('../../assets/fonts/lato-v25-latin/lato-v25-latin-100.woff2') format('woff2');
+}
+
+// lato-100italic - latin
+@font-face {
+ font-display: swap;
+ font-family: 'Lato';
+ font-style: italic;
+ font-weight: 100;
+ src: url('../../assets/fonts/lato-v25-latin/lato-v25-latin-100italic.woff2') format('woff2');
+}
+
+// lato-300 - latin
+@font-face {
+ font-display: swap;
+ font-family: 'Lato';
+ font-style: normal;
+ font-weight: 300;
+ src: url('../../assets/fonts/lato-v25-latin/lato-v25-latin-300.woff2') format('woff2');
+}
+
+// lato-300italic - latin
+@font-face {
+ font-display: swap;
+ font-family: 'Lato';
+ font-style: italic;
+ font-weight: 300;
+ src: url('../../assets/fonts/lato-v25-latin/lato-v25-latin-300italic.woff2') format('woff2');
+}
+
+// lato-regular - latin
+@font-face {
+ font-display: swap;
+ font-family: 'Lato';
+ font-style: normal;
+ font-weight: 400;
+ src: url('../../assets/fonts/lato-v25-latin/lato-v25-latin-regular.woff2') format('woff2');
+}
+
+// lato-italic - latin
+@font-face {
+ font-display: swap;
+ font-family: 'Lato';
+ font-style: italic;
+ font-weight: 400;
+ src: url('../../assets/fonts/lato-v25-latin/lato-v25-latin-italic.woff2') format('woff2');
+}
+
+// lato-700 - latin
+@font-face {
+ font-display: swap;
+ font-family: 'Lato';
+ font-style: normal;
+ font-weight: 700;
+ src: url('../../assets/fonts/lato-v25-latin/lato-v25-latin-700.woff2') format('woff2');
+}
+
+// lato-700italic - latin
+@font-face {
+ font-display: swap;
+ font-family: 'Lato';
+ font-style: italic;
+ font-weight: 700;
+ src: url('../../assets/fonts/lato-v25-latin/lato-v25-latin-700italic.woff2') format('woff2');
+}
+
+// lato-900 - latin
+@font-face {
+ font-display: swap;
+ font-family: 'Lato';
+ font-style: normal;
+ font-weight: 900;
+ src: url('../../assets/fonts/lato-v25-latin/lato-v25-latin-900.woff2') format('woff2');
+}
+
+// lato-900italic - latin
+@font-face {
+ font-display: swap;
+ font-family: 'Lato';
+ font-style: italic;
+ font-weight: 900;
+ src: url('../../assets/fonts/lato-v25-latin/lato-v25-latin-900italic.woff2') format('woff2');
+}
diff --git a/06_react/unterricht/tag35/01_reusable-components/src/styles/02_fonts/_source-sans-3-v19-latin.scss b/06_react/unterricht/tag35/01_reusable-components/src/styles/02_fonts/_source-sans-3-v19-latin.scss
new file mode 100644
index 0000000..b732c16
--- /dev/null
+++ b/06_react/unterricht/tag35/01_reusable-components/src/styles/02_fonts/_source-sans-3-v19-latin.scss
@@ -0,0 +1,143 @@
+// source-sans-3-200 - latin
+@font-face {
+ font-display: swap;
+ font-family: 'Source Sans 3';
+ font-style: normal;
+ font-weight: 200;
+ src: url('../../assets/fonts/source-sans-3-v19-latin/source-sans-3-v19-latin-200.woff2') format('woff2');
+}
+
+// source-sans-3-200italic - latin
+@font-face {
+ font-display: swap;
+ font-family: 'Source Sans 3';
+ font-style: italic;
+ font-weight: 200;
+ src: url('../../assets/fonts/source-sans-3-v19-latin/source-sans-3-v19-latin-200italic.woff2') format('woff2');
+}
+
+// source-sans-3-300 - latin
+@font-face {
+ font-display: swap;
+ font-family: 'Source Sans 3';
+ font-style: normal;
+ font-weight: 300;
+ src: url('../../assets/fonts/source-sans-3-v19-latin/source-sans-3-v19-latin-300.woff2') format('woff2');
+}
+
+// source-sans-3-300italic - latin
+@font-face {
+ font-display: swap;
+ font-family: 'Source Sans 3';
+ font-style: italic;
+ font-weight: 300;
+ src: url('../../assets/fonts/source-sans-3-v19-latin/source-sans-3-v19-latin-300italic.woff2') format('woff2');
+}
+
+// source-sans-3-regular - latin
+@font-face {
+ font-display: swap;
+ font-family: 'Source Sans 3';
+ font-style: normal;
+ font-weight: 400;
+ src: url('../../assets/fonts/source-sans-3-v19-latin/source-sans-3-v19-latin-regular.woff2') format('woff2');
+}
+
+// source-sans-3-italic - latin
+@font-face {
+ font-display: swap;
+ font-family: 'Source Sans 3';
+ font-style: italic;
+ font-weight: 400;
+ src: url('../../assets/fonts/source-sans-3-v19-latin/source-sans-3-v19-latin-italic.woff2') format('woff2');
+}
+
+// source-sans-3-500 - latin
+@font-face {
+ font-display: swap;
+ font-family: 'Source Sans 3';
+ font-style: normal;
+ font-weight: 500;
+ src: url('../../assets/fonts/source-sans-3-v19-latin/source-sans-3-v19-latin-500.woff2') format('woff2');
+}
+
+// source-sans-3-500italic - latin
+@font-face {
+ font-display: swap;
+ font-family: 'Source Sans 3';
+ font-style: italic;
+ font-weight: 500;
+ src: url('../../assets/fonts/source-sans-3-v19-latin/source-sans-3-v19-latin-500italic.woff2') format('woff2');
+}
+
+// source-sans-3-600 - latin
+@font-face {
+ font-display: swap;
+ font-family: 'Source Sans 3';
+ font-style: normal;
+ font-weight: 600;
+ src: url('../../assets/fonts/source-sans-3-v19-latin/source-sans-3-v19-latin-600.woff2') format('woff2');
+}
+
+// source-sans-3-600italic - latin
+@font-face {
+ font-display: swap;
+ font-family: 'Source Sans 3';
+ font-style: italic;
+ font-weight: 600;
+ src: url('../../assets/fonts/source-sans-3-v19-latin/source-sans-3-v19-latin-600italic.woff2') format('woff2');
+}
+
+// source-sans-3-700 - latin
+@font-face {
+ font-display: swap;
+ font-family: 'Source Sans 3';
+ font-style: normal;
+ font-weight: 700;
+ src: url('../../assets/fonts/source-sans-3-v19-latin/source-sans-3-v19-latin-700.woff2') format('woff2');
+}
+
+// source-sans-3-700italic - latin
+@font-face {
+ font-display: swap;
+ font-family: 'Source Sans 3';
+ font-style: italic;
+ font-weight: 700;
+ src: url('../../assets/fonts/source-sans-3-v19-latin/source-sans-3-v19-latin-700italic.woff2') format('woff2');
+}
+
+// source-sans-3-800 - latin
+@font-face {
+ font-display: swap;
+ font-family: 'Source Sans 3';
+ font-style: normal;
+ font-weight: 800;
+ src: url('../../assets/fonts/source-sans-3-v19-latin/source-sans-3-v19-latin-800.woff2') format('woff2');
+}
+
+// source-sans-3-800italic - latin
+@font-face {
+ font-display: swap;
+ font-family: 'Source Sans 3';
+ font-style: italic;
+ font-weight: 800;
+ src: url('../../assets/fonts/source-sans-3-v19-latin/source-sans-3-v19-latin-800italic.woff2') format('woff2');
+}
+
+// source-sans-3-900 - latin
+@font-face {
+ font-display: swap;
+ font-family: 'Source Sans 3';
+ font-style: normal;
+ font-weight: 900;
+ src: url('../../assets/fonts/source-sans-3-v19-latin/source-sans-3-v19-latin-900.woff2') format('woff2');
+}
+
+// source-sans-3-900italic - latin
+@font-face {
+ font-display: swap;
+ font-family: 'Source Sans 3';
+ font-style: italic;
+ font-weight: 900;
+ src: url('../../assets/fonts/source-sans-3-v19-latin/source-sans-3-v19-latin-900italic.woff2') format('woff2');
+}
diff --git a/06_react/unterricht/tag35/01_reusable-components/src/styles/03_base/_colors.scss b/06_react/unterricht/tag35/01_reusable-components/src/styles/03_base/_colors.scss
new file mode 100644
index 0000000..a550f3d
--- /dev/null
+++ b/06_react/unterricht/tag35/01_reusable-components/src/styles/03_base/_colors.scss
@@ -0,0 +1,13 @@
+/* Color Theme Swatches in Hex */
+$color-1: #5c4b51;
+$color-2: #8cbeb2;
+$color-3: #f2ebbf;
+$color-4: #f3b562;
+$color-5: #f06060;
+
+$color-red: $color-5;
+$color-white: white; // falls weiß geändert wird z.B.: #f8f8f8
+$color-black: #101010;
+
+$color-dark-blue: #283e4a;
+$linear-gradient-dark: linear-gradient(180deg, rgba(40, 62, 74, 1) 0%, rgba(24, 32, 38, 1) 100%);
diff --git a/06_react/unterricht/tag35/01_reusable-components/src/styles/03_base/_index.scss b/06_react/unterricht/tag35/01_reusable-components/src/styles/03_base/_index.scss
new file mode 100644
index 0000000..aaf4e12
--- /dev/null
+++ b/06_react/unterricht/tag35/01_reusable-components/src/styles/03_base/_index.scss
@@ -0,0 +1,2 @@
+// Variables (colors, typography) are pulled in by the partials that need them via @use.
+@forward 'theme';
diff --git a/06_react/unterricht/tag35/01_reusable-components/src/styles/03_base/_theme.scss b/06_react/unterricht/tag35/01_reusable-components/src/styles/03_base/_theme.scss
new file mode 100644
index 0000000..1c7e05a
--- /dev/null
+++ b/06_react/unterricht/tag35/01_reusable-components/src/styles/03_base/_theme.scss
@@ -0,0 +1,32 @@
+@use 'typography' as *;
+
+// Allgemeine Formatierung
+*,
+html {
+ box-sizing: border-box;
+}
+
+html,
+body {
+ height: 100%;
+}
+
+body {
+ margin: 0;
+ padding: 0;
+ font-family: $font-copy;
+}
+
+h1,
+h2,
+h3,
+h4,
+h5,
+h6 {
+ font-family: $font-headline;
+ font-weight: 600;
+}
+
+blockquote {
+ font-family: $font-quote;
+}
diff --git a/06_react/unterricht/tag35/01_reusable-components/src/styles/03_base/_typography.scss b/06_react/unterricht/tag35/01_reusable-components/src/styles/03_base/_typography.scss
new file mode 100644
index 0000000..7c9b095
--- /dev/null
+++ b/06_react/unterricht/tag35/01_reusable-components/src/styles/03_base/_typography.scss
@@ -0,0 +1,9 @@
+$fallback-serif: Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;
+$fallback-sans-serif: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
+
+$font-headline: 'Lato', $fallback-serif;
+$font-subclaim: $fallback-sans-serif;
+
+$font-menu: 'Source Sans 3', $fallback-sans-serif;
+$font-copy: 'Source Sans 3', $fallback-sans-serif;
+$font-quote: 'Gloria Hallelujah', $fallback-serif;
diff --git a/06_react/unterricht/tag35/01_reusable-components/src/styles/04_plugins/_index.scss b/06_react/unterricht/tag35/01_reusable-components/src/styles/04_plugins/_index.scss
new file mode 100644
index 0000000..bd5ba6a
--- /dev/null
+++ b/06_react/unterricht/tag35/01_reusable-components/src/styles/04_plugins/_index.scss
@@ -0,0 +1,7 @@
+// @use '@fortawesome/fontawesome-free/scss/variables' with (
+// $font-path: '@fa-webfonts'
+// );
+// @use '@fortawesome/fontawesome-free/scss/fontawesome';
+// @use '@fortawesome/fontawesome-free/scss/solid';
+
+// @use 'toastify-1.12/toastify';
diff --git a/06_react/unterricht/tag35/01_reusable-components/src/styles/04_plugins/toastify-1.12/_toastify.scss b/06_react/unterricht/tag35/01_reusable-components/src/styles/04_plugins/toastify-1.12/_toastify.scss
new file mode 100644
index 0000000..e359a14
--- /dev/null
+++ b/06_react/unterricht/tag35/01_reusable-components/src/styles/04_plugins/toastify-1.12/_toastify.scss
@@ -0,0 +1,88 @@
+/*!
+ * Toastify js 1.12.0
+ * https://github.com/apvarun/toastify-js
+ * @license MIT licensed
+ *
+ * Copyright (C) 2018 Varun A P
+ */
+
+.toastify {
+ padding: 12px 20px;
+ color: #ffffff;
+ display: inline-block;
+ box-shadow:
+ 0 3px 6px -1px rgba(0, 0, 0, 0.12),
+ 0 10px 36px -4px rgba(77, 96, 232, 0.3);
+ background: -webkit-linear-gradient(315deg, #73a5ff, #5477f5);
+ background: linear-gradient(135deg, #73a5ff, #5477f5);
+ position: fixed;
+ opacity: 0;
+ transition: all 0.4s cubic-bezier(0.215, 0.61, 0.355, 1);
+ border-radius: 2px;
+ cursor: pointer;
+ text-decoration: none;
+ max-width: calc(50% - 20px);
+ z-index: 2147483647;
+}
+
+.toastify.on {
+ opacity: 1;
+}
+
+.toast-close {
+ background: transparent;
+ border: 0;
+ color: white;
+ cursor: pointer;
+ font-family: inherit;
+ font-size: 1em;
+ opacity: 0.4;
+ padding: 0 5px;
+}
+
+.toastify-right {
+ right: 15px;
+}
+
+.toastify-left {
+ left: 15px;
+}
+
+.toastify-top {
+ top: -150px;
+}
+
+.toastify-bottom {
+ bottom: -150px;
+}
+
+.toastify-rounded {
+ border-radius: 25px;
+}
+
+.toastify-avatar {
+ width: 1.5em;
+ height: 1.5em;
+ margin: -7px 5px;
+ border-radius: 2px;
+}
+
+.toastify-center {
+ margin-left: auto;
+ margin-right: auto;
+ left: 0;
+ right: 0;
+ max-width: fit-content;
+ max-width: -moz-fit-content;
+}
+
+@media only screen and (max-width: 360px) {
+ .toastify-right,
+ .toastify-left {
+ margin-left: auto;
+ margin-right: auto;
+ left: 0;
+ right: 0;
+ max-width: fit-content;
+ }
+}
diff --git a/06_react/unterricht/tag35/01_reusable-components/src/styles/05_modules/_button.scss b/06_react/unterricht/tag35/01_reusable-components/src/styles/05_modules/_button.scss
new file mode 100644
index 0000000..1660f6b
--- /dev/null
+++ b/06_react/unterricht/tag35/01_reusable-components/src/styles/05_modules/_button.scss
@@ -0,0 +1,17 @@
+button,
+input {
+ &.btn-custom {
+ background-color: #f0f0f0;
+ color: #333;
+ border: 1px solid #ccc;
+ padding: 8px 16px;
+ border-radius: 0px;
+ margin: 3px;
+ &:hover,
+ &:focus {
+ background-color: #e0e0e0;
+ color: #333;
+ border: 1px solid #ccc;
+ }
+ }
+}
diff --git a/06_react/unterricht/tag35/01_reusable-components/src/styles/05_modules/_chuck-norris-joke.scss b/06_react/unterricht/tag35/01_reusable-components/src/styles/05_modules/_chuck-norris-joke.scss
new file mode 100644
index 0000000..232b479
--- /dev/null
+++ b/06_react/unterricht/tag35/01_reusable-components/src/styles/05_modules/_chuck-norris-joke.scss
@@ -0,0 +1,38 @@
+@use '../03_base/colors' as *;
+
+.chuck-norris-joke {
+ position: relative;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ width: 100%;
+ min-height: calc(100vh - 3.5rem); // full screen below the navbar
+ background: #555 url('../../assets/img/concrete-bg.jpg') center no-repeat fixed;
+ background-size: cover;
+
+ &::after {
+ content: '';
+ position: absolute;
+ z-index: 1;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ background: radial-gradient(circle, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.8) 100%);
+ }
+
+ > * {
+ position: relative;
+ z-index: 2;
+ }
+
+ .joke-text {
+ color: $color-white;
+ text-align: center;
+ font-size: 3rem;
+ max-width: 80%;
+ padding: 2rem;
+ text-shadow: 2px 2px 5px rgba(black, 0.5);
+ }
+}
diff --git a/06_react/unterricht/tag35/01_reusable-components/src/styles/05_modules/_header-main.scss b/06_react/unterricht/tag35/01_reusable-components/src/styles/05_modules/_header-main.scss
new file mode 100644
index 0000000..2884477
--- /dev/null
+++ b/06_react/unterricht/tag35/01_reusable-components/src/styles/05_modules/_header-main.scss
@@ -0,0 +1,15 @@
+.m-header-main {
+ width: 100%;
+ height: 400px;
+
+ // https://cssreference.io/property/background/
+ background: #efefef url('../../assets/img/header-bg.webp') center no-repeat border-box;
+ background-size: cover;
+
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: center;
+
+ border: 20px solid rgba(white, 0.25);
+}
diff --git a/06_react/unterricht/tag35/01_reusable-components/src/styles/05_modules/_index.scss b/06_react/unterricht/tag35/01_reusable-components/src/styles/05_modules/_index.scss
new file mode 100644
index 0000000..594a29d
--- /dev/null
+++ b/06_react/unterricht/tag35/01_reusable-components/src/styles/05_modules/_index.scss
@@ -0,0 +1,7 @@
+@forward 'button';
+// @forward 'chuck-norris-joke';
+@forward 'header-main';
+@forward 'input-amount';
+@forward 'logo-main';
+// @forward 'menu-main';
+// @forward 'product-manager';
diff --git a/06_react/unterricht/tag35/01_reusable-components/src/styles/05_modules/_input-amount.scss b/06_react/unterricht/tag35/01_reusable-components/src/styles/05_modules/_input-amount.scss
new file mode 100644
index 0000000..8701a7c
--- /dev/null
+++ b/06_react/unterricht/tag35/01_reusable-components/src/styles/05_modules/_input-amount.scss
@@ -0,0 +1,27 @@
+.m-input-amount {
+ .input-group {
+ .input-group-text {
+ padding: 0;
+ display: inline-block;
+ overflow: hidden;
+ button {
+ border-radius: 0;
+ }
+ }
+ input {
+ max-width: 85px;
+ text-align: center;
+ }
+ /* Für Chrome, Safari, Edge und Opera */
+ input::-webkit-outer-spin-button,
+ input::-webkit-inner-spin-button {
+ -webkit-appearance: none;
+ margin: 0;
+ }
+
+ /* Für Firefox */
+ input[type='number'] {
+ appearance: textfield;
+ }
+ }
+}
diff --git a/06_react/unterricht/tag35/01_reusable-components/src/styles/05_modules/_logo-main.scss b/06_react/unterricht/tag35/01_reusable-components/src/styles/05_modules/_logo-main.scss
new file mode 100644
index 0000000..399bd12
--- /dev/null
+++ b/06_react/unterricht/tag35/01_reusable-components/src/styles/05_modules/_logo-main.scss
@@ -0,0 +1,21 @@
+.logo-main {
+ margin: 0;
+
+ img,
+ svg {
+ width: 320px;
+ height: auto;
+ max-width: 320px;
+ }
+
+ figcaption {
+ width: 1px;
+ height: 1px;
+ padding: 0;
+ margin: -1px;
+ overflow: hidden;
+ clip: rect(0, 0, 0, 0);
+ white-space: nowrap;
+ border: 0;
+ }
+}
diff --git a/06_react/unterricht/tag35/01_reusable-components/src/styles/05_modules/_menu-main.scss b/06_react/unterricht/tag35/01_reusable-components/src/styles/05_modules/_menu-main.scss
new file mode 100644
index 0000000..df4627e
--- /dev/null
+++ b/06_react/unterricht/tag35/01_reusable-components/src/styles/05_modules/_menu-main.scss
@@ -0,0 +1,20 @@
+@use '../03_base/colors' as *;
+@use '../03_base/typography' as *;
+
+// Main navigation = Bootstrap 6 navbar (see includes/menu-main.html).
+// Only the look from frontend-gulp is added here: black bar, uppercase links.
+.menu-main {
+ background-color: $color-black;
+ font-family: $font-menu;
+
+ .nav-link {
+ text-transform: uppercase;
+ }
+}
+
+// Mobile drawer: Bootstrap 6 alpha keeps it white although the navbar is dark
+// (data-bs-theme="dark"), which leaves the light link text invisible. Give it the bar's colour.
+.menu-main .drawer {
+ background-color: $color-black;
+ color: $color-white;
+}
diff --git a/06_react/unterricht/tag35/01_reusable-components/src/styles/05_modules/_product-manager.scss b/06_react/unterricht/tag35/01_reusable-components/src/styles/05_modules/_product-manager.scss
new file mode 100644
index 0000000..4f3ed4d
--- /dev/null
+++ b/06_react/unterricht/tag35/01_reusable-components/src/styles/05_modules/_product-manager.scss
@@ -0,0 +1,47 @@
+.product-manager {
+ .nav-products-actions {
+ ul {
+ padding: 0;
+ margin: 0;
+ list-style: none;
+ display: flex;
+ justify-content: flex-end;
+
+ li {
+ button {
+ margin: 0.5rem 0 0.5rem 0.5rem;
+ }
+ }
+ }
+ }
+
+ table {
+ .th-actions {
+ width: 200px;
+ }
+ .th-dragger {
+ width: 50px;
+ }
+
+ td {
+ vertical-align: middle;
+ button {
+ margin: 0 2px;
+ }
+ }
+
+ tbody:empty::after {
+ content: 'loading products...';
+ width: max-content;
+ display: inline-block;
+ color: #999;
+ padding: 1rem;
+ }
+ tfoot .row > * {
+ margin-bottom: 0.5rem;
+ @media (min-width: 992px) {
+ margin-bottom: 0;
+ }
+ }
+ }
+}
diff --git a/06_react/unterricht/tag35/01_reusable-components/src/styles/main.scss b/06_react/unterricht/tag35/01_reusable-components/src/styles/main.scss
new file mode 100644
index 0000000..297e74f
--- /dev/null
+++ b/06_react/unterricht/tag35/01_reusable-components/src/styles/main.scss
@@ -0,0 +1,13 @@
+// Single stylesheet entry, linked in src/html/includes/head.html.
+// Same folders as in frontend-gulp; @use instead of the deprecated @import.
+
+// 01 Frameworks
+@use '01_frameworks' as *;
+// 02 Fonts
+@use '02_fonts' as *;
+// 03 Base
+@use '03_base' as *;
+// 04 Plugins
+@use '04_plugins' as *;
+// 05 Modules
+@use '05_modules' as *;
diff --git a/06_react/unterricht/tag35/01_reusable-components/vite.config.js b/06_react/unterricht/tag35/01_reusable-components/vite.config.js
new file mode 100644
index 0000000..24ad103
--- /dev/null
+++ b/06_react/unterricht/tag35/01_reusable-components/vite.config.js
@@ -0,0 +1,15 @@
+import react from '@vitejs/plugin-react';
+import { defineConfig } from 'vite';
+
+// https://vite.dev/config/
+export default defineConfig({
+ plugins: [react()],
+ css: {
+ preprocessorOptions: {
+ scss: {
+ quietDeps: true, // Unix
+ silenceDeprecations: ['color-functions', 'global-builtin', 'import', 'legacy-js-api', 'if-function'],
+ },
+ },
+ },
+});