feat: add "Hello from the otter side" easter eggs

Custom 404 pages for landing and docs sites, otter greeting on the
first-login sidebar, and a one-time welcome toast after password change.
This commit is contained in:
SnapOtter
2026-05-16 22:45:22 +08:00
parent b5db8f3192
commit fd69a60e48
5 changed files with 94 additions and 3 deletions
+54
View File
@@ -16,5 +16,59 @@ const { Layout } = DefaultTheme;
<GitHubStars />
</div>
</template>
<template #not-found>
<div class="not-found-page">
<span class="not-found-otter">🦦</span>
<h1 class="not-found-heading">Hello from the otter side!</h1>
<p class="not-found-text">This page swam away. Let's get you back on track.</p>
<a href="/" class="not-found-link">Back to docs</a>
</div>
</template>
</Layout>
</template>
<style scoped>
.not-found-page {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
min-height: 60vh;
text-align: center;
padding: 2rem;
}
.not-found-otter {
font-size: 4.5rem;
}
.not-found-heading {
margin-top: 1.5rem;
font-size: 2.25rem;
font-weight: 700;
letter-spacing: -0.02em;
}
.not-found-text {
margin-top: 1rem;
font-size: 1.125rem;
color: var(--vp-c-text-2);
}
.not-found-link {
margin-top: 2rem;
display: inline-block;
padding: 0.625rem 1.5rem;
border-radius: 0.5rem;
background: var(--vp-c-brand-1);
color: var(--vp-c-white);
font-size: 0.875rem;
font-weight: 500;
transition: background 0.2s;
}
.not-found-link:hover {
background: var(--vp-c-brand-2);
text-decoration: none;
}
</style>
+26
View File
@@ -0,0 +1,26 @@
import { Footer } from "@/components/footer";
import { Navbar } from "@/components/navbar";
export default function NotFound() {
return (
<>
<Navbar />
<main className="flex min-h-screen flex-col items-center justify-center px-6 pt-16">
<span className="text-7xl">🦦</span>
<h1 className="mt-6 text-4xl font-bold tracking-tight sm:text-5xl">
Hello from the otter side!
</h1>
<p className="mt-4 text-lg text-muted">
This page swam away. Let&apos;s get you back on track.
</p>
<a
href="/"
className="mt-8 rounded-lg bg-accent px-6 py-3 text-sm font-medium text-accent-foreground transition-colors hover:bg-accent-hover"
>
Back to homepage
</a>
</main>
<Footer />
</>
);
}
+10 -1
View File
@@ -1,7 +1,7 @@
import { APP_VERSION, en, shouldShowConsent } from "@snapotter/shared";
import { Component, type ErrorInfo, lazy, type ReactNode, Suspense, useEffect } from "react";
import { BrowserRouter, Navigate, Route, Routes, useLocation } from "react-router-dom";
import { Toaster } from "sonner";
import { Toaster, toast } from "sonner";
import { ConnectionMonitor } from "./components/common/connection-monitor";
import { KeyboardShortcutProvider } from "./components/common/keyboard-shortcut-provider";
import { I18nProvider } from "./contexts/i18n-context";
@@ -186,6 +186,15 @@ export function App() {
fetchAnalyticsConfig();
}, [fetchAnalyticsConfig]);
useEffect(() => {
if (localStorage.getItem("snapotter-welcome") === "1") {
localStorage.removeItem("snapotter-welcome");
toast("Hello from the otter side! 🦦", {
duration: 5000,
});
}
}, []);
useEffect(() => {
if (
!analyticsConfigLoaded ||
@@ -100,6 +100,7 @@ export function ChangePasswordPage() {
return;
}
localStorage.setItem("snapotter-welcome", "1");
// Trigger browser password save prompt via real form submission + navigation
const username = localStorage.getItem("snapotter-username") || "admin";
triggerBrowserPasswordSave(username, newPassword);
@@ -218,6 +219,7 @@ export function ChangePasswordPage() {
</div>
<div className="hidden lg:flex flex-1 bg-primary/90 items-center justify-center p-12 text-white rounded-s-3xl">
<div className="max-w-lg space-y-6 text-center">
<span className="text-7xl">🦦</span>
<h2 className="text-3xl font-bold">{t.changePassword.sidebarTitle}</h2>
<p className="text-lg text-white/80">{t.changePassword.sidebarDescription}</p>
</div>