Adding post graph to terminal
This commit is contained in:
parent
d11393780d
commit
6bfac464fa
5 changed files with 239 additions and 12 deletions
139
assets/js/post-graph.js
Normal file
139
assets/js/post-graph.js
Normal file
|
|
@ -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);
|
||||
});
|
||||
})();
|
||||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -287,19 +287,61 @@
|
|||
<div>{{ partial "elements/crt-tv.html" . }}</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
{{ range first 1 (union (where .Site.RegularPages "Type" "updates") (where .Site.RegularPages "Type" "blog")).ByDate.Reverse }}
|
||||
<div id="latest-post">
|
||||
<div id="latest-post-link">{{ .Permalink }}</div>
|
||||
<div id="latest-post-title">
|
||||
{{ if eq .Type "blog" }}
|
||||
New blog post: {{ .Title }}
|
||||
{{ else }}
|
||||
{{ .Plain }}
|
||||
{{ if eq .Type "blog" }} New blog post: {{ .Title }} {{ else }} {{ .Plain }}
|
||||
{{ end }}
|
||||
</div>
|
||||
<div id="latest-post-date">{{ .Lastmod.Format "Jan 2, 2006" }}</div>
|
||||
</div>
|
||||
{{ end }}
|
||||
|
||||
<!-- GitHub-style posting graph -->
|
||||
<div class="posting-graph" style="display: none">
|
||||
<!-- Blog posts data as JSON -->
|
||||
<script id="blog-posts-data" type="application/json">
|
||||
{
|
||||
{{ $oneYearAgo := now.AddDate -1 0 0 }}
|
||||
{{ $allBlogPosts := where .Site.RegularPages "Type" "blog" }}
|
||||
{{ $recentBlogPosts := slice }}
|
||||
{{ range $allBlogPosts }}
|
||||
{{ if ge .Date.Unix $oneYearAgo.Unix }}
|
||||
{{ $recentBlogPosts = $recentBlogPosts | append . }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ $postsByDate := dict }}
|
||||
{{ range $recentBlogPosts }}
|
||||
{{ $dateKey := .Date.Format "2006-01-02" }}
|
||||
{{ $existing := index $postsByDate $dateKey }}
|
||||
{{ if $existing }}
|
||||
{{ $postsByDate = merge $postsByDate (dict $dateKey ($existing | append .)) }}
|
||||
{{ else }}
|
||||
{{ $postsByDate = merge $postsByDate (dict $dateKey (slice .)) }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ range $date, $posts := $postsByDate }}
|
||||
"{{ $date }}": [
|
||||
{{ range $index, $post := $posts }}
|
||||
{{ if $index }},{{ end }}
|
||||
{
|
||||
"title": {{ $post.Title | jsonify }},
|
||||
"url": "{{ $post.Permalink }}"
|
||||
}
|
||||
{{ end }}
|
||||
]{{ if ne $date (index (last 1 (slice ($postsByDate | collections.KeyVals))) 0).Key }},{{ end }}
|
||||
{{ end }}
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="post-graph-container">
|
||||
<div id="post-graph-info" class="post-graph-info">
|
||||
Hover over a day to see posts
|
||||
</div>
|
||||
<div id="weeks-container" class="weeks-container"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{ end }}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue