refactor: improve 404 page loading experience and styling
- Replace Suspense with useEffect for better control over component mounting. - Update loading indicators with fixed positioning and enhanced styling for a terminal-like appearance. - Modify KernelPanic404 component to improve text color handling and ensure proper visibility. - Introduce checks for 404 page detection based on pathname and data attributes for more accurate rendering.
This commit is contained in:
@@ -16,21 +16,27 @@ export default function ClientProviders({
|
||||
}) {
|
||||
const [mounted, setMounted] = useState(false);
|
||||
const [is404Page, setIs404Page] = useState(false);
|
||||
const pathname = usePathname();
|
||||
|
||||
useEffect(() => {
|
||||
setMounted(true);
|
||||
// Check if we're on a 404 page by looking for the data attribute
|
||||
// Check if we're on a 404 page by looking for the data attribute or pathname
|
||||
const check404 = () => {
|
||||
if (typeof window !== "undefined") {
|
||||
const has404Component = document.querySelector('[data-404-page]');
|
||||
setIs404Page(!!has404Component);
|
||||
const is404Path = pathname === '/404' || window.location.pathname === '/404' || window.location.pathname.includes('404');
|
||||
setIs404Page(!!has404Component || is404Path);
|
||||
}
|
||||
};
|
||||
// Check immediately and after a short delay
|
||||
check404();
|
||||
const timeout = setTimeout(check404, 100);
|
||||
return () => clearTimeout(timeout);
|
||||
}, []);
|
||||
const interval = setInterval(check404, 500);
|
||||
return () => {
|
||||
clearTimeout(timeout);
|
||||
clearInterval(interval);
|
||||
};
|
||||
}, [pathname]);
|
||||
|
||||
return (
|
||||
<AnalyticsProvider>
|
||||
|
||||
@@ -559,12 +559,19 @@ export default function KernelPanic404() {
|
||||
if (!output) return;
|
||||
const d = document.createElement("div");
|
||||
d.innerHTML = text;
|
||||
if (type === "log-warn") d.style.color = "#ffb000";
|
||||
// Default color for normal text - use setProperty with important to override globals.css
|
||||
if (!type || (type !== "log-warn" && type !== "log-err" && type !== "alert" && type !== "log-sys" && type !== "log-k" && type !== "log-dim")) {
|
||||
d.style.setProperty("color", "var(--phosphor)", "important");
|
||||
}
|
||||
if (type === "log-warn") d.style.setProperty("color", "#ffb000", "important");
|
||||
if (type === "log-err" || type === "alert")
|
||||
d.style.color = "var(--alert)";
|
||||
if (type === "log-dim") d.style.opacity = "0.6";
|
||||
if (type === "log-sys") d.style.color = "cyan";
|
||||
if (type === "log-k") d.style.color = "#fff";
|
||||
d.style.setProperty("color", "var(--alert)", "important");
|
||||
if (type === "log-dim") {
|
||||
d.style.opacity = "0.6";
|
||||
d.style.setProperty("color", "var(--phosphor)", "important");
|
||||
}
|
||||
if (type === "log-sys") d.style.setProperty("color", "cyan", "important");
|
||||
if (type === "log-k") d.style.setProperty("color", "#fff", "important");
|
||||
if (type === "pulse-red") d.classList.add("pulse-red");
|
||||
if (type === "fsociety-mask") d.classList.add("fsociety-mask");
|
||||
if (type === "memory-error") d.classList.add("memory-error");
|
||||
@@ -1447,18 +1454,40 @@ export default function KernelPanic404() {
|
||||
--phosphor: #33ff00;
|
||||
--phosphor-sec: #008f11;
|
||||
--alert: #ff3333;
|
||||
--font: "Courier New", Courier, monospace;
|
||||
--font: 'Courier New', Courier, monospace;
|
||||
}
|
||||
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
|
||||
body {
|
||||
background-color: var(--bg-color);
|
||||
margin: 0;
|
||||
height: 100vh;
|
||||
overflow: hidden;
|
||||
font-family: var(--font);
|
||||
color: var(--phosphor);
|
||||
user-select: none;
|
||||
cursor: default;
|
||||
transition: filter 0.5s, transform 0.5s;
|
||||
}
|
||||
|
||||
/* --- CRT EFFECTS --- */
|
||||
.crt-wrap {
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
height: 100%;
|
||||
padding: 30px;
|
||||
box-sizing: border-box;
|
||||
background: radial-gradient(circle at center, #111 0%, #000 100%);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* Override globals.css div color rule for 404 page - must be very specific */
|
||||
html body:has([data-404-page]) .crt-wrap,
|
||||
html body:has([data-404-page]) .crt-wrap *,
|
||||
html body:has([data-404-page]) #output,
|
||||
html body:has([data-404-page]) #output div,
|
||||
html body:has([data-404-page]) #output * {
|
||||
color: var(--phosphor) !important;
|
||||
}
|
||||
|
||||
.crt-wrap::before {
|
||||
@@ -1468,25 +1497,22 @@ export default function KernelPanic404() {
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background:
|
||||
linear-gradient(rgba(18, 16, 16, 0) 50%, rgba(0, 0, 0, 0.25) 50%),
|
||||
linear-gradient(
|
||||
90deg,
|
||||
rgba(255, 0, 0, 0.06),
|
||||
rgba(0, 255, 0, 0.02),
|
||||
rgba(0, 0, 255, 0.06)
|
||||
);
|
||||
background-size:
|
||||
100% 4px,
|
||||
3px 100%;
|
||||
background: linear-gradient(rgba(18, 16, 16, 0) 50%, rgba(0, 0, 0, 0.25) 50%),
|
||||
linear-gradient(90deg, rgba(255, 0, 0, 0.06), rgba(0, 255, 0, 0.02), rgba(0, 0, 255, 0.06));
|
||||
background-size: 100% 4px, 3px 100%;
|
||||
pointer-events: none;
|
||||
z-index: 90;
|
||||
}
|
||||
|
||||
.glow {
|
||||
text-shadow:
|
||||
0 0 2px var(--phosphor-sec),
|
||||
0 0 8px var(--phosphor);
|
||||
text-shadow: 0 0 2px var(--phosphor-sec), 0 0 8px var(--phosphor);
|
||||
}
|
||||
|
||||
/* Hide chat widget on 404 page */
|
||||
body:has([data-404-page]) [data-chat-widget] {
|
||||
display: none !important;
|
||||
visibility: hidden !important;
|
||||
opacity: 0 !important;
|
||||
}
|
||||
|
||||
/* --- TERMINAL --- */
|
||||
@@ -1507,7 +1533,6 @@ export default function KernelPanic404() {
|
||||
margin-bottom: 20px;
|
||||
font-size: 1.1rem;
|
||||
line-height: 1.4;
|
||||
color: var(--phosphor);
|
||||
}
|
||||
|
||||
#output::-webkit-scrollbar {
|
||||
@@ -1527,7 +1552,6 @@ export default function KernelPanic404() {
|
||||
margin-right: 10px;
|
||||
font-weight: bold;
|
||||
white-space: nowrap;
|
||||
color: var(--phosphor);
|
||||
}
|
||||
|
||||
#cmd-input {
|
||||
@@ -1852,7 +1876,7 @@ export default function KernelPanic404() {
|
||||
|
||||
<div id="flash-overlay" ref={overlayRef}></div>
|
||||
|
||||
<div className="crt-wrap glow" ref={bodyRef}>
|
||||
<div className="crt-wrap glow" ref={bodyRef} data-404-page="true">
|
||||
<div id="terminal">
|
||||
<div id="output" ref={outputRef}></div>
|
||||
<div
|
||||
|
||||
41
app/components/KernelPanic404Wrapper.tsx
Normal file
41
app/components/KernelPanic404Wrapper.tsx
Normal file
@@ -0,0 +1,41 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect } from "react";
|
||||
|
||||
export default function KernelPanic404Wrapper() {
|
||||
useEffect(() => {
|
||||
// Ensure body and html don't interfere
|
||||
document.body.style.background = "#020202";
|
||||
document.body.style.color = "#33ff00";
|
||||
document.documentElement.style.background = "#020202";
|
||||
document.documentElement.style.color = "#33ff00";
|
||||
|
||||
return () => {
|
||||
// Cleanup
|
||||
document.body.style.background = "";
|
||||
document.body.style.color = "";
|
||||
document.documentElement.style.background = "";
|
||||
document.documentElement.style.color = "";
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<iframe
|
||||
src="/404-terminal.html"
|
||||
style={{
|
||||
position: "fixed",
|
||||
top: 0,
|
||||
left: 0,
|
||||
width: "100vw",
|
||||
height: "100vh",
|
||||
border: "none",
|
||||
zIndex: 9999,
|
||||
margin: 0,
|
||||
padding: 0,
|
||||
backgroundColor: "#020202",
|
||||
}}
|
||||
data-404-page="true"
|
||||
allowTransparency={false}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -1,30 +1,80 @@
|
||||
"use client";
|
||||
|
||||
import { Suspense } from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
import dynamic from "next/dynamic";
|
||||
|
||||
// Dynamically import KernelPanic404 to avoid SSR issues
|
||||
const KernelPanic404 = dynamic(() => import("./components/KernelPanic404"), {
|
||||
// Dynamically import KernelPanic404Wrapper to avoid SSR issues
|
||||
const KernelPanic404 = dynamic(() => import("./components/KernelPanic404Wrapper"), {
|
||||
ssr: false,
|
||||
loading: () => (
|
||||
<div className="flex items-center justify-center min-h-screen bg-black text-[#33ff00] font-mono">
|
||||
<div style={{
|
||||
position: "fixed",
|
||||
top: 0,
|
||||
left: 0,
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
backgroundColor: "#020202",
|
||||
color: "#33ff00",
|
||||
fontFamily: "monospace"
|
||||
}}>
|
||||
<div>Loading terminal...</div>
|
||||
</div>
|
||||
),
|
||||
});
|
||||
|
||||
export default function NotFound() {
|
||||
const [mounted, setMounted] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
setMounted(true);
|
||||
}, []);
|
||||
|
||||
if (!mounted) {
|
||||
return (
|
||||
<div style={{
|
||||
position: "fixed",
|
||||
top: 0,
|
||||
left: 0,
|
||||
width: "100vw",
|
||||
height: "100vh",
|
||||
margin: 0,
|
||||
padding: 0,
|
||||
overflow: "hidden",
|
||||
backgroundColor: "#020202",
|
||||
zIndex: 9998
|
||||
}}>
|
||||
<div style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
color: "#33ff00",
|
||||
fontFamily: "monospace"
|
||||
}}>
|
||||
Loading terminal...
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<main className="min-h-screen w-full bg-black overflow-hidden relative">
|
||||
<Suspense
|
||||
fallback={
|
||||
<div className="flex items-center justify-center min-h-screen bg-black text-[#33ff00] font-mono">
|
||||
<div>Loading terminal...</div>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<KernelPanic404 />
|
||||
</Suspense>
|
||||
</main>
|
||||
<div style={{
|
||||
position: "fixed",
|
||||
top: 0,
|
||||
left: 0,
|
||||
width: "100vw",
|
||||
height: "100vh",
|
||||
margin: 0,
|
||||
padding: 0,
|
||||
overflow: "hidden",
|
||||
backgroundColor: "#020202",
|
||||
zIndex: 9998
|
||||
}}>
|
||||
<KernelPanic404 />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user