update not found page
This commit is contained in:
parent
b3c03e0c41
commit
f8195aa401
BIN
public/images/coralz_0.png
Normal file
BIN
public/images/coralz_0.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 177 KiB |
BIN
public/images/coralz_1.png
Normal file
BIN
public/images/coralz_1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 176 KiB |
BIN
public/sound/poke.wav
Normal file
BIN
public/sound/poke.wav
Normal file
Binary file not shown.
BIN
public/sound/squeak.wav
Normal file
BIN
public/sound/squeak.wav
Normal file
Binary file not shown.
@ -7,6 +7,17 @@
|
|||||||
--primary: #F48120;
|
--primary: #F48120;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@keyframes click-bounce {
|
||||||
|
0%, 100% {
|
||||||
|
transform: scale(1, 1);
|
||||||
|
/* animation-timing-function: linear(0.2, 0.8, 1); */
|
||||||
|
}
|
||||||
|
30% {
|
||||||
|
transform: scale(1.18, 0.9);
|
||||||
|
/* animation-timing-function: cubic-bezier(0.8, 0, 1, 1); */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@keyframes silly-bounce {
|
@keyframes silly-bounce {
|
||||||
0%, 100% {
|
0%, 100% {
|
||||||
transform: translate(0px, 0px) scale(0.9, 1.1);
|
transform: translate(0px, 0px) scale(0.9, 1.1);
|
||||||
|
|||||||
@ -1,4 +1,6 @@
|
|||||||
|
import WobblingImage from "@/components/wobbling-image";
|
||||||
import type { Metadata } from "next";
|
import type { Metadata } from "next";
|
||||||
|
import Link from "@/components/link";
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: "Wep wep",
|
title: "Wep wep",
|
||||||
@ -8,12 +10,19 @@ export default function NotFound() {
|
|||||||
return (
|
return (
|
||||||
<main className="flex items-center h-screen pt-16 md:pt-32 pb-12 px-8 md:px-0">
|
<main className="flex items-center h-screen pt-16 md:pt-32 pb-12 px-8 md:px-0">
|
||||||
<div className="mx-auto w-[380px]">
|
<div className="mx-auto w-[380px]">
|
||||||
|
<noscript>
|
||||||
<header className="mb-8 -ms-5 text-center">
|
<header className="mb-8 -ms-5 text-center">
|
||||||
<h1 className="font-bold text-8xl">404</h1>
|
<h1 className="font-bold text-8xl">404</h1>
|
||||||
</header>
|
</header>
|
||||||
<div className="">
|
<div className="">
|
||||||
Oh you lost, you know there's nothing here...
|
Oh you lost, you know there's nothing here...
|
||||||
</div>
|
</div>
|
||||||
|
</noscript>
|
||||||
|
<WobblingImage
|
||||||
|
img1="/images/coralz_0.png"
|
||||||
|
img2="/images/coralz_1.png"
|
||||||
|
/>
|
||||||
|
<Link target="_blank" href="https://x.com/JoelGuerraC/status/1840178999546319101">Source</Link>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -3,9 +3,8 @@ import { NolaGlitchClientOnly } from "@/components/nola-glitch";
|
|||||||
import { Sosmed } from "@/components/sosmed";
|
import { Sosmed } from "@/components/sosmed";
|
||||||
import HomeText from "@/components/home-text.mdx"
|
import HomeText from "@/components/home-text.mdx"
|
||||||
|
|
||||||
import Link from "next/link";
|
import Link from "@/components/link";
|
||||||
import { FakeWindow, HomeWindows } from "@/components/windows";
|
import { FakeWindow, HomeWindows } from "@/components/windows";
|
||||||
import Taskbar from "@/components/taskbar";
|
|
||||||
import { WindowManagerProvider } from "@/hooks/window-manager";
|
import { WindowManagerProvider } from "@/hooks/window-manager";
|
||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
@ -28,12 +27,12 @@ export default function Home() {
|
|||||||
<HomeText />
|
<HomeText />
|
||||||
</article>
|
</article>
|
||||||
<section className="my-8">
|
<section className="my-8">
|
||||||
<p>⚡ Powered with <Link href="https://www.cloudflare.com/" target="_blank" className="text-primary underline">Cloudflare</Link> ☁️</p>
|
<p>⚡ Powered with <Link href="https://www.cloudflare.com/" target="_blank">Cloudflare</Link> ☁️</p>
|
||||||
</section>
|
</section>
|
||||||
<footer className="mt-20 text-center">
|
<footer className="mt-20 text-center">
|
||||||
<p>© <span className="text-sm">2025 Nomi Nonszy</span></p>
|
<p>© <span className="text-sm">2025 Nomi Nonszy</span></p>
|
||||||
<p className="text-sm">
|
<p className="text-sm">
|
||||||
<Link href={"/terms"} className="text-primary underline">Terms</Link> and <Link href={"/privacy"} className="text-primary underline">Privacy</Link>
|
<Link href={"/terms"}>Terms</Link> and <Link href={"/privacy"}>Privacy</Link>
|
||||||
</p>
|
</p>
|
||||||
</footer>
|
</footer>
|
||||||
</FakeWindow>
|
</FakeWindow>
|
||||||
|
|||||||
14
src/components/link.tsx
Normal file
14
src/components/link.tsx
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import clsx from "clsx";
|
||||||
|
import NextLink from "next/link"
|
||||||
|
|
||||||
|
function Link({ className, ...props }: React.ComponentProps<typeof NextLink>) {
|
||||||
|
return (
|
||||||
|
<NextLink
|
||||||
|
className={clsx("text-primary underline", className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export default Link;
|
||||||
@ -15,7 +15,7 @@ export const SimpleArticle = ({
|
|||||||
Back
|
Back
|
||||||
</ButtonPrimary>
|
</ButtonPrimary>
|
||||||
</Link>
|
</Link>
|
||||||
<article className="space-y-5 [&_p]:leading-relaxed relative [&_h1]:text-2xl [&_h2]:text-xl">
|
<article className="space-y-5 [&_p]:leading-relaxed [&_p]:text-sm [&_li]:text-sm relative [&_h1]:text-2xl [&_h2]:text-xl">
|
||||||
{children}
|
{children}
|
||||||
</article>
|
</article>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
# Privacy Policy
|
# Privacy Policy
|
||||||
|
|
||||||
This website ("nonszy.space") fully respects the privacy of its visitors. This document explains how we handle visitor information. The short answer is: **we do not collect, track, or store your personal information**.
|
This website ("nonszy.space") fully respects the privacy of its visitors. This page explains how we handle visitor information. The short answer is: **we do not collect, track, or store your personal information**.
|
||||||
|
|
||||||
However, future feature additions will update the privacy policy.
|
However, future feature additions will update the privacy policy.
|
||||||
132
src/components/wobbling-image.tsx
Normal file
132
src/components/wobbling-image.tsx
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
|
import clsx from "clsx";
|
||||||
|
import Image from "next/image";
|
||||||
|
import { useCallback, useEffect, useRef, useState } from "react"
|
||||||
|
|
||||||
|
interface WobblingImageInterface {
|
||||||
|
img1: string
|
||||||
|
img2?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
function WobblingImage ({
|
||||||
|
img1, img2
|
||||||
|
}: WobblingImageInterface) {
|
||||||
|
const size = 400;
|
||||||
|
const [isAnimating, setIsAnimating] = useState(false);
|
||||||
|
|
||||||
|
const audioPath = "/sound/poke.wav";
|
||||||
|
const audioContextRef = useRef<AudioContext | null>(null);
|
||||||
|
const [audioBuffer, setAudioBuffer] = useState<AudioBuffer | null>(null);
|
||||||
|
const [audioLoaded, setAudioLoaded] = useState(false);
|
||||||
|
|
||||||
|
const [dummyAudio, setDummyAudio] = useState<HTMLAudioElement | null>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (typeof Audio !== undefined) setDummyAudio(new Audio(audioPath))
|
||||||
|
return () => {
|
||||||
|
if (dummyAudio) dummyAudio.pause();
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const initializeAudioContext = useCallback((): AudioContext => {
|
||||||
|
if (!audioContextRef.current) {
|
||||||
|
audioContextRef.current = new (window.AudioContext || (window as any).webkitAudioContext)();
|
||||||
|
}
|
||||||
|
return audioContextRef.current;
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const loadAudio = useCallback(async (url: string): Promise<AudioBuffer> => {
|
||||||
|
const response = await fetch(url);
|
||||||
|
const arrayBuffer = await response.arrayBuffer();
|
||||||
|
const context = initializeAudioContext();
|
||||||
|
return await context.decodeAudioData(arrayBuffer);
|
||||||
|
}, [initializeAudioContext]);
|
||||||
|
|
||||||
|
const initializeAudio = useCallback(async (): Promise<void> => {
|
||||||
|
if (audioBuffer) return;
|
||||||
|
|
||||||
|
setAudioLoaded(false);
|
||||||
|
try {
|
||||||
|
const buffer = await loadAudio(audioPath);
|
||||||
|
setAudioBuffer(buffer);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to load audio:', error);
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
setAudioLoaded(true);
|
||||||
|
}
|
||||||
|
}, [audioBuffer, loadAudio]);
|
||||||
|
|
||||||
|
const playRandomPitch = useCallback(async (): Promise<void> => {
|
||||||
|
await initializeAudio();
|
||||||
|
|
||||||
|
if (!audioBuffer || !audioContextRef.current) return;
|
||||||
|
|
||||||
|
const context = audioContextRef.current;
|
||||||
|
const changeToLowPitch = Math.floor(Math.random() * 10);
|
||||||
|
const randomPitch = Math.random() * 0.2 + (changeToLowPitch == 1 ? 0.25 : 0.85);
|
||||||
|
|
||||||
|
const source = context.createBufferSource();
|
||||||
|
source.buffer = audioBuffer;
|
||||||
|
source.playbackRate.value = randomPitch;
|
||||||
|
source.connect(context.destination);
|
||||||
|
source.start(0);
|
||||||
|
|
||||||
|
source.onended = () => {
|
||||||
|
source.disconnect();
|
||||||
|
};
|
||||||
|
}, [audioBuffer, initializeAudio]);
|
||||||
|
|
||||||
|
|
||||||
|
function handleClick() {
|
||||||
|
setIsAnimating(false);
|
||||||
|
requestAnimationFrame(() => setIsAnimating(true));
|
||||||
|
playRandomPitch();
|
||||||
|
if (dummyAudio && !audioLoaded) {
|
||||||
|
dummyAudio.currentTime = 0;
|
||||||
|
dummyAudio.play();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleAnimationEnd() {
|
||||||
|
setIsAnimating(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="">
|
||||||
|
<div
|
||||||
|
className={clsx(
|
||||||
|
"relative mx-auto cursor-grab h-[400px] select-none",
|
||||||
|
isAnimating && "animate-[click-bounce_150ms_ease-out]"
|
||||||
|
)}
|
||||||
|
onClick={handleClick}
|
||||||
|
onAnimationEnd={handleAnimationEnd}
|
||||||
|
role="button"
|
||||||
|
tabIndex={0}
|
||||||
|
onKeyDown={(e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); handleClick(); } }}
|
||||||
|
onMouseDown={(e) => e.preventDefault()}
|
||||||
|
onPointerDown={(e) => e.preventDefault()}
|
||||||
|
>
|
||||||
|
<Image
|
||||||
|
className={clsx("absolute left-1/2 -translate-x-1/2 top-0 pointer-events-none", isAnimating ? "opacity-0" : "opacity-100")}
|
||||||
|
alt="clip1"
|
||||||
|
src={img1}
|
||||||
|
width={size}
|
||||||
|
height={size}
|
||||||
|
draggable={false}
|
||||||
|
/>
|
||||||
|
<Image
|
||||||
|
className={clsx("absolute left-1/2 -translate-x-1/2 top-0 pointer-events-none", isAnimating ? "opacity-100" : "opacity-0")}
|
||||||
|
alt="clip2"
|
||||||
|
src={img2 || img1}
|
||||||
|
width={size}
|
||||||
|
height={size}
|
||||||
|
draggable={false}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default WobblingImage;
|
||||||
@ -24,6 +24,7 @@ const config: Config = {
|
|||||||
},
|
},
|
||||||
animation: {
|
animation: {
|
||||||
"silly-bouncing": 'silly-bounce 0.8s infinite',
|
"silly-bouncing": 'silly-bounce 0.8s infinite',
|
||||||
|
"click-bouncing": 'click-bounce 200ms',
|
||||||
'window-popup': 'window-popup 1s',
|
'window-popup': 'window-popup 1s',
|
||||||
'window-popdown': 'window-popdown 1s'
|
'window-popdown': 'window-popdown 1s'
|
||||||
},
|
},
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user