first commit
This commit is contained in:
143
src/pages/formations.astro
Normal file
143
src/pages/formations.astro
Normal file
@@ -0,0 +1,143 @@
|
||||
---
|
||||
import BaseLayout from '../layouts/BaseLayout.astro';
|
||||
import Reveal from '../components/islands/Reveal';
|
||||
import { loadContent } from '../lib/content';
|
||||
|
||||
const formations = await loadContent('formations');
|
||||
|
||||
function extractLocation(school: string): string {
|
||||
const match = school.match(/(Nantes|Saint\s?Père[^\s]*|Paris|Lyon|Rennes|Lille)/i);
|
||||
return match ? match[1].toUpperCase() : 'FR';
|
||||
}
|
||||
---
|
||||
|
||||
<BaseLayout title="Formations" description="Mon parcours d'étude">
|
||||
<section class="py-24 min-h-screen">
|
||||
<div class="container mx-auto px-4">
|
||||
<Reveal client:load>
|
||||
<div class="mb-16">
|
||||
<div class="flex flex-wrap items-end justify-between gap-4">
|
||||
<div>
|
||||
<p
|
||||
class="font-mono text-xs uppercase tracking-[0.3em] text-[color:var(--color-cyan)] mb-2 flex items-center gap-2"
|
||||
>
|
||||
<span class="led led-cyan"></span>
|
||||
// bpm log · crate digging
|
||||
</p>
|
||||
<h1 class="stencil text-5xl md:text-7xl uppercase leading-none">
|
||||
Mes <span class="text-[color:var(--color-cyan)] glow-text-cyan">formations</span>
|
||||
</h1>
|
||||
</div>
|
||||
<div class="font-mono text-[10px] uppercase tracking-widest text-[color:var(--color-text-dim)] text-right space-y-1">
|
||||
<div>[entries: {formations.items.length}]</div>
|
||||
<div>[status: stored]</div>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-[color:var(--color-text-muted)] mt-4 max-w-xl font-mono text-sm">
|
||||
<span class="text-[color:var(--color-magenta)]">></span> un parcours d'étude dans le développement et les
|
||||
systèmes numériques.
|
||||
</p>
|
||||
</div>
|
||||
</Reveal>
|
||||
|
||||
<div class="max-w-4xl mx-auto space-y-12">
|
||||
{
|
||||
formations.items.map((f, i) => {
|
||||
const isEven = i % 2 === 0;
|
||||
const tilt = isEven ? -1.5 : 1.8;
|
||||
const location = extractLocation(f.school);
|
||||
return (
|
||||
<Reveal
|
||||
delay={i * 0.1}
|
||||
direction={isEven ? 'left' : 'right'}
|
||||
client:visible
|
||||
>
|
||||
<div
|
||||
class="relative group transition-transform duration-500 hover:rotate-0"
|
||||
style={`transform: rotate(${tilt}deg); max-width: 640px; margin-${isEven ? 'right' : 'left'}: auto;`}
|
||||
>
|
||||
<article
|
||||
class="relative bg-[#F5EDE0] text-[#14130E] rounded-sm overflow-hidden shadow-[0_20px_50px_-20px_rgba(0,0,0,0.8)]"
|
||||
style="background-image: repeating-linear-gradient(0deg, rgba(20,19,14,0.025) 0 1px, transparent 1px 4px);"
|
||||
>
|
||||
<!-- Header ticket -->
|
||||
<div class="flex items-center justify-between px-5 py-3 border-b-2 border-dashed border-[#14130E]/30">
|
||||
<span class="stencil text-[11px] uppercase tracking-[0.3em]">
|
||||
Free Party Invitation
|
||||
</span>
|
||||
<span class="stencil text-[11px] uppercase tracking-[0.2em] text-[#14130E]/70">
|
||||
EDU SYSTEM · #{String(i + 1).padStart(3, '0')}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- Body -->
|
||||
<div class="p-5 md:p-8 grid grid-cols-1 md:grid-cols-[auto_1fr] gap-6">
|
||||
<div class="font-mono text-[10px] uppercase tracking-widest space-y-2 md:border-r-2 md:border-dashed md:border-[#14130E]/30 md:pr-6">
|
||||
<div>
|
||||
<div class="text-[#14130E]/50">DATE</div>
|
||||
<div class="stencil text-base tracking-wider">{f.period}</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="text-[#14130E]/50">LOCATION</div>
|
||||
<div class="stencil text-base tracking-wider">{location}</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="text-[#14130E]/50">ACCESS</div>
|
||||
<div class="stencil text-base tracking-wider">ALL AREAS</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="stencil text-2xl md:text-3xl uppercase leading-tight mb-2">
|
||||
{f.title}
|
||||
</h3>
|
||||
{f.schoolUrl ? (
|
||||
<a
|
||||
href={f.schoolUrl}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="font-mono text-xs text-[#7A1027] hover:underline uppercase tracking-wider"
|
||||
>
|
||||
{f.school} ↗
|
||||
</a>
|
||||
) : (
|
||||
<p class="font-mono text-xs uppercase tracking-wider">{f.school}</p>
|
||||
)}
|
||||
{f.description && (
|
||||
<p class="text-sm text-[#14130E]/75 mt-4 font-sans">{f.description}</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Footer -->
|
||||
<div class="flex items-center justify-between px-5 py-3 border-t-2 border-dashed border-[#14130E]/30 bg-[#EDE3D0]">
|
||||
<span class="stencil text-[11px] uppercase tracking-[0.3em] text-[#7A1027]">
|
||||
★ Admit one
|
||||
</span>
|
||||
<span class="font-mono text-[10px] uppercase tracking-widest text-[#14130E]/60">
|
||||
no refund / no exchange
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- Bar code imitation -->
|
||||
<div class="absolute right-3 top-12 flex gap-[2px]">
|
||||
{Array.from({ length: 24 }).map((_, j) => (
|
||||
<span
|
||||
class="block w-[1.5px] bg-[#14130E]/50"
|
||||
style={`height: ${12 + ((j * 7) % 18)}px`}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<!-- Punch holes for tear -->
|
||||
<div class="absolute left-0 top-1/2 -translate-x-1/2 -translate-y-1/2 w-6 h-6 rounded-full bg-[color:var(--color-bg)]"></div>
|
||||
<div class="absolute right-0 top-1/2 translate-x-1/2 -translate-y-1/2 w-6 h-6 rounded-full bg-[color:var(--color-bg)]"></div>
|
||||
</div>
|
||||
</Reveal>
|
||||
);
|
||||
})
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</BaseLayout>
|
||||
Reference in New Issue
Block a user