Preparing for a theme revamp
Post last updated 2 months ago
The itch hits once again and I'm looking to revamp the theme of this blog. I'll leave all the code for my current theme at the end of the post for posterity. Firstly, some reflections on what I like and don't like about my current theme.
The good
- the "Charcoal" dark theme, which was first designed together with my girlfriend1 and then adjusted
- the toast button, I'll probably keep it
- the light/dark and color palette buttons in the header
- the TT2020 font
The bad
- the right-side header/footer menu feels a bit off
- the CSS got too messy, and while the AI did help me do what I envisioned, I feel it did so in a very clunky way
- home page feels off
- not all elements of a blog post are fitting nicely one into the other (things like code blocks, blockquotes, headings etc)
The future
I want my next theme to be simpler and more coherent. Some nice blogs that inspired me with this are:
- chronosaur.us Archive 🔗 - very nice layout and that pink is lovely
- tadaima.bearblog.dev Archive 🔗 - I adore the simplicity of it and again, the pink is just killing it
- avas.bearblog.dev Archive 🔗 - simplicity and the pink accent in dark mode, chef's kiss
So besides simplicity I might have a slight pink obsession.
While the vision is mine, the code is in some parts generated with AI
Home
<h1 style="
font-family: ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;
font-size: 1.5em;
line-height: 1.2;
">
hi<br>
buna<br>
willkommen<br>
bienvenue<br>
こんにちは
</h1>
<p>
everyone, you've stumbled upon my refuge on the internet. Here I'm sharing my thoughts, <i>more or less coherently</i> about various topics, from tech to politics and random daily stuff. In my life I've been warned more than once about being insensitive when expressing my thoughts, consider yourself warned. These being said, I do have good intentions. <br>
Have a nice stay! (´• ω •`)
</p>
Nav
<div class="theme-controls" role="group" aria-label="Theme settings">
<span aria-hidden="true">◆◆</span>
<button type="button" id="preferdark" class="theme-toggle" data-action="switch-light">ʕ -ᴥ-ʔ</button>
<button type="button" id="preferlight" class="theme-toggle" data-action="switch-dark">ʕ •ᴥ•ʔ</button>
<span class="palette-dropdown" id="light-palette-dropdown">
<button type="button" class="theme-icon" data-action="toggle-palette">☼</button>
<div class="palette-menu">
<button class="palette-option" data-palette="first">Rose</button>
<button class="palette-option" data-palette="second">Forest</button>
<button class="palette-option" data-palette="third">Ocean</button>
<button class="palette-option" data-palette="fourth">Warmth</button>
<button class="palette-option" data-palette="fifth">Cool</button>
</div>
</span>
<span class="palette-dropdown" id="dark-palette-dropdown">
<button type="button" class="theme-icon" data-action="toggle-palette"> ☾ </button>
<div class="palette-menu">
<button class="palette-option" data-palette="first">Deep Teal</button>
<button class="palette-option" data-palette="second">Plum Garden</button>
<button class="palette-option" data-palette="third">Ember</button>
<button class="palette-option" data-palette="fourth">Moss</button>
<button class="palette-option" data-palette="fifth">Midnight</button>
<button class="palette-option" data-palette="sixth">Charcoal</button>
</div>
</span>
<span aria-hidden="true">◆◆</span>
</div>
<p class="intro">Read a few words <a href="/about">about myself</a>, my views on <a href="/ai">AI</a>, what I <a href="/use">use</a> or check <a href="/blog">all posts</a><br>You can subscribe to my <a href="/feed">RSS</a> or <a href="mailto:george.bals25@gmail.com">contact me</a></p>
Head
<script>
(function() {
const html = document.documentElement;
const getStored = (key, fallback) => localStorage.getItem(key) || fallback;
// Default logic: Force 'dark' and 'sixth' (Charcoal) for new users
const theme = getStored('theme', 'dark');
html.setAttribute('data-theme', theme);
const defaultPal = (theme === 'dark') ? 'sixth' : 'first';
html.setAttribute('data-palette', getStored('pal-' + theme, defaultPal));
function updateUI() {
const currentPal = html.getAttribute('data-palette');
document.querySelectorAll('.palette-option').forEach(btn => {
btn.classList.toggle('active', btn.getAttribute('data-palette') === currentPal);
});
}
document.addEventListener('click', (e) => {
const target = e.target;
const action = target.closest('[data-action]')?.getAttribute('data-action');
const palBtn = target.closest('.palette-option');
if (action?.startsWith('switch-')) {
const newMode = action.replace('switch-', '');
html.setAttribute('data-theme', newMode);
localStorage.setItem('theme', newMode);
const savedPal = getStored('pal-' + newMode, (newMode === 'dark' ? 'sixth' : 'first'));
html.setAttribute('data-palette', savedPal);
updateUI();
}
if (action === 'toggle-palette') {
e.stopPropagation();
const menu = target.closest('.palette-dropdown').querySelector('.palette-menu');
const isShow = menu.classList.contains('show');
document.querySelectorAll('.palette-menu').forEach(m => m.classList.remove('show'));
if (!isShow) menu.classList.add('show');
}
if (palBtn) {
const newPal = palBtn.getAttribute('data-palette');
html.setAttribute('data-palette', newPal);
localStorage.setItem('pal-' + html.getAttribute('data-theme'), newPal);
updateUI();
}
if (!target.closest('.palette-dropdown')) {
document.querySelectorAll('.palette-menu').forEach(m => m.classList.remove('show'));
}
});
window.addEventListener('DOMContentLoaded', updateUI);
})();
</script>
Footer
<a href="https://www.goeuropean.org/"><img src="https://bear-images.sfo2.cdn.digitaloceanspaces.com/balssh/buyfromeu.gif" alt="Buy from EU"></a>
CSS
/* 1. FONT & CORE VARIABLES */
@font-face {
font-family: 'tt2020';
src: url('https://bear-images.sfo2.cdn.digitaloceanspaces.com/balssh/tt2020base-regular.woff2') format('woff2');
font-weight: normal;
font-style: normal;
font-display: swap;
}
:root {
--font-mono: 'tt2020', monospace;
--width: 65ch;
color-scheme: dark;
/* Default: Charcoal */
--bg: oklch(17.5% 0.02 339.24);
--text: oklch(82% 0.04 98);
--text-dim: oklch(68% 0.03 98);
--accent: oklch(72% 0.11 34.37);
--link: oklch(78% 0.10 145);
--code-bg: oklch(21% 0.02 339);
--border: oklch(27% 0.02 339);
}
/* --- Light Palettes --- */
html[data-theme="light"][data-palette="first"] {
--bg: oklch(94% 0.025 290);
--text: oklch(25% 0.04 290);
--text-dim: oklch(50% 0.035 290);
--accent: oklch(68% 0.18 30); /* Coral sunset against lavender */
--link: oklch(50% 0.12 140); /* Fresh lime contrast */
--code-bg: oklch(90% 0.035 290);
--border: oklch(86% 0.045 290);
}
html[data-theme="light"][data-palette="second"] {
--bg: oklch(95% 0.02 145);
--text: oklch(22% 0.03 145);
--text-dim: oklch(48% 0.03 145);
--accent: oklch(55% 0.14 145);
--link: oklch(42% 0.1 145);
--code-bg: oklch(91% 0.025 145);
--border: oklch(87% 0.03 145);
}
html[data-theme="light"][data-palette="third"] {
--bg: oklch(96% 0.025 195); /* Shifted toward seafoam/cyan */
--text: oklch(22% 0.04 195);
--text-dim: oklch(48% 0.03 195); /* Added depth */
--accent: oklch(65% 0.16 20); /* Salmon/coral - ocean sunset */
--link: oklch(45% 0.1 265); /* Deep water blue */
--code-bg: oklch(92% 0.03 195);
--border: oklch(88% 0.035 195);
}
html[data-theme="light"][data-palette="fourth"] {
--bg: oklch(94% 0.025 55); /* Warm sand */
--text: oklch(25% 0.04 55);
--text-dim: oklch(50% 0.035 55); /* Added depth */
--accent: oklch(62% 0.18 30); /* Terracotta/rust */
--link: oklch(48% 0.1 245); /* Shadow blue */
--code-bg: oklch(90% 0.03 55);
--border: oklch(86% 0.04 55);
}
html[data-theme="light"][data-palette="fifth"] {
--bg: oklch(94% 0.02 255); /* Storm slate */
--text: oklch(20% 0.03 255);
--text-dim: oklch(45% 0.025 255); /* Added depth */
--accent: oklch(68% 0.16 55); /* Lightning amber */
--link: oklch(50% 0.1 345); /* Soft magenta */
--code-bg: oklch(90% 0.02 255);
--border: oklch(85% 0.03 255);
}
/* --- Dark Palettes --- */
html[data-theme="dark"][data-palette="first"] {
--bg: oklch(17% 0.025 215);
--text: oklch(82% 0.04 210);
--accent: oklch(70% 0.12 205);
--link: oklch(76% 0.11 140);
--code-bg: oklch(21% 0.02 215);
--border: oklch(27% 0.025 215);
}
html[data-theme="dark"][data-palette="second"] {
--bg: oklch(17% 0.02 270);
--text: oklch(82% 0.04 285);
--accent: oklch(73% 0.15 300);
--link: oklch(75% 0.10 80);
--code-bg: oklch(21% 0.02 270);
--border: oklch(27% 0.02 270);
}
html[data-theme="dark"][data-palette="third"] {
--bg: oklch(17.5% 0.02 15);
--text: oklch(82% 0.04 50);
--accent: oklch(74% 0.16 40);
--link: oklch(74% 0.10 155);
--code-bg: oklch(21% 0.02 20);
--border: oklch(27% 0.02 20);
}
html[data-theme="dark"][data-palette="fourth"] {
--bg: oklch(17% 0.02 140);
--text: oklch(82% 0.04 135);
--accent: oklch(72% 0.14 80);
--link: oklch(76% 0.10 30);
--code-bg: oklch(21% 0.02 140);
--border: oklch(27% 0.02 140);
}
html[data-theme="dark"][data-palette="fifth"] {
--bg: oklch(14% 0.015 250);
--text: oklch(85% 0.05 55);
--accent: oklch(75% 0.18 315);
--link: oklch(78% 0.12 185);
--code-bg: oklch(19% 0.015 250);
--border: oklch(25% 0.015 250);
}
html[data-theme="dark"][data-palette="sixth"] {
--bg: oklch(17.5% 0.02 339.24);
--text: oklch(82% 0.04 98);
--accent: oklch(72% 0.11 34.37);
--link: oklch(78% 0.10 145);
--code-bg: oklch(21% 0.02 339);
--border: oklch(27% 0.02 339);
}
/* 2. GLOBAL LAYOUT & MOBILE FIXES */
*, *::before, *::after {
transition: background-color 0.3s ease, color 0.3s ease, border-color 0.3s ease;
box-sizing: border-box;
}
html {
background-color: var(--bg);
height: 100%;
scrollbar-gutter: stable;
}
body {
font-family: var(--font-mono);
font-weight: 600;
font-size: 1.3rem;
line-height: 1.5;
margin: 0;
padding: 20px;
min-height: 100vh;
background-color: var(--bg);
color: var(--text);
text-align: justify;
}
/* Images & Directive Gif */
img {
max-width: 100%;
height: auto;
display: block;
margin: 1.5rem auto;
border-radius: 4px;
}
#footer-directive img {
display: inline-block;
margin: 0 auto;
max-width: 180px;
height: auto;
border: 1px solid var(--border);
padding: 4px;
background: var(--code-bg);
}
/* Desktop Grid */
@media screen and (min-width: 992px) {
body {
display: grid;
margin: 0 auto;
max-width: 1400px;
grid-template-columns: 1fr var(--width) 25ch 0.5fr;
grid-template-rows: auto auto 1fr;
grid-template-areas:
". main header ."
". main footer ."
". main . .";
justify-items: start;
column-gap: 40px;
padding: 60px 40px;
}
header {
grid-area: header;
border-left: 5px solid color-mix(in oklch, var(--accent), transparent 50%);
padding: 0 0 5px 1.2rem;
align-self: start;
}
footer {
grid-area: footer;
padding: 0 1.2rem !important;
}
#footer-directive img {
margin: 0;
}
main {
grid-area: main;
width: 100%;
max-width: var(--width);
margin: 0 auto;
}
}
/* 3. TYPOGRAPHY & IFRAMES */
h1, h2, h3 {
color: var(--accent);
font-weight: 700;
margin-top: 0;
}
a {
color: var(--link);
text-decoration: none;
}
a:hover {
color: var(--accent);
text-decoration: underline;
}
hr {
border: 0;
border-top: 1px dashed var(--border);
margin: 2rem 0;
}
code {
font-family: monospace;
padding: 2px 5px;
background-color: var(--code-bg);
border-radius: 3px;
color: var(--link);
}
blockquote {
border-left: 2px solid var(--accent);
color: var(--text-dim);
padding-left: 20px;
font-style: italic;
margin: 1.5rem 0;
}
.embed-container {
width: 100%;
margin: 1.5rem 0;
}
iframe {
border: 1px solid var(--border);
border-radius: 8px;
filter: grayscale(0.2) contrast(0.9);
transition: all 0.3s ease;
}
iframe:hover {
filter: grayscale(0) contrast(1);
border-color: var(--accent);
}
/* 4. POST LIST (Fixed Mobile Spacing) */
ul.blog-posts {
list-style: none;
padding: 0;
}
ul.blog-posts > li {
display: flex;
flex-direction: row-reverse;
justify-content: space-between;
align-items: baseline;
padding: 0.6em 0;
border-bottom: 1px solid var(--border);
gap: 1rem;
}
ul.blog-posts a {
color: var(--text);
}
ul.blog-posts a:hover {
color: var(--link);
padding-left: 4px;
}
@media screen and (max-width: 600px) {
ul.blog-posts > li {
flex-direction: column;
align-items: flex-start;
gap: 0.2rem;
}
}
/* 5. YOUR CUSTOM UPVOTE BUTTONS (Restored) */
.upvote-button svg {
display: none;
}
.upvote-button {
flex-direction: row !important;
gap: .75em;
cursor: pointer;
background: transparent;
border: none;
padding: 0;
display: flex;
}
.upvote-button::before {
content: 'ʕ ꈍᴥꈍʔ';
font-family: var(--font-mono);
font-size: 0.9rem;
border: 1px solid var(--border);
border-radius: .5em;
padding: 0.3em 0.8em;
background-color: var(--code-bg);
color: var(--text);
transition: all 0.2s ease;
}
.upvote-button:hover::before {
content: 'ʕ•ᴥ•ʔノ♡';
background-color: var(--link);
color: var(--bg);
border-color: var(--link);
}
.upvote-button[disabled]::before {
content: 'ʕ≧ᴥ≦ʔ';
background-color: transparent;
border: 1px dashed var(--border);
color: var(--text-dim);
}
.upvote-count {
margin: 0;
color: var(--text-dim);
font-size: 0.9rem;
}
.upvote-count::after {
content: ' ♡';
}
/* 6. UI CONTROLS */
.theme-controls {
display: flex;
align-items: center;
gap: 12px;
margin: 1rem 0;
font-size: 0.95rem;
color: var(--text-dim);
position: relative;
}
#preferlight, #preferdark, .palette-dropdown {
display: none;
}
html[data-theme="light"] #preferlight, html[data-theme="light"] #light-palette-dropdown {
display: inline-flex;
}
html[data-theme="dark"] #preferdark, html[data-theme="dark"] #dark-palette-dropdown {
display: inline-flex;
}
.theme-toggle {
cursor: pointer;
font-size: 1.2rem;
padding: 0.2rem;
background: none;
border: 1px solid transparent;
border-radius: 4px;
color: var(--text-dim);
}
.theme-toggle:hover {
color: var(--accent);
background: var(--code-bg);
border-color: var(--border);
}
.theme-icon {
cursor: pointer;
font-size: 1.4rem;
padding: 0.2rem;
background: none;
border: 1px solid transparent;
border-radius: 4px;
color: var(--text-dim);
}
.theme-icon:hover {
color: var(--accent);
background: var(--code-bg);
border-color: var(--border);
}
.palette-menu {
display: none;
position: absolute;
top: 100%;
left: 50%;
transform: translateX(-50%);
background-color: var(--code-bg);
border: 1px solid var(--border);
border-radius: 4px;
box-shadow: 0 4px 12px rgba(0,0,0,0.4);
z-index: 100;
min-width: 150px;
}
.palette-menu.show {
display: flex;
flex-direction: column;
}
.palette-option {
padding: 0.5rem;
font-family: var(--font-mono);
color: var(--text);
background: none;
border: none;
cursor: pointer;
text-align: center;
}
.palette-option:hover {
background-color: var(--accent);
color: var(--bg);
}
.palette-option.active {
background-color: var(--link);
color: var(--bg);
}
/* 7. CODE BLOCKS */
.highlight {
background-color: var(--code-bg);
border: 1px solid var(--border);
border-radius: 8px;
margin: 1.5rem 0;
padding: 1.2rem;
overflow-x: auto; /* Keeps long code lines from breaking the layout */
font-family: var(--font-mono);
font-size: 0.85em; /* Scales nicely against your 1.3rem body size */
color: var(--text);
box-shadow: inset 0 2px 4px rgb(0 0 0 / 5%);
scrollbar-color: var(--border) transparent; /* For Firefox */
}
/* Reset the `<pre>` tag often generated by markdown parsers */
.highlight pre {
margin: 0;
padding: 0;
background: transparent;
border: none;
}
/* Override your inline `code` rule so the whole block isn't your --link color */
.highlight code {
background-color: transparent;
padding: 0;
color: inherit;
border-radius: 0;
font-family: inherit;
font-size: inherit;
white-space: pre; /* Preserves formatting */
}
/* Custom Webkit scrollbars so the scrollable code blocks match the theme */
.highlight::-webkit-scrollbar {
height: 8px;
}
.highlight::-webkit-scrollbar-track {
background: transparent;
border-radius: 0 0 8px 8px;
}
.highlight::-webkit-scrollbar-thumb {
background-color: var(--border);
border-radius: 4px;
}
.highlight::-webkit-scrollbar-thumb:hover {
background-color: var(--accent);
}
You can reach out by sending me an email.
The color combinations were chosen based on my very vague ramblings about what colors I think I'd like to use and her actual good eyes.↩