added background to panel itself

This commit is contained in:
onysd 2026-09-08 02:02:18 +03:00
parent 87173ae43f
commit f7b3af48de
8 changed files with 122 additions and 58 deletions

View file

@ -0,0 +1,46 @@
import { useEffect, useRef } from "react";
import { BgIcons } from "./BgIcons";
// The product's background: three blurred orbs that drift with the pointer,
// and the field of slowly moving icons over them. Ported from the marketing
// site so the console reads as the same product.
//
// One component for both places it appears -- the sign-in screen and the
// workspace behind every page -- because two copies of a parallax handler is
// how they end up subtly different.
export function AppBackground({ className = "" }: { className?: string }) {
const orbsRef = useRef<HTMLDivElement>(null);
// The orbs drift with the pointer, the same 30px parallax the site uses.
// Written straight to the node instead of through state: this fires on every
// mouse move, and re-rendering the tree for a background offset would be a
// lot of work to move three blurred circles.
useEffect(() => {
// Someone who asked the system for less motion gets none of this. The CSS
// drift is already disabled for them, and a JS-driven transform would walk
// straight past that preference.
if (window.matchMedia?.("(prefers-reduced-motion: reduce)").matches) {
return;
}
function onMove(event: MouseEvent) {
const node = orbsRef.current;
if (!node) return;
const x = (event.clientX / window.innerWidth - 0.5) * 30;
const y = (event.clientY / window.innerHeight - 0.5) * 30;
node.style.transform = `translate(${x}px, ${y}px)`;
}
window.addEventListener("mousemove", onMove);
return () => window.removeEventListener("mousemove", onMove);
}, []);
return (
<div className={`app-background ${className}`.trim()} aria-hidden="true">
<div className="bg-orbs" ref={orbsRef}>
<div className="bg-orb bg-orb--1" />
<div className="bg-orb bg-orb--2" />
<div className="bg-orb bg-orb--3" />
</div>
<BgIcons />
</div>
);
}

View file

@ -37,6 +37,7 @@ import { permissionBotVerificationReview, permissionServerManage, permissionAdmi
import { type Navigate, type RouteState, routeTitle } from "../routing";
import { ThemeSwitch } from "../theme";
import { AddServerLinkModal } from "./AddServerLinkModal";
import { AppBackground } from "./AppBackground";
import { AppLink } from "./AppLink";
// Compresses a sorted (or unsorted) list of layer numbers into run-length
@ -338,6 +339,9 @@ export function Shell({
</header>
<main className="content">{children}</main>
</div>
{/* Behind everything, fixed to the viewport. The sidebar and topbar paint
over it, so it shows through the working area only. */}
<AppBackground className="app-background--workspace" />
</div>
);
}