Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
89f9194420
|
|||
|
53fa9c815f
|
|||
|
25e55272d9
|
|||
|
2a1258a820
|
|||
|
01ac4d61cf
|
@@ -19,6 +19,7 @@
|
|||||||
"ajv": "^8.17.1",
|
"ajv": "^8.17.1",
|
||||||
"ajv-formats": "^3.0.1",
|
"ajv-formats": "^3.0.1",
|
||||||
"awesome-ajv-errors": "^5.1.0",
|
"awesome-ajv-errors": "^5.1.0",
|
||||||
|
"lodash": "^4.17.21",
|
||||||
"next": "15.3.0",
|
"next": "15.3.0",
|
||||||
"react": "^19.1.0",
|
"react": "^19.1.0",
|
||||||
"react-dom": "^19.1.0",
|
"react-dom": "^19.1.0",
|
||||||
@@ -28,6 +29,7 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/eslintrc": "^3",
|
"@eslint/eslintrc": "^3",
|
||||||
"@tailwindcss/postcss": "^4",
|
"@tailwindcss/postcss": "^4",
|
||||||
|
"@types/lodash": "^4",
|
||||||
"@types/node": "^20",
|
"@types/node": "^20",
|
||||||
"@types/react": "^19",
|
"@types/react": "^19",
|
||||||
"@types/react-dom": "^19",
|
"@types/react-dom": "^19",
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
+1
-5
@@ -1,7 +1,6 @@
|
|||||||
import type { Metadata } from "next";
|
import type { Metadata } from "next";
|
||||||
import { Inter } from "next/font/google";
|
import { Inter } from "next/font/google";
|
||||||
import "./globals.css";
|
import "./globals.css";
|
||||||
import config from "../../public/config/config.json";
|
|
||||||
|
|
||||||
const inter = Inter({
|
const inter = Inter({
|
||||||
variable: "--font-inter",
|
variable: "--font-inter",
|
||||||
@@ -9,10 +8,7 @@ const inter = Inter({
|
|||||||
preload: true,
|
preload: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = { title: "Portfolio" };
|
||||||
title: config.name.join(" "),
|
|
||||||
description: "Portfolio",
|
|
||||||
};
|
|
||||||
|
|
||||||
export default function RootLayout({
|
export default function RootLayout({
|
||||||
children,
|
children,
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import {
|
|||||||
Text,
|
Text,
|
||||||
Html,
|
Html,
|
||||||
type PerspectiveCameraProps,
|
type PerspectiveCameraProps,
|
||||||
useProgress,
|
PerformanceMonitor,
|
||||||
} from "@react-three/drei";
|
} from "@react-three/drei";
|
||||||
import {
|
import {
|
||||||
animated as threeAnimated,
|
animated as threeAnimated,
|
||||||
@@ -26,11 +26,10 @@ import {
|
|||||||
Suspense,
|
Suspense,
|
||||||
useCallback,
|
useCallback,
|
||||||
type JSX,
|
type JSX,
|
||||||
type Dispatch,
|
|
||||||
type SetStateAction,
|
|
||||||
} from "react";
|
} from "react";
|
||||||
|
import round from "lodash/round";
|
||||||
import Stack from "@/util/stack";
|
import Stack from "@/util/stack";
|
||||||
import { Canvas, useFrame } from "@react-three/fiber";
|
import { Canvas } from "@react-three/fiber";
|
||||||
import { mdiArrowLeftBold } from "@mdi/js";
|
import { mdiArrowLeftBold } from "@mdi/js";
|
||||||
import { Icon } from "@mdi/react";
|
import { Icon } from "@mdi/react";
|
||||||
import { PDF } from "../util/PDF";
|
import { PDF } from "../util/PDF";
|
||||||
@@ -45,42 +44,21 @@ import { Credits } from "../ui/Credits";
|
|||||||
import { isWebGL2Available } from "@react-three/drei";
|
import { isWebGL2Available } from "@react-three/drei";
|
||||||
import { useWindowSize } from "../hooks/useWindowSize";
|
import { useWindowSize } from "../hooks/useWindowSize";
|
||||||
import { Info } from "../util/Info";
|
import { Info } from "../util/Info";
|
||||||
|
import { Loader } from "../ui/Loader";
|
||||||
|
|
||||||
const AnimatedCam = threeAnimated(PerspectiveCamera);
|
const AnimatedCam = threeAnimated(PerspectiveCamera);
|
||||||
const AnimatedButton = webAnimated.button as React.ComponentType<
|
const AnimatedButton = webAnimated.button as React.ComponentType<
|
||||||
React.ButtonHTMLAttributes<HTMLButtonElement> & { children?: React.ReactNode }
|
React.ButtonHTMLAttributes<HTMLButtonElement> & { children?: React.ReactNode }
|
||||||
>;
|
>;
|
||||||
|
|
||||||
function FpsUpdater({
|
|
||||||
onUpdate,
|
|
||||||
}: {
|
|
||||||
onUpdate: Dispatch<SetStateAction<number>>;
|
|
||||||
}) {
|
|
||||||
const fpsRef = useRef([0]);
|
|
||||||
useFrame((_, delta) => fpsRef.current.push(1 / delta));
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const id = setInterval(() => {
|
|
||||||
const avg =
|
|
||||||
fpsRef.current.reduce((a, b) => a + b, 0) / fpsRef.current.length;
|
|
||||||
fpsRef.current = [];
|
|
||||||
onUpdate(avg);
|
|
||||||
}, 1000);
|
|
||||||
|
|
||||||
return () => clearInterval(id);
|
|
||||||
}, [onUpdate]);
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function Scene(props: JSX.IntrinsicElements["group"]) {
|
export function Scene(props: JSX.IntrinsicElements["group"]) {
|
||||||
const { nodes, materials } = useGLTF("/scene.glb") as unknown as GLTFResult;
|
const { nodes, materials } = useGLTF("/scene.glb") as unknown as GLTFResult;
|
||||||
const { progress } = useProgress();
|
|
||||||
const { width, height } = useWindowSize();
|
const { width, height } = useWindowSize();
|
||||||
const config = useConfig();
|
const config = useConfig();
|
||||||
|
|
||||||
// States
|
// States
|
||||||
const [fps, setFps] = useState(0);
|
const [fps, setFps] = useState(0);
|
||||||
|
const [dpr, setDpr] = useState(2);
|
||||||
const [pendingView, setPendingView] = useState<View | null>(null);
|
const [pendingView, setPendingView] = useState<View | null>(null);
|
||||||
const [backHovered, setBackHovered] = useState(false);
|
const [backHovered, setBackHovered] = useState(false);
|
||||||
const [backClicked, setBackClicked] = useState(false);
|
const [backClicked, setBackClicked] = useState(false);
|
||||||
@@ -135,7 +113,6 @@ export function Scene(props: JSX.IntrinsicElements["group"]) {
|
|||||||
precision: 0.0001,
|
precision: 0.0001,
|
||||||
friction: 80,
|
friction: 80,
|
||||||
mass: 10,
|
mass: 10,
|
||||||
clamp: true,
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -151,6 +128,7 @@ export function Scene(props: JSX.IntrinsicElements["group"]) {
|
|||||||
{isWebGL2Available() ? (
|
{isWebGL2Available() ? (
|
||||||
width >= 1.5 * height ? (
|
width >= 1.5 * height ? (
|
||||||
<>
|
<>
|
||||||
|
<Loader />
|
||||||
<div className="pointer-events-none fixed z-[999999999] size-full">
|
<div className="pointer-events-none fixed z-[999999999] size-full">
|
||||||
<AnimatedButton
|
<AnimatedButton
|
||||||
style={{
|
style={{
|
||||||
@@ -178,32 +156,27 @@ export function Scene(props: JSX.IntrinsicElements["group"]) {
|
|||||||
</AnimatedButton>
|
</AnimatedButton>
|
||||||
<div className="min-w-12 text-white bottom-0 right-0 absolute m-3 p-1 text-xs text-right text-stroke-2 text-stroke-black paint-sfm">
|
<div className="min-w-12 text-white bottom-0 right-0 absolute m-3 p-1 text-xs text-right text-stroke-2 text-stroke-black paint-sfm">
|
||||||
<Info />
|
<Info />
|
||||||
{isNaN(fps) ? "-" : fps.toFixed(0)} fps
|
{fps > 0 && (
|
||||||
|
<>
|
||||||
|
{fps.toFixed(0)} fps | {dpr}x
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Canvas
|
<Canvas
|
||||||
shadows
|
shadows
|
||||||
|
dpr={dpr}
|
||||||
gl={{ localClippingEnabled: true, antialias: true, alpha: true }}
|
gl={{ localClippingEnabled: true, antialias: true, alpha: true }}
|
||||||
>
|
>
|
||||||
<Suspense
|
<Suspense fallback={null}>
|
||||||
fallback={
|
|
||||||
<Html fullscreen>
|
|
||||||
<div className="pt-10 w-screen h-screen flex flex-col space-y-6 justify-center items-center text-white text-4xl pointer-events-none">
|
|
||||||
<p>Loading...</p>
|
|
||||||
<div className="w-48 bg-neutral-700 h-4 rounded-lg">
|
|
||||||
<div
|
|
||||||
className="h-full rounded-lg bg-neutral-100"
|
|
||||||
style={{
|
|
||||||
width: `${progress.toFixed(0)}%`,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</Html>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<group {...props} dispose={null}>
|
<group {...props} dispose={null}>
|
||||||
<FpsUpdater onUpdate={setFps} />
|
<PerformanceMonitor
|
||||||
|
ms={100}
|
||||||
|
onChange={(api) => {
|
||||||
|
setFps(api.fps);
|
||||||
|
setDpr(round(1.5 * api.factor + 0.5, 1));
|
||||||
|
}}
|
||||||
|
>
|
||||||
<Environment preset="apartment" />
|
<Environment preset="apartment" />
|
||||||
<AnimatedCam makeDefault {...cameraSpring} />
|
<AnimatedCam makeDefault {...cameraSpring} />
|
||||||
<Buttons
|
<Buttons
|
||||||
@@ -244,21 +217,17 @@ export function Scene(props: JSX.IntrinsicElements["group"]) {
|
|||||||
currentView === View.PCView ? "auto" : "none"
|
currentView === View.PCView ? "auto" : "none"
|
||||||
}
|
}
|
||||||
occlude="blending"
|
occlude="blending"
|
||||||
className="w-[1452px] h-[810px] bg-neutral-400"
|
className="w-[1452px] h-[810px] bg-[#0e1838]"
|
||||||
scale={10}
|
scale={10}
|
||||||
position={[0, 170, 0.25]}
|
position={[0, 170, 0.5]}
|
||||||
raycast={
|
raycast={
|
||||||
currentView === View.DesktopView
|
currentView === View.DesktopView
|
||||||
? () => null
|
? () => null
|
||||||
: undefined
|
: undefined
|
||||||
}
|
}
|
||||||
distanceFactor={10}
|
distanceFactor={10}
|
||||||
style={{
|
|
||||||
backgroundImage: "url(/assets/pc-bg.webp)",
|
|
||||||
backgroundColor: "#111535",
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<div className="w-full h-full backdrop-blur-md">
|
<div className="size-full">
|
||||||
<PCUI />
|
<PCUI />
|
||||||
</div>
|
</div>
|
||||||
</Html>
|
</Html>
|
||||||
@@ -333,7 +302,7 @@ export function Scene(props: JSX.IntrinsicElements["group"]) {
|
|||||||
}
|
}
|
||||||
occlude="blending"
|
occlude="blending"
|
||||||
className="w-[1008px] h-[1614px] bg-blue-100"
|
className="w-[1008px] h-[1614px] bg-blue-100"
|
||||||
position={[0, 2.8, 0]}
|
position={[0, 2.85, 0]}
|
||||||
rotation={[-Math.PI / 2, 0, Math.PI / 2]}
|
rotation={[-Math.PI / 2, 0, Math.PI / 2]}
|
||||||
raycast={
|
raycast={
|
||||||
currentView === View.CellphoneView
|
currentView === View.CellphoneView
|
||||||
@@ -352,7 +321,7 @@ export function Scene(props: JSX.IntrinsicElements["group"]) {
|
|||||||
</group>
|
</group>
|
||||||
<Text
|
<Text
|
||||||
position={[-2.415, 12.5, -6]}
|
position={[-2.415, 12.5, -6]}
|
||||||
font="/assets/inter-bold.ttf"
|
font="/assets/clashdisplay.ttf"
|
||||||
color="black"
|
color="black"
|
||||||
fontSize={3}
|
fontSize={3}
|
||||||
>
|
>
|
||||||
@@ -360,7 +329,7 @@ export function Scene(props: JSX.IntrinsicElements["group"]) {
|
|||||||
</Text>
|
</Text>
|
||||||
<Text
|
<Text
|
||||||
position={[5.185, 12.5, 1.592]}
|
position={[5.185, 12.5, 1.592]}
|
||||||
font="/assets/inter-bold.ttf"
|
font="/assets/clashdisplay.ttf"
|
||||||
rotation={[0, -Math.PI / 2, 0]}
|
rotation={[0, -Math.PI / 2, 0]}
|
||||||
color="black"
|
color="black"
|
||||||
fontSize={3}
|
fontSize={3}
|
||||||
@@ -390,6 +359,7 @@ export function Scene(props: JSX.IntrinsicElements["group"]) {
|
|||||||
</Text>
|
</Text>
|
||||||
)}
|
)}
|
||||||
<StaticMeshes nodes={nodes} materials={materials} />
|
<StaticMeshes nodes={nodes} materials={materials} />
|
||||||
|
</PerformanceMonitor>
|
||||||
</group>
|
</group>
|
||||||
</Suspense>
|
</Suspense>
|
||||||
</Canvas>
|
</Canvas>
|
||||||
@@ -400,9 +370,9 @@ export function Scene(props: JSX.IntrinsicElements["group"]) {
|
|||||||
config.fallbackUrl ? "pt-12" : ""
|
config.fallbackUrl ? "pt-12" : ""
|
||||||
} flex flex-col space-y-6 w-screen h-screen text-center justify-center items-center text-white text-4xl`}
|
} flex flex-col space-y-6 w-screen h-screen text-center justify-center items-center text-white text-4xl`}
|
||||||
>
|
>
|
||||||
<p>Screen too small, please rotate</p>
|
<p className="mx-8">Screen too small, please rotate</p>
|
||||||
{config.fallbackUrl && (
|
{config.fallbackUrl && (
|
||||||
<p className="text-base">
|
<p className="text-base mx-8">
|
||||||
or visit the{" "}
|
or visit the{" "}
|
||||||
<a
|
<a
|
||||||
href={config.fallbackUrl}
|
href={config.fallbackUrl}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ export const Credits = ({ currentView }: CreditsProps) => {
|
|||||||
occlude="blending"
|
occlude="blending"
|
||||||
className="w-[1452px] h-[810px] bg-neutral-400"
|
className="w-[1452px] h-[810px] bg-neutral-400"
|
||||||
scale={10}
|
scale={10}
|
||||||
position={[0, 170, 0.25]}
|
position={[0, 170, 0.5]}
|
||||||
raycast={currentView === View.CreditsView ? () => null : undefined}
|
raycast={currentView === View.CreditsView ? () => null : undefined}
|
||||||
distanceFactor={10}
|
distanceFactor={10}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -0,0 +1,91 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { useProgress } from "@react-three/drei";
|
||||||
|
import { animated, useSpring, useTransition } from "@react-spring/web";
|
||||||
|
import { useEffect, useState, useRef } from "react";
|
||||||
|
import { createPortal } from "react-dom";
|
||||||
|
|
||||||
|
export const Loader = ({ minDuration = 750, fadeMs = 600 }) => {
|
||||||
|
const { progress } = useProgress();
|
||||||
|
const [loadedAt, setLoadedAt] = useState<number | null>(null);
|
||||||
|
|
||||||
|
const maxSeen = useRef(0);
|
||||||
|
if (progress > maxSeen.current) maxSeen.current = progress;
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (maxSeen.current === 100 && loadedAt === null) setLoadedAt(Date.now());
|
||||||
|
}, [loadedAt]);
|
||||||
|
|
||||||
|
const visible =
|
||||||
|
loadedAt === null || Date.now() - loadedAt < minDuration + fadeMs;
|
||||||
|
|
||||||
|
const barSpring = useSpring({
|
||||||
|
from: { width: "0%" },
|
||||||
|
to: { width: "100%" },
|
||||||
|
config: { duration: minDuration },
|
||||||
|
});
|
||||||
|
|
||||||
|
const overlay = useTransition(visible, {
|
||||||
|
from: { opacity: 1 },
|
||||||
|
enter: { opacity: 1 },
|
||||||
|
leave: { opacity: 0 },
|
||||||
|
config: { duration: fadeMs, easing: (t) => Math.pow(t, 2) },
|
||||||
|
});
|
||||||
|
|
||||||
|
return createPortal(
|
||||||
|
overlay(
|
||||||
|
(styles, show) =>
|
||||||
|
show && (
|
||||||
|
// @ts-expect-error children not typed bug
|
||||||
|
<animated.div
|
||||||
|
style={{
|
||||||
|
...styles,
|
||||||
|
position: "fixed",
|
||||||
|
inset: 0,
|
||||||
|
background: "#1b1b1b",
|
||||||
|
zIndex: 999999999,
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
alignItems: "center",
|
||||||
|
justifyContent: "center",
|
||||||
|
gap: "1.5rem",
|
||||||
|
fontSize: "2.25rem",
|
||||||
|
color: "white",
|
||||||
|
pointerEvents: "none",
|
||||||
|
paddingTop: "2.5rem",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<p>Loading…</p>
|
||||||
|
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
width: 192,
|
||||||
|
height: 16,
|
||||||
|
background: "#4b4b4b",
|
||||||
|
borderRadius: 8,
|
||||||
|
overflow: "hidden",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{/* @ts-expect-error children not typed bug */}
|
||||||
|
<animated.div
|
||||||
|
style={{
|
||||||
|
...barSpring,
|
||||||
|
height: "100%",
|
||||||
|
background: "#ffffff",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{/* @ts-expect-error children not typed bug */}
|
||||||
|
<animated.div className="text-[#1b1b1b] text-xs justify-center flex items-center h-full">
|
||||||
|
{barSpring.width.to((w) => {
|
||||||
|
const p = parseInt(w) || 0;
|
||||||
|
return `${p > 5 ? p : ""}`;
|
||||||
|
})}
|
||||||
|
</animated.div>
|
||||||
|
</animated.div>
|
||||||
|
</div>
|
||||||
|
</animated.div>
|
||||||
|
)
|
||||||
|
),
|
||||||
|
document.body
|
||||||
|
);
|
||||||
|
};
|
||||||
+13
-13
@@ -308,11 +308,11 @@ const Window: FC<HTMLAttributes<HTMLDivElement>> = ({ children, ...props }) => {
|
|||||||
<div className="flex h-full space-x-1">
|
<div className="flex h-full space-x-1">
|
||||||
<Icon
|
<Icon
|
||||||
path={mdiFolder}
|
path={mdiFolder}
|
||||||
className="text-neutral-400 h-full w-fit rounded-tl-lg rounded-br-lg transition-all hover:bg-blue-800 hover:ring-blue-500 hover:ring-1 p-1.5"
|
className="text-neutral-400 size-8 rounded-tl-lg rounded-br-lg transition-all hover:bg-blue-800 hover:ring-blue-500 hover:ring-1 p-1.5"
|
||||||
/>
|
/>
|
||||||
<Icon
|
<Icon
|
||||||
path={mdiPin}
|
path={mdiPin}
|
||||||
className="text-neutral-400 h-full w-fit rounded-b-lg transition-all hover:bg-blue-800 hover:ring-blue-500 hover:ring-1 p-1.5"
|
className="text-neutral-400 size-8 rounded-b-lg transition-all hover:bg-blue-800 hover:ring-blue-500 hover:ring-1 p-1.5"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<p className="absolute left-1/2 transform -translate-x-1/2 text-white">
|
<p className="absolute left-1/2 transform -translate-x-1/2 text-white">
|
||||||
@@ -321,21 +321,21 @@ const Window: FC<HTMLAttributes<HTMLDivElement>> = ({ children, ...props }) => {
|
|||||||
<div className="flex h-full space-x-1 ml-auto justify-end">
|
<div className="flex h-full space-x-1 ml-auto justify-end">
|
||||||
<Icon
|
<Icon
|
||||||
path={mdiWindowMinimize}
|
path={mdiWindowMinimize}
|
||||||
className="text-neutral-100 h-full w-fit rounded-b-lg transition-all hover:bg-amber-800 hover:ring-amber-500 hover:ring-1 p-1.5"
|
className="text-neutral-100 size-8 rounded-b-lg transition-all hover:bg-amber-800 hover:ring-amber-500 hover:ring-1 p-1.5"
|
||||||
/>
|
/>
|
||||||
<Icon
|
<Icon
|
||||||
path={mdiWindowRestore}
|
path={mdiWindowRestore}
|
||||||
className="text-neutral-100 h-full w-fit rounded-b-lg transition-all hover:bg-green-800 hover:ring-green-500 hover:ring-1 p-1.5"
|
className="text-neutral-100 size-8 rounded-b-lg transition-all hover:bg-green-800 hover:ring-green-500 hover:ring-1 p-1.5"
|
||||||
/>
|
/>
|
||||||
<Icon
|
<Icon
|
||||||
path={mdiWindowClose}
|
path={mdiWindowClose}
|
||||||
className="text-neutral-100 h-full w-fit rounded-tr-lg rounded-bl-lg transition-all hover:bg-red-800 hover:ring-red-500 hover:ring-1 p-1.5"
|
className="text-neutral-100 size-8 rounded-tr-lg rounded-bl-lg transition-all hover:bg-red-800 hover:ring-red-500 hover:ring-1 p-1.5"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex bg-neutral-950 size-full rounded-b-lg text-white">
|
<div className="flex bg-neutral-950 size-full rounded-b-lg text-white">
|
||||||
<div className="h-full w-fit bg-neutral-950 flex flex-col rounded-bl-lg">
|
<div className="h-full w-fit bg-neutral-950 flex flex-col rounded-bl-lg">
|
||||||
<div className="h-14 p-2 pr-1 flex justify-center w-fit space-x-1">
|
<div className="h-14 p-2 pr-1 flex justify-center w-36 space-x-1">
|
||||||
<Icon
|
<Icon
|
||||||
path={mdiArrowLeft}
|
path={mdiArrowLeft}
|
||||||
className="text-neutral-100 h-full w-fit rounded-md transition-all hover:ring-neutral-500 hover:ring-1 p-2"
|
className="text-neutral-100 h-full w-fit rounded-md transition-all hover:ring-neutral-500 hover:ring-1 p-2"
|
||||||
@@ -402,7 +402,7 @@ const Window: FC<HTMLAttributes<HTMLDivElement>> = ({ children, ...props }) => {
|
|||||||
>
|
>
|
||||||
<Icon
|
<Icon
|
||||||
path={mdiHelp}
|
path={mdiHelp}
|
||||||
className="text-neutral-100 h-full w-fit rounded-md transition-all hover:ring-neutral-500 hover:ring-1 p-2"
|
className="text-neutral-100 size-11 rounded-md transition-all hover:ring-neutral-500 hover:ring-1 p-2"
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -417,7 +417,7 @@ const Window: FC<HTMLAttributes<HTMLDivElement>> = ({ children, ...props }) => {
|
|||||||
defaultValue="/home/ahmed/Desktop/projects"
|
defaultValue="/home/ahmed/Desktop/projects"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex justify-center h-full w-fit space-x-1">
|
<div className="flex justify-center h-full w-36 space-x-1">
|
||||||
<Icon
|
<Icon
|
||||||
path={mdiBackspace}
|
path={mdiBackspace}
|
||||||
className="text-neutral-100 h-full w-fit rounded-md transition-all hover:ring-neutral-500 hover:ring-1 p-2"
|
className="text-neutral-100 h-full w-fit rounded-md transition-all hover:ring-neutral-500 hover:ring-1 p-2"
|
||||||
@@ -446,7 +446,7 @@ const Taskbar = () => {
|
|||||||
<div className="flex space-x-4 h-full w-fit items-center">
|
<div className="flex space-x-4 h-full w-fit items-center">
|
||||||
<SiArchlinux
|
<SiArchlinux
|
||||||
color={SiArchlinuxHex}
|
color={SiArchlinuxHex}
|
||||||
className="h-full w-fit transition-transform hover:scale-110"
|
className="size-10 transition-transform hover:scale-110"
|
||||||
/>
|
/>
|
||||||
<div className="w-8 h-full">
|
<div className="w-8 h-full">
|
||||||
<div className="w-full h-1/2 bg-blue-900 outline-1 outline-blue-600 transition-all hover:bg-blue-700 hover:outline-blue-400" />
|
<div className="w-full h-1/2 bg-blue-900 outline-1 outline-blue-600 transition-all hover:bg-blue-700 hover:outline-blue-400" />
|
||||||
@@ -454,19 +454,19 @@ const Taskbar = () => {
|
|||||||
</div>
|
</div>
|
||||||
<Icon
|
<Icon
|
||||||
path={mdiFolder}
|
path={mdiFolder}
|
||||||
className="text-blue-500 h-full w-fit transition-transform hover:scale-110 border-b-2"
|
className="text-blue-500 size-10 transition-transform hover:scale-110 border-b-2"
|
||||||
/>
|
/>
|
||||||
<SiVscodium
|
<SiVscodium
|
||||||
color={SiVscodiumHex}
|
color={SiVscodiumHex}
|
||||||
className="h-full w-fit transition-transform hover:scale-110"
|
className="size-10 transition-transform hover:scale-110"
|
||||||
/>
|
/>
|
||||||
<Icon
|
<Icon
|
||||||
path={mdiConsole}
|
path={mdiConsole}
|
||||||
className="text-neutral-400 h-full w-fit transition-transform hover:scale-110"
|
className="text-neutral-400 size-10 transition-transform hover:scale-110"
|
||||||
/>
|
/>
|
||||||
<SiFirefoxbrowser
|
<SiFirefoxbrowser
|
||||||
color={SiFirefoxbrowserHex}
|
color={SiFirefoxbrowserHex}
|
||||||
className="h-full w-fit transition-transform hover:scale-110"
|
className="size-10 transition-transform hover:scale-110"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex space-x-2 h-full w-fit items-center">
|
<div className="flex space-x-2 h-full w-fit items-center">
|
||||||
|
|||||||
@@ -1021,6 +1021,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"@types/lodash@npm:^4":
|
||||||
|
version: 4.17.16
|
||||||
|
resolution: "@types/lodash@npm:4.17.16"
|
||||||
|
checksum: 10c0/cf017901b8ab1d7aabc86d5189d9288f4f99f19a75caf020c0e2c77b8d4cead4db0d0b842d009b029339f92399f49f34377dd7c2721053388f251778b4c23534
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"@types/node@npm:^20":
|
"@types/node@npm:^20":
|
||||||
version: 20.17.30
|
version: 20.17.30
|
||||||
resolution: "@types/node@npm:20.17.30"
|
resolution: "@types/node@npm:20.17.30"
|
||||||
@@ -3868,6 +3875,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"lodash@npm:^4.17.21":
|
||||||
|
version: 4.17.21
|
||||||
|
resolution: "lodash@npm:4.17.21"
|
||||||
|
checksum: 10c0/d8cbea072bb08655bb4c989da418994b073a608dffa608b09ac04b43a791b12aeae7cd7ad919aa4c925f33b48490b5cfe6c1f71d827956071dae2e7bb3a6b74c
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"loose-envify@npm:^1.0.0, loose-envify@npm:^1.4.0":
|
"loose-envify@npm:^1.0.0, loose-envify@npm:^1.4.0":
|
||||||
version: 1.4.0
|
version: 1.4.0
|
||||||
resolution: "loose-envify@npm:1.4.0"
|
resolution: "loose-envify@npm:1.4.0"
|
||||||
@@ -4535,6 +4549,7 @@ __metadata:
|
|||||||
"@react-three/drei": "npm:^10.0.7"
|
"@react-three/drei": "npm:^10.0.7"
|
||||||
"@react-three/fiber": "npm:^9.1.2"
|
"@react-three/fiber": "npm:^9.1.2"
|
||||||
"@tailwindcss/postcss": "npm:^4"
|
"@tailwindcss/postcss": "npm:^4"
|
||||||
|
"@types/lodash": "npm:^4"
|
||||||
"@types/node": "npm:^20"
|
"@types/node": "npm:^20"
|
||||||
"@types/react": "npm:^19"
|
"@types/react": "npm:^19"
|
||||||
"@types/react-dom": "npm:^19"
|
"@types/react-dom": "npm:^19"
|
||||||
@@ -4544,6 +4559,7 @@ __metadata:
|
|||||||
awesome-ajv-errors: "npm:^5.1.0"
|
awesome-ajv-errors: "npm:^5.1.0"
|
||||||
eslint: "npm:^9"
|
eslint: "npm:^9"
|
||||||
eslint-config-next: "npm:15.3.0"
|
eslint-config-next: "npm:15.3.0"
|
||||||
|
lodash: "npm:^4.17.21"
|
||||||
next: "npm:15.3.0"
|
next: "npm:15.3.0"
|
||||||
react: "npm:^19.1.0"
|
react: "npm:^19.1.0"
|
||||||
react-dom: "npm:^19.1.0"
|
react-dom: "npm:^19.1.0"
|
||||||
|
|||||||
Reference in New Issue
Block a user