diff --git a/content/archive.md b/content/archive.md
new file mode 100644
index 0000000..a4a7385
--- /dev/null
+++ b/content/archive.md
@@ -0,0 +1 @@
+[directory]
diff --git a/content/default.css b/content/default.css
index c49940e..2e16ab0 100644
--- a/content/default.css
+++ b/content/default.css
@@ -1,20 +1,29 @@
/* content/default.css */
-/*
- The "27bslash6" Aesthetic:
- - Stark Black & White
- - Helvetica / Arial
- - Narrow, centered reading column
- - Zero border radius, zero shadows
-*/
-
:root {
--bg-color: #ffffff;
- --text-color: #000000;
- --link-color: #cc0000; /* That specific "angry" red he sometimes uses, or just black */
- --meta-color: #666666;
- --font-stack: "Helvetica Neue", Helvetica, Arial, sans-serif;
- --max-width: 680px; /* The classic narrow column */
+ --header-bg: #000000;
+ --header-text: #ffffff;
+ --text-color: #333333;
+ --link-color: #000000;
+ --accent-color: #cc0000;
+ --sidebar-bg: #ffffff;
+ --sidebar-border: #000000;
+ --font-primary: "Helvetica Neue", Helvetica, Arial, sans-serif;
+ --font-mono: "Monaco", "Menlo", monospace;
+ --content-width: 680px;
+}
+
+body.dark-mode {
+ --bg-color: #1a1a1a;
+ --header-bg: #000000;
+ /* Keep header black, maybe slightly lighter? User said "dark theme" */
+ --header-text: #e0e0e0;
+ --text-color: #e0e0e0;
+ --link-color: #ffffff;
+ --accent-color: #ff4444;
+ --sidebar-bg: #2a2a2a;
+ --sidebar-border: #555555;
}
* {
@@ -22,216 +31,279 @@
}
body {
+ margin: 0;
+ padding: 0;
background-color: var(--bg-color);
color: var(--text-color);
- font-family: var(--font-stack);
- font-size: 15px; /* Slightly smaller, crisp text */
- line-height: 1.5;
- margin: 0;
- padding: 2rem 1rem;
+ font-family: var(--font-primary);
+ font-size: 18px;
+ line-height: 1.6;
+ -webkit-font-smoothing: antialiased;
}
-/* The main document container */
-body > * {
- max-width: var(--max-width);
- margin-left: auto;
- margin-right: auto;
- display: block;
+/* Header - Stark Black Block */
+/* Ensure header text color uses variable */
+.main-header {
+ background-color: var(--header-bg);
+ color: var(--header-text);
+ /* Make header taller per request */
+ padding: 6rem 1rem;
+ margin-bottom: 5rem;
+}
+
+.header-content {
+ max-width: var(--content-width);
+ margin: 0 auto;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 2rem;
+ /* Space between logo and text */
+}
+
+.header-logo img {
+ height: 80px;
+ /* Adjust as needed */
+ width: auto;
+ margin: 0;
+ border: none;
+}
+
+.main-header h1 {
+ margin: 0;
+ /* Make title bigger per request */
+ font-size: 4rem;
+ font-weight: 700;
+ letter-spacing: -1px;
+ line-height: 1;
+ text-align: left;
+}
+
+/* Content Container */
+.main-content {
+ max-width: var(--content-width);
+ margin: 0 auto;
+ padding: 0 1rem 8rem 1rem;
+ /* Bottom padding for scroll space */
}
/* Typography */
-h1, h2, h3 {
- font-weight: bold;
- letter-spacing: -0.5px;
- margin-top: 2.5rem;
- margin-bottom: 1rem;
+/* Update headers to use text color variable */
+h1,
+h2,
+h3,
+h4 {
+ color: var(--text-color);
+ margin-top: 2.5em;
+ margin-bottom: 0.8em;
+ font-weight: 700;
+ line-height: 1.2;
}
-h1 {
- font-size: 24px;
- border-bottom: 1px solid #000;
- padding-bottom: 10px;
- margin-top: 0;
+/* First Line Logic - "Sugar" */
+/* Update first paragraph color */
+.main-content>p:first-of-type {
+ font-size: 1.3em;
+ color: var(--text-color);
+ /* Was hardcoded #000 */
+ margin-bottom: 2em;
+ line-height: 1.5;
}
-h2 {
- font-size: 18px;
+/* Dark Mode Toggle Button */
+#theme-toggle {
+ background: none;
+ border: 1px solid var(--sidebar-border);
+ color: var(--text-color);
+ padding: 5px 10px;
+ cursor: pointer;
+ font-family: var(--font-primary);
+ margin-top: 1rem;
+ width: 100%;
+ text-transform: uppercase;
+ font-size: 0.8rem;
+}
+
+#theme-toggle:hover {
+ background-color: var(--accent-color);
+ color: #fff;
+ border-color: var(--accent-color);
}
p {
- margin-bottom: 1.2rem;
- text-align: justify; /* Gives it that "formal letter" look */
+ margin-bottom: 1.5em;
}
-/* Links - Stark and obvious */
a {
- color: var(--text-color);
+ color: var(--link-color);
text-decoration: underline;
text-decoration-thickness: 1px;
+ text-underline-offset: 2px;
}
a:hover {
- color: var(--link-color);
- text-decoration: none;
+ color: var(--accent-color);
+ text-decoration-color: var(--accent-color);
}
-/* Code blocks - Raw and industrial */
-pre {
- background: #f0f0f0;
- border: 1px solid #ccc;
- padding: 15px;
- font-family: "Monaco", "Menlo", "Consolas", monospace;
- font-size: 12px;
- overflow-x: auto;
- margin: 1.5rem 0;
-}
-
-code {
- font-family: "Monaco", "Menlo", "Consolas", monospace;
- background: #f0f0f0;
- padding: 2px 4px;
- font-size: 90%;
-}
-
-/* Blockquotes - The "Email Reply" look */
-blockquote {
- margin: 1.5rem 0;
- padding-left: 15px;
- border-left: 4px solid #000;
- color: var(--meta-color);
- font-style: italic;
-}
-
-/* Images - fit the column */
+/* Images - Full width of container */
img {
max-width: 100%;
height: auto;
display: block;
- margin: 2rem auto;
- border: 1px solid #000; /* Optional: adds to the brutalist feel */
+ margin: 3rem auto;
}
-/* Lists */
-ul, ol {
- padding-left: 20px;
- margin-bottom: 1.5rem;
+/* Code */
+pre {
+ background: #f4f4f4;
+ padding: 1.5rem;
+ overflow-x: auto;
+ font-size: 0.9em;
+ border-radius: 4px;
+ /* Slight softening */
+ margin: 2rem 0;
}
-li {
- margin-bottom: 0.5rem;
+code {
+ font-family: var(--font-mono);
+ background: #f4f4f4;
+ padding: 2px 4px;
+ font-size: 0.9em;
}
-/*
- Specific Components
-*/
-
-/* Top Banner - The "System Notice" Style
-*/
-.topbanner {
- background-color: #f4f4f4; /* Very light grey, distinct from white body */
- border: 1px solid #000; /* Crisp definition */
- border-left-width: 6px; /* Thick accent, matches your sidebar theme */
- padding: 1.5rem 2rem; /* Generous padding for readability */
- margin-bottom: 3rem; /* Push the H1 down */
- font-size: 14px; /* Slightly smaller than body text */
+blockquote {
+ border-left: 3px solid #000;
+ margin: 2rem 0;
+ padding-left: 1.5rem;
+ font-style: italic;
+ color: #666;
}
-/* Ensure text inside the banner doesn't inherit the 'justify' from global p */
-.topbanner p {
- text-align: left;
- margin-bottom: 0.5rem;
-}
-
-.topbanner p:last-child {
- margin-bottom: 0;
-}
-
-/* Optional: Make links inside the banner aggressive */
-.topbanner a {
- font-weight: bold;
- border-bottom: 2px solid var(--link-color);
- text-decoration: none;
-}
-
-.topbanner a:hover {
- background-color: var(--link-color);
- color: white;
-}
-
-/* The Site Headline (Top of Index) */
-.site-headline {
- margin-bottom: 3rem;
- text-align: left;
-}
-
-.site-headline h1 {
- font-size: 32px;
- border: none;
- padding: 0;
- margin: 0;
- letter-spacing: -1px;
-}
-
-/* Sidebar Styles */
+/* Sidebar - The "Ghost" Panel */
.sidebar {
- float: right;
- width: 30%;
- min-width: 250px;
- margin-left: 2rem;
- margin-bottom: 1rem;
- padding: 1rem;
- background-color: #f9f9f9;
- border-left: 4px solid #333;
+ position: fixed;
+ right: 2rem;
+ bottom: 2rem;
+ width: 300px;
+ background: var(--sidebar-bg);
+ border: 1px solid var(--sidebar-border);
+ padding: 2rem;
+ opacity: 0;
+ /* Default hidden */
+ pointer-events: none;
+ transition: opacity 0.3s ease;
+ z-index: 100;
+ box-shadow: 10px 10px 0px rgba(0, 0, 0, 0.1);
+ /* 27bslash6 vibe */
}
-/* The Latest Posts List */
-.latest-posts {
- margin-top: 3rem;
- border-top: 4px solid #000;
- padding-top: 1rem;
+.sidebar.force-visible {
+ opacity: 1 !important;
+ pointer-events: auto !important;
+}
+
+#close-sidebar {
+ position: absolute;
+ top: 5px;
+ right: 10px;
+ background: none;
+ border: none;
+ font-size: 1.5rem;
+ cursor: pointer;
+ font-weight: bold;
+ color: var(--text-color);
}
.latest-posts h2 {
- font-size: 14px;
+ margin-top: 0;
+ font-size: 1rem;
text-transform: uppercase;
- color: var(--meta-color);
- margin-bottom: 1rem;
+ border-bottom: 2px solid var(--sidebar-border);
+ padding-bottom: 0.5rem;
}
.latest-posts ul {
list-style: none;
padding: 0;
+ margin: 0;
}
.latest-posts li {
+ margin-bottom: 0.8rem;
+ font-size: 0.9rem;
display: flex;
- justify-content: space-between;
- border-bottom: 1px solid #eee;
- padding: 8px 0;
+ flex-direction: column;
}
.latest-posts .date {
- color: var(--meta-color);
- font-size: 12px;
- margin-right: 1rem;
- min-width: 100px;
+ font-size: 0.75rem;
+ color: #888;
+ margin-bottom: 2px;
}
.latest-posts a {
text-decoration: none;
- font-weight: bold;
+ font-weight: 500;
}
.latest-posts a:hover {
- text-decoration: underline;
- color: var(--link-color);
+ color: var(--accent-color);
}
-/* Directory Link */
.directory-link {
- margin: 2rem 0;
- text-align: right;
- font-size: 12px;
- text-transform: uppercase;
+ margin-top: 1.5rem;
+ text-align: center;
+ font-size: 0.9rem;
font-weight: bold;
+ text-transform: uppercase;
+}
+
+/* Mobile Trigger */
+#read-more-trigger {
+ position: fixed;
+ bottom: 0;
+ left: 0;
+ width: 100%;
+ background: #000;
+ color: #fff;
+ text-align: center;
+ padding: 1rem;
+ font-weight: bold;
+ cursor: pointer;
+ transform: translateY(100%);
+ transition: transform 0.3s ease;
+ z-index: 90;
+ display: none;
+ /* Desktop default hidden */
+}
+
+/* Mobile Tweaks */
+@media (max-width: 900px) {
+ .sidebar {
+ display: none;
+ /* Hide standard sidebar on mobile */
+ }
+
+ .sidebar.force-visible {
+ display: block;
+ left: 1rem;
+ right: 1rem;
+ bottom: 4rem;
+ /* Above trigger */
+ width: auto;
+ }
+
+ #read-more-trigger {
+ display: block;
+ /* Active on mobile */
+ }
+
+ #read-more-trigger.visible {
+ transform: translateY(0);
+ }
+
+ .main-header h1 {
+ font-size: 2rem;
+ }
}
\ No newline at end of file
diff --git a/content/entries/test_math.md b/content/entries/test_math.md
new file mode 100644
index 0000000..aa77f4c
--- /dev/null
+++ b/content/entries/test_math.md
@@ -0,0 +1,17 @@
+---
+title: "Math Test"
+---
+
+This is a test of **MathJax** support.
+
+Inline math: $E=mc^2$ is the theory of special relativity.
+
+Block math:
+$$
+\sum_{i=1}^{n} i = \frac{n(n+1)}{2}
+$$
+
+Another block:
+$$
+\int_{-\infty}^{\infty} e^{-x^2} dx = \sqrt{\pi}
+$$
diff --git a/content/theme.js b/content/theme.js
new file mode 100644
index 0000000..36c1df5
--- /dev/null
+++ b/content/theme.js
@@ -0,0 +1,131 @@
+document.addEventListener('DOMContentLoaded', () => {
+ const sidebar = document.getElementById('sidebar');
+ const closeBtn = document.getElementById('close-sidebar');
+ const trigger = document.getElementById('read-more-trigger');
+ const body = document.body;
+ let manualClose = false;
+
+ // --- Sidebar Logic ---
+
+ function checkSidebarVisibility() {
+ if (manualClose) return;
+
+ const scrollTop = window.scrollY;
+ const windowHeight = window.innerHeight;
+ const docHeight = document.documentElement.scrollHeight;
+
+ // "Sidebar fix": Check if page is short (content fits in window or close to it)
+ // If content is short, sidebar should be visible immediately (if desktop)
+ if (docHeight <= windowHeight * 1.2 && window.innerWidth > 900) {
+ sidebar.classList.add('visible');
+ sidebar.style.opacity = 1;
+ sidebar.style.pointerEvents = 'auto';
+ return;
+ }
+
+ // Scroll Logic for longer pages
+ if (scrollTop + windowHeight > docHeight * 0.9) {
+ sidebar.classList.add('visible');
+ trigger.classList.add('visible');
+
+ // Dynamic Opacity near bottom
+ const remaining = docHeight - (scrollTop + windowHeight);
+ const threshold = docHeight * 0.1;
+
+ if (remaining < threshold) {
+ const opacity = 1 - (remaining / threshold);
+ sidebar.style.opacity = Math.min(Math.max(opacity, 0), 1);
+
+ if (opacity > 0) {
+ sidebar.style.pointerEvents = 'auto';
+ } else {
+ sidebar.style.pointerEvents = 'none';
+ }
+ } else {
+ // Should be redundant with visibility check but safe
+ }
+ } else {
+ // Hide if scrolled up?
+ // "It just is gone then... manual close... refresh if want it back"
+ // But scroll behavior implies transient visibility.
+ // We'll hide it if we scroll back up, unless it's short content.
+ sidebar.style.opacity = 0;
+ sidebar.style.pointerEvents = 'none';
+ }
+ }
+
+ window.addEventListener('scroll', checkSidebarVisibility);
+ window.addEventListener('resize', checkSidebarVisibility);
+
+ // Initial check
+ setTimeout(checkSidebarVisibility, 100); // Slight delay for rendering
+
+ // Mobile Trigger
+ trigger.addEventListener('click', () => {
+ sidebar.classList.add('force-visible');
+ sidebar.style.opacity = 1;
+ sidebar.style.pointerEvents = 'auto';
+ });
+
+ // Close Button
+ closeBtn.addEventListener('click', () => {
+ sidebar.classList.remove('visible');
+ sidebar.classList.remove('force-visible');
+ sidebar.style.opacity = 0;
+ sidebar.style.pointerEvents = 'none';
+ manualClose = true;
+ trigger.style.display = 'none';
+ });
+
+ // --- Dark Mode Logic ---
+
+ // Create Toggle Button
+ const sidebarContent = document.querySelector('.sidebar-content');
+ const themeBtn = document.createElement('button');
+ themeBtn.id = 'theme-toggle';
+ themeBtn.textContent = 'Toggle Theme';
+ sidebarContent.appendChild(themeBtn);
+
+ function setDarkMode(enable) {
+ if (enable) {
+ body.classList.add('dark-mode');
+ themeBtn.textContent = 'Switch to Light Mode';
+ } else {
+ body.classList.remove('dark-mode');
+ themeBtn.textContent = 'Switch to Dark Mode';
+ }
+ }
+
+ function getCookie(name) {
+ const v = document.cookie.match('(^|;) ?' + name + '=([^;]*)(;|$)');
+ return v ? v[2] : null;
+ }
+
+ function setCookie(name, value, hours) {
+ const d = new Date();
+ d.setTime(d.getTime() + (hours * 60 * 60 * 1000));
+ document.cookie = name + "=" + value + ";path=/;expires=" + d.toUTCString();
+ }
+
+ // Init Dark Mode
+ const cookieTheme = getCookie('theme');
+ if (cookieTheme === 'dark') {
+ setDarkMode(true);
+ } else if (cookieTheme === 'light') {
+ setDarkMode(false);
+ } else {
+ // Time based auto-detect
+ const hour = new Date().getHours();
+ if (hour < 6 || hour >= 18) {
+ setDarkMode(true);
+ } else {
+ setDarkMode(false);
+ }
+ }
+
+ themeBtn.addEventListener('click', () => {
+ const isDark = body.classList.contains('dark-mode');
+ setDarkMode(!isDark);
+ setCookie('theme', !isDark ? 'dark' : 'light', 24);
+ });
+});
diff --git a/go.mod b/go.mod
index 4f8d212..fbe5dcf 100644
--- a/go.mod
+++ b/go.mod
@@ -8,6 +8,7 @@ require go.abhg.dev/goldmark/frontmatter v0.3.0
require (
github.com/BurntSushi/toml v1.6.0 // indirect
+ github.com/litao91/goldmark-mathjax v0.0.0-20210217064022-a43cf739a50f // indirect
github.com/tendstofortytwo/goldmark-customtag v0.0.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
diff --git a/go.sum b/go.sum
index 0b623c1..4bf0a52 100644
--- a/go.sum
+++ b/go.sum
@@ -1,18 +1,25 @@
github.com/BurntSushi/toml v1.6.0 h1:dRaEfpa2VI55EwlIW72hMRHdWouJeRF7TPYhI+AUQjk=
github.com/BurntSushi/toml v1.6.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/litao91/goldmark-mathjax v0.0.0-20210217064022-a43cf739a50f h1:plCPYXRXDCO57qjqegCzaVf1t6aSbgCMD+zfz18POfs=
+github.com/litao91/goldmark-mathjax v0.0.0-20210217064022-a43cf739a50f/go.mod h1:leg+HM7jUS84JYuY120zmU68R6+UeU6uZ/KAW7cViKE=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/tendstofortytwo/goldmark-customtag v0.0.1 h1:c3Wnzi98gE7BPaqio/UOQVGGJU0EMdgKwjQHo9Y7NKQ=
github.com/tendstofortytwo/goldmark-customtag v0.0.1/go.mod h1:9KHP0WeHIafExF+Zu4CIDfzgfMo/FaEKXUO7NFmCyos=
+github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.7.16 h1:n+CJdUxaFMiDUNnWC3dMWCIQJSkxH4uz3ZwQBkAlVNE=
github.com/yuin/goldmark v1.7.16/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg=
go.abhg.dev/goldmark/frontmatter v0.3.0 h1:ZOrMkeyyYzhlbenFNmOXyGFx1dFE8TgBWAgZfs9D5RA=
go.abhg.dev/goldmark/frontmatter v0.3.0/go.mod h1:W3KXvVveKKxU1FIFZ7fgFFQrlkcolnDcOVmu19cCO9U=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/parse.go b/parse.go
index d9694f3..8b0ee1e 100644
--- a/parse.go
+++ b/parse.go
@@ -8,40 +8,24 @@ import (
"path/filepath"
"regexp"
"strings"
+ "time"
"git.else-if.org/jess/blog/templates"
+ "github.com/BurntSushi/toml"
+ mathjax "github.com/litao91/goldmark-mathjax"
"github.com/yuin/goldmark"
"github.com/yuin/goldmark/extension"
"github.com/yuin/goldmark/parser"
"github.com/yuin/goldmark/renderer/html"
"go.abhg.dev/goldmark/frontmatter"
+ "gopkg.in/yaml.v3"
)
// GetContentPath ensures the content is cached and returns the path to the cached file.
func GetContentPath(file ContentFile) (string, error) {
cachePath := GetCacheFilename(file.OriginalPath)
- // 1. Check Cache Freshness (if not in TestMode)
- if !TestMode {
- cacheInfo, errCache := os.Stat(cachePath)
- origInfo, errOrig := os.Stat(file.OriginalPath)
- if errCache == nil && errOrig == nil && cacheInfo.ModTime().After(origInfo.ModTime()) {
- return cachePath, nil
- }
- }
-
- // 2. Regenerate Content
- cacheMutex.Lock()
- defer cacheMutex.Unlock()
-
- if !TestMode {
- cacheInfo, errCache := os.Stat(cachePath)
- origInfo, errOrig := os.Stat(file.OriginalPath)
- if errCache == nil && errOrig == nil && cacheInfo.ModTime().After(origInfo.ModTime()) {
- return cachePath, nil
- }
- }
// Read Raw File
raw, err := ReadRaw(file.OriginalPath)
@@ -59,9 +43,9 @@ func GetContentPath(file ContentFile) (string, error) {
goldmark.WithExtensions(
extension.GFM,
&frontmatter.Extender{},
+ mathjax.MathJax,
templates.SidebarTag, // ||| ->