Added color switching, moved scripts into dedicated files
This commit is contained in:
+123
-24
@@ -1,4 +1,4 @@
|
|||||||
@import url("pygments.css");
|
@import url("pygments.css");
|
||||||
@import url("pygments-dark.css") (prefers-color-theme: dark);
|
@import url("pygments-dark.css") (prefers-color-theme: dark);
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
@@ -44,9 +44,16 @@
|
|||||||
:root {
|
:root {
|
||||||
--main-bg-color: hsl(210, 20%, 98%);
|
--main-bg-color: hsl(210, 20%, 98%);
|
||||||
--main-text-color: hsl(0, 5%, 10%);
|
--main-text-color: hsl(0, 5%, 10%);
|
||||||
--main-link-color: hsl(0, 100%, 35%);
|
--main-link-color: hsl(220, 90%, 45%);
|
||||||
|
--accent-default: hsl(220, 90%, 45%);
|
||||||
|
--accent-alt: hsl(140, 45%, 28%);
|
||||||
--table-border-color: hsl(0, 0%, 85%);
|
--table-border-color: hsl(0, 0%, 85%);
|
||||||
--table-head-border-color: hsl(0, 0%, 70%);
|
--table-head-border-color: hsl(0, 0%, 70%);
|
||||||
|
--main-font: 'Latin Modern', Georgia, Cambria, 'Times New Roman', Times, serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
html[data-font="sans"] {
|
||||||
|
--main-font: 'Segoe UI', system-ui, -apple-system, Roboto, Helvetica, Arial, sans-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (prefers-color-scheme: dark) {
|
@media (prefers-color-scheme: dark) {
|
||||||
@@ -54,6 +61,8 @@
|
|||||||
--main-bg-color: hsl(0, 5%, 10%);
|
--main-bg-color: hsl(0, 5%, 10%);
|
||||||
--main-text-color: hsl(210, 20%, 98%);
|
--main-text-color: hsl(210, 20%, 98%);
|
||||||
--main-link-color: hsl(0, 100%, 65%);
|
--main-link-color: hsl(0, 100%, 65%);
|
||||||
|
--accent-default: hsl(0, 100%, 65%);
|
||||||
|
--accent-alt: hsl(55, 100%, 60%);
|
||||||
--table-border-color: hsl(0, 0%, 15%);
|
--table-border-color: hsl(0, 0%, 15%);
|
||||||
--table-head-border-color: hsl(0, 0%, 30%);
|
--table-head-border-color: hsl(0, 0%, 30%);
|
||||||
}
|
}
|
||||||
@@ -63,6 +72,8 @@
|
|||||||
--main-bg-color: hsl(0, 5%, 10%);
|
--main-bg-color: hsl(0, 5%, 10%);
|
||||||
--main-text-color: hsl(210, 20%, 98%);
|
--main-text-color: hsl(210, 20%, 98%);
|
||||||
--main-link-color: hsl(0, 100%, 65%);
|
--main-link-color: hsl(0, 100%, 65%);
|
||||||
|
--accent-default: hsl(0, 100%, 65%);
|
||||||
|
--accent-alt: hsl(55, 100%, 60%);
|
||||||
--table-border-color: hsl(0, 0%, 15%);
|
--table-border-color: hsl(0, 0%, 15%);
|
||||||
--table-head-border-color: hsl(0, 0%, 30%);
|
--table-head-border-color: hsl(0, 0%, 30%);
|
||||||
}
|
}
|
||||||
@@ -70,11 +81,29 @@
|
|||||||
:root[data-theme="light"] {
|
:root[data-theme="light"] {
|
||||||
--main-bg-color: hsl(210, 20%, 98%);
|
--main-bg-color: hsl(210, 20%, 98%);
|
||||||
--main-text-color: hsl(0, 5%, 10%);
|
--main-text-color: hsl(0, 5%, 10%);
|
||||||
--main-link-color: hsl(0, 100%, 35%);
|
--main-link-color: hsl(220, 90%, 45%);
|
||||||
|
--accent-default: hsl(220, 90%, 45%);
|
||||||
|
--accent-alt: hsl(140, 45%, 28%);
|
||||||
--table-border-color: hsl(0, 0%, 85%);
|
--table-border-color: hsl(0, 0%, 85%);
|
||||||
--table-head-border-color: hsl(0, 0%, 70%);
|
--table-head-border-color: hsl(0, 0%, 70%);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Accent-Alt-Override */
|
||||||
|
:root[data-accent="alt"]:not([data-theme="dark"]) {
|
||||||
|
--main-link-color: hsl(140, 45%, 28%);
|
||||||
|
--main-bg-color: hsl(35, 30%, 92%);
|
||||||
|
}
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
:root[data-accent="alt"]:not([data-theme]) {
|
||||||
|
--main-link-color: hsl(55, 100%, 60%);
|
||||||
|
--main-bg-color: hsl(260, 15%, 8%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
:root[data-theme="dark"][data-accent="alt"] {
|
||||||
|
--main-link-color: hsl(55, 100%, 60%);
|
||||||
|
--main-bg-color: hsl(260, 15%, 8%);
|
||||||
|
}
|
||||||
|
|
||||||
*, *::before, *::after {
|
*, *::before, *::after {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
@@ -106,6 +135,7 @@ body {
|
|||||||
color: var(--main-text-color);
|
color: var(--main-text-color);
|
||||||
background-color: var(--main-bg-color);
|
background-color: var(--main-bg-color);
|
||||||
text-rendering: optimizeLegibility;
|
text-rendering: optimizeLegibility;
|
||||||
|
font-family: var(--main-font);
|
||||||
}
|
}
|
||||||
|
|
||||||
header {
|
header {
|
||||||
@@ -151,6 +181,7 @@ a:not([class]) {
|
|||||||
|
|
||||||
a, a:visited {
|
a, a:visited {
|
||||||
color: var(--main-link-color);
|
color: var(--main-link-color);
|
||||||
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
a:focus {
|
a:focus {
|
||||||
@@ -158,6 +189,10 @@ a:focus {
|
|||||||
outline: 2px solid hsl(220, 90%, 52%);
|
outline: 2px solid hsl(220, 90%, 52%);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
a:hover,
|
||||||
|
a:focus-visible {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
h1 {
|
h1 {
|
||||||
font-size: 2.5rem;
|
font-size: 2.5rem;
|
||||||
@@ -218,7 +253,8 @@ ul.menuitems {
|
|||||||
font-size: 0.9rem;
|
font-size: 0.9rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
#theme-toggle {
|
#theme-toggle,
|
||||||
|
#font-toggle {
|
||||||
background: none;
|
background: none;
|
||||||
border: none;
|
border: none;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
@@ -235,15 +271,42 @@ ul.menuitems {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#theme-toggle:hover,
|
#theme-toggle:hover,
|
||||||
#theme-toggle:focus-visible {
|
#theme-toggle:focus-visible,
|
||||||
|
#font-toggle:hover,
|
||||||
|
#font-toggle:focus-visible {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#theme-toggle:focus-visible {
|
#accent-toggle {
|
||||||
|
width: 0.9rem;
|
||||||
|
height: 0.9rem;
|
||||||
|
padding: 0;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: linear-gradient(90deg, var(--accent-default) 50%, var(--accent-alt) 50%);
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
opacity: 0.85;
|
||||||
|
transition: opacity 0.15s ease, transform 0.15s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
#accent-toggle:hover,
|
||||||
|
#accent-toggle:focus-visible {
|
||||||
|
opacity: 1;
|
||||||
|
transform: scale(1.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#theme-toggle:focus-visible,
|
||||||
|
#accent-toggle:focus-visible,
|
||||||
|
#font-toggle:focus-visible {
|
||||||
outline: 2px solid hsl(220, 90%, 52%);
|
outline: 2px solid hsl(220, 90%, 52%);
|
||||||
outline-offset: 2px;
|
outline-offset: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#font-toggle {
|
||||||
|
font-family: sans-serif;
|
||||||
|
font-size: 0.95rem;
|
||||||
|
}
|
||||||
|
|
||||||
#banner, #contentinfo {
|
#banner, #contentinfo {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
@@ -283,6 +346,38 @@ ul.menuitems {
|
|||||||
content: "Categories:";
|
content: "Categories:";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#tag-cloud {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 0.5rem;
|
||||||
|
list-style: none;
|
||||||
|
max-width: 300px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#tag-cloud:before {
|
||||||
|
content: "Tags:";
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
font-size: 1.4rem;
|
||||||
|
line-height: 1.8rem;
|
||||||
|
margin-bottom: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
#tag-cloud li {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#tag-cloud a {
|
||||||
|
display: inline;
|
||||||
|
-webkit-line-clamp: unset;
|
||||||
|
overflow: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
#tag-cloud li.tag-weight-1 a { font-size: 0.7rem; opacity: 0.7; }
|
||||||
|
#tag-cloud li.tag-weight-2 a { font-size: 0.8rem; opacity: 0.85; }
|
||||||
|
#tag-cloud li.tag-weight-3 a { font-size: 0.9rem; opacity: 1; }
|
||||||
|
#tag-cloud li.tag-weight-4 a { font-size: 1rem; opacity: 1; font-weight: bold; }
|
||||||
|
|
||||||
#translations {
|
#translations {
|
||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
@@ -333,15 +428,9 @@ html[lang="de"] {
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
line-height: 1.3;
|
line-height: 1.3;
|
||||||
text-decoration: none;
|
|
||||||
padding-bottom: 1px;
|
padding-bottom: 1px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.menuitems a:hover,
|
|
||||||
.menuitems a:focus-visible {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
#content {
|
#content {
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
}
|
}
|
||||||
@@ -413,14 +502,6 @@ footer.post-info {
|
|||||||
color: var(--main-link-color);
|
color: var(--main-link-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.toc a {
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.toc a:hover {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Headings
|
* Headings
|
||||||
*/
|
*/
|
||||||
@@ -514,10 +595,23 @@ footer.post-info {
|
|||||||
* Images
|
* Images
|
||||||
*/
|
*/
|
||||||
|
|
||||||
.entry-content img {
|
img, svg {
|
||||||
|
max-width: 100%;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
svg.injected-svg text,
|
||||||
|
svg.injected-svg tspan {
|
||||||
|
font-family: var(--main-font);
|
||||||
|
}
|
||||||
|
|
||||||
|
.entry-content img,
|
||||||
|
.entry-content svg.injected-svg {
|
||||||
counter-increment: figures;
|
counter-increment: figures;
|
||||||
display: block;
|
display: block;
|
||||||
max-width: 80%;
|
max-width: 80%;
|
||||||
|
width: auto;
|
||||||
|
height: auto;
|
||||||
margin: 0 auto 0 auto;
|
margin: 0 auto 0 auto;
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
cursor: zoom-in;
|
cursor: zoom-in;
|
||||||
@@ -565,15 +659,20 @@ footer.post-info {
|
|||||||
max-height: 95vh;
|
max-height: 95vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
.lightbox-overlay img {
|
.lightbox-overlay #lightbox-media {
|
||||||
|
max-width: 95vw;
|
||||||
|
max-height: 85vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lightbox-overlay #lightbox-media img,
|
||||||
|
.lightbox-overlay #lightbox-media svg {
|
||||||
max-width: 95vw;
|
max-width: 95vw;
|
||||||
max-height: 85vh;
|
max-height: 85vh;
|
||||||
object-fit: contain;
|
object-fit: contain;
|
||||||
background: #fff;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.lightbox-overlay #lightbox-caption {
|
.lightbox-overlay #lightbox-caption {
|
||||||
color: #111;
|
color: var(--main-text-color);
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin-top: 0.75rem;
|
margin-top: 0.75rem;
|
||||||
font-size: 0.95rem;
|
font-size: 0.95rem;
|
||||||
|
|||||||
@@ -0,0 +1,63 @@
|
|||||||
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
|
const overlay = document.getElementById('lightbox-overlay');
|
||||||
|
const mediaContainer = document.getElementById('lightbox-media');
|
||||||
|
const overlayCaption = document.getElementById('lightbox-caption');
|
||||||
|
|
||||||
|
function openLightboxWithImg(src, alt, figureNumber, captionText) {
|
||||||
|
mediaContainer.innerHTML = '';
|
||||||
|
const img = document.createElement('img');
|
||||||
|
img.src = src;
|
||||||
|
img.alt = alt;
|
||||||
|
mediaContainer.appendChild(img);
|
||||||
|
setCaption(figureNumber, captionText);
|
||||||
|
overlay.classList.add('active');
|
||||||
|
}
|
||||||
|
|
||||||
|
function openLightboxWithSvg(svgEl, figureNumber, captionText) {
|
||||||
|
mediaContainer.innerHTML = '';
|
||||||
|
const svgClone = svgEl.cloneNode(true);
|
||||||
|
mediaContainer.appendChild(svgClone);
|
||||||
|
setCaption(figureNumber, captionText);
|
||||||
|
overlay.classList.add('active');
|
||||||
|
}
|
||||||
|
|
||||||
|
function setCaption(figureNumber, captionText) {
|
||||||
|
overlayCaption.innerHTML = captionText
|
||||||
|
? '<span class="fig-number">Figure ' + figureNumber + ':</span> ' + captionText
|
||||||
|
: '';
|
||||||
|
}
|
||||||
|
|
||||||
|
document.querySelectorAll('.entry-content img').forEach(function (img, index) {
|
||||||
|
const figureNumber = index + 1;
|
||||||
|
const originalSrc = img.src;
|
||||||
|
const originalAlt = img.alt;
|
||||||
|
const captionEl = img.nextElementSibling;
|
||||||
|
const captionText = (captionEl && captionEl.tagName === 'EM') ? captionEl.textContent : '';
|
||||||
|
|
||||||
|
img.addEventListener('click', function () {
|
||||||
|
openLightboxWithImg(originalSrc, originalAlt, figureNumber, captionText);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
document.addEventListener('svg-injected', function (e) {
|
||||||
|
const svgEl = e.detail.svgEl;
|
||||||
|
svgEl.style.cursor = 'zoom-in';
|
||||||
|
svgEl.addEventListener('click', function () {
|
||||||
|
openLightboxWithSvg(svgEl, e.detail.figureNumber, e.detail.captionText);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
overlay.addEventListener('click', function () {
|
||||||
|
overlay.classList.remove('active');
|
||||||
|
mediaContainer.innerHTML = '';
|
||||||
|
overlayCaption.innerHTML = '';
|
||||||
|
});
|
||||||
|
|
||||||
|
document.addEventListener('keydown', function (e) {
|
||||||
|
if (e.key === 'Escape') {
|
||||||
|
overlay.classList.remove('active');
|
||||||
|
mediaContainer.innerHTML = '';
|
||||||
|
overlayCaption.innerHTML = '';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
|
const injectedSvgs = [];
|
||||||
|
|
||||||
|
function parseColorMap(cssText, prop) {
|
||||||
|
const map = {};
|
||||||
|
const regex = new RegExp('\\[' + prop + '="([^"]+)"\\]\\s*{\\s*' + prop + ':\\s*([^;]+);', 'g');
|
||||||
|
let m;
|
||||||
|
while ((m = regex.exec(cssText)) !== null) {
|
||||||
|
map[m[1]] = m[2].trim();
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyThemeToSvg(entry, isDark) {
|
||||||
|
const { svgEl, fillMap, strokeMap } = entry;
|
||||||
|
|
||||||
|
Object.keys(fillMap).forEach(function (lightColor) {
|
||||||
|
svgEl.querySelectorAll('[fill="' + lightColor + '"]').forEach(function (el) {
|
||||||
|
el.setAttribute('fill', isDark ? fillMap[lightColor] : lightColor);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.keys(strokeMap).forEach(function (lightColor) {
|
||||||
|
svgEl.querySelectorAll('[stroke="' + lightColor + '"]').forEach(function (el) {
|
||||||
|
el.setAttribute('stroke', isDark ? strokeMap[lightColor] : lightColor);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getIsDark() {
|
||||||
|
const attr = document.documentElement.getAttribute('data-theme');
|
||||||
|
if (attr) return attr === 'dark';
|
||||||
|
return window.matchMedia('(prefers-color-scheme: dark)').matches;
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyThemeToAll() {
|
||||||
|
const isDark = getIsDark();
|
||||||
|
injectedSvgs.forEach(function (entry) {
|
||||||
|
applyThemeToSvg(entry, isDark);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const svgImages = document.querySelectorAll('.entry-content img[src$=".svg"]');
|
||||||
|
|
||||||
|
svgImages.forEach(function (img, index) {
|
||||||
|
const figureNumber = index + 1;
|
||||||
|
const originalSrc = img.src;
|
||||||
|
const originalAlt = img.alt;
|
||||||
|
const captionEl = img.nextElementSibling;
|
||||||
|
const captionText = (captionEl && captionEl.tagName === 'EM') ? captionEl.textContent : '';
|
||||||
|
|
||||||
|
fetch(img.src)
|
||||||
|
.then(function (response) { return response.text(); })
|
||||||
|
.then(function (svgText) {
|
||||||
|
const parser = new DOMParser();
|
||||||
|
const svgDoc = parser.parseFromString(svgText, 'image/svg+xml');
|
||||||
|
const svgEl = svgDoc.querySelector('svg');
|
||||||
|
|
||||||
|
if (!svgEl) return;
|
||||||
|
|
||||||
|
if (img.alt) {
|
||||||
|
svgEl.setAttribute('role', 'img');
|
||||||
|
svgEl.setAttribute('aria-label', img.alt);
|
||||||
|
}
|
||||||
|
|
||||||
|
svgEl.classList.add('injected-svg');
|
||||||
|
|
||||||
|
// Dark-Farbzuordnung aus dem internen <style>-Block auslesen, dann Block entfernen
|
||||||
|
const styleEl = svgEl.querySelector('style');
|
||||||
|
let fillMap = {};
|
||||||
|
let strokeMap = {};
|
||||||
|
if (styleEl) {
|
||||||
|
fillMap = parseColorMap(styleEl.textContent, 'fill');
|
||||||
|
strokeMap = parseColorMap(styleEl.textContent, 'stroke');
|
||||||
|
styleEl.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
img.replaceWith(svgEl);
|
||||||
|
|
||||||
|
const entry = { svgEl: svgEl, fillMap: fillMap, strokeMap: strokeMap };
|
||||||
|
injectedSvgs.push(entry);
|
||||||
|
applyThemeToSvg(entry, getIsDark());
|
||||||
|
|
||||||
|
document.dispatchEvent(new CustomEvent('svg-injected', {
|
||||||
|
detail: { svgEl: svgEl, originalSrc: originalSrc, originalAlt: originalAlt, figureNumber: figureNumber, captionText: captionText }
|
||||||
|
}));
|
||||||
|
})
|
||||||
|
.catch(function (err) {
|
||||||
|
console.error('SVG injection failed for', img.src, err);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
document.addEventListener('themechange', applyThemeToAll);
|
||||||
|
});
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
(function () {
|
||||||
|
const storedTheme = localStorage.getItem('theme');
|
||||||
|
if (storedTheme === 'dark' || storedTheme === 'light') {
|
||||||
|
document.documentElement.setAttribute('data-theme', storedTheme);
|
||||||
|
}
|
||||||
|
const storedFont = localStorage.getItem('font');
|
||||||
|
if (storedFont === 'sans' || storedFont === 'serif') {
|
||||||
|
document.documentElement.setAttribute('data-font', storedFont);
|
||||||
|
}
|
||||||
|
const storedAccent = localStorage.getItem('accent');
|
||||||
|
if (storedAccent === 'alt' || storedAccent === 'default') {
|
||||||
|
document.documentElement.setAttribute('data-accent', storedAccent);
|
||||||
|
}
|
||||||
|
})();
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
|
const root = document.documentElement;
|
||||||
|
|
||||||
|
// Theme toggle
|
||||||
|
const toggleBtn = document.getElementById('theme-toggle');
|
||||||
|
|
||||||
|
function getCurrentTheme() {
|
||||||
|
const attr = root.getAttribute('data-theme');
|
||||||
|
if (attr) return attr;
|
||||||
|
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateIcon() {
|
||||||
|
toggleBtn.textContent = getCurrentTheme() === 'dark' ? '☀' : '☾';
|
||||||
|
}
|
||||||
|
updateIcon();
|
||||||
|
toggleBtn.addEventListener('click', function () {
|
||||||
|
const next = getCurrentTheme() === 'dark' ? 'light' : 'dark';
|
||||||
|
root.setAttribute('data-theme', next);
|
||||||
|
localStorage.setItem('theme', next);
|
||||||
|
updateIcon();
|
||||||
|
document.dispatchEvent(new CustomEvent('themechange'));
|
||||||
|
});
|
||||||
|
|
||||||
|
// Accent toggle
|
||||||
|
const accentToggleBtn = document.getElementById('accent-toggle');
|
||||||
|
|
||||||
|
function getCurrentAccent() {
|
||||||
|
return root.getAttribute('data-accent') === 'alt' ? 'alt' : 'default';
|
||||||
|
}
|
||||||
|
|
||||||
|
accentToggleBtn.addEventListener('click', function () {
|
||||||
|
const next = getCurrentAccent() === 'alt' ? 'default' : 'alt';
|
||||||
|
root.setAttribute('data-accent', next);
|
||||||
|
localStorage.setItem('accent', next);
|
||||||
|
document.dispatchEvent(new CustomEvent('themechange'));
|
||||||
|
});
|
||||||
|
|
||||||
|
// Font toggle
|
||||||
|
const fontToggleBtn = document.getElementById('font-toggle');
|
||||||
|
|
||||||
|
function getCurrentFont() {
|
||||||
|
return root.getAttribute('data-font') === 'sans' ? 'sans' : 'serif';
|
||||||
|
}
|
||||||
|
|
||||||
|
fontToggleBtn.addEventListener('click', function () {
|
||||||
|
const next = getCurrentFont() === 'sans' ? 'serif' : 'sans';
|
||||||
|
root.setAttribute('data-font', next);
|
||||||
|
localStorage.setItem('font', next);
|
||||||
|
});
|
||||||
|
});
|
||||||
+26
-70
@@ -6,14 +6,9 @@
|
|||||||
{% block head %}
|
{% block head %}
|
||||||
<title>{% block title %}{{ SITENAME }}{% endblock title %}</title>
|
<title>{% block title %}{{ SITENAME }}{% endblock title %}</title>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<script>
|
|
||||||
(function () {
|
<script src="{{ main_siteurl | default(SITEURL) }}/theme/js/theme-init.js"></script>
|
||||||
const stored = localStorage.getItem('theme');
|
|
||||||
if (stored === 'dark' || stored === 'light') {
|
|
||||||
document.documentElement.setAttribute('data-theme', stored);
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
</script>
|
|
||||||
<link rel="stylesheet" type="text/css" href="{{ main_siteurl | default(SITEURL) }}/theme/css/site.css" />
|
<link rel="stylesheet" type="text/css" href="{{ main_siteurl | default(SITEURL) }}/theme/css/site.css" />
|
||||||
|
|
||||||
{% if FEED_ALL_ATOM %}
|
{% if FEED_ALL_ATOM %}
|
||||||
@@ -62,7 +57,11 @@
|
|||||||
</ul>
|
</ul>
|
||||||
<span class="header-delimiter">·</span>
|
<span class="header-delimiter">·</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
<button id="font-toggle" aria-label="Toggle font">Aa</button>
|
||||||
|
<span class="header-delimiter">·</span>
|
||||||
<button id="theme-toggle" aria-label="Toggle color theme">◐</button>
|
<button id="theme-toggle" aria-label="Toggle color theme">◐</button>
|
||||||
|
<span class="header-delimiter">·</span>
|
||||||
|
<button id="accent-toggle" aria-label="Toggle accent color"></button>
|
||||||
</div>
|
</div>
|
||||||
<h1><a href="{{ SITEURL }}/">{{ SITENAME }} <strong>{{ SITESUBTITLE }}</strong></a></h1>
|
<h1><a href="{{ SITEURL }}/">{{ SITENAME }} <strong>{{ SITESUBTITLE }}</strong></a></h1>
|
||||||
</header><!-- /#banner -->
|
</header><!-- /#banner -->
|
||||||
@@ -94,9 +93,23 @@
|
|||||||
<ul id="categories" class="menuitems">
|
<ul id="categories" class="menuitems">
|
||||||
{% for cat, null in categories %}
|
{% for cat, null in categories %}
|
||||||
<li{% if cat == category %} class="active"{% endif %}><a href="{{ SITEURL }}/{{ cat.url }}">{{ cat }}</a></li>
|
<li{% if cat == category %} class="active"{% endif %}><a href="{{ SITEURL }}/{{ cat.url }}">{{ cat }}</a></li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% if DISPLAY_TAG_CLOUD_ON_MENU | default(true) and tags is defined and tags %}
|
||||||
|
{% set tag_counts = tags | map('last') | map('length') | list %}
|
||||||
|
{% set max_count = tag_counts | max %}
|
||||||
|
{% if max_count and max_count > 0 %}
|
||||||
|
<ul id="tag-cloud" class="menuitems">
|
||||||
|
{% for tag, articles_in_tag in tags | sort %}
|
||||||
|
{% set weight = ((articles_in_tag | length) / max_count * 4) | round(0, 'ceil') | int %}
|
||||||
|
<li class="tag-weight-{{ weight }}">
|
||||||
|
<a href="{{ SITEURL }}/{{ tag.url }}">{{ tag }}</a>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
</nav><!-- /#menu -->
|
</nav><!-- /#menu -->
|
||||||
<main id="content">
|
<main id="content">
|
||||||
{% block content %}
|
{% block content %}
|
||||||
@@ -112,71 +125,14 @@
|
|||||||
|
|
||||||
<div class="lightbox-overlay" id="lightbox-overlay">
|
<div class="lightbox-overlay" id="lightbox-overlay">
|
||||||
<div class="lightbox-content">
|
<div class="lightbox-content">
|
||||||
<img id="lightbox-img" src="" alt="">
|
<div id="lightbox-media"></div>
|
||||||
<p id="lightbox-caption"></p>
|
<p id="lightbox-caption"></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script src="{{ main_siteurl | default(SITEURL) }}/theme/js/lightbox.js" defer></script>
|
||||||
document.addEventListener('DOMContentLoaded', function () {
|
<script src="{{ main_siteurl | default(SITEURL) }}/theme/js/toggles.js" defer></script>
|
||||||
const overlay = document.getElementById('lightbox-overlay');
|
<script src="{{ main_siteurl | default(SITEURL) }}/theme/js/svg-inject.js" defer></script>
|
||||||
const overlayImg = document.getElementById('lightbox-img');
|
|
||||||
const overlayCaption = document.getElementById('lightbox-caption');
|
|
||||||
|
|
||||||
document.querySelectorAll('.entry-content img').forEach(function (img, index) {
|
|
||||||
const figureNumber = index + 1;
|
|
||||||
|
|
||||||
img.addEventListener('click', function () {
|
|
||||||
overlayImg.src = img.src;
|
|
||||||
overlayImg.alt = img.alt;
|
|
||||||
const captionEl = img.nextElementSibling;
|
|
||||||
const captionText = (captionEl && captionEl.tagName === 'EM') ? captionEl.textContent : '';
|
|
||||||
overlayCaption.innerHTML = captionText
|
|
||||||
? '<span class="fig-number">Figure ' + figureNumber + ':</span> ' + captionText
|
|
||||||
: '';
|
|
||||||
overlay.classList.add('active');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
overlay.addEventListener('click', function () {
|
|
||||||
overlay.classList.remove('active');
|
|
||||||
overlayImg.src = '';
|
|
||||||
overlayCaption.innerHTML = '';
|
|
||||||
});
|
|
||||||
|
|
||||||
document.addEventListener('keydown', function (e) {
|
|
||||||
if (e.key === 'Escape') {
|
|
||||||
overlay.classList.remove('active');
|
|
||||||
overlayImg.src = '';
|
|
||||||
overlayCaption.innerHTML = '';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
document.addEventListener('DOMContentLoaded', function () {
|
|
||||||
const toggleBtn = document.getElementById('theme-toggle');
|
|
||||||
const root = document.documentElement;
|
|
||||||
|
|
||||||
function getCurrentTheme() {
|
|
||||||
const attr = root.getAttribute('data-theme');
|
|
||||||
if (attr) return attr;
|
|
||||||
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateIcon() {
|
|
||||||
toggleBtn.textContent = getCurrentTheme() === 'dark' ? '☀' : '☾';
|
|
||||||
}
|
|
||||||
updateIcon();
|
|
||||||
toggleBtn.addEventListener('click', function () {
|
|
||||||
const next = getCurrentTheme() === 'dark' ? 'light' : 'dark';
|
|
||||||
root.setAttribute('data-theme', next);
|
|
||||||
localStorage.setItem('theme', next);
|
|
||||||
updateIcon();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
Reference in New Issue
Block a user