refactor: update photo gallery and reduce image count
- Reduced the number of photos displayed from 68 to 33 in the photo gallery. - Removed unused photo files (photos 34 to 68) from the public directory. - Updated Docker configuration for better environment management and container naming. - Upgraded Next.js and ESLint dependencies to their latest versions. - Added ESLint configuration file for improved code quality checks. - Introduced a .dockerignore file to exclude unnecessary files from the Docker context. - Added an example .env file for environment variable configuration. Co-authored-by: Copilot <copilot@github.com>
@@ -0,0 +1,7 @@
|
|||||||
|
node_modules
|
||||||
|
.next
|
||||||
|
.git
|
||||||
|
Dockerfile
|
||||||
|
docker-compose.yml
|
||||||
|
npm-debug.log
|
||||||
|
.env
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
WEB_PORT=3000
|
||||||
@@ -31,7 +31,7 @@ yarn-error.log*
|
|||||||
.pnpm-debug.log*
|
.pnpm-debug.log*
|
||||||
|
|
||||||
# env files (can opt-in for committing if needed)
|
# env files (can opt-in for committing if needed)
|
||||||
.env*
|
.env
|
||||||
|
|
||||||
# vercel
|
# vercel
|
||||||
.vercel
|
.vercel
|
||||||
|
|||||||
@@ -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
|
FROM node:20-alpine AS builder
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
# Copier les fichiers de dépendances pour profiter du cache Docker
|
COPY --from=deps /app/node_modules ./node_modules
|
||||||
COPY package*.json ./
|
|
||||||
|
|
||||||
# Installer uniquement ce qu'il faut pour le build
|
|
||||||
RUN npm ci
|
|
||||||
|
|
||||||
# Copier tout le code
|
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
# Build Next.js pour la production
|
# Variables build-time
|
||||||
|
ENV NEXT_TELEMETRY_DISABLED=1
|
||||||
|
|
||||||
RUN npm run build
|
RUN npm run build
|
||||||
|
|
||||||
# === Étape 2 : Runner léger ===
|
|
||||||
|
# ====== 3. Runner (prod minimal) ======
|
||||||
FROM node:20-alpine AS runner
|
FROM node:20-alpine AS runner
|
||||||
|
|
||||||
WORKDIR /app
|
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 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
|
EXPOSE 3000
|
||||||
|
|
||||||
# Lancer le serveur Next.js
|
CMD ["node", "server.js"]
|
||||||
CMD ["npm", "start"]
|
|
||||||
@@ -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() {
|
export default function Footer() {
|
||||||
return (
|
return (
|
||||||
@@ -42,16 +42,16 @@ export default function Footer() {
|
|||||||
<h4 className="font-semibold text-sm mb-4">Contact</h4>
|
<h4 className="font-semibold text-sm mb-4">Contact</h4>
|
||||||
<div className="space-y-3">
|
<div className="space-y-3">
|
||||||
<a
|
<a
|
||||||
href="https://arthurp.fr"
|
href="https://contact.arthurp.fr"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
className="flex items-center gap-2 text-sm text-muted hover:text-emphasis transition-colors"
|
className="flex items-center gap-2 text-sm text-muted hover:text-emphasis transition-colors"
|
||||||
>
|
>
|
||||||
<Globe size={16} />
|
<Globe size={16} />
|
||||||
arthurp.fr
|
contact.arthurp.fr
|
||||||
</a>
|
</a>
|
||||||
<a
|
<a
|
||||||
href="https://github.com"
|
href="https://github.com/arthur-pbty/portfolio"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
className="flex items-center gap-2 text-sm text-muted hover:text-emphasis transition-colors"
|
className="flex items-center gap-2 text-sm text-muted hover:text-emphasis transition-colors"
|
||||||
@@ -60,11 +60,20 @@ export default function Footer() {
|
|||||||
GitHub
|
GitHub
|
||||||
</a>
|
</a>
|
||||||
<a
|
<a
|
||||||
href="mailto:arthur.puechberty@outlook.com"
|
href="mailto:contact@arthurp.fr"
|
||||||
className="flex items-center gap-2 text-sm text-muted hover:text-emphasis transition-colors"
|
className="flex items-center gap-2 text-sm text-muted hover:text-emphasis transition-colors"
|
||||||
>
|
>
|
||||||
<Mail size={16} />
|
<Mail size={16} />
|
||||||
arthur.puechberty@outlook.com
|
contact@arthurp.fr
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
href="https://arthurp.fr"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
className="flex items-center gap-2 text-sm text-muted hover:text-emphasis transition-colors"
|
||||||
|
>
|
||||||
|
<Presentation size={16} />
|
||||||
|
arthurp.fr
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ import {
|
|||||||
Image,
|
Image,
|
||||||
Tv,
|
Tv,
|
||||||
Monitor,
|
Monitor,
|
||||||
|
Music,
|
||||||
|
Search,
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
|
|
||||||
const infra = [
|
const infra = [
|
||||||
@@ -55,6 +57,18 @@ const personalServices = [
|
|||||||
url: "jellyfin.arthurp.fr",
|
url: "jellyfin.arthurp.fr",
|
||||||
desc: "Serveur multimédia auto-hébergé — films, séries, musique.",
|
desc: "Serveur multimédia auto-hébergé — films, séries, musique.",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
icon: <Music size={20} className="text-purple-400" />,
|
||||||
|
name: "Navidrome",
|
||||||
|
url: "navidrome.arthurp.fr",
|
||||||
|
desc: "Serveur de musique auto-hébergé — streaming de ma bibliothèque musicale.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: <Search size={20} className="text-amber-400" />,
|
||||||
|
name: "SearXNG",
|
||||||
|
url: "searxng.arthurp.fr",
|
||||||
|
desc: "Moteur de recherche anonyme et décentralisé.",
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
export default function Homelab() {
|
export default function Homelab() {
|
||||||
|
|||||||
@@ -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 = [
|
const projects = [
|
||||||
{
|
{
|
||||||
@@ -9,11 +9,67 @@ const projects = [
|
|||||||
tags: ["Site vitrine", "Hub"],
|
tags: ["Site vitrine", "Hub"],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "pomodoro.arthurp.fr",
|
name: "links.arthurp.fr",
|
||||||
url: "https://pomodoro.arthurp.fr",
|
url: "https://links.arthurp.fr",
|
||||||
desc: "Application de gestion du temps basée sur la méthode Pomodoro.",
|
desc: "Page de centralisation de liens.",
|
||||||
icon: <Timer size={20} className="text-red-400" />,
|
icon: <Link2 size={20} className="text-pink-400" />,
|
||||||
tags: ["Productivité", "Web App"],
|
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: <Bot size={20} className="text-indigo-400" />,
|
||||||
|
tags: ["Discord", "Bot", "Dashboard"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "clock.arthurp.fr",
|
||||||
|
url: "https://clock.arthurp.fr",
|
||||||
|
desc: "Application d'affichage et de gestion du temps.",
|
||||||
|
icon: <Clock size={20} className="text-sky-400" />,
|
||||||
|
tags: ["Temps", "Utilitaire"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "flint.arthurp.fr",
|
||||||
|
url: "https://flint.arthurp.fr",
|
||||||
|
desc: "Saas de gestion de bots Discord avec dashboard.",
|
||||||
|
icon: <Zap size={20} className="text-indigo-400" />,
|
||||||
|
tags: ["Discord", "Bot", "Dashboard"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "learn.arthurp.fr",
|
||||||
|
url: "https://learn.arthurp.fr",
|
||||||
|
desc: "Plateforme d'apprentissage et de documentation personnelle.",
|
||||||
|
icon: <BookOpen size={20} className="text-orange-400" />,
|
||||||
|
tags: ["Apprentissage", "Documentation"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "form.arthurp.fr",
|
||||||
|
url: "https://form.arthurp.fr",
|
||||||
|
desc: "Système de formulaires auto-hébergé.",
|
||||||
|
icon: <FileText size={20} className="text-teal-400" />,
|
||||||
|
tags: ["Formulaires", "Auto-hébergé"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "reducelink.arthurp.fr",
|
||||||
|
url: "https://reducelink.arthurp.fr",
|
||||||
|
desc: "Service de réduction de liens.",
|
||||||
|
icon: <LinkIcon size={20} className="text-amber-400" />,
|
||||||
|
tags: ["Outil", "Raccourcisseur"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "imprimersudoku.arthurp.fr",
|
||||||
|
url: "https://imprimersudoku.arthurp.fr",
|
||||||
|
desc: "Feuille de grilles de Sudoku imprimables.",
|
||||||
|
icon: <Grid3X3 size={20} className="text-teal-400" />,
|
||||||
|
tags: ["Jeu", "Imprimante"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "qrcode.arthurp.fr",
|
||||||
|
url: "https://qrcode.arthurp.fr",
|
||||||
|
desc: "Générateur de QR codes personnalisés.",
|
||||||
|
icon: <QrCode size={20} className="text-cyan-400" />,
|
||||||
|
tags: ["Outil", "Utilitaire"],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "qcu.arthurp.fr",
|
name: "qcu.arthurp.fr",
|
||||||
@@ -37,53 +93,11 @@ const projects = [
|
|||||||
tags: ["Communication", "Auto-hébergé"],
|
tags: ["Communication", "Auto-hébergé"],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "qrcode.arthurp.fr",
|
name: "pomodoro.arthurp.fr",
|
||||||
url: "https://qrcode.arthurp.fr",
|
url: "https://pomodoro.arthurp.fr",
|
||||||
desc: "Générateur de QR codes personnalisés.",
|
desc: "Application de gestion du temps basée sur la méthode Pomodoro.",
|
||||||
icon: <QrCode size={20} className="text-cyan-400" />,
|
icon: <Timer size={20} className="text-red-400" />,
|
||||||
tags: ["Outil", "Utilitaire"],
|
tags: ["Productivité", "Web App"],
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "learn.arthurp.fr",
|
|
||||||
url: "https://learn.arthurp.fr",
|
|
||||||
desc: "Plateforme d'apprentissage et de documentation personnelle.",
|
|
||||||
icon: <BookOpen size={20} className="text-orange-400" />,
|
|
||||||
tags: ["Apprentissage", "Documentation"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "links.arthurp.fr",
|
|
||||||
url: "https://links.arthurp.fr",
|
|
||||||
desc: "Page de centralisation de liens.",
|
|
||||||
icon: <Link2 size={20} className="text-pink-400" />,
|
|
||||||
tags: ["Liens", "Hub"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "form.arthurp.fr",
|
|
||||||
url: "https://form.arthurp.fr",
|
|
||||||
desc: "Système de formulaires auto-hébergé.",
|
|
||||||
icon: <FileText size={20} className="text-teal-400" />,
|
|
||||||
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: <Bot size={20} className="text-indigo-400" />,
|
|
||||||
tags: ["Discord", "Bot", "Dashboard"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "reducelink.arthurp.fr",
|
|
||||||
url: "https://reducelink.arthurp.fr",
|
|
||||||
desc: "Service de réduction de liens.",
|
|
||||||
icon: <LinkIcon size={20} className="text-amber-400" />,
|
|
||||||
tags: ["Outil", "Raccourcisseur"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "clock.arthurp.fr",
|
|
||||||
url: "https://clock.arthurp.fr",
|
|
||||||
desc: "Application d'affichage et de gestion du temps.",
|
|
||||||
icon: <Clock size={20} className="text-sky-400" />,
|
|
||||||
tags: ["Temps", "Utilitaire"],
|
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ const palmares = [
|
|||||||
results: [
|
results: [
|
||||||
{ rank: "1er", event: "Spi Ouest France", boat: "Open 5.70" },
|
{ rank: "1er", event: "Spi Ouest France", boat: "Open 5.70" },
|
||||||
{ rank: "1er", event: "GPEN", boat: "Open 5.70" },
|
{ rank: "1er", event: "GPEN", boat: "Open 5.70" },
|
||||||
{ rank: "3e", event: "18h d'Arcachon", boat: "Open 5.70" },
|
{ rank: "3e", event: "18h d'Arcachon", boat: "5.90" },
|
||||||
{ rank: "2e", event: "Championnat de France Espoirs", boat: "" },
|
{ rank: "2e", event: "Championnat de France Espoirs", boat: "Open 5.70" },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -41,9 +41,9 @@ const qualities = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
function getRankColor(rank: string) {
|
function getRankColor(rank: string) {
|
||||||
if (rank.startsWith("1er")) return "text-yellow-400 bg-yellow-400/10 border-yellow-400/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("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("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";
|
return "text-blue-400 bg-blue-400/10 border-blue-400/20";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,7 +89,8 @@ export default function Sailing() {
|
|||||||
deux championnats du monde
|
deux championnats du monde
|
||||||
</strong>{" "}
|
</strong>{" "}
|
||||||
en Open Skiff et obtenu le statut de{" "}
|
en Open Skiff et obtenu le statut de{" "}
|
||||||
<strong className="text-emphasis">sportif de haut niveau</strong>.
|
<strong className="text-emphasis">sportif de haut niveau</strong>{" "}
|
||||||
|
en gagnant le titre de champion de France en Open 5.70.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -115,15 +116,15 @@ export default function Sailing() {
|
|||||||
{/* Highlights */}
|
{/* Highlights */}
|
||||||
<div className="grid grid-cols-3 gap-2 sm:gap-3">
|
<div className="grid grid-cols-3 gap-2 sm:gap-3">
|
||||||
<div className="p-3 sm:p-4 rounded-xl border border-border bg-card text-center">
|
<div className="p-3 sm:p-4 rounded-xl border border-border bg-card text-center">
|
||||||
<div className="text-2xl font-bold text-emphasis">2</div>
|
<div className="text-2xl font-bold text-emphasis">1</div>
|
||||||
<div className="text-[10px] text-muted mt-1">
|
<div className="text-[10px] text-muted mt-1">
|
||||||
Championnats du monde
|
Champion de France
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="p-3 sm:p-4 rounded-xl border border-border bg-card text-center">
|
<div className="p-3 sm:p-4 rounded-xl border border-border bg-card text-center">
|
||||||
<div className="text-2xl font-bold text-emphasis">9e</div>
|
<div className="text-2xl font-bold text-emphasis">9e</div>
|
||||||
<div className="text-[10px] text-muted mt-1">
|
<div className="text-[10px] text-muted mt-1">
|
||||||
Mondial (×2)
|
Championnat du monde (×2)
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="p-3 sm:p-4 rounded-xl border border-border bg-card text-center">
|
<div className="p-3 sm:p-4 rounded-xl border border-border bg-card text-center">
|
||||||
|
|||||||
@@ -12,8 +12,15 @@ const ThemeContext = createContext<{
|
|||||||
toggleTheme: () => {},
|
toggleTheme: () => {},
|
||||||
});
|
});
|
||||||
|
|
||||||
export function useTheme() {
|
// safe getter (évite SSR crash)
|
||||||
return useContext(ThemeContext);
|
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({
|
export default function ThemeProvider({
|
||||||
@@ -21,21 +28,15 @@ export default function ThemeProvider({
|
|||||||
}: {
|
}: {
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
}) {
|
}) {
|
||||||
const [theme, setTheme] = useState<Theme>("dark");
|
const [theme, setTheme] = useState<Theme>(() => getInitialTheme());
|
||||||
const [mounted, setMounted] = useState(false);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const stored =
|
document.documentElement.setAttribute("data-theme", theme);
|
||||||
(document.documentElement.getAttribute("data-theme") as Theme) || "dark";
|
localStorage.setItem("theme", theme);
|
||||||
setTheme(stored);
|
}, [theme]);
|
||||||
setMounted(true);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const toggleTheme = () => {
|
const toggleTheme = () => {
|
||||||
const next = theme === "dark" ? "light" : "dark";
|
setTheme((prev) => (prev === "dark" ? "light" : "dark"));
|
||||||
setTheme(next);
|
|
||||||
localStorage.setItem("theme", next);
|
|
||||||
document.documentElement.setAttribute("data-theme", next);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -44,3 +45,7 @@ export default function ThemeProvider({
|
|||||||
</ThemeContext.Provider>
|
</ThemeContext.Provider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function useTheme() {
|
||||||
|
return useContext(ThemeContext);
|
||||||
|
}
|
||||||
@@ -108,7 +108,7 @@ const jsonLd = {
|
|||||||
"Auto-hébergement",
|
"Auto-hébergement",
|
||||||
"Infrastructure réseau",
|
"Infrastructure réseau",
|
||||||
],
|
],
|
||||||
sameAs: ["https://github.com"],
|
sameAs: ["https://github.com/arthur-pbty/portfolio"],
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function RootLayout({
|
export default function RootLayout({
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ export const metadata: Metadata = {
|
|||||||
"Galerie photo d'Arthur P. — moments de vie, voile et aventures.",
|
"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");
|
const num = String(i + 1).padStart(3, "0");
|
||||||
return { src: `/pictures/photo_${num}.webp`, alt: `Photo ${i + 1}` };
|
return { src: `/pictures/photo_${num}.webp`, alt: `Photo ${i + 1}` };
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,12 +1,20 @@
|
|||||||
services:
|
services:
|
||||||
web:
|
next-app:
|
||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
|
||||||
|
container_name: portfolio-app
|
||||||
|
|
||||||
ports:
|
ports:
|
||||||
- "3000:3000"
|
- "${WEB_PORT}:3000"
|
||||||
volumes:
|
|
||||||
- ./:/app # monte ton code pour hot reload
|
env_file:
|
||||||
- /app/node_modules # préserver les modules installés dans l'image
|
- .env
|
||||||
|
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
- NODE_ENV=development
|
- PORT=3000
|
||||||
command: npm run dev
|
- NODE_ENV=production
|
||||||
|
- HOSTNAME=0.0.0.0
|
||||||
@@ -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;
|
||||||
@@ -9,17 +9,18 @@
|
|||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"lucide-react": "^0.576.0",
|
"lucide-react": "^0.576.0",
|
||||||
"next": "16.1.6",
|
"next": "^16.2.4",
|
||||||
"react": "19.2.3",
|
"react": "19.2.3",
|
||||||
"react-dom": "19.2.3"
|
"react-dom": "19.2.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@eslint/eslintrc": "^3.3.5",
|
||||||
"@tailwindcss/postcss": "^4",
|
"@tailwindcss/postcss": "^4",
|
||||||
"@types/node": "^20",
|
"@types/node": "^20",
|
||||||
"@types/react": "^19",
|
"@types/react": "^19",
|
||||||
"@types/react-dom": "^19",
|
"@types/react-dom": "^19",
|
||||||
"eslint": "^9",
|
"eslint": "^9.39.4",
|
||||||
"eslint-config-next": "16.1.6",
|
"eslint-config-next": "^16.1.6",
|
||||||
"tailwindcss": "^4",
|
"tailwindcss": "^4",
|
||||||
"typescript": "5.9.3"
|
"typescript": "5.9.3"
|
||||||
}
|
}
|
||||||
@@ -68,6 +69,7 @@
|
|||||||
"integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==",
|
"integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/code-frame": "^7.29.0",
|
"@babel/code-frame": "^7.29.0",
|
||||||
"@babel/generator": "^7.29.0",
|
"@babel/generator": "^7.29.0",
|
||||||
@@ -353,15 +355,15 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@eslint/config-array": {
|
"node_modules/@eslint/config-array": {
|
||||||
"version": "0.21.1",
|
"version": "0.21.2",
|
||||||
"resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.1.tgz",
|
"resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.2.tgz",
|
||||||
"integrity": "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==",
|
"integrity": "sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint/object-schema": "^2.1.7",
|
"@eslint/object-schema": "^2.1.7",
|
||||||
"debug": "^4.3.1",
|
"debug": "^4.3.1",
|
||||||
"minimatch": "^3.1.2"
|
"minimatch": "^3.1.5"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
@@ -394,9 +396,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@eslint/eslintrc": {
|
"node_modules/@eslint/eslintrc": {
|
||||||
"version": "3.3.4",
|
"version": "3.3.5",
|
||||||
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.4.tgz",
|
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.5.tgz",
|
||||||
"integrity": "sha512-4h4MVF8pmBsncB60r0wSJiIeUKTSD4m7FmTFThG8RHlsg9ajqckLm9OraguFGZE4vVdpiI1Q4+hFnisopmG6gQ==",
|
"integrity": "sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -407,7 +409,7 @@
|
|||||||
"ignore": "^5.2.0",
|
"ignore": "^5.2.0",
|
||||||
"import-fresh": "^3.2.1",
|
"import-fresh": "^3.2.1",
|
||||||
"js-yaml": "^4.1.1",
|
"js-yaml": "^4.1.1",
|
||||||
"minimatch": "^3.1.3",
|
"minimatch": "^3.1.5",
|
||||||
"strip-json-comments": "^3.1.1"
|
"strip-json-comments": "^3.1.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -418,9 +420,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@eslint/js": {
|
"node_modules/@eslint/js": {
|
||||||
"version": "9.39.3",
|
"version": "9.39.4",
|
||||||
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.3.tgz",
|
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.4.tgz",
|
||||||
"integrity": "sha512-1B1VkCq6FuUNlQvlBYb+1jDu/gV297TIs/OeiaSR9l1H27SVW55ONE1e1Vp16NqP683+xEGzxYtv4XCiDPaQiw==",
|
"integrity": "sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -1036,9 +1038,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@next/env": {
|
"node_modules/@next/env": {
|
||||||
"version": "16.1.6",
|
"version": "16.2.4",
|
||||||
"resolved": "https://registry.npmjs.org/@next/env/-/env-16.1.6.tgz",
|
"resolved": "https://registry.npmjs.org/@next/env/-/env-16.2.4.tgz",
|
||||||
"integrity": "sha512-N1ySLuZjnAtN3kFnwhAwPvZah8RJxKasD7x1f8shFqhncnWZn4JMfg37diLNuoHsLAlrDfM3g4mawVdtAG8XLQ==",
|
"integrity": "sha512-dKkkOzOSwFYe5RX6y26fZgkSpVAlIOJKQHIiydQcrWH6y/97+RceSOAdjZ14Qa3zLduVUy0TXcn+EiM6t4rPgw==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@next/eslint-plugin-next": {
|
"node_modules/@next/eslint-plugin-next": {
|
||||||
@@ -1052,9 +1054,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@next/swc-darwin-arm64": {
|
"node_modules/@next/swc-darwin-arm64": {
|
||||||
"version": "16.1.6",
|
"version": "16.2.4",
|
||||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.1.6.tgz",
|
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.2.4.tgz",
|
||||||
"integrity": "sha512-wTzYulosJr/6nFnqGW7FrG3jfUUlEf8UjGA0/pyypJl42ExdVgC6xJgcXQ+V8QFn6niSG2Pb8+MIG1mZr2vczw==",
|
"integrity": "sha512-OXTFFox5EKN1Ym08vfrz+OXxmCcEjT4SFMbNRsWZE99dMqt2Kcusl5MqPXcW232RYkMLQTy0hqgAMEsfEd/l2A==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -1068,9 +1070,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@next/swc-darwin-x64": {
|
"node_modules/@next/swc-darwin-x64": {
|
||||||
"version": "16.1.6",
|
"version": "16.2.4",
|
||||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.1.6.tgz",
|
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.2.4.tgz",
|
||||||
"integrity": "sha512-BLFPYPDO+MNJsiDWbeVzqvYd4NyuRrEYVB5k2N3JfWncuHAy2IVwMAOlVQDFjj+krkWzhY2apvmekMkfQR0CUQ==",
|
"integrity": "sha512-XhpVnUfmYWvD3YrXu55XdcAkQtOnvaI6wtQa8fuF5fGoKoxIUZ0kWPtcOfqJEWngFF/lOS9l3+O9CcownhiQxQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -1084,9 +1086,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@next/swc-linux-arm64-gnu": {
|
"node_modules/@next/swc-linux-arm64-gnu": {
|
||||||
"version": "16.1.6",
|
"version": "16.2.4",
|
||||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.1.6.tgz",
|
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.2.4.tgz",
|
||||||
"integrity": "sha512-OJYkCd5pj/QloBvoEcJ2XiMnlJkRv9idWA/j0ugSuA34gMT6f5b7vOiCQHVRpvStoZUknhl6/UxOXL4OwtdaBw==",
|
"integrity": "sha512-Mx/tjlNA3G8kg14QvuGAJ4xBwPk1tUHq56JxZ8CXnZwz1Etz714soCEzGQQzVMz4bEnGPowzkV6Xrp6wAkEWOQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -1100,9 +1102,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@next/swc-linux-arm64-musl": {
|
"node_modules/@next/swc-linux-arm64-musl": {
|
||||||
"version": "16.1.6",
|
"version": "16.2.4",
|
||||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.1.6.tgz",
|
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.2.4.tgz",
|
||||||
"integrity": "sha512-S4J2v+8tT3NIO9u2q+S0G5KdvNDjXfAv06OhfOzNDaBn5rw84DGXWndOEB7d5/x852A20sW1M56vhC/tRVbccQ==",
|
"integrity": "sha512-iVMMp14514u7Nup2umQS03nT/bN9HurK8ufylC3FZNykrwjtx7V1A7+4kvhbDSCeonTVqV3Txnv0Lu+m2oDXNg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -1116,9 +1118,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@next/swc-linux-x64-gnu": {
|
"node_modules/@next/swc-linux-x64-gnu": {
|
||||||
"version": "16.1.6",
|
"version": "16.2.4",
|
||||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.1.6.tgz",
|
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.2.4.tgz",
|
||||||
"integrity": "sha512-2eEBDkFlMMNQnkTyPBhQOAyn2qMxyG2eE7GPH2WIDGEpEILcBPI/jdSv4t6xupSP+ot/jkfrCShLAa7+ZUPcJQ==",
|
"integrity": "sha512-EZOvm1aQWgnI/N/xcWOlnS3RQBk0VtVav5Zo7n4p0A7UKyTDx047k8opDbXgBpHl4CulRqRfbw3QrX2w5UOXMQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -1132,9 +1134,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@next/swc-linux-x64-musl": {
|
"node_modules/@next/swc-linux-x64-musl": {
|
||||||
"version": "16.1.6",
|
"version": "16.2.4",
|
||||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.1.6.tgz",
|
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.2.4.tgz",
|
||||||
"integrity": "sha512-oicJwRlyOoZXVlxmIMaTq7f8pN9QNbdes0q2FXfRsPhfCi8n8JmOZJm5oo1pwDaFbnnD421rVU409M3evFbIqg==",
|
"integrity": "sha512-h9FxsngCm9cTBf71AR4fGznDEDx1hS7+kSEiIRjq5kO1oXWm07DxVGZjCvk0SGx7TSjlUqhI8oOyz7NfwAdPoA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -1148,9 +1150,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@next/swc-win32-arm64-msvc": {
|
"node_modules/@next/swc-win32-arm64-msvc": {
|
||||||
"version": "16.1.6",
|
"version": "16.2.4",
|
||||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.1.6.tgz",
|
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.2.4.tgz",
|
||||||
"integrity": "sha512-gQmm8izDTPgs+DCWH22kcDmuUp7NyiJgEl18bcr8irXA5N2m2O+JQIr6f3ct42GOs9c0h8QF3L5SzIxcYAAXXw==",
|
"integrity": "sha512-3NdJV5OXMSOeJYijX+bjaLge3mJBlh4ybydbT4GFoB/2hAojWHtMhl3CYlYoMrjPuodp0nzFVi4Tj2+WaMg+Ow==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -1164,9 +1166,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@next/swc-win32-x64-msvc": {
|
"node_modules/@next/swc-win32-x64-msvc": {
|
||||||
"version": "16.1.6",
|
"version": "16.2.4",
|
||||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.1.6.tgz",
|
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.2.4.tgz",
|
||||||
"integrity": "sha512-NRfO39AIrzBnixKbjuo2YiYhB6o9d8v/ymU9m/Xk8cyVk+k7XylniXkHwjs4s70wedVffc6bQNbufk5v0xEm0A==",
|
"integrity": "sha512-kMVGgsqhO5YTYODD9IPGGhA6iprWidQckK3LmPeW08PIFENRmgfb4MjXHO+p//d+ts2rpjvK5gXWzXSMrPl9cw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -1562,6 +1564,7 @@
|
|||||||
"integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==",
|
"integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"csstype": "^3.2.2"
|
"csstype": "^3.2.2"
|
||||||
}
|
}
|
||||||
@@ -1621,6 +1624,7 @@
|
|||||||
"integrity": "sha512-klQbnPAAiGYFyI02+znpBRLyjL4/BrBd0nyWkdC0s/6xFLkXYQ8OoRrSkqacS1ddVxf/LDyODIKbQ5TgKAf/Fg==",
|
"integrity": "sha512-klQbnPAAiGYFyI02+znpBRLyjL4/BrBd0nyWkdC0s/6xFLkXYQ8OoRrSkqacS1ddVxf/LDyODIKbQ5TgKAf/Fg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/scope-manager": "8.56.1",
|
"@typescript-eslint/scope-manager": "8.56.1",
|
||||||
"@typescript-eslint/types": "8.56.1",
|
"@typescript-eslint/types": "8.56.1",
|
||||||
@@ -1775,9 +1779,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": {
|
"node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": {
|
||||||
"version": "5.0.4",
|
"version": "5.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz",
|
||||||
"integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==",
|
"integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -2146,6 +2150,7 @@
|
|||||||
"integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==",
|
"integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"acorn": "bin/acorn"
|
"acorn": "bin/acorn"
|
||||||
},
|
},
|
||||||
@@ -2446,9 +2451,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/brace-expansion": {
|
"node_modules/brace-expansion": {
|
||||||
"version": "1.1.12",
|
"version": "1.1.14",
|
||||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
|
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz",
|
||||||
"integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
|
"integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -2489,6 +2494,7 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"baseline-browser-mapping": "^2.9.0",
|
"baseline-browser-mapping": "^2.9.0",
|
||||||
"caniuse-lite": "^1.0.30001759",
|
"caniuse-lite": "^1.0.30001759",
|
||||||
@@ -3051,25 +3057,26 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/eslint": {
|
"node_modules/eslint": {
|
||||||
"version": "9.39.3",
|
"version": "9.39.4",
|
||||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.3.tgz",
|
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.4.tgz",
|
||||||
"integrity": "sha512-VmQ+sifHUbI/IcSopBCF/HO3YiHQx/AVd3UVyYL6weuwW+HvON9VYn5l6Zl1WZzPWXPNZrSQpxwkkZ/VuvJZzg==",
|
"integrity": "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/eslint-utils": "^4.8.0",
|
"@eslint-community/eslint-utils": "^4.8.0",
|
||||||
"@eslint-community/regexpp": "^4.12.1",
|
"@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/config-helpers": "^0.4.2",
|
||||||
"@eslint/core": "^0.17.0",
|
"@eslint/core": "^0.17.0",
|
||||||
"@eslint/eslintrc": "^3.3.1",
|
"@eslint/eslintrc": "^3.3.5",
|
||||||
"@eslint/js": "9.39.3",
|
"@eslint/js": "9.39.4",
|
||||||
"@eslint/plugin-kit": "^0.4.1",
|
"@eslint/plugin-kit": "^0.4.1",
|
||||||
"@humanfs/node": "^0.16.6",
|
"@humanfs/node": "^0.16.6",
|
||||||
"@humanwhocodes/module-importer": "^1.0.1",
|
"@humanwhocodes/module-importer": "^1.0.1",
|
||||||
"@humanwhocodes/retry": "^0.4.2",
|
"@humanwhocodes/retry": "^0.4.2",
|
||||||
"@types/estree": "^1.0.6",
|
"@types/estree": "^1.0.6",
|
||||||
"ajv": "^6.12.4",
|
"ajv": "^6.14.0",
|
||||||
"chalk": "^4.0.0",
|
"chalk": "^4.0.0",
|
||||||
"cross-spawn": "^7.0.6",
|
"cross-spawn": "^7.0.6",
|
||||||
"debug": "^4.3.2",
|
"debug": "^4.3.2",
|
||||||
@@ -3088,7 +3095,7 @@
|
|||||||
"is-glob": "^4.0.0",
|
"is-glob": "^4.0.0",
|
||||||
"json-stable-stringify-without-jsonify": "^1.0.1",
|
"json-stable-stringify-without-jsonify": "^1.0.1",
|
||||||
"lodash.merge": "^4.6.2",
|
"lodash.merge": "^4.6.2",
|
||||||
"minimatch": "^3.1.2",
|
"minimatch": "^3.1.5",
|
||||||
"natural-compare": "^1.4.0",
|
"natural-compare": "^1.4.0",
|
||||||
"optionator": "^0.9.3"
|
"optionator": "^0.9.3"
|
||||||
},
|
},
|
||||||
@@ -3241,6 +3248,7 @@
|
|||||||
"integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==",
|
"integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@rtsao/scc": "^1.1.0",
|
"@rtsao/scc": "^1.1.0",
|
||||||
"array-includes": "^3.1.9",
|
"array-includes": "^3.1.9",
|
||||||
@@ -3599,9 +3607,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/flatted": {
|
"node_modules/flatted": {
|
||||||
"version": "3.3.4",
|
"version": "3.4.2",
|
||||||
"resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.4.tgz",
|
"resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz",
|
||||||
"integrity": "sha512-3+mMldrTAPdta5kjX2G2J7iX4zxtnwpdA8Tr2ZSjkyPSanvbZAcy6flmtnXbEybHrDcU9641lxrMfFuUxVz9vA==",
|
"integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
@@ -4994,14 +5002,14 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/next": {
|
"node_modules/next": {
|
||||||
"version": "16.1.6",
|
"version": "16.2.4",
|
||||||
"resolved": "https://registry.npmjs.org/next/-/next-16.1.6.tgz",
|
"resolved": "https://registry.npmjs.org/next/-/next-16.2.4.tgz",
|
||||||
"integrity": "sha512-hkyRkcu5x/41KoqnROkfTm2pZVbKxvbZRuNvKXLRXxs3VfyO0WhY50TQS40EuKO9SW3rBj/sF3WbVwDACeMZyw==",
|
"integrity": "sha512-kPvz56wF5frc+FxlHI5qnklCzbq53HTwORaWBGdT0vNoKh1Aya9XC8aPauH4NJxqtzbWsS5mAbctm4cr+EkQ2Q==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@next/env": "16.1.6",
|
"@next/env": "16.2.4",
|
||||||
"@swc/helpers": "0.5.15",
|
"@swc/helpers": "0.5.15",
|
||||||
"baseline-browser-mapping": "^2.8.3",
|
"baseline-browser-mapping": "^2.9.19",
|
||||||
"caniuse-lite": "^1.0.30001579",
|
"caniuse-lite": "^1.0.30001579",
|
||||||
"postcss": "8.4.31",
|
"postcss": "8.4.31",
|
||||||
"styled-jsx": "5.1.6"
|
"styled-jsx": "5.1.6"
|
||||||
@@ -5013,15 +5021,15 @@
|
|||||||
"node": ">=20.9.0"
|
"node": ">=20.9.0"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@next/swc-darwin-arm64": "16.1.6",
|
"@next/swc-darwin-arm64": "16.2.4",
|
||||||
"@next/swc-darwin-x64": "16.1.6",
|
"@next/swc-darwin-x64": "16.2.4",
|
||||||
"@next/swc-linux-arm64-gnu": "16.1.6",
|
"@next/swc-linux-arm64-gnu": "16.2.4",
|
||||||
"@next/swc-linux-arm64-musl": "16.1.6",
|
"@next/swc-linux-arm64-musl": "16.2.4",
|
||||||
"@next/swc-linux-x64-gnu": "16.1.6",
|
"@next/swc-linux-x64-gnu": "16.2.4",
|
||||||
"@next/swc-linux-x64-musl": "16.1.6",
|
"@next/swc-linux-x64-musl": "16.2.4",
|
||||||
"@next/swc-win32-arm64-msvc": "16.1.6",
|
"@next/swc-win32-arm64-msvc": "16.2.4",
|
||||||
"@next/swc-win32-x64-msvc": "16.1.6",
|
"@next/swc-win32-x64-msvc": "16.2.4",
|
||||||
"sharp": "^0.34.4"
|
"sharp": "^0.34.5"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@opentelemetry/api": "^1.1.0",
|
"@opentelemetry/api": "^1.1.0",
|
||||||
@@ -5338,9 +5346,9 @@
|
|||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
"node_modules/picomatch": {
|
"node_modules/picomatch": {
|
||||||
"version": "2.3.1",
|
"version": "2.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz",
|
||||||
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
|
"integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -5361,9 +5369,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/postcss": {
|
"node_modules/postcss": {
|
||||||
"version": "8.5.6",
|
"version": "8.5.12",
|
||||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz",
|
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.12.tgz",
|
||||||
"integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==",
|
"integrity": "sha512-W62t/Se6rA0Az3DfCL0AqJwXuKwBeYg6nOaIgzP+xZ7N5BFCI7DYi1qs6ygUYT6rvfi6t9k65UMLJC+PHZpDAA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -5447,6 +5455,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react/-/react-19.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/react/-/react-19.2.3.tgz",
|
||||||
"integrity": "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==",
|
"integrity": "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
@@ -5456,6 +5465,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.3.tgz",
|
||||||
"integrity": "sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==",
|
"integrity": "sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"scheduler": "^0.27.0"
|
"scheduler": "^0.27.0"
|
||||||
},
|
},
|
||||||
@@ -6139,11 +6149,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/tinyglobby/node_modules/picomatch": {
|
"node_modules/tinyglobby/node_modules/picomatch": {
|
||||||
"version": "4.0.3",
|
"version": "4.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
|
||||||
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
"integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
},
|
},
|
||||||
@@ -6306,6 +6317,7 @@
|
|||||||
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
|
"peer": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"tsc": "bin/tsc",
|
"tsc": "bin/tsc",
|
||||||
"tsserver": "bin/tsserver"
|
"tsserver": "bin/tsserver"
|
||||||
@@ -6581,6 +6593,7 @@
|
|||||||
"integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==",
|
"integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://github.com/sponsors/colinhacks"
|
"url": "https://github.com/sponsors/colinhacks"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,25 +2,28 @@
|
|||||||
"name": "portfolio",
|
"name": "portfolio",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev",
|
"dev": "next dev",
|
||||||
"build": "next build",
|
"build": "next build",
|
||||||
"start": "next start",
|
"start": "next start",
|
||||||
"lint": "eslint"
|
"lint": "eslint .",
|
||||||
|
"lint:fix": "eslint . --fix"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"lucide-react": "^0.576.0",
|
"lucide-react": "^0.576.0",
|
||||||
"next": "16.1.6",
|
"next": "^16.2.4",
|
||||||
"react": "19.2.3",
|
"react": "19.2.3",
|
||||||
"react-dom": "19.2.3"
|
"react-dom": "19.2.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@eslint/eslintrc": "^3.3.5",
|
||||||
"@tailwindcss/postcss": "^4",
|
"@tailwindcss/postcss": "^4",
|
||||||
"@types/node": "^20",
|
"@types/node": "^20",
|
||||||
"@types/react": "^19",
|
"@types/react": "^19",
|
||||||
"@types/react-dom": "^19",
|
"@types/react-dom": "^19",
|
||||||
"eslint": "^9",
|
"eslint": "^9.39.4",
|
||||||
"eslint-config-next": "16.1.6",
|
"eslint-config-next": "^16.1.6",
|
||||||
"tailwindcss": "^4",
|
"tailwindcss": "^4",
|
||||||
"typescript": "5.9.3"
|
"typescript": "5.9.3"
|
||||||
}
|
}
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 71 KiB |
|
Before Width: | Height: | Size: 86 KiB |
|
Before Width: | Height: | Size: 323 KiB |
|
Before Width: | Height: | Size: 275 KiB |
|
Before Width: | Height: | Size: 141 KiB |
|
Before Width: | Height: | Size: 1003 KiB |
|
Before Width: | Height: | Size: 512 KiB |
|
Before Width: | Height: | Size: 120 KiB |
|
Before Width: | Height: | Size: 349 KiB |
|
Before Width: | Height: | Size: 380 KiB |
|
Before Width: | Height: | Size: 282 KiB |
|
Before Width: | Height: | Size: 368 KiB |
|
Before Width: | Height: | Size: 49 KiB |
|
Before Width: | Height: | Size: 6.1 KiB |
|
Before Width: | Height: | Size: 116 KiB |
|
Before Width: | Height: | Size: 92 KiB |
|
Before Width: | Height: | Size: 78 KiB |
|
Before Width: | Height: | Size: 1.8 MiB |
|
Before Width: | Height: | Size: 56 KiB |
|
Before Width: | Height: | Size: 134 KiB |
|
Before Width: | Height: | Size: 250 KiB |
|
Before Width: | Height: | Size: 698 KiB |
|
Before Width: | Height: | Size: 1.1 MiB |
|
Before Width: | Height: | Size: 330 KiB |
|
Before Width: | Height: | Size: 121 KiB |
|
Before Width: | Height: | Size: 174 KiB |
|
Before Width: | Height: | Size: 36 KiB |
|
Before Width: | Height: | Size: 448 KiB |
|
Before Width: | Height: | Size: 478 KiB |
|
Before Width: | Height: | Size: 363 KiB |
|
Before Width: | Height: | Size: 333 KiB |
|
Before Width: | Height: | Size: 136 KiB |
|
Before Width: | Height: | Size: 82 KiB |
|
Before Width: | Height: | Size: 82 KiB |
|
Before Width: | Height: | Size: 722 KiB |