Skip to content

Commit cae25f9

Browse files
committed
Refactor: add Nav component; theme toggle (SVG); extract theme tokens (accent: #006CAC light, #fca311 dark); adjust blog title + headings; update tagline/description; simplify home (hide Projects/Experience); accent navbar divider + active underline
1 parent c04b6dd commit cae25f9

File tree

11 files changed

+149
-38
lines changed

11 files changed

+149
-38
lines changed

public/moon.svg

Lines changed: 4 additions & 0 deletions
Loading

public/sun.svg

Lines changed: 4 additions & 0 deletions
Loading

src/components/Nav.astro

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
---
2+
import { site } from '../site';
3+
const path = Astro.url.pathname;
4+
const isBlog = path.startsWith('/blog');
5+
---
6+
<nav aria-label="Primary" class="topnav">
7+
<a href="/" class="brand">{site.brand}</a>
8+
<div class="links">
9+
<a href="/blog" class:list={{ active: isBlog }}>Blog</a>
10+
<button id="theme-toggle" class="toggle" aria-label="Toggle theme" type="button">
11+
<img src="/moon.svg" alt="" class="icon moon" aria-hidden="true" />
12+
<img src="/sun.svg" alt="" class="icon sun" aria-hidden="true" />
13+
</button>
14+
</div>
15+
16+
</nav>
17+

src/layouts/Base.astro

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
---
22
// Props: title, description
3+
import "../styles/theme.css";
34
import "../styles/global.css";
45
const { title = 'Your Name', description = 'Personal site' } = Astro.props;
56
---
@@ -10,6 +11,16 @@ const { title = 'Your Name', description = 'Personal site' } = Astro.props;
1011
<meta name="viewport" content="width=device-width, initial-scale=1" />
1112
<meta name="description" content={description} />
1213
<meta name="theme-color" content="#ffffff" />
14+
<script>
15+
(function() {
16+
try {
17+
var stored = localStorage.getItem('theme');
18+
var prefersDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
19+
var theme = stored || (prefersDark ? 'dark' : 'light');
20+
document.documentElement.dataset.theme = theme;
21+
} catch (_) { /* no-op */ }
22+
})();
23+
</script>
1324

1425
<link rel="preload" as="font" href="/fonts/geist/GeistMono-Variable.woff2" type="font/woff2" crossorigin>
1526

@@ -20,6 +31,34 @@ const { title = 'Your Name', description = 'Personal site' } = Astro.props;
2031
<main>
2132
<slot />
2233
</main>
34+
<script>
35+
(function() {
36+
function setLabel(btn) {
37+
var theme = document.documentElement.dataset.theme || 'light';
38+
var isDark = theme === 'dark';
39+
btn.setAttribute('aria-pressed', String(isDark));
40+
btn.setAttribute('aria-label', isDark ? 'Switch to light mode' : 'Switch to dark mode');
41+
btn.title = isDark ? 'Light mode' : 'Dark mode';
42+
}
43+
function init() {
44+
var btn = document.getElementById('theme-toggle');
45+
if (!btn) return;
46+
setLabel(btn);
47+
btn.addEventListener('click', function() {
48+
var current = document.documentElement.dataset.theme === 'dark' ? 'dark' : 'light';
49+
var next = current === 'dark' ? 'light' : 'dark';
50+
document.documentElement.dataset.theme = next;
51+
try { localStorage.setItem('theme', next); } catch(_) {}
52+
setLabel(btn);
53+
});
54+
}
55+
if (document.readyState === 'loading') {
56+
document.addEventListener('DOMContentLoaded', init);
57+
} else {
58+
init();
59+
}
60+
})();
61+
</script>
2362
</body>
2463

2564
</html>

src/layouts/PostLayout.astro

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
---
22
import Base from './Base.astro';
3+
import Nav from "../components/Nav.astro";
34
45
interface Props {
56
title: string;
@@ -16,9 +17,7 @@ const formatted = d.toLocaleDateString(undefined, {
1617

1718
<Base title={`${title} — Hidayatullah`} description={description ?? title}>
1819
<div class="wrap">
19-
<nav aria-label="Breadcrumbs" class="muted">
20-
<a href="/">About</a> / <a href="/blog">Blog</a>
21-
</nav>
20+
<Nav />
2221
<article class="post-article">
2322
<header>
2423
<h1 class="post-h1">{title}</h1>
@@ -34,10 +33,11 @@ const formatted = d.toLocaleDateString(undefined, {
3433

3534
<style>
3635
.post-article { margin-top: 0.5rem; }
37-
.post-h1 { margin: 0 0 0.25rem; font-size: clamp(1.6rem, 3.6vw, 2.2rem); }
36+
.post-h1 { margin: 0 0 0.25rem; font-size: clamp(1.35rem, 3vw, 1.9rem); }
3837
.post-meta { color: var(--muted); font-size: 0.9rem; }
3938
.post-summary { color: color-mix(in oklab, var(--text) 85%, transparent); margin: 0.5rem 0 1rem; }
4039
.post-content :is(p, ul, ol, pre, blockquote) { margin: 0 0 var(--space); }
40+
.post-content :global(h1) { font-size: clamp(1.35rem, 3vw, 1.9rem); margin: 0 0 var(--space); }
4141
.post-content code { background: color-mix(in oklab, var(--text) 8%, transparent); padding: 0.05em 0.3em; border-radius: 4px; }
4242
.post-content pre { padding: 0.75rem; border-radius: var(--radius); overflow: auto; }
4343
.post-content blockquote { border-left: 2px solid color-mix(in oklab, var(--text) 20%, transparent); padding-left: 0.75rem; color: var(--muted); }

src/pages/404.astro

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,14 @@
11
---
22
import Base from "../layouts/Base.astro";
3+
import Nav from "../components/Nav.astro";
34
---
45

56
<Base title="404 — Not Found" description="The page you’re looking for doesn’t exist.">
67
<div class="wrap">
7-
<nav aria-label="Primary">
8-
<a href="/">About</a> /
9-
<a href="/blog">Blog</a>
10-
</nav>
8+
<Nav />
119

1210
<h1>Page not found</h1>
1311
<p class="muted">The link may be broken or the page may have moved.</p>
1412
<p><a href="/">← Back to home</a></p>
1513
</div>
1614
</Base>
17-

src/pages/blog.astro

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
---
22
import Base from "../layouts/Base.astro";
3+
import Nav from "../components/Nav.astro";
34
import PostItem from "../components/PostItem.astro";
45
import { getCollection } from 'astro:content';
56
@@ -17,10 +18,7 @@ const posts = all
1718

1819
<Base title="Blog — Hidayatullah" description="All posts by Hidayatullah">
1920
<div class="wrap">
20-
<nav aria-label="Primary">
21-
<a href="/">About</a> /
22-
<a href="/blog">Blog</a>
23-
</nav>
21+
<Nav />
2422
<h1>Blog</h1>
2523
<div class="posts">
2624
{posts.map((p) => <PostItem {...p} />)}

src/pages/index.astro

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
---
22
import Base from "../layouts/Base.astro";
3+
import Nav from "../components/Nav.astro";
4+
import { site } from "../site";
35
import ProjectItem from "../components/ProjectItem.astro";
46
5-
const name = "Hidayatullah";
6-
const tagline = "Developer, systems builder, problem solver.";
7-
const bio = "I like creating practical tools that make work faster, smarter, and easier.";
7+
const name = site.brand;
8+
const tagline = site.tagline;
9+
const bio = site.description;
810
911
const projects = [
1012
{
@@ -30,24 +32,23 @@ const projects = [
3032

3133
<Base title={`${name} — ${tagline}`} description={bio}>
3234
<div class="wrap">
33-
<nav aria-label="Primary">
34-
<a href="/">About</a> /
35-
<a href="/blog">Blog</a>
36-
</nav>
35+
<Nav />
3736

3837
<section id="about">
39-
<h1>{name}</h1>
40-
<span class="kicker">{tagline}</span>
38+
<h1>{tagline}</h1>
4139
<p>{bio}</p>
4240
</section>
4341

42+
<!--
4443
<section id="projects">
4544
<h2>Projects</h2>
4645
<div class="projects">
4746
{projects.map((p) => <ProjectItem {...p} />)}
4847
</div>
4948
</section>
49+
-->
5050

51+
<!--
5152
<section id="experience">
5253
<h2>Work Experience</h2>
5354
<article class="experience">
@@ -61,6 +62,7 @@ const projects = [
6162
</ul>
6263
</article>
6364
</section>
65+
-->
6466

6567

6668

src/site.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export const site = {
2+
brand: 'Hidayatullah',
3+
tagline: 'Learner, automation enthusiast, explorer.',
4+
description: 'I enjoy learning by doing—whether coding, automating workflows, or just trying things out—and sharing what I discover along the way.',
5+
};

src/styles/global.css

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,26 +7,14 @@
77
}
88

99
:root {
10-
--bg: #fafafa;
11-
--text: #111111;
12-
--muted: #6b7280;
13-
--accent: #0ea5e9;
10+
/* sizing/spacing/typography tokens (colors in theme.css) */
1411
--max-w: 68ch;
1512
--lh: 1.6;
1613
--space: clamp(1rem, 2vw, 1.75rem);
1714
--radius: 10px;
1815
--font: "Geist Mono", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
1916
}
2017

21-
@media (prefers-color-scheme: dark) {
22-
:root {
23-
--bg: #0c0c0c;
24-
--text: #e5e7eb;
25-
--muted: #9ca3af;
26-
--accent: #38bdf8;
27-
}
28-
}
29-
3018
* { box-sizing: border-box; }
3119

3220
html, body {
@@ -57,15 +45,33 @@ h1, h2, h3 {
5745
}
5846

5947
h1 { font-size: clamp(1.8rem, 4vw, 2.6rem); }
60-
h2 { font-size: clamp(1.4rem, 3vw, 1.8rem); color: var(--muted); }
48+
h2 { font-size: clamp(1.25rem, 2.5vw, 1.6rem); color: var(--muted); }
49+
/* Tighter spacing under section headings */
50+
h2 { margin: calc(var(--space) * 1.2) 0 calc(var(--space) * 0.75); }
6151

6252
p { margin: 0 0 var(--space); }
6353

6454
a { color: inherit; text-underline-offset: 0.2em; }
6555
a:hover { color: var(--accent); }
6656

67-
nav { margin-bottom: calc(var(--space) * 2); color: var(--muted); }
68-
nav a { margin-right: 0.6rem; }
57+
nav { margin-bottom: calc(var(--space) * 2); color: var(--text); }
58+
[data-theme="dark"] nav { color: #ffffff; }
59+
nav.topnav { display: flex; align-items: center; justify-content: space-between; border-bottom: 1px solid var(--accent); padding-bottom: 0.6rem; margin-bottom: calc(var(--space) * 1.25); }
60+
nav a { margin-right: 0.8rem; text-decoration: none; }
61+
nav a:last-child { margin-right: 0; }
62+
nav .brand { color: inherit; font-variation-settings: "wght" 700; margin-right: 0; font-size: clamp(1.1rem, 2.2vw, 1.4rem); letter-spacing: -0.01em; }
63+
nav .links { display: inline-flex; align-items: center; gap: 0.75rem; }
64+
nav .links a { color: inherit; margin-right: 0; }
65+
nav a.active { text-decoration: underline; text-decoration-color: var(--accent); font-variation-settings: "wght" 600; }
66+
nav a.active:hover { color: inherit; }
67+
nav .toggle { background: none; border: none; color: inherit; cursor: pointer; font: inherit; }
68+
nav .toggle { display: inline-flex; align-items: center; justify-content: center; line-height: 1; padding: 0; width: 1.8rem; height: 1.8rem; }
69+
nav .toggle .icon { display: none; width: 1.3rem; height: 1.3rem; }
70+
[data-theme="light"] nav .toggle .icon.moon { display: block; }
71+
[data-theme="dark"] nav .toggle .icon.sun { display: block; }
72+
[data-theme="dark"] nav .toggle .icon { filter: invert(1); }
73+
[data-theme="light"] nav .toggle .icon.moon { display: inline-block; }
74+
[data-theme="dark"] nav .toggle .icon.sun { display: inline-block; }
6975

7076
section { margin: calc(var(--space) * 2) 0; }
7177

@@ -138,3 +144,10 @@ section { margin: calc(var(--space) * 2) 0; }
138144
border-top: 1px solid color-mix(in oklab, var(--text) 12%, transparent);
139145
}
140146
.experience-title { margin: 0 0 0.5rem; font-size: 1.05rem; }
147+
148+
/* Homepage tagline size (smaller than default h1) */
149+
#about h1 { font-size: clamp(1.4rem, 3.2vw, 2rem); }
150+
151+
/* Make blog titles accent in all themes */
152+
.post-title a,
153+
.post-h1 { color: var(--accent); }

0 commit comments

Comments
 (0)