Skip to content

Commit 8264ba5

Browse files
Copilotulysses4ever
andcommitted
Add dark mode support with toggle button
Co-authored-by: ulysses4ever <[email protected]>
1 parent f3bdd4a commit 8264ba5

4 files changed

Lines changed: 203 additions & 0 deletions

File tree

docs/assets/css/dark-mode.css

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
/* Dark Mode Styles for Learn You a Haskell */
2+
3+
/* Dark mode is activated by adding 'dark-mode' class to body */
4+
body.dark-mode {
5+
background-color: #1a1a1a;
6+
color: #e0e0e0;
7+
}
8+
9+
body.dark-mode.introcontent {
10+
background-image: none;
11+
background-color: #2d2d2d;
12+
}
13+
14+
body.dark-mode .bgwrapper {
15+
background-color: #1a1a1a;
16+
}
17+
18+
body.dark-mode h1,
19+
body.dark-mode h2,
20+
body.dark-mode h3 {
21+
color: #e0e0e0;
22+
}
23+
24+
body.dark-mode a {
25+
color: #66b3ff;
26+
}
27+
28+
body.dark-mode a:visited {
29+
color: #9999ff;
30+
}
31+
32+
body.dark-mode a:hover {
33+
color: #ff6666;
34+
}
35+
36+
body.dark-mode code:not(.label, .function, .type, .class, .law) {
37+
background-color: #2d2d2d;
38+
color: #e0e0e0;
39+
}
40+
41+
body.dark-mode pre > code {
42+
background-color: #0d0d0d;
43+
color: #00ff00;
44+
}
45+
46+
body.dark-mode .hintbox {
47+
background-color: #3d3d1a;
48+
color: #e0e0e0;
49+
}
50+
51+
body.dark-mode .chapters > li > a {
52+
color: #e0e0e0;
53+
border-bottom: 1px solid #404040;
54+
}
55+
56+
body.dark-mode .chapters > li > a:visited {
57+
color: #b0b0b0;
58+
}
59+
60+
body.dark-mode .chapters > li > a:hover {
61+
color: #ff6666;
62+
}
63+
64+
body.dark-mode .chapters > li > ul > li > a {
65+
color: #e0e0e0;
66+
}
67+
68+
body.dark-mode .chapters > li > ul > li > a:visited {
69+
color: #b0b0b0;
70+
}
71+
72+
body.dark-mode .chapters > li > ul > li > a:hover {
73+
color: #ff6666;
74+
}
75+
76+
body.dark-mode .errata {
77+
background-color: #3d1a1a;
78+
color: #e0e0e0;
79+
}
80+
81+
/* Dark mode toggle button */
82+
.dark-mode-toggle {
83+
position: fixed;
84+
top: 40px;
85+
right: 20px;
86+
z-index: 9999;
87+
background-color: #333;
88+
color: white;
89+
border: 2px solid #555;
90+
border-radius: 50%;
91+
width: 50px;
92+
height: 50px;
93+
cursor: pointer;
94+
font-size: 24px;
95+
display: flex;
96+
align-items: center;
97+
justify-content: center;
98+
transition: all 0.3s ease;
99+
box-shadow: 0 2px 5px rgba(0,0,0,0.3);
100+
}
101+
102+
.dark-mode-toggle:hover {
103+
background-color: #444;
104+
transform: scale(1.1);
105+
}
106+
107+
body.dark-mode .dark-mode-toggle {
108+
background-color: #f0f0f0;
109+
color: #333;
110+
border-color: #ccc;
111+
}
112+
113+
body.dark-mode .dark-mode-toggle:hover {
114+
background-color: #e0e0e0;
115+
}
116+
117+
/* Adjust toggle button for mobile */
118+
@media screen and (max-width: 600px) {
119+
.dark-mode-toggle {
120+
width: 45px;
121+
height: 45px;
122+
font-size: 20px;
123+
top: 40px;
124+
right: 10px;
125+
}
126+
}
127+
128+
/* Dark mode for index page specific elements */
129+
body.dark-mode #newsplash {
130+
color: #e0e0e0;
131+
}
132+
133+
body.dark-mode .newsplash a.nostarchlink {
134+
color: #66b3ff;
135+
}
136+
137+
body.dark-mode .newsplash a.nostarchlink:hover {
138+
color: #ff6666;
139+
}

