feat: updates

This commit is contained in:
2025-08-17 22:09:53 +02:00
parent 998e955ec8
commit 8c0dc905d9
18 changed files with 869 additions and 776 deletions

2
static/css/app.css Normal file

File diff suppressed because one or more lines are too long

View File

@@ -1,256 +0,0 @@
.chroma {
color: #4c4f69;
background-color: #eff1f5;
}
.chroma .cl {
color: #4c4f69;
}
.chroma .err {
color: #d20f39;
}
.chroma .x {
color: #4c4f69;
}
.chroma .hl {
background-color: #bcc0cc;
}
.chroma .lnt {
color: #8c8fa1;
}
.chroma .ln {
color: #8c8fa1;
}
.chroma .k {
color: #8839ef;
}
.chroma .kr {
color: #8839ef;
}
.chroma .kp {
color: #8839ef;
}
.chroma .kc {
color: #fe640b;
}
.chroma .kd {
color: #d20f39;
}
.chroma .kn {
color: #179299;
}
.chroma .kt {
color: #d20f39;
}
.chroma .n {
color: #4c4f69;
}
.chroma .nc {
color: #df8e1d;
}
.chroma .no {
color: #df8e1d;
}
.chroma .nd {
color: #1e66f5;
font-weight: bold;
}
.chroma .ni {
color: #179299;
}
.chroma .ne {
color: #fe640b;
}
.chroma .nf {
color: #1e66f5;
}
.chroma .fm {
color: #1e66f5;
}
.chroma .nl {
color: #04a5e5;
}
.chroma .nn {
color: #fe640b;
}
.chroma .py {
color: #fe640b;
}
.chroma .nt {
color: #8839ef;
}
.chroma .nv {
color: #dc8a78;
}
.chroma .vc {
color: #dc8a78;
}
.chroma .vg {
color: #dc8a78;
}
.chroma .vi {
color: #dc8a78;
}
.chroma .vm {
color: #dc8a78;
}
.chroma .na {
color: #1e66f5;
}
.chroma .nb {
color: #04a5e5;
}
.chroma .bp {
color: #04a5e5;
}
.chroma .nx {
color: #4c4f69;
}
.chroma .l {
color: #4c4f69;
}
.chroma .ld {
color: #4c4f69;
}
.chroma .s {
color: #40a02b;
}
.chroma .sc {
color: #40a02b;
}
.chroma .s1 {
color: #40a02b;
}
.chroma .s2 {
color: #40a02b;
}
.chroma .sb {
color: #40a02b;
}
.chroma .sx {
color: #40a02b;
}
.chroma .ss {
color: #40a02b;
}
.chroma .si {
color: #40a02b;
}
.chroma .sa {
color: #d20f39;
}
.chroma .dl {
color: #1e66f5;
}
.chroma .se {
color: #1e66f5;
}
.chroma .sr {
color: #179299;
}
.chroma .sd {
color: #9ca0b0;
}
.chroma .sh {
color: #9ca0b0;
}
.chroma .m {
color: #fe640b;
}
.chroma .mb {
color: #fe640b;
}
.chroma .mh {
color: #fe640b;
}
.chroma .mi {
color: #fe640b;
}
.chroma .mf {
color: #fe640b;
}
.chroma .il {
color: #fe640b;
}
.chroma .mo {
color: #fe640b;
}
.chroma .o {
color: #04a5e5;
font-weight: bold;
}
.chroma .ow {
color: #04a5e5;
font-weight: bold;
}
.chroma .c {
color: #9ca0b0;
font-style: italic;
}
.chroma .c1 {
color: #9ca0b0;
font-style: italic;
}
.chroma .cm {
color: #9ca0b0;
font-style: italic;
}
.chroma .cs {
color: #9ca0b0;
font-style: italic;
}
.chroma .ch {
color: #acb0be;
font-style: italic;
}
.chroma .cp {
color: #9ca0b0;
font-style: italic;
}
.chroma .cpf {
color: #9ca0b0;
font-weight: bold;
}
.chroma .g {
color: #4c4f69;
}
.chroma .gi {
color: #40a02b;
background-color: #ccd0da;
}
.chroma .gd {
color: #d20f39;
background-color: #ccd0da;
}
.chroma .ge {
color: #4c4f69;
font-style: italic;
}
.chroma .gs {
color: #4c4f69;
font-weight: bold;
}
.chroma .gl {
color: #4c4f69;
text-decoration: underline;
}
.chroma .gh {
color: #fe640b;
font-weight: bold;
}
.chroma .gu {
color: #fe640b;
font-weight: bold;
}
.chroma .go {
color: #4c4f69;
}
.chroma .gp {
color: #4c4f69;
}
.chroma .gr {
color: #d20f39;
}
.chroma .gt {
color: #d20f39;
}

