Initial site: Astro + M3 Expressive, projects, blog
Personal site & blog for jeanlucmakiola.de. - Astro 7 static output; self-hosted Inter + JetBrains Mono (Fontsource) - Material 3 Expressive design tokens (red accent over neutral surfaces) - Home (hero + about + selected work + latest writing) - /work index + per-app pages (Calendula, Agendula, floret-kit) with build-time Gitea release tags, brand-icon link rows, features grid, and an at-a-glance facts panel - Blog via Markdown content collection; RSS, sitemap, robots, OG/SEO - Privacy-respecting Umami analytics, env-gated (off in dev) - Dockerfile (build -> Caddy) + Caddyfile for Coolify deploy Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
110
src/pages/index.astro
Normal file
110
src/pages/index.astro
Normal file
@@ -0,0 +1,110 @@
|
||||
---
|
||||
import BaseLayout from '../layouts/BaseLayout.astro';
|
||||
import { Icon } from 'astro-icon/components';
|
||||
import { getCollection } from 'astro:content';
|
||||
import { SITE } from '../consts';
|
||||
|
||||
const posts = (await getCollection('blog', ({ data }) => !data.draft))
|
||||
.sort((a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf())
|
||||
.slice(0, 4);
|
||||
|
||||
const fmt = (d: Date) =>
|
||||
d.toLocaleDateString(SITE.lang, { year: 'numeric', month: 'short' });
|
||||
|
||||
const GITEA = 'https://gitea.jeanlucmakiola.de/makiolaj';
|
||||
|
||||
// Selected work — pulled from the projects collection (single source of truth;
|
||||
// per-app pages live at /work/<slug>). Older experiments live on Gitea.
|
||||
const projects = (await getCollection('projects')).sort(
|
||||
(a, b) => a.data.order - b.data.order
|
||||
);
|
||||
---
|
||||
|
||||
<BaseLayout title={SITE.title}>
|
||||
<!-- Intro: hero + about side by side on wide screens -->
|
||||
<section class="intro" aria-label="Intro">
|
||||
<div class="hero intro__lead">
|
||||
<span class="hero__eyebrow">Developer & designer</span>
|
||||
<h1>Jean-Luc Makiola<span class="dot">.</span></h1>
|
||||
<p class="lead">
|
||||
I build design-led Android apps with Material 3 Expressive on top of
|
||||
open, self-hostable standards. This is my corner of the web — projects,
|
||||
writing, and notes.
|
||||
</p>
|
||||
<div class="hero__actions">
|
||||
<a class="btn btn--filled" href="#work">View work</a>
|
||||
<a class="text-link" href="/blog">Read the blog <span class="dot">→</span></a>
|
||||
<a class="text-link" href="mailto:mail@jeanlucmakiola.de">
|
||||
<Icon name="mdi:email-outline" /> Get in touch
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="about intro__about" id="about">
|
||||
<p>
|
||||
I'd rather put a thoughtful interface on top of an open protocol than
|
||||
reinvent a sync stack. My apps read and write through the platform's own
|
||||
providers, so your data stays yours — and stays portable.
|
||||
</p>
|
||||
<p class="muted">
|
||||
They form the <strong>Floret</strong> family: small, focused tools that
|
||||
share one expressive design language. Everything around them — code,
|
||||
translations, builds — runs on infrastructure I host myself.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Selected work -->
|
||||
<section class="section" id="work">
|
||||
<div class="section-head">
|
||||
<h2>Selected work</h2>
|
||||
<a class="btn btn--text" href="/work">All work →</a>
|
||||
</div>
|
||||
<ul class="project-grid">
|
||||
{
|
||||
projects.map((p) => (
|
||||
<li>
|
||||
<a class="project-card" href={`/work/${p.id}/`}>
|
||||
<span class={`project-card__status${p.data.released ? ' is-released' : ''}`}>
|
||||
{p.data.status}
|
||||
</span>
|
||||
<span class="project-card__title">
|
||||
{p.data.name}
|
||||
<span class="arrow" aria-hidden="true">→</span>
|
||||
</span>
|
||||
<p>{p.data.summary}</p>
|
||||
</a>
|
||||
</li>
|
||||
))
|
||||
}
|
||||
</ul>
|
||||
<p class="aside">
|
||||
Plus a trail of smaller experiments and utilities — most unfinished by
|
||||
design — over on <a href={GITEA} rel="noopener">my Gitea</a>.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<!-- Latest writing -->
|
||||
{
|
||||
posts.length > 0 && (
|
||||
<section class="section">
|
||||
<div class="section-head">
|
||||
<h2>Latest writing</h2>
|
||||
<a class="btn btn--text" href="/blog">All posts →</a>
|
||||
</div>
|
||||
<ul class="writing-list">
|
||||
{posts.map((post) => (
|
||||
<li>
|
||||
<a class="writing-row" href={`/blog/${post.id}/`}>
|
||||
<span class="writing-row__title">{post.data.title}</span>
|
||||
<time datetime={post.data.pubDate.toISOString()}>
|
||||
{fmt(post.data.pubDate)}
|
||||
</time>
|
||||
</a>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
</BaseLayout>
|
||||
Reference in New Issue
Block a user