11---
2+ import fs from ' node:fs' ;
23import { getCollection , render } from ' astro:content' ;
34import Base from ' ../../layouts/Base.astro' ;
5+ import { LOC , GEM_COLORS , fmtLoc , sizeLabel } from ' ../../data/islands' ;
46
57export async function getStaticPaths() {
6- const projects = await getCollection (' projects' );
7- return projects .map ((project ) => ({
8+ const projects = (await getCollection (' projects' )).sort (
9+ (a , b ) => a .data .order - b .data .order
10+ );
11+ return projects .map ((project , index ) => ({
812 params: { slug: project .id },
9- props: { project },
13+ props: { project , accent: GEM_COLORS [ index % GEM_COLORS . length ] },
1014 }));
1115}
1216
13- const { project } = Astro .props ;
14- const { title, summary, tech, status, repo, demo, screenshot } = project .data ;
17+ const { project, accent } = Astro .props ;
18+ const { title, summary, tech, status, repo, demo } = project .data ;
19+ // Only render the screenshot if the file actually exists in public/
20+ const screenshot =
21+ project .data .screenshot && fs .existsSync (` public${project .data .screenshot } ` )
22+ ? project .data .screenshot
23+ : undefined ;
24+ const loc = LOC [project .id ];
1525const { Content } = await render (project );
1626---
1727
18- <Base title ={ ` ${title } · Ethan ` } description ={ summary } >
28+ <Base title ={ ` ${title } · Ethan ` } description ={ summary } accent = { accent } >
1929 <article class =" project" >
20- <a href =" /#projects" class =" back" >← All projects</a >
21- <h1 >{ title } </h1 >
30+ <a href =" /#projects" class =" back" >← Back to the archipelago</a >
31+ <div class =" title-row" >
32+ <span class =" gem" aria-hidden =" true" ></span >
33+ <h1 >{ title } </h1 >
34+ </div >
35+ { loc && (
36+ <p class = " island-line" >{ fmtLoc (loc )} lines of code · { sizeLabel (loc )} </p >
37+ )}
2238 <p class =" summary" >{ summary } </p >
2339 <div class =" meta" >
2440 <ul class =" tech-list" >
@@ -47,17 +63,49 @@ const { Content } = await render(project);
4763 }
4864
4965 .back {
50- color: var(--text-dim );
66+ color: var(--ink-soft );
5167 font-size: 0.9rem;
68+ font-weight: 600;
69+ }
70+
71+ .back:hover {
72+ color: var(--ink);
73+ text-decoration: none;
74+ }
75+
76+ .title-row {
77+ display: flex;
78+ align-items: center;
79+ gap: 0.8rem;
80+ margin: 1rem 0 0.15rem;
81+ }
82+
83+ .gem {
84+ width: 1.05rem;
85+ height: 1.05rem;
86+ background: var(--accent);
87+ border-radius: 4px;
88+ transform: rotate(45deg);
89+ flex-shrink: 0;
90+ box-shadow: 0 2px 8px color-mix(in srgb, var(--accent) 45%, transparent);
5291 }
5392
5493 h1 {
5594 font-size: clamp(1.8rem, 5vw, 2.6rem);
56- margin: 0.8rem 0 0.5rem;
95+ line-height: 1.2;
96+ }
97+
98+ .island-line {
99+ color: color-mix(in srgb, var(--accent) 70%, var(--ink));
100+ font-weight: 700;
101+ font-size: 0.9rem;
102+ text-transform: uppercase;
103+ letter-spacing: 0.06em;
104+ margin-bottom: 0.9rem;
57105 }
58106
59107 .summary {
60- color: var(--text-dim );
108+ color: var(--ink-soft );
61109 font-size: 1.1rem;
62110 margin-bottom: 1.2rem;
63111 }
@@ -78,33 +126,37 @@ const { Content } = await render(project);
78126
79127 .tech-list li {
80128 font-size: 0.8rem;
81- padding: 0.15rem 0.6rem;
82- border: 1px solid var(--border);
129+ font-weight: 600;
130+ padding: 0.18rem 0.65rem;
131+ border: 1px solid color-mix(in srgb, var(--accent) 35%, var(--border));
83132 border-radius: 999px;
84- color: var(--accent);
85- background: color-mix(in srgb, var(--accent) 6 %, transparent );
133+ color: color-mix(in srgb, var(--accent) 60%, var(--ink) );
134+ background: color-mix(in srgb, var(--accent) 10 %, var(--card) );
86135 }
87136
88137 .links {
89138 display: flex;
90139 gap: 1rem;
91140 flex-wrap: wrap;
92141 align-items: center;
142+ font-weight: 600;
93143 }
94144
95145 .badge {
96- color: var(--text-dim );
146+ color: var(--ink-soft );
97147 font-size: 0.85rem;
98148 border: 1px dashed var(--border);
99149 border-radius: 999px;
100150 padding: 0.15rem 0.7rem;
151+ background: var(--card);
101152 }
102153
103154 .shot {
104155 width: 100%;
105156 border-radius: var(--radius);
106157 border: 1px solid var(--border);
107158 margin-bottom: 1.6rem;
159+ box-shadow: 0 10px 30px rgba(67, 64, 90, 0.08);
108160 }
109161
110162 .body :global(h2) {
@@ -119,7 +171,6 @@ const { Content } = await render(project);
119171
120172 .body :global(p) {
121173 margin-bottom: 1rem;
122- color: var(--text);
123174 }
124175
125176 .body :global(ul),
@@ -130,4 +181,8 @@ const { Content } = await render(project);
130181 .body :global(li) {
131182 margin-bottom: 0.35rem;
132183 }
184+
185+ .body :global(strong) {
186+ color: color-mix(in srgb, var(--accent) 45%, var(--ink));
187+ }
133188</style >
0 commit comments