From cd1766619da82803a29a20b331784808f8ca5575 Mon Sep 17 00:00:00 2001 From: dvorakmortonxd Date: Wed, 23 Sep 2026 23:55:30 +0200 Subject: [PATCH] added ability to drag apps wherever on desktop theme --- src/app/components/WindowsDesktop.tsx | 188 ++++++------ src/app/components/useDesktopIcons.ts | 412 ++++++++++++++++++++++++++ src/app/skeuo.css | 51 ++++ 3 files changed, 567 insertions(+), 84 deletions(-) create mode 100644 src/app/components/useDesktopIcons.ts diff --git a/src/app/components/WindowsDesktop.tsx b/src/app/components/WindowsDesktop.tsx index fb2d784..aa60515 100644 --- a/src/app/components/WindowsDesktop.tsx +++ b/src/app/components/WindowsDesktop.tsx @@ -6,7 +6,7 @@ import { APPS, APP_BY_ID, createWebsiteApp, type AppDef } from "./apps"; import WinWindow, { type WinState } from "./WinWindow"; import Clock from "./Clock"; import { useTheme } from "./useTheme"; -import { useDragOrder } from "./useDragOrder"; +import { useDesktopIcons } from "./useDesktopIcons"; import { WALLPAPER, friends } from "../data"; const TASKBAR_HEIGHT = 48; @@ -24,6 +24,16 @@ interface Shortcut { image?: string; } +interface IconEntry { + id: string; + label: string; + title: string; + glyph: ReactNode; + color?: string; + image?: string; + onOpen: () => void; +} + const SERVICE_SHORTCUTS: Shortcut[] = [ { id: "svc-proxmox", icon: "🖥️", label: "Proxmox", appId: "alacritty", color: "#1257a0", desc: "Server Management" }, { id: "svc-ai", icon: "🦾", label: "Llama.cpp", url: "https://ai.dvorakmortonxd.dev/", color: "#157347", desc: "Local AI Server" }, @@ -43,6 +53,13 @@ const FRIEND_SHORTCUTS: Shortcut[] = friends.map((f, i) => ({ desc: f.desc, })); +/** Stable list of every desktop icon, used to seed the placement grid. */ +const ICON_KEYS = [ + ...LEFT_APPS.map((a) => a.id), + ...SERVICE_SHORTCUTS.map((s) => s.id), + ...FRIEND_SHORTCUTS.map((f) => f.id), +]; + export default function WindowsDesktop() { const { theme, toggle } = useTheme(); @@ -67,13 +84,13 @@ export default function WindowsDesktop() { const [closingIds, setClosingIds] = useState([]); const [minimizingIds, setMinimizingIds] = useState([]); - const [leftApps, setLeftApps] = useState(LEFT_APPS); - const [serviceItems, setServiceItems] = useState(SERVICE_SHORTCUTS); - const [friendItems, setFriendItems] = useState(FRIEND_SHORTCUTS); + const leftApps = LEFT_APPS; + const serviceItems = SERVICE_SHORTCUTS; + const friendItems = FRIEND_SHORTCUTS; - const leftDrag = useDragOrder(setLeftApps); - const serviceDrag = useDragOrder(setServiceItems); - const friendDrag = useDragOrder(setFriendItems); + const desktopRef = useRef(null); + const { positions, dragId, onPointerDown, consumeDrag } = + useDesktopIcons(desktopRef, ICON_KEYS); const [dynamicApps, setDynamicApps] = useState>({}); const getApp = (id: string): AppDef | undefined => APP_BY_ID[id] ?? dynamicApps[id]; @@ -236,13 +253,79 @@ export default function WindowsDesktop() { const wallpaper = `url('${WALLPAPER}')`; - const iconClick = (drag: ReturnType, id: string, action: () => void) => { - if (drag.consumeDragged()) return; + const iconClick = (id: string, action: () => void) => { + if (consumeDrag()) return; activateIcon(id, action); }; + const leftEntries: IconEntry[] = leftApps.map((app) => ({ + id: app.id, + label: app.title, + title: `Open ${app.title}`, + glyph: app.icon, + color: app.color, + onOpen: () => openApp(app.id), + })); + const serviceEntries: IconEntry[] = serviceItems.map((s) => ({ + id: s.id, + label: s.label, + title: s.label, + glyph: s.icon, + onOpen: () => openShortcut(s), + })); + const friendEntries: IconEntry[] = friendItems.map((f) => ({ + id: f.id, + label: f.label, + title: f.label, + glyph: "🫂", + image: f.image, + onOpen: () => openShortcut(f), + })); + const allEntries = [...leftEntries, ...serviceEntries, ...friendEntries]; + + const renderIcon = (entry: IconEntry, interactive = true) => { + const pos = positions[entry.id]; + return ( + + ); + }; + return (
{ @@ -254,83 +337,20 @@ export default function WindowsDesktop() { >