View File

@@ -1,256 +0,0 @@
.chroma {
color: #cdd6f4;
background-color: #1e1e2e;
}
.chroma .cl {
color: #cdd6f4;
}
.chroma .err {
color: #f38ba8;
}
.chroma .x {
color: #cdd6f4;
}
.chroma .hl {
background-color: #45475a;
}
.chroma .lnt {
color: #7f849c;
}
.chroma .ln {
color: #7f849c;
}
.chroma .k {
color: #cba6f7;
}
.chroma .kr {
color: #cba6f7;
}
.chroma .kp {
color: #cba6f7;
}
.chroma .kc {
color: #fab387;
}
.chroma .kd {
color: #f38ba8;
}
.chroma .kn {
color: #94e2d5;
}
.chroma .kt {
color: #f38ba8;
}
.chroma .n {
color: #cdd6f4;
}
.chroma .nc {
color: #f9e2af;
}
.chroma .no {
color: #f9e2af;
}
.chroma .nd {
color: #89b4fa;
font-weight: bold;
}
.chroma .ni {
color: #94e2d5;
}
.chroma .ne {
color: #fab387;
}
.chroma .nf {
color: #89b4fa;
}
.chroma .fm {
color: #89b4fa;
}
.chroma .nl {
color: #89dceb;
}
.chroma .nn {
color: #fab387;
}
.chroma .py {
color: #fab387;
}
.chroma .nt {
color: #cba6f7;
}
.chroma .nv {
color: #f5e0dc;
}
.chroma .vc {
color: #f5e0dc;
}
.chroma .vg {
color: #f5e0dc;
}
.chroma .vi {
color: #f5e0dc;
}
.chroma .vm {
color: #f5e0dc;
}
.chroma .na {
color: #89b4fa;
}
.chroma .nb {
color: #89dceb;
}
.chroma .bp {
color: #89dceb;
}
.chroma .nx {
color: #cdd6f4;
}
.chroma .l {
color: #cdd6f4;
}
.chroma .ld {
color: #cdd6f4;
}
.chroma .s {
color: #a6e3a1;
}
.chroma .sc {
color: #a6e3a1;
}
.chroma .s1 {
color: #a6e3a1;
}
.chroma .s2 {
color: #a6e3a1;
}
.chroma .sb {
color: #a6e3a1;
}
.chroma .sx {
color: #a6e3a1;
}
.chroma .ss {
color: #a6e3a1;
}
.chroma .si {
color: #a6e3a1;
}
.chroma .sa {
color: #f38ba8;
}
.chroma .dl {
color: #89b4fa;
}
.chroma .se {
color: #89b4fa;
}
.chroma .sr {
color: #94e2d5;
}
.chroma .sd {
color: #6c7086;
}
.chroma .sh {
color: #6c7086;
}
.chroma .m {
color: #fab387;
}
.chroma .mb {
color: #fab387;
}
.chroma .mh {
color: #fab387;
}
.chroma .mi {
color: #fab387;
}
.chroma .mf {
color: #fab387;
}
.chroma .il {
color: #fab387;
}
.chroma .mo {
color: #fab387;
}
.chroma .o {
color: #89dceb;
font-weight: bold;
}
.chroma .ow {
color: #89dceb;
font-weight: bold;
}
.chroma .c {
color: #6c7086;
font-style: italic;
}
.chroma .c1 {
color: #6c7086;
font-style: italic;
}
.chroma .cm {
color: #6c7086;
font-style: italic;
}
.chroma .cs {
color: #6c7086;
font-style: italic;
}
.chroma .ch {
color: #585b70;
font-style: italic;
}
.chroma .cp {
color: #6c7086;
font-style: italic;
}
.chroma .cpf {
color: #6c7086;
font-weight: bold;
}
.chroma .g {
color: #cdd6f4;
}
.chroma .gi {
color: #a6e3a1;
background-color: #313244;
}
.chroma .gd {
color: #f38ba8;
background-color: #313244;
}
.chroma .ge {
color: #cdd6f4;
font-style: italic;
}
.chroma .gs {
color: #cdd6f4;
font-weight: bold;
}
.chroma .gl {
color: #cdd6f4;
text-decoration: underline;
}
.chroma .gh {
color: #fab387;
font-weight: bold;
}
.chroma .gu {
color: #fab387;
font-weight: bold;
}
.chroma .go {
color: #cdd6f4;
}
.chroma .gp {
color: #cdd6f4;
}
.chroma .gr {
color: #f38ba8;
}
.chroma .gt {
color: #f38ba8;
}

View File

@@ -1,173 +0,0 @@
:root[data-theme="latte"] {
--bg: #eff1f5;
--fg: #4c4f69;
--muted: #8c8fa1;
--card: #ffffffcc;
--accent: #7287fd;
--accent-2: #179299;
--code-bg: color-mix(in srgb, var(--bg) 88%, transparent);
--border: #ccd0da;
}
:root[data-theme="mocha"] {
--bg: #1e1e2e;
--fg: #cdd6f4;
--muted: #a6adc8;
--card: #1e1e2ecc;
--accent: #b4befe;
--accent-2: #94e2d5;
--code-bg: color-mix(in srgb, var(--bg) 70%, transparent);
--border: #313244;
}
html,
body {
background: var(--bg);
color: var(--fg);
}
a {
color: var(--accent);
text-decoration: underline;
text-decoration-color: color-mix(in srgb, var(--accent) 40%, transparent);
}
pre,
code {
background: var(--code-bg);
}
.post-card {
background: var(--card);
border: 1px solid var(--border);
border-radius: 12px;
box-shadow: 0 8px 20px rgba(0, 0, 0, .05);
}
.progress {
position: fixed;
top: 0;
left: 0;
height: 2px;
width: 0;
background: var(--accent-2);
z-index: 50;
}
@media (min-width: 1100px) {
.with-sidenotes {
max-width: 70ch;
margin-right: 22ch;
position: relative;
}
.sidenote {
position: absolute;
right: -20ch;
width: 18ch;
color: var(--muted);
}
}
html,
body {
margin: 0;
}
html {
font-family: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
line-height: 1.7;
}
pre, code, kbd, samp {
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
}
main {
max-width: 70ch;
padding: 2rem 1rem 4rem;
margin: 0 auto;
}
.post-card {
padding: 1rem 1.25rem;
transition: transform .15s ease, box-shadow .15s ease;
}
.post-card:hover {
transform: translateY(-2px);
box-shadow: 0 10px 24px rgba(0, 0, 0, .08);
}
.post-meta {
color: var(--muted);
font-size: .9rem;
}
.tag {
display: inline-block;
border: 1px solid var(--border);
border-radius: 999px;
padding: .1rem .5rem;
margin-right: .25rem;
color: var(--muted);
}
/* Minimal header and navigation */
.site-header {
position: sticky;
top: 0;
backdrop-filter: saturate(180%) blur(8px);
background: color-mix(in srgb, var(--bg) 85%, transparent);
border-bottom: 1px solid var(--border);
}
.container {
max-width: 70ch;
margin: 0 auto;
padding: .75rem 1rem;
}
.header-inner {
display: flex;
align-items: center;
gap: .75rem;
}
.site-logo {
text-decoration: none;
color: inherit;
font-weight: 600;
margin-right: auto;
}
.site-nav {
display: flex;
gap: .5rem;
flex-wrap: wrap;
}
.site-nav__link {
text-decoration: none;
color: var(--fg);
border: 1px solid transparent;
border-radius: 8px;
padding: .25rem .5rem;
}
.site-nav__link:hover {
background: var(--card);
border-color: var(--border);
}
.site-nav__link.is-active {
background: color-mix(in srgb, var(--accent) 12%, var(--bg));
border-color: color-mix(in srgb, var(--accent) 30%, var(--border));
}
.theme-toggle {
background: transparent;
border: 1px solid var(--border);
border-radius: 999px;
padding: .25rem .5rem;
color: var(--fg);
}

