initial commit
This commit is contained in:
commit
3ba76b4f02
90 changed files with 12507 additions and 0 deletions
242
src/pages/index.astro
Normal file
242
src/pages/index.astro
Normal file
|
|
@ -0,0 +1,242 @@
|
|||
---
|
||||
import BaseLayout from "~/layouts/BaseLayout.astro";
|
||||
import Eyebrow from "~/components/atoms/Eyebrow.astro";
|
||||
import Mark from "~/components/atoms/Mark.astro";
|
||||
import LatestLine from "~/components/molecules/LatestLine.astro";
|
||||
import IndexRow from "~/components/molecules/IndexRow.astro";
|
||||
import HeroZone from "~/components/islands/HeroZone";
|
||||
import { blog, art, code } from "~/lib/urls";
|
||||
import { getCollection } from "astro:content";
|
||||
|
||||
// Pull the most recent published post for the "selected writing" line.
|
||||
const posts = await getCollection("posts", ({ data }) => !data.draft);
|
||||
posts.sort((a, b) => b.data.date.getTime() - a.data.date.getTime());
|
||||
const latest = posts[0];
|
||||
|
||||
const dateFmt = new Intl.DateTimeFormat("en-AU", {
|
||||
month: "short",
|
||||
year: "numeric",
|
||||
});
|
||||
|
||||
// Subdomain index. Each row points at the right destination. Some entries are
|
||||
// out-of-repo containers; flagging external just signals intent for now (rel attrs).
|
||||
const indexItems = [
|
||||
{ num: "01", name: "Blog", href: blog("/"), desc: "Writing", external: false, soon: false },
|
||||
{ num: "02", name: "Code", href: code("/"), desc: "Experiments & tools", external: false, soon: false },
|
||||
{ num: "03", name: "Art", href: art("/"), desc: "Generative & physical", external: false, soon: false },
|
||||
{ num: "04", name: "Signage", href: undefined, desc: undefined, external: true, soon: true },
|
||||
{ num: "05", name: "Keycaps", href: undefined, desc: undefined, external: true, soon: true },
|
||||
{ num: "06", name: "Social", href: undefined, desc: undefined, external: true, soon: true },
|
||||
];
|
||||
---
|
||||
|
||||
<BaseLayout title="Josh Bairstow" current="home" showCoordInTopbar={true}>
|
||||
<Fragment slot="marks">
|
||||
<Mark kind="ringdots" width={84} top="14%" left="3%" rotate={-5} />
|
||||
<Mark kind="pipes" width={28} top="73%" left="6%" rotate={8} />
|
||||
<Mark kind="dots" width={52} top="26%" right="3.5%" />
|
||||
<Mark kind="concentric" width={42} bottom="9%" right="7%" />
|
||||
<Mark kind="ringdots" width={66} bottom="20%" left="44%" rotate={-3} />
|
||||
</Fragment>
|
||||
|
||||
<main class="home" data-layout="stack">
|
||||
<section class="intro">
|
||||
<Eyebrow>Engineer · Sydney</Eyebrow>
|
||||
<h2 class="statement">
|
||||
I make small,<br /><em>careful</em> things<span class="accent">.</span>
|
||||
</h2>
|
||||
<p class="lead">
|
||||
Software, tools, and the occasional mark in ink. A quiet corner of the
|
||||
internet — mostly writing, sometimes shipping.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="hero">
|
||||
<HeroZone client:load />
|
||||
</section>
|
||||
|
||||
{
|
||||
latest && (
|
||||
<section class="latest">
|
||||
<Eyebrow>Selected writing</Eyebrow>
|
||||
<LatestLine
|
||||
title={latest.data.title}
|
||||
href={blog(`/posts/${latest.id}/`)}
|
||||
date={dateFmt.format(latest.data.date)}
|
||||
/>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
||||
<section class="index">
|
||||
<Eyebrow>Index</Eyebrow>
|
||||
<nav>
|
||||
{indexItems.map((item) => (
|
||||
<IndexRow
|
||||
num={item.num}
|
||||
name={item.name}
|
||||
href={item.href}
|
||||
desc={item.desc}
|
||||
soon={item.soon}
|
||||
external={item.external}
|
||||
/>
|
||||
))}
|
||||
</nav>
|
||||
</section>
|
||||
</main>
|
||||
</BaseLayout>
|
||||
|
||||
<style>
|
||||
/* Stack layout — editorial, centered. The canonical landing per docs/planning.md. */
|
||||
.home {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 880px);
|
||||
grid-template-areas: "intro" "hero" "latest" "index";
|
||||
justify-content: center;
|
||||
gap: clamp(28px, 4.6vh, 52px);
|
||||
align-content: start;
|
||||
padding-top: clamp(40px, 7vh, 96px);
|
||||
text-align: center;
|
||||
flex: 1;
|
||||
}
|
||||
.intro {
|
||||
grid-area: intro;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
.intro :global(.eyebrow) {
|
||||
margin-bottom: clamp(18px, 3.4vh, 30px);
|
||||
}
|
||||
.statement {
|
||||
font-family: var(--font-display);
|
||||
font-weight: 500;
|
||||
font-size: clamp(40px, 5.4vw, 82px);
|
||||
line-height: 0.97;
|
||||
letter-spacing: -0.02em;
|
||||
margin: 0;
|
||||
color: var(--fg-on-dark-1);
|
||||
text-wrap: balance;
|
||||
}
|
||||
:global(body:not(.dark)) .statement {
|
||||
color: var(--fg-1);
|
||||
}
|
||||
.statement em {
|
||||
font-style: italic;
|
||||
font-weight: 400;
|
||||
}
|
||||
.statement .accent {
|
||||
color: var(--accent-deep);
|
||||
}
|
||||
.lead {
|
||||
font-family: var(--font-body);
|
||||
font-weight: 300;
|
||||
font-size: clamp(15px, 1.45vw, 18px);
|
||||
line-height: 1.6;
|
||||
color: var(--fg-on-dark-2);
|
||||
max-width: 56ch;
|
||||
margin: clamp(20px, 3.6vh, 32px) auto 0;
|
||||
text-align: center;
|
||||
}
|
||||
:global(body:not(.dark)) .lead {
|
||||
color: var(--fg-2);
|
||||
}
|
||||
|
||||
.hero {
|
||||
grid-area: hero;
|
||||
display: flex;
|
||||
}
|
||||
/* Styles for .hzframe + its children come from the React island's class names */
|
||||
.hero :global(.hzframe) {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
border-radius: var(--radius-cutout);
|
||||
background: radial-gradient(
|
||||
120% 95% at 64% 18%,
|
||||
#c9b299 0%,
|
||||
#8a6a47 30%,
|
||||
#4a3826 60%,
|
||||
#221e18 92%
|
||||
);
|
||||
box-shadow: var(--shadow-2);
|
||||
cursor: crosshair;
|
||||
transition: background 700ms var(--ease-out);
|
||||
aspect-ratio: 16 / 7;
|
||||
}
|
||||
.hero :global(.hzframe .grain) {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background-image: url(/assets/texture-grain.svg);
|
||||
background-size: 220px;
|
||||
opacity: 0.12;
|
||||
mix-blend-mode: overlay;
|
||||
pointer-events: none;
|
||||
}
|
||||
.hero :global(.hzframe .hzaccent) {
|
||||
position: absolute;
|
||||
right: 9%;
|
||||
top: 12%;
|
||||
width: 76px;
|
||||
opacity: 0.18;
|
||||
filter: invert(1);
|
||||
pointer-events: none;
|
||||
transition: transform 900ms var(--ease-out);
|
||||
}
|
||||
.hero :global(.hzframe .hzwm) {
|
||||
position: absolute;
|
||||
left: 8%;
|
||||
bottom: 9%;
|
||||
width: 128px;
|
||||
opacity: 0.1;
|
||||
filter: invert(1);
|
||||
pointer-events: none;
|
||||
}
|
||||
.hero :global(.hzframe .hztag) {
|
||||
position: absolute;
|
||||
right: 8%;
|
||||
bottom: 8%;
|
||||
font-family: var(--font-mono);
|
||||
font-size: 10px;
|
||||
letter-spacing: 0.14em;
|
||||
text-transform: uppercase;
|
||||
color: rgba(239, 231, 218, 0.5);
|
||||
}
|
||||
|
||||
.latest {
|
||||
grid-area: latest;
|
||||
max-width: 640px;
|
||||
margin: 0 auto;
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
}
|
||||
.latest :global(.eyebrow) {
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
|
||||
.index {
|
||||
grid-area: index;
|
||||
text-align: left;
|
||||
}
|
||||
.index :global(.eyebrow) {
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
@media (max-width: 860px) {
|
||||
.home {
|
||||
grid-template-columns: 1fr;
|
||||
text-align: left;
|
||||
}
|
||||
.intro {
|
||||
align-items: flex-start;
|
||||
}
|
||||
.lead {
|
||||
text-align: left;
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
}
|
||||
.hero :global(.hzframe) {
|
||||
aspect-ratio: 16 / 9;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Loading…
Add table
Add a link
Reference in a new issue