Add the initial version of the site theme

This commit is contained in:
Jesse Braham 2025-01-22 17:25:01 +01:00
parent 0d6bd2f7a3
commit 8df35f9b02
21 changed files with 3181 additions and 0 deletions

11
.gitignore vendored Normal file
View File

@ -0,0 +1,11 @@
# npm
node_modules/
# Python
__pycache__/
venv/
# Generated files
cache/
output/
theme/static/css/**/*.css

85
theme/css/lightbulb.css Normal file
View File

@ -0,0 +1,85 @@
pre { line-height: 125%; }
td.linenos .normal { color: #3c4354; background-color: transparent; padding-left: 5px; padding-right: 5px; }
span.linenos { color: #3c4354; background-color: transparent; padding-left: 5px; padding-right: 5px; }
td.linenos .special { color: #3c4354; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
span.linenos.special { color: #3c4354; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
.highlight .hll { background-color: #6e7681 }
.highlight { background: #1d2331; color: #d4d2c8 }
.highlight .c { color: #7e8aa1 } /* Comment */
.highlight .err { color: #f88f7f } /* Error */
.highlight .esc { color: #d4d2c8 } /* Escape */
.highlight .g { color: #d4d2c8 } /* Generic */
.highlight .k { color: #FFAD66 } /* Keyword */
.highlight .l { color: #D5FF80 } /* Literal */
.highlight .n { color: #d4d2c8 } /* Name */
.highlight .o { color: #FFAD66 } /* Operator */
.highlight .x { color: #d4d2c8 } /* Other */
.highlight .p { color: #d4d2c8 } /* Punctuation */
.highlight .ch { color: #f88f7f; font-style: italic } /* Comment.Hashbang */
.highlight .cm { color: #7e8aa1 } /* Comment.Multiline */
.highlight .cp { color: #FFAD66; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #7e8aa1 } /* Comment.PreprocFile */
.highlight .c1 { color: #7e8aa1 } /* Comment.Single */
.highlight .cs { color: #7e8aa1; font-style: italic } /* Comment.Special */
.highlight .gd { color: #f88f7f; background-color: #3d1e20 } /* Generic.Deleted */
.highlight .ge { color: #d4d2c8; font-style: italic } /* Generic.Emph */
.highlight .ges { color: #d4d2c8 } /* Generic.EmphStrong */
.highlight .gr { color: #f88f7f } /* Generic.Error */
.highlight .gh { color: #d4d2c8 } /* Generic.Heading */
.highlight .gi { color: #6ad4af; background-color: #19362c } /* Generic.Inserted */
.highlight .go { color: #7e8aa1 } /* Generic.Output */
.highlight .gp { color: #d4d2c8 } /* Generic.Prompt */
.highlight .gs { color: #d4d2c8; font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #d4d2c8 } /* Generic.Subheading */
.highlight .gt { color: #f88f7f } /* Generic.Traceback */
.highlight .kc { color: #FFAD66 } /* Keyword.Constant */
.highlight .kd { color: #FFAD66 } /* Keyword.Declaration */
.highlight .kn { color: #FFAD66 } /* Keyword.Namespace */
.highlight .kp { color: #FFAD66 } /* Keyword.Pseudo */
.highlight .kr { color: #FFAD66 } /* Keyword.Reserved */
.highlight .kt { color: #73D0FF } /* Keyword.Type */
.highlight .ld { color: #D5FF80 } /* Literal.Date */
.highlight .m { color: #DFBFFF } /* Literal.Number */
.highlight .s { color: #D5FF80 } /* Literal.String */
.highlight .na { color: #FFD173 } /* Name.Attribute */
.highlight .nb { color: #FFD173 } /* Name.Builtin */
.highlight .nc { color: #73D0FF } /* Name.Class */
.highlight .no { color: #FFD173 } /* Name.Constant */
.highlight .nd { color: #7e8aa1; font-weight: bold; font-style: italic } /* Name.Decorator */
.highlight .ni { color: #95E6CB } /* Name.Entity */
.highlight .ne { color: #73D0FF } /* Name.Exception */
.highlight .nf { color: #FFD173 } /* Name.Function */
.highlight .nl { color: #d4d2c8 } /* Name.Label */
.highlight .nn { color: #d4d2c8 } /* Name.Namespace */
.highlight .nx { color: #d4d2c8 } /* Name.Other */
.highlight .py { color: #FFD173 } /* Name.Property */
.highlight .nt { color: #5CCFE6 } /* Name.Tag */
.highlight .nv { color: #d4d2c8 } /* Name.Variable */
.highlight .ow { color: #FFAD66 } /* Operator.Word */
.highlight .pm { color: #d4d2c8 } /* Punctuation.Marker */
.highlight .w { color: #d4d2c8 } /* Text.Whitespace */
.highlight .mb { color: #DFBFFF } /* Literal.Number.Bin */
.highlight .mf { color: #DFBFFF } /* Literal.Number.Float */
.highlight .mh { color: #DFBFFF } /* Literal.Number.Hex */
.highlight .mi { color: #DFBFFF } /* Literal.Number.Integer */
.highlight .mo { color: #DFBFFF } /* Literal.Number.Oct */
.highlight .sa { color: #F29E74 } /* Literal.String.Affix */
.highlight .sb { color: #D5FF80 } /* Literal.String.Backtick */
.highlight .sc { color: #D5FF80 } /* Literal.String.Char */
.highlight .dl { color: #D5FF80 } /* Literal.String.Delimiter */
.highlight .sd { color: #7e8aa1 } /* Literal.String.Doc */
.highlight .s2 { color: #D5FF80 } /* Literal.String.Double */
.highlight .se { color: #95E6CB } /* Literal.String.Escape */
.highlight .sh { color: #D5FF80 } /* Literal.String.Heredoc */
.highlight .si { color: #95E6CB } /* Literal.String.Interpol */
.highlight .sx { color: #95E6CB } /* Literal.String.Other */
.highlight .sr { color: #95E6CB } /* Literal.String.Regex */
.highlight .s1 { color: #D5FF80 } /* Literal.String.Single */
.highlight .ss { color: #DFBFFF } /* Literal.String.Symbol */
.highlight .bp { color: #5CCFE6 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #FFD173 } /* Name.Function.Magic */
.highlight .vc { color: #d4d2c8 } /* Name.Variable.Class */
.highlight .vg { color: #d4d2c8 } /* Name.Variable.Global */
.highlight .vi { color: #d4d2c8 } /* Name.Variable.Instance */
.highlight .vm { color: #d4d2c8 } /* Name.Variable.Magic */
.highlight .il { color: #DFBFFF } /* Literal.Number.Integer.Long */

342
theme/css/main.css Normal file
View File

@ -0,0 +1,342 @@
@import "tailwindcss";
@theme {
--font-mono: "Space Mono", "monospace";
--font-sans: "Metropolis", "sans-serif";
}
@utility border-b-3 {
border-bottom-width: 3px;
}
@utility container {
@apply mx-auto px-4;
}
/* ************************************************************************* */
/* Fonts */
@layer base {
@font-face {
font-family: "Metropolis";
src: url("../fonts/metropolis/Metropolis-ExtraLight.otf");
font-style: normal;
font-weight: 200;
}
@font-face {
font-family: "Metropolis";
src: url("../fonts/metropolis/Metropolis-Regular.otf");
font-style: normal;
font-weight: 400;
}
@font-face {
font-family: "Metropolis";
src: url("../fonts/metropolis/Metropolis-Bold.otf");
font-style: normal;
font-weight: 700;
}
@font-face {
font-family: "Space Mono";
src: url("../fonts/space-mono/SpaceMono-Regular.ttf");
}
}
/* ************************************************************************* */
/* Base Styles */
html,
body {
@apply h-full w-full;
}
body {
@apply bg-zinc-900 flex flex-col font-sans text-zinc-50;
}
main {
@apply flex-1 pb-20 pt-16;
}
h1 {
@apply text-4xl;
&::after {
content: ".";
@apply font-bold ml-px text-amber-600;
}
}
h2,
h3,
h4 {
@apply mb-4 mt-8;
&::before {
@apply mr-2 text-amber-600;
}
}
h2 {
@apply text-2xl;
&::before {
content: "#";
}
}
h3 {
@apply text-xl;
&::before {
content: "##";
}
}
h4 {
@apply text-lg;
&::before {
content: "###";
}
}
a:hover {
@apply bg-amber-600;
}
/* ************************************************************************* */
/* Header */
header {
@apply font-mono py-4;
.container {
@apply flex items-center justify-between;
.title {
@apply text-2xl;
}
a {
@apply border-amber-600 border-b-3 px-px;
&:not(:first-of-type) {
@apply ml-1;
}
}
}
}
/* ************************************************************************* */
/* Footer */
footer {
@apply font-mono py-8 text-sm;
.container {
@apply flex items-center justify-between;
.cc {
@apply flex-1;
a {
@apply border-amber-600 border-b-2 px-px whitespace-nowrap;
}
}
.social {
@apply flex flex-1 items-center justify-end;
a:not(:first-of-type) {
@apply ml-3;
}
img {
@apply bg-zinc-50 h-6 ring-3 ring-inset ring-zinc-900;
&:hover {
@apply bg-zinc-900;
}
}
}
}
}
/* ************************************************************************* */
/* Post List */
.post-list {
@apply mt-8 text-lg;
li {
@apply flex;
.date {
@apply font-mono mr-3 text-zinc-400;
}
.title {
@apply pt-px;
&::before {
content: "#";
@apply mr-1 text-amber-600;
}
a {
@apply px-px py-1;
}
}
}
}
/* ************************************************************************* */
/* Articles */
.article-meta {
@apply font-mono text-lg text-zinc-400;
}
article {
@apply font-light mt-8 text-lg;
blockquote {
@apply p-3;
p {
&::before {
content: "❝";
@apply mr-2 text-amber-600;
}
&::after {
content: "❞";
@apply ml-2 text-amber-600;
}
}
}
table {
@apply border border-zinc-50 my-6 text-base w-full;
th {
@apply border-b border-zinc-50 px-2 py-1;
}
td {
@apply px-2 py-px;
}
}
ol {
@apply list-decimal list-inside mb-4;
}
ul {
@apply list-disc list-inside mb-4;
}
strong {
@apply font-bold;
}
a:not(.toclink) {
@apply border-b-2 border-amber-600 px-px;
}
p {
@apply leading-6 mb-4;
& > code {
@apply font-mono mx-1 text-sm text-zinc-400;
}
}
.highlight {
@apply font-mono my-6 px-3 py-2 overflow-x-scroll text-sm;
}
}
.toc {
@apply mb-8;
.toctitle {
@apply block mb-4 mt-8 text-2xl;
&::before {
content: "#";
@apply mr-2 text-amber-600;
}
}
ul {
@apply mb-0;
li {
@apply mb-1;
a {
@apply px-px py-1;
}
}
}
a + ul {
@apply ml-4 mt-2;
}
}
.footnote {
@apply mt-8 text-base;
ol {
@apply list-decimal list-inside pt-2;
li {
@apply mt-2;
p {
@apply inline-block mb-0;
}
}
}
}
.neighbours {
@apply flex items-center justify-between mt-16 w-full;
div {
@apply flex-1;
a {
@apply flex items-center;
span {
@apply text-amber-600 text-4xl;
}
&:hover span {
@apply text-zinc-50;
}
}
&:first-of-type a {
@apply pr-4;
span {
@apply ml-2 mr-4;
}
}
&:last-of-type a {
@apply justify-end pl-4 text-right;
span {
@apply ml-4 mr-2;
}
}
}
}

2489
theme/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

16
theme/package.json Normal file
View File

@ -0,0 +1,16 @@
{
"private": true,
"type": "module",
"scripts": {
"build:dev": "npx postcss css/ --env=development --dir=static/css/",
"build:prod": "npx postcss css/ --env=production --dir=static/css/",
"watch": "npx postcss css/ --env=development --dir=static/css/ --watch",
"clean": "rm static/css/*.css"
},
"devDependencies": {
"@tailwindcss/postcss": "^4.0.0",
"cssnano": "^7.0.6",
"postcss-cli": "^11.0.0",
"tailwindcss": "^4.0.0"
}
}

10
theme/postcss.config.mjs Normal file
View File

@ -0,0 +1,10 @@
const PRODUCTION = process.env.NODE_ENV === "production";
export default {
plugins: {
"@tailwindcss/postcss": {},
// Only enable the 'cssnano' plugin in production:
...(PRODUCTION ? { cssnano: {} } : null),
},
};

View File

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--!Font
Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License -
https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.-->
<path fill="#d97706"
d="M64 32C28.7 32 0 60.7 0 96L0 416c0 35.3 28.7 64 64 64l320 0c35.3 0 64-28.7 64-64l0-320c0-35.3-28.7-64-64-64L64 32zM218 271.7L64.2 172.4C66 156.4 79.5 144 96 144l256 0c16.5 0 30 12.4 31.8 28.4L230 271.7c-1.8 1.2-3.9 1.8-6 1.8s-4.2-.6-6-1.8zm29.4 26.9L384 210.4 384 336c0 17.7-14.3 32-32 32L96 368c-17.7 0-32-14.3-32-32l0-125.6 136.6 88.2c7 4.5 15.1 6.9 23.4 6.9s16.4-2.4 23.4-6.9z" />
</svg>

After

Width:  |  Height:  |  Size: 649 B

View File

@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--!Font
Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License -
https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.-->
<path fill="#d97706"
d="M64 32C28.7 32 0 60.7 0 96L0 416c0 35.3 28.7 64 64 64l320 0c35.3 0 64-28.7 64-64l0-320c0-35.3-28.7-64-64-64L64 32zM96 136c0-13.3 10.7-24 24-24c137 0 248 111 248 248c0 13.3-10.7 24-24 24s-24-10.7-24-24c0-110.5-89.5-200-200-200c-13.3 0-24-10.7-24-24zm0 96c0-13.3 10.7-24 24-24c83.9 0 152 68.1 152 152c0 13.3-10.7 24-24 24s-24-10.7-24-24c0-57.4-46.6-104-104-104c-13.3 0-24-10.7-24-24zm0 120a32 32 0 1 1 64 0 32 32 0 1 1 -64 0z" />
</svg>

After

Width:  |  Height:  |  Size: 693 B

View File

@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--!Font
Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License -
https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.-->
<path fill="#d97706"
d="M120.8 335.5c-5.9-.4-12.6-.8-20.2-1.3c-3.3 4.1-6.6 8.4-6.6 13.5c0 18.5 65.5 18.5 65.5-1.5c0-8.3-7.4-8.7-38.8-10.7zm7.8-117.9c-32.3 0-33.7 44.5-.7 44.5c32.5 0 31.7-44.5 .7-44.5zM384 32H64C28.7 32 0 60.7 0 96V416c0 35.3 28.7 64 64 64H384c35.3 0 64-28.7 64-64V96c0-35.3-28.7-64-64-64zM243.9 172.2c-14.5 0-22.9-8.4-22.9-22.9c0-14.5 8.4-22.3 22.9-22.3c14.7 0 23.1 7.8 23.1 22.3s-8.4 22.9-23.1 22.9zM149.6 195h49.5l0 21.6-23.4 1.8c4.6 5.8 9.4 14 9.4 25.7c0 48.7-57.2 47.2-74.2 42.4l-8.4 13.4c5 .3 9.8 .6 14.3 .8c56.3 3.2 80.5 4.6 80.5 38.5c0 29.2-25.7 45.7-69.9 45.7c-46 0-63.5-11.6-63.5-31.7c0-11.4 5.1-17.5 14-25.9c-8.4-3.5-11.2-9.9-11.2-16.8c0-9.6 7.4-16.3 23-30.6l.2-.2c-12.4-6.1-21.8-19.3-21.8-38.1c0-51.6 56.6-53.3 81.6-46.8zM270.5 303.1l13 1.8 0 20.1H211.1V304.9c2.7-.4 5-.7 6.9-.9c9.9-1.2 10.1-1.3 10.1-6V223.3c0-4.4-.9-4.7-10.1-7.8c-1.9-.7-4.2-1.4-6.9-2.4l2.8-20.6h52.6V298c0 4.1 .2 4.6 4.1 5.1zm106.6-10.4L384 315c-10.9 5.4-26.9 10.2-41.4 10.2c-30.2 0-41.7-12.2-41.7-40.9V217.7c0-.8 0-1.4-.2-1.8c-.8-1.2-4.2-.7-19.6-.7V192.6c22.3-2.5 31.2-13.7 34-41.4h24.2c0 33.3-.6 38 .7 38.6c.3 .1 .7 0 1.3 0h35.8v25.4H339.3v60.7c0 .2 0 .5 0 .9c-.2 6.3-.9 30.4 37.9 15.9z" />
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -0,0 +1,36 @@
{% extends "partials/_base.html" %}
{# Page title: #}
{% block title %}posts {{ SITENAME|lower }}{% endblock %}
{# Page metadata: #}
{% block meta %}
<meta name="description" content="" />
<link rel="canonical" href="{{ SITEURL }}/{{ ARCHIVES_SAVE_AS }}" />
{% endblock %}
{# OpenGraph metadata: #}
{% block opengraph %}
<meta property="og:type" content="website" />
<meta property="og:url" content="{{ SITEURL }}/{{ ARCHIVES_SAVE_AS }}" />
<meta property="og:title" content="posts {{ SITENAME|lower }}" />
<meta property="og:image" content="" />
<meta property="og:description" content="" />
{% endblock %}
{# Page content: #}
{% block content %}
<h1>Posts</h1>
<ul class="post-list">
{% for article in dates %}
<li class="flex-col md:flex-row mb-4 md:mb-2">
<span class="date text-base md:text-lg">{{ article.locale_date }}</span>
<span class="title">
<a href="{{ SITEURL }}/{{ article.url }}">{{ article.title }}</a>
</span>
</li>
{% endfor %}
</ul>
{% endblock %}

View File

@ -0,0 +1,59 @@
{% extends "partials/_base.html" %}
{# Page title: #}
{% block title %}{{ article.title|lower }} {{ SITENAME|lower }}{% endblock %}
{# Page metadata: #}
{% block meta %}
<meta name="description" content="{{ article.summary|striptags }}" />
<link rel="canonical" href="{{ SITEURL }}/{{ article.url }}" />
{% endblock %}
{# OpenGraph metadata: #}
{% block opengraph %}
<meta property="og:type" content="article" />
<meta property="og:url" content="{{ SITEURL }}/{{ article.url }}" />
<meta property="og:title" content="{{ article.title|lower }} {{ SITENAME|lower }}" />
<meta property="og:image" content="" />
<meta property="og:description" content="{{ article.summary|striptags }}" />
{% endblock %}
{# Page styles: #}
{% block styles %}
{% assets output="css/lightbulb.%(version)s.css", "css/lightbulb.css" %}
<link rel="stylesheet" type="text/css" href="{{ SITEURL }}/{{ ASSET_URL }}" />
{% endassets %}
{% endblock %}
{# Page content: #}
{% block content %}
<h1>{{ article.title }}</h1>
<div class="article-meta">Posted on {{ article.locale_date }}</div>
<article role="article">
{{ article.content }}
</article>
{% if article.prev_article or article.next_article %}
<div class="neighbours">
<div>
{% if article.prev_article %}
<a href="{{ SITEURL }}/{{ article.prev_article.url}}">
<span></span>
{{ article.prev_article.title }}
</a>
{% endif %}
</div>
<div class="spacer hidden md:block"></div>
<div>
{% if article.next_article %}
<a href="{{ SITEURL }}/{{ article.next_article.url}}">
{{ article.next_article.title }}
<span></span>
</a>
{% endif %}
</div>
</div>
{% endif %}
{% endblock %}

View File

@ -0,0 +1,27 @@
{% extends "partials/_base.html" %}
{# Page title: #}
{% block title %}{{ SITENAME|lower }}{% endblock %}
{# Page metadata: #}
{% block meta %}
<meta name="description" content="" />
<link rel="canonical" href="{{ SITEURL }}" />
{% endblock %}
{# OpenGraph metadata: #}
{% block opengraph %}
<meta property="og:type" content="website" />
<meta property="og:url" content="{{ SITEURL }}" />
<meta property="og:title" content="{{ SITENAME|lower }}" />
<meta property="og:image" content="" />
<meta property="og:description" content="" />
{% endblock %}
{# Page content: #}
{% block content %}
{# TODO: ??? #}
{% endblock %}

29
theme/templates/page.html Normal file
View File

@ -0,0 +1,29 @@
{% extends "partials/_base.html" %}
{# Page title: #}
{% block title %}{{ page.title|lower }} {{ SITENAME|lower }}{% endblock %}
{# Page metadata: #}
{% block meta %}
<meta name="description" content="" />
<link rel="canonical" href="{{ SITEURL }}/{{ page.url }}" />
{% endblock %}
{# OpenGraph metadata: #}
{% block opengraph %}
<meta property="og:type" content="article" />
<meta property="og:url" content="{{ SITEURL }}/{{ page.url }}" />
<meta property="og:title" content="{{ page.title|lower }} {{ SITENAME|lower }}" />
<meta property="og:image" content="" />
<meta property="og:description" content="" />
{% endblock %}
{# Page content: #}
{% block content %}
<h1>{{ page.title }}</h1>
<article role="article">
{{ page.content }}
</article>
{% endblock %}

View File

@ -0,0 +1,30 @@
<!DOCTYPE html>
<html lang="{{ DEFAULT_LANG }}">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>{% block title %}{% endblock %}</title>
<meta name="generator" content="Pelican" />
{% block meta %}{% endblock %}
{% block opengraph %}{% endblock %}
{% assets output="css/main.%(version)s.css", "css/main.css" %}
<link rel="stylesheet" type="text/css" href="{{ SITEURL }}/{{ ASSET_URL }}" />
{% endassets %}
{% block styles %}{% endblock %}
<link rel="alternate" type="application/atom+xml" href="{{ SITEURL }}/{{ FEED_ALL_ATOM }}" />
<link rel="sitemap" type="application/xml" title="Sitemap" href="{{ SITEURL }}/sitemap.xml" />
</head>
<body>
{% include "partials/_header.html" %}
<main role="main" class="container">
{% block content %}{% endblock %}
</main>
{% include "partials/_footer.html" %}
</body>
</html>

View File

@ -0,0 +1,15 @@
<footer>
<div class="container flex-col md:flex-row">
<div class="cc text-center md:text-left">
This work is licensed under
<a href="https://creativecommons.org/licenses/by-nc-sa/4.0/?ref=chooser-v1" target="_blank">CC BY-NC-SA 4.0</a>
</div>
<div class="social mt-6 md:mt-0">
{% for (name, url) in SOCIAL %}
<a href="{{ url }}" title="{{ name }}" target="_blank">
<img src="{{ SITEURL }}/theme/images/{{ name }}.svg" />
</a>
{% endfor %}
</div>
</div>
</footer>

View File

@ -0,0 +1,14 @@
<header role="banner">
<div class="container flex-col md:flex-row">
<div>
<a href="{{ SITEURL }}/" title="{{ SITENAME|lower }}" class="title">{{ SITENAME|lower }}</a>
</div>
<div class="mt-6 md:mt-0">
<nav role="navigation">
{% for (title, url) in MENUITEMS %}
<a href="{{ SITEURL }}/{{ url }}" title="{{ title }}">/{{ title }}</a>
{% endfor %}
</nav>
</div>
</div>
</header>