first version
This commit is contained in:
commit
33bf3d1e5d
39 files changed
+5197
No files matched your search
@@ -0,0 +1,18 @@
|
||||
---
|
||||
import Section from "./ui/Section.astro";
|
||||
|
||||
const { aboutMe } = Astro.props;
|
||||
|
||||
---
|
||||
|
||||
<Section id="about-me">
|
||||
<h3 class="text-3xl font-bold text-white text-center mb-10">
|
||||
Acerca de mí
|
||||
</h3>
|
||||
{aboutMe.split("\n").map((line: string) => (
|
||||
line.trim() !== "" ? (
|
||||
<p class="text-gray-400 mb-4 text-wrap">{line}</p>
|
||||
) : null
|
||||
))}
|
||||
</Section>
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
---
|
||||
import Section from "./ui/Section.astro";
|
||||
|
||||
const { experience } = Astro.props;
|
||||
|
||||
interface ExperienceProps {
|
||||
role: string;
|
||||
company: string;
|
||||
duration: string;
|
||||
description: string;
|
||||
}
|
||||
---
|
||||
|
||||
<Section id="experience">
|
||||
<h3 class="text-3xl font-bold text-white text-center mb-10">
|
||||
Experiencia
|
||||
</h3>
|
||||
<div class="space-y-12">
|
||||
{experience.map((exp: ExperienceProps) => (
|
||||
<div class="flex gap-x-3 relative group rounded-lg">
|
||||
<div class="relative last:after:hidden after:absolute after:top-0 after:bottom-0 after:start-3.5 after:w-px after:-translate-x-[0.5px] after:bg-gray-200 dark:after:bg-neutral-700 dark:group-hover:after:bg-neutral-600">
|
||||
<div class="relative z-10 size-7 flex justify-center items-center">
|
||||
<div class="size-2 rounded-full bg-white border-2 border-gray-300 group-hover:border-gray-600 dark:bg-neutral-800 dark:border-neutral-600 dark:group-hover:border-neutral-600"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section-card overflow-hidden md:flex">
|
||||
<div class="p-8 flex-1">
|
||||
<span class="text-sm text-sky-400 mb-4 block">
|
||||
{exp.duration}
|
||||
</span>
|
||||
<h4 class="text-xl font-bold text-white mb-2">
|
||||
{exp.role}
|
||||
</h4>
|
||||
<h5 class="text-md font-medium text-gray-500 mb-4">
|
||||
{exp.company}
|
||||
</h5>
|
||||
<p class="text-gray-400 text-wrap">{exp.description}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</Section>
|
||||
@@ -0,0 +1,10 @@
|
||||
---
|
||||
const { name } = Astro.props;
|
||||
---
|
||||
|
||||
<footer class="text-center py-8">
|
||||
<p class="text-gray-500">
|
||||
© {new Date().getFullYear()}
|
||||
{name}. Built with Astro & Tailwind CSS.
|
||||
</p>
|
||||
</footer>
|
||||
@@ -0,0 +1,130 @@
|
||||
---
|
||||
import { navItems } from "@data/index";
|
||||
---
|
||||
|
||||
<header
|
||||
id="header-nav"
|
||||
class="fixed top-0 left-0 right-0 z-50 transition-all duration-300 bg-background/95 ease-in-out"
|
||||
>
|
||||
<div class="container mx-auto px-4">
|
||||
<div class="flex items-center justify-between h-16">
|
||||
{/* Logo */}
|
||||
<a href="#home" class="text-xl font-bold text-foreground"> {"<Aferrer />"} </a>
|
||||
|
||||
{/* Desktop Navigation */}
|
||||
<nav class="hidden md:flex items-center gap-8">
|
||||
{
|
||||
navItems.map((item) => (
|
||||
<a
|
||||
href={item.href}
|
||||
class="text-sm font-medium text-foreground/80 hover:text-foreground transition-colors"
|
||||
>
|
||||
{item.label}
|
||||
</a>
|
||||
))
|
||||
}
|
||||
</nav>
|
||||
|
||||
{/* Mobile Navigation */}
|
||||
<div class="md:hidden">
|
||||
<button
|
||||
id="menu-toggle-button"
|
||||
class="p-2 rounded-md text-foreground hover:bg-foreground/10 transition-colors z-50 relative"
|
||||
>
|
||||
<span id="menu-icon" class="text-2xl">☰</span>
|
||||
</button>
|
||||
<nav
|
||||
id="mobile-menu"
|
||||
class="
|
||||
fixed top-0 left-0 right-0 h-dvh w-full
|
||||
flex flex-col items-center justify-center
|
||||
bg-background/95
|
||||
shadow-md
|
||||
z-40
|
||||
-translate-y-full
|
||||
transition-transform duration-500 ease-in-out
|
||||
bg-[#111827]/95
|
||||
backdrop-blur-md
|
||||
"
|
||||
>
|
||||
<div class="flex flex-col items-center space-y-8">
|
||||
{
|
||||
navItems.map((item) => (
|
||||
<a
|
||||
href={item.href}
|
||||
class="text-xl font-medium text-foreground/80 hover:text-foreground transition-colors"
|
||||
>
|
||||
{item.label}
|
||||
</a>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<script>
|
||||
let scrolled = false;
|
||||
let isMobileMenuOpen = false; // Variable de estado
|
||||
|
||||
const header = document.getElementById("header-nav");
|
||||
const mobileMenu = document.getElementById("mobile-menu");
|
||||
const body = document.body;
|
||||
|
||||
// --- Function to update header style based on scroll and menu state ---
|
||||
function updateHeaderStyle() {
|
||||
scrolled = window.scrollY > 0;
|
||||
|
||||
// The header maintains the blur if:
|
||||
// 1. The page is scrolled OR
|
||||
// 2. The mobile menu is open
|
||||
if (scrolled || isMobileMenuOpen) {
|
||||
header?.classList.add("shadow-md", "backdrop-blur-md");
|
||||
} else {
|
||||
// The blur is only removed if there is NO scroll AND the menu is closed
|
||||
header?.classList.remove("shadow-md", "backdrop-blur-md");
|
||||
}
|
||||
}
|
||||
|
||||
// Add client-side scroll event listener
|
||||
if (typeof window !== "undefined") {
|
||||
window.addEventListener("scroll", updateHeaderStyle);
|
||||
updateHeaderStyle();
|
||||
}
|
||||
|
||||
// Mobile menu toggle
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
const menuButton = document.getElementById("menu-toggle-button");
|
||||
const menuIcon = document.getElementById("menu-icon");
|
||||
const mobileLinks = document.querySelectorAll("#mobile-menu a");
|
||||
|
||||
if (!menuButton || !menuIcon || !mobileMenu) return;
|
||||
|
||||
const closeMobileMenu = () => {
|
||||
mobileMenu.classList.add("-translate-y-full");
|
||||
mobileMenu.classList.remove("translate-y-0");
|
||||
body.classList.remove("overflow-hidden");
|
||||
menuIcon.textContent = "☰";
|
||||
updateHeaderStyle();
|
||||
};
|
||||
|
||||
menuButton?.addEventListener("click", () => {
|
||||
isMobileMenuOpen = !isMobileMenuOpen;
|
||||
if (isMobileMenuOpen) {
|
||||
mobileMenu.classList.remove("-translate-y-full");
|
||||
mobileMenu.classList.add("translate-y-0");
|
||||
body.classList.add("overflow-hidden");
|
||||
menuIcon.textContent = "✕";
|
||||
} else {
|
||||
closeMobileMenu();
|
||||
}
|
||||
updateHeaderStyle();
|
||||
});
|
||||
|
||||
mobileLinks.forEach(link => {
|
||||
link.addEventListener("click", closeMobileMenu);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,88 @@
|
||||
---
|
||||
import { Icon } from 'astro-icon/components'
|
||||
|
||||
const { name, title, bio, github, linkedin } = Astro.props;
|
||||
---
|
||||
<section id="hero" class="py-20 md:py-32 flex flex-col items-center justify-center min-h-[90vh]">
|
||||
<div class="flex flex-col md:flex-row items-center md:items-center text-center md:text-left max-w-4xl w-full">
|
||||
<div class="mb-6 md:mb-0 md:mr-12 flex-shrink-0 relative group">
|
||||
<img
|
||||
src="/avatar.webp"
|
||||
alt={`${name} Avatar`}
|
||||
class="w-32 h-32 md:w-48 md:h-48 rounded-full mx-auto border-4 border-slate-600 md:border-slate-300 relative z-20"
|
||||
/>
|
||||
<div class="absolute -inset-1 rounded-full blur-md bg-gradient-to-br from-slate-500 via-cyan-500 to-indigo-500 z-10 glow"></div>
|
||||
</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<h1
|
||||
class="text-4xl md:text-6xl font-extrabold tracking-tight bg-gradient-to-r from-slate-300 to-slate-500 bg-clip-text text-transparent mb-4 text-balance"
|
||||
>
|
||||
{name}
|
||||
</h1>
|
||||
<h2
|
||||
class="text-2xl md:text-3xl font-semibold tracking-tight bg-gradient-to-r from-cyan-400 to-indigo-400 bg-clip-text text-transparent mb-6"
|
||||
>
|
||||
{title}
|
||||
</h2>
|
||||
<p class="text-lg text-gray-400 max-w-full text-wrap">{bio}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-8 flex space-x-6 items-center justify-center max-w-4xl w-full">
|
||||
<a
|
||||
href={github}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="text-gray-400 hover:text-gray-200 transition-colors hover:scale-110 duration-500"
|
||||
aria-label="GitHub"
|
||||
>
|
||||
<Icon name="gitea" class="w-8 h-8" />
|
||||
</a>
|
||||
<a
|
||||
href={linkedin}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="text-gray-400 hover:text-gray-200 transition-colors hover:scale-110 duration-500"
|
||||
aria-label="LinkedIn"
|
||||
>
|
||||
<Icon name="linkedin" class="w-8 h-8" />
|
||||
</a>
|
||||
</div>
|
||||
</section>
|
||||
<style>
|
||||
/* Optional: Add any additional styles for the Hero component here */
|
||||
#header-nav {
|
||||
animation: blur linear both;
|
||||
animation-timeline: scroll();
|
||||
animation-range: 0 500px;
|
||||
/* height: 80px; */
|
||||
background: rgba(255, 255, 255, 0.8);
|
||||
backdrop-filter: blur(0px);
|
||||
}
|
||||
/* Glow siempre visible */
|
||||
.glow {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
transition: transform 0.3s ease-out, opacity 0.3s ease-out;
|
||||
}
|
||||
|
||||
/* Efecto pulsante al hacer hover */
|
||||
.group:hover .glow {
|
||||
animation: pulse 1.5s infinite;
|
||||
}
|
||||
|
||||
/* Animación de pulso */
|
||||
@keyframes pulse {
|
||||
0% {
|
||||
transform: scale(1);
|
||||
opacity: 0.6;
|
||||
}
|
||||
50% {
|
||||
transform: scale(1.1);
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
transform: scale(1);
|
||||
opacity: 0.6;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,69 @@
|
||||
---
|
||||
import Section from "./ui/Section.astro";
|
||||
|
||||
const { projects } = Astro.props;
|
||||
|
||||
interface project {
|
||||
title: string;
|
||||
description: string;
|
||||
tags: string[];
|
||||
liveUrl?: string;
|
||||
repoUrl: string;
|
||||
}
|
||||
---
|
||||
<Section id="projects">
|
||||
<h3 class="text-3xl font-bold text-white text-center mb-10">
|
||||
Proyectos
|
||||
</h3>
|
||||
<div class="space-y-12">
|
||||
{
|
||||
projects.map((project: project) => (
|
||||
<div class="section-card overflow-hidden md:flex">
|
||||
<div class="p-8 flex-1">
|
||||
<h4 class="text-xl font-bold text-white mb-2">
|
||||
{project.title}
|
||||
</h4>
|
||||
<p class="text-gray-400 mb-4">{project.description}</p>
|
||||
<div class="flex flex-wrap gap-2 mb-6">
|
||||
{project.tags.map((tag) => (
|
||||
<span class="bg-gray-700 text-sky-300 text-xs font-semibold px-2.5 py-1 rounded-full">
|
||||
{tag}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
<div class="flex items-center gap-4">
|
||||
{project.liveUrl && (
|
||||
<a
|
||||
href={project.liveUrl}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="inline-flex items-center gap-2 text-sky-400 hover:text-sky-300 transition-colors"
|
||||
>
|
||||
<span
|
||||
class="iconify"
|
||||
data-icon="mdi:open-in-new"
|
||||
data-inline="false"
|
||||
/>
|
||||
Live Demo
|
||||
</a>
|
||||
)}
|
||||
<a
|
||||
href={project.repoUrl}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="inline-flex items-center gap-2 text-sky-400 hover:text-sky-300 transition-colors"
|
||||
>
|
||||
<span
|
||||
class="iconify"
|
||||
data-icon="mdi:github"
|
||||
data-inline="false"
|
||||
/>
|
||||
Source Code
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
</Section>
|
||||
@@ -0,0 +1,41 @@
|
||||
---
|
||||
import { Icon } from "astro-icon/components";
|
||||
import Section from "./ui/Section.astro";
|
||||
|
||||
const { skills } = Astro.props;
|
||||
|
||||
interface SkillProps {
|
||||
name: string;
|
||||
icon: string;
|
||||
}
|
||||
---
|
||||
|
||||
<Section id="skills">
|
||||
<h3 class="text-3xl font-bold text-white text-center mb-10">
|
||||
Habilidades
|
||||
</h3>
|
||||
<div class="flex items-center justify-between flex-wrap gap-6">
|
||||
{skills.map((skill:SkillProps) => (
|
||||
<div class="flex flex-col items-center justify-center p-6 text-center">
|
||||
<div class="relative group">
|
||||
<!-- Icono -->
|
||||
<Icon
|
||||
name={skill.icon}
|
||||
class="text-4xl mb-3 cursor-pointer"
|
||||
data-inline="false"
|
||||
/>
|
||||
|
||||
<!-- Tooltip con flecha -->
|
||||
<div class="absolute top-full left-1/2 mt-3 -translate-x-1/2 hidden group-hover:flex flex-col items-center">
|
||||
<!-- Cuerpo del tooltip -->
|
||||
<div class="bg-gray-800 text-white text-sm px-2 py-1 rounded shadow-lg whitespace-nowrap relative">
|
||||
{skill.name}
|
||||
<!-- Flechita -->
|
||||
<div class="absolute -top-1 left-1/2 -translate-x-1/2 w-2 h-2 bg-gray-800 rotate-45"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</Section>
|
||||
@@ -0,0 +1,3 @@
|
||||
<section class="container mx-auto max-w-7xl px-6 py-12 md:py-20" id={Astro.props.id}>
|
||||
<slot />
|
||||
</section>
|
||||
Reference in new issue
Block a user