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() {

Contact

- arthurp.fr + contact.arthurp.fr - arthur.puechberty@outlook.com + contact@arthurp.fr + + + + arthurp.fr
diff --git a/app/components/Homelab.tsx b/app/components/Homelab.tsx index 308a28a..843ef18 100644 --- a/app/components/Homelab.tsx +++ b/app/components/Homelab.tsx @@ -7,6 +7,8 @@ import { Image, Tv, Monitor, + Music, + Search, } from "lucide-react"; const infra = [ @@ -55,6 +57,18 @@ const personalServices = [ url: "jellyfin.arthurp.fr", desc: "Serveur multimédia auto-hébergé — films, séries, musique.", }, + { + icon: , + name: "Navidrome", + url: "navidrome.arthurp.fr", + desc: "Serveur de musique auto-hébergé — streaming de ma bibliothèque musicale.", + }, + { + icon: , + name: "SearXNG", + url: "searxng.arthurp.fr", + desc: "Moteur de recherche anonyme et décentralisé.", + }, ]; export default function Homelab() { diff --git a/app/components/Projects.tsx b/app/components/Projects.tsx index 424eb60..2f1205d 100644 --- a/app/components/Projects.tsx +++ b/app/components/Projects.tsx @@ -1,4 +1,4 @@ -import { ExternalLink, Timer, FileQuestion, Grid3X3, Video, QrCode, BookOpen, Link2, FileText, Bot, LinkIcon, Clock } from "lucide-react"; +import { ExternalLink, Timer, FileQuestion, Grid3X3, Video, QrCode, BookOpen, Link2, FileText, Bot, LinkIcon, Clock, Zap } from "lucide-react"; const projects = [ { @@ -9,11 +9,67 @@ const projects = [ tags: ["Site vitrine", "Hub"], }, { - name: "pomodoro.arthurp.fr", - url: "https://pomodoro.arthurp.fr", - desc: "Application de gestion du temps basée sur la méthode Pomodoro.", - icon: , - tags: ["Productivité", "Web App"], + name: "links.arthurp.fr", + url: "https://links.arthurp.fr", + desc: "Page de centralisation de liens.", + icon: , + tags: ["Liens", "Hub"], + }, + { + name: "lazybot.arthurp.fr", + url: "https://lazybot.arthurp.fr", + desc: "Bot Discord contrôlé via un dashboard web, développé et hébergé par moi.", + icon: , + tags: ["Discord", "Bot", "Dashboard"], + }, + { + name: "clock.arthurp.fr", + url: "https://clock.arthurp.fr", + desc: "Application d'affichage et de gestion du temps.", + icon: , + tags: ["Temps", "Utilitaire"], + }, + { + name: "flint.arthurp.fr", + url: "https://flint.arthurp.fr", + desc: "Saas de gestion de bots Discord avec dashboard.", + icon: , + tags: ["Discord", "Bot", "Dashboard"], + }, + { + name: "learn.arthurp.fr", + url: "https://learn.arthurp.fr", + desc: "Plateforme d'apprentissage et de documentation personnelle.", + icon: , + tags: ["Apprentissage", "Documentation"], + }, + { + name: "form.arthurp.fr", + url: "https://form.arthurp.fr", + desc: "Système de formulaires auto-hébergé.", + icon: , + tags: ["Formulaires", "Auto-hébergé"], + }, + { + name: "reducelink.arthurp.fr", + url: "https://reducelink.arthurp.fr", + desc: "Service de réduction de liens.", + icon: , + tags: ["Outil", "Raccourcisseur"], + }, + { + name: "imprimersudoku.arthurp.fr", + url: "https://imprimersudoku.arthurp.fr", + desc: "Feuille de grilles de Sudoku imprimables.", + icon: , + tags: ["Jeu", "Imprimante"], + }, + { + name: "qrcode.arthurp.fr", + url: "https://qrcode.arthurp.fr", + desc: "Générateur de QR codes personnalisés.", + icon: , + tags: ["Outil", "Utilitaire"], }, { name: "qcu.arthurp.fr", @@ -37,53 +93,11 @@ const projects = [ tags: ["Communication", "Auto-hébergé"], }, { - name: "qrcode.arthurp.fr", - url: "https://qrcode.arthurp.fr", - desc: "Générateur de QR codes personnalisés.", - icon: , - tags: ["Outil", "Utilitaire"], - }, - { - name: "learn.arthurp.fr", - url: "https://learn.arthurp.fr", - desc: "Plateforme d'apprentissage et de documentation personnelle.", - icon: , - tags: ["Apprentissage", "Documentation"], - }, - { - name: "links.arthurp.fr", - url: "https://links.arthurp.fr", - desc: "Page de centralisation de liens.", - icon: , - tags: ["Liens", "Hub"], - }, - { - name: "form.arthurp.fr", - url: "https://form.arthurp.fr", - desc: "Système de formulaires auto-hébergé.", - icon: , - tags: ["Formulaires", "Auto-hébergé"], - }, - { - name: "lazybot.arthurp.fr", - url: "https://lazybot.arthurp.fr", - desc: "Bot Discord contrôlé via un dashboard web, développé et hébergé par moi.", - icon: , - tags: ["Discord", "Bot", "Dashboard"], - }, - { - name: "reducelink.arthurp.fr", - url: "https://reducelink.arthurp.fr", - desc: "Service de réduction de liens.", - icon: , - tags: ["Outil", "Raccourcisseur"], - }, - { - name: "clock.arthurp.fr", - url: "https://clock.arthurp.fr", - desc: "Application d'affichage et de gestion du temps.", - icon: , - tags: ["Temps", "Utilitaire"], + name: "pomodoro.arthurp.fr", + url: "https://pomodoro.arthurp.fr", + desc: "Application de gestion du temps basée sur la méthode Pomodoro.", + icon: , + tags: ["Productivité", "Web App"], }, ]; diff --git a/app/components/Sailing.tsx b/app/components/Sailing.tsx index 83eb0c7..17f2bd6 100644 --- a/app/components/Sailing.tsx +++ b/app/components/Sailing.tsx @@ -6,8 +6,8 @@ const palmares = [ results: [ { rank: "1er", event: "Spi Ouest France", boat: "Open 5.70" }, { rank: "1er", event: "GPEN", boat: "Open 5.70" }, - { rank: "3e", event: "18h d'Arcachon", boat: "Open 5.70" }, - { rank: "2e", event: "Championnat de France Espoirs", boat: "" }, + { rank: "3e", event: "18h d'Arcachon", boat: "5.90" }, + { rank: "2e", event: "Championnat de France Espoirs", boat: "Open 5.70" }, ], }, { @@ -41,9 +41,9 @@ const qualities = [ ]; function getRankColor(rank: string) { - if (rank.startsWith("1er")) return "text-yellow-400 bg-yellow-400/10 border-yellow-400/20"; - if (rank.startsWith("2e")) return "text-gray-300 bg-gray-300/10 border-gray-300/20"; - if (rank.startsWith("3e")) return "text-amber-600 bg-amber-600/10 border-amber-600/20"; + if (rank.startsWith("1er")) {return "text-yellow-400 bg-yellow-400/10 border-yellow-400/20";} + if (rank.startsWith("2e")) {return "text-gray-300 bg-gray-300/10 border-gray-300/20";} + if (rank.startsWith("3e")) {return "text-amber-600 bg-amber-600/10 border-amber-600/20";} return "text-blue-400 bg-blue-400/10 border-blue-400/20"; } @@ -89,7 +89,8 @@ export default function Sailing() { deux championnats du monde {" "} en Open Skiff et obtenu le statut de{" "} - sportif de haut niveau. + sportif de haut niveau{" "} + en gagnant le titre de champion de France en Open 5.70.

@@ -115,15 +116,15 @@ export default function Sailing() { {/* Highlights */}
-
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