Skip to content

Commit 505083f

Browse files
authored
Merge pull request #12 from rmfisher26/visual-styles
Visual styles
2 parents 29172ef + 49b3664 commit 505083f

File tree

2 files changed

+155
-27
lines changed

2 files changed

+155
-27
lines changed

src/pages/index.astro

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ const featuredDate = featured?.data.pubDate.toLocaleDateString('en-US', {
3131

3232
<!-- HERO -->
3333
<section class="hero">
34-
<div class="hero-eyebrow">quantum compiler internals</div>
34+
<div class="hero-eyebrow">welcome</div>
3535
<h1>Casting a line into <em><span class="hero-guppy">Guppy's</span></em> depths</h1>
3636
<p class="hero-desc">
3737
A working log of everything I'm discovering about Guppylang —

src/pages/log.astro

Lines changed: 154 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
import Base from '../layouts/Base.astro';
33
import Header from '../components/Header.astro';
44
5+
const WEEKS_PER_PAGE = 2;
6+
57
const entries = [
68
{
79
week: 'Week of Mar 3, 2026',
@@ -12,8 +14,8 @@ const entries = [
1214
{
1315
type: 'reading',
1416
label: 'Reading',
15-
title: 'Diving into HUGR\'s value vs control flow distinction',
16-
body: 'Spent a couple of hours reading through the HUGR spec. The split between dataflow and control flow graphs is clicking more — DataflowBlocks and BasicBlocks are fundamentally different containers. Still fuzzy on how the CFG node relates to the outer DFG.',
17+
title: "Diving into HUGR's value vs control flow distinction",
18+
body: "Spent a couple of hours reading through the HUGR spec. The split between dataflow and control flow graphs is clicking more — DataflowBlocks and BasicBlocks are fundamentally different containers. Still fuzzy on how the CFG node relates to the outer DFG.",
1719
},
1820
{
1921
type: 'pr',
@@ -58,7 +60,7 @@ const entries = [
5860
{
5961
type: 'reading',
6062
label: 'Reading',
61-
title: 'Reading about Python\'s sys.excepthook and how test frameworks intercept it',
63+
title: "Reading about Python's sys.excepthook and how test frameworks intercept it",
6264
body: 'Rabbit hole from the comptime PR. pytest, IPython, and rich all monkey-patch sys.excepthook at startup. The save/restore pattern is essential for test isolation — each framework assumes it owns the hook.',
6365
},
6466
{
@@ -77,7 +79,7 @@ const entries = [
7779
type: 'exploration',
7880
label: 'Exploration',
7981
title: 'Reproducing the comptime exception hook bug locally',
80-
body: 'Managed to reproduce the sys.excepthook not being restored after a comptime error. The issue is that pretty_errors installs its hook and the comptime path raises before the teardown runs.',
82+
body: "Managed to reproduce the sys.excepthook not being restored after a comptime error. The issue is that pretty_errors installs its hook and the comptime path raises before the teardown runs.",
8183
},
8284
],
8385
},
@@ -99,8 +101,8 @@ const entries = [
99101
{
100102
type: 'reading',
101103
label: 'Reading',
102-
title: 'Reading through Python\'s frame inspection docs (sys._getframe, f_code, f_back)',
103-
body: 'The wasm path fix required understanding the call stack deeply. f_code.co_filename is the key field — it gives you the source file for any frame, which is how you find the user\'s file vs internal guppylang frames.',
104+
title: "Reading through Python's frame inspection docs (sys._getframe, f_code, f_back)",
105+
body: "The wasm path fix required understanding the call stack deeply. f_code.co_filename is the key field — it gives you the source file for any frame, which is how you find the user's file vs internal guppylang frames.",
104106
},
105107
],
106108
},
@@ -114,30 +116,36 @@ const typeColors: Record<string, string> = {
114116
reading: '#7c5cbf',
115117
exploration: '#b06d2a',
116118
};
119+
120+
const totalPages = Math.ceil(entries.length / WEEKS_PER_PAGE);
117121
---
118122

119123
<Base title="Log">
120124
<Header />
121125

122126
<main class="log-main">
123-
<div class="log-header">
124-
<div class="log-eyebrow">working in public</div>
127+
<div class="page-header">
128+
<div class="log-eyebrow">status update</div>
125129
<h1>Log</h1>
126130
<p class="log-desc">
127131
A running record of what I'm reading, building, and figuring out — day by day.
128132
</p>
129133
</div>
130134

131-
<div class="timeline">
132-
{entries.map((week) => (
133-
<section class="week-block">
135+
<!-- Timeline -->
136+
<div class="timeline" id="timeline">
137+
{entries.map((week, i) => (
138+
<section
139+
class="week-block"
140+
data-week-index={i}
141+
data-page={Math.floor(i / WEEKS_PER_PAGE)}
142+
id={`week-${i}`}
143+
>
134144
<div class="week-label">{week.week}</div>
135-
136145
<div class="week-entries">
137146
{week.days.map((day) => (
138147
<div class="day-group">
139148
<div class="day-date">{day.date}</div>
140-
141149
<div class="day-items">
142150
{day.items.map((item) => (
143151
<div class="log-entry" style={`--entry-color: ${typeColors[item.type] ?? 'var(--muted)'}`}>
@@ -161,6 +169,23 @@ const typeColors: Record<string, string> = {
161169
</section>
162170
))}
163171
</div>
172+
173+
<!-- Pagination controls -->
174+
<div class="pagination" id="pagination">
175+
<button class="page-btn" id="prev-btn" aria-label="Previous page" disabled>
176+
<svg width="16" height="16" viewBox="0 0 16 16" fill="none">
177+
<path d="M10 3L5 8L10 13" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/>
178+
</svg>
179+
Prev
180+
</button>
181+
<span class="page-indicator" id="page-indicator">Page 1 of {totalPages}</span>
182+
<button class="page-btn" id="next-btn" aria-label="Next page">
183+
Next
184+
<svg width="16" height="16" viewBox="0 0 16 16" fill="none">
185+
<path d="M6 3L11 8L6 13" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/>
186+
</svg>
187+
</button>
188+
</div>
164189
</main>
165190
</Base>
166191

@@ -171,18 +196,43 @@ const typeColors: Record<string, string> = {
171196
padding: 4rem 2rem 6rem;
172197
}
173198

199+
@keyframes fadeUp {
200+
from { opacity: 0; transform: translateY(16px); }
201+
to { opacity: 1; transform: translateY(0); }
202+
}
203+
174204
/* ── HEADER ── */
175-
.log-header {
176-
margin-bottom: 4rem;
205+
.page-header {
206+
animation: fadeUp 0.5s ease both;
177207
}
178208

209+
.timeline {
210+
animation: fadeUp 0.5s ease 0.15s both;
211+
}
212+
213+
.pagination {
214+
animation: fadeUp 0.5s ease 0.25s both;
215+
}
216+
217+
.log-header { margin-bottom: 2.5rem; }
218+
179219
.log-eyebrow {
180220
font-family: 'JetBrains Mono', monospace;
181-
font-size: 0.72rem;
182-
letter-spacing: 0.12em;
183-
text-transform: uppercase;
184-
color: var(--muted);
185-
margin-bottom: 0.75rem;
221+
font-size: 0.78rem;
222+
letter-spacing: 0.06em;
223+
color: var(--accent);
224+
margin-bottom: 1rem;
225+
display: flex;
226+
align-items: center;
227+
gap: 0.5rem;
228+
}
229+
230+
.log-eyebrow::before {
231+
content: '';
232+
display: inline-block;
233+
width: 1.5rem;
234+
height: 1px;
235+
background: var(--accent);
186236
}
187237

188238
h1 {
@@ -207,6 +257,8 @@ const typeColors: Record<string, string> = {
207257
margin-bottom: 3.5rem;
208258
}
209259

260+
.week-block[hidden] { display: none; }
261+
210262
.week-label {
211263
font-family: 'Syne', sans-serif;
212264
font-weight: 700;
@@ -248,10 +300,8 @@ const typeColors: Record<string, string> = {
248300
.log-entry {
249301
position: relative;
250302
display: flex;
251-
gap: 0;
252303
}
253304

254-
/* Dot on the timeline rail */
255305
.entry-dot {
256306
position: absolute;
257307
left: -1.5rem;
@@ -321,6 +371,52 @@ const typeColors: Record<string, string> = {
321371
margin: 0;
322372
}
323373

374+
/* ── PAGINATION ── */
375+
.pagination {
376+
display: flex;
377+
align-items: center;
378+
justify-content: space-between;
379+
gap: 1rem;
380+
padding-top: 2rem;
381+
border-top: 1px solid var(--border);
382+
margin-top: 1rem;
383+
}
384+
385+
.page-btn {
386+
display: flex;
387+
align-items: center;
388+
gap: 0.4rem;
389+
font-family: 'Syne', sans-serif;
390+
font-size: 0.82rem;
391+
font-weight: 600;
392+
letter-spacing: 0.04em;
393+
color: var(--ink);
394+
background: none;
395+
border: 1px solid var(--border);
396+
border-radius: 6px;
397+
padding: 0.5rem 1rem;
398+
cursor: pointer;
399+
transition: border-color 0.15s, background 0.15s, color 0.15s;
400+
}
401+
402+
.page-btn:hover:not(:disabled) {
403+
border-color: var(--ink);
404+
background: var(--ink);
405+
color: var(--paper);
406+
}
407+
408+
.page-btn:disabled {
409+
opacity: 0.3;
410+
cursor: not-allowed;
411+
}
412+
413+
.page-indicator {
414+
font-family: 'JetBrains Mono', monospace;
415+
font-size: 0.75rem;
416+
color: var(--muted);
417+
letter-spacing: 0.04em;
418+
}
419+
324420
/* ── MOBILE ── */
325421
@media (max-width: 600px) {
326422
.day-group {
@@ -332,9 +428,41 @@ const typeColors: Record<string, string> = {
332428
text-align: left;
333429
padding-top: 0;
334430
}
335-
336-
.day-items {
337-
border-left-width: 2px;
338-
}
339431
}
340432
</style>
433+
434+
<script>
435+
const WEEKS_PER_PAGE = 2;
436+
const weeks = Array.from(document.querySelectorAll<HTMLElement>('.week-block'));
437+
const prevBtn = document.getElementById('prev-btn') as HTMLButtonElement;
438+
const nextBtn = document.getElementById('next-btn') as HTMLButtonElement;
439+
const indicator = document.getElementById('page-indicator')!;
440+
441+
const totalPages = Math.ceil(weeks.length / WEEKS_PER_PAGE);
442+
let currentPage = 0;
443+
444+
function goToPage(page: number) {
445+
currentPage = Math.max(0, Math.min(page, totalPages - 1));
446+
447+
// Show/hide weeks
448+
weeks.forEach((w, i) => {
449+
const onPage = Math.floor(i / WEEKS_PER_PAGE) === currentPage;
450+
w.hidden = !onPage;
451+
});
452+
453+
// Update pagination controls
454+
prevBtn.disabled = currentPage === 0;
455+
nextBtn.disabled = currentPage === totalPages - 1;
456+
indicator.textContent = `Page ${currentPage + 1} of ${totalPages}`;
457+
458+
}
459+
460+
461+
// Prev / next
462+
prevBtn.addEventListener('click', () => goToPage(currentPage - 1));
463+
nextBtn.addEventListener('click', () => goToPage(currentPage + 1));
464+
465+
// Init
466+
goToPage(0);
467+
468+
</script>

0 commit comments

Comments
 (0)