Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions src/components/BaseHead.astro
Original file line number Diff line number Diff line change
Expand Up @@ -59,4 +59,32 @@ const { title, description, image = "/blog-placeholder-1.jpg" } = Astro.props;
<meta property="twitter:description" content={description} />
<meta property="twitter:image" content={new URL(image, Astro.url)} />

<!-- Theme Script -->
<script is:inline>
const getTheme = () => {
if (typeof localStorage !== "undefined" && localStorage.getItem("theme"))
return localStorage.getItem("theme");
if (window.matchMedia("(prefers-color-scheme: dark)").matches)
return "dark";
return "light";
};

const applyTheme = (theme) => {
if (theme === "dark") document.documentElement.classList.add("dark");
else document.documentElement.classList.remove("dark");
localStorage.setItem("theme", theme);
};

// Expose globally for use by ThemeToggleButton
window.applyTheme = applyTheme;

// Initial load
applyTheme(getTheme());

// View Transitions hook
document.addEventListener("astro:after-swap", () => {
applyTheme(getTheme());
});
</script>

<ClientRouter />
3 changes: 1 addition & 2 deletions src/components/Footer.astro
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@ const today = new Date();
<style>
footer {
padding: 2em 1em 6em 1em;
background: linear-gradient(var(--gray-gradient)) no-repeat;
color: rgb(var(--gray));
text-align: center;
}
Expand All @@ -72,7 +71,7 @@ const today = new Date();
}

.social-links .tech-icon svg {
width: 20px;
width: 1.25rem;
color: rgb(var(--gray));
}

Expand Down
66 changes: 58 additions & 8 deletions src/components/Header.astro
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
---
import HeaderLink from "./HeaderLink.astro";
import ThemeToggleButton from "./ThemeToggleButton.astro";
---

<header>
Expand Down Expand Up @@ -44,15 +45,16 @@ import HeaderLink from "./HeaderLink.astro";
></path></svg
>
</a>
<ThemeToggleButton />
</div>
</nav>
</header>
<style>
header {
margin: 0;
padding: 0 1em;
background: white;
box-shadow: 0 2px 8px rgba(var(--black), 5%);
background: var(--surface-background);
box-shadow: 0 0.125rem 0.5rem rgba(var(--black), 5%);
}

h2 {
Expand All @@ -66,7 +68,7 @@ import HeaderLink from "./HeaderLink.astro";
}
nav {
display: grid;
grid-template-columns: auto auto auto;
grid-template-columns: 1fr auto 1fr;
}

nav div {
Expand All @@ -75,21 +77,21 @@ import HeaderLink from "./HeaderLink.astro";
}

#IconAndTitle {
justify-content: left;
justify-content: flex-start;
}

#InternalLinks {
justify-content: center;
}

#SocialLinks {
justify-content: right;
justify-content: flex-end;
}

nav a {
padding: 1em 0.5em;
color: var(--black);
border-bottom: 4px solid transparent;
border-bottom: 0.25rem solid transparent;
text-decoration: none;
}

Expand All @@ -102,10 +104,58 @@ import HeaderLink from "./HeaderLink.astro";
.social-links a {
display: flex;
}
.social-links a,
#theme-toggle {
padding: 1em 0.5em;
color: var(--black);
border-bottom: 0.25rem solid transparent;
text-decoration: none;
}

@media (max-width: 45rem) {
nav {
grid-template-areas:
"logo"
"social"
"links";
grid-template-columns: 1fr;
grid-template-rows: auto auto auto;
gap: 0.2em;
padding: 1.5em 0;
justify-items: center;
}

#IconAndTitle {
grid-area: logo;
justify-content: center;
margin-right: 0;
}

@media (max-width: 720px) {
.social-links {
/* Make profile icon larger on mobile */
#IconAndTitle img {
width: 5rem;
height: 5rem;
}

#SocialLinks {
grid-area: social;
display: flex;
justify-content: center;
}

#InternalLinks {
grid-area: links;
width: 100%;
justify-content: center;
gap: 1.5em;
}

:global(#theme-toggle) {
display: none;
}
}

:global(#theme-toggle) {
margin-left: 1em;
}
</style>
91 changes: 91 additions & 0 deletions src/components/ThemeToggleButton.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
<button id="theme-toggle" aria-label="Toggle theme">
<svg
class="sun-icon"
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<circle cx="12" cy="12" r="5"></circle>
<line x1="12" y1="1" x2="12" y2="3"></line>
<line x1="12" y1="21" x2="12" y2="23"></line>
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line>
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line>
<line x1="1" y1="12" x2="3" y2="12"></line>
<line x1="21" y1="12" x2="23" y2="12"></line>
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line>
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line>
</svg>
<svg
class="moon-icon"
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"></path>
</svg>
</button>

<style>
#theme-toggle {
border: none;
background: none;
cursor: pointer;
padding: 0.5rem;
color: rgb(var(--black));
border-radius: 50%;
transition:
background-color 0.2s ease,
transform 0.2s ease;
display: flex;
align-items: center;
justify-content: center;
}

#theme-toggle:hover {
background-color: rgb(var(--gray-light));
transform: scale(1.1);
}

/* Default: Light mode -> Show Moon, Hide Sun */
#theme-toggle .sun-icon {
display: none;
}
#theme-toggle .moon-icon {
display: block;
}

/* Dark mode: -> Show Sun, Hide Moon */
:global(html.dark) #theme-toggle .sun-icon {
display: block;
}
:global(html.dark) #theme-toggle .moon-icon {
display: none;
}
</style>

<script>
const handleToggleClick = () => {
const isDark = document.documentElement.classList.contains("dark");
// Call the global applyTheme function exposed from BaseHead.astro
window.applyTheme?.(isDark ? "light" : "dark");
};

const setupThemeToggle = () => {
const themeToggle = document.getElementById("theme-toggle");
themeToggle?.addEventListener("click", handleToggleClick);
};

document.addEventListener("astro:page-load", setupThemeToggle);
</script>
4 changes: 2 additions & 2 deletions src/layouts/BlogPost.astro
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,11 @@ const { title, description, pubDate, updatedDate, heroImage } = Astro.props;
.hero-image img {
display: block;
margin: 0 auto;
border-radius: 12px;
border-radius: 0.75rem;
box-shadow: var(--box-shadow);
}
.prose {
width: 720px;
width: 45rem;
max-width: calc(100% - 2em);
margin: auto;
padding: 1em;
Expand Down
8 changes: 4 additions & 4 deletions src/pages/blog/index.astro
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import Header from "../../components/Header.astro";
import { getImageFromLibrary } from "../../utils";

const posts = (await getCollection("blog")).sort(
(a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf()
(a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf(),
);
---

Expand All @@ -20,7 +20,7 @@ const posts = (await getCollection("blog")).sort(
<BaseHead title={SITE_TITLE} description={SITE_DESCRIPTION} />
<style>
main {
width: 960px;
width: 60rem;
}
ul {
display: flex;
Expand Down Expand Up @@ -50,7 +50,7 @@ const posts = (await getCollection("blog")).sort(
}
ul li img {
margin-bottom: 0.5rem;
border-radius: 12px;
border-radius: 0.75rem;
}
ul li a {
display: block;
Expand All @@ -71,7 +71,7 @@ const posts = (await getCollection("blog")).sort(
ul a:hover img {
box-shadow: var(--box-shadow);
}
@media (max-width: 720px) {
@media (max-width: 45rem) {
ul {
gap: 0.5em;
}
Expand Down
Loading