Compare commits

...

3 Commits

Author SHA1 Message Date
0b04eed82b change restore window 2025-09-03 12:45:09 +07:00
9471a13388 working window manager 2025-09-03 12:09:00 +07:00
3ff1248887 update legal stuff 2025-09-03 10:51:20 +07:00
9 changed files with 220 additions and 83 deletions

View File

@ -6,10 +6,12 @@ import HomeText from "@/components/home-text.mdx"
import Link from "next/link"; import Link from "next/link";
import { FakeWindow, HomeWindows } from "@/components/windows"; import { FakeWindow, HomeWindows } from "@/components/windows";
import Taskbar from "@/components/taskbar"; import Taskbar from "@/components/taskbar";
import { WindowManagerProvider } from "@/hooks/window-manager";
export default function Home() { export default function Home() {
return (<> return (<>
<main className="flex items-center pt-16 md:pt-24 pb-12 px-8 md:px-0 overflow-x-hidden"> <main className="flex items-center pt-16 md:pt-24 pb-12 px-8 md:px-0 overflow-x-hidden">
<WindowManagerProvider>
<FakeWindow windowText="Homepage"> <FakeWindow windowText="Homepage">
<HomeWindows /> <HomeWindows />
<header className="text-center mb-8"> <header className="text-center mb-8">
@ -31,10 +33,11 @@ export default function Home() {
<footer className="mt-20 text-center"> <footer className="mt-20 text-center">
<p>&copy; <span className="text-sm">2025 Nomi Nonszy</span></p> <p>&copy; <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 and conditions</Link> and <Link href={"/privacy"} className="text-primary underline">Privacy Policy</Link> <Link href={"/terms"} className="text-primary underline">Terms</Link> and <Link href={"/privacy"} className="text-primary underline">Privacy</Link>
</p> </p>
</footer> </footer>
</FakeWindow> </FakeWindow>
</WindowManagerProvider>
</main> </main>
</>); </>);
} }

View File

@ -1,6 +1,6 @@
import type { Metadata } from "next"; import type { Metadata } from "next";
import PrivacyPolicy from "@/components/texts/privacy-policy.mdx" import PrivacyPolicy from "@/components/texts/privacy.mdx"
import { SimpleArticle } from "@/components/page-template"; import { SimpleArticle } from "@/components/page-template";
export const metadata: Metadata = { export const metadata: Metadata = {

View File

@ -1,10 +1,10 @@
import type { Metadata } from "next"; import type { Metadata } from "next";
import TermsAndConditions from "@/components/texts/terms-and-condition.mdx" import TermsAndConditions from "@/components/texts/terms.mdx"
import { SimpleArticle } from "@/components/page-template"; import { SimpleArticle } from "@/components/page-template";
export const metadata: Metadata = { export const metadata: Metadata = {
title: "Terms and conditions", title: "Terms",
}; };
export default function Terms () { export default function Terms () {

View File

@ -1,8 +1,27 @@
'use client' 'use client'
import { FakeWindow, useWindowManager } from "@/hooks/window-manager";
import { Icon } from "@iconify/react"; import { Icon } from "@iconify/react";
import clsx from "clsx"; import clsx from "clsx";
import { useState, useRef, useEffect } from "react"; import React, { useState, useRef, useEffect, useReducer } from "react";
export const RestoreWindowsButton = ({ onClick, className, ...props}: React.ComponentProps<"button">) => {
const windowManager = useWindowManager();
const isWindowsDataDirty = !windowManager.windows.find(w =>
w.closed == true
|| w.minimized == true
|| (w.offset.x != 0 && w.offset.y != 0)
)
return (
<button
className={clsx("bg-primary border border-[#FFA826]", className, isWindowsDataDirty && "hidden")}
onClick={windowManager.resetAll}
{...props}
/>
)
}
export const FakeRelativeWindow = ({ export const FakeRelativeWindow = ({
windowText, windowText,
@ -17,12 +36,15 @@ export const FakeRelativeWindow = ({
withAnim?: boolean, withAnim?: boolean,
children: React.ReactNode children: React.ReactNode
}) => { }) => {
const [isMinimized, setMinimize] = useState(false); const windowManager = useWindowManager();
const [offset, setOffset] = useState({ x: 0, y: 0 }); const windowName = windowText.toLocaleLowerCase();
const currentWindow = windowManager.get(windowName);
const [animation, setAnimation] = useState({ const [animation, setAnimation] = useState({
window: "animate-window-popup", window: "animate-window-popup",
content: "animate-[fade-in-half_1s]" content: "animate-[fade-in-half_1s]"
}); });
const popupRef = useRef<HTMLDivElement>(null); const popupRef = useRef<HTMLDivElement>(null);
const pos = useRef({ const pos = useRef({
dragging: false, dragging: false,
@ -32,6 +54,32 @@ export const FakeRelativeWindow = ({
y: 0 y: 0
}); });
const populateWindow = () => {
windowManager.add({
name: windowName,
closed: false,
minimized: false,
offset: { x: 0, y: 0 }
})
}
useEffect(() => {
if (!windowManager.isLocalDataExists) {
if (!currentWindow) populateWindow();
return () => {
windowManager.remove(windowName);
}
}
}, []);
useEffect(() => {
console.log(windowManager.windows)
}, [windowManager.windows]);
useEffect(() => {
if (popupRef.current) popupRef.current.style.transform = `translate(${currentWindow?.offset.x || 0}px, ${currentWindow?.offset.y || 0}px)`;
}, [currentWindow?.offset])
useEffect(() => { useEffect(() => {
if (!withAnim) return; if (!withAnim) return;
const node = popupRef.current; const node = popupRef.current;
@ -56,16 +104,17 @@ export const FakeRelativeWindow = ({
return () => observer.disconnect(); return () => observer.disconnect();
}, []); }, []);
const toggleMinimize = () => setMinimize(!isMinimized); const toggleMinimize = () => windowManager.toggleMinimize(windowName);
const handleClose = () => windowManager.close(windowName);
const onMouseDown = (e: React.MouseEvent) => { const onMouseDown = (e: React.MouseEvent) => {
if (!draggable) return; if (!draggable || !currentWindow) return;
if (popupRef.current) { if (popupRef.current) {
pos.current.dragging = true; pos.current.dragging = true;
pos.current.mouseX = e.clientX; pos.current.mouseX = e.clientX;
pos.current.mouseY = e.clientY; pos.current.mouseY = e.clientY;
pos.current.x = offset.x; pos.current.x = currentWindow.offset.x;
pos.current.y = offset.y; pos.current.y = currentWindow.offset.y;
document.body.style.userSelect = "none"; document.body.style.userSelect = "none";
} }
window.addEventListener("mousemove", onMouseMove); window.addEventListener("mousemove", onMouseMove);
@ -80,16 +129,21 @@ export const FakeRelativeWindow = ({
}; };
const onMouseMove = (e: MouseEvent) => { const onMouseMove = (e: MouseEvent) => {
if (!currentWindow) return;
if (pos.current.dragging && popupRef.current) { if (pos.current.dragging && popupRef.current) {
const dx = e.clientX - pos.current.mouseX; const dx = e.clientX - pos.current.mouseX;
const dy = e.clientY - pos.current.mouseY; const dy = e.clientY - pos.current.mouseY;
const newX = pos.current.x + dx; const newX = pos.current.x + dx;
const newY = pos.current.y + dy; const newY = pos.current.y + dy;
popupRef.current.style.transform = `translate(${newX}px, ${newY}px)`; windowManager.move(windowName, {
setOffset({ x: newX, y: newY }); x: newX,
y: newY
});
} }
}; };
if (!currentWindow || currentWindow?.closed) return
return ( return (
<div className={clsx("absolute hidden lg:block", className)}> <div className={clsx("absolute hidden lg:block", className)}>
<div className={clsx("mx-auto md:border bg-background border-primary", withAnim && animation.window)} ref={popupRef}> <div className={clsx("mx-auto md:border bg-background border-primary", withAnim && animation.window)} ref={popupRef}>
@ -98,14 +152,24 @@ export const FakeRelativeWindow = ({
onMouseDown={onMouseDown} onMouseDown={onMouseDown}
> >
<div className="ms-1 pointer-events-none"> <div className="ms-1 pointer-events-none">
{windowText} {currentWindow ? currentWindow.name : "Error!"}
</div> </div>
<div className="flex gap-2"> <div className="flex gap-2">
<button className="bg-primary border border-[#FFA826] border-outset p-1" onClick={toggleMinimize}><Icon icon="lucide:minus"/></button> <button
<button className="bg-primary border border-[#FFA826] border-outset p-1"><Icon icon="lucide:x"/></button> className="bg-primary border border-[#FFA826] border-outset p-1"
onClick={toggleMinimize}
>
<Icon icon="lucide:minus"/>
</button>
<button
className="bg-primary border border-[#FFA826] border-outset p-1"
onClick={handleClose}
>
<Icon icon="lucide:x"/>
</button>
</div> </div>
</div> </div>
<div className={clsx("m-1 border border-primary", isMinimized ? "h-0 overflow-y-clip" : "h-fit")}> <div className={clsx("m-1 border border-primary", currentWindow?.minimized ? "h-0 overflow-y-clip" : "h-fit")}>
<div className={clsx("md:p-4", withAnim && animation.content)}> <div className={clsx("md:p-4", withAnim && animation.content)}>
{children} {children}
</div> </div>

View File

@ -8,10 +8,8 @@ export const FloatingLabel = ({
children: React.ReactNode; children: React.ReactNode;
}) => { }) => {
return ( return (
<div>
<PopoverText text={placeholder}> <PopoverText text={placeholder}>
{children} {children}
</PopoverText> </PopoverText>
</div>
); );
}; };

View File

@ -1,3 +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 document 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.

View File

@ -1,21 +1,21 @@
# Terms and Conditions # Terms
## 1. Acceptance of Terms ## Acceptance of Terms
By accessing and using this website (“nonszy.space”), you agree to be bound by these Terms and Conditions. If you do not agree with any part of these Terms and Conditions, you are advised not to use this Site. By accessing and using this website (“nonszy.space”), you agree to be bound by these Terms and Conditions. If you do not agree with any part of these Terms and Conditions, you are advised not to use this Site.
## 2. Third Party Intellectual Property Rights ## Third Party Intellectual Property Rights
Some materials on this Site, **such as the Coral Glasses character, or the ENA Dream BBQ game and ENA Series, are the property of <a href='https://joelgc.com' className='text-primary underline'>JoelG</a>** and are used under fair use. The Site owner does not claim any rights to these materials. All copyrights and trademarks remain the property of their respective owners. Some materials on this Site, **such as the Coral Glasses character, or the ENA Dream BBQ game and ENA Series, are the property of <a href='https://joelgc.com' className='text-primary underline'>JoelG</a>** and are used under fair use. The Site owner does not claim any rights to these materials. All copyrights and trademarks remain the property of their respective owners.
## 3. Content Ownership and Copyright ## Content Ownership and Copyright
Some materials on this Site, including but not limited to **applications, code, digital works, 2D illustrations, 3D works, designs, and OC (Original Characters) such as Nola, that owned by the site owner**, are protected by copyright and intellectual property rights in accordance with applicable laws and regulations. Some materials on this Site, including but not limited to **applications, code, digital works, 2D illustrations, 3D works, designs, and OC (Original Characters) such as Nola, that owned by the site owner**, are protected by copyright and intellectual property rights in accordance with applicable laws and regulations.
- Content may only be used for personal and non-commercial purposes unless written permission is obtained. - Content may only be used for personal and non-commercial purposes unless written permission is obtained.
- It is prohibited to reproduce, modify, distribute, sell, or utilize the content on this Site for commercial purposes without written permission. - It is prohibited to reproduce, modify, distribute, sell, or utilize the content on this Site for commercial purposes without written permission.
## 4. Prohibited Uses for AI Training ## Prohibited Uses for AI Training
All content on this Site is **strictly prohibited from being used for training, developing, or improving artificial intelligence (AI) models**, including but not limited to: All content on this Site is **strictly prohibited from being used for training, developing, or improving artificial intelligence (AI) models**, including but not limited to:
@ -25,7 +25,7 @@ All content on this Site is **strictly prohibited from being used for training,
Any violation of these terms may be subject to legal action in accordance with applicable copyright and intellectual property laws. Any violation of these terms may be subject to legal action in accordance with applicable copyright and intellectual property laws.
## 5. User Responsibility ## User Responsibility
Users are prohibited from: Users are prohibited from:
@ -33,14 +33,14 @@ Users are prohibited from:
- Uploading or distributing harmful material, including malware or illegal content. - Uploading or distributing harmful material, including malware or illegal content.
- Using the Site to violate applicable laws or regulations. - Using the Site to violate applicable laws or regulations.
## 6. External Links ## External Links
This Site may contain links to third-party sites. The Site owner is not responsible for the content, policies, or practices of such external sites. This Site may contain links to third-party sites. The Site owner is not responsible for the content, policies, or practices of such external sites.
## 7. Disclaimer ## Disclaimer
The Site is provided “as is” without warranty of any kind. The Site owner is not responsible for any direct or indirect losses resulting from the use of the Site. The Site is provided “as is” without warranty of any kind. The Site owner is not responsible for any direct or indirect losses resulting from the use of the Site.
## 8. Changes to Terms and Conditions ## Changes to Terms and Conditions
These Terms and Conditions are subject to change at any time without prior notice. The latest version will be published on this page and will be effective from the date of publication. These Terms and Conditions are subject to change at any time without prior notice. The latest version will be published on this page and will be effective from the date of publication.

View File

@ -1,6 +1,6 @@
import { Icon } from "@iconify/react"; import { Icon } from "@iconify/react";
import { FloatingLabel } from "@/components/floating-label"; import { FloatingLabel } from "@/components/floating-label";
import { FakeRelativeWindow } from "./client-windows"; import { FakeRelativeWindow, RestoreWindowsButton } from "./client-windows";
import Image from "next/image" import Image from "next/image"
import Link from "next/link"; import Link from "next/link";
@ -16,6 +16,10 @@ export const FakeWindow = ({
<div className="ms-1 pointer-events-none"> <div className="ms-1 pointer-events-none">
{windowText} {windowText}
</div> </div>
<div className="inline-flex">
<RestoreWindowsButton className="border-outset px-2 text-xs me-2">
Restore Windows
</RestoreWindowsButton>
<FloatingLabel placeholder="Useless button btw"> <FloatingLabel placeholder="Useless button btw">
<div className="flex gap-2"> <div className="flex gap-2">
<button className="bg-primary border border-[#FFA826] border-outset p-1"><Icon icon="lucide:minus"/></button> <button className="bg-primary border border-[#FFA826] border-outset p-1"><Icon icon="lucide:minus"/></button>
@ -24,6 +28,7 @@ export const FakeWindow = ({
</FloatingLabel> </FloatingLabel>
</div> </div>
</div> </div>
</div>
<div className="m-1 md:border border-primary"> <div className="m-1 md:border border-primary">
<div className="md:p-8"> <div className="md:p-8">
{children} {children}
@ -34,23 +39,6 @@ export const FakeWindow = ({
export const HomeWindows = () => ( export const HomeWindows = () => (
<div className="relative"> <div className="relative">
{/* <FakeRelativeWindow
windowText="featured.exe"
className="left-[540px] top-0 z-20"
draggable
>
<div className="space-y-2" style={{ width: 300 }}>
<Image
className=""
alt="Left 4 Dead"
src="https://shared.fastly.steamstatic.com/store_item_assets/steam/apps/550/header.jpg?t=1745368562"
width={300}
height={200}
unoptimized
/>
<p>Join my Left 4 Dead 2 server!</p>
</div>
</FakeRelativeWindow> */}
<FakeRelativeWindow <FakeRelativeWindow
windowText="nola.png" windowText="nola.png"
className="-right-[73%] top-[1300px] z-20" className="-right-[73%] top-[1300px] z-20"

View File

@ -1,9 +1,91 @@
interface iFakeWindow { 'use client'
import React, { createContext, useContext, useEffect, useState } from "react";
export interface FakeWindow {
name: string; name: string;
minimized: boolean; minimized: boolean;
closed: boolean; closed: boolean;
offset: { offset: {
x: number x: number;
y: number y: number;
} }
} }
interface WindowManagerContextType {
windows: FakeWindow[];
isLocalDataExists: boolean;
get: (name: string) => FakeWindow | undefined;
add: (window: FakeWindow) => void;
updateWindow: (name: string, changes: Partial<FakeWindow>) => void;
toggleMinimize: (name: string) => void;
close: (name: string) => void;
remove: (name: string) => void;
move: (name: string, offset: { x: number; y: number }) => void;
resetAll: () => void;
}
const WindowManagerContext = createContext<WindowManagerContextType | undefined>(undefined);
export const WindowManagerProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
const [windows, setWindows] = useState<FakeWindow[]>([]);
const [isInit, setInit] = useState(false);
const [isLocalDataExists, setExists] = useState(false);
useEffect(() => {
const data = localStorage.getItem("fake-windows-data");
if (data) {
setWindows(JSON.parse(data));
setExists(true);
}
setInit(true);
}, []);
useEffect(() => {
if (isInit && typeof window !== 'undefined' && windows.length > 0) {
window.localStorage.setItem('fake-windows-data', JSON.stringify(windows));
}
}, [windows]);
const get = (name: string) => windows.find(window => window.name == name);
const add = (window: FakeWindow) => setWindows(w => [...w, window]);
const updateWindow = (name: string, changes: Partial<FakeWindow>) =>
setWindows(w =>
w.map(win => win.name === name ? { ...win, ...changes } : win)
);
const toggleMinimize = (name: string) =>
setWindows(w =>
w.map(win => win.name === name ? { ...win, minimized: !win.minimized } : win)
);
const open = (name: string) => updateWindow(name, { closed: false });
const close = (name: string) => updateWindow(name, { closed: true });
const move = (name: string, offset: { x: number; y: number }) =>
updateWindow(name, { offset });
const remove = (name: string) => setWindows(w => w.filter(win => win.name !== name));
const resetAll = () => setWindows(w =>
w.map(win => ({
name: win.name,
closed: false,
minimized: false,
offset: { x: 0, y: 0 }
}))
);
return (
<WindowManagerContext.Provider value={{
windows,
isLocalDataExists,
get, add, updateWindow, toggleMinimize, close, move, remove, resetAll
}}>
{children}
</WindowManagerContext.Provider>
);
};
export function useWindowManager() {
const ctx = useContext(WindowManagerContext);
if (!ctx) throw new Error("useWindowManager must be used within WindowManagerProvider");
return ctx;
}