All checks were successful
Deploy production / build-deploy (push) Successful in 24s
Stack & icônes - grille unique enrichie (+24 technos) : React, TypeORM, Apache, Gitea, GitLab, GitHub Actions, Vite, pnpm, Socket.io, Chart.js, Discord.js, Prisma, Sequelize, IntelliJ IDEA, VS Code, Windows, HubSpot, HTML5/CSS3… - nouvelles catégories « Bases de données & ORM » et « Tests & Qualité » - 21 icônes simple-icons + tracés monochromes custom VS Code, Windows, Playwright ; support du fill-rule dans TechIcon - mise en page masonry (CSS columns) + titres et puces centrés Contenu & UI - Hero : retrait du badge « ouvert aux opportunités » - About / Contact : reformulation orientée projets - ProjectCard : statut « en développement » - typographie : tirets cadratins → virgules (titres, OG, aria-labels) - ajout du visuel public/images/logo/couverture.png
51 lines
1.8 KiB
Plaintext
51 lines
1.8 KiB
Plaintext
---
|
|
import Icon from "./Icon.astro";
|
|
import type { Project } from "../data/content";
|
|
|
|
const STATUS: Record<Project["status"], { label: string; color: string }> = {
|
|
live: { label: "en ligne", color: "var(--accent)" },
|
|
dev: { label: "en développement", color: "var(--warn)" },
|
|
archived: { label: "archivé", color: "var(--text-dim)" },
|
|
oss: { label: "open-source", color: "var(--info)" },
|
|
};
|
|
|
|
interface Props { project: Project; }
|
|
const { project: p } = Astro.props;
|
|
const st = STATUS[p.status];
|
|
const mono = p.title.replace(/[^A-Za-z0-9]/g, "").slice(0, 2);
|
|
|
|
// Toute la carte devient cliquable (nouvel onglet) dès qu'un lien est défini.
|
|
const Tag = p.link ? "a" : "article";
|
|
const linkAttrs = p.link
|
|
? { href: p.link, target: "_blank", rel: "noopener", "aria-label": `${p.title}, voir le projet (nouvel onglet)` }
|
|
: {};
|
|
---
|
|
<Tag class:list={["card", p.link && "card--link"]} {...linkAttrs}>
|
|
<div class:list={["card-media", p.imgDark && "card-media--themed"]}>
|
|
{p.img ? (
|
|
<>
|
|
<img class="logo-light" src={p.img} alt={p.title} loading="lazy" />
|
|
{p.imgDark && <img class="logo-dark" src={p.imgDark} alt={p.title} loading="lazy" />}
|
|
</>
|
|
) : (
|
|
<div class="card-mono"><span>{mono}</span></div>
|
|
)}
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="card-head">
|
|
<span class="status"><span class="status-dot" style={`background:${st.color}`}></span>{st.label}</span>
|
|
{p.link && (
|
|
<span class="ext-link" aria-hidden="true">
|
|
<Icon name="external" size={16} />
|
|
</span>
|
|
)}
|
|
</div>
|
|
<h3 class="card-title">{p.title}</h3>
|
|
<p class="card-sub">{p.subtitle}</p>
|
|
<p class="card-desc">{p.desc}</p>
|
|
<div class="chips">
|
|
{p.stack.map((s) => <span class="chip">{s}</span>)}
|
|
</div>
|
|
</div>
|
|
</Tag>
|