feat: recover portfolio pages from scratch workspaces
- Add base layouts (BaseLayout, BlogLayout, ProjectLayout) - Add UI components (Header, Footer, Navigation, Card, Tag) - Add About page with personal story - Add Projects pages (index, detail) - Add homepage content - Add SEO files (robots.txt, webmanifest) Work was done by agents in isolated workspaces. Consolidated into main repo for proper git tracking.
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
---
|
||||
import '../styles/global.css';
|
||||
|
||||
export interface Props {
|
||||
title: string;
|
||||
description: string;
|
||||
image?: string;
|
||||
}
|
||||
|
||||
const { title, description, image } = Astro.props;
|
||||
const canonicalURL = new URL(Astro.url.pathname, Astro.site);
|
||||
const socialImage = image ? new URL(image, Astro.site) : new URL('/images/og-default.jpg', Astro.site);
|
||||
---
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="es">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{title} | David Aragón - Indie Builder</title>
|
||||
<meta name="description" content={description}>
|
||||
<link rel="canonical" href={canonicalURL} />
|
||||
|
||||
<!-- Open Graph -->
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:url" content={canonicalURL} />
|
||||
<meta property="og:title" content={title} />
|
||||
<meta property="og:description" content={description} />
|
||||
<meta property="og:image" content={socialImage} />
|
||||
|
||||
<!-- Twitter Card -->
|
||||
<meta name="twitter:card" content="summary_large_image" />
|
||||
<meta name="twitter:url" content={canonicalURL} />
|
||||
<meta name="twitter:title" content={title} />
|
||||
<meta name="twitter:description" content={description} />
|
||||
<meta name="twitter:image" content={socialImage} />
|
||||
|
||||
<!-- Favicon -->
|
||||
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
|
||||
|
||||
<!-- Fonts -->
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
|
||||
</head>
|
||||
<body class="min-h-screen flex flex-col">
|
||||
<slot />
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,34 @@
|
||||
---
|
||||
const blogPostJsonLd = {
|
||||
"@context": "https://schema.org",
|
||||
"@type": "BlogPosting",
|
||||
"headline": "{title}",
|
||||
"description": "{description}",
|
||||
"image": "{socialImage}",
|
||||
"datePublished": "{publishDate}",
|
||||
"author": {
|
||||
"@type": "Person",
|
||||
"name": "David Aragón",
|
||||
"url": "https://davidaragon.impresion3d.pro"
|
||||
},
|
||||
"publisher": {
|
||||
"@type": "Person",
|
||||
"name": "David Aragón",
|
||||
"url": "https://davidaragon.impresion3d.pro"
|
||||
},
|
||||
"keywords": "{keywords}",
|
||||
"articleSection": "{category}",
|
||||
"inLanguage": "es-ES"
|
||||
};
|
||||
---
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="es">
|
||||
<head>
|
||||
<!-- JSON-LD Blog Structured Data -->
|
||||
<script type="application/ld+json" set:html={JSON.stringify(blogPostJsonLd)} />
|
||||
</head>
|
||||
<body>
|
||||
<!-- Blog content -->
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,95 @@
|
||||
---
|
||||
import BaseLayout from './BaseLayout.astro';
|
||||
import Header from '../components/layout/Header.astro';
|
||||
import Footer from '../components/layout/Footer.astro';
|
||||
import Tag from '../components/ui/Tag.astro';
|
||||
import { formatDate } from '../utils/dateFormat';
|
||||
|
||||
export interface Props {
|
||||
title: string;
|
||||
description: string;
|
||||
url: string;
|
||||
github?: string;
|
||||
status: string;
|
||||
tags: string[];
|
||||
startDate: Date;
|
||||
image?: string;
|
||||
}
|
||||
|
||||
const { title, description, url, github, status, tags, startDate, image } = Astro.props;
|
||||
|
||||
const statusColors = {
|
||||
active: 'text-accent-green',
|
||||
development: 'text-accent-yellow',
|
||||
completed: 'text-text-tertiary',
|
||||
};
|
||||
---
|
||||
|
||||
<BaseLayout title={title} description={description} image={image}>
|
||||
<Header />
|
||||
<main class="flex-1">
|
||||
<article class="max-w-5xl mx-auto px-4 sm:px-6 lg:px-8 py-12">
|
||||
<header class="mb-12">
|
||||
<div class="flex items-center gap-3 mb-4">
|
||||
<span class={`text-sm font-semibold uppercase tracking-wide ${statusColors[status] || 'text-text-tertiary'}`}>
|
||||
{status}
|
||||
</span>
|
||||
<span class="text-text-tertiary">•</span>
|
||||
<time datetime={startDate.toISOString()} class="text-sm text-text-tertiary">
|
||||
Desde {formatDate(startDate)}
|
||||
</time>
|
||||
</div>
|
||||
|
||||
<h1 class="text-4xl md:text-5xl font-bold mb-4">{title}</h1>
|
||||
<p class="text-xl text-text-secondary mb-6">{description}</p>
|
||||
|
||||
<div class="flex flex-wrap gap-3">
|
||||
<a
|
||||
href={url}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="px-6 py-3 bg-primary hover:bg-primary/80 text-background rounded-lg
|
||||
font-semibold transition-colors"
|
||||
>
|
||||
Ver Proyecto →
|
||||
</a>
|
||||
{github && (
|
||||
<a
|
||||
href={github}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="px-6 py-3 bg-surface hover:bg-surface/80 text-text-primary rounded-lg
|
||||
font-semibold border border-text-tertiary/20 transition-colors"
|
||||
>
|
||||
GitHub →
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
</header>
|
||||
|
||||
{image && (
|
||||
<div class="mb-12 rounded-xl overflow-hidden border border-text-tertiary/20">
|
||||
<img
|
||||
src={image}
|
||||
alt={title}
|
||||
class="w-full h-auto"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div class="prose prose-invert prose-lg max-w-none">
|
||||
<slot />
|
||||
</div>
|
||||
|
||||
<footer class="mt-12 pt-8 border-t border-text-tertiary/20">
|
||||
<h3 class="text-lg font-semibold mb-4">Tecnologías</h3>
|
||||
<div class="flex flex-wrap gap-2">
|
||||
{tags.map(tag => (
|
||||
<Tag label={tag} variant="neutral" />
|
||||
))}
|
||||
</div>
|
||||
</footer>
|
||||
</article>
|
||||
</main>
|
||||
<Footer />
|
||||
</BaseLayout>
|
||||
Reference in New Issue
Block a user