Merge branch 'placed-pixels' into 'main'

Pixel pulses & whois display name fix

See merge request sc07/canvas!21
This commit is contained in:
Grant 2024-07-15 22:30:13 +00:00
commit 95b61fa050
9 changed files with 109 additions and 5 deletions

View File

@ -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();
@ -23,6 +24,7 @@ export const CanvasWrapper = () => {
<PanZoomWrapper>
<BlankOverlay />
<HeatmapOverlay />
<PixelPulses />
{config && <Template />}
<CanvasInner />
<Cursor />

View File

@ -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,

View File

@ -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 (
@ -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>
);

View File

@ -0,0 +1,59 @@
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>;
};

View File

@ -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";
@ -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,

View File

@ -15,7 +15,7 @@ export const SidebarBase = ({children, shown, icon, setSidebarShown, title, desc
return (
<div>
<motion.div
className={`absolute w-screen h-screen z-50 left-0 top-0 bg-black`}
className={`absolute w-screen h-screen z-50 left-0 top-0 bg-black pointer-events-none`}
initial={{ opacity: 0, visibility: 'hidden' }}
animate={{ opacity: shown ? 0.25 : 0, visibility: shown ? 'visible' : 'hidden' }}
transition={{ type: 'spring', stiffness: 50 }}

View File

@ -38,6 +38,8 @@ interface IAppContext {
setBlankOverlay: React.Dispatch<React.SetStateAction<IMapOverlay>>;
heatmapOverlay: IMapOverlay;
setHeatmapOverlay: React.Dispatch<React.SetStateAction<IMapOverlay>>;
pixelPulses: boolean;
setPixelPulses: (state: boolean) => void
profile?: string; // sub
setProfile: (v?: string) => void;
@ -123,6 +125,7 @@ export const AppContext = ({ children }: PropsWithChildren) => {
opacity: 1,
loading: false,
});
const [pixelPulses, setPixelPulses] = useState<boolean>(false)
const [profile, setProfile] = useState<string>();
@ -229,6 +232,8 @@ export const AppContext = ({ children }: PropsWithChildren) => {
setBlankOverlay,
heatmapOverlay,
setHeatmapOverlay,
pixelPulses,
setPixelPulses,
profile,
setProfile,
infoSidebar,

View File

@ -201,6 +201,19 @@ main {
}
}
@keyframes pixel-pulse {
from {
width: 50px;
height: 50px;
transform: translate(-24.5px, -24.5px);
}
to {
width: 10px;
height: 10px;
transform: translate(-4.5px, -4.5px);
}
}
@import "./components/Toolbar/Palette.scss";
@import "./components/Templating/Template.scss";
@import "./board.scss";

View File

@ -227,6 +227,7 @@ export type AuthSession = {
};
user: {
username: string;
display_name?: string;
picture_url?: string;
};
};