diff --git a/assets/js/post-graph.js b/assets/js/post-graph.js new file mode 100644 index 0000000..84f9d1b --- /dev/null +++ b/assets/js/post-graph.js @@ -0,0 +1,139 @@ +(function () { + // Parse the blog posts data + const postsData = JSON.parse( + document.getElementById("blog-posts-data").textContent, + ); + const weeksContainer = document.getElementById("weeks-container"); + const infoDiv = document.getElementById("post-graph-info"); + + // Calculate date range (365 days back from today) + const today = new Date(); + today.setHours(0, 0, 0, 0); + const startDate = new Date(today); + startDate.setDate(startDate.getDate() - 364); + + // Find the first Monday + let firstMonday = new Date(startDate); + const dayOfWeek = firstMonday.getDay(); + if (dayOfWeek === 0) { + firstMonday.setDate(firstMonday.getDate() + 1); + } else if (dayOfWeek > 1) { + firstMonday.setDate(firstMonday.getDate() + (8 - dayOfWeek)); + } + + // Generate all day blocks + let currentDate = new Date(firstMonday); + let currentWeek = []; + const weeks = []; + + while (currentDate <= today) { + const dateKey = currentDate.toISOString().split("T")[0]; + const posts = postsData[dateKey] || []; + const postCount = posts.length; + + let block = "░"; + let cssClass = ""; + if (postCount === 1) { + block = "▒"; + cssClass = "has-posts"; + } else if (postCount > 1) { + block = "▓"; + cssClass = "has-posts multiple-posts"; + } + + const postTitles = posts.map((p) => p.title).join(" | "); + const postUrl = posts.length > 0 ? posts[0].url : ""; + + currentWeek.push({ + block: block, + class: cssClass, + date: dateKey, + postCount: postCount, + postTitles: postTitles, + postUrl: postUrl, + posts: posts, + }); + + // Check if it's Sunday or the last day + const dow = currentDate.getDay(); + if (dow === 0) { + weeks.push([...currentWeek]); + currentWeek = []; + } + + currentDate.setDate(currentDate.getDate() + 1); + } + + // Add remaining days if any + if (currentWeek.length > 0) { + weeks.push(currentWeek); + } + + // Function to handle day hover + window.handleDayHover = function (element, isEnter) { + const date = element.dataset.date; + const postCount = parseInt(element.dataset.postCount || "0"); + const postTitles = element.dataset.postTitles; + const infoDiv = document.getElementById("post-graph-info"); + + if (isEnter) { + document + .querySelectorAll(".day-block") + .forEach((b) => b.classList.remove("active")); + + const d = new Date(date + "T00:00:00"); + const formattedDate = d.toLocaleDateString("en-GB", { + weekday: "short", + year: "numeric", + month: "short", + day: "numeric", + }); + + if (postCount > 0) { + element.classList.add("active"); + infoDiv.classList.add("active"); + infoDiv.textContent = `${formattedDate}: ${postTitles}`; + } else { + infoDiv.classList.remove("active"); + infoDiv.textContent = `${formattedDate}: No posts`; + } + } else { + element.classList.remove("active"); + infoDiv.classList.remove("active"); + infoDiv.textContent = "Hover over a day to see posts"; + } + }; + + // Function to handle day click + window.handleDayClick = function (element) { + const postUrl = element.dataset.postUrl; + if (postUrl) { + window.location.href = postUrl; + } + }; + + // Render the weeks + weeks.forEach((week) => { + const weekColumn = document.createElement("div"); + weekColumn.className = "week-column"; + + week.forEach((day) => { + const dayBlock = document.createElement("div"); + dayBlock.className = `day-block ${day.class}`; + dayBlock.dataset.date = day.date; + dayBlock.dataset.postCount = day.postCount; + dayBlock.dataset.postTitles = day.postTitles; + dayBlock.dataset.postUrl = day.postUrl; + dayBlock.setAttribute("onmouseenter", "handleDayHover(this, true)"); + dayBlock.setAttribute("onmouseleave", "handleDayHover(this, false)"); + if (day.postUrl) { + dayBlock.setAttribute("onclick", "handleDayClick(this)"); + } + dayBlock.textContent = day.block; + + weekColumn.appendChild(dayBlock); + }); + + weeksContainer.appendChild(weekColumn); + }); +})(); diff --git a/assets/js/terminal.js b/assets/js/terminal.js index c266fc9..0e494dc 100644 --- a/assets/js/terminal.js +++ b/assets/js/terminal.js @@ -35,19 +35,14 @@ class TerminalShell { "", "NERV OS v2.015 - MAGI System Interface", "Initializing A.T. Field protocols...", - "CASPER... ONLINE", - "BALTHASAR... ONLINE", - "MELCHIOR... ONLINE", + "CASPER: ONLINE / BALTHASAR: ONLINE / MELCHIOR: ONLINE", "Synchronization ratio: 41.3%... 67.8%... 89.2%... OK", "Loading Evangelion Unit-01 core drivers... OK", - "Mounting LCL interface... OK", "Neural connection established... OK", - "", "Running pattern analysis... PATTERN BLUE", "", "All systems optimal.", "", - "", ]; for (let i = 0; i < bootMessages.length; i++) { @@ -67,6 +62,12 @@ class TerminalShell { this.printHTML(" "); + let postGraph = document.getElementsByClassName("posting-graph")[0]; + this.printHTML("Retrieving post activity..."); + this.printHTML(" "); + this.printHTML(postGraph.innerHTML); + this.printHTML(" "); + // Get latest post info let latestPostTitle = document.getElementById("latest-post-title"); let latestPostDate = document.getElementById("latest-post-date"); diff --git a/assets/sass/pages/homepage.scss b/assets/sass/pages/homepage.scss index c46f51c..3040883 100644 --- a/assets/sass/pages/homepage.scss +++ b/assets/sass/pages/homepage.scss @@ -160,6 +160,49 @@ animation: text-glitch-cycle 3s ease infinite; } } + + .post-graph-container { + display: flex; + flex-direction: column; + gap: 10px; + } + .post-graph-info { + min-height: 2em; + color: #888; + font-size: 12px; + } + .post-graph-info.active { + color: #4caf50; + } + .weeks-container { + display: flex; + gap: 3px; + margin-left: 1em; + } + .week-column { + display: flex; + flex-direction: column; + gap: 4px; + } + .day-block { + display: flex; + align-items: center; + justify-content: center; + cursor: default; + position: relative; + color: #555; + user-select: none; + } + .day-block.has-posts { + color: #4caf50; + cursor: pointer; + } + .day-block.multiple-posts { + color: #2196f3; + } + .day-block.active { + background: rgba(76, 175, 80, 0.2); + } } .navigation { diff --git a/content/blog/2026-01-12-week-4-got-webmentions/index.md b/content/blog/2026-01-12-week-4-got-webmentions/index.md index 1cae573..694c011 100644 --- a/content/blog/2026-01-12-week-4-got-webmentions/index.md +++ b/content/blog/2026-01-12-week-4-got-webmentions/index.md @@ -14,7 +14,7 @@ draft: false - 🛜 Added an RSS feed for the blog. I've made my full posts available via RSS so you can consume them however you please. - 💏 Made some significant progress towards our plans for moving house, and life in general! - 🎁 Found some awesome little bits of tech and my wife kindly agreed to get them for my birthday next month, they will absolutely be showing up on the blog some time after that. -- 🧑‍💻 Wrote a script that can take a video with subtitles and a string of text, and return the gif of the clip. It'll be online shortly on GitHub and my resources section. +- 🧑‍💻 Wrote a script that can take a video with subtitles and a string of text, and return the gif of the clip. I wrote a blog post about it, and it's on my GitHub. ## Links I Found Interesting @@ -24,6 +24,8 @@ draft: false - [What I Have Learned Being on the IndieWeb for a Month](https://brennan.day/what-i-have-learned-being-on-the-indieweb-for-a-month/) - Brennan reviews what he has learnt from being on the IndieWeb for a month, and I definitely feel like I should post something similar very soon - I still have a few week or so! +- [Pocket TTS](https://kyutai.org/blog/2026-01-13-pocket-tts) - A tiny TTS application that can run locally. + ## Music - 📺 [Mortal Kombat x Rhythm is a Dancer](https://www.youtube.com/watch?v=vKxn6P947PE) diff --git a/layouts/index.html b/layouts/index.html index aa59789..ff1ffb7 100644 --- a/layouts/index.html +++ b/layouts/index.html @@ -287,19 +287,61 @@
{{ partial "elements/crt-tv.html" . }}
- {{ range first 1 (union (where .Site.RegularPages "Type" "updates") (where .Site.RegularPages "Type" "blog")).ByDate.Reverse }}
{{ .Permalink }}
- {{ if eq .Type "blog" }} - New blog post: {{ .Title }} - {{ else }} - {{ .Plain }} + {{ if eq .Type "blog" }} New blog post: {{ .Title }} {{ else }} {{ .Plain }} {{ end }}
{{ .Lastmod.Format "Jan 2, 2006" }}
{{ end }} + + + + {{ end }}