Skip to content

Commit d6c5d2e

Browse files
committed
feat: Refresh homepage with project artwork and card layouts
- Add project emblem artwork to preview cards - Refresh homepage hero and current work sections
1 parent f1909cd commit d6c5d2e

5 files changed

Lines changed: 101 additions & 20 deletions

File tree

7.3 KB
Loading
17.3 KB
Loading
11.6 KB
Loading

src/components/project-preview-card.tsx

Lines changed: 61 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,33 @@
1-
import { ArrowUpRight, Github } from 'lucide-react'
1+
import { ArrowRight, Github } from 'lucide-react'
22

33
import { InstallCommand, ProjectLink } from '@/components/catalog-row'
44
import { Button } from '@/components/ui/button'
55
import type { CatalogProject } from '@/data/projects'
6+
import { formatRelativeTime } from '@/lib/format'
7+
8+
const projectArtwork = {
9+
'period-space': '/project-emblems/period-space.webp',
10+
pastebridge: '/project-emblems/pastebridge.webp',
11+
'mmf-golden-gate-fixer': '/project-emblems/mmf-golden-gate-fixer.webp',
12+
} as const
13+
14+
function ProjectArtwork({ id }: { id: string }) {
15+
const src =
16+
projectArtwork[id as keyof typeof projectArtwork] ??
17+
projectArtwork['period-space']
18+
19+
return (
20+
<img
21+
src={src}
22+
alt=""
23+
width="800"
24+
height="800"
25+
loading="lazy"
26+
decoding="async"
27+
className="h-full w-full object-cover"
28+
/>
29+
)
30+
}
631

