first commit

This commit is contained in:
Matt Kane
2026-04-01 10:44:22 +01:00
commit 43fcb9a131
1789 changed files with 395041 additions and 0 deletions

View File

@@ -0,0 +1,167 @@
---
import type { MediaValue } from "emdash";
import { Image } from "emdash/ui";
interface Props {
title: string;
summary?: string;
featuredImage: MediaValue | string;
href: string;
client?: string;
year?: string;
categories?: string[];
tags?: string[];
}
const { title, summary, featuredImage, href, client, year, categories, tags } =
Astro.props;
// Combine categories and tags for display
const allTags = [...(categories || []), ...(tags || [])];
---
<article class="project-card">
<a href={href} class="card-link">
<div class="card-image">
<Image image={featuredImage} />
<div class="card-overlay">
<span class="card-view">View Project</span>
</div>
</div>
<div class="card-content">
<h2 class="card-title">{title}</h2>
<div class="card-meta">
{client && <span class="card-client">{client}</span>}
{client && year && <span class="card-separator">·</span>}
{year && <span class="card-year">{year}</span>}
</div>
{summary && <p class="card-summary">{summary}</p>}
{
allTags.length > 0 && (
<div class="card-categories">
{allTags.map((tag) => (
<span class="card-category">{tag}</span>
))}
</div>
)
}
</div>
</a>
</article>
<style>
.project-card {
position: relative;
}
.card-link {
display: flex;
flex-direction: column;
gap: var(--spacing-lg, 1.5rem);
text-decoration: none;
color: inherit;
}
.card-image {
position: relative;
overflow: hidden;
border-radius: var(--radius, 4px);
}
.card-image img {
width: 100%;
height: auto;
aspect-ratio: 4 / 3;
object-fit: cover;
transition: transform var(--transition-slow, 300ms ease);
}
.card-overlay {
position: absolute;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
background: rgba(0, 0, 0, 0);
transition: background var(--transition-base, 200ms ease);
}
.card-view {
font-family: var(--font-serif, Georgia, serif);
font-size: var(--font-size-sm, 0.875rem);
color: white;
padding: var(--spacing-sm, 0.5rem) var(--spacing-md, 1rem);
border: 1px solid white;
border-radius: var(--radius, 4px);
opacity: 0;
transform: translateY(10px);
transition:
opacity var(--transition-base, 200ms ease),
transform var(--transition-base, 200ms ease);
}
.project-card:hover .card-image img {
transform: scale(1.03);
}
.project-card:hover .card-overlay {
background: rgba(0, 0, 0, 0.4);
}
.project-card:hover .card-view {
opacity: 1;
transform: translateY(0);
}
.card-content {
display: flex;
flex-direction: column;
gap: var(--spacing-xs, 0.25rem);
}
.card-title {
font-family: var(--font-serif, Georgia, serif);
font-size: var(--font-size-xl, 1.5rem);
font-weight: 500;
transition: color var(--transition-fast, 150ms ease);
}
.project-card:hover .card-title {
color: var(--color-accent, #7c3aed);
}
.card-meta {
font-size: var(--font-size-sm, 0.875rem);
color: var(--color-muted, #6b7280);
}
.card-separator {
margin: 0 var(--spacing-xs, 0.25rem);
}
.card-summary {
font-size: var(--font-size-sm, 0.875rem);
color: var(--color-muted, #6b7280);
line-height: 1.6;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
.card-categories {
display: flex;
flex-wrap: wrap;
gap: var(--spacing-sm, 0.5rem);
margin-top: var(--spacing-sm, 0.5rem);
}
.card-category {
font-size: 0.75rem;
text-transform: uppercase;
letter-spacing: 0.05em;
color: var(--color-muted, #6b7280);
padding: var(--spacing-xs, 0.25rem) var(--spacing-sm, 0.5rem);
border: 1px solid var(--color-border, #e5e7eb);
border-radius: var(--radius, 4px);
}
</style>