]> danix's work - danix.xyz-2.git/commitdiff
feat: create 404 error page with search, recent articles, and easter egg
authorDanilo M. <redacted>
Fri, 17 Apr 2026 08:41:05 +0000 (10:41 +0200)
committerDanilo M. <redacted>
Fri, 17 Apr 2026 08:41:05 +0000 (10:41 +0200)
themes/danix-xyz-hacker/i18n/en.yaml
themes/danix-xyz-hacker/i18n/it.yaml
themes/danix-xyz-hacker/layouts/404.html [new file with mode: 0644]

index 164b6a8330d224dc03bd1adc6fc22b45c8a8c4d2..be5e352b596b1fe2ca9ebb873180e3acdf69935b 100644 (file)
@@ -49,3 +49,18 @@ error: "An error occurred. Please try again."
 # Social
 follow: "Follow me"
 contactMe: "Contact me"
+
+# 404 Page
+notFoundHeading: "404"
+notFound: "Page Not Found"
+notFoundMessage: "Sorry, the page you're looking for doesn't exist. Try searching or browse the articles below."
+searchPlaceholder: "Search articles..."
+noSearchResults: "No articles found matching your search."
+recentArticles: "Recent Articles"
+goHome: "Go Home"
+browseArticles: "Browse Articles"
+contactSupport: "Get in Touch"
+followWhiteRabbit: "Follow the white rabbit..."
+easterEggTitle: "Choose Your Path"
+bluePill: "Stay Here"
+redPill: "Show Me More"
index 926bf01aeacd2bf05a76db3cc8e7a6637f83ef78..4c2bf82b86aaf9fc2e703bc80148787d54066ab1 100644 (file)
@@ -49,3 +49,18 @@ error: "Si è verificato un errore. Riprova."
 # Social
 follow: "Seguimi"
 contactMe: "Contattami"
