mirror of
https://github.com/Patiun/com.gregkilmer.www.git
synced 2026-11-08 04:08:24 +00:00
Start the rebuild: note schema, vault kit and data migration
Phase 1 of the functional design plan. - Move the old site into legacy/, unchanged, for reference. It still builds from there until cutover. - Add packages/schema: the one definition of all 20 note types, with field titles and descriptions, note and vault checks, and JSON Schema export so later editing tools and the MCP server share it. - Add vault-kit: Obsidian templates generated from the schema, and the Site guide for 24.01_PersonalWebsite. - Add tools/migrate: turns the legacy JSON, collections, store data and page text into 545 Site folder notes and 84 images, and checks the result with the schema. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012aSbo2D1qP8cMFQCykf7kx
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
---
|
||||
/**
|
||||
* ProjectCard.astro
|
||||
* ---------------------------------------------------------------------------
|
||||
* Card for a single project entry from the `projects` collection. Renders title,
|
||||
* role, tech pills, summary, and links (repo/demo/case study). Placeholder
|
||||
* entries (frontmatter `placeholder: true`) get a subtle badge so they read as
|
||||
* "to be filled" rather than real work, per the chosen content approach.
|
||||
*/
|
||||
import { type CollectionEntry } from 'astro:content';
|
||||
import Icon from '@components/Icon.astro';
|
||||
|
||||
interface Props {
|
||||
project: CollectionEntry<'projects'>;
|
||||
}
|
||||
const { project } = Astro.props;
|
||||
const d = project.data;
|
||||
|
||||
const links = [
|
||||
d.repo && { href: d.repo, label: 'GitHub', icon: 'github' },
|
||||
d.demo && { href: d.demo, label: 'Live demo', icon: 'open-in-new' },
|
||||
d.caseStudy && { href: d.caseStudy, label: 'Case study', icon: 'file-document-outline' },
|
||||
].filter(Boolean) as { href: string; label: string; icon: string }[];
|
||||
---
|
||||
|
||||
<article
|
||||
class:list={[
|
||||
'card card-interactive flex h-full flex-col gap-4',
|
||||
d.placeholder && 'border-dashed',
|
||||
]}
|
||||
style={d.placeholder ? 'border-color: color-mix(in srgb, var(--color-accent) 45%, transparent);' : ''}
|
||||
>
|
||||
<div class="flex items-start justify-between gap-3">
|
||||
<div class="flex flex-col gap-1">
|
||||
<h3 style="color: var(--color-text);">{d.title}</h3>
|
||||
<p class="font-eyebrow text-xs uppercase tracking-[0.18em]" style="color: var(--color-text-subtle);">
|
||||
{d.role}
|
||||
</p>
|
||||
</div>
|
||||
{d.placeholder && (
|
||||
<span
|
||||
class="pill"
|
||||
style="background: color-mix(in srgb, var(--color-accent) 18%, transparent); color: var(--color-accent);"
|
||||
>
|
||||
<Icon name="pencil" class="h-3.5 w-3.5" />
|
||||
Placeholder
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{d.tech.length > 0 && (
|
||||
<ul class="flex flex-wrap gap-2">
|
||||
{d.tech.map((t) => <li class="pill">{t}</li>)}
|
||||
</ul>
|
||||
)}
|
||||
|
||||
<p class="grow text-sm leading-relaxed" style="color: var(--color-text-muted);">
|
||||
{d.summary}
|
||||
</p>
|
||||
|
||||
{links.length > 0 && (
|
||||
<ul class="mt-1 flex flex-wrap gap-4">
|
||||
{links.map((l) => (
|
||||
<li>
|
||||
<a
|
||||
href={l.href}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="inline-flex items-center gap-1.5 font-sans text-sm font-semibold transition-colors"
|
||||
style="color: var(--color-accent);"
|
||||
>
|
||||
<Icon name={l.icon} class="h-4 w-4" />
|
||||
{l.label}
|
||||
</a>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
)}
|
||||
</article>
|
||||
Reference in New Issue
Block a user