diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 0000000..dc8e944
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,7 @@
+node_modules
+.next
+.git
+Dockerfile
+docker-compose.yml
+npm-debug.log
+.env
\ No newline at end of file
diff --git a/.env.exemple b/.env.exemple
new file mode 100644
index 0000000..8f0968b
--- /dev/null
+++ b/.env.exemple
@@ -0,0 +1 @@
+WEB_PORT=3000
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index b5a55c4..1e6ce6e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -31,7 +31,7 @@ yarn-error.log*
.pnpm-debug.log*
# env files (can opt-in for committing if needed)
-.env*
+.env
# vercel
.vercel
diff --git a/Dockerfile b/Dockerfile
index 193b26c..34cb63c 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,34 +1,44 @@
-# === Étape 1 : Build ===
+# ====== 1. Dependencies ======
+FROM node:20-alpine AS deps
+
+WORKDIR /app
+
+COPY package.json package-lock.json* ./
+RUN npm ci
+
+
+# ====== 2. Build ======
FROM node:20-alpine AS builder
WORKDIR /app
-# Copier les fichiers de dépendances pour profiter du cache Docker
-COPY package*.json ./
-
-# Installer uniquement ce qu'il faut pour le build
-RUN npm ci
-
-# Copier tout le code
+COPY --from=deps /app/node_modules ./node_modules
COPY . .
-# Build Next.js pour la production
+# Variables build-time
+ENV NEXT_TELEMETRY_DISABLED=1
+
RUN npm run build
-# === Étape 2 : Runner léger ===
+
+# ====== 3. Runner (prod minimal) ======
FROM node:20-alpine AS runner
WORKDIR /app
-# Copier uniquement ce qui est nécessaire pour la prod
-COPY --from=builder /app/package*.json ./
-COPY --from=builder /app/node_modules ./node_modules
-COPY --from=builder /app/.next ./.next
-COPY --from=builder /app/public ./public
-
-# Mode production
ENV NODE_ENV=production
+ENV NEXT_TELEMETRY_DISABLED=1
+
+# user non-root (bonne pratique)
+RUN addgroup -S nextjs && adduser -S nextjs -G nextjs
+
+# Copy standalone output
+COPY --from=builder /app/public ./public
+COPY --from=builder /app/.next/standalone ./
+COPY --from=builder /app/.next/static ./.next/static
+
+USER nextjs
+
EXPOSE 3000
-# Lancer le serveur Next.js
-CMD ["npm", "start"]
\ No newline at end of file
+CMD ["node", "server.js"]
\ No newline at end of file
diff --git a/app/components/Footer.tsx b/app/components/Footer.tsx
index 3410c98..98f5210 100644
--- a/app/components/Footer.tsx
+++ b/app/components/Footer.tsx
@@ -1,4 +1,4 @@
-import { Github, Mail, Globe, Heart } from "lucide-react";
+import { Github, Mail, Globe, Heart, Presentation } from "lucide-react";
export default function Footer() {
return (
@@ -42,16 +42,16 @@ export default function Footer() {
-
2
+
1
- Championnats du monde
+ Champion de France
9e
- Mondial (×2)
+ Championnat du monde (×2)
diff --git a/app/components/ThemeProvider.tsx b/app/components/ThemeProvider.tsx
index 81246dd..461170e 100644
--- a/app/components/ThemeProvider.tsx
+++ b/app/components/ThemeProvider.tsx
@@ -12,8 +12,15 @@ const ThemeContext = createContext<{
toggleTheme: () => {},
});
-export function useTheme() {
- return useContext(ThemeContext);
+// safe getter (évite SSR crash)
+function getInitialTheme(): Theme {
+ if (typeof window === "undefined") {return "dark";}
+
+ return (
+ (localStorage.getItem("theme") as Theme) ||
+ (document.documentElement.getAttribute("data-theme") as Theme) ||
+ "dark"
+ );
}
export default function ThemeProvider({
@@ -21,21 +28,15 @@ export default function ThemeProvider({
}: {
children: React.ReactNode;
}) {
- const [theme, setTheme] = useState("dark");
- const [mounted, setMounted] = useState(false);
+ const [theme, setTheme] = useState(() => getInitialTheme());
useEffect(() => {
- const stored =
- (document.documentElement.getAttribute("data-theme") as Theme) || "dark";
- setTheme(stored);
- setMounted(true);
- }, []);
+ document.documentElement.setAttribute("data-theme", theme);
+ localStorage.setItem("theme", theme);
+ }, [theme]);
const toggleTheme = () => {
- const next = theme === "dark" ? "light" : "dark";
- setTheme(next);
- localStorage.setItem("theme", next);
- document.documentElement.setAttribute("data-theme", next);
+ setTheme((prev) => (prev === "dark" ? "light" : "dark"));
};
return (
@@ -44,3 +45,7 @@ export default function ThemeProvider({
);
}
+
+export function useTheme() {
+ return useContext(ThemeContext);
+}
\ No newline at end of file
diff --git a/app/layout.tsx b/app/layout.tsx
index f0bf92d..b8470e6 100644
--- a/app/layout.tsx
+++ b/app/layout.tsx
@@ -108,7 +108,7 @@ const jsonLd = {
"Auto-hébergement",
"Infrastructure réseau",
],
- sameAs: ["https://github.com"],
+ sameAs: ["https://github.com/arthur-pbty/portfolio"],
};
export default function RootLayout({
diff --git a/app/photos/page.tsx b/app/photos/page.tsx
index 03f0deb..2498362 100644
--- a/app/photos/page.tsx
+++ b/app/photos/page.tsx
@@ -9,7 +9,7 @@ export const metadata: Metadata = {
"Galerie photo d'Arthur P. — moments de vie, voile et aventures.",
};
-const photos = Array.from({ length: 68 }, (_, i) => {
+const photos = Array.from({ length: 33 }, (_, i) => {
const num = String(i + 1).padStart(3, "0");
return { src: `/pictures/photo_${num}.webp`, alt: `Photo ${i + 1}` };
});
diff --git a/docker-compose.yml b/docker-compose.yml
index df24aeb..9327066 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -1,12 +1,20 @@
services:
- web:
+ next-app:
build:
context: .
+ dockerfile: Dockerfile
+
+ container_name: portfolio-app
+
ports:
- - "3000:3000"
- volumes:
- - ./:/app # monte ton code pour hot reload
- - /app/node_modules # préserver les modules installés dans l'image
+ - "${WEB_PORT}:3000"
+
+ env_file:
+ - .env
+
+ restart: unless-stopped
+
environment:
- - NODE_ENV=development
- command: npm run dev
\ No newline at end of file
+ - PORT=3000
+ - NODE_ENV=production
+ - HOSTNAME=0.0.0.0
\ No newline at end of file
diff --git a/eslint.config.js b/eslint.config.js
new file mode 100644
index 0000000..e19fd73
--- /dev/null
+++ b/eslint.config.js
@@ -0,0 +1,46 @@
+import js from "@eslint/js";
+import next from "eslint-config-next";
+import tseslint from "typescript-eslint";
+
+const config = [
+ // Base JavaScript recommended rules
+ js.configs.recommended,
+
+ // TypeScript recommended rules
+ ...tseslint.configs.recommended,
+
+ // Next.js recommended rules
+ ...next,
+
+ {
+ rules: {
+ // ===== Code quality =====
+ "no-console": "warn",
+ "prefer-const": "error",
+ eqeqeq: ["error", "always"],
+ curly: ["error", "all"],
+
+ // ===== TypeScript =====
+ "@typescript-eslint/no-unused-vars": ["warn"],
+
+ // ===== React / Next =====
+ "react-hooks/exhaustive-deps": "warn",
+ "react/react-in-jsx-scope": "off",
+
+ // ===== Style =====
+ semi: ["error", "always"],
+ quotes: ["error", "double"],
+ },
+ },
+
+ {
+ ignores: [
+ "node_modules",
+ ".next",
+ "dist",
+ "out",
+ ],
+ },
+];
+
+export default config;
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
index d728081..649db8f 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -9,17 +9,18 @@
"version": "0.1.0",
"dependencies": {
"lucide-react": "^0.576.0",
- "next": "16.1.6",
+ "next": "^16.2.4",
"react": "19.2.3",
"react-dom": "19.2.3"
},
"devDependencies": {
+ "@eslint/eslintrc": "^3.3.5",
"@tailwindcss/postcss": "^4",
"@types/node": "^20",
"@types/react": "^19",
"@types/react-dom": "^19",
- "eslint": "^9",
- "eslint-config-next": "16.1.6",
+ "eslint": "^9.39.4",
+ "eslint-config-next": "^16.1.6",
"tailwindcss": "^4",
"typescript": "5.9.3"
}
@@ -68,6 +69,7 @@
"integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/code-frame": "^7.29.0",
"@babel/generator": "^7.29.0",
@@ -353,15 +355,15 @@
}
},
"node_modules/@eslint/config-array": {
- "version": "0.21.1",
- "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.1.tgz",
- "integrity": "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==",
+ "version": "0.21.2",
+ "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.2.tgz",
+ "integrity": "sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"@eslint/object-schema": "^2.1.7",
"debug": "^4.3.1",
- "minimatch": "^3.1.2"
+ "minimatch": "^3.1.5"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -394,9 +396,9 @@
}
},
"node_modules/@eslint/eslintrc": {
- "version": "3.3.4",
- "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.4.tgz",
- "integrity": "sha512-4h4MVF8pmBsncB60r0wSJiIeUKTSD4m7FmTFThG8RHlsg9ajqckLm9OraguFGZE4vVdpiI1Q4+hFnisopmG6gQ==",
+ "version": "3.3.5",
+ "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.5.tgz",
+ "integrity": "sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -407,7 +409,7 @@
"ignore": "^5.2.0",
"import-fresh": "^3.2.1",
"js-yaml": "^4.1.1",
- "minimatch": "^3.1.3",
+ "minimatch": "^3.1.5",
"strip-json-comments": "^3.1.1"
},
"engines": {
@@ -418,9 +420,9 @@
}
},
"node_modules/@eslint/js": {
- "version": "9.39.3",
- "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.3.tgz",
- "integrity": "sha512-1B1VkCq6FuUNlQvlBYb+1jDu/gV297TIs/OeiaSR9l1H27SVW55ONE1e1Vp16NqP683+xEGzxYtv4XCiDPaQiw==",
+ "version": "9.39.4",
+ "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.4.tgz",
+ "integrity": "sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw==",
"dev": true,
"license": "MIT",
"engines": {
@@ -1036,9 +1038,9 @@
}
},
"node_modules/@next/env": {
- "version": "16.1.6",
- "resolved": "https://registry.npmjs.org/@next/env/-/env-16.1.6.tgz",
- "integrity": "sha512-N1ySLuZjnAtN3kFnwhAwPvZah8RJxKasD7x1f8shFqhncnWZn4JMfg37diLNuoHsLAlrDfM3g4mawVdtAG8XLQ==",
+ "version": "16.2.4",
+ "resolved": "https://registry.npmjs.org/@next/env/-/env-16.2.4.tgz",
+ "integrity": "sha512-dKkkOzOSwFYe5RX6y26fZgkSpVAlIOJKQHIiydQcrWH6y/97+RceSOAdjZ14Qa3zLduVUy0TXcn+EiM6t4rPgw==",
"license": "MIT"
},
"node_modules/@next/eslint-plugin-next": {
@@ -1052,9 +1054,9 @@
}
},
"node_modules/@next/swc-darwin-arm64": {
- "version": "16.1.6",
- "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.1.6.tgz",
- "integrity": "sha512-wTzYulosJr/6nFnqGW7FrG3jfUUlEf8UjGA0/pyypJl42ExdVgC6xJgcXQ+V8QFn6niSG2Pb8+MIG1mZr2vczw==",
+ "version": "16.2.4",
+ "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.2.4.tgz",
+ "integrity": "sha512-OXTFFox5EKN1Ym08vfrz+OXxmCcEjT4SFMbNRsWZE99dMqt2Kcusl5MqPXcW232RYkMLQTy0hqgAMEsfEd/l2A==",
"cpu": [
"arm64"
],
@@ -1068,9 +1070,9 @@
}
},
"node_modules/@next/swc-darwin-x64": {
- "version": "16.1.6",
- "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.1.6.tgz",
- "integrity": "sha512-BLFPYPDO+MNJsiDWbeVzqvYd4NyuRrEYVB5k2N3JfWncuHAy2IVwMAOlVQDFjj+krkWzhY2apvmekMkfQR0CUQ==",
+ "version": "16.2.4",
+ "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.2.4.tgz",
+ "integrity": "sha512-XhpVnUfmYWvD3YrXu55XdcAkQtOnvaI6wtQa8fuF5fGoKoxIUZ0kWPtcOfqJEWngFF/lOS9l3+O9CcownhiQxQ==",
"cpu": [
"x64"
],
@@ -1084,9 +1086,9 @@
}
},
"node_modules/@next/swc-linux-arm64-gnu": {
- "version": "16.1.6",
- "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.1.6.tgz",
- "integrity": "sha512-OJYkCd5pj/QloBvoEcJ2XiMnlJkRv9idWA/j0ugSuA34gMT6f5b7vOiCQHVRpvStoZUknhl6/UxOXL4OwtdaBw==",
+ "version": "16.2.4",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.2.4.tgz",
+ "integrity": "sha512-Mx/tjlNA3G8kg14QvuGAJ4xBwPk1tUHq56JxZ8CXnZwz1Etz714soCEzGQQzVMz4bEnGPowzkV6Xrp6wAkEWOQ==",
"cpu": [
"arm64"
],
@@ -1100,9 +1102,9 @@
}
},
"node_modules/@next/swc-linux-arm64-musl": {
- "version": "16.1.6",
- "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.1.6.tgz",
- "integrity": "sha512-S4J2v+8tT3NIO9u2q+S0G5KdvNDjXfAv06OhfOzNDaBn5rw84DGXWndOEB7d5/x852A20sW1M56vhC/tRVbccQ==",
+ "version": "16.2.4",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.2.4.tgz",
+ "integrity": "sha512-iVMMp14514u7Nup2umQS03nT/bN9HurK8ufylC3FZNykrwjtx7V1A7+4kvhbDSCeonTVqV3Txnv0Lu+m2oDXNg==",
"cpu": [
"arm64"
],
@@ -1116,9 +1118,9 @@
}
},
"node_modules/@next/swc-linux-x64-gnu": {
- "version": "16.1.6",
- "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.1.6.tgz",
- "integrity": "sha512-2eEBDkFlMMNQnkTyPBhQOAyn2qMxyG2eE7GPH2WIDGEpEILcBPI/jdSv4t6xupSP+ot/jkfrCShLAa7+ZUPcJQ==",
+ "version": "16.2.4",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.2.4.tgz",
+ "integrity": "sha512-EZOvm1aQWgnI/N/xcWOlnS3RQBk0VtVav5Zo7n4p0A7UKyTDx047k8opDbXgBpHl4CulRqRfbw3QrX2w5UOXMQ==",
"cpu": [
"x64"
],
@@ -1132,9 +1134,9 @@
}
},
"node_modules/@next/swc-linux-x64-musl": {
- "version": "16.1.6",
- "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.1.6.tgz",
- "integrity": "sha512-oicJwRlyOoZXVlxmIMaTq7f8pN9QNbdes0q2FXfRsPhfCi8n8JmOZJm5oo1pwDaFbnnD421rVU409M3evFbIqg==",
+ "version": "16.2.4",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.2.4.tgz",
+ "integrity": "sha512-h9FxsngCm9cTBf71AR4fGznDEDx1hS7+kSEiIRjq5kO1oXWm07DxVGZjCvk0SGx7TSjlUqhI8oOyz7NfwAdPoA==",
"cpu": [
"x64"
],
@@ -1148,9 +1150,9 @@
}
},
"node_modules/@next/swc-win32-arm64-msvc": {
- "version": "16.1.6",
- "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.1.6.tgz",
- "integrity": "sha512-gQmm8izDTPgs+DCWH22kcDmuUp7NyiJgEl18bcr8irXA5N2m2O+JQIr6f3ct42GOs9c0h8QF3L5SzIxcYAAXXw==",
+ "version": "16.2.4",
+ "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.2.4.tgz",
+ "integrity": "sha512-3NdJV5OXMSOeJYijX+bjaLge3mJBlh4ybydbT4GFoB/2hAojWHtMhl3CYlYoMrjPuodp0nzFVi4Tj2+WaMg+Ow==",
"cpu": [
"arm64"
],
@@ -1164,9 +1166,9 @@
}
},
"node_modules/@next/swc-win32-x64-msvc": {
- "version": "16.1.6",
- "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.1.6.tgz",
- "integrity": "sha512-NRfO39AIrzBnixKbjuo2YiYhB6o9d8v/ymU9m/Xk8cyVk+k7XylniXkHwjs4s70wedVffc6bQNbufk5v0xEm0A==",
+ "version": "16.2.4",
+ "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.2.4.tgz",
+ "integrity": "sha512-kMVGgsqhO5YTYODD9IPGGhA6iprWidQckK3LmPeW08PIFENRmgfb4MjXHO+p//d+ts2rpjvK5gXWzXSMrPl9cw==",
"cpu": [
"x64"
],
@@ -1562,6 +1564,7 @@
"integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"csstype": "^3.2.2"
}
@@ -1621,6 +1624,7 @@
"integrity": "sha512-klQbnPAAiGYFyI02+znpBRLyjL4/BrBd0nyWkdC0s/6xFLkXYQ8OoRrSkqacS1ddVxf/LDyODIKbQ5TgKAf/Fg==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@typescript-eslint/scope-manager": "8.56.1",
"@typescript-eslint/types": "8.56.1",
@@ -1775,9 +1779,9 @@
}
},
"node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": {
- "version": "5.0.4",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz",
- "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==",
+ "version": "5.0.5",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz",
+ "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -2146,6 +2150,7 @@
"integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==",
"dev": true,
"license": "MIT",
+ "peer": true,
"bin": {
"acorn": "bin/acorn"
},
@@ -2446,9 +2451,9 @@
}
},
"node_modules/brace-expansion": {
- "version": "1.1.12",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
- "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
+ "version": "1.1.14",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz",
+ "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -2489,6 +2494,7 @@
}
],
"license": "MIT",
+ "peer": true,
"dependencies": {
"baseline-browser-mapping": "^2.9.0",
"caniuse-lite": "^1.0.30001759",
@@ -3051,25 +3057,26 @@
}
},
"node_modules/eslint": {
- "version": "9.39.3",
- "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.3.tgz",
- "integrity": "sha512-VmQ+sifHUbI/IcSopBCF/HO3YiHQx/AVd3UVyYL6weuwW+HvON9VYn5l6Zl1WZzPWXPNZrSQpxwkkZ/VuvJZzg==",
+ "version": "9.39.4",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.4.tgz",
+ "integrity": "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.8.0",
"@eslint-community/regexpp": "^4.12.1",
- "@eslint/config-array": "^0.21.1",
+ "@eslint/config-array": "^0.21.2",
"@eslint/config-helpers": "^0.4.2",
"@eslint/core": "^0.17.0",
- "@eslint/eslintrc": "^3.3.1",
- "@eslint/js": "9.39.3",
+ "@eslint/eslintrc": "^3.3.5",
+ "@eslint/js": "9.39.4",
"@eslint/plugin-kit": "^0.4.1",
"@humanfs/node": "^0.16.6",
"@humanwhocodes/module-importer": "^1.0.1",
"@humanwhocodes/retry": "^0.4.2",
"@types/estree": "^1.0.6",
- "ajv": "^6.12.4",
+ "ajv": "^6.14.0",
"chalk": "^4.0.0",
"cross-spawn": "^7.0.6",
"debug": "^4.3.2",
@@ -3088,7 +3095,7 @@
"is-glob": "^4.0.0",
"json-stable-stringify-without-jsonify": "^1.0.1",
"lodash.merge": "^4.6.2",
- "minimatch": "^3.1.2",
+ "minimatch": "^3.1.5",
"natural-compare": "^1.4.0",
"optionator": "^0.9.3"
},
@@ -3241,6 +3248,7 @@
"integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@rtsao/scc": "^1.1.0",
"array-includes": "^3.1.9",
@@ -3599,9 +3607,9 @@
}
},
"node_modules/flatted": {
- "version": "3.3.4",
- "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.4.tgz",
- "integrity": "sha512-3+mMldrTAPdta5kjX2G2J7iX4zxtnwpdA8Tr2ZSjkyPSanvbZAcy6flmtnXbEybHrDcU9641lxrMfFuUxVz9vA==",
+ "version": "3.4.2",
+ "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz",
+ "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==",
"dev": true,
"license": "ISC"
},
@@ -4994,14 +5002,14 @@
"license": "MIT"
},
"node_modules/next": {
- "version": "16.1.6",
- "resolved": "https://registry.npmjs.org/next/-/next-16.1.6.tgz",
- "integrity": "sha512-hkyRkcu5x/41KoqnROkfTm2pZVbKxvbZRuNvKXLRXxs3VfyO0WhY50TQS40EuKO9SW3rBj/sF3WbVwDACeMZyw==",
+ "version": "16.2.4",
+ "resolved": "https://registry.npmjs.org/next/-/next-16.2.4.tgz",
+ "integrity": "sha512-kPvz56wF5frc+FxlHI5qnklCzbq53HTwORaWBGdT0vNoKh1Aya9XC8aPauH4NJxqtzbWsS5mAbctm4cr+EkQ2Q==",
"license": "MIT",
"dependencies": {
- "@next/env": "16.1.6",
+ "@next/env": "16.2.4",
"@swc/helpers": "0.5.15",
- "baseline-browser-mapping": "^2.8.3",
+ "baseline-browser-mapping": "^2.9.19",
"caniuse-lite": "^1.0.30001579",
"postcss": "8.4.31",
"styled-jsx": "5.1.6"
@@ -5013,15 +5021,15 @@
"node": ">=20.9.0"
},
"optionalDependencies": {
- "@next/swc-darwin-arm64": "16.1.6",
- "@next/swc-darwin-x64": "16.1.6",
- "@next/swc-linux-arm64-gnu": "16.1.6",
- "@next/swc-linux-arm64-musl": "16.1.6",
- "@next/swc-linux-x64-gnu": "16.1.6",
- "@next/swc-linux-x64-musl": "16.1.6",
- "@next/swc-win32-arm64-msvc": "16.1.6",
- "@next/swc-win32-x64-msvc": "16.1.6",
- "sharp": "^0.34.4"
+ "@next/swc-darwin-arm64": "16.2.4",
+ "@next/swc-darwin-x64": "16.2.4",
+ "@next/swc-linux-arm64-gnu": "16.2.4",
+ "@next/swc-linux-arm64-musl": "16.2.4",
+ "@next/swc-linux-x64-gnu": "16.2.4",
+ "@next/swc-linux-x64-musl": "16.2.4",
+ "@next/swc-win32-arm64-msvc": "16.2.4",
+ "@next/swc-win32-x64-msvc": "16.2.4",
+ "sharp": "^0.34.5"
},
"peerDependencies": {
"@opentelemetry/api": "^1.1.0",
@@ -5338,9 +5346,9 @@
"license": "ISC"
},
"node_modules/picomatch": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
- "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz",
+ "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==",
"dev": true,
"license": "MIT",
"engines": {
@@ -5361,9 +5369,9 @@
}
},
"node_modules/postcss": {
- "version": "8.5.6",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz",
- "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==",
+ "version": "8.5.12",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.12.tgz",
+ "integrity": "sha512-W62t/Se6rA0Az3DfCL0AqJwXuKwBeYg6nOaIgzP+xZ7N5BFCI7DYi1qs6ygUYT6rvfi6t9k65UMLJC+PHZpDAA==",
"dev": true,
"funding": [
{
@@ -5447,6 +5455,7 @@
"resolved": "https://registry.npmjs.org/react/-/react-19.2.3.tgz",
"integrity": "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==",
"license": "MIT",
+ "peer": true,
"engines": {
"node": ">=0.10.0"
}
@@ -5456,6 +5465,7 @@
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.3.tgz",
"integrity": "sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"scheduler": "^0.27.0"
},
@@ -6139,11 +6149,12 @@
}
},
"node_modules/tinyglobby/node_modules/picomatch": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
- "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
+ "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
"dev": true,
"license": "MIT",
+ "peer": true,
"engines": {
"node": ">=12"
},
@@ -6306,6 +6317,7 @@
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
"dev": true,
"license": "Apache-2.0",
+ "peer": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
@@ -6581,6 +6593,7 @@
"integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==",
"dev": true,
"license": "MIT",
+ "peer": true,
"funding": {
"url": "https://github.com/sponsors/colinhacks"
}
diff --git a/package.json b/package.json
index 7512511..bf4df6b 100644
--- a/package.json
+++ b/package.json
@@ -2,25 +2,28 @@
"name": "portfolio",
"version": "0.1.0",
"private": true,
+ "type": "module",
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
- "lint": "eslint"
+ "lint": "eslint .",
+ "lint:fix": "eslint . --fix"
},
"dependencies": {
"lucide-react": "^0.576.0",
- "next": "16.1.6",
+ "next": "^16.2.4",
"react": "19.2.3",
"react-dom": "19.2.3"
},
"devDependencies": {
+ "@eslint/eslintrc": "^3.3.5",
"@tailwindcss/postcss": "^4",
"@types/node": "^20",
"@types/react": "^19",
"@types/react-dom": "^19",
- "eslint": "^9",
- "eslint-config-next": "16.1.6",
+ "eslint": "^9.39.4",
+ "eslint-config-next": "^16.1.6",
"tailwindcss": "^4",
"typescript": "5.9.3"
}
diff --git a/public/pictures/photo_034.webp b/public/pictures/photo_034.webp
deleted file mode 100644
index 7c94c6c..0000000
Binary files a/public/pictures/photo_034.webp and /dev/null differ
diff --git a/public/pictures/photo_035.webp b/public/pictures/photo_035.webp
deleted file mode 100644
index 1148dc6..0000000
Binary files a/public/pictures/photo_035.webp and /dev/null differ
diff --git a/public/pictures/photo_036.webp b/public/pictures/photo_036.webp
deleted file mode 100644
index 0aa020c..0000000
Binary files a/public/pictures/photo_036.webp and /dev/null differ
diff --git a/public/pictures/photo_037.webp b/public/pictures/photo_037.webp
deleted file mode 100644
index 0a1d3ed..0000000
Binary files a/public/pictures/photo_037.webp and /dev/null differ
diff --git a/public/pictures/photo_038.webp b/public/pictures/photo_038.webp
deleted file mode 100644
index e98508f..0000000
Binary files a/public/pictures/photo_038.webp and /dev/null differ
diff --git a/public/pictures/photo_039.webp b/public/pictures/photo_039.webp
deleted file mode 100644
index 84f342c..0000000
Binary files a/public/pictures/photo_039.webp and /dev/null differ
diff --git a/public/pictures/photo_040.webp b/public/pictures/photo_040.webp
deleted file mode 100644
index 4cb9fd1..0000000
Binary files a/public/pictures/photo_040.webp and /dev/null differ
diff --git a/public/pictures/photo_041.webp b/public/pictures/photo_041.webp
deleted file mode 100644
index 574c250..0000000
Binary files a/public/pictures/photo_041.webp and /dev/null differ
diff --git a/public/pictures/photo_042.webp b/public/pictures/photo_042.webp
deleted file mode 100644
index 2d827fd..0000000
Binary files a/public/pictures/photo_042.webp and /dev/null differ
diff --git a/public/pictures/photo_043.webp b/public/pictures/photo_043.webp
deleted file mode 100644
index 40d7c69..0000000
Binary files a/public/pictures/photo_043.webp and /dev/null differ
diff --git a/public/pictures/photo_044.webp b/public/pictures/photo_044.webp
deleted file mode 100644
index 4e7d5a0..0000000
Binary files a/public/pictures/photo_044.webp and /dev/null differ
diff --git a/public/pictures/photo_045.webp b/public/pictures/photo_045.webp
deleted file mode 100644
index e1fb912..0000000
Binary files a/public/pictures/photo_045.webp and /dev/null differ
diff --git a/public/pictures/photo_046.webp b/public/pictures/photo_046.webp
deleted file mode 100644
index e2477ae..0000000
Binary files a/public/pictures/photo_046.webp and /dev/null differ
diff --git a/public/pictures/photo_047.webp b/public/pictures/photo_047.webp
deleted file mode 100644
index 6e7fe8b..0000000
Binary files a/public/pictures/photo_047.webp and /dev/null differ
diff --git a/public/pictures/photo_048.webp b/public/pictures/photo_048.webp
deleted file mode 100644
index 77e2a2d..0000000
Binary files a/public/pictures/photo_048.webp and /dev/null differ
diff --git a/public/pictures/photo_049.webp b/public/pictures/photo_049.webp
deleted file mode 100644
index 8a3b865..0000000
Binary files a/public/pictures/photo_049.webp and /dev/null differ
diff --git a/public/pictures/photo_050.webp b/public/pictures/photo_050.webp
deleted file mode 100644
index e524f3e..0000000
Binary files a/public/pictures/photo_050.webp and /dev/null differ
diff --git a/public/pictures/photo_051.webp b/public/pictures/photo_051.webp
deleted file mode 100644
index 650926c..0000000
Binary files a/public/pictures/photo_051.webp and /dev/null differ
diff --git a/public/pictures/photo_052.webp b/public/pictures/photo_052.webp
deleted file mode 100644
index 4a8027d..0000000
Binary files a/public/pictures/photo_052.webp and /dev/null differ
diff --git a/public/pictures/photo_053.webp b/public/pictures/photo_053.webp
deleted file mode 100644
index a3334a8..0000000
Binary files a/public/pictures/photo_053.webp and /dev/null differ
diff --git a/public/pictures/photo_054.webp b/public/pictures/photo_054.webp
deleted file mode 100644
index d73c19d..0000000
Binary files a/public/pictures/photo_054.webp and /dev/null differ
diff --git a/public/pictures/photo_055.webp b/public/pictures/photo_055.webp
deleted file mode 100644
index 92216b4..0000000
Binary files a/public/pictures/photo_055.webp and /dev/null differ
diff --git a/public/pictures/photo_056.webp b/public/pictures/photo_056.webp
deleted file mode 100644
index 183336c..0000000
Binary files a/public/pictures/photo_056.webp and /dev/null differ
diff --git a/public/pictures/photo_057.webp b/public/pictures/photo_057.webp
deleted file mode 100644
index cfb1778..0000000
Binary files a/public/pictures/photo_057.webp and /dev/null differ
diff --git a/public/pictures/photo_058.webp b/public/pictures/photo_058.webp
deleted file mode 100644
index 6787ee6..0000000
Binary files a/public/pictures/photo_058.webp and /dev/null differ
diff --git a/public/pictures/photo_059.webp b/public/pictures/photo_059.webp
deleted file mode 100644
index fdaefc1..0000000
Binary files a/public/pictures/photo_059.webp and /dev/null differ
diff --git a/public/pictures/photo_060.webp b/public/pictures/photo_060.webp
deleted file mode 100644
index cdd9129..0000000
Binary files a/public/pictures/photo_060.webp and /dev/null differ
diff --git a/public/pictures/photo_061.webp b/public/pictures/photo_061.webp
deleted file mode 100644
index 0b807dd..0000000
Binary files a/public/pictures/photo_061.webp and /dev/null differ
diff --git a/public/pictures/photo_062.webp b/public/pictures/photo_062.webp
deleted file mode 100644
index 253cf96..0000000
Binary files a/public/pictures/photo_062.webp and /dev/null differ
diff --git a/public/pictures/photo_063.webp b/public/pictures/photo_063.webp
deleted file mode 100644
index 07b0fdb..0000000
Binary files a/public/pictures/photo_063.webp and /dev/null differ
diff --git a/public/pictures/photo_064.webp b/public/pictures/photo_064.webp
deleted file mode 100644
index 473a472..0000000
Binary files a/public/pictures/photo_064.webp and /dev/null differ
diff --git a/public/pictures/photo_065.webp b/public/pictures/photo_065.webp
deleted file mode 100644
index 6d4cbab..0000000
Binary files a/public/pictures/photo_065.webp and /dev/null differ
diff --git a/public/pictures/photo_066.webp b/public/pictures/photo_066.webp
deleted file mode 100644
index 24baef7..0000000
Binary files a/public/pictures/photo_066.webp and /dev/null differ
diff --git a/public/pictures/photo_067.webp b/public/pictures/photo_067.webp
deleted file mode 100644
index b7eebd2..0000000
Binary files a/public/pictures/photo_067.webp and /dev/null differ
diff --git a/public/pictures/photo_068.webp b/public/pictures/photo_068.webp
deleted file mode 100644
index 8124ebf..0000000
Binary files a/public/pictures/photo_068.webp and /dev/null differ