docs/assets/js/dark-mode.js

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// Dark Mode Toggle Functionality for Learn You a Haskell
2+
3+
(function() {
4+
'use strict';
5+
6+
// Check for saved theme preference or default to light mode
7+
const currentTheme = localStorage.getItem('theme') || 'light';
8+
9+
// Apply the theme immediately to prevent flash
10+
if (currentTheme === 'dark') {
11+
document.body.classList.add('dark-mode');
12+
}
13+
14+
// Create and add the toggle button
15+
function createToggleButton() {
16+
const toggleButton = document.createElement('button');
17+
toggleButton.className = 'dark-mode-toggle';
18+
toggleButton.setAttribute('aria-label', 'Toggle dark mode');
19+
toggleButton.setAttribute('title', 'Toggle dark mode');
20+
21+
// Set initial icon based on current theme
22+
updateButtonIcon(toggleButton);
23+
24+
// Add click handler
25+
toggleButton.addEventListener('click', function() {
26+
document.body.classList.toggle('dark-mode');
27+
28+
// Save preference
29+
if (document.body.classList.contains('dark-mode')) {
30+
localStorage.setItem('theme', 'dark');
31+
} else {
32+
localStorage.setItem('theme', 'light');
33+
}
34+
35+
// Update button icon
36+
updateButtonIcon(toggleButton);
37+
});
38+
39+
document.body.appendChild(toggleButton);
40+
}
41+
42+
function updateButtonIcon(button) {
43+
if (document.body.classList.contains('dark-mode')) {
44+
button.innerHTML = '☀️';
45+
button.setAttribute('title', 'Switch to light mode');
46+
} else {
47+
button.innerHTML = '🌙';
48+
button.setAttribute('title', 'Switch to dark mode');
49+
}
50+
}
51+
52+
// Wait for DOM to be ready
53+
if (document.readyState === 'loading') {
54+
document.addEventListener('DOMContentLoaded', createToggleButton);
55+
} else {
56+
createToggleButton();
57+
}
58+
})();

docs/index.html

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
<link rel="stylesheet" href="assets/css/style.css">
1818
<!-- "Donato to Ukraine" top of the page banner -->
1919
<link rel="stylesheet" href="assets/css/ukraine-banner.css">
20+
<!-- Dark Mode Support -->
21+
<link rel="stylesheet" href="assets/css/dark-mode.css">
2022
<link rel="preload" as="image" href="assets/images/newsplash-new-short.webp">
2123
<link rel="preload" as="image" href="assets/images/newsplash-new-long.webp">
2224

@@ -106,6 +108,8 @@ <h1 style="display: none;">A guide to Haskell programming language</h1>
106108
<script async defer src="https://buttons.github.io/buttons.js"></script>
107109
<!-- custom JS -->
108110
<script src="assets/js/toggleShow.js" async></script>
111+
<!-- Dark Mode Toggle -->
112+
<script src="assets/js/dark-mode.js"></script>
109113
<!-- redirect Russia (for now) -->
110114
<!-- <script src="https://redirectrussia.org/v1.js" data-hide-domain="hide" async integrity="sha384-K4/XEYup4kNv/qt2ucIwIH2wLT9I+z3s17CHQNMBB2/E8/Kw2VYsXQKB/7kylubA" crossorigin="anonymous"></script> -->
111115
</body>

markdown/config/template.html

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
<base href="">
99
<link rel="stylesheet" href="assets/css/reset.css">
1010
<link rel="stylesheet" href="assets/css/style.css">
11+
<link rel="stylesheet" href="assets/css/dark-mode.css">
1112
<link rel="shortcut icon" href="assets/images/favicon.png" type="image/png">
1213
$if(prev_filename)$
1314
<link rel="prev" href="${prev_filename}.html">
@@ -73,6 +74,7 @@
7374
<script type="text/javascript" src="sh/Scripts/shCore.js"></script>
7475
<script type="text/javascript" src="sh/Scripts/shBrushHaskell.js"></script>
7576
<script type="text/javascript" src="sh/Scripts/shBrushPlain.js"></script>
77+
<script src="assets/js/dark-mode.js"></script>
7678
<script type="text/javascript">
7779
dp.SyntaxHighlighter.ClipboardSwf = '/sh/Scripts/clipboard.swf';
7880
dp.SyntaxHighlighter.HighlightAll('code', false, false, false, 1, false);

0 commit comments

Comments
 (0)