feat: initial portfolio implementation with dark mode and i18n

- Add Astro portfolio with TypeScript
- Implement dark/light theme toggle
- Add Spanish/English translations
- Create under construction page
- Style with Tailwind CSS and glassmorphism effects
- Add profile image, projects, skills, and experience sections
This commit is contained in:
Itziar Zameza García
2026-03-14 22:41:48 +01:00
parent 085cc4c6cb
commit 476dd54c0e
13 changed files with 4546 additions and 16 deletions
+7 -1
View File
@@ -1,5 +1,11 @@
// @ts-check
import { defineConfig } from 'astro/config';
import tailwindcss from '@tailwindcss/vite';
// https://astro.build/config
export default defineConfig({});
export default defineConfig({
vite: {
plugins: [tailwindcss()]
}
});
+5 -1
View File
@@ -12,6 +12,10 @@
"astro": "astro"
},
"dependencies": {
"astro": "^6.0.4"
"@astrojs/check": "^0.9.7",
"@tailwindcss/vite": "^4.2.1",
"astro": "^6.0.4",
"astro-i18n": "^2.2.4",
"tailwindcss": "^4.2.1"
}
}
+3967
View File
File diff suppressed because it is too large Load Diff
+20
View File
@@ -0,0 +1,20 @@
(function () {
const savedLang = localStorage.getItem("language") || "en";
const htmlLang = document.documentElement.lang || "en";
const currentLang = savedLang || htmlLang;
window.setLanguage = function (lang) {
localStorage.setItem("language", lang);
location.reload();
};
window.getCurrentLanguage = function () {
return localStorage.getItem("language") || "en";
};
window.toggleLanguage = function () {
const currentLang = getCurrentLanguage();
const newLang = currentLang === "en" ? "es" : "en";
setLanguage(newLang);
};
})();
+15
View File
@@ -0,0 +1,15 @@
(function() {
const theme = localStorage.getItem('theme');
const systemPrefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
const initialTheme = theme || (systemPrefersDark ? 'dark' : 'light');
document.documentElement.classList.toggle('dark', initialTheme === 'dark');
window.toggleTheme = function() {
const currentTheme = document.documentElement.classList.contains('dark') ? 'dark' : 'light';
const newTheme = currentTheme === 'dark' ? 'light' : 'dark';
document.documentElement.classList.toggle('dark');
localStorage.setItem('theme', newTheme);
};
})();
+115
View File
@@ -0,0 +1,115 @@
export const translations = {
en: {
nav: {
home: 'Home',
projects: 'Projects',
stack: 'Stack',
contact: 'Contact',
},
hero: {
available: 'Available for Projects',
title: 'Product Designer &',
gradientText: 'Tech Strategist',
description: 'Fusing avant-garde aesthetics with technical functionality to create high-impact digital experiences.',
startProject: 'Start a project',
},
about: {
title: 'About Me',
description: 'Specialized in transforming <span class="font-bold">complex infrastructures</span> into intuitive interfaces. My approach combines user-centered design with a solid <span class="italic">strategic vision</span> of product.',
},
projects: {
title: 'Selected Works',
subtitle: 'Featured case studies',
viewAll: 'View All',
viewProject: 'View Project',
},
techStack: {
title: 'Tech Curated Stack',
categories: {
design: {
title: 'Design',
items: 'Figma, Framer, Adobe CC, Prototyping.',
},
frontend: {
title: 'Frontend',
items: 'React, Tailwind, Next.js, Typescript.',
},
stack: {
title: 'Stack',
items: 'PostgreSQL, Supabase, Node.js, API Design.',
},
product: {
title: 'Product',
items: 'Agile, SCRUM, Notion, Linear, Strategy.',
},
},
},
cta: {
title: 'Ready to scale?',
description: "Let's work together to take your product to the next level with world-class design.",
letsTalk: "Let's talk",
},
experience: {
title: 'Experience',
present: 'Present',
},
},
es: {
nav: {
home: 'Inicio',
projects: 'Proyectos',
stack: 'Stack',
contact: 'Contacto',
},
hero: {
available: 'Disponible para Proyectos',
title: 'Diseñadora de Producto &',
gradientText: 'Estratega Tecnológica',
description: 'Fusionando estética vanguardista con funcionalidad técnica para crear experiencias digitales de alto impacto.',
startProject: 'Iniciar proyecto',
},
about: {
title: 'Sobre mí',
description: 'Especializada en transformar <span class="font-bold">infraestructuras complejas</span> en interfaces intuitivas. Mi enfoque combina el diseño centrado en el usuario con una sólida <span class="italic">visión estratégica</span> de producto.',
},
projects: {
title: 'Trabajos Seleccionados',
subtitle: 'Casos de estudio destacados',
viewAll: 'Ver Todos',
viewProject: 'Ver Proyecto',
},
techStack: {
title: 'Stack Tecnológico Curado',
categories: {
design: {
title: 'Diseño',
items: 'Figma, Framer, Adobe CC, Prototipado.',
},
frontend: {
title: 'Frontend',
items: 'React, Tailwind, Next.js, Typescript.',
},
stack: {
title: 'Stack',
items: 'PostgreSQL, Supabase, Node.js, Diseño API.',
},
product: {
title: 'Producto',
items: 'Agile, SCRUM, Notion, Linear, Estrategia.',
},
},
},
cta: {
title: '¿Listo para escalar?',
description: 'Trabajemos juntos para llevar tu producto al siguiente nivel con diseño de clase mundial.',
letsTalk: 'Hablemos',
},
experience: {
title: 'Experiencia',
present: 'Actualidad',
},
},
};
export type Language = keyof typeof translations;
export type TranslationKey = keyof typeof translations.en;
+29
View File
@@ -0,0 +1,29 @@
---
export interface Props {
title: string;
}
const { title } = Astro.props;
---
<!doctype html>
<html lang="en" class="light">
<head>
<meta charset="UTF-8" />
<meta name="description" content="Astro description" />
<meta name="viewport" content="width=device-width" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="generator" content={Astro.generator} />
<title>{title}</title>
</head>
<body class="bg-background-light dark:bg-background-dark font-display text-slate-900 dark:text-slate-100 min-h-screen pb-24">
<script src="/scripts/theme-toggle.js" is:inline />
<slot />
</body>
</html>
<style>
isolate {
isolation: isolate;
}
</style>
+214 -14
View File
@@ -1,17 +1,217 @@
---
import Layout from '../layouts/Layout.astro';
import '../styles/global.css';
import { translations, type Language } from '../i18n/ui';
const lang: Language = 'en';
const t = translations[lang];
const projects = [
{
id: 1,
title: 'Luminary App',
description: 'A fintech dashboard redesign for high-net-worth individuals.',
url: 'luminary-project.co',
image: 'https://lh3.googleusercontent.com/aida-public/AB6AXuDuiRGNBP07ZrmaH7F-Q5XCG8XcmSnVisQQn-Tq4zMmt4oxFQYhnVmEZ16pqAEXpXmPJ29Xc42MlLHJHMla4Q1dMWqm2apfbWMmKQW4gH3fD35Piy_YM1xG2DEHO_es1DqVWQ1GzgmjaRrLehiCzLynVjvtlIg7p5NL8kDBwKBkPqk_nYfYK7jv1lDBrVN4AZ1Hz_j_sRfkerkDWmP2oaTSQh0gN2DLNyN-r34Nda4Dp3GWFWRjZSlivobGKj0mj0eg7QK_Fqcp5GU',
},
{
id: 2,
title: 'Ether OS',
description: 'A minimalist operating system concept based on spatial UI.',
url: 'ether-spatial.io',
image: 'https://lh3.googleusercontent.com/aida-public/AB6AXuDvWd-Z_6rj37HlgWlrmx1VJHroq2bg6Pv0atKO0GnAF5_74-yfWaASnLWaWh5J6NiThTvt1W3avgzNI3bOpEG0GoVeYjwZxqMwZZRIiaaODFunpArG-H2otP37dkbfuWzOP_QoEWn6INmZ8YFm50k3YDvoCyZNrnv1dETjWlyg2cok9MP4IIqJLDVxp5Yi32R9BUDgxGlVWLUceUR71hTQRKQqKI9jsQPH7E0Y1OLKeCOZ1Wo-RKabzipc2Vtvmo6RtGvT2X0VoSE',
},
];
const skills = [
{ name: 'Visual Design', level: 95, category: 'Expert' },
{ name: 'Prototyping', level: 88, category: 'Advanced' },
{ name: 'Interaction Design', level: 82, category: 'Advanced' },
];
const experience = [
{
period: '2022 - Present',
title: 'Senior UX Designer',
company: 'Studio Vanta • Remote',
description: 'Leading the design language for next-gen SaaS products and immersive web experiences.',
isActive: true,
},
{
period: '2020 - 2022',
title: 'Product Designer',
company: 'Flow Digital • Madrid',
description: 'Conceptualized and launched 4 mobile applications with over 1M combined downloads.',
isActive: false,
},
];
---
---
<Layout title="Itziar ZG - Vanguard CV">
<!-- Top Navigation -->
<nav class="sticky top-0 z-50 flex items-center justify-between p-4 glass-dark">
<div class="flex items-center gap-2">
<span class="material-symbols-outlined text-primary text-3xl">deployed_code</span>
<h1 class="text-xl font-bold tracking-tight">Itziar ZG</h1>
</div>
<div class="flex items-center gap-2">
<button
onclick="toggleLanguage()"
class="p-2 rounded-full hover:bg-primary/10 transition-colors"
>
<span class="material-symbols-outlined text-primary">translate</span>
</button>
<button
onclick="toggleTheme()"
class="p-2 rounded-full hover:bg-primary/10 transition-colors"
>
<span class="material-symbols-outlined text-primary">dark_mode</span>
</button>
</div>
</nav>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width" />
<meta name="generator" content={Astro.generator} />
<title>Astro</title>
</head>
<body>
<h1>Astro</h1>
</body>
</html>
<!-- Hero Section -->
<header class="relative px-6 pt-10 pb-16 overflow-hidden">
<div class="absolute top-0 right-0 -z-10 w-64 h-64 bg-primary/20 rounded-full blur-[100px]"></div>
<div class="absolute bottom-0 left-0 -z-10 w-48 h-48 bg-purple-600/10 rounded-full blur-[80px]"></div>
<div class="flex flex-col items-center text-center gap-6">
<div class="relative p-1 rounded-full bg-gradient-to-tr from-primary to-purple-400">
<div
class="w-32 h-32 rounded-full bg-cover bg-center border-4 border-background-dark"
data-alt="Professional portrait of a female digital designer"
style="background-image: url('https://lh3.googleusercontent.com/aida-public/AB6AXuD6WeB0nJf-ZCuFJ6oa6vOkhHSa7HvieIuXVDVhw_U7ITO-kq3Gi8J9JWbH0WOiEd2zxiItpdWLWJY89C09LQncuy8iD4pjprH8H7aiGUya87L_ap88RqW2GuhhUJHNt74NW_m7y4KGn43RzotxT69wM9i-ri2HEEMQtBZRWPUtWgjSqSguENLtttWkpQrUrXBoy8TXkmvdya-d9S9QKMbaDSVa_6eVpI7uR_BAB1wRlMdbAFlVZVmzUG3HafS5P4jOA1I0nkvNChY')"
></div>
</div>
<div class="space-y-2">
<h2 class="text-4xl font-bold tracking-tighter">Vanguard Designer</h2>
<p class="text-primary font-medium tracking-widest uppercase text-sm">Crafting Digital Excellence</p>
<div class="flex gap-2 justify-center mt-4">
<span class="px-3 py-1 rounded-full text-xs font-semibold glass border border-primary/20">UI/UX</span>
<span class="px-3 py-1 rounded-full text-xs font-semibold glass border border-primary/20">Motion</span>
<span class="px-3 py-1 rounded-full text-xs font-semibold glass border border-primary/20">Strategy</span>
</div>
</div>
</div>
</header>
<!-- About Section -->
<section class="px-6 mb-12">
<div class="glass-dark rounded-xl p-6 space-y-4">
<div class="flex items-center gap-2 text-primary">
<span class="material-symbols-outlined">person</span>
<h3 class="font-bold text-lg">About Me</h3>
</div>
<p class="text-slate-400 leading-relaxed">
A sophisticated designer specializing in high-end digital experiences with a focus on dark aesthetics, glassmorphism, and modern typography. Transforming complex problems into elegant, intuitive interfaces.
</p>
<div class="flex gap-4 pt-2">
<button class="flex-1 bg-primary text-white py-3 rounded-lg font-bold shadow-lg shadow-primary/20">Download CV</button>
<button class="flex-1 border border-primary/30 text-primary py-3 rounded-lg font-bold glass">Contact</button>
</div>
</div>
</section>
<!-- Skills Section -->
<section class="px-6 mb-12">
<h3 class="text-2xl font-bold mb-6 px-1">Core Expertise</h3>
<div class="grid grid-cols-1 gap-4">
<div class="glass-dark p-5 rounded-xl border-l-4 border-primary">
<div class="flex justify-between items-center mb-3">
<span class="font-bold">Visual Design</span>
<span class="text-xs text-primary bg-primary/10 px-2 py-1 rounded">Expert</span>
</div>
<div class="w-full bg-slate-800 h-1.5 rounded-full overflow-hidden">
<div class="bg-primary h-full w-[95%]"></div>
</div>
</div>
<div class="glass-dark p-5 rounded-xl border-l-4 border-primary">
<div class="flex justify-between items-center mb-3">
<span class="font-bold">Prototyping</span>
<span class="text-xs text-primary bg-primary/10 px-2 py-1 rounded">Advanced</span>
</div>
<div class="w-full bg-slate-800 h-1.5 rounded-full overflow-hidden">
<div class="bg-primary h-full w-[88%]"></div>
</div>
</div>
<div class="glass-dark p-5 rounded-xl border-l-4 border-primary">
<div class="flex justify-between items-center mb-3">
<span class="font-bold">Interaction Design</span>
<span class="text-xs text-primary bg-primary/10 px-2 py-1 rounded">Advanced</span>
</div>
<div class="w-full bg-slate-800 h-1.5 rounded-full overflow-hidden">
<div class="bg-primary h-full w-[82%]"></div>
</div>
</div>
</div>
</section>
<!-- Projects Section -->
<section class="px-6 mb-12">
<div class="flex justify-between items-end mb-6 px-1">
<h3 class="text-2xl font-bold">Latest Work</h3>
<a class="text-primary text-sm font-semibold" href="#">View All</a>
</div>
<div class="flex flex-col gap-6">
{projects.map((project) => (
<div class="group relative rounded-xl overflow-hidden glass-dark">
<div
class="h-48 bg-cover bg-center"
data-alt="Abstract purple 3D geometric shapes background"
style={`background-image: url('${project.image}')`}
></div>
<div class="p-5">
<h4 class="text-xl font-bold mb-1">{project.title}</h4>
<p class="text-slate-400 text-sm mb-4">{project.description}</p>
<div class="flex items-center gap-2">
<span class="material-symbols-outlined text-primary text-sm">link</span>
<span class="text-xs font-mono uppercase tracking-widest">{project.url}</span>
</div>
</div>
</div>
))}
</div>
</section>
<!-- Experience Timeline -->
<section class="px-6 mb-12">
<h3 class="text-2xl font-bold mb-6 px-1">Experience</h3>
<div class="space-y-8 relative before:absolute before:left-[11px] before:top-2 before:bottom-2 before:w-0.5 before:bg-primary/20">
{experience.map((job) => (
<div class="relative pl-8">
<div class="absolute left-0 top-1.5 w-[24px] h-[24px] rounded-full bg-background-dark border-2 flex items-center justify-center" class:border-primary={job.isActive} class:border-primary/30={!job.isActive}>
<div class="w-2 h-2 rounded-full bg-primary" class:bg-primary/30={!job.isActive}></div>
</div>
<span class="text-xs font-bold text-primary mb-1 block uppercase tracking-tighter" class:text-slate-500={!job.isActive}>{job.period}</span>
<h4 class="text-lg font-bold">{job.title}</h4>
<p class="text-slate-400 text-sm">{job.company}</p>
<p class="mt-2 text-sm leading-relaxed text-slate-500">{job.description}</p>
</div>
))}
</div>
</section>
<!-- Bottom Navigation Bar -->
<div class="fixed bottom-6 left-1/2 -translate-x-1/2 w-[90%] max-w-md z-50">
<div class="glass-dark rounded-full px-6 py-3 flex items-center justify-between border border-primary/30 shadow-2xl shadow-primary/20">
<a class="flex flex-col items-center gap-1 text-primary" href="#">
<span class="material-symbols-outlined fill-1">home</span>
</a>
<a class="flex flex-col items-center gap-1 text-slate-500" href="#">
<span class="material-symbols-outlined">work</span>
</a>
<a class="flex flex-col items-center gap-1 text-slate-500" href="#">
<span class="material-symbols-outlined">grid_view</span>
</a>
<a class="flex flex-col items-center gap-1 text-slate-500" href="#">
<span class="material-symbols-outlined">mail</span>
</a>
<a class="flex flex-col items-center gap-1 text-slate-500" href="#">
<span class="material-symbols-outlined">person</span>
</a>
</div>
</div>
<script src="/scripts/language-toggle.js" is:inline />
</Layout>
+74
View File
@@ -0,0 +1,74 @@
---
import Layout from '../layouts/Layout.astro';
---
<Layout title="Under Construction - Itziar ZG">
<div class="min-h-screen flex items-center justify-center px-6">
<div class="text-center space-y-8 max-w-2xl">
<!-- Construction Icon -->
<div class="flex justify-center">
<div class="relative">
<div class="w-32 h-32 bg-primary/20 rounded-full flex items-center justify-center animate-pulse">
<span class="material-symbols-outlined text-6xl text-primary">construction</span>
</div>
<div class="absolute -top-2 -right-2 w-8 h-8 bg-yellow-400 rounded-full flex items-center justify-center">
<span class="material-symbols-outlined text-sm text-slate-900">priority_high</span>
</div>
</div>
</div>
<!-- Main Content -->
<div class="space-y-4">
<h1 class="text-4xl font-bold tracking-tighter text-gradient">Under Construction</h1>
<p class="text-xl text-slate-600 dark:text-slate-400">
We're building something amazing!
</p>
<p class="text-slate-500 dark:text-slate-500 leading-relaxed">
This portfolio is currently under development. I'm working hard to bring you an exceptional digital experience with cutting-edge design and innovative features.
</p>
</div>
<!-- Progress Indicator -->
<div class="space-y-3">
<div class="flex justify-between text-sm text-slate-500">
<span>Development Progress</span>
<span>85%</span>
</div>
<div class="w-full bg-slate-200 dark:bg-slate-700 h-2 rounded-full overflow-hidden">
<div class="bg-primary h-full w-[85%] rounded-full animate-pulse"></div>
</div>
</div>
<!-- Contact Options -->
<div class="space-y-4">
<p class="text-sm text-slate-500">
Want to get in touch while I finish building?
</p>
<div class="flex gap-4 justify-center">
<a href="mailto:contact@itziarzg.com" class="glass-dark px-6 py-3 rounded-lg text-primary font-medium flex items-center gap-2 hover:bg-primary/10 transition-colors">
<span class="material-symbols-outlined">email</span>
Email Me
</a>
<a href="#" class="glass-dark px-6 py-3 rounded-lg text-primary font-medium flex items-center gap-2 hover:bg-primary/10 transition-colors">
<span class="material-symbols-outlined">schedule</span>
Check Back Soon
</a>
</div>
</div>
<!-- Footer Info -->
<div class="pt-8 border-t border-slate-200 dark:border-slate-700">
<p class="text-xs text-slate-400">
© 2026 Itziar ZG • Portfolio coming soon • Built with Astro & Tailwind CSS
</p>
</div>
</div>
</div>
<!-- Animated Background Elements -->
<div class="fixed inset-0 -z-10 overflow-hidden">
<div class="absolute top-20 left-20 w-64 h-64 bg-primary/10 rounded-full blur-3xl animate-pulse"></div>
<div class="absolute bottom-20 right-20 w-48 h-48 bg-purple-500/10 rounded-full blur-2xl animate-pulse" style="animation-delay: 1s;"></div>
<div class="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-96 h-96 bg-primary/5 rounded-full blur-3xl animate-pulse" style="animation-delay: 2s;"></div>
</div>
</Layout>
+20
View File
@@ -0,0 +1,20 @@
(function () {
const savedLang = localStorage.getItem("language") || "en";
const htmlLang = document.documentElement.lang || "en";
const currentLang = savedLang || htmlLang;
window.setLanguage = function (lang) {
localStorage.setItem("language", lang);
location.reload();
};
window.getCurrentLanguage = function () {
return localStorage.getItem("language") || "en";
};
window.toggleLanguage = function () {
const currentLang = getCurrentLanguage();
const newLang = currentLang === "en" ? "es" : "en";
setLanguage(newLang);
};
})();
+15
View File
@@ -0,0 +1,15 @@
(function() {
const theme = localStorage.getItem('theme');
const systemPrefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
const initialTheme = theme || (systemPrefersDark ? 'dark' : 'light');
document.documentElement.classList.toggle('dark', initialTheme === 'dark');
window.toggleTheme = function() {
const currentTheme = document.documentElement.classList.contains('dark') ? 'dark' : 'light';
const newTheme = currentTheme === 'dark' ? 'light' : 'dark';
document.documentElement.classList.toggle('dark');
localStorage.setItem('theme', newTheme);
};
})();
+41
View File
@@ -0,0 +1,41 @@
@import "tailwindcss";
@import url("https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300;400;500;600;700&display=swap");
@import url("https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght@100..700,0..1&display=swap");
:root {
--primary: #8c2bee;
--background-light: #f7f6f8;
--background-dark: #0d0614;
}
.glass {
background: rgba(140, 43, 238, 0.05);
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
border: 1px solid rgba(140, 43, 238, 0.1);
}
.dark .glass {
background: rgba(140, 43, 238, 0.05);
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
border: 1px solid rgba(140, 43, 238, 0.1);
}
.glass-dark {
background: rgba(20, 10, 30, 0.6);
backdrop-filter: blur(16px);
-webkit-backdrop-filter: blur(16px);
border: 1px solid rgba(140, 43, 238, 0.2);
}
.text-gradient {
background: linear-gradient(135deg, #8c2bee 0%, #d4a5ff 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
body {
min-height: max(884px, 100dvh);
}
+24
View File
@@ -0,0 +1,24 @@
/** @type {import('tailwindcss').Config} */
export default {
darkMode: 'class',
content: ['./src/**/*.{astro,html,js,ts,jsx,tsx}'],
theme: {
extend: {
colors: {
primary: '#8c2bee',
'background-light': '#f7f6f8',
'background-dark': '#191022',
},
fontFamily: {
display: ['Space Grotesk', 'sans-serif'],
},
borderRadius: {
DEFAULT: '0.5rem',
lg: '1rem',
xl: '1.5rem',
full: '9999px',
},
},
},
plugins: [],
}