first commit
This commit is contained in:
167
templates/portfolio-cloudflare/src/components/ProjectCard.astro
Normal file
167
templates/portfolio-cloudflare/src/components/ProjectCard.astro
Normal 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>
|
||||
Reference in New Issue
Block a user