+
+# 404 Page
+notFoundHeading: "404"
+notFound: "Pagina Non Trovata"
+notFoundMessage: "Mi dispiace, la pagina che stai cercando non esiste. Prova a cercare o sfoglia gli articoli qui sotto."
+searchPlaceholder: "Cerca articoli..."
+noSearchResults: "Nessun articolo trovato che corrisponda alla tua ricerca."
+recentArticles: "Articoli Recenti"
+goHome: "Torna a Casa"
+browseArticles: "Sfoglia Articoli"
+contactSupport: "Contattami"
+followWhiteRabbit: "Segui il coniglio bianco..."
+easterEggTitle: "Scegli il Tuo Percorso"
+bluePill: "Rimani Qui"
+redPill: "Mostrami di Più"
diff --git a/themes/danix-xyz-hacker/layouts/404.html b/themes/danix-xyz-hacker/layouts/404.html
new file mode 100644 (file)
index 0000000..8cb694c
--- /dev/null
@@ -0,0 +1,169 @@
+{{ define "main" }}
+<main class="min-h-screen flex items-center justify-center px-4">
+  <div class="text-center max-w-2xl w-full" x-data="notFoundPage()">
+    <!-- 404 Heading -->
+    <h1 class="text-7xl md:text-8xl font-bold text-accent mb-4 animate-fade-in">
+      404
+    </h1>
+
+    <!-- Error Message -->
+    <h2 class="text-3xl md:text-4xl font-bold mb-6">
+      {{ i18n "notFound" }}
+    </h2>
+
+    <p class="text-lg text-text-dim mb-8">
+      {{ i18n "notFoundMessage" }}
+    </p>
+
+    <!-- Search Box -->
+    <div class="mb-12">
+      <form id="search-form" class="flex flex-col gap-4">
+        <label for="search-input" class="sr-only">{{ i18n "searchPlaceholder" }}</label>
+        <input
+          id="search-input"
+          type="text"
+          placeholder="{{ (i18n "searchPlaceholder") }}"
+          class="px-4 py-3 border-2 border-gray-300 dark:border-gray-700 rounded focus:outline-none focus:ring-2 focus:ring-accent focus:border-transparent bg-bg text-text"
+          @input="filterArticles($el.value)"
+        />
+      </form>
+      <div id="search-results" class="mt-4 text-left space-y-3" x-show="filteredArticles.length > 0">
+        <template x-for="article in filteredArticles" :key="article.title">
+          <div class="p-4 border-l-4 border-accent bg-gray-50 dark:bg-gray-900 hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors">
+            <a :href="article.url" class="block text-left">
+              <h4 class="font-bold text-accent hover:underline" x-text="article.title"></h4>
+              <p class="text-sm text-text-dim mt-1" x-text="article.date"></p>
+            </a>
+          </div>
+        </template>
+      </div>
+      <div x-show="searchQuery && filteredArticles.length === 0" class="mt-4 text-text-dim">
+        {{ i18n "noSearchResults" }}
+      </div>
+    </div>
+
+    <!-- Recent Articles Section -->
+    <div class="mb-12">
+      <h3 class="text-2xl font-bold mb-6">{{ i18n "recentArticles" }}</h3>
+      <div class="space-y-4">
+        {{ range first 5 (where .Site.RegularPages "Section" "articles") }}
+        <div class="p-4 border-l-4 border-accent bg-gray-50 dark:bg-gray-900 hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors">
+          <a href="{{ .Permalink }}" class="block text-left">
+            <h4 class="font-bold text-accent hover:underline">{{ .Title }}</h4>
+            <p class="text-sm text-text-dim mt-1">
+              {{ .Date.Format "Jan 02, 2006" }}
+            </p>
+          </a>
+        </div>
+        {{ end }}
+      </div>
+    </div>
+
+    <!-- Navigation Links -->
+    <div class="space-y-4 flex flex-col items-center mb-12">
+      <a href="{{ .Site.BaseURL }}" class="btn btn-primary">
+        {{ i18n "goHome" }}
+      </a>
+      <a href="{{ .Site.BaseURL }}{{ .Site.Language.Lang }}/articles/" class="btn btn-secondary">
+        {{ i18n "browseArticles" }}
+      </a>
+      <a href="{{ .Site.BaseURL }}{{ .Site.Language.Lang }}/here/" class="btn btn-outline">
+        {{ i18n "contactSupport" }}
+      </a>
+    </div>
+
+    <!-- Easter Egg Trigger -->
+    <div class="mt-12 pt-8 border-t border-gray-300 dark:border-gray-700">
+      <button
+        @click="toggleEasterEgg()"
+        class="text-sm text-text-dim hover:text-accent transition-colors underline"
+      >
+        {{ i18n "followWhiteRabbit" }}
+      </button>
+    </div>
+
+    <!-- Easter Egg Modal (Hidden by default) -->
+    <div
+      class="fixed inset-0 z-50 hidden"
+      :class="{ 'flex items-center justify-center': showEasterEgg }"
+      x-show="showEasterEgg"
+      x-cloak
+    >
+      <!-- Overlay -->
+      <div
+        class="absolute inset-0 bg-black/50"
+        @click="showEasterEgg = false"
+      ></div>
+
+      <!-- Modal Content -->
+      <div class="relative bg-bg border-2 border-accent p-8 rounded-lg shadow-xl max-w-md mx-4">
+        <h2 class="text-2xl font-bold mb-6 text-accent">{{ i18n "easterEggTitle" }}</h2>
+
+        <div class="space-y-4">
+          <button
+            @click="showEasterEgg = false; window.location.href = '{{ .Site.BaseURL }}'"
+            class="w-full btn btn-primary"
+          >
+            💊 {{ i18n "bluePill" }}
+          </button>
+
+          <button
+            @click="goToRandomArticle()"
+            class="w-full btn btn-secondary"
+          >
+            🐰 {{ i18n "redPill" }}
+          </button>
+        </div>
+
+        <button
+          @click="showEasterEgg = false"
+          class="absolute top-4 right-4 text-text-dim hover:text-text dark:hover:text-text transition-colors"
+          aria-label="Close modal"
+        >
+          ✕
+        </button>
+      </div>
+    </div>
+  </div>
+</main>
+
+<script>
+function notFoundPage() {
+  return {
+    showEasterEgg: false,
+    searchQuery: '',
+    filteredArticles: [],
+    allArticles: [
+      {{ range (where .Site.RegularPages "Section" "articles") }}
+      {
+        title: '{{ .Title | safeJS }}',
+        url: '{{ .Permalink }}',
+        date: '{{ .Date.Format "Jan 02, 2006" }}',
+        content: '{{ (.Summary | plainify | safeJS) }}'
+      },
+      {{ end }}
+    ],
+    filterArticles(query) {
+      this.searchQuery = query.toLowerCase();
+      if (!this.searchQuery) {
+        this.filteredArticles = [];
+        return;
+      }
+      this.filteredArticles = this.allArticles.filter(article =>
+        article.title.toLowerCase().includes(this.searchQuery) ||
+        article.content.toLowerCase().includes(this.searchQuery)
+      ).slice(0, 5);
+    },
+    toggleEasterEgg() {
+      this.showEasterEgg = !this.showEasterEgg;
+    },
+    goToRandomArticle() {
+      if (this.allArticles.length > 0) {
+        const randomArticle = this.allArticles[Math.floor(Math.random() * this.allArticles.length)];
+        window.location.href = randomArticle.url;
+      }
+    }
+  };
+}
+</script>
+{{ end }}