mirror of
https://github.com/MarginaliaSearch/MarginaliaSearch.git
synced 2025-02-23 21:18:58 +00:00
Merge pull request #98 from samstorment/ThemeSwitcher
OS Independent Theme Switcher
This commit is contained in:
commit
bb06cc9ff3
BIN
code/libraries/array/cpp/resources/libcpp.so
Executable file
BIN
code/libraries/array/cpp/resources/libcpp.so
Executable file
Binary file not shown.
@ -1,6 +1,6 @@
|
|||||||
// This sets the data-has-js attribute on the body tag to true, so we can style the page with the assumption that
|
// This sets the data-has-js attribute on the html tag to true, so we can style the page with the assumption that
|
||||||
// the browser supports JS. This is a progressive enhancement, so the page will still work without JS.
|
// the browser supports JS. This is a progressive enhancement, so the page will still work without JS.
|
||||||
document.getElementsByTagName('body')[0].setAttribute('data-has-js', 'true');
|
document.documentElement.setAttribute('data-has-js', 'true');
|
||||||
|
|
||||||
// To prevent the filter menu from being opened when the user hits enter on the search box, we need to add a keydown
|
// To prevent the filter menu from being opened when the user hits enter on the search box, we need to add a keydown
|
||||||
// handler to the search box that stops the event from propagating. Janky hack, but it works.
|
// handler to the search box that stops the event from propagating. Janky hack, but it works.
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
:root {
|
:root {
|
||||||
|
color-scheme: light;
|
||||||
|
|
||||||
--clr-bg-page: hsl(60, 42%, 95%); // $nicotine-light
|
--clr-bg-page: hsl(60, 42%, 95%); // $nicotine-light
|
||||||
|
|
||||||
--clr-bg-ui: hsl(0, 0%, 100%);
|
--clr-bg-ui: hsl(0, 0%, 100%);
|
||||||
@ -26,29 +28,41 @@
|
|||||||
--font-family-heading: serif; // $heading-fonts
|
--font-family-heading: serif; // $heading-fonts
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@mixin dark-theme-mixin {
|
||||||
|
color-scheme: dark;
|
||||||
|
|
||||||
|
--clr-bg-page: hsl(0, 0%, 6%);
|
||||||
|
|
||||||
|
--clr-bg-ui: hsl(0, 0%, 18%);
|
||||||
|
--clr-text-ui: #ddd;
|
||||||
|
|
||||||
|
--clr-bg-theme: hsl(0, 0%, 2%);
|
||||||
|
--clr-text-theme: var(--clr-text-ui);
|
||||||
|
|
||||||
|
--clr-bg-highlight: hsl(0, 0%, 11%);
|
||||||
|
--clr-text-highlight: #fff;
|
||||||
|
|
||||||
|
--clr-bg-accent: hsl(200, 32%, 28%);
|
||||||
|
--clr-border-accent: hsl(200, 8%, 12%);
|
||||||
|
|
||||||
|
--clr-border: hsl(0, 0%, 30%);
|
||||||
|
|
||||||
|
--clr-shadow: #000;
|
||||||
|
|
||||||
|
--clr-link: #8a8aff;
|
||||||
|
--clr-link-visited: #ffadff;
|
||||||
|
--clr-heading-link-visited: var(--clr-link-visited);
|
||||||
|
}
|
||||||
|
|
||||||
|
:root[data-theme='dark'] {
|
||||||
|
@include dark-theme-mixin;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Makes theme match the user's OS preference when JS is disabled
|
||||||
@media (prefers-color-scheme: dark) {
|
@media (prefers-color-scheme: dark) {
|
||||||
:root {
|
:root:not([data-has-js="true"]) {
|
||||||
--clr-bg-page: hsl(0, 0%, 6%);
|
@include dark-theme-mixin;
|
||||||
|
|
||||||
--clr-bg-ui: hsl(0, 0%, 18%);
|
|
||||||
--clr-text-ui: #ddd;
|
|
||||||
|
|
||||||
--clr-bg-theme: hsl(0, 0%, 2%);
|
|
||||||
--clr-text-theme: var(--clr-text-ui);
|
|
||||||
|
|
||||||
--clr-bg-highlight: hsl(0, 0%, 11%);
|
|
||||||
--clr-text-highlight: #fff;
|
|
||||||
|
|
||||||
--clr-bg-accent: hsl(200, 32%, 28%);
|
|
||||||
--clr-border-accent: hsl(200, 8%, 12%);
|
|
||||||
|
|
||||||
--clr-border: hsl(0, 0%, 30%);
|
|
||||||
|
|
||||||
--clr-shadow: #000;
|
|
||||||
|
|
||||||
--clr-link: #8a8aff;
|
|
||||||
--clr-link-visited: #ffadff;
|
|
||||||
--clr-heading-link-visited: var(--clr-link-visited);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,10 +70,6 @@
|
|||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
html {
|
|
||||||
color-scheme: light dark;
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
a {
|
||||||
color: var(--clr-link);
|
color: var(--clr-link);
|
||||||
}
|
}
|
||||||
@ -199,6 +209,9 @@ header {
|
|||||||
color: var(--clr-text-ui);
|
color: var(--clr-text-ui);
|
||||||
box-shadow: 0 0 0.5ch var(--clr-shadow);
|
box-shadow: 0 0 0.5ch var(--clr-shadow);
|
||||||
margin-bottom: 1ch;
|
margin-bottom: 1ch;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
nav {
|
nav {
|
||||||
a {
|
a {
|
||||||
@ -228,6 +241,15 @@ header {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#theme {
|
||||||
|
padding: .5ch;
|
||||||
|
display: none;
|
||||||
|
|
||||||
|
[data-has-js='true'] & {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#complaint {
|
#complaint {
|
||||||
@extend .dialog;
|
@extend .dialog;
|
||||||
max-width: 60ch;
|
max-width: 60ch;
|
||||||
@ -333,10 +355,8 @@ section.cards {
|
|||||||
line-height: 1.6;
|
line-height: 1.6;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (prefers-color-scheme: dark) {
|
[data-theme='dark'] & {
|
||||||
& {
|
border: 1px solid var(--clr-border);
|
||||||
border: 1px solid var(--clr-border);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -525,6 +545,8 @@ footer {
|
|||||||
font-family: var(--font-family-heading);
|
font-family: var(--font-family-heading);
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
}
|
}
|
||||||
|
|
||||||
#suggestions-anchor {
|
#suggestions-anchor {
|
||||||
@ -717,7 +739,7 @@ footer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@media (max-device-width: 624px) {
|
@media (max-device-width: 624px) {
|
||||||
body[data-has-js="true"] { // This property is set via js so we can selectively enable these changes only if JS is enabled;
|
[data-has-js="true"] body { // This property is set via js so we can selectively enable these changes only if JS is enabled;
|
||||||
// This is desirable since mobile navigation is JS-driven. If JS is disabled, having a squished
|
// This is desirable since mobile navigation is JS-driven. If JS is disabled, having a squished
|
||||||
// GUI is better than having no working UI.
|
// GUI is better than having no working UI.
|
||||||
margin: 0 !important;
|
margin: 0 !important;
|
||||||
@ -733,6 +755,8 @@ footer {
|
|||||||
#mcfeast {
|
#mcfeast {
|
||||||
display: inline;
|
display: inline;
|
||||||
float: right;
|
float: right;
|
||||||
|
width: 2rem;
|
||||||
|
font-size: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
#menu-close {
|
#menu-close {
|
||||||
|
@ -0,0 +1,57 @@
|
|||||||
|
function getTheme() {
|
||||||
|
const theme = window.localStorage.getItem('theme');
|
||||||
|
|
||||||
|
// if a valid theme is set in localStorage, return it
|
||||||
|
if (theme === 'dark' || theme === 'light') {
|
||||||
|
return { value: theme, system: false };
|
||||||
|
}
|
||||||
|
|
||||||
|
// if matchMedia is supported and OS theme is dark
|
||||||
|
if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
|
||||||
|
return { value: 'dark', system: true };
|
||||||
|
}
|
||||||
|
|
||||||
|
return { value: 'light', system: true };
|
||||||
|
}
|
||||||
|
|
||||||
|
function setTheme(value) {
|
||||||
|
if (value === 'dark' || value === 'light') {
|
||||||
|
window.localStorage.setItem('theme', value);
|
||||||
|
} else {
|
||||||
|
window.localStorage.removeItem('theme');
|
||||||
|
}
|
||||||
|
|
||||||
|
const theme = getTheme();
|
||||||
|
|
||||||
|
document.documentElement.setAttribute('data-theme', theme.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
function initializeTheme() {
|
||||||
|
const themeSelect = document.getElementById('theme-select');
|
||||||
|
|
||||||
|
const theme = getTheme();
|
||||||
|
|
||||||
|
document.documentElement.setAttribute('data-theme', theme.value);
|
||||||
|
|
||||||
|
// system is selected by default in the themeSwitcher so ignore it here
|
||||||
|
if (!theme.system) {
|
||||||
|
themeSelect.value = theme.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
themeSelect.addEventListener('change', e => {
|
||||||
|
setTheme(e.target.value);
|
||||||
|
});
|
||||||
|
|
||||||
|
const mql = window.matchMedia('(prefers-color-scheme: dark)');
|
||||||
|
|
||||||
|
// if someone changes their theme at the OS level we need to update
|
||||||
|
// their theme immediately if they're using their OS theme
|
||||||
|
mql.addEventListener('change', e => {
|
||||||
|
if (themeSelect.value !== 'system') return;
|
||||||
|
|
||||||
|
if (e.matches) setTheme('dark');
|
||||||
|
else setTheme('light');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
initializeTheme();
|
@ -7,4 +7,15 @@
|
|||||||
<a href="https://memex.marginalia.nu/projects/edge/supporting.gmi">Donate</a>
|
<a href="https://memex.marginalia.nu/projects/edge/supporting.gmi">Donate</a>
|
||||||
<a class="extra" href="https://search.marginalia.nu/explore/random">Random</a>
|
<a class="extra" href="https://search.marginalia.nu/explore/random">Random</a>
|
||||||
</nav>
|
</nav>
|
||||||
|
<div id="theme">
|
||||||
|
<label for="theme-select" class="screenreader-only">Color Theme</label>
|
||||||
|
<select id="theme-select">
|
||||||
|
<option value="system" selected>System</option>
|
||||||
|
<option value="light">Light</option>
|
||||||
|
<option value="dark">Dark</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
|
<!-- load this ASAP to avoid color theme flicker -->
|
||||||
|
<script src="/theme.js"></script>
|
Loading…
Reference in New Issue
Block a user