732
export function ProjectPreviewCard({ project }: { project: CatalogProject }) {
833
const githubUrl = project.githubUrl ?? project.href
@@ -11,44 +36,63 @@ export function ProjectPreviewCard({ project }: { project: CatalogProject }) {
1136
)
1237

1338
return (
14-
<article className="flex min-h-64 flex-col justify-between overflow-hidden rounded-3xl border bg-card p-6 shadow-sm sm:p-8">
15-
<div>
16-
<h3 className="max-w-3xl font-display text-3xl font-semibold tracking-[-0.035em] text-balance sm:text-4xl">
39+
<article className="group flex min-h-full flex-col overflow-hidden rounded-[1.75rem] border border-black/[0.06] bg-card shadow-[0_1px_2px_rgba(0,0,0,0.03)] transition-[transform,box-shadow] duration-500 ease-out hover:-translate-y-1 hover:shadow-[0_24px_60px_-30px_rgba(15,23,42,0.35)] motion-reduce:transform-none motion-reduce:transition-none dark:border-white/[0.08] dark:shadow-none dark:hover:shadow-[0_24px_60px_-30px_rgba(0,0,0,0.8)]">
40+
<div className="relative h-56 overflow-hidden bg-muted sm:h-64">
41+
<div className="absolute inset-0 transition-transform duration-700 ease-out group-hover:scale-[1.025] motion-reduce:transform-none">
42+
<ProjectArtwork id={project.id} />
43+
</div>
44+
</div>
45+
46+
<div className="flex flex-1 flex-col p-6 sm:p-7">
47+
<div className="mb-5 flex min-h-5 items-center gap-2 text-xs text-muted-foreground">
48+
{project.language ? <span>{project.language}</span> : null}
49+
{project.language && project.updatedAt ? (
50+
<span aria-hidden="true">·</span>
51+
) : null}
52+
{project.updatedAt ? (
53+
<span>Updated {formatRelativeTime(project.updatedAt)}</span>
54+
) : null}
55+
</div>
56+
57+
<h3 className="font-display text-2xl font-semibold tracking-[-0.035em] text-balance sm:text-[1.75rem]">
1758
{project.name}
1859
</h3>
19-
<p className="mt-3 max-w-2xl text-base leading-relaxed text-muted-foreground sm:text-lg">
60+
<p className="mt-3 text-[0.9375rem] leading-6 text-muted-foreground sm:text-base">
2061
{project.description}
2162
</p>
22-
</div>
2363

24-
<div className="mt-8 flex flex-col gap-5 lg:flex-row lg:items-end lg:justify-between">
2564
{project.installCommand ? (
26-
<div className="min-w-0 max-w-2xl flex-1">
65+
<div className="mt-6 min-w-0">
2766
<InstallCommand command={project.installCommand} />
2867
</div>
2968
) : null}
3069

31-
<div className="flex shrink-0 flex-wrap items-center gap-2">
70+
<div className="mt-auto flex flex-wrap items-center gap-2 pt-7">
3271
{hasProjectView ? (
33-
<Button asChild>
72+
<Button asChild className="rounded-full px-5">
3473
{project.homepageUrl && !project.to ? (
3574
<a href={project.homepageUrl} target="_blank" rel="noreferrer">
36-
View project
37-
<ArrowUpRight data-icon="inline-end" />
75+
Explore project
76+
<ArrowRight data-icon="inline-end" />
3877
</a>
3978
) : (
4079
<ProjectLink project={project}>
41-
View project
42-
<ArrowUpRight data-icon="inline-end" />
80+
Explore project
81+
<ArrowRight data-icon="inline-end" />
4382
</ProjectLink>
4483
)}
4584
</Button>
4685
) : null}
4786
{githubUrl ? (
48-
<Button asChild variant="outline">
87+
<Button
88+
asChild
89+
variant="ghost"
90+
size="icon"
91+
className="rounded-full"
92+
>
4993
<a href={githubUrl} target="_blank" rel="noreferrer">
50-
<Github data-icon="inline-start" />
51-
Source
94+
<Github />
95+
<span className="sr-only">View {project.name} source</span>
5296
</a>
5397
</Button>
5498
) : null}

src/routes/index.tsx

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ function HomeRoute() {
2626
<PageLayout className="py-0 sm:py-0 lg:py-0">
2727
<PageContent className="gap-0">
2828
{error ? (
29-
<Alert className="my-4">
29+
<Alert className="mt-4">
3030
<AlertCircle />
3131
<AlertTitle>GitHub is rate-limited or unreachable</AlertTitle>
3232
<AlertDescription>
@@ -36,9 +36,46 @@ function HomeRoute() {
3636
</Alert>
3737
) : null}
3838

39-
<section aria-label="Projects">
39+
<header className="flex min-h-[31rem] flex-col justify-center border-b border-border/60 py-20 sm:min-h-[36rem] sm:py-24 lg:min-h-[39rem]">
40+
<h1 className="max-w-5xl font-display text-5xl font-semibold leading-[0.98] tracking-[-0.06em] text-balance sm:text-7xl lg:text-[5.75rem]">
41+
Software for the spaces between systems.
42+
</h1>
43+
<div className="mt-8 grid gap-6 sm:mt-10 sm:grid-cols-[minmax(0,38rem)_auto] sm:items-end sm:justify-between">
44+
<p className="max-w-2xl text-lg leading-8 text-muted-foreground sm:text-xl">
45+
A small collection of focused, open-source tools for making Linux,
46+
macOS, and the devices between them work better together.
47+
</p>
48+
<p className="text-sm leading-6 text-muted-foreground sm:text-right">
49+
Built in public
50+
<br />
51+
Designed for daily use
52+
</p>
53+
</div>
54+
</header>
55+
56+
<section className="py-14 sm:py-20" aria-labelledby="work-heading">
57+
<div className="mb-8 flex items-end justify-between gap-4 sm:mb-10">
58+
<div>
59+
<h2
60+
id="work-heading"
61+
className="font-display text-3xl font-semibold tracking-[-0.04em] sm:text-4xl"
62+
>
63+
Current work
64+
</h2>
65+
<p className="mt-2 text-muted-foreground">
66+
Practical projects, actively shaped and maintained.
67+
</p>
68+
</div>
69+
{workProjects.length > 0 ? (
70+
<p className="hidden text-sm text-muted-foreground sm:block">
71+
{workProjects.length}{' '}
72+
{workProjects.length === 1 ? 'project' : 'projects'}
73+
</p>
74+
) : null}
75+
</div>
76+
4077
{workProjects.length > 0 ? (
41-
<div className="grid gap-5 py-5">
78+
<div className="grid gap-5 md:grid-cols-2 xl:grid-cols-3">
4279
{workProjects.map((project) => (
4380
<ProjectPreviewCard key={project.id} project={project} />
4481
))}

0 commit comments

Comments
 (0)