diff --git a/.gitignore b/.gitignore
index 06ecca63..5ef6a520 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,28 +1,41 @@
-# Logs
-logs
-*.log
+# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
+
+# dependencies
+/node_modules
+/.pnp
+.pnp.*
+.yarn/*
+!.yarn/patches
+!.yarn/plugins
+!.yarn/releases
+!.yarn/versions
+
+# testing
+/coverage
+
+# next.js
+/.next/
+/out/
+
+# production
+/build
+
+# misc
+.DS_Store
+*.pem
+
+# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
-pnpm-debug.log*
-lerna-debug.log*
-
-node_modules
-dist
-dist-ssr
-*.local
-vendor
-var
-
-# Editor directories and files
-.vscode/*
-!.vscode/extensions.json
-.idea
-.DS_Store
-*.suo
-*.ntvs*
-*.njsproj
-*.sln
-*.sw?
+.pnpm-debug.log*
+
+# env files (can opt-in for committing if needed)
+.env*
+
+# vercel
+.vercel
-.env
+# typescript
+*.tsbuildinfo
+next-env.d.ts
diff --git a/.vscode/extensions.json b/.vscode/extensions.json
deleted file mode 100644
index a7cea0b0..00000000
--- a/.vscode/extensions.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "recommendations": ["Vue.volar"]
-}
diff --git a/README.md b/README.md
index fdedd97c..e215bc4c 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,36 @@
-# Personal Portfolio
+This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).
-https://www.maxdlr.com
+## Getting Started
-> Simple landing page on my main domain.
-> It mainly redirects visitors to what they're looking for.
+First, run the development server:
+
+```bash
+npm run dev
+# or
+yarn dev
+# or
+pnpm dev
+# or
+bun dev
+```
+
+Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
+
+You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
+
+This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
+
+## Learn More
+
+To learn more about Next.js, take a look at the following resources:
+
+- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
+- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
+
+You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
+
+## Deploy on Vercel
+
+The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
+
+Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.
diff --git a/biome.json b/biome.json
new file mode 100644
index 00000000..e69d1175
--- /dev/null
+++ b/biome.json
@@ -0,0 +1,12 @@
+{
+ "$schema": "https://biomejs.dev/schemas/2.0.5/schema.json",
+ "formatter": {
+ "enabled": false
+ },
+ "linter": {
+ "enabled": false
+ },
+ "assist": {
+ "enabled": false
+ }
+}
diff --git a/biome.jsonc b/biome.jsonc
new file mode 100644
index 00000000..516d9f8c
--- /dev/null
+++ b/biome.jsonc
@@ -0,0 +1,17 @@
+{
+ "formatter": {
+ "indentStyle": "space", // default is `tab`
+ "lineWidth": 100, // default is `80`
+ },
+ "javascript": {
+ "formatter": {
+ "quoteStyle": "single", // default is `double`
+ "lineWidth": 120, // override `formatter.lineWidth`
+ },
+ },
+ "json": {
+ "formatter": {
+ "enabled": false,
+ },
+ },
+}
diff --git a/eslint.config.js b/eslint.config.js
deleted file mode 100644
index b1a73bfc..00000000
--- a/eslint.config.js
+++ /dev/null
@@ -1,17 +0,0 @@
-import globals from "globals";
-import pluginJs from "@eslint/js";
-import tseslint from "typescript-eslint";
-import pluginVue from "eslint-plugin-vue";
-
-/** @type {import('eslint').Linter.Config[]} */
-export default [
- { files: ["**/*.{js,mjs,cjs,ts,vue}"] },
- { languageOptions: { globals: globals.browser } },
- pluginJs.configs.recommended,
- ...tseslint.configs.recommended,
- ...pluginVue.configs["flat/essential"],
- {
- files: ["**/*.vue"],
- languageOptions: { parserOptions: { parser: tseslint.parser } },
- },
-];
diff --git a/index.html b/index.html
deleted file mode 100644
index 763ff733..00000000
--- a/index.html
+++ /dev/null
@@ -1,45 +0,0 @@
-
-
-
-
-
-
- Maxdlr - Developer & Motion designer
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/next.config.ts b/next.config.ts
new file mode 100644
index 00000000..e9ffa308
--- /dev/null
+++ b/next.config.ts
@@ -0,0 +1,7 @@
+import type { NextConfig } from "next";
+
+const nextConfig: NextConfig = {
+ /* config options here */
+};
+
+export default nextConfig;
diff --git a/old/.gitignore b/old/.gitignore
new file mode 100644
index 00000000..06ecca63
--- /dev/null
+++ b/old/.gitignore
@@ -0,0 +1,28 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+lerna-debug.log*
+
+node_modules
+dist
+dist-ssr
+*.local
+vendor
+var
+
+# Editor directories and files
+.vscode/*
+!.vscode/extensions.json
+.idea
+.DS_Store
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
+
+.env
diff --git a/.prettierignore b/old/.prettierignore
similarity index 100%
rename from .prettierignore
rename to old/.prettierignore
diff --git a/.prettierrc b/old/.prettierrc
similarity index 100%
rename from .prettierrc
rename to old/.prettierrc
diff --git a/Dockerfile b/old/Dockerfile
similarity index 100%
rename from Dockerfile
rename to old/Dockerfile
diff --git a/old/README.md b/old/README.md
new file mode 100644
index 00000000..fdedd97c
--- /dev/null
+++ b/old/README.md
@@ -0,0 +1,6 @@
+# Personal Portfolio
+
+https://www.maxdlr.com
+
+> Simple landing page on my main domain.
+> It mainly redirects visitors to what they're looking for.
diff --git a/docker-compose.yml b/old/docker-compose.yml
similarity index 100%
rename from docker-compose.yml
rename to old/docker-compose.yml
diff --git a/nginx.conf b/old/nginx.conf
similarity index 100%
rename from nginx.conf
rename to old/nginx.conf
diff --git a/public/current-project.gif b/old/public/current-project.gif
similarity index 100%
rename from public/current-project.gif
rename to old/public/current-project.gif
diff --git a/public/cv-motion.pdf b/old/public/cv-motion.pdf
similarity index 100%
rename from public/cv-motion.pdf
rename to old/public/cv-motion.pdf
diff --git a/public/cv.pdf b/old/public/cv.pdf
similarity index 100%
rename from public/cv.pdf
rename to old/public/cv.pdf
diff --git a/public/favicon.jpg b/old/public/favicon.jpg
similarity index 100%
rename from public/favicon.jpg
rename to old/public/favicon.jpg
diff --git a/public/loading.gif b/old/public/loading.gif
similarity index 100%
rename from public/loading.gif
rename to old/public/loading.gif
diff --git a/public/logo.png b/old/public/logo.png
similarity index 100%
rename from public/logo.png
rename to old/public/logo.png
diff --git a/public/photo.jpg b/old/public/photo.jpg
similarity index 100%
rename from public/photo.jpg
rename to old/public/photo.jpg
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 00000000..cef67345
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,1911 @@
+{
+ "name": "maxdlr-portfolio",
+ "version": "0.1.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "maxdlr-portfolio",
+ "version": "0.1.0",
+ "dependencies": {
+ "motion": "^12.23.24",
+ "next": "15.5.4",
+ "react": "19.1.0",
+ "react-dom": "19.1.0",
+ "use-breakpoint": "^4.0.10"
+ },
+ "devDependencies": {
+ "@biomejs/biome": "2.2.0",
+ "@tailwindcss/postcss": "^4",
+ "@types/node": "^20",
+ "@types/react": "^19",
+ "@types/react-dom": "^19",
+ "tailwindcss": "^4",
+ "typescript": "^5"
+ }
+ },
+ "node_modules/@alloc/quick-lru": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz",
+ "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/@biomejs/biome": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-2.2.0.tgz",
+ "integrity": "sha512-3On3RSYLsX+n9KnoSgfoYlckYBoU6VRM22cw1gB4Y0OuUVSYd/O/2saOJMrA4HFfA1Ff0eacOvMN1yAAvHtzIw==",
+ "dev": true,
+ "license": "MIT OR Apache-2.0",
+ "bin": {
+ "biome": "bin/biome"
+ },
+ "engines": {
+ "node": ">=14.21.3"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/biome"
+ },
+ "optionalDependencies": {
+ "@biomejs/cli-darwin-arm64": "2.2.0",
+ "@biomejs/cli-darwin-x64": "2.2.0",
+ "@biomejs/cli-linux-arm64": "2.2.0",
+ "@biomejs/cli-linux-arm64-musl": "2.2.0",
+ "@biomejs/cli-linux-x64": "2.2.0",
+ "@biomejs/cli-linux-x64-musl": "2.2.0",
+ "@biomejs/cli-win32-arm64": "2.2.0",
+ "@biomejs/cli-win32-x64": "2.2.0"
+ }
+ },
+ "node_modules/@biomejs/cli-darwin-arm64": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-2.2.0.tgz",
+ "integrity": "sha512-zKbwUUh+9uFmWfS8IFxmVD6XwqFcENjZvEyfOxHs1epjdH3wyyMQG80FGDsmauPwS2r5kXdEM0v/+dTIA9FXAg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT OR Apache-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=14.21.3"
+ }
+ },
+ "node_modules/@biomejs/cli-darwin-x64": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-2.2.0.tgz",
+ "integrity": "sha512-+OmT4dsX2eTfhD5crUOPw3RPhaR+SKVspvGVmSdZ9y9O/AgL8pla6T4hOn1q+VAFBHuHhsdxDRJgFCSC7RaMOw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT OR Apache-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=14.21.3"
+ }
+ },
+ "node_modules/@biomejs/cli-linux-arm64": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-2.2.0.tgz",
+ "integrity": "sha512-6eoRdF2yW5FnW9Lpeivh7Mayhq0KDdaDMYOJnH9aT02KuSIX5V1HmWJCQQPwIQbhDh68Zrcpl8inRlTEan0SXw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT OR Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=14.21.3"
+ }
+ },
+ "node_modules/@biomejs/cli-linux-arm64-musl": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.2.0.tgz",
+ "integrity": "sha512-egKpOa+4FL9YO+SMUMLUvf543cprjevNc3CAgDNFLcjknuNMcZ0GLJYa3EGTCR2xIkIUJDVneBV3O9OcIlCEZQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT OR Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=14.21.3"
+ }
+ },
+ "node_modules/@biomejs/cli-linux-x64": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-2.2.0.tgz",
+ "integrity": "sha512-5UmQx/OZAfJfi25zAnAGHUMuOd+LOsliIt119x2soA2gLggQYrVPA+2kMUxR6Mw5M1deUF/AWWP2qpxgH7Nyfw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT OR Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=14.21.3"
+ }
+ },
+ "node_modules/@biomejs/cli-linux-x64-musl": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-2.2.0.tgz",
+ "integrity": "sha512-I5J85yWwUWpgJyC1CcytNSGusu2p9HjDnOPAFG4Y515hwRD0jpR9sT9/T1cKHtuCvEQ/sBvx+6zhz9l9wEJGAg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT OR Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=14.21.3"
+ }
+ },
+ "node_modules/@biomejs/cli-win32-arm64": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-2.2.0.tgz",
+ "integrity": "sha512-n9a1/f2CwIDmNMNkFs+JI0ZjFnMO0jdOyGNtihgUNFnlmd84yIYY2KMTBmMV58ZlVHjgmY5Y6E1hVTnSRieggA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT OR Apache-2.0",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=14.21.3"
+ }
+ },
+ "node_modules/@biomejs/cli-win32-x64": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-2.2.0.tgz",
+ "integrity": "sha512-Nawu5nHjP/zPKTIryh2AavzTc/KEg4um/MxWdXW0A6P/RZOyIpa7+QSjeXwAwX/utJGaCoXRPWtF3m5U/bB3Ww==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT OR Apache-2.0",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=14.21.3"
+ }
+ },
+ "node_modules/@emnapi/runtime": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.5.0.tgz",
+ "integrity": "sha512-97/BJ3iXHww3djw6hYIfErCZFee7qCtrneuLa20UXFCOTCfBM2cvQHjWJ2EG0s0MtdNwInarqCTz35i4wWXHsQ==",
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@img/colour": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.0.0.tgz",
+ "integrity": "sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==",
+ "license": "MIT",
+ "optional": true,
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@img/sharp-darwin-arm64": {
+ "version": "0.34.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.4.tgz",
+ "integrity": "sha512-sitdlPzDVyvmINUdJle3TNHl+AG9QcwiAMsXmccqsCOMZNIdW2/7S26w0LyU8euiLVzFBL3dXPwVCq/ODnf2vA==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-darwin-arm64": "1.2.3"
+ }
+ },
+ "node_modules/@img/sharp-darwin-x64": {
+ "version": "0.34.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.4.tgz",
+ "integrity": "sha512-rZheupWIoa3+SOdF/IcUe1ah4ZDpKBGWcsPX6MT0lYniH9micvIU7HQkYTfrx5Xi8u+YqwLtxC/3vl8TQN6rMg==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-darwin-x64": "1.2.3"
+ }
+ },
+ "node_modules/@img/sharp-libvips-darwin-arm64": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.3.tgz",
+ "integrity": "sha512-QzWAKo7kpHxbuHqUC28DZ9pIKpSi2ts2OJnoIGI26+HMgq92ZZ4vk8iJd4XsxN+tYfNJxzH6W62X5eTcsBymHw==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-darwin-x64": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.3.tgz",
+ "integrity": "sha512-Ju+g2xn1E2AKO6YBhxjj+ACcsPQRHT0bhpglxcEf+3uyPY+/gL8veniKoo96335ZaPo03bdDXMv0t+BBFAbmRA==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linux-arm": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.3.tgz",
+ "integrity": "sha512-x1uE93lyP6wEwGvgAIV0gP6zmaL/a0tGzJs/BIDDG0zeBhMnuUPm7ptxGhUbcGs4okDJrk4nxgrmxpib9g6HpA==",
+ "cpu": [
+ "arm"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linux-arm64": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.3.tgz",
+ "integrity": "sha512-I4RxkXU90cpufazhGPyVujYwfIm9Nk1QDEmiIsaPwdnm013F7RIceaCc87kAH+oUB1ezqEvC6ga4m7MSlqsJvQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linux-ppc64": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.3.tgz",
+ "integrity": "sha512-Y2T7IsQvJLMCBM+pmPbM3bKT/yYJvVtLJGfCs4Sp95SjvnFIjynbjzsa7dY1fRJX45FTSfDksbTp6AGWudiyCg==",
+ "cpu": [
+ "ppc64"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linux-s390x": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.3.tgz",
+ "integrity": "sha512-RgWrs/gVU7f+K7P+KeHFaBAJlNkD1nIZuVXdQv6S+fNA6syCcoboNjsV2Pou7zNlVdNQoQUpQTk8SWDHUA3y/w==",
+ "cpu": [
+ "s390x"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linux-x64": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.3.tgz",
+ "integrity": "sha512-3JU7LmR85K6bBiRzSUc/Ff9JBVIFVvq6bomKE0e63UXGeRw2HPVEjoJke1Yx+iU4rL7/7kUjES4dZ/81Qjhyxg==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linuxmusl-arm64": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.3.tgz",
+ "integrity": "sha512-F9q83RZ8yaCwENw1GieztSfj5msz7GGykG/BA+MOUefvER69K/ubgFHNeSyUu64amHIYKGDs4sRCMzXVj8sEyw==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linuxmusl-x64": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.3.tgz",
+ "integrity": "sha512-U5PUY5jbc45ANM6tSJpsgqmBF/VsL6LnxJmIf11kB7J5DctHgqm0SkuXzVWtIY90GnJxKnC/JT251TDnk1fu/g==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-linux-arm": {
+ "version": "0.34.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.4.tgz",
+ "integrity": "sha512-Xyam4mlqM0KkTHYVSuc6wXRmM7LGN0P12li03jAnZ3EJWZqj83+hi8Y9UxZUbxsgsK1qOEwg7O0Bc0LjqQVtxA==",
+ "cpu": [
+ "arm"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-arm": "1.2.3"
+ }
+ },
+ "node_modules/@img/sharp-linux-arm64": {
+ "version": "0.34.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.4.tgz",
+ "integrity": "sha512-YXU1F/mN/Wu786tl72CyJjP/Ngl8mGHN1hST4BGl+hiW5jhCnV2uRVTNOcaYPs73NeT/H8Upm3y9582JVuZHrQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-arm64": "1.2.3"
+ }
+ },
+ "node_modules/@img/sharp-linux-ppc64": {
+ "version": "0.34.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.4.tgz",
+ "integrity": "sha512-F4PDtF4Cy8L8hXA2p3TO6s4aDt93v+LKmpcYFLAVdkkD3hSxZzee0rh6/+94FpAynsuMpLX5h+LRsSG3rIciUQ==",
+ "cpu": [
+ "ppc64"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-ppc64": "1.2.3"
+ }
+ },
+ "node_modules/@img/sharp-linux-s390x": {
+ "version": "0.34.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.4.tgz",
+ "integrity": "sha512-qVrZKE9Bsnzy+myf7lFKvng6bQzhNUAYcVORq2P7bDlvmF6u2sCmK2KyEQEBdYk+u3T01pVsPrkj943T1aJAsw==",
+ "cpu": [
+ "s390x"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-s390x": "1.2.3"
+ }
+ },
+ "node_modules/@img/sharp-linux-x64": {
+ "version": "0.34.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.4.tgz",
+ "integrity": "sha512-ZfGtcp2xS51iG79c6Vhw9CWqQC8l2Ot8dygxoDoIQPTat/Ov3qAa8qpxSrtAEAJW+UjTXc4yxCjNfxm4h6Xm2A==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-x64": "1.2.3"
+ }
+ },
+ "node_modules/@img/sharp-linuxmusl-arm64": {
+ "version": "0.34.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.4.tgz",
+ "integrity": "sha512-8hDVvW9eu4yHWnjaOOR8kHVrew1iIX+MUgwxSuH2XyYeNRtLUe4VNioSqbNkB7ZYQJj9rUTT4PyRscyk2PXFKA==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linuxmusl-arm64": "1.2.3"
+ }
+ },
+ "node_modules/@img/sharp-linuxmusl-x64": {
+ "version": "0.34.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.4.tgz",
+ "integrity": "sha512-lU0aA5L8QTlfKjpDCEFOZsTYGn3AEiO6db8W5aQDxj0nQkVrZWmN3ZP9sYKWJdtq3PWPhUNlqehWyXpYDcI9Sg==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linuxmusl-x64": "1.2.3"
+ }
+ },
+ "node_modules/@img/sharp-wasm32": {
+ "version": "0.34.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.4.tgz",
+ "integrity": "sha512-33QL6ZO/qpRyG7woB/HUALz28WnTMI2W1jgX3Nu2bypqLIKx/QKMILLJzJjI+SIbvXdG9fUnmrxR7vbi1sTBeA==",
+ "cpu": [
+ "wasm32"
+ ],
+ "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT",
+ "optional": true,
+ "dependencies": {
+ "@emnapi/runtime": "^1.5.0"
+ },
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-win32-arm64": {
+ "version": "0.34.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.4.tgz",
+ "integrity": "sha512-2Q250do/5WXTwxW3zjsEuMSv5sUU4Tq9VThWKlU2EYLm4MB7ZeMwF+SFJutldYODXF6jzc6YEOC+VfX0SZQPqA==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "Apache-2.0 AND LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-win32-ia32": {
+ "version": "0.34.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.4.tgz",
+ "integrity": "sha512-3ZeLue5V82dT92CNL6rsal6I2weKw1cYu+rGKm8fOCCtJTR2gYeUfY3FqUnIJsMUPIH68oS5jmZ0NiJ508YpEw==",
+ "cpu": [
+ "ia32"
+ ],
+ "license": "Apache-2.0 AND LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-win32-x64": {
+ "version": "0.34.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.4.tgz",
+ "integrity": "sha512-xIyj4wpYs8J18sVN3mSQjwrw7fKUqRw+Z5rnHNCy5fYTxigBz81u5mOMPmFumwjcn8+ld1ppptMBCLic1nz6ig==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "Apache-2.0 AND LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@isaacs/fs-minipass": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz",
+ "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "minipass": "^7.0.4"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ }
+ },
+ "node_modules/@jridgewell/gen-mapping": {
+ "version": "0.3.13",
+ "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
+ "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/sourcemap-codec": "^1.5.0",
+ "@jridgewell/trace-mapping": "^0.3.24"
+ }
+ },
+ "node_modules/@jridgewell/remapping": {
+ "version": "2.3.5",
+ "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz",
+ "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/gen-mapping": "^0.3.5",
+ "@jridgewell/trace-mapping": "^0.3.24"
+ }
+ },
+ "node_modules/@jridgewell/resolve-uri": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
+ "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@jridgewell/sourcemap-codec": {
+ "version": "1.5.5",
+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
+ "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@jridgewell/trace-mapping": {
+ "version": "0.3.31",
+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz",
+ "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/resolve-uri": "^3.1.0",
+ "@jridgewell/sourcemap-codec": "^1.4.14"
+ }
+ },
+ "node_modules/@next/env": {
+ "version": "15.5.4",
+ "resolved": "https://registry.npmjs.org/@next/env/-/env-15.5.4.tgz",
+ "integrity": "sha512-27SQhYp5QryzIT5uO8hq99C69eLQ7qkzkDPsk3N+GuS2XgOgoYEeOav7Pf8Tn4drECOVDsDg8oj+/DVy8qQL2A==",
+ "license": "MIT"
+ },
+ "node_modules/@next/swc-darwin-arm64": {
+ "version": "15.5.4",
+ "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.5.4.tgz",
+ "integrity": "sha512-nopqz+Ov6uvorej8ndRX6HlxCYWCO3AHLfKK2TYvxoSB2scETOcfm/HSS3piPqc3A+MUgyHoqE6je4wnkjfrOA==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@next/swc-darwin-x64": {
+ "version": "15.5.4",
+ "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-15.5.4.tgz",
+ "integrity": "sha512-QOTCFq8b09ghfjRJKfb68kU9k2K+2wsC4A67psOiMn849K9ZXgCSRQr0oVHfmKnoqCbEmQWG1f2h1T2vtJJ9mA==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@next/swc-linux-arm64-gnu": {
+ "version": "15.5.4",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.5.4.tgz",
+ "integrity": "sha512-eRD5zkts6jS3VfE/J0Kt1VxdFqTnMc3QgO5lFE5GKN3KDI/uUpSyK3CjQHmfEkYR4wCOl0R0XrsjpxfWEA++XA==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@next/swc-linux-arm64-musl": {
+ "version": "15.5.4",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.5.4.tgz",
+ "integrity": "sha512-TOK7iTxmXFc45UrtKqWdZ1shfxuL4tnVAOuuJK4S88rX3oyVV4ZkLjtMT85wQkfBrOOvU55aLty+MV8xmcJR8A==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@next/swc-linux-x64-gnu": {
+ "version": "15.5.4",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.5.4.tgz",
+ "integrity": "sha512-7HKolaj+481FSW/5lL0BcTkA4Ueam9SPYWyN/ib/WGAFZf0DGAN8frNpNZYFHtM4ZstrHZS3LY3vrwlIQfsiMA==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@next/swc-linux-x64-musl": {
+ "version": "15.5.4",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.5.4.tgz",
+ "integrity": "sha512-nlQQ6nfgN0nCO/KuyEUwwOdwQIGjOs4WNMjEUtpIQJPR2NUfmGpW2wkJln1d4nJ7oUzd1g4GivH5GoEPBgfsdw==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@next/swc-win32-arm64-msvc": {
+ "version": "15.5.4",
+ "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.5.4.tgz",
+ "integrity": "sha512-PcR2bN7FlM32XM6eumklmyWLLbu2vs+D7nJX8OAIoWy69Kef8mfiN4e8TUv2KohprwifdpFKPzIP1njuCjD0YA==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@next/swc-win32-x64-msvc": {
+ "version": "15.5.4",
+ "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.5.4.tgz",
+ "integrity": "sha512-1ur2tSHZj8Px/KMAthmuI9FMp/YFusMMGoRNJaRZMOlSkgvLjzosSdQI0cJAKogdHl3qXUQKL9MGaYvKwA7DXg==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@swc/helpers": {
+ "version": "0.5.15",
+ "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz",
+ "integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "tslib": "^2.8.0"
+ }
+ },
+ "node_modules/@tailwindcss/node": {
+ "version": "4.1.14",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.14.tgz",
+ "integrity": "sha512-hpz+8vFk3Ic2xssIA3e01R6jkmsAhvkQdXlEbRTk6S10xDAtiQiM3FyvZVGsucefq764euO/b8WUW9ysLdThHw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/remapping": "^2.3.4",
+ "enhanced-resolve": "^5.18.3",
+ "jiti": "^2.6.0",
+ "lightningcss": "1.30.1",
+ "magic-string": "^0.30.19",
+ "source-map-js": "^1.2.1",
+ "tailwindcss": "4.1.14"
+ }
+ },
+ "node_modules/@tailwindcss/oxide": {
+ "version": "4.1.14",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.14.tgz",
+ "integrity": "sha512-23yx+VUbBwCg2x5XWdB8+1lkPajzLmALEfMb51zZUBYaYVPDQvBSD/WYDqiVyBIo2BZFa3yw1Rpy3G2Jp+K0dw==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "dependencies": {
+ "detect-libc": "^2.0.4",
+ "tar": "^7.5.1"
+ },
+ "engines": {
+ "node": ">= 10"
+ },
+ "optionalDependencies": {
+ "@tailwindcss/oxide-android-arm64": "4.1.14",
+ "@tailwindcss/oxide-darwin-arm64": "4.1.14",
+ "@tailwindcss/oxide-darwin-x64": "4.1.14",
+ "@tailwindcss/oxide-freebsd-x64": "4.1.14",
+ "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.14",
+ "@tailwindcss/oxide-linux-arm64-gnu": "4.1.14",
+ "@tailwindcss/oxide-linux-arm64-musl": "4.1.14",
+ "@tailwindcss/oxide-linux-x64-gnu": "4.1.14",
+ "@tailwindcss/oxide-linux-x64-musl": "4.1.14",
+ "@tailwindcss/oxide-wasm32-wasi": "4.1.14",
+ "@tailwindcss/oxide-win32-arm64-msvc": "4.1.14",
+ "@tailwindcss/oxide-win32-x64-msvc": "4.1.14"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-android-arm64": {
+ "version": "4.1.14",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.14.tgz",
+ "integrity": "sha512-a94ifZrGwMvbdeAxWoSuGcIl6/DOP5cdxagid7xJv6bwFp3oebp7y2ImYsnZBMTwjn5Ev5xESvS3FFYUGgPODQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-darwin-arm64": {
+ "version": "4.1.14",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.14.tgz",
+ "integrity": "sha512-HkFP/CqfSh09xCnrPJA7jud7hij5ahKyWomrC3oiO2U9i0UjP17o9pJbxUN0IJ471GTQQmzwhp0DEcpbp4MZTA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-darwin-x64": {
+ "version": "4.1.14",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.14.tgz",
+ "integrity": "sha512-eVNaWmCgdLf5iv6Qd3s7JI5SEFBFRtfm6W0mphJYXgvnDEAZ5sZzqmI06bK6xo0IErDHdTA5/t7d4eTfWbWOFw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-freebsd-x64": {
+ "version": "4.1.14",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.14.tgz",
+ "integrity": "sha512-QWLoRXNikEuqtNb0dhQN6wsSVVjX6dmUFzuuiL09ZeXju25dsei2uIPl71y2Ic6QbNBsB4scwBoFnlBfabHkEw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": {
+ "version": "4.1.14",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.14.tgz",
+ "integrity": "sha512-VB4gjQni9+F0VCASU+L8zSIyjrLLsy03sjcR3bM0V2g4SNamo0FakZFKyUQ96ZVwGK4CaJsc9zd/obQy74o0Fw==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-linux-arm64-gnu": {
+ "version": "4.1.14",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.14.tgz",
+ "integrity": "sha512-qaEy0dIZ6d9vyLnmeg24yzA8XuEAD9WjpM5nIM1sUgQ/Zv7cVkharPDQcmm/t/TvXoKo/0knI3me3AGfdx6w1w==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-linux-arm64-musl": {
+ "version": "4.1.14",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.14.tgz",
+ "integrity": "sha512-ISZjT44s59O8xKsPEIesiIydMG/sCXoMBCqsphDm/WcbnuWLxxb+GcvSIIA5NjUw6F8Tex7s5/LM2yDy8RqYBQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-linux-x64-gnu": {
+ "version": "4.1.14",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.14.tgz",
+ "integrity": "sha512-02c6JhLPJj10L2caH4U0zF8Hji4dOeahmuMl23stk0MU1wfd1OraE7rOloidSF8W5JTHkFdVo/O7uRUJJnUAJg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-linux-x64-musl": {
+ "version": "4.1.14",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.14.tgz",
+ "integrity": "sha512-TNGeLiN1XS66kQhxHG/7wMeQDOoL0S33x9BgmydbrWAb9Qw0KYdd8o1ifx4HOGDWhVmJ+Ul+JQ7lyknQFilO3Q==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-wasm32-wasi": {
+ "version": "4.1.14",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.14.tgz",
+ "integrity": "sha512-uZYAsaW/jS/IYkd6EWPJKW/NlPNSkWkBlaeVBi/WsFQNP05/bzkebUL8FH1pdsqx4f2fH/bWFcUABOM9nfiJkQ==",
+ "bundleDependencies": [
+ "@napi-rs/wasm-runtime",
+ "@emnapi/core",
+ "@emnapi/runtime",
+ "@tybys/wasm-util",
+ "@emnapi/wasi-threads",
+ "tslib"
+ ],
+ "cpu": [
+ "wasm32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "@emnapi/core": "^1.5.0",
+ "@emnapi/runtime": "^1.5.0",
+ "@emnapi/wasi-threads": "^1.1.0",
+ "@napi-rs/wasm-runtime": "^1.0.5",
+ "@tybys/wasm-util": "^0.10.1",
+ "tslib": "^2.4.0"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-win32-arm64-msvc": {
+ "version": "4.1.14",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.14.tgz",
+ "integrity": "sha512-Az0RnnkcvRqsuoLH2Z4n3JfAef0wElgzHD5Aky/e+0tBUxUhIeIqFBTMNQvmMRSP15fWwmvjBxZ3Q8RhsDnxAA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-win32-x64-msvc": {
+ "version": "4.1.14",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.14.tgz",
+ "integrity": "sha512-ttblVGHgf68kEE4om1n/n44I0yGPkCPbLsqzjvybhpwa6mKKtgFfAzy6btc3HRmuW7nHe0OOrSeNP9sQmmH9XA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@tailwindcss/postcss": {
+ "version": "4.1.14",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/postcss/-/postcss-4.1.14.tgz",
+ "integrity": "sha512-BdMjIxy7HUNThK87C7BC8I1rE8BVUsfNQSI5siQ4JK3iIa3w0XyVvVL9SXLWO//CtYTcp1v7zci0fYwJOjB+Zg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@alloc/quick-lru": "^5.2.0",
+ "@tailwindcss/node": "4.1.14",
+ "@tailwindcss/oxide": "4.1.14",
+ "postcss": "^8.4.41",
+ "tailwindcss": "4.1.14"
+ }
+ },
+ "node_modules/@types/node": {
+ "version": "20.19.20",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.20.tgz",
+ "integrity": "sha512-2Q7WS25j4pS1cS8yw3d6buNCVJukOTeQ39bAnwR6sOJbaxvyCGebzTMypDFN82CxBLnl+lSWVdCCWbRY6y9yZQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "undici-types": "~6.21.0"
+ }
+ },
+ "node_modules/@types/react": {
+ "version": "19.2.2",
+ "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.2.tgz",
+ "integrity": "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "csstype": "^3.0.2"
+ }
+ },
+ "node_modules/@types/react-dom": {
+ "version": "19.2.1",
+ "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.1.tgz",
+ "integrity": "sha512-/EEvYBdT3BflCWvTMO7YkYBHVE9Ci6XdqZciZANQgKpaiDRGOLIlRo91jbTNRQjgPFWVaRxcYc0luVNFitz57A==",
+ "dev": true,
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "^19.2.0"
+ }
+ },
+ "node_modules/caniuse-lite": {
+ "version": "1.0.30001749",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001749.tgz",
+ "integrity": "sha512-0rw2fJOmLfnzCRbkm8EyHL8SvI2Apu5UbnQuTsJ0ClgrH8hcwFooJ1s5R0EP8o8aVrFu8++ae29Kt9/gZAZp/Q==",
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "CC-BY-4.0"
+ },
+ "node_modules/chownr": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz",
+ "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==",
+ "dev": true,
+ "license": "BlueOak-1.0.0",
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/client-only": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz",
+ "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==",
+ "license": "MIT"
+ },
+ "node_modules/csstype": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
+ "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/detect-libc": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
+ "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
+ "devOptional": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/enhanced-resolve": {
+ "version": "5.18.3",
+ "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.3.tgz",
+ "integrity": "sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "graceful-fs": "^4.2.4",
+ "tapable": "^2.2.0"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ }
+ },
+ "node_modules/framer-motion": {
+ "version": "12.23.24",
+ "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.23.24.tgz",
+ "integrity": "sha512-HMi5HRoRCTou+3fb3h9oTLyJGBxHfW+HnNE25tAXOvVx/IvwMHK0cx7IR4a2ZU6sh3IX1Z+4ts32PcYBOqka8w==",
+ "license": "MIT",
+ "dependencies": {
+ "motion-dom": "^12.23.23",
+ "motion-utils": "^12.23.6",
+ "tslib": "^2.4.0"
+ },
+ "peerDependencies": {
+ "@emotion/is-prop-valid": "*",
+ "react": "^18.0.0 || ^19.0.0",
+ "react-dom": "^18.0.0 || ^19.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@emotion/is-prop-valid": {
+ "optional": true
+ },
+ "react": {
+ "optional": true
+ },
+ "react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/graceful-fs": {
+ "version": "4.2.11",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
+ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/jiti": {
+ "version": "2.6.1",
+ "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz",
+ "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "jiti": "lib/jiti-cli.mjs"
+ }
+ },
+ "node_modules/lightningcss": {
+ "version": "1.30.1",
+ "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.1.tgz",
+ "integrity": "sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==",
+ "dev": true,
+ "license": "MPL-2.0",
+ "dependencies": {
+ "detect-libc": "^2.0.3"
+ },
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ },
+ "optionalDependencies": {
+ "lightningcss-darwin-arm64": "1.30.1",
+ "lightningcss-darwin-x64": "1.30.1",
+ "lightningcss-freebsd-x64": "1.30.1",
+ "lightningcss-linux-arm-gnueabihf": "1.30.1",
+ "lightningcss-linux-arm64-gnu": "1.30.1",
+ "lightningcss-linux-arm64-musl": "1.30.1",
+ "lightningcss-linux-x64-gnu": "1.30.1",
+ "lightningcss-linux-x64-musl": "1.30.1",
+ "lightningcss-win32-arm64-msvc": "1.30.1",
+ "lightningcss-win32-x64-msvc": "1.30.1"
+ }
+ },
+ "node_modules/lightningcss-darwin-arm64": {
+ "version": "1.30.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.1.tgz",
+ "integrity": "sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-darwin-x64": {
+ "version": "1.30.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.1.tgz",
+ "integrity": "sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-freebsd-x64": {
+ "version": "1.30.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.1.tgz",
+ "integrity": "sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-arm-gnueabihf": {
+ "version": "1.30.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.1.tgz",
+ "integrity": "sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-arm64-gnu": {
+ "version": "1.30.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.1.tgz",
+ "integrity": "sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-arm64-musl": {
+ "version": "1.30.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.1.tgz",
+ "integrity": "sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-x64-gnu": {
+ "version": "1.30.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.1.tgz",
+ "integrity": "sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-x64-musl": {
+ "version": "1.30.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.1.tgz",
+ "integrity": "sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-win32-arm64-msvc": {
+ "version": "1.30.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.1.tgz",
+ "integrity": "sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-win32-x64-msvc": {
+ "version": "1.30.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.1.tgz",
+ "integrity": "sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/magic-string": {
+ "version": "0.30.19",
+ "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.19.tgz",
+ "integrity": "sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/sourcemap-codec": "^1.5.5"
+ }
+ },
+ "node_modules/minipass": {
+ "version": "7.1.2",
+ "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
+ "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": ">=16 || 14 >=14.17"
+ }
+ },
+ "node_modules/minizlib": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.1.0.tgz",
+ "integrity": "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "minipass": "^7.1.2"
+ },
+ "engines": {
+ "node": ">= 18"
+ }
+ },
+ "node_modules/motion": {
+ "version": "12.23.24",
+ "resolved": "https://registry.npmjs.org/motion/-/motion-12.23.24.tgz",
+ "integrity": "sha512-Rc5E7oe2YZ72N//S3QXGzbnXgqNrTESv8KKxABR20q2FLch9gHLo0JLyYo2hZ238bZ9Gx6cWhj9VO0IgwbMjCw==",
+ "license": "MIT",
+ "dependencies": {
+ "framer-motion": "^12.23.24",
+ "tslib": "^2.4.0"
+ },
+ "peerDependencies": {
+ "@emotion/is-prop-valid": "*",
+ "react": "^18.0.0 || ^19.0.0",
+ "react-dom": "^18.0.0 || ^19.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@emotion/is-prop-valid": {
+ "optional": true
+ },
+ "react": {
+ "optional": true
+ },
+ "react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/motion-dom": {
+ "version": "12.23.23",
+ "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.23.23.tgz",
+ "integrity": "sha512-n5yolOs0TQQBRUFImrRfs/+6X4p3Q4n1dUEqt/H58Vx7OW6RF+foWEgmTVDhIWJIMXOuNNL0apKH2S16en9eiA==",
+ "license": "MIT",
+ "dependencies": {
+ "motion-utils": "^12.23.6"
+ }
+ },
+ "node_modules/motion-utils": {
+ "version": "12.23.6",
+ "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-12.23.6.tgz",
+ "integrity": "sha512-eAWoPgr4eFEOFfg2WjIsMoqJTW6Z8MTUCgn/GZ3VRpClWBdnbjryiA3ZSNLyxCTmCQx4RmYX6jX1iWHbenUPNQ==",
+ "license": "MIT"
+ },
+ "node_modules/nanoid": {
+ "version": "3.3.11",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
+ "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "bin": {
+ "nanoid": "bin/nanoid.cjs"
+ },
+ "engines": {
+ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
+ }
+ },
+ "node_modules/next": {
+ "version": "15.5.4",
+ "resolved": "https://registry.npmjs.org/next/-/next-15.5.4.tgz",
+ "integrity": "sha512-xH4Yjhb82sFYQfY3vbkJfgSDgXvBB6a8xPs9i35k6oZJRoQRihZH+4s9Yo2qsWpzBmZ3lPXaJ2KPXLfkvW4LnA==",
+ "license": "MIT",
+ "dependencies": {
+ "@next/env": "15.5.4",
+ "@swc/helpers": "0.5.15",
+ "caniuse-lite": "^1.0.30001579",
+ "postcss": "8.4.31",
+ "styled-jsx": "5.1.6"
+ },
+ "bin": {
+ "next": "dist/bin/next"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^19.8.0 || >= 20.0.0"
+ },
+ "optionalDependencies": {
+ "@next/swc-darwin-arm64": "15.5.4",
+ "@next/swc-darwin-x64": "15.5.4",
+ "@next/swc-linux-arm64-gnu": "15.5.4",
+ "@next/swc-linux-arm64-musl": "15.5.4",
+ "@next/swc-linux-x64-gnu": "15.5.4",
+ "@next/swc-linux-x64-musl": "15.5.4",
+ "@next/swc-win32-arm64-msvc": "15.5.4",
+ "@next/swc-win32-x64-msvc": "15.5.4",
+ "sharp": "^0.34.3"
+ },
+ "peerDependencies": {
+ "@opentelemetry/api": "^1.1.0",
+ "@playwright/test": "^1.51.1",
+ "babel-plugin-react-compiler": "*",
+ "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0",
+ "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0",
+ "sass": "^1.3.0"
+ },
+ "peerDependenciesMeta": {
+ "@opentelemetry/api": {
+ "optional": true
+ },
+ "@playwright/test": {
+ "optional": true
+ },
+ "babel-plugin-react-compiler": {
+ "optional": true
+ },
+ "sass": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/next/node_modules/postcss": {
+ "version": "8.4.31",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz",
+ "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==",
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/postcss"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "nanoid": "^3.3.6",
+ "picocolors": "^1.0.0",
+ "source-map-js": "^1.0.2"
+ },
+ "engines": {
+ "node": "^10 || ^12 || >=14"
+ }
+ },
+ "node_modules/picocolors": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
+ "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
+ "license": "ISC"
+ },
+ "node_modules/postcss": {
+ "version": "8.5.6",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz",
+ "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/postcss"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "nanoid": "^3.3.11",
+ "picocolors": "^1.1.1",
+ "source-map-js": "^1.2.1"
+ },
+ "engines": {
+ "node": "^10 || ^12 || >=14"
+ }
+ },
+ "node_modules/react": {
+ "version": "19.1.0",
+ "resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz",
+ "integrity": "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/react-dom": {
+ "version": "19.1.0",
+ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz",
+ "integrity": "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==",
+ "license": "MIT",
+ "dependencies": {
+ "scheduler": "^0.26.0"
+ },
+ "peerDependencies": {
+ "react": "^19.1.0"
+ }
+ },
+ "node_modules/scheduler": {
+ "version": "0.26.0",
+ "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz",
+ "integrity": "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==",
+ "license": "MIT"
+ },
+ "node_modules/semver": {
+ "version": "7.7.3",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
+ "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
+ "license": "ISC",
+ "optional": true,
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/sharp": {
+ "version": "0.34.4",
+ "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.4.tgz",
+ "integrity": "sha512-FUH39xp3SBPnxWvd5iib1X8XY7J0K0X7d93sie9CJg2PO8/7gmg89Nve6OjItK53/MlAushNNxteBYfM6DEuoA==",
+ "hasInstallScript": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "dependencies": {
+ "@img/colour": "^1.0.0",
+ "detect-libc": "^2.1.0",
+ "semver": "^7.7.2"
+ },
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-darwin-arm64": "0.34.4",
+ "@img/sharp-darwin-x64": "0.34.4",
+ "@img/sharp-libvips-darwin-arm64": "1.2.3",
+ "@img/sharp-libvips-darwin-x64": "1.2.3",
+ "@img/sharp-libvips-linux-arm": "1.2.3",
+ "@img/sharp-libvips-linux-arm64": "1.2.3",
+ "@img/sharp-libvips-linux-ppc64": "1.2.3",
+ "@img/sharp-libvips-linux-s390x": "1.2.3",
+ "@img/sharp-libvips-linux-x64": "1.2.3",
+ "@img/sharp-libvips-linuxmusl-arm64": "1.2.3",
+ "@img/sharp-libvips-linuxmusl-x64": "1.2.3",
+ "@img/sharp-linux-arm": "0.34.4",
+ "@img/sharp-linux-arm64": "0.34.4",
+ "@img/sharp-linux-ppc64": "0.34.4",
+ "@img/sharp-linux-s390x": "0.34.4",
+ "@img/sharp-linux-x64": "0.34.4",
+ "@img/sharp-linuxmusl-arm64": "0.34.4",
+ "@img/sharp-linuxmusl-x64": "0.34.4",
+ "@img/sharp-wasm32": "0.34.4",
+ "@img/sharp-win32-arm64": "0.34.4",
+ "@img/sharp-win32-ia32": "0.34.4",
+ "@img/sharp-win32-x64": "0.34.4"
+ }
+ },
+ "node_modules/source-map-js": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
+ "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/styled-jsx": {
+ "version": "5.1.6",
+ "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.6.tgz",
+ "integrity": "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==",
+ "license": "MIT",
+ "dependencies": {
+ "client-only": "0.0.1"
+ },
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "peerDependencies": {
+ "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0"
+ },
+ "peerDependenciesMeta": {
+ "@babel/core": {
+ "optional": true
+ },
+ "babel-plugin-macros": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/tailwindcss": {
+ "version": "4.1.14",
+ "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.14.tgz",
+ "integrity": "sha512-b7pCxjGO98LnxVkKjaZSDeNuljC4ueKUddjENJOADtubtdo8llTaJy7HwBMeLNSSo2N5QIAgklslK1+Ir8r6CA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/tapable": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz",
+ "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/webpack"
+ }
+ },
+ "node_modules/tar": {
+ "version": "7.5.1",
+ "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.1.tgz",
+ "integrity": "sha512-nlGpxf+hv0v7GkWBK2V9spgactGOp0qvfWRxUMjqHyzrt3SgwE48DIv/FhqPHJYLHpgW1opq3nERbz5Anq7n1g==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "@isaacs/fs-minipass": "^4.0.0",
+ "chownr": "^3.0.0",
+ "minipass": "^7.1.2",
+ "minizlib": "^3.1.0",
+ "yallist": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/tslib": {
+ "version": "2.8.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
+ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
+ "license": "0BSD"
+ },
+ "node_modules/typescript": {
+ "version": "5.9.3",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
+ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=14.17"
+ }
+ },
+ "node_modules/undici-types": {
+ "version": "6.21.0",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
+ "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/use-breakpoint": {
+ "version": "4.0.10",
+ "resolved": "https://registry.npmjs.org/use-breakpoint/-/use-breakpoint-4.0.10.tgz",
+ "integrity": "sha512-rnUpZwCQCTtexbpM8S5aiJrfIx6NTvt0WwATiH4hCBN6gQNgkYPFoFt6g/3pAuyqU9D9tLKwXfsVqEWMBnwo6A==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react": ">=18",
+ "react-dom": ">=18"
+ }
+ },
+ "node_modules/yallist": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz",
+ "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==",
+ "dev": true,
+ "license": "BlueOak-1.0.0",
+ "engines": {
+ "node": ">=18"
+ }
+ }
+ }
+}
diff --git a/package.json b/package.json
index 7ed5925c..d33b787c 100644
--- a/package.json
+++ b/package.json
@@ -1,49 +1,28 @@
{
"name": "maxdlr-portfolio",
+ "version": "0.1.0",
"private": true,
- "version": "0.0.0",
- "type": "module",
"scripts": {
- "dev": "vite",
- "build": "vue-tsc -b && vite build",
- "preview": "vite preview"
+ "dev": "next dev --turbopack",
+ "build": "next build --turbopack",
+ "start": "next start",
+ "lint": "biome check",
+ "format": "biome format --write"
},
"dependencies": {
- "@octokit/openapi-types": "^22.2.0",
- "@octokit/types": "^13.6.1",
- "@types/lodash": "^4.17.13",
- "@types/node": "^24.0.3",
- "@unhead/vue": "^1.11.18",
- "@vueuse/components": "^13.3.0",
- "@vueuse/core": "^11.3.0",
- "bootstrap-icons-vue": "^1.11.3",
- "franken-ui": "^1.1.0",
- "lodash": "^4.17.21",
- "marked": "^15.0.6",
- "marked-shiki": "^1.2.0",
- "octokit": "^4.1.2",
- "postcss-combine-duplicated-selectors": "^10.0.3",
- "postcss-sort-media-queries": "^5.2.0",
- "undici": "^7.3.0",
- "vue": "^3.5.10",
- "vue-i18n": "10.0.5",
- "vue-router": "^4.5.0"
+ "motion": "^12.23.24",
+ "next": "15.5.4",
+ "react": "19.1.0",
+ "react-dom": "19.1.0",
+ "use-breakpoint": "^4.0.10"
},
"devDependencies": {
- "@eslint/js": "^9.14.0",
- "@vitejs/plugin-vue": "^5.1.4",
- "autoprefixer": "^10.4.20",
- "eslint": "^9.14.0",
- "eslint-plugin-vue": "^9.31.0",
- "globals": "^15.12.0",
- "postcss": "^8.5.1",
- "prettier": "3.3.3",
- "sass-embedded": "^1.83.4",
- "shiki": "^2.3.2",
- "tailwindcss": "^3.4.13",
- "typescript": "^5.5.3",
- "typescript-eslint": "^8.14.0",
- "vite": "^5.4.8",
- "vue-tsc": "^2.1.6"
+ "@biomejs/biome": "2.2.0",
+ "@tailwindcss/postcss": "^4",
+ "@types/node": "^20",
+ "@types/react": "^19",
+ "@types/react-dom": "^19",
+ "tailwindcss": "^4",
+ "typescript": "^5"
}
}
diff --git a/postcss.config.js b/postcss.config.js
deleted file mode 100644
index bc43c55b..00000000
--- a/postcss.config.js
+++ /dev/null
@@ -1,10 +0,0 @@
-export default {
- plugins: {
- tailwindcss: {},
- autoprefixer: {},
- "franken-ui/postcss/sort-media-queries": { sort: "mobile-first" },
- "franken-ui/postcss/combine-duplicated-selectors": {
- removeDuplicatedProperties: true,
- },
- },
-};
diff --git a/postcss.config.mjs b/postcss.config.mjs
new file mode 100644
index 00000000..c7bcb4b1
--- /dev/null
+++ b/postcss.config.mjs
@@ -0,0 +1,5 @@
+const config = {
+ plugins: ["@tailwindcss/postcss"],
+};
+
+export default config;
diff --git a/public/file.svg b/public/file.svg
new file mode 100644
index 00000000..004145cd
--- /dev/null
+++ b/public/file.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/public/globe.svg b/public/globe.svg
new file mode 100644
index 00000000..567f17b0
--- /dev/null
+++ b/public/globe.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/public/next.svg b/public/next.svg
new file mode 100644
index 00000000..5174b28c
--- /dev/null
+++ b/public/next.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/public/vercel.svg b/public/vercel.svg
new file mode 100644
index 00000000..77053960
--- /dev/null
+++ b/public/vercel.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/public/window.svg b/public/window.svg
new file mode 100644
index 00000000..b2b2a44f
--- /dev/null
+++ b/public/window.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/App.vue b/src/App.vue
deleted file mode 100644
index d4562241..00000000
--- a/src/App.vue
+++ /dev/null
@@ -1,27 +0,0 @@
-
-
-
-
-
-
-
-
diff --git a/src/app/api/photos/route.ts b/src/app/api/photos/route.ts
new file mode 100644
index 00000000..85145006
--- /dev/null
+++ b/src/app/api/photos/route.ts
@@ -0,0 +1,31 @@
+import { readdir } from "fs/promises";
+import path from "path";
+
+export interface Photo {
+ name: string;
+ path: string;
+ category: string;
+ alt: string;
+}
+
+export async function GET() {
+ const dir = path.join(process.cwd(), "public/photo-collections");
+ const files = await readdir(dir);
+
+ const photoCollection: Photo[] = [];
+ const regex = /^([a-zA-Z0-9_-]+)-\d+\.\w+$/;
+
+ files.forEach((file: string) => {
+ const match = file.match(regex);
+ if (match) {
+ photoCollection.push({
+ name: file,
+ path: "/photo-collections/" + file,
+ category: match[1],
+ alt: match[1],
+ });
+ }
+ });
+
+ return Response.json(photoCollection);
+}
diff --git a/src/app/dev/page.tsx b/src/app/dev/page.tsx
new file mode 100644
index 00000000..81615eaa
--- /dev/null
+++ b/src/app/dev/page.tsx
@@ -0,0 +1,4 @@
+const Dev = () => {
+ return "dev";
+};
+export default Dev;
diff --git a/src/app/favicon.ico b/src/app/favicon.ico
new file mode 100644
index 00000000..718d6fea
Binary files /dev/null and b/src/app/favicon.ico differ
diff --git a/src/app/globals.css b/src/app/globals.css
new file mode 100644
index 00000000..a2dc41ec
--- /dev/null
+++ b/src/app/globals.css
@@ -0,0 +1,26 @@
+@import "tailwindcss";
+
+:root {
+ --background: #ffffff;
+ --foreground: #171717;
+}
+
+@theme inline {
+ --color-background: var(--background);
+ --color-foreground: var(--foreground);
+ --font-sans: var(--font-geist-sans);
+ --font-mono: var(--font-geist-mono);
+}
+
+@media (prefers-color-scheme: dark) {
+ :root {
+ --background: #0a0a0a;
+ --foreground: #ededed;
+ }
+}
+
+body {
+ background: var(--background);
+ color: var(--foreground);
+ font-family: Arial, Helvetica, sans-serif;
+}
diff --git a/src/app/layout.tsx b/src/app/layout.tsx
new file mode 100644
index 00000000..1709b558
--- /dev/null
+++ b/src/app/layout.tsx
@@ -0,0 +1,25 @@
+"use client";
+import Tabs from "@/components/tabs/Tabs";
+import { Anton } from "next/font/google";
+import { PhotoProvider } from "../components/PhotoGallery/PhotosContext";
+import "./globals.css";
+import { TabsProvider } from "@/components/tabs/TabsContext";
+
+const geistSans = Anton({ weight: "400" });
+
+export default function RootLayout({
+ children,
+}: Readonly<{
+ children: React.ReactNode;
+}>) {
+ return (
+
+
+
+
+ {children}
+
+
+
+ );
+}
diff --git a/src/app/motion/[category]/page.tsx b/src/app/motion/[category]/page.tsx
new file mode 100644
index 00000000..184cf130
--- /dev/null
+++ b/src/app/motion/[category]/page.tsx
@@ -0,0 +1,5 @@
+const MotionByCategory = () => {
+ return "motion";
+};
+
+export default MotionByCategory;
diff --git a/src/app/motion/layout.tsx b/src/app/motion/layout.tsx
new file mode 100644
index 00000000..01a7523f
--- /dev/null
+++ b/src/app/motion/layout.tsx
@@ -0,0 +1,9 @@
+"use client";
+
+export default function MotionLayout({
+ children,
+}: Readonly<{
+ children: React.ReactNode;
+}>) {
+ return {children}
;
+}
diff --git a/src/app/motion/page.tsx b/src/app/motion/page.tsx
new file mode 100644
index 00000000..797f9e70
--- /dev/null
+++ b/src/app/motion/page.tsx
@@ -0,0 +1,5 @@
+const Motion = () => {
+ return "motion";
+};
+
+export default Motion;
diff --git a/src/app/page.tsx b/src/app/page.tsx
new file mode 100644
index 00000000..44b29333
--- /dev/null
+++ b/src/app/page.tsx
@@ -0,0 +1,7 @@
+"use client";
+
+const Home = () => {
+ return "home";
+};
+
+export default Home;
diff --git a/src/app/photos/[category]/page.tsx b/src/app/photos/[category]/page.tsx
new file mode 100644
index 00000000..34611a83
--- /dev/null
+++ b/src/app/photos/[category]/page.tsx
@@ -0,0 +1,21 @@
+"use client";
+import { Photo } from "@/app/api/photos/route";
+import PhotoGallery from "@/components/PhotoGallery/PhotoGallery";
+import { useParams } from "next/navigation";
+import { useEffect } from "react";
+import { usePhotos } from "../../../components/PhotoGallery/PhotosContext";
+
+const PhotosByCategory = () => {
+ const { setCategory, photos, loading, setShownPhoto } = usePhotos();
+ const { category } = useParams();
+ useEffect(() => setCategory(category as string));
+
+ return (
+ photo.category === category)}
+ loading={loading}
+ />
+ );
+};
+
+export default PhotosByCategory;
diff --git a/src/app/photos/layout.tsx b/src/app/photos/layout.tsx
new file mode 100644
index 00000000..24b2b2de
--- /dev/null
+++ b/src/app/photos/layout.tsx
@@ -0,0 +1,29 @@
+"use client";
+import Button from "@/components/Button/Button";
+import { upperFirst } from "@/services/helpers";
+import { usePhotos } from "../../components/PhotoGallery/PhotosContext";
+
+export default function PhotosLayout({
+ children,
+}: Readonly<{
+ children: React.ReactNode;
+}>) {
+ const { categories, category, loading } = usePhotos();
+ return (
+
+
+ {!loading &&
+ categories.map((cat: string) => (
+
+
+
+ ))}
+
+ {children}
+
+ );
+}
diff --git a/src/app/photos/page.tsx b/src/app/photos/page.tsx
new file mode 100644
index 00000000..9d066f70
--- /dev/null
+++ b/src/app/photos/page.tsx
@@ -0,0 +1,12 @@
+"use client";
+import PhotoGallery from "@/components/PhotoGallery/PhotoGallery";
+import { useEffect } from "react";
+import { usePhotos } from "../../components/PhotoGallery/PhotosContext";
+
+const PhotosDefault = () => {
+ const { setCategory, photos, loading } = usePhotos();
+ useEffect(() => setCategory("all"));
+ return ;
+};
+
+export default PhotosDefault;
diff --git a/src/components/Button/Button.tsx b/src/components/Button/Button.tsx
new file mode 100644
index 00000000..19bb5bd3
--- /dev/null
+++ b/src/components/Button/Button.tsx
@@ -0,0 +1,88 @@
+"use client";
+import { motion } from "motion/react";
+import Link from "next/link";
+import { FC, ReactElement } from "react";
+
+interface ButtonProps {
+ label?: string;
+ url?: string;
+ className?: string;
+ onClick?: () => void;
+ Icon?: ReactElement;
+ target?: string;
+ border?: boolean;
+ rotating?: boolean;
+}
+
+const Button: FC = ({
+ label = "",
+ url = "",
+ className = "",
+ onClick = () => {},
+ Icon,
+ target,
+ border = false,
+ rotating = false,
+}) => {
+ const content = (
+
+ {Icon && Icon}
+ {label && {label}}
+
+ );
+
+ const classes = `${className} inline-flex items-center cursor-pointer ${border && "border-1 p-1 rounded-md"}`;
+
+ const Element = () => {
+ if (url) {
+ return (
+
+ {content}
+
+ );
+ }
+ return (
+
+ );
+ };
+
+ const RotatingButton = () => (
+
+
+
+ );
+
+ return rotating ? : ;
+};
+
+export default Button;
diff --git a/src/components/Dev/Dev.tsx b/src/components/Dev/Dev.tsx
new file mode 100644
index 00000000..85fd5d12
--- /dev/null
+++ b/src/components/Dev/Dev.tsx
@@ -0,0 +1,5 @@
+const Dev = () => {
+ return "dev";
+};
+
+export default Dev;
diff --git a/src/components/Landing/Landing.tsx b/src/components/Landing/Landing.tsx
new file mode 100644
index 00000000..5305b724
--- /dev/null
+++ b/src/components/Landing/Landing.tsx
@@ -0,0 +1,11 @@
+import { Metadata } from "next";
+
+export const metadata: Metadata = {
+ title: "Create Next App",
+ description: "Generated by create next app",
+};
+const Landing = () => {
+ return "landing";
+};
+
+export default Landing;
diff --git a/src/components/Motion/Motion.tsx b/src/components/Motion/Motion.tsx
new file mode 100644
index 00000000..797f9e70
--- /dev/null
+++ b/src/components/Motion/Motion.tsx
@@ -0,0 +1,5 @@
+const Motion = () => {
+ return "motion";
+};
+
+export default Motion;
diff --git a/src/components/PhotoGallery/PhotoGallery.tsx b/src/components/PhotoGallery/PhotoGallery.tsx
new file mode 100644
index 00000000..a8cc7f1c
--- /dev/null
+++ b/src/components/PhotoGallery/PhotoGallery.tsx
@@ -0,0 +1,108 @@
+"use client";
+
+import { Photo } from "@/app/api/photos/route";
+import { AnimatePresence, motion } from "framer-motion";
+import Image from "next/image";
+import { ReactElement } from "react";
+import useBreakpoint from "use-breakpoint";
+import Loading from "../loading/Loading";
+import { usePhotos } from "./PhotosContext";
+import PhotoShow from "./PhotoShow";
+
+export interface PhotoProps {
+ photos: Photo[];
+ loading: boolean;
+}
+
+const PhotoGallery = ({ photos, loading }: PhotoProps) => {
+ const { shownPhoto, setShownPhoto } = usePhotos();
+
+ const BREAKPOINTS = {
+ base: 0,
+ sm: 640,
+ md: 768,
+ lg: 1024,
+ xl: 1280,
+ "2xl": 1536,
+ };
+ const { breakpoint } = useBreakpoint(BREAKPOINTS);
+
+ const photoElements = photos.map(
+ (photo): ReactElement => (
+
+ setShownPhoto(photo)}
+ />
+
+ ),
+ );
+
+ const masonryGrid = (colsCount: number) => {
+ if (!photoElements.length) return null;
+
+ const cols: ReactElement[][] = Array.from({ length: colsCount }, () => []);
+ photoElements.forEach((photoEl, i) => {
+ cols[i % colsCount].push(photoEl);
+ });
+
+ return (
+
+
+ {cols.map((col, i) => (
+
+ {col}
+
+ ))}
+
+
+ );
+ };
+
+ const cols =
+ breakpoint === "xl" || breakpoint === "2xl"
+ ? 3
+ : breakpoint === "lg" || breakpoint === "md"
+ ? 2
+ : 1;
+
+ return loading ? (
+
+ ) : (
+ <>
+
+ {masonryGrid(cols || 1)}
+ >
+ );
+};
+
+export default PhotoGallery;
diff --git a/src/components/PhotoGallery/PhotoShow.tsx b/src/components/PhotoGallery/PhotoShow.tsx
new file mode 100644
index 00000000..eba85b4b
--- /dev/null
+++ b/src/components/PhotoGallery/PhotoShow.tsx
@@ -0,0 +1,86 @@
+import { Photo } from "@/app/api/photos/route";
+import { AnimatePresence, motion } from "framer-motion";
+import Image from "next/image";
+import { usePhotos } from "./PhotosContext";
+import { useEffect } from "react";
+
+interface PhotoShowProps {
+ photo?: Photo;
+}
+
+const PhotoShow = ({ photo }: PhotoShowProps) => {
+ const { setShownPhoto } = usePhotos();
+
+ const handleClickCapture = (event: any) => {
+ const isClickOutside = !!event.target.attributes["data-click-out"];
+ if (isClickOutside) {
+ setShownPhoto(undefined);
+ }
+ };
+
+ useEffect(() => {
+ const handleKeyDown = (event: KeyboardEvent) => {
+ if (event.key === "Escape") {
+ setShownPhoto(undefined);
+ }
+ };
+
+ if (photo) {
+ window.addEventListener("keydown", handleKeyDown);
+ }
+
+ return () => {
+ window.removeEventListener("keydown", handleKeyDown);
+ };
+ }, [photo, setShownPhoto]);
+
+ return (
+ photo && (
+
+ )
+ );
+};
+
+export default PhotoShow;
diff --git a/src/components/PhotoGallery/PhotosContext.tsx b/src/components/PhotoGallery/PhotosContext.tsx
new file mode 100644
index 00000000..348463f7
--- /dev/null
+++ b/src/components/PhotoGallery/PhotosContext.tsx
@@ -0,0 +1,120 @@
+"use client";
+import {
+ createContext,
+ useContext,
+ useEffect,
+ useState,
+ ReactNode,
+ Dispatch,
+ SetStateAction,
+} from "react";
+import { Photo } from "@/app/api/photos/route";
+import { UrlParams } from "@/services/urlParams";
+
+interface PhotoContextType {
+ photos: Photo[];
+ loading: boolean;
+ categories: string[];
+ category: string;
+ setCategory: Dispatch>;
+ shownPhoto?: Photo;
+ setShownPhoto: Dispatch>;
+ refetch: () => Promise;
+}
+
+const PhotoContext = createContext(undefined);
+
+export const PhotoProvider = ({ children }: { children: ReactNode }) => {
+ const [photos, setPhotos] = useState([]);
+ const [shownPhoto, setShownPhoto] = useState();
+ const [loading, setLoading] = useState(true);
+ const [category, setCategory] = useState("all");
+ const [isInitialized, setIsInitialized] = useState(false);
+
+ const fetchPhotos = async () => {
+ setLoading(true);
+ try {
+ const res = await fetch("/api/photos");
+ const data = await res.json();
+ setPhotos(data);
+ } catch (error) {
+ console.error("Error fetching photos:", error);
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ useEffect(() => {
+ if (photos.length > 0 && !isInitialized) {
+ const photoParam = UrlParams.get("p");
+ if (photoParam) {
+ const photo = photos.find((p) => p.name === photoParam);
+ if (photo) {
+ setShownPhoto(photo);
+ }
+ }
+ setIsInitialized(true);
+ }
+ }, [photos, isInitialized]);
+
+ useEffect(() => {
+ if (!isInitialized) return;
+
+ if (shownPhoto) {
+ UrlParams.set("p", shownPhoto.name);
+ } else {
+ UrlParams.remove("p");
+ }
+ }, [shownPhoto, isInitialized]);
+
+ useEffect(() => {
+ const cleanup = UrlParams.onChange(() => {
+ const photoParam = UrlParams.get("p");
+ if (photoParam && photos.length > 0) {
+ const photo = photos.find((p) => p.name === photoParam);
+ if (photo) {
+ setShownPhoto(photo);
+ } else {
+ setShownPhoto(undefined);
+ }
+ } else {
+ setShownPhoto(undefined);
+ }
+ });
+ return cleanup;
+ }, [photos]);
+
+ useEffect(() => {
+ setTimeout(() => fetchPhotos(), 1000);
+ }, []);
+
+ const categories = Array.from([
+ "all",
+ ...new Set(photos.map((p) => p.category)),
+ ]);
+
+ return (
+
+ {children}
+
+ );
+};
+
+export const usePhotos = () => {
+ const context = useContext(PhotoContext);
+ if (!context) {
+ throw new Error("usePhotos must be used within a PhotoProvider");
+ }
+ return context;
+};
diff --git a/src/components/atoms/ArticleCard.vue b/src/components/atoms/ArticleCard.vue
deleted file mode 100644
index b92ffb01..00000000
--- a/src/components/atoms/ArticleCard.vue
+++ /dev/null
@@ -1,51 +0,0 @@
-
-
-
-
-
-
-
{{ blogArticle.title }}
-
- {{ blogArticle.publishedAt }}
- - {{ viewCount }}
-
-
-
{{ $t("minute-read", { minutes: readingTime }) }}
-
-
-
diff --git a/src/components/atoms/Button.vue b/src/components/atoms/Button.vue
deleted file mode 100644
index 42838a08..00000000
--- a/src/components/atoms/Button.vue
+++ /dev/null
@@ -1,45 +0,0 @@
-
-
-
-
-
diff --git a/src/components/atoms/Layout.vue b/src/components/atoms/Layout.vue
deleted file mode 100644
index 39482e06..00000000
--- a/src/components/atoms/Layout.vue
+++ /dev/null
@@ -1,99 +0,0 @@
-
-
-
-
-
-
-
-
-
-
diff --git a/src/components/atoms/LightBox.vue b/src/components/atoms/LightBox.vue
deleted file mode 100644
index 4f1cb4cf..00000000
--- a/src/components/atoms/LightBox.vue
+++ /dev/null
@@ -1,129 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
![]()
-
-
-
-
-
-
-
-
diff --git a/src/components/atoms/Loader.vue b/src/components/atoms/Loader.vue
deleted file mode 100644
index b7fe92e4..00000000
--- a/src/components/atoms/Loader.vue
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
diff --git a/src/components/atoms/transitions/TransitionSlideDown.vue b/src/components/atoms/transitions/TransitionSlideDown.vue
deleted file mode 100644
index bfc9517a..00000000
--- a/src/components/atoms/transitions/TransitionSlideDown.vue
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
-
-
-
diff --git a/src/components/atoms/transitions/TransitionSlideUp.vue b/src/components/atoms/transitions/TransitionSlideUp.vue
deleted file mode 100644
index 9da593d0..00000000
--- a/src/components/atoms/transitions/TransitionSlideUp.vue
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
-
-
-
diff --git a/src/components/gh/ContribSquare.vue b/src/components/gh/ContribSquare.vue
deleted file mode 100644
index 8bff9d29..00000000
--- a/src/components/gh/ContribSquare.vue
+++ /dev/null
@@ -1,42 +0,0 @@
-
-
-
-
- {{ index }}
-
-
diff --git a/src/components/icons/Icons.tsx b/src/components/icons/Icons.tsx
new file mode 100644
index 00000000..893498c6
--- /dev/null
+++ b/src/components/icons/Icons.tsx
@@ -0,0 +1,96 @@
+export const CameraStroke = (
+
+);
+
+export const CameraFill = (
+
+);
+
+export const TagStroke = (
+
+);
+
+export const TriangleStroke = (
+
+);
+
+export const TriangleFill = (
+
+);
+
+export const HouseStroke = (
+
+);
+
+export const HouseFill = (
+
+);
diff --git a/src/components/loading/Loading.tsx b/src/components/loading/Loading.tsx
new file mode 100644
index 00000000..40c8fc9e
--- /dev/null
+++ b/src/components/loading/Loading.tsx
@@ -0,0 +1,4 @@
+const Loading = () => {
+ return "loading";
+};
+export default Loading;
diff --git a/src/components/pages/Blog/Blog.vue b/src/components/pages/Blog/Blog.vue
deleted file mode 100644
index eddbeb4a..00000000
--- a/src/components/pages/Blog/Blog.vue
+++ /dev/null
@@ -1,58 +0,0 @@
-
-
-
-
-
-
-
-
-
- {{ $t("blog-title") }}
-
-
-
- {{ $t("no-articles") }}
-
-
-
-
-
diff --git a/src/components/pages/Blog/BlogArticle.vue b/src/components/pages/Blog/BlogArticle.vue
deleted file mode 100644
index 9e77e555..00000000
--- a/src/components/pages/Blog/BlogArticle.vue
+++ /dev/null
@@ -1,105 +0,0 @@
-
-
-
-
-
-
-
-
-
- Maxime de la Rocheterie
-
- •
- {{ article.publishedAt }}
-
-
- {{ article.title }}
-
-
-
-
diff --git a/src/components/pages/Github/GithubContributions.vue b/src/components/pages/Github/GithubContributions.vue
deleted file mode 100644
index 14bcb8e3..00000000
--- a/src/components/pages/Github/GithubContributions.vue
+++ /dev/null
@@ -1,110 +0,0 @@
-
-
-
-
-
diff --git a/src/components/pages/Home.vue b/src/components/pages/Home.vue
deleted file mode 100644
index 8a559a9f..00000000
--- a/src/components/pages/Home.vue
+++ /dev/null
@@ -1,170 +0,0 @@
-
-
-
-
-
-
-
-
Maxdlr
-
{{ $t("job-title") }}
-
-
-
-
-
- {{ $t("this-is-the-website-of") }}
- {{ data.author.name }}.
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/components/pages/Photo/Photos.vue b/src/components/pages/Photo/Photos.vue
deleted file mode 100644
index fca36bfc..00000000
--- a/src/components/pages/Photo/Photos.vue
+++ /dev/null
@@ -1,235 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
- No photos, apparently
-
-
-
-
-
-
![]()
-
-
-
-
-
-
diff --git a/src/components/tabs/Tabs.tsx b/src/components/tabs/Tabs.tsx
new file mode 100644
index 00000000..5583145f
--- /dev/null
+++ b/src/components/tabs/Tabs.tsx
@@ -0,0 +1,37 @@
+"use client";
+import { usePathname, useRouter } from "next/navigation";
+import Button from "../Button/Button";
+import { useTabs, Tab } from "@/components/tabs/TabsContext";
+import { useEffect } from "react";
+
+const Tabs = () => {
+ const router = useRouter();
+ const { tab, setTab, tabs } = useTabs();
+
+ const handleTabSelect = (newTab: Tab) => {
+ setTab(newTab.label === "Dev" ? tab : newTab);
+ router.push(newTab.uri);
+ };
+
+ const Tab = (tabItem: Tab) => (
+