Construire un portfolio open-source moderne avec Nuxt 3 — thèmes CSS, données JSON, SEO automatique, et déploiement Docker.
OpenFolio propose quatre thèmes visuels complets sans JavaScript. Tout repose sur des variables CSS — changer de thème = changer une feuille de style.
Chaque fichier dans assets/themes/ définit les mêmes variables CSS sur :root :
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap');
:root {
/* Couleurs primaires */
--color-primary: #3b82f6;
--color-secondary: #8b5cf6;
--color-accent: #10b981;
/* Fonds */
--bg-primary: #0a0a0a;
--bg-secondary: #111827;
--bg-card: #1f2937;
/* Texte */
--text-primary: #f9fafb;
--text-secondary: #9ca3af;
--text-muted: #6b7280;
/* Typographie */
--font-family: 'Inter', sans-serif;
/* Effets */
--shadow-glow: 0 0 20px rgba(59, 130, 246, 0.3);
--shadow-card: 0 4px 20px rgba(0, 0, 0, 0.4);
}| Thème | Primaire | Secondaire | Ambiance |
|---|---|---|---|
default | #3b82f6 bleu | #8b5cf6 violet | Sombre, professionnel |
cyberpunk | #00ff41 vert néon | #ff0080 rose | Haute intensité |
forest | #10b981 vert | #059669 vert foncé | Naturel, doux |
ocean | #0ea5e9 bleu ciel | #7c3aed violet | Apaisant, lisible |
Une seule ligne dans nuxt.config.ts :
css: ['~/assets/themes/cyberpunk.css'],Nuxt injecte ce CSS en global, avant tout composant. Toutes les variables sont disponibles partout.
<template>
<nav class="header">
<span class="logo">OpenFolio</span>
</nav>
</template>
<style scoped>
.header {
background: var(--bg-secondary);
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}
.logo {
color: var(--color-primary);
font-family: var(--font-family);
font-weight: 700;
}
</style>Règle : jamais de valeur hex codée en dur dans un composant. Toujours var(--...). Si une couleur n'a pas de variable, l'ajouter dans tous les thèmes.
Copier default.css, renommer, modifier les variables :
:root {
--color-primary: #f97316; /* orange */
--color-secondary: #ec4899; /* rose */
--color-accent: #fbbf24; /* ambre */
--bg-primary: #1c1917;
--bg-secondary: #292524;
--bg-card: #3c3330;
--text-primary: #fef3c7;
--text-secondary: #d6d3d1;
--text-muted: #a8a29e;
--font-family: 'Inter', sans-serif;
--shadow-glow: 0 0 20px rgba(249, 115, 22, 0.3);
--shadow-card: 0 4px 20px rgba(0, 0, 0, 0.5);
}Puis dans nuxt.config.ts :
css: ['~/assets/themes/sunset.css'],Chaque thème définit trois animations CSS réutilisables :
@keyframes fadeInUp {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
}
@keyframes pulse-glow {
0%, 100% { box-shadow: var(--shadow-glow); }
50% { box-shadow: 0 0 40px rgba(var(--color-primary-rgb), 0.6); }
}
@keyframes float {
0%, 100% { transform: translateY(0px); }
50% { transform: translateY(-10px); }
}Utilisation dans un composant :
<style scoped>
.card {
animation: fadeInUp 0.6s ease forwards;
animation-delay: calc(var(--index) * 0.1s); /* stagger via CSS var */
}
</style>Le stagger par CSS variable évite d'avoir du JavaScript pour décaler les animations d'entrée.