Skip to content

Commit d70cce7

Browse files
authored
Add night mode (dark mode) toggle feature - Resolves #82 (#161)
1 parent fdc8cd6 commit d70cce7

2 files changed

Lines changed: 234 additions & 0 deletions

File tree

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# Night Mode Implementation
2+
3+
## Overview
4+
This document explains the night mode (dark mode) feature added to the Bioconductor Package Review Documentation website.
5+
6+
## Implementation Details
7+
8+
### Files Modified
9+
- `includes/header.html` - Added dark mode toggle button, CSS styles, and JavaScript functionality
10+
11+
### Features
12+
1. **Toggle Button**: A floating button in the bottom-right corner that allows users to switch between light and dark modes
13+
- Moon icon (🌙) for light mode
14+
- Sun icon (☀️) for dark mode
15+
- Smooth hover animation
16+
17+
2. **Persistent Theme**: User's theme preference is saved in browser's localStorage
18+
- Theme persists across page reloads and navigation
19+
- Automatically applies saved theme on page load
20+
21+
3. **Dark Mode Styling**: Comprehensive dark theme covering:
22+
- Background colors (dark gray/black)
23+
- Text colors (light gray/white)
24+
- Navigation sidebar
25+
- Code blocks
26+
- Tables
27+
- Links and headings
28+
- Header bar
29+
30+
### Color Scheme
31+
**Light Mode** (Default):
32+
- Background: White
33+
- Text: #333E50
34+
- Primary: #6faef5
35+
- Headings: #5c677e
36+
37+
**Dark Mode**:
38+
- Background: #1a1a1a
39+
- Text: #e0e0e0
40+
- Sidebar: #2d2d2d
41+
- Code blocks: #2d2d2d
42+
- Links: #6faef5
43+
- Headings: #87b13f
44+
45+
### How It Works
46+
1. JavaScript creates a toggle button on page load
47+
2. Checks localStorage for saved theme preference
48+
3. Applies dark mode class to body if preference is 'dark'
49+
4. Button click toggles the 'dark-mode' class on body element
50+
5. CSS rules with `.dark-mode` selector override default styles
51+
6. Theme preference is saved to localStorage on each toggle
52+
53+
### Browser Compatibility
54+
- Works in all modern browsers that support:
55+
- localStorage API
56+
- CSS3
57+
- ES6 JavaScript
58+
- Font Awesome icons (already included)
59+
60+
### Testing
61+
To test the implementation:
62+
1. Build the bookdown site
63+
2. Open in a browser
64+
3. Click the toggle button in bottom-right corner
65+
4. Verify dark mode applies correctly
66+
5. Reload page to verify theme persists
67+
6. Navigate to different pages to ensure consistency
68+
69+
## Future Enhancements
70+
Possible improvements:
71+
- System preference detection (prefers-color-scheme media query)
72+
- Keyboard shortcut for toggling
73+
- Smooth transition animations between themes
74+
- Additional color scheme options

