This commit is contained in:
2026-08-09 11:45:48 +02:00
parent f70b51986e
commit 21da2edd79
4 changed files with 103 additions and 4 deletions
+25 -1
View File
@@ -4,12 +4,36 @@
<body> <body>
<center><h1>404 Not Found</h1></center> <center><h1>404 Not Found</h1></center>
<hr><center>The page has been deleted</center> <hr><center>The page has been deleted</center>
<center id="undo" style="display:none"><br><a href="/">Restore website</a></center>
<script> <script>
/* Restore hatch: clicking the heading undeletes the website */ /* Restore hatch: clicking the heading undeletes the website */
function restore() {
try {
localStorage.removeItem('siteDeleted');
localStorage.removeItem('siteDeletedViews');
} catch (e) {}
}
document.querySelector('h1').addEventListener('click', function () { document.querySelector('h1').addEventListener('click', function () {
try { localStorage.removeItem('siteDeleted'); } catch (e) {} restore();
location.replace('/'); location.replace('/');
}); });
/* Restoring is symmetric with deleting: it needs a confirmation too */
document.querySelector('#undo a').addEventListener('click', function (e) {
if (!confirm('Are you sure? This will restore the entire website.')) {
e.preventDefault();
return;
}
restore();
});
/* View 1 is the deletion, view 2 is the disbelieving reload (nothing
changes; that's the point), view 3 gets the way out */
try {
if (localStorage.getItem('siteDeleted')) {
var views = 1 + (parseInt(localStorage.getItem('siteDeletedViews'), 10) || 0);
localStorage.setItem('siteDeletedViews', views);
if (views > 2) document.getElementById('undo').style.display = '';
}
} catch (e) {}
</script> </script>
</body> </body>
</html> </html>
+3 -3
View File
@@ -262,9 +262,9 @@
</div> </div>
</div> </div>
<div class="project-body"> <div class="project-body">
<p>Born out of a deep distrust of Microsoft and Google, this project is my ongoing effort to self-host as much of my digital life as possible. Every device on my network is named after a Pokémon and assigned a local IP of <code>10.0.0.x</code>, where <code>x</code> is its Pokédex number.</p> <p>Born out of a deep distrust of Microsoft and Google, this project is my ongoing effort to self-host as much of my digital life as possible. Every device on my network is named after a Pokémon and assigned a local IP of <code class="text-tip text-tip--list" data-tip="Bulbasaur · Raspberry Pi · 10.0.0.1&#10;Charizard · home server · 10.0.0.6&#10;Nidoran♀ · TV · 10.0.0.29&#10;Nidoran♂ · Chromecast · 10.0.0.32&#10;Growlithe · Nintendo Switch · 10.0.0.58&#10;Abra · iPhone · 10.0.0.63&#10;Kadabra · iPad · 10.0.0.64&#10;Eevee · laptop · 10.0.0.133&#10;Mewtwo · desktop · 10.0.0.150&#10;Mew · router · 10.0.0.151">10.0.0.x</code>, where <code>x</code> is its Pokédex number.</p>
<p>The primary server, <strong>Charizard</strong>, runs Unraid OS and manages a disk array totalling 44 TB. It hosts a Gitea instance for personal projects, a file server, and a media server, exposed to the internet through <strong>Nginx Proxy Manager</strong> with SSL certificates from Let's Encrypt.</p> <p>The primary server, <strong class="text-tip" data-tip="10.0.0.6">Charizard</strong>, runs Unraid OS and manages a disk array totalling 44 TB. It hosts a Gitea instance for personal projects, a file server, and a media server, exposed to the internet through <strong>Nginx Proxy Manager</strong> with SSL certificates from Let's Encrypt.</p>
<p>An extension of the setup lives on <strong>Bulbasaur</strong>, a Raspberry Pi running Pi-hole for network-wide ad blocking and a WireGuard VPN server for secure remote access.</p> <p>An extension of the setup lives on <strong class="text-tip" data-tip="10.0.0.1">Bulbasaur</strong>, a Raspberry Pi running Pi-hole for network-wide ad blocking and a WireGuard VPN server for secure remote access.</p>
<p>Charizard is turning five this year. In that time I've learned an enormous amount about networking, Linux administration, and the particular satisfaction of fixing something broken at 2 in the morning that nobody asked you to build in the first place.</p> <p>Charizard is turning five this year. In that time I've learned an enormous amount about networking, Linux administration, and the particular satisfaction of fixing something broken at 2 in the morning that nobody asked you to build in the first place.</p>
</div> </div>
<div class="project-tags"> <div class="project-tags">
+46
View File
@@ -728,3 +728,49 @@
arrange(CYCLE[pos]).finally(() => { busy = false; }); arrange(CYCLE[pos]).finally(() => { busy = false; });
}); });
})(); })();
// ── Goat ──────────────────────────────────────────────────────
(function () {
console.log(`
%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%
%%%% %%%%%%%%%%%
%%% %%%%%%%%%%%%%%%
%% %%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%`);
const FACTS = [
`The word admiral comes from the Arabic "amir al bahr", which translates to "commander of the sea". Somewhere along the way into European languages, the bahr fell off, so the word we kept literally means "commander of the".`,
`The word stationery comes from (perhaps obviously) the word stationary. It's because book shops were some of the first shops to be in permanent buildings, since books are too heavy to carry around in a cart.`,
`The Wikipedia page for economist Guy Standing was the site of one of the biggest edit wars in Wikipedia history, started when an editor uploaded a picture with the description "Guy Standing sitting".`,
`The introduction of shipping containers, which hide their contents, dropped the number of alcohol bottles marked as "broken" by almost 100%.`,
`The words "chess" and "check" both come from the ancient Persian word "shah", meaning "king". "Check mate" comes from "shah maat", meaning "the king is dead".`,
`No one knows the origin of the character of Igor in the Frankenstein story. He's not in the original book, and his first known appearance is from the movie adaptation of a play. So it's not known if he originally appeared in the play or the movie.`,
`To avoid a binary overflow error, Swiss trains are not allowed to have exactly 256 axles.`,
];
console.log('Fun fact: ' + FACTS[Math.floor(Math.random() * FACTS.length)]);
})();
+29
View File
@@ -836,6 +836,25 @@ footer {
pointer-events: none; pointer-events: none;
} }
/* Body-text tooltips: dotted underline marks hover info
(dashed marks clickable, see .dnd-roll) */
.text-tip {
position: relative;
cursor: help;
text-decoration: underline;
text-decoration-style: dotted;
text-decoration-thickness: 2px;
text-underline-offset: 3px;
}
/* List variant: newlines (&#10;) in the attribute become line breaks */
[data-tip].text-tip--list:hover::after,
[data-tip].text-tip--list:focus-visible::after,
[data-tip].text-tip--list.tip-open::after {
white-space: pre-line;
text-align: left;
max-width: 300px;
}
.skills-cards { .skills-cards {
display: grid; display: grid;
grid-template-columns: repeat(2, 1fr); grid-template-columns: repeat(2, 1fr);
@@ -859,7 +878,17 @@ footer {
position: relative; position: relative;
user-select: none; user-select: none;
-webkit-user-select: none; -webkit-user-select: none;
cursor: pointer;
text-decoration: underline;
text-decoration-style: dashed;
text-decoration-thickness: 2px;
text-underline-offset: 3px;
border-radius: 4px;
padding: 0 0.15em;
margin: 0 -0.15em;
transition: background 150ms ease;
} }
.dnd-roll:hover { background: var(--pink); }
.die-scene { .die-scene {
position: absolute; position: absolute;
bottom: calc(100% + 10px); bottom: calc(100% + 10px);