first commit
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
// Load and display all blog posts
|
||||
async function loadBlogPosts() {
|
||||
try {
|
||||
const response = await fetch('blog-posts.json');
|
||||
const posts = await response.json();
|
||||
const container = document.getElementById("blogPostsContainer");
|
||||
|
||||
// Sort posts by date (newest first)
|
||||
const sortedPosts = posts.sort((a, b) => new Date(b.date) - new Date(a.date));
|
||||
|
||||
sortedPosts.forEach(post => {
|
||||
const postElement = document.createElement('div');
|
||||
postElement.className = 'blog-post';
|
||||
postElement.id = `post-${post.id}`;
|
||||
|
||||
// Convert content newlines to paragraphs
|
||||
const contentParagraphs = post.content.split('\n\n').filter(p => p.trim().length > 0);
|
||||
const formattedContent = contentParagraphs.map(p => `<p>${p.trim()}</p>`).join('');
|
||||
|
||||
postElement.innerHTML = `
|
||||
<h2 class="blog-post-title">${post.title}</h2>
|
||||
<p class="blog-post-date">${post.date}</p>
|
||||
<p class="blog-post-excerpt">${post.excerpt}</p>
|
||||
<div class="blog-post-content">${formattedContent}</div>
|
||||
<p class="blog-post-signature">-- Author --</p>
|
||||
`;
|
||||
|
||||
container.appendChild(postElement);
|
||||
});
|
||||
|
||||
// Scroll to post if hash is present
|
||||
if (window.location.hash) {
|
||||
setTimeout(() => {
|
||||
const targetPost = document.querySelector(window.location.hash);
|
||||
if (targetPost) {
|
||||
targetPost.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
||||
}
|
||||
}, 100);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error loading blog posts:', error);
|
||||
document.getElementById("blogPostsContainer").innerHTML =
|
||||
'<p class="error">Error loading blog posts. Please try again later.</p>';
|
||||
}
|
||||
}
|
||||
|
||||
// Load posts when page loads
|
||||
window.addEventListener('load', loadBlogPosts);
|
||||
@@ -0,0 +1,138 @@
|
||||
// Error messages with time-of-day awareness
|
||||
// Each error code has multiple witty messages that rotate randomly
|
||||
|
||||
function getErrorMessage(errorCode) {
|
||||
const today = new Date();
|
||||
// Your timezone, your problem - we just read what your browser tells us
|
||||
const hours = today.getHours();
|
||||
|
||||
const timeContext = hours < 6 ? 'late' : hours < 12 ? 'morning' : hours < 18 ? 'afternoon' : 'evening';
|
||||
|
||||
const messages = {
|
||||
400: [
|
||||
"Bad Request? More like bad judgment. What were you even thinking?",
|
||||
"Your browser sent something that made the server question its life choices.",
|
||||
"Syntax error: human detected. Please reformat your existence.",
|
||||
"The server tried to parse your request. It failed. Miserably.",
|
||||
"This isn't a buffet. You can't just order whatever you want.",
|
||||
"Your request was so malformed, it gave the parser an existential crisis.",
|
||||
"Bad request? That's putting it mildly. The server is offended.",
|
||||
"The server politely declined your request. It's not you, it's... actually, it is you."
|
||||
],
|
||||
401: [
|
||||
"Unauthorized. You shall not pass. Unless you have the password.",
|
||||
"Access denied. This area requires more credentials than a spy movie.",
|
||||
"You need authentication. This isn't a BYOB party.",
|
||||
"Unauthorized access attempt. The server is judging you right now.",
|
||||
"Credentials required. No, 'password123' doesn't count.",
|
||||
"Authentication failed. Try harder. Or don't. The server doesn't care.",
|
||||
"Access denied. Even the server has standards.",
|
||||
"You're not authorized. The bouncer said no."
|
||||
],
|
||||
403: [
|
||||
"Forbidden. This isn't the page you're looking for. Move along.",
|
||||
"Access forbidden. The server has trust issues. Can you blame it?",
|
||||
"Permission denied. The server said 'absolutely not' in seventeen languages.",
|
||||
"Forbidden territory. Even VPNs can't save you now.",
|
||||
"This area is off-limits. The server drew a line. You crossed it.",
|
||||
"Access forbidden. The server is protecting you from yourself.",
|
||||
"Permission denied. The server would rather die than show you this.",
|
||||
"Forbidden. This page has restraining orders against browsers like yours.",
|
||||
"Access denied. The server is gatekeeping. Deal with it.",
|
||||
"This content is forbidden. The server has standards, unlike some people."
|
||||
],
|
||||
404: [
|
||||
"Page not found. It's gone. Vanished. Poof. Like my motivation on Monday.",
|
||||
"The page you seek does not exist in this dimension. Try another reality.",
|
||||
"This page doesn't exist. Neither do my regrets about creating this message.",
|
||||
"The server searched everywhere. Even checked under the couch.",
|
||||
"Page not found. It left. Said it needed to find itself. We're all very supportive.",
|
||||
"The page you're looking for has achieved enlightenment and transcended the web.",
|
||||
"This page doesn't exist. It's not you, it's me. Actually, it's definitely you.",
|
||||
"The server even checked the last place you'd look. Still nothing.",
|
||||
"Page not found. It's in witness protection. The server knows where it is but won't tell.",
|
||||
"The page escaped. Last seen heading toward the exit. We're not chasing it.",
|
||||
"This page doesn't exist. The server looked twice. Still gone. Accept it.",
|
||||
"The page ran away to join the circus. Good for it."
|
||||
],
|
||||
405: [
|
||||
"Method not allowed. The server rejected your approach. Try a different strategy.",
|
||||
"HTTP method denied. The server is picky about how you ask questions.",
|
||||
"Method not allowed. The server prefers a more elegant approach.",
|
||||
"This method isn't allowed here. The server has strict rules about manners.",
|
||||
"Method rejected. The server wants you to ask nicely next time.",
|
||||
"HTTP method not allowed. The server is traditional. Write a letter instead."
|
||||
],
|
||||
408: [
|
||||
"Request timeout. You took too long. The server has moved on with its life.",
|
||||
"Timeout. The server waited. And waited. And got tired of waiting.",
|
||||
"Request timeout. The server gave up. You should probably do the same.",
|
||||
"Too slow. The server timed out waiting for you to make up your mind.",
|
||||
"Request timeout. The server has better things to do than wait for your request.",
|
||||
"Timeout. The server lost interest. Can you blame it?"
|
||||
],
|
||||
429: [
|
||||
"Slow down, turbo. The server isn't impressed by your enthusiasm.",
|
||||
"Rate limit exceeded. You've been greedy. The server noticed.",
|
||||
"The server is overwhelmed. By you. Specifically.",
|
||||
"Rate limit. You're making too many requests. The server needs a break from you.",
|
||||
"The server is putting you in timeout. Think about what you've done.",
|
||||
"Rate limit exceeded. The server is judging your lack of patience.",
|
||||
"Slow down. You're making too many requests. The server has trust issues now.",
|
||||
"Rate limit exceeded. The server says 'no more'. It's not negotiable."
|
||||
],
|
||||
500: [
|
||||
"We may or may not have broken something. Oops.",
|
||||
"Something went wrong. We're pretending it's not our fault.",
|
||||
"The server had a moment. It happens. Usually on Fridays.",
|
||||
"The hamsters powering the server need a coffee break.",
|
||||
"Something broke. The server is working on it. Or sleeping. Hard to tell.",
|
||||
"The server made a mistake. We're all human. Well, the server isn't, but you know.",
|
||||
"The server tried its best. Its best wasn't good enough today.",
|
||||
"Something crashed. Probably our hopes and dreams.",
|
||||
"The server is having an existential crisis. Give it a moment.",
|
||||
"The server regrets to inform you that it regrets.",
|
||||
"Something went wrong. The server is embarrassed. Please look away.",
|
||||
"The server encountered an error while encountering an error. Meta."
|
||||
],
|
||||
502: [
|
||||
"The upstream server is having a bad day. Join the club.",
|
||||
"The server talked to another server. They're not speaking anymore.",
|
||||
"The server reached out for help. The other server hung up.",
|
||||
"The gateway is bad. The server would elaborate, but it's bad at explaining things.",
|
||||
"The upstream server said 'no'. We're respecting its boundaries.",
|
||||
"Two servers walked into a bar. Neither ordered anything useful.",
|
||||
"The server called for backup. Backup didn't answer.",
|
||||
"Communication failed between servers. Relationship status: it's complicated."
|
||||
],
|
||||
503: [
|
||||
"The server is currently unavailable. Try again later. Or don't. Your choice.",
|
||||
"The server is taking a mental health day.",
|
||||
"The server is out of the office. It left a note. We can't read it.",
|
||||
"The service is down. The server is using this time to reflect on its choices.",
|
||||
"The server is temporarily unavailable. Permanently temporary.",
|
||||
"The service is taking a break. Self-care is important, even for servers.",
|
||||
"The server is busy. It's busy being unavailable.",
|
||||
"The service is down for maintenance. Or questioning its purpose. Same thing."
|
||||
],
|
||||
504: [
|
||||
"The server waited too long. It's done waiting.",
|
||||
"The gateway timed out waiting for another server. Patience isn't infinite.",
|
||||
"The server waited patiently. Then impatiently. Then gave up.",
|
||||
"The gateway is having commitment issues. It won't wait forever.",
|
||||
"The other server took too long. This server has places to be.",
|
||||
"The gateway waited. And waited. Now it's leaving.",
|
||||
"The server's patience expired before your request did.",
|
||||
"Time's up. The gateway moved on. You should too."
|
||||
]
|
||||
};
|
||||
|
||||
const errorMessages = messages[errorCode] || [
|
||||
`Error ${errorCode}. Something went wrong. The server is confused, and honestly, so are we.`
|
||||
];
|
||||
|
||||
// Randomly select a message
|
||||
const randomIndex = Math.floor(Math.random() * errorMessages.length);
|
||||
return errorMessages[randomIndex];
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
// Error page script - loads error messages and updates the page
|
||||
(function() {
|
||||
const errorCode = parseInt(document.body.getAttribute('data-error-code') || '404', 10);
|
||||
|
||||
const script = document.createElement('script');
|
||||
script.src = 'error-messages.js';
|
||||
script.onload = function() {
|
||||
const messageElement = document.getElementById('errorMessage');
|
||||
if (messageElement && typeof getErrorMessage === 'function') {
|
||||
messageElement.textContent = getErrorMessage(errorCode);
|
||||
} else if (messageElement) {
|
||||
// Fallback messages
|
||||
const fallbacks = {
|
||||
403: "Forbidden. This isn't the page you're looking for. Move along.",
|
||||
404: "Page not found. It's gone. Vanished. Poof. Like my motivation on Monday.",
|
||||
500: "Internal server error. We broke something. Oops."
|
||||
};
|
||||
messageElement.textContent = fallbacks[errorCode] || "Something went wrong.";
|
||||
}
|
||||
};
|
||||
script.onerror = function() {
|
||||
const messageElement = document.getElementById('errorMessage');
|
||||
if (messageElement) {
|
||||
const fallbacks = {
|
||||
403: "Forbidden. This isn't the page you're looking for. Move along.",
|
||||
404: "Page not found. It's gone. Vanished. Poof. Like my motivation on Monday.",
|
||||
500: "Internal server error. We broke something. Oops."
|
||||
};
|
||||
messageElement.textContent = fallbacks[errorCode] || "Something went wrong.";
|
||||
}
|
||||
};
|
||||
document.head.appendChild(script);
|
||||
})();
|
||||
@@ -0,0 +1,99 @@
|
||||
// Figure out what time-based lie to tell visitors about their life choices
|
||||
const determineGreet = hours => {
|
||||
document.getElementById("greeting").innerText = `It's ${hours < 12 ? "Morning and Currently" : hours < 18 ? "Afternoon and Currently" : "Evening and Currently"}`;
|
||||
};
|
||||
|
||||
// Show the relentless march of time
|
||||
function displayTime(time) {
|
||||
document.getElementById("time").innerHTML = time;
|
||||
}
|
||||
|
||||
// Passive-aggressively suggest blog reading at 2-hour intervals (we're persistent, not pushy)
|
||||
const determineBlogMessage = hours => {
|
||||
let message;
|
||||
|
||||
if (hours >= 0 && hours < 2) {
|
||||
message = "Late night reading? Check out my <a href='blog/index.html' class='blog-link'>Blog</a>";
|
||||
} else if (hours >= 2 && hours < 4) {
|
||||
message = "Insomniac hours? Peruse my <a href='blog/index.html' class='blog-link'>Blog</a>";
|
||||
} else if (hours >= 4 && hours < 6) {
|
||||
message = "Early bird? Catch up on my <a href='blog/index.html' class='blog-link'>Blog</a>";
|
||||
} else if (hours >= 6 && hours < 8) {
|
||||
message = "Coffee and a <a href='blog/index.html' class='blog-link'>Blog</a>?";
|
||||
} else if (hours >= 8 && hours < 10) {
|
||||
message = "Morning routine? Add my <a href='blog/index.html' class='blog-link'>Blog</a> to it";
|
||||
} else if (hours >= 10 && hours < 12) {
|
||||
message = "Mid-morning break? Read my <a href='blog/index.html' class='blog-link'>Blog</a>";
|
||||
} else if (hours >= 12 && hours < 14) {
|
||||
message = "Lunch break? Browse my <a href='blog/index.html' class='blog-link'>Blog</a>";
|
||||
} else if (hours >= 14 && hours < 16) {
|
||||
message = "Afternoon slump? Perk up with my <a href='blog/index.html' class='blog-link'>Blog</a>";
|
||||
} else if (hours >= 16 && hours < 18) {
|
||||
message = "It's a good time to read my <a href='blog/index.html' class='blog-link'>Blog</a>";
|
||||
} else if (hours >= 18 && hours < 20) {
|
||||
message = "Get comfy and read my <a href='blog/index.html' class='blog-link'>Blog</a>";
|
||||
} else if (hours >= 20 && hours < 22) {
|
||||
message = "Wind down with my <a href='blog/index.html' class='blog-link'>Blog</a>";
|
||||
} else {
|
||||
message = "Nightcap? End your day with my <a href='blog/index.html' class='blog-link'>Blog</a>";
|
||||
}
|
||||
document.getElementById("blogMessage").innerHTML = message;
|
||||
};
|
||||
|
||||
|
||||
// Tick tock, tick tock - time marches on regardless of your location
|
||||
setInterval(function () {
|
||||
const today = new Date();
|
||||
const time = today.toLocaleTimeString('en-US', {
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
hour12: false
|
||||
});
|
||||
displayTime(time);
|
||||
}, 1000);
|
||||
|
||||
// Fetch the freshest posts to lure readers into the content trap
|
||||
async function loadRecentPosts() {
|
||||
try {
|
||||
const response = await fetch('blog/api/posts.php');
|
||||
const posts = await response.json();
|
||||
const recentPostsContainer = document.getElementById("recentPosts");
|
||||
|
||||
// Only the top 3 - we're not monsters showing everything at once
|
||||
const recentPosts = posts.slice(0, 3);
|
||||
|
||||
recentPosts.forEach(post => {
|
||||
const postLink = document.createElement('a');
|
||||
postLink.href = `blog/post.html?id=${post.id}`;
|
||||
postLink.textContent = `${post.date} - ${post.title}`;
|
||||
recentPostsContainer.appendChild(postLink);
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error loading blog posts:', error);
|
||||
// Silence is golden when things break
|
||||
}
|
||||
}
|
||||
|
||||
// Boot up the whole circus when the page loads
|
||||
window.addEventListener('load', (event) => {
|
||||
const today = new Date();
|
||||
const time = today.toLocaleTimeString('en-US', {
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
hour12: false
|
||||
});
|
||||
// Your timezone, your problem - we just display what your browser tells us
|
||||
const localHours = today.getHours();
|
||||
determineGreet(localHours);
|
||||
determineBlogMessage(localHours);
|
||||
displayTime(time);
|
||||
loadRecentPosts();
|
||||
// updateWeather(); // Weather is overrated anyway
|
||||
});
|
||||
|
||||
// Keep harassing visitors about the blog every 60 seconds
|
||||
setInterval(function () {
|
||||
const today = new Date();
|
||||
const localHours = today.getHours();
|
||||
determineBlogMessage(localHours);
|
||||
}, 60000);
|
||||
@@ -0,0 +1,7 @@
|
||||
// Apply theme immediately to prevent flash
|
||||
(function() {
|
||||
const theme = localStorage.getItem('theme') ||
|
||||
(window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light');
|
||||
document.documentElement.setAttribute('data-theme', theme);
|
||||
})();
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
// Theme system - helping visitors avoid retinal damage since 2024
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
const html = document.documentElement;
|
||||
|
||||
function getStoredTheme() {
|
||||
// Check everywhere for theme preferences - we're thorough like that
|
||||
if (typeof localStorage !== 'undefined') {
|
||||
const stored = localStorage.getItem('theme');
|
||||
if (stored === 'dark' || stored === 'light') {
|
||||
return stored;
|
||||
}
|
||||
}
|
||||
|
||||
const cookies = document.cookie.split(';');
|
||||
for (let cookie of cookies) {
|
||||
const [name, value] = cookie.trim().split('=');
|
||||
if (name === 'simple_style' && (value === 'dark' || value === 'light')) {
|
||||
return value;
|
||||
}
|
||||
if (name === 'theme' && (value === 'dark' || value === 'light')) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
// When in doubt, trust the OS (they know what they're doing... probably)
|
||||
if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
|
||||
return 'dark';
|
||||
}
|
||||
return 'light';
|
||||
}
|
||||
|
||||
function setThemeEverywhere(theme) {
|
||||
// Scatter theme preferences like seeds in the wind - something's gotta stick
|
||||
const cookieOptions = `path=/; max-age=${60 * 60 * 24 * 365 * 5}; SameSite=Lax`;
|
||||
|
||||
// localStorage for the modern folks
|
||||
if (typeof localStorage !== 'undefined') {
|
||||
localStorage.setItem('theme', theme);
|
||||
}
|
||||
|
||||
// Cookies for SearXNG (it's picky about naming conventions)
|
||||
document.cookie = `simple_style=${theme}; ${cookieOptions}`;
|
||||
|
||||
// More cookies - redundancy is our middle name
|
||||
document.cookie = `theme=${theme}; ${cookieOptions}`;
|
||||
|
||||
// Data attribute for immediate gratification
|
||||
html.setAttribute('data-theme', theme);
|
||||
|
||||
// Don't forget the icon - visual feedback matters
|
||||
updateToggleIcon(theme);
|
||||
}
|
||||
|
||||
function getTheme() {
|
||||
return getStoredTheme();
|
||||
}
|
||||
|
||||
function setTheme(theme) {
|
||||
setThemeEverywhere(theme);
|
||||
}
|
||||
|
||||
function updateToggleIcon(theme) {
|
||||
const themeToggle = document.getElementById('themeToggle');
|
||||
if (themeToggle) {
|
||||
const moonIcon = themeToggle.querySelector('.theme-icon-moon');
|
||||
const sunIcon = themeToggle.querySelector('.theme-icon-sun');
|
||||
if (moonIcon && sunIcon) {
|
||||
if (theme === 'dark') {
|
||||
moonIcon.style.display = 'none';
|
||||
sunIcon.style.display = 'block';
|
||||
} else {
|
||||
moonIcon.style.display = 'block';
|
||||
sunIcon.style.display = 'none';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function toggleTheme() {
|
||||
const currentTheme = html.getAttribute('data-theme') || getTheme();
|
||||
const newTheme = currentTheme === 'dark' ? 'light' : 'dark';
|
||||
setTheme(newTheme);
|
||||
}
|
||||
|
||||
function initTheme() {
|
||||
const theme = getTheme();
|
||||
setTheme(theme);
|
||||
|
||||
const themeToggle = document.getElementById('themeToggle');
|
||||
if (themeToggle) {
|
||||
themeToggle.removeEventListener('click', toggleTheme); // No double-clicking shenanigans
|
||||
themeToggle.addEventListener('click', toggleTheme);
|
||||
}
|
||||
}
|
||||
|
||||
// Dance the cookie shuffle before searching - SearXNG has opinions
|
||||
const searchForm = document.getElementById('search');
|
||||
if (searchForm) {
|
||||
searchForm.addEventListener('submit', function(e) {
|
||||
const theme = getTheme();
|
||||
// Out with the old cookie
|
||||
document.cookie = 'theme=; path=/; max-age=0; SameSite=Lax';
|
||||
// In with SearXNG's preferred flavor
|
||||
const cookieOptions = `path=/; max-age=${60 * 60 * 24 * 365 * 5}; SameSite=Lax`;
|
||||
document.cookie = `simple_style=${theme}; ${cookieOptions}`;
|
||||
});
|
||||
}
|
||||
|
||||
// Get this party started
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', initTheme);
|
||||
} else {
|
||||
initTheme();
|
||||
}
|
||||
|
||||
// Listen for OS theme changes - stay responsive to user preferences
|
||||
if (window.matchMedia) {
|
||||
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
|
||||
if (mediaQuery.addEventListener) {
|
||||
mediaQuery.addEventListener('change', function(e) {
|
||||
// Only auto-switch if they haven't explicitly chosen - consent matters
|
||||
if (!localStorage.getItem('theme') && !document.cookie.includes('simple_style') && !document.cookie.includes('theme=')) {
|
||||
setTheme(e.matches ? 'dark' : 'light');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
})();
|
||||
Reference in New Issue
Block a user