View File

@@ -1,51 +1,43 @@
(function () {
const root = document.documentElement;
const key = "theme";
const stored = localStorage.getItem(key);
const prefersDark = window.matchMedia("(prefers-color-scheme: dark)").matches;
const initial = stored || (prefersDark ? "mocha" : "latte");
root.setAttribute("data-theme", initial);
toggleChroma(initial);
const btn = document.getElementById("theme-toggle");
function updateToggleIcon(theme) {
if (!btn) return;
const isDark = theme === "mocha";
btn.textContent = isDark ? "☀️" : "🌙";
btn.setAttribute("aria-label", isDark ? "Switch to light theme" : "Switch to dark theme");
btn.setAttribute("title", isDark ? "Light theme" : "Dark theme");
// Home: show as many posts as fit the viewport height
(function () {
if (!document.body.classList.contains('is-home')) return;
const list = document.getElementById('home-post-items');
if (!list) return;
const items = Array.from(list.querySelectorAll('.home-post-item'));
const header = document.querySelector('.site-header');
const footer = document.querySelector('.site-footer');
function availableHeight() {
const vh = window.innerHeight;
const headerH = header ? header.getBoundingClientRect().height : 0;
const footerH = footer ? footer.getBoundingClientRect().height : 0;
const mainPadding = 48; // approx padding in main
return Math.max(0, vh - headerH - footerH - mainPadding);
}
function setTheme(next) {
root.setAttribute("data-theme", next);
localStorage.setItem(key, next);
toggleChroma(next);
updateToggleIcon(next);
}
function toggleChroma(theme) {
const latte = document.getElementById("chroma-latte");
const mocha = document.getElementById("chroma-mocha");
if (latte && mocha) {
if (theme === "mocha") {
mocha.removeAttribute("disabled");
latte.setAttribute("disabled", "disabled");
} else {
latte.removeAttribute("disabled");
mocha.setAttribute("disabled", "disabled");
function relayout() {
items.forEach(el => el.classList.add('hidden'));
let shown = 0;
let used = 0;
const gap = (() => {
const ul = list;
const styles = window.getComputedStyle(ul);
const rowGap = parseFloat(styles.rowGap || styles.gap || '0');
return isNaN(rowGap) ? 0 : rowGap;
})();
for (const el of items) {
el.classList.remove('hidden');
const h = el.getBoundingClientRect().height;
if (used + h + (shown > 0 ? gap : 0) > availableHeight()) {
el.classList.add('hidden');
break;
}
used += h + (shown > 0 ? gap : 0);
shown++;
}
}
updateToggleIcon(initial);
btn && btn.addEventListener("click", () => {
setTheme(root.getAttribute("data-theme") === "latte" ? "mocha" : "latte");
});
// Reading progress
const bar = document.getElementById("progress");
function onScroll() {
const t = document.documentElement;
const scrolled = (t.scrollTop / (t.scrollHeight - t.clientHeight)) * 100;
bar && (bar.style.width = scrolled + "%");
}
document.addEventListener("scroll", onScroll, { passive: true });
onScroll();
const ro = new ResizeObserver(relayout);
ro.observe(document.documentElement);
header && ro.observe(header);
footer && ro.observe(footer);
window.addEventListener('load', relayout);
window.addEventListener('orientationchange', relayout);
})();