diff --git a/static/css/site.css b/static/css/site.css
index dabf72e..75e0c0e 100644
--- a/static/css/site.css
+++ b/static/css/site.css
@@ -1,4 +1,4 @@
- @import url("pygments.css");
+@import url("pygments.css");
@import url("pygments-dark.css") (prefers-color-theme: dark);
@font-face {
@@ -44,9 +44,16 @@
:root {
--main-bg-color: hsl(210, 20%, 98%);
--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-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) {
@@ -54,6 +61,8 @@
--main-bg-color: hsl(0, 5%, 10%);
--main-text-color: hsl(210, 20%, 98%);
--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-head-border-color: hsl(0, 0%, 30%);
}
@@ -63,6 +72,8 @@
--main-bg-color: hsl(0, 5%, 10%);
--main-text-color: hsl(210, 20%, 98%);
--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-head-border-color: hsl(0, 0%, 30%);
}
@@ -70,11 +81,29 @@
:root[data-theme="light"] {
--main-bg-color: hsl(210, 20%, 98%);
--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-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 {
box-sizing: border-box;
}
@@ -106,6 +135,7 @@ body {
color: var(--main-text-color);
background-color: var(--main-bg-color);
text-rendering: optimizeLegibility;
+ font-family: var(--main-font);
}
header {
@@ -151,6 +181,7 @@ a:not([class]) {
a, a:visited {
color: var(--main-link-color);
+ text-decoration: none;
}
a:focus {
@@ -158,6 +189,10 @@ a:focus {
outline: 2px solid hsl(220, 90%, 52%);
}
+a:hover,
+a:focus-visible {
+ text-decoration: underline;
+}
h1 {
font-size: 2.5rem;
@@ -218,7 +253,8 @@ ul.menuitems {
font-size: 0.9rem;
}
-#theme-toggle {
+#theme-toggle,
+#font-toggle {
background: none;
border: none;
padding: 0;
@@ -235,15 +271,42 @@ ul.menuitems {
}
#theme-toggle:hover,
-#theme-toggle:focus-visible {
+#theme-toggle:focus-visible,
+#font-toggle:hover,
+#font-toggle:focus-visible {
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-offset: 2px;
}
+#font-toggle {
+ font-family: sans-serif;
+ font-size: 0.95rem;
+}
+
#banner, #contentinfo {
width: 100%;
text-align: center;
@@ -283,6 +346,38 @@ ul.menuitems {
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 {
text-align: right;
}
@@ -333,15 +428,9 @@ html[lang="de"] {
overflow: hidden;
text-overflow: ellipsis;
line-height: 1.3;
- text-decoration: none;
padding-bottom: 1px;
}
-.menuitems a:hover,
-.menuitems a:focus-visible {
- text-decoration: underline;
-}
-
#content {
flex: 1 1 auto;
}
@@ -413,14 +502,6 @@ footer.post-info {
color: var(--main-link-color);
}
-.toc a {
- text-decoration: none;
-}
-
-.toc a:hover {
- text-decoration: underline;
-}
-
/*
* Headings
*/
@@ -514,10 +595,23 @@ footer.post-info {
* 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;
display: block;
max-width: 80%;
+ width: auto;
+ height: auto;
margin: 0 auto 0 auto;
padding: 1rem;
cursor: zoom-in;
@@ -565,15 +659,20 @@ footer.post-info {
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-height: 85vh;
object-fit: contain;
- background: #fff;
}
.lightbox-overlay #lightbox-caption {
- color: #111;
+ color: var(--main-text-color);
text-align: center;
margin-top: 0.75rem;
font-size: 0.95rem;
diff --git a/static/js/lightbox.js b/static/js/lightbox.js
new file mode 100644
index 0000000..a1ad40d
--- /dev/null
+++ b/static/js/lightbox.js
@@ -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
+ ? 'Figure ' + figureNumber + ': ' + 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 = '';
+ }
+ });
+});
diff --git a/static/js/svg-inject.js b/static/js/svg-inject.js
new file mode 100644
index 0000000..1842c1d
--- /dev/null
+++ b/static/js/svg-inject.js
@@ -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