taskbar handles many open windows: shrink buttons, scroll on overflow, keep active in view

This commit is contained in:
Martin Dvořák 2026-09-24 07:25:09 +00:00
commit 338146671b
3 changed files with 54 additions and 4 deletions

View file

@ -1,6 +1,6 @@
"use client";
import { useRef, useState, type ReactNode } from "react";
import { useEffect, useRef, useState, type ReactNode } from "react";
import Image from "next/image";
import { APPS, APP_BY_ID, createWebsiteApp, type AppDef } from "./apps";
import WinWindow, { type WinState } from "./WinWindow";
@ -89,9 +89,25 @@ export default function WindowsDesktop() {
const friendItems = FRIEND_SHORTCUTS;
const desktopRef = useRef<HTMLDivElement>(null);
const tbRef = useRef<HTMLDivElement>(null);
const { positions, dragId, onPointerDown, consumeDrag } =
useDesktopIcons(desktopRef, ICON_KEYS);
// When the taskbar buttons overflow, keep the focused window's button visible
// so opening an app doesn't leave its button off the (scrollable) right edge.
useEffect(() => {
const bar = tbRef.current;
const active = bar?.querySelector<HTMLElement>(".win-tb-btn.active");
if (!bar || !active) return;
const barRect = bar.getBoundingClientRect();
const btnRect = active.getBoundingClientRect();
if (btnRect.left < barRect.left) {
bar.scrollLeft += btnRect.left - barRect.left;
} else if (btnRect.right > barRect.right) {
bar.scrollLeft += btnRect.right - barRect.right;
}
}, [activeId]);
const [dynamicApps, setDynamicApps] = useState<Record<string, AppDef>>({});
const getApp = (id: string): AppDef | undefined => APP_BY_ID[id] ?? dynamicApps[id];
@ -452,7 +468,16 @@ export default function WindowsDesktop() {
</span>
</button>
<div className="win-tb-buttons">
<div
className="win-tb-buttons"
ref={tbRef}
onWheel={(e) => {
const bar = tbRef.current;
// Translate a vertical mouse wheel into horizontal scrolling while
// the button strip overflows, so every open app stays reachable.
if (bar && bar.scrollWidth > bar.clientWidth) bar.scrollLeft += e.deltaY;
}}
>
{wins.map((w) => {
const app = getApp(w.appId) ?? APP_BY_ID.welcome;
return (