From 41a6d16ef6a356bc286b0eafe267d04aeed174f3 Mon Sep 17 00:00:00 2001 From: delta Date: Mon, 3 Feb 2025 22:58:46 +0100 Subject: initial commit --- assets/css/404.css | 13 +++ assets/css/index.css | 198 +++++++++++++++++++++++++++++++++ assets/css/posts.css | 7 ++ assets/css/reset.css | 48 ++++++++ assets/icons/apple-touch-icon.png | Bin 0 -> 4938 bytes assets/icons/favicon-16x16.png | Bin 0 -> 347 bytes assets/icons/favicon-32x32.png | Bin 0 -> 675 bytes assets/js/live.js | 225 ++++++++++++++++++++++++++++++++++++++ assets/js/main.js | 41 +++++++ 9 files changed, 532 insertions(+) create mode 100644 assets/css/404.css create mode 100644 assets/css/index.css create mode 100644 assets/css/posts.css create mode 100644 assets/css/reset.css create mode 100644 assets/icons/apple-touch-icon.png create mode 100644 assets/icons/favicon-16x16.png create mode 100644 assets/icons/favicon-32x32.png create mode 100644 assets/js/live.js create mode 100644 assets/js/main.js (limited to 'assets') diff --git a/assets/css/404.css b/assets/css/404.css new file mode 100644 index 0000000..b75ef00 --- /dev/null +++ b/assets/css/404.css @@ -0,0 +1,13 @@ +main { + display: flex; + align-items: center; + justify-content: center; +} + +main > div { + text-align: center; +} + +main > div > div { + color: var(--fg-low); +} diff --git a/assets/css/index.css b/assets/css/index.css new file mode 100644 index 0000000..9f9ce62 --- /dev/null +++ b/assets/css/index.css @@ -0,0 +1,198 @@ +:root { + --font: "Iosevka Comfy Duo"; + + --fg-low: oklch(70% 0.01368 253.09); + --fg: oklch(80% 0.01368 253.09); + --fg-high: oklch(90% 0.01368 253.09); + + --bg-lowest: oklch(15% 0.01368 253.09); + --bg-low: oklch(17.5% 0.01368 253.09); + --bg: oklch(20% 0.01368 253.09); + --bg-high: oklch(22.5% 0.01368 253.09); + --bg-highest: oklch(25% 0.01368 253.09); + + --border: oklch(35% 0.023 253.09); + --border-variant: oklch(30% 0.023 253.09); + + --red: oklch(80% 0.15765 24.728); + --red-bright: oklch(90% 0.15765 24.728); + --orange: oklch(80% 0.139 45.216); + --orange-bright: oklch(90% 0.139 45.216); + --yellow: oklch(80% 0.12758 76.402); + --yellow-bright: oklch(90% 0.12758 76.402); + --green: oklch(80% 0.11211 147.63); + --green-bright: oklch(90% 0.11211 147.63); + --cyan: oklch(80% 0.09919 181.49); + --cyan-bright: oklch(90% 0.09919 181.49); + --blue: oklch(80% 0.09994 249.58); + --blue-bright: oklch(90% 0.09994 249.58); + --purple: oklch(80% 0.09923 296.61); + --purple-bright: oklch(90% 0.09923 296.61); + --pink: oklch(80% 0.06662 9.2146); + --pink-bright: oklch(90% 0.06662 9.2146); + + --border-radius: 5px; + --border-width: 2px; + --padding: 5px; + --padding-big: 10px; +} + +body { + font-family: "Iosevka Comfy Duo"; + background-color: var(--bg); + color: var(--fg); + display: flex; + gap: var(--padding-big); + min-height: 100vh; + padding: var(--padding-big); + box-sizing: border-box; + position: relative; +} + +#lower { + --bar-size: 0.3em; + position: absolute; + z-index: -1; + bottom: 0; + right: 0; + aspect-ratio: 1 / 1; + height: calc(var(--bar-size) * 14); /* magic number */ + background-image: linear-gradient( + -45deg, + transparent, + transparent var(--bar-size), + var(--blue) var(--bar-size), + var(--blue) calc(var(--bar-size) * 2), + transparent calc(var(--bar-size) * 2), + transparent calc(var(--bar-size) * 3), + var(--green) calc(var(--bar-size) * 3), + var(--green) calc(var(--bar-size) * 4), + transparent calc(var(--bar-size) * 4), + transparent calc(var(--bar-size) * 5), + var(--yellow) calc(var(--bar-size) * 5), + var(--yellow) calc(var(--bar-size) * 6), + transparent calc(var(--bar-size) * 6), + transparent calc(var(--bar-size) * 7), + var(--orange) calc(var(--bar-size) * 7), + var(--orange) calc(var(--bar-size) * 8), + transparent calc(var(--bar-size) * 8), + transparent calc(var(--bar-size) * 9), + var(--red) calc(var(--bar-size) * 9), + var(--red) calc(var(--bar-size) * 10), + transparent calc(var(--bar-size) * 10) + ); +} + +/* + * failsafe for when the viewport is too small and the rainbow overlaps the text + */ +main > div, +footer > span { + background-color: var(--bg); +} + +#upper { + display: flex; + flex-direction: column; + flex-grow: 1; +} + +#upper > div { + flex-grow: 1; + display: flex; + flex-direction: column; + gap: var(--padding-big); + align-items: center; +} + +.subtle { + color: var(--fg-low); +} + +main { + flex-grow: 1; + width: 80vw; + line-height: 1.5; +} + +nav > ul { + display: flex; +} + +main, +nav { + padding: var(--padding-big); +} + +nav li:not(:last-of-type)::after, +footer > span:not(:last-of-type)::after { + content: "|"; + margin-left: var(--padding); + margin-right: var(--padding); + color: var(--border); +} + +footer { + text-align: center; + padding: var(--padding); + font-size: 0.8em; +} + +a, +a:link { + color: var(--yellow); +} + +a:visited { + color: var(--pink); +} + +a:focus, +a:hover { + color: var(--yellow-bright); +} + +a:active { + color: var(--yellow); +} + +h1 { + font-size: 1.5em; + margin-bottom: calc(var(--padding-big) * 2); +} + +h2 { + font-size: 1.25em; + margin-bottom: calc(var(--padding-big) * 1.5); +} + +p:not(:last-of-type) { + margin-bottom: var(--padding-big); +} + +main li { + margin-left: var(--padding-big); + list-style-type: "- "; + list-style-position: inside; +} + +main li::marker { + color: var(--border); +} + +main ol, +main ul { + padding-top: var(--padding); + gap: var(--padding); + display: flex; + flex-direction: column; +} + +main ol:not(:last-child), +main ul:not(:last-child) { + margin-bottom: var(--padding-big); +} + +strong { + font-weight: bold; +} diff --git a/assets/css/posts.css b/assets/css/posts.css new file mode 100644 index 0000000..50ca347 --- /dev/null +++ b/assets/css/posts.css @@ -0,0 +1,7 @@ +.list > li { + margin-left: 0; +} + +.list > li > span { + float: right; +} diff --git a/assets/css/reset.css b/assets/css/reset.css new file mode 100644 index 0000000..e29c0f5 --- /dev/null +++ b/assets/css/reset.css @@ -0,0 +1,48 @@ +/* http://meyerweb.com/eric/tools/css/reset/ + v2.0 | 20110126 + License: none (public domain) +*/ + +html, body, div, span, applet, object, iframe, +h1, h2, h3, h4, h5, h6, p, blockquote, pre, +a, abbr, acronym, address, big, cite, code, +del, dfn, em, img, ins, kbd, q, s, samp, +small, strike, strong, sub, sup, tt, var, +b, u, i, center, +dl, dt, dd, ol, ul, li, +fieldset, form, label, legend, +table, caption, tbody, tfoot, thead, tr, th, td, +article, aside, canvas, details, embed, +figure, figcaption, footer, header, hgroup, +menu, nav, output, ruby, section, summary, +time, mark, audio, video { + margin: 0; + padding: 0; + border: 0; + font-size: 100%; + font: inherit; + vertical-align: baseline; +} +/* HTML5 display-role reset for older browsers */ +article, aside, details, figcaption, figure, +footer, header, hgroup, menu, nav, section { + display: block; +} +body { + line-height: 1; +} +ol, ul { + list-style: none; +} +blockquote, q { + quotes: none; +} +blockquote:before, blockquote:after, +q:before, q:after { + content: ''; + content: none; +} +table { + border-collapse: collapse; + border-spacing: 0; +} diff --git a/assets/icons/apple-touch-icon.png b/assets/icons/apple-touch-icon.png new file mode 100644 index 0000000..bfdf6cc Binary files /dev/null and b/assets/icons/apple-touch-icon.png differ diff --git a/assets/icons/favicon-16x16.png b/assets/icons/favicon-16x16.png new file mode 100644 index 0000000..adba0ac Binary files /dev/null and b/assets/icons/favicon-16x16.png differ diff --git a/assets/icons/favicon-32x32.png b/assets/icons/favicon-32x32.png new file mode 100644 index 0000000..af10188 Binary files /dev/null and b/assets/icons/favicon-32x32.png differ diff --git a/assets/js/live.js b/assets/js/live.js new file mode 100644 index 0000000..a015d05 --- /dev/null +++ b/assets/js/live.js @@ -0,0 +1,225 @@ +/* + Live.js - One script closer to Designing in the Browser + Written for Handcraft.com by Martin Kool (@mrtnkl). + + Version 4. + Recent change: Made stylesheet and mimetype checks case insensitive. + + http://livejs.com + http://livejs.com/license (MIT) + @livejs + + Include live.js#css to monitor css changes only. + Include live.js#js to monitor js changes only. + Include live.js#html to monitor html changes only. + Mix and match to monitor a preferred combination such as live.js#html,css + + By default, just include live.js to monitor all css, js and html changes. + + Live.js can also be loaded as a bookmarklet. It is best to only use it for CSS then, + as a page reload due to a change in html or css would not re-include the bookmarklet. + To monitor CSS and be notified that it has loaded, include it as: live.js#css,notify +*/ +(function () { + var headers = { Etag: 1, "Last-Modified": 1, "Content-Length": 1, "Content-Type": 1 }, + resources = {}, + pendingRequests = {}, + currentLinkElements = {}, + oldLinkElements = {}, + interval = 1000, + loaded = false, + active = { html: 1, css: 1, js: 1 }; + + var Live = { + // performs a cycle per interval + heartbeat: function () { + if (document.body) { + // make sure all resources are loaded on first activation + if (!loaded) Live.loadresources(); + Live.checkForChanges(); + } + setTimeout(Live.heartbeat, interval); + }, + + // loads all local css and js resources upon first activation + loadresources: function () { + // helper method to assert if a given url is local + function isLocal(url) { + var loc = document.location, + reg = new RegExp("^\\.|^\/(?!\/)|^[\\w]((?!://).)*$|" + loc.protocol + "//" + loc.host); + return url.match(reg); + } + + // gather all resources + var scripts = document.getElementsByTagName("script"), + links = document.getElementsByTagName("link"), + uris = []; + + // track local js urls + for (var i = 0; i < scripts.length; i++) { + var script = scripts[i], + src = script.getAttribute("src"); + if (src && isLocal(src)) uris.push(src); + if (src && src.match(/\blive.js#/)) { + for (var type in active) active[type] = src.match("[#,|]" + type) != null; + if (src.match("notify")) alert("Live.js is loaded."); + } + } + if (!active.js) uris = []; + if (active.html) uris.push(document.location.href); + + // track local css urls + for (var i = 0; i < links.length && active.css; i++) { + var link = links[i], + rel = link.getAttribute("rel"), + href = link.getAttribute("href", 2); + if (href && rel && rel.match(new RegExp("stylesheet", "i")) && isLocal(href)) { + uris.push(href); + currentLinkElements[href] = link; + } + } + + // initialize the resources info + for (var i = 0; i < uris.length; i++) { + var url = uris[i]; + Live.getHead(url, function (url, info) { + resources[url] = info; + }); + } + + // add rule for morphing between old and new css files + var head = document.getElementsByTagName("head")[0], + style = document.createElement("style"), + rule = "transition: all .3s ease-out;"; + css = [".livejs-loading * { ", rule, " -webkit-", rule, "-moz-", rule, "-o-", rule, "}"].join(""); + style.setAttribute("type", "text/css"); + head.appendChild(style); + style.styleSheet ? (style.styleSheet.cssText = css) : style.appendChild(document.createTextNode(css)); + + // yep + loaded = true; + }, + + // check all tracking resources for changes + checkForChanges: function () { + for (var url in resources) { + if (pendingRequests[url]) continue; + + Live.getHead(url, function (url, newInfo) { + var oldInfo = resources[url], + hasChanged = false; + resources[url] = newInfo; + for (var header in oldInfo) { + // do verification based on the header type + var oldValue = oldInfo[header], + newValue = newInfo[header], + contentType = newInfo["Content-Type"]; + switch (header.toLowerCase()) { + case "etag": + if (!newValue) break; + // fall through to default + default: + hasChanged = oldValue != newValue; + break; + } + // if changed, act + if (hasChanged) { + Live.refreshResource(url, contentType); + break; + } + } + }); + } + }, + + // act upon a changed url of certain content type + refreshResource: function (url, type) { + switch (type.toLowerCase()) { + // css files can be reloaded dynamically by replacing the link element + case "text/css": + var link = currentLinkElements[url], + html = document.body.parentNode, + head = link.parentNode, + next = link.nextSibling, + newLink = document.createElement("link"); + + html.className = html.className.replace(/\s*livejs\-loading/gi, "") + " livejs-loading"; + newLink.setAttribute("type", "text/css"); + newLink.setAttribute("rel", "stylesheet"); + newLink.setAttribute("href", url + "?now=" + new Date() * 1); + next ? head.insertBefore(newLink, next) : head.appendChild(newLink); + currentLinkElements[url] = newLink; + oldLinkElements[url] = link; + + // schedule removal of the old link + Live.removeoldLinkElements(); + break; + + // check if an html resource is our current url, then reload + case "text/html": + if (url != document.location.href) return; + + // local javascript changes cause a reload as well + case "text/javascript": + case "application/javascript": + case "application/x-javascript": + document.location.reload(); + } + }, + + // removes the old stylesheet rules only once the new one has finished loading + removeoldLinkElements: function () { + var pending = 0; + for (var url in oldLinkElements) { + // if this sheet has any cssRules, delete the old link + try { + var link = currentLinkElements[url], + oldLink = oldLinkElements[url], + html = document.body.parentNode, + sheet = link.sheet || link.styleSheet, + rules = sheet.rules || sheet.cssRules; + if (rules.length >= 0) { + oldLink.parentNode.removeChild(oldLink); + delete oldLinkElements[url]; + setTimeout(function () { + html.className = html.className.replace(/\s*livejs\-loading/gi, ""); + }, 100); + } + } catch (e) { + pending++; + } + if (pending) setTimeout(Live.removeoldLinkElements, 50); + } + }, + + // performs a HEAD request and passes the header info to the given callback + getHead: function (url, callback) { + pendingRequests[url] = true; + var xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XmlHttp"); + xhr.open("HEAD", url, true); + xhr.onreadystatechange = function () { + delete pendingRequests[url]; + if (xhr.readyState == 4 && xhr.status != 304) { + xhr.getAllResponseHeaders(); + var info = {}; + for (var h in headers) { + var value = xhr.getResponseHeader(h); + // adjust the simple Etag variant to match on its significant part + if (h.toLowerCase() == "etag" && value) value = value.replace(/^W\//, ""); + if (h.toLowerCase() == "content-type" && value) value = value.replace(/^(.*?);.*?$/i, "$1"); + info[h] = value; + } + callback(url, info); + } + }; + xhr.send(); + }, + }; + + // start listening + if (document.location.protocol != "file:") { + if (!window.liveJsLoaded) Live.heartbeat(); + + window.liveJsLoaded = true; + } else if (window.console) console.log("Live.js doesn't support the file protocol. It needs http."); +})(); diff --git a/assets/js/main.js b/assets/js/main.js new file mode 100644 index 0000000..5bc2d41 --- /dev/null +++ b/assets/js/main.js @@ -0,0 +1,41 @@ +// Toggle the navigation menu and theme +document.addEventListener("DOMContentLoaded", function () { + var menuToggle = document.getElementById("menu-toggle"); + var mainNav = document.getElementById("main-nav"); + var themeToggle = document.getElementById("theme-toggle"); + var body = document.body; + + // Menu toggle functionality + menuToggle.addEventListener("click", function () { + mainNav.classList.toggle("open"); + }); + + // Theme toggle functionality + themeToggle.addEventListener("click", function () { + // Toggle between 'light' and 'dark' themes + var currentTheme = body.getAttribute("data-theme") || "light"; + var newTheme = currentTheme === "dark" ? "light" : "dark"; + body.setAttribute("data-theme", newTheme); + localStorage.setItem("theme", newTheme); + }); + + // On page load, set the theme from localStorage or system preference + var storedTheme = localStorage.getItem("theme"); + if (storedTheme) { + body.setAttribute("data-theme", storedTheme); + } else { + // Detect system preference + var prefersDarkScheme = window.matchMedia("(prefers-color-scheme: dark)").matches; + var defaultTheme = prefersDarkScheme ? "dark" : "light"; + body.setAttribute("data-theme", defaultTheme); + } + + // Listen for changes in the system color scheme + window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", function (e) { + var storedTheme = localStorage.getItem("theme"); + if (!storedTheme) { + var newColorScheme = e.matches ? "dark" : "light"; + body.setAttribute("data-theme", newColorScheme); + } + }); +}); -- cgit v1.2.3