Skip to content

Commit 77cfab1

Browse files
committed
Add light/dark theme selection button
1 parent 4449da7 commit 77cfab1

File tree

2 files changed

+77
-0
lines changed

2 files changed

+77
-0
lines changed

src/components/ThemeToggle.astro

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
<button id="theme-toggle" aria-label="Toggle theme" title="Toggle theme">
2+
<svg id="moon-icon" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-moon">
3+
<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"></path>
4+
</svg>
5+
<svg id="sun-icon" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-sun" style="display: none;">
6+
<circle cx="12" cy="12" r="5"></circle>
7+
<line x1="12" y1="1" x2="12" y2="3"></line>
8+
<line x1="12" y1="21" x2="12" y2="23"></line>
9+
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line>
10+
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line>
11+
<line x1="1" y1="12" x2="3" y2="12"></line>
12+
<line x1="21" y1="12" x2="23" y2="12"></line>
13+
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line>
14+
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line>
15+
</svg>
16+
</button>
17+
18+
<style>
19+
#theme-toggle {
20+
color: var(--pico-text);
21+
background: none;
22+
border: none;
23+
cursor: pointer;
24+
padding: 0.5rem;
25+
position: absolute;
26+
top: 1rem;
27+
right: 1rem;
28+
z-index: 1000;
29+
transition: all 0.3s ease;
30+
}
31+
#theme-toggle:hover {
32+
opacity: 0.8;
33+
}
34+
</style>
35+
36+
<script is:inline>
37+
const themeToggle = document.getElementById('theme-toggle');
38+
const htmlElement = document.documentElement;
39+
const moonIcon = document.getElementById('moon-icon');
40+
const sunIcon = document.getElementById('sun-icon');
41+
42+
const getSavedTheme = () => localStorage.getItem('theme');
43+
const getPreferredTheme = () => window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
44+
45+
const setThemeIcons = (theme) => {
46+
if (theme === 'dark') {
47+
moonIcon.style.display = 'block';
48+
sunIcon.style.display = 'none';
49+
} else {
50+
moonIcon.style.display = 'none';
51+
sunIcon.style.display = 'block';
52+
}
53+
};
54+
55+
const applyTheme = (theme) => {
56+
if (theme === 'dark') {
57+
htmlElement.setAttribute('data-theme', 'dark');
58+
} else {
59+
htmlElement.setAttribute('data-theme', 'light');
60+
}
61+
localStorage.setItem('theme', theme);
62+
setThemeIcons(theme);
63+
};
64+
65+
// Set theme on initial load
66+
const initialTheme = getSavedTheme() || getPreferredTheme();
67+
applyTheme(initialTheme);
68+
69+
themeToggle.addEventListener('click', () => {
70+
const currentTheme = htmlElement.getAttribute('data-theme') === 'dark' ? 'dark' : 'light';
71+
const newTheme = currentTheme === 'dark' ? 'light' : 'dark';
72+
applyTheme(newTheme);
73+
});
74+
</script>

src/layouts/Default.astro

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
---
22
import { languages, markdownify } from '../i18n/config';
3+
import ThemeToggle from '../components/ThemeToggle.astro';
34
45
interface Props {
56
title: string;
@@ -48,6 +49,7 @@ const languageEntries = Object.entries(languages);
4849
<meta name="twitter:image" content="https://keepandroidopen.org/img/altered-deal.png">
4950
<link rel="me" href="https://techhub.social/@keepandroidopen">
5051
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.min.css">
52+
5153
<!-- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.colors.min.css"> -->
5254
<style is:global>
5355

@@ -188,6 +190,7 @@ const languageEntries = Object.entries(languages);
188190
</head>
189191
<body>
190192
<header>
193+
<ThemeToggle />
191194
<h1>{title}</h1>
192195
<div class="lang-menu">
193196
{languageEntries.map(([_code, { label, path }], i) => (

0 commit comments

Comments
 (0)