Loading packages/client/src/components/CanvasWrapper.tsx +2 −0 Original line number Diff line number Diff line Loading @@ -13,6 +13,7 @@ import { KeybindManager } from "../lib/keybinds"; import { BlankOverlay } from "./Overlay/BlankOverlay"; import { HeatmapOverlay } from "./Overlay/HeatmapOverlay"; import { useTemplateContext } from "../contexts/TemplateContext"; import { PixelPulses } from "./Overlay/PixelPulses"; export const CanvasWrapper = () => { const { config } = useAppContext(); Loading @@ -23,6 +24,7 @@ export const CanvasWrapper = () => { <PanZoomWrapper> <BlankOverlay /> <HeatmapOverlay /> <PixelPulses /> {config && <Template />} <CanvasInner /> <Cursor /> Loading packages/client/src/components/Header/User.tsx +1 −1 Original line number Diff line number Diff line Loading @@ -7,7 +7,7 @@ export const User = () => { return user ? ( <Card> <UserElement name={user.user.username} name={user.user.display_name || user.user.username} description={user.service.instance.hostname} avatarProps={{ showFallback: true, Loading packages/client/src/components/Overlay/OverlaySettings.tsx +10 −1 Original line number Diff line number Diff line Loading @@ -2,7 +2,7 @@ import { Slider, Spinner, Switch } from "@nextui-org/react"; import { useAppContext } from "../../contexts/AppContext"; export const OverlaySettings = () => { const { blankOverlay, setBlankOverlay, heatmapOverlay, setHeatmapOverlay } = const { blankOverlay, setBlankOverlay, heatmapOverlay, setHeatmapOverlay, pixelPulses, setPixelPulses } = useAppContext(); return ( Loading Loading @@ -56,6 +56,15 @@ export const OverlaySettings = () => { getValue={(v) => (v as number) * 100 + "%"} /> )} <Switch isSelected={pixelPulses} onValueChange={(v) => setPixelPulses(v) } > New Pixel Pulses </Switch> </section> </div> ); Loading packages/client/src/components/Overlay/PixelPulses.tsx 0 → 100644 +59 −0 Original line number Diff line number Diff line import { CSSProperties, useEffect, useState } from "react"; import { useAppContext } from "../../contexts/AppContext"; import network from "../../lib/network"; import { Pixel } from "@sc07-canvas/lib/src/net"; import { Canvas } from "../../lib/canvas"; export const PixelPulses = () => { const { pixelPulses } = useAppContext(); const [pulses, setPulses] = useState<JSX.Element[]>([]); useEffect(() => { function handlePixel({ x, y, color }: Pixel) { if (!pixelPulses) { return; } const paletteColor = Canvas.instance?.Pallete.getColor(color); const pulseStyle: CSSProperties = { position: "absolute", zIndex: "100", left: x + "px", top: y + "px", width: "50px", height: "50px", border: `1px solid #${paletteColor?.hex || "000"}`, // default to black in the case it fails to load, but that shouldn't happen borderRadius: "100px", transform: "translate(-24.5px, -24.5px)", animationName: "pixel-pulse", animationTimingFunction: "ease-in-out", animationDuration: "2s", animationFillMode: "forwards", }; // used in the case of two pixels coming through for the same position // rare, but causes issues with react // even if the pixels are close to eachother, the ms will be different const timestamp = Date.now(); const pulseElement = ( <div key={`${x}-${y}-${timestamp}`} style={pulseStyle}></div> ); setPulses((prevPulses) => [...prevPulses, pulseElement]); setTimeout(() => { setPulses((prevPulses) => prevPulses.slice(1)); // Remove the oldest pulse after 3700ms }, 2500); } network.on("pixel", handlePixel); return () => { network.off("pixel", handlePixel); }; }, [pixelPulses]); return <div>{pulses}</div>; }; packages/client/src/components/Profile/UserCard.tsx +17 −2 Original line number Diff line number Diff line Loading @@ -2,7 +2,7 @@ import { faMessage, faWarning } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { Avatar, Button, Link, Spinner, User } from "@nextui-org/react"; import { ClientConfig } from "@sc07-canvas/lib/src/net"; import { MouseEvent, useEffect, useState } from "react"; import { MouseEvent, useEffect, useMemo, useState } from "react"; import { toast } from "react-toastify"; import { useAppContext } from "../../contexts/AppContext"; Loading Loading @@ -72,11 +72,26 @@ export const UserCard = ({ user }: { user: IUser }) => { setProfile(user.sub); }; const name = useMemo(() => { if (!user || !user.sub) { return 'Unknown' } const regex = /^(.*)@/; const match = user.sub.match(regex); if (match) { return match[1]; } return 'Unknown' }, [user]) return ( <div className="flex flex-col gap-1"> <div className="flex flex-row space-between p-2"> <User name={user?.display_name || 'Unknown'} name={user?.display_name || name} description={user?.sub || 'Unknown'} avatarProps={{ showFallback: true, Loading Loading
packages/client/src/components/CanvasWrapper.tsx +2 −0 Original line number Diff line number Diff line Loading @@ -13,6 +13,7 @@ import { KeybindManager } from "../lib/keybinds"; import { BlankOverlay } from "./Overlay/BlankOverlay"; import { HeatmapOverlay } from "./Overlay/HeatmapOverlay"; import { useTemplateContext } from "../contexts/TemplateContext"; import { PixelPulses } from "./Overlay/PixelPulses"; export const CanvasWrapper = () => { const { config } = useAppContext(); Loading @@ -23,6 +24,7 @@ export const CanvasWrapper = () => { <PanZoomWrapper> <BlankOverlay /> <HeatmapOverlay /> <PixelPulses /> {config && <Template />} <CanvasInner /> <Cursor /> Loading
packages/client/src/components/Header/User.tsx +1 −1 Original line number Diff line number Diff line Loading @@ -7,7 +7,7 @@ export const User = () => { return user ? ( <Card> <UserElement name={user.user.username} name={user.user.display_name || user.user.username} description={user.service.instance.hostname} avatarProps={{ showFallback: true, Loading
packages/client/src/components/Overlay/OverlaySettings.tsx +10 −1 Original line number Diff line number Diff line Loading @@ -2,7 +2,7 @@ import { Slider, Spinner, Switch } from "@nextui-org/react"; import { useAppContext } from "../../contexts/AppContext"; export const OverlaySettings = () => { const { blankOverlay, setBlankOverlay, heatmapOverlay, setHeatmapOverlay } = const { blankOverlay, setBlankOverlay, heatmapOverlay, setHeatmapOverlay, pixelPulses, setPixelPulses } = useAppContext(); return ( Loading Loading @@ -56,6 +56,15 @@ export const OverlaySettings = () => { getValue={(v) => (v as number) * 100 + "%"} /> )} <Switch isSelected={pixelPulses} onValueChange={(v) => setPixelPulses(v) } > New Pixel Pulses </Switch> </section> </div> ); Loading
packages/client/src/components/Overlay/PixelPulses.tsx 0 → 100644 +59 −0 Original line number Diff line number Diff line import { CSSProperties, useEffect, useState } from "react"; import { useAppContext } from "../../contexts/AppContext"; import network from "../../lib/network"; import { Pixel } from "@sc07-canvas/lib/src/net"; import { Canvas } from "../../lib/canvas"; export const PixelPulses = () => { const { pixelPulses } = useAppContext(); const [pulses, setPulses] = useState<JSX.Element[]>([]); useEffect(() => { function handlePixel({ x, y, color }: Pixel) { if (!pixelPulses) { return; } const paletteColor = Canvas.instance?.Pallete.getColor(color); const pulseStyle: CSSProperties = { position: "absolute", zIndex: "100", left: x + "px", top: y + "px", width: "50px", height: "50px", border: `1px solid #${paletteColor?.hex || "000"}`, // default to black in the case it fails to load, but that shouldn't happen borderRadius: "100px", transform: "translate(-24.5px, -24.5px)", animationName: "pixel-pulse", animationTimingFunction: "ease-in-out", animationDuration: "2s", animationFillMode: "forwards", }; // used in the case of two pixels coming through for the same position // rare, but causes issues with react // even if the pixels are close to eachother, the ms will be different const timestamp = Date.now(); const pulseElement = ( <div key={`${x}-${y}-${timestamp}`} style={pulseStyle}></div> ); setPulses((prevPulses) => [...prevPulses, pulseElement]); setTimeout(() => { setPulses((prevPulses) => prevPulses.slice(1)); // Remove the oldest pulse after 3700ms }, 2500); } network.on("pixel", handlePixel); return () => { network.off("pixel", handlePixel); }; }, [pixelPulses]); return <div>{pulses}</div>; };
packages/client/src/components/Profile/UserCard.tsx +17 −2 Original line number Diff line number Diff line Loading @@ -2,7 +2,7 @@ import { faMessage, faWarning } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { Avatar, Button, Link, Spinner, User } from "@nextui-org/react"; import { ClientConfig } from "@sc07-canvas/lib/src/net"; import { MouseEvent, useEffect, useState } from "react"; import { MouseEvent, useEffect, useMemo, useState } from "react"; import { toast } from "react-toastify"; import { useAppContext } from "../../contexts/AppContext"; Loading Loading @@ -72,11 +72,26 @@ export const UserCard = ({ user }: { user: IUser }) => { setProfile(user.sub); }; const name = useMemo(() => { if (!user || !user.sub) { return 'Unknown' } const regex = /^(.*)@/; const match = user.sub.match(regex); if (match) { return match[1]; } return 'Unknown' }, [user]) return ( <div className="flex flex-col gap-1"> <div className="flex flex-row space-between p-2"> <User name={user?.display_name || 'Unknown'} name={user?.display_name || name} description={user?.sub || 'Unknown'} avatarProps={{ showFallback: true, Loading