feat: initial commit
This commit is contained in:
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
*.lock
|
||||
|
||||
public/
|
||||
7
Dockerfile
Normal file
7
Dockerfile
Normal file
@@ -0,0 +1,7 @@
|
||||
FROM nginx:alpine
|
||||
|
||||
COPY ./public /usr/share/nginx/html
|
||||
|
||||
EXPOSE 80
|
||||
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
5
archetypes/default.md
Normal file
5
archetypes/default.md
Normal file
@@ -0,0 +1,5 @@
|
||||
+++
|
||||
date = '{{ .Date }}'
|
||||
draft = true
|
||||
title = '{{ replace .File.ContentBaseName "-" " " | title }}'
|
||||
+++
|
||||
7
content/about/_index.md
Normal file
7
content/about/_index.md
Normal file
@@ -0,0 +1,7 @@
|
||||
---
|
||||
title: "About"
|
||||
---
|
||||
|
||||
This is a minimal About page. Customize it in `content/about/_index.md`.
|
||||
|
||||
|
||||
34
content/posts/example-margin-garden.md
Normal file
34
content/posts/example-margin-garden.md
Normal file
@@ -0,0 +1,34 @@
|
||||
---
|
||||
title: "Margin Garden Example"
|
||||
date: 2025-08-17T10:00:00Z
|
||||
tags: [design, hugo, demo]
|
||||
summary: "A demo post showing margin notes, code blocks, and theme toggling."
|
||||
---
|
||||
|
||||
This is a short example of the Margin Garden style. We'll use a footnote for a margin note.[^mn]
|
||||
|
||||
## Code sample
|
||||
|
||||
```ts
|
||||
function greet(name: string): string {
|
||||
return `Hello, ${name}!`;
|
||||
}
|
||||
|
||||
console.log(greet("world"));
|
||||
```
|
||||
|
||||
Blockquotes should look refined:
|
||||
|
||||
> Good design is as little design as possible.
|
||||
|
||||
A list with tags-like styling:
|
||||
|
||||
- `hugo`
|
||||
- `theme`
|
||||
- `catppuccin`
|
||||
|
||||
And an inline code `const x = 1` example.
|
||||
|
||||
[^mn]: This footnote appears as a margin note on wide screens.
|
||||
|
||||
|
||||
21
hugo.toml
Normal file
21
hugo.toml
Normal file
@@ -0,0 +1,21 @@
|
||||
baseURL = 'https://blog.jokresner.de/'
|
||||
languageCode = 'en-us'
|
||||
title = 'My personal blog'
|
||||
|
||||
[markup]
|
||||
[markup.highlight]
|
||||
noClasses = false
|
||||
|
||||
[menu]
|
||||
[[menu.main]]
|
||||
name = 'Home'
|
||||
url = '/'
|
||||
weight = 1
|
||||
[[menu.main]]
|
||||
name = 'Posts'
|
||||
url = '/posts/'
|
||||
weight = 2
|
||||
[[menu.main]]
|
||||
name = 'About'
|
||||
url = '/about/'
|
||||
weight = 3
|
||||
18
layouts/_default/baseof.html
Normal file
18
layouts/_default/baseof.html
Normal file
@@ -0,0 +1,18 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>{{ if .IsHome }}{{ .Site.Title }}{{ else }}{{ .Title }} · {{ .Site.Title }}{{ end }}</title>
|
||||
<link rel="stylesheet" href="/css/theme.css">
|
||||
<link id="chroma-latte" rel="stylesheet" href="/css/latte-chroma-style.css">
|
||||
<link id="chroma-mocha" rel="stylesheet" href="/css/mocha-chroma-style.css" disabled>
|
||||
<script defer src="/theme.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
{{ partial "header.html" . }}
|
||||
<main>
|
||||
{{ block "main" . }}{{ end }}
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
19
layouts/_default/list.html
Normal file
19
layouts/_default/list.html
Normal file
@@ -0,0 +1,19 @@
|
||||
{{ define "main" }}
|
||||
<section>
|
||||
<h1>{{ .Title }}</h1>
|
||||
{{ range .Pages.ByDate.Reverse }}
|
||||
<article class="post-card">
|
||||
<h2><a href="{{ .RelPermalink }}">{{ .Title }}</a></h2>
|
||||
<div class="post-meta">
|
||||
<time datetime="{{ .Date.Format "2006-01-02" }}">{{ .Date.Format "Jan 2, 2006" }}</time>
|
||||
{{ with .Params.tags }}
|
||||
· {{ range . }}<span class="tag">#{{ . }}</span>{{ end }}
|
||||
{{ end }}
|
||||
</div>
|
||||
{{ with .Summary }}<p>{{ . }}</p>{{ end }}
|
||||
</article>
|
||||
{{ end }}
|
||||
</section>
|
||||
{{ end }}
|
||||
|
||||
|
||||
16
layouts/_default/single.html
Normal file
16
layouts/_default/single.html
Normal file
@@ -0,0 +1,16 @@
|
||||
{{ define "main" }}
|
||||
<article class="with-sidenotes">
|
||||
<header>
|
||||
<h1>{{ .Title }}</h1>
|
||||
<div class="post-meta">
|
||||
<time datetime="{{ .Date.Format "2006-01-02" }}">{{ .Date.Format "Jan 2, 2006" }}</time>
|
||||
{{ with .Params.tags }}
|
||||
· {{ range . }}<span class="tag">#{{ . }}</span>{{ end }}
|
||||
{{ end }}
|
||||
</div>
|
||||
</header>
|
||||
<div class="content">{{ .Content }}</div>
|
||||
</article>
|
||||
{{ end }}
|
||||
|
||||
|
||||
18
layouts/_partials/header.html
Normal file
18
layouts/_partials/header.html
Normal file
@@ -0,0 +1,18 @@
|
||||
<header class="site-header">
|
||||
<div class="container header-inner">
|
||||
<a class="site-logo" href="/">{{ .Site.Title }}</a>
|
||||
<nav class="site-nav" aria-label="Main">
|
||||
{{ $p := . }}
|
||||
{{ with .Site.Menus.main }}
|
||||
{{ range . }}
|
||||
{{ $active := or ($p.IsMenuCurrent "main" .) ($p.HasMenuCurrent "main" .) }}
|
||||
<a class="site-nav__link {{ if $active }}is-active{{ end }}" href="{{ .URL }}">{{ .Name }}</a>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
</nav>
|
||||
<button id="theme-toggle" class="theme-toggle" aria-label="Toggle theme">🌙</button>
|
||||
</div>
|
||||
<div class="progress" id="progress"></div>
|
||||
</header>
|
||||
|
||||
|
||||
256
static/css/latte-chroma-style.css
Normal file
256
static/css/latte-chroma-style.css
Normal file
@@ -0,0 +1,256 @@
|
||||
.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;
|
||||
}
|
||||
|
||||
256
static/css/mocha-chroma-style.css
Normal file
256
static/css/mocha-chroma-style.css
Normal file
@@ -0,0 +1,256 @@
|
||||
.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;
|
||||
}
|
||||
|
||||
173
static/css/theme.css
Normal file
173
static/css/theme.css
Normal file
@@ -0,0 +1,173 @@
|
||||
: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);
|
||||
}
|
||||
51
static/theme.js
Normal file
51
static/theme.js
Normal file
@@ -0,0 +1,51 @@
|
||||
(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");
|
||||
}
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
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();
|
||||
})();
|
||||
Reference in New Issue
Block a user