diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index ac2a697..9978f7e 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -33,8 +33,8 @@ jobs: - name: Test run: npm run test - - name: Build - run: npm run build + - name: Type check + run: npx tsc --noEmit # ── Job 2: Deploy to dev (only on dev branch, after tests pass) ── deploy-dev: diff --git a/app/components/Hero.tsx b/app/components/Hero.tsx index d00c988..d3339c0 100644 --- a/app/components/Hero.tsx +++ b/app/components/Hero.tsx @@ -23,10 +23,10 @@ export default async function Hero({ locale }: HeroProps) {
-
+
{/* Left: Text Content */} -
+
{getLabel("hero.badge", "Student & Self-Hoster")} @@ -41,26 +41,26 @@ export default async function Hero({ locale }: HeroProps) { -

+

{t("description")}

-
+ {/* Right: The Photo */} -
+
- Dennis Konkol + Dennis Konkol
diff --git a/next.config.ts b/next.config.ts index b0493f8..251413f 100644 --- a/next.config.ts +++ b/next.config.ts @@ -34,10 +34,12 @@ const nextConfig: NextConfig = { experimental: { // Tree-shake barrel-file packages in both dev and production optimizePackageImports: ["lucide-react", "framer-motion", "react-icons", "@tiptap/react"], + // Merge all CSS into a single chunk to eliminate the render-blocking CSS chain + // (84dc7384.css → 3aefc04b.css sequential dependency reported by PageSpeed). + cssChunking: "loose", // Note: optimizeCss (critters) is intentionally disabled — it converts the main // to a JS-deferred preload, which PageSpeed reads as a - // sequential CSS chain and reports 410ms of render-blocking. Without it both CSS - // files load as parallel tags discovered from the initial HTML (~150ms total). + // sequential CSS chain and reports 410ms of render-blocking. ...(process.env.NODE_ENV !== "production" ? { webpackBuildWorker: true } : {}), }, diff --git a/package-lock.json b/package-lock.json index 409ce58..7512de5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,8 +10,6 @@ "dependencies": { "@next/bundle-analyzer": "^15.1.7", "@prisma/client": "^5.22.0", - "@react-three/fiber": "^9.5.0", - "@shadergradient/react": "^2.4.20", "@swc/helpers": "^0.5.19", "@tiptap/extension-color": "^3.15.3", "@tiptap/extension-highlight": "^3.15.3", @@ -38,8 +36,7 @@ "react-markdown": "^10.1.0", "redis": "^5.8.2", "sanitize-html": "^2.17.0", - "tailwind-merge": "^2.6.0", - "three": "^0.183.1" + "tailwind-merge": "^2.6.0" }, "devDependencies": { "@eslint/eslintrc": "^3", @@ -538,6 +535,7 @@ "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.6.tgz", "integrity": "sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -2998,54 +2996,6 @@ "@prisma/debug": "5.22.0" } }, - "node_modules/@react-three/fiber": { - "version": "9.5.0", - "resolved": "https://registry.npmjs.org/@react-three/fiber/-/fiber-9.5.0.tgz", - "integrity": "sha512-FiUzfYW4wB1+PpmsE47UM+mCads7j2+giRBltfwH7SNhah95rqJs3ltEs9V3pP8rYdS0QlNne+9Aj8dS/SiaIA==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.17.8", - "@types/webxr": "*", - "base64-js": "^1.5.1", - "buffer": "^6.0.3", - "its-fine": "^2.0.0", - "react-use-measure": "^2.1.7", - "scheduler": "^0.27.0", - "suspend-react": "^0.1.3", - "use-sync-external-store": "^1.4.0", - "zustand": "^5.0.3" - }, - "peerDependencies": { - "expo": ">=43.0", - "expo-asset": ">=8.4", - "expo-file-system": ">=11.0", - "expo-gl": ">=11.0", - "react": ">=19 <19.3", - "react-dom": ">=19 <19.3", - "react-native": ">=0.78", - "three": ">=0.156" - }, - "peerDependenciesMeta": { - "expo": { - "optional": true - }, - "expo-asset": { - "optional": true - }, - "expo-file-system": { - "optional": true - }, - "expo-gl": { - "optional": true - }, - "react-dom": { - "optional": true - }, - "react-native": { - "optional": true - } - } - }, "node_modules/@redis/bloom": { "version": "5.10.0", "resolved": "https://registry.npmjs.org/@redis/bloom/-/bloom-5.10.0.tgz", @@ -3141,16 +3091,6 @@ "integrity": "sha512-bXHSaW5jRTmke9Vd0h5P7BtWZG9Znqb8gSDxZnxaGSJnGwPLDPfS+3g0BKzeWqzgZPsIVZkM7m2tbo18cm5HBw==", "license": "MIT" }, - "node_modules/@shadergradient/react": { - "version": "2.4.20", - "resolved": "https://registry.npmjs.org/@shadergradient/react/-/react-2.4.20.tgz", - "integrity": "sha512-MVYvYgTHK3d36C2jNKzt4OzWeyNyc/bWI0zKRyv5EgI2hmUee8nD0cmuNX9X1lw1RCcuof6n1Rnj63jWepZHJA==", - "license": "MIT", - "peerDependencies": { - "react": "^18.2.0 || ^19.0.0", - "react-dom": "^18.2.0 || ^19.0.0" - } - }, "node_modules/@shuding/opentype.js": { "version": "1.4.0-beta.0", "resolved": "https://registry.npmjs.org/@shuding/opentype.js/-/opentype.js-1.4.0-beta.0.tgz", @@ -4275,15 +4215,6 @@ "@types/react": "^19.2.0" } }, - "node_modules/@types/react-reconciler": { - "version": "0.28.9", - "resolved": "https://registry.npmjs.org/@types/react-reconciler/-/react-reconciler-0.28.9.tgz", - "integrity": "sha512-HHM3nxyUZ3zAylX8ZEyrDNd2XZOnQ0D5XfunJF5FLQnZbHHYq4UWvW1QfelQNXv1ICNkwYhfxjwfnqivYB6bFg==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*" - } - }, "node_modules/@types/sanitize-html": { "version": "2.16.0", "resolved": "https://registry.npmjs.org/@types/sanitize-html/-/sanitize-html-2.16.0.tgz", @@ -4320,12 +4251,6 @@ "integrity": "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==", "license": "MIT" }, - "node_modules/@types/webxr": { - "version": "0.5.24", - "resolved": "https://registry.npmjs.org/@types/webxr/-/webxr-0.5.24.tgz", - "integrity": "sha512-h8fgEd/DpoS9CBrjEQXR+dIDraopAEfu4wYVNY2tEPwk60stPWhvZMf4Foo5FakuQ7HFZoa8WceaWFervK2Ovg==", - "license": "MIT" - }, "node_modules/@types/whatwg-mimetype": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/@types/whatwg-mimetype/-/whatwg-mimetype-3.0.2.tgz", @@ -5490,26 +5415,6 @@ "dev": true, "license": "MIT" }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, "node_modules/baseline-browser-mapping": { "version": "2.9.19", "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.19.tgz", @@ -5621,30 +5526,6 @@ "node-int64": "^0.4.0" } }, - "node_modules/buffer": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", - "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.2.1" - } - }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -8322,26 +8203,6 @@ "@formatjs/icu-messageformat-parser": "^3.4.0" } }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "BSD-3-Clause" - }, "node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", @@ -9115,18 +8976,6 @@ "node": ">= 0.4" } }, - "node_modules/its-fine": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/its-fine/-/its-fine-2.0.0.tgz", - "integrity": "sha512-KLViCmWx94zOvpLwSlsx6yOCeMhZYaxrJV87Po5k/FoZzcPSahvK5qJ7fYhS61sZi5ikmh2S3Hz55A2l3U69ng==", - "license": "MIT", - "dependencies": { - "@types/react-reconciler": "^0.28.9" - }, - "peerDependencies": { - "react": "^19.0.0" - } - }, "node_modules/jest": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", @@ -12833,21 +12682,6 @@ "react": ">=18" } }, - "node_modules/react-use-measure": { - "version": "2.1.7", - "resolved": "https://registry.npmjs.org/react-use-measure/-/react-use-measure-2.1.7.tgz", - "integrity": "sha512-KrvcAo13I/60HpwGO5jpW7E9DfusKyLPLvuHlUyP5zqnmAPhNc6qTRjUQrdTADl0lpPpDVU2/Gg51UlOGHXbdg==", - "license": "MIT", - "peerDependencies": { - "react": ">=16.13", - "react-dom": ">=16.13" - }, - "peerDependenciesMeta": { - "react-dom": { - "optional": true - } - } - }, "node_modules/read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", @@ -13880,15 +13714,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/suspend-react": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/suspend-react/-/suspend-react-0.1.3.tgz", - "integrity": "sha512-aqldKgX9aZqpoDp3e8/BZ8Dm7x1pJl+qI3ZKxDN0i/IQTWUwBx/ManmlVJ3wowqbno6c2bmiIfs+Um6LbsjJyQ==", - "license": "MIT", - "peerDependencies": { - "react": ">=17.0" - } - }, "node_modules/symbol-tree": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", @@ -14041,12 +13866,6 @@ "node": ">=0.8" } }, - "node_modules/three": { - "version": "0.183.1", - "resolved": "https://registry.npmjs.org/three/-/three-0.183.1.tgz", - "integrity": "sha512-Psv6bbd3d/M/01MT2zZ+VmD0Vj2dbWTNhfe4CuSg7w5TuW96M3NOyCVuh9SZQ05CpGmD7NEcJhZw4GVjhCYxfQ==", - "license": "MIT" - }, "node_modules/tiny-inflate": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.3.tgz", @@ -15261,35 +15080,6 @@ "integrity": "sha512-N+d4UJSJbt/R3wqY7Coqs5pcV0aUj2j9IaQ3rNj9bVCLld8tTGKRa2USARjnvZJWVx1NDmQev8EknoczaOQDOA==", "license": "MIT" }, - "node_modules/zustand": { - "version": "5.0.11", - "resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.11.tgz", - "integrity": "sha512-fdZY+dk7zn/vbWNCYmzZULHRrss0jx5pPFiOuMZ/5HJN6Yv3u+1Wswy/4MpZEkEGhtNH+pwxZB8OKgUBPzYAGg==", - "license": "MIT", - "engines": { - "node": ">=12.20.0" - }, - "peerDependencies": { - "@types/react": ">=18.0.0", - "immer": ">=9.0.6", - "react": ">=18.0.0", - "use-sync-external-store": ">=1.2.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "immer": { - "optional": true - }, - "react": { - "optional": true - }, - "use-sync-external-store": { - "optional": true - } - } - }, "node_modules/zwitch": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", diff --git a/package.json b/package.json index b63d6cb..363d0e2 100644 --- a/package.json +++ b/package.json @@ -54,8 +54,6 @@ "dependencies": { "@next/bundle-analyzer": "^15.1.7", "@prisma/client": "^5.22.0", - "@react-three/fiber": "^9.5.0", - "@shadergradient/react": "^2.4.20", "@swc/helpers": "^0.5.19", "@tiptap/extension-color": "^3.15.3", "@tiptap/extension-highlight": "^3.15.3", @@ -82,8 +80,7 @@ "react-markdown": "^10.1.0", "redis": "^5.8.2", "sanitize-html": "^2.17.0", - "tailwind-merge": "^2.6.0", - "three": "^0.183.1" + "tailwind-merge": "^2.6.0" }, "browserslist": [ "chrome >= 100",