includes/header.html

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,164 @@
55
crossorigin="anonymous"
66
referrerpolicy="no-referrer"
77
/>
8+
9+
<style>
10+
/* Dark mode toggle button */
11+
.dark-mode-toggle {
12+
position: fixed;
13+
bottom: 20px;
14+
right: 20px;
15+
z-index: 1000;
16+
background: #6faef5;
17+
border: none;
18+
border-radius: 50%;
19+
width: 50px;
20+
height: 50px;
21+
cursor: pointer;
22+
box-shadow: 0 2px 10px rgba(0,0,0,0.2);
23+
transition: all 0.3s ease;
24+
display: flex;
25+
align-items: center;
26+
justify-content: center;
27+
color: white;
28+
font-size: 20px;
29+
}
30+
31+
.dark-mode-toggle:hover {
32+
transform: scale(1.1);
33+
box-shadow: 0 4px 15px rgba(0,0,0,0.3);
34+
}
35+
36+
/* Dark mode styles */
37+
body.dark-mode {
38+
background-color: #1a1a1a;
39+
color: #e0e0e0;
40+
}
41+
42+
body.dark-mode .book .book-body .page-wrapper .page-inner section.normal {
43+
background-color: #1a1a1a;
44+
color: #e0e0e0;
45+
}
46+
47+
body.dark-mode .book .book-summary {
48+
background-color: #2d2d2d;
49+
color: #e0e0e0;
50+
}
51+
52+
body.dark-mode .book .book-summary ul.summary li a {
53+
color: #b0b0b0;
54+
}
55+
56+
body.dark-mode .book .book-summary ul.summary li.active > a {
57+
color: #6faef5;
58+
}
59+
60+
body.dark-mode .book .book-summary ul.summary li > a:hover {
61+
color: #6faef5;
62+
}
63+
64+
body.dark-mode .book .book-body .page-wrapper .page-inner section.normal a {
65+
color: #6faef5;
66+
}
67+
68+
body.dark-mode h1,
69+
body.dark-mode h2,
70+
body.dark-mode h3,
71+
body.dark-mode h4,
72+
body.dark-mode h5,
73+
body.dark-mode h6 {
74+
color: #87b13f;
75+
}
76+
77+
body.dark-mode .book .book-body .page-wrapper .page-inner section.normal code {
78+
background: #2d2d2d;
79+
color: #e0e0e0;
80+
}
81+
82+
body.dark-mode .book .book-body .page-wrapper .page-inner section.normal pre {
83+
background: #2d2d2d;
84+
border: 1px solid #404040;
85+
}
86+
87+
body.dark-mode div.book-header.fixed[style] {
88+
background-color: #2d2d2d !important;
89+
}
90+
91+
body.dark-mode .book .book-header h1 a,
92+
body.dark-mode .book .book-header h1 a:hover {
93+
color: #e0e0e0;
94+
}
95+
96+
body.dark-mode .book .book-header .btn {
97+
color: #b0b0b0;
98+
}
99+
100+
body.dark-mode .book .book-header .btn:hover {
101+
color: #e0e0e0;
102+
}
103+
104+
body.dark-mode .summaryblock {
105+
background-color: #2d2d2d;
106+
color: #e0e0e0;
107+
border-color: #6faef5;
108+
}
109+
110+
body.dark-mode .part > span {
111+
color: #b0b0b0;
112+
}
113+
114+
body.dark-mode p.caption {
115+
color: #b0b0b0;
116+
}
117+
118+
body.dark-mode table {
119+
background-color: #2d2d2d;
120+
color: #e0e0e0;
121+
}
122+
123+
body.dark-mode table thead {
124+
background-color: #404040;
125+
}
126+
127+
body.dark-mode table tr:nth-child(even) {
128+
background-color: #252525;
129+
}
130+
131+
body.dark-mode .dark-mode-toggle {
132+
background: #404040;
133+
}
134+
</style>
135+
136+
<script>
137+
// Dark mode toggle functionality
138+
document.addEventListener('DOMContentLoaded', function() {
139+
// Create toggle button
140+
const toggleButton = document.createElement('button');
141+
toggleButton.className = 'dark-mode-toggle';
142+
toggleButton.setAttribute('aria-label', 'Toggle dark mode');
143+
toggleButton.innerHTML = '<i class="fas fa-moon"></i>';
144+
document.body.appendChild(toggleButton);
145+
146+
// Check for saved theme preference or default to light mode
147+
const currentTheme = localStorage.getItem('theme') || 'light';
148+
if (currentTheme === 'dark') {
149+
document.body.classList.add('dark-mode');
150+
toggleButton.innerHTML = '<i class="fas fa-sun"></i>';
151+
}
152+
153+
// Toggle theme on button click
154+
toggleButton.addEventListener('click', function() {
155+
document.body.classList.toggle('dark-mode');
156+
157+
// Update icon and save preference
158+
if (document.body.classList.contains('dark-mode')) {
159+
toggleButton.innerHTML = '<i class="fas fa-sun"></i>';
160+
localStorage.setItem('theme', 'dark');
161+
} else {
162+
toggleButton.innerHTML = '<i class="fas fa-moon"></i>';
163+
localStorage.setItem('theme', 'light');
164+
}
165+
});
166+
});
167+
</script>
8168
</head>

0 commit comments

Comments
 (0)