Loading packages/client/src/components/App.tsx +2 −0 Original line number Diff line number Diff line Loading @@ -4,6 +4,7 @@ import { CanvasWrapper } from "./CanvasWrapper"; import { Pallete } from "./Pallete"; import { TemplateContext } from "../contexts/TemplateContext"; import { SettingsSidebar } from "./Settings/SettingsSidebar"; import { DebugModal } from "./Debug/DebugModal"; const App = () => { return ( Loading @@ -13,6 +14,7 @@ const App = () => { <CanvasWrapper /> <Pallete /> <DebugModal /> <SettingsSidebar /> </TemplateContext> </AppContext> Loading packages/client/src/components/Debug/DebugModal.tsx 0 → 100644 +66 −0 Original line number Diff line number Diff line import { useEffect, useState } from "react"; import { Debug, FlagCategory } from "@sc07-canvas/lib/src/debug"; import { Button, Modal, ModalBody, ModalContent, ModalFooter, ModalHeader, Switch, useDisclosure, } from "@nextui-org/react"; export const DebugModal = () => { const { isOpen, onOpen, onOpenChange } = useDisclosure(); useEffect(() => { const handleOpen = () => { onOpen(); }; Debug.on("openTools", handleOpen); return () => { Debug.off("openTools", handleOpen); }; }, []); return ( <Modal isOpen={isOpen} onOpenChange={onOpenChange} placement="center"> <ModalContent> {(onClose) => ( <> <ModalHeader className="flex flex-col gap-1"> Debug Tools </ModalHeader> <ModalBody> <Button onPress={() => Debug.openDebug()}> Open Debug Information </Button> {Debug.flags.getAll().map((flag, i, arr) => ( <> {arr[i - 1]?.category !== flag.category && ( <p>{FlagCategory[flag.category]}</p> )} <div key={flag.id}> <Switch size="sm" defaultSelected={flag.enabled} onValueChange={(v) => Debug.flags.setEnabled(flag.id, v)} > {flag.id} </Switch> </div> </> ))} </ModalBody> <ModalFooter> <Button onPress={onClose}>Close</Button> </ModalFooter> </> )} </ModalContent> </Modal> ); }; packages/client/src/components/Header.tsx +2 −0 Original line number Diff line number Diff line import { Button } from "@nextui-org/react"; import { useAppContext } from "../contexts/AppContext"; import { User } from "./Header/User"; import { Debug } from "@sc07-canvas/lib/src/debug"; export const Header = () => { const { setSettingsSidebar } = useAppContext(); Loading @@ -12,6 +13,7 @@ export const Header = () => { <div className="box"> <User /> <Button onClick={() => setSettingsSidebar(true)}>Settings</Button> <Button onClick={() => Debug.openDebugTools()}>debug</Button> </div> </header> ); Loading packages/lib/src/debug.ts 0 → 100644 +185 −0 Original line number Diff line number Diff line import EventEmitter from "eventemitter3"; interface DebugEvents { openTools(): void; } interface DebugArgs { point: [x: number, y: number, id?: string]; text: [str: any]; } export enum FlagCategory { "Renderer", "DebugMessages", "Uncategorized", } class ExperimentFlag { id: string; enabled: boolean; category: FlagCategory = FlagCategory.Uncategorized; constructor(id: string, defaultEnabled = false, category?: FlagCategory) { this.id = id; this.enabled = defaultEnabled; if (category) this.category = category; } } interface FlagEvents { enable(flag_id: string): void; disable(flag_id: string): void; } class FlagManager extends EventEmitter<FlagEvents> { flags: ExperimentFlag[]; constructor() { super(); this.flags = []; this.register( // RENDERER new ExperimentFlag( "PANZOOM_PINCH_TRANSFORM_1", false, FlagCategory.Renderer ), new ExperimentFlag( "PANZOOM_PINCH_TRANSFORM_2", false, FlagCategory.Renderer ), // DEBUG MESSAGES new ExperimentFlag( "PANZOOM_PINCH_DEBUG_MESSAGES", false, FlagCategory.DebugMessages ) ); } register(...flags: ExperimentFlag[]) { this.flags.push(...flags); } getFlag(flag: string) { return this.flags.find((f) => f.id === flag); } enabled(flag: string) { return this.getFlag(flag)?.enabled; } setEnabled(flagID: string, enabled: boolean) { const flag = this.flags.find((f) => f.id === flagID); if (!flag) throw new Error("Unknown flag " + flagID); flag.enabled = enabled; if (enabled) { this.emit("enable", flagID); } else { this.emit("disable", flagID); } } getAll() { return [...this.flags].sort((a, b) => a.category - b.category); } } /** * Debug wrapper * * Goals: * - toggle debug flags (similar to Discord experiments) * - open blank debug tab with useragent and any flags */ class Debugcl extends EventEmitter<DebugEvents> { readonly flags = new FlagManager(); constructor() { super(); } openDebug() { const wind = window.open("about:blank", "_blank"); if (!wind) { alert( "Failed to open debug tab. Is your anti-popup too powerful? Or did this get triggered from not a trusted event" ); return; } wind.document.write(` <h1>debug menu</h1> <pre>${JSON.stringify( { userAgent: navigator.userAgent, flags: this.flags .getAll() .filter((f) => f.enabled) .map((f) => f.id), }, null, 2 )}</pre> `); wind.document.close(); } openDebugTools() { this.emit("openTools"); } /** * Create debug marker * * Useful on touchscreen devices * * @param type * @param args * @returns */ debug<T extends keyof DebugArgs>(type: T, ...args: DebugArgs[T]) { switch (type) { case "point": { const [x, y, id] = args; if (document.getElementById("debug-" + id)) { document.getElementById("debug-" + id)!.style.top = y + "px"; document.getElementById("debug-" + id)!.style.left = x + "px"; return; } let el = document.createElement("div"); if (id) el.id = "debug-" + id; el.classList.add("debug-point"); el.style.setProperty("top", y + "px"); el.style.setProperty("left", x + "px"); document.body.appendChild(el); break; } case "text": { const [str] = args; // create debug box in canvas-meta if it doesn't exist if (!document.getElementById("canvas-meta-debug")) { let debugBox = document.createElement("div"); debugBox.id = "canvas-meta-debug"; debugBox.style.whiteSpace = "pre"; debugBox.style.unicodeBidi = "embed"; document.getElementById("canvas-meta")!.prepend(debugBox); } document.getElementById("canvas-meta-debug")!.innerText = typeof str === "string" ? str : JSON.stringify(str, null, 2); break; } } } } export const Debug = new Debugcl(); packages/lib/src/renderer/lib/zoom.utils.ts +2 −1 Original line number Diff line number Diff line import { Debug } from "../../debug"; import { PanZoom } from "../PanZoom"; export function handleCalculateZoomPositions( Loading @@ -17,7 +18,7 @@ export function handleCalculateZoomPositions( const calculatedPositionX = x - mouseX * scaleDifference; const calculatedPositionY = y - mouseY * scaleDifference; contextInstance.debug(calculatedPositionX, calculatedPositionY, "zoom"); // Debug.debug("point", calculatedPositionX, calculatedPositionY, "zoom"); // do not limit to bounds when there is padding animation, // it causes animation strange behaviour Loading Loading
packages/client/src/components/App.tsx +2 −0 Original line number Diff line number Diff line Loading @@ -4,6 +4,7 @@ import { CanvasWrapper } from "./CanvasWrapper"; import { Pallete } from "./Pallete"; import { TemplateContext } from "../contexts/TemplateContext"; import { SettingsSidebar } from "./Settings/SettingsSidebar"; import { DebugModal } from "./Debug/DebugModal"; const App = () => { return ( Loading @@ -13,6 +14,7 @@ const App = () => { <CanvasWrapper /> <Pallete /> <DebugModal /> <SettingsSidebar /> </TemplateContext> </AppContext> Loading
packages/client/src/components/Debug/DebugModal.tsx 0 → 100644 +66 −0 Original line number Diff line number Diff line import { useEffect, useState } from "react"; import { Debug, FlagCategory } from "@sc07-canvas/lib/src/debug"; import { Button, Modal, ModalBody, ModalContent, ModalFooter, ModalHeader, Switch, useDisclosure, } from "@nextui-org/react"; export const DebugModal = () => { const { isOpen, onOpen, onOpenChange } = useDisclosure(); useEffect(() => { const handleOpen = () => { onOpen(); }; Debug.on("openTools", handleOpen); return () => { Debug.off("openTools", handleOpen); }; }, []); return ( <Modal isOpen={isOpen} onOpenChange={onOpenChange} placement="center"> <ModalContent> {(onClose) => ( <> <ModalHeader className="flex flex-col gap-1"> Debug Tools </ModalHeader> <ModalBody> <Button onPress={() => Debug.openDebug()}> Open Debug Information </Button> {Debug.flags.getAll().map((flag, i, arr) => ( <> {arr[i - 1]?.category !== flag.category && ( <p>{FlagCategory[flag.category]}</p> )} <div key={flag.id}> <Switch size="sm" defaultSelected={flag.enabled} onValueChange={(v) => Debug.flags.setEnabled(flag.id, v)} > {flag.id} </Switch> </div> </> ))} </ModalBody> <ModalFooter> <Button onPress={onClose}>Close</Button> </ModalFooter> </> )} </ModalContent> </Modal> ); };
packages/client/src/components/Header.tsx +2 −0 Original line number Diff line number Diff line import { Button } from "@nextui-org/react"; import { useAppContext } from "../contexts/AppContext"; import { User } from "./Header/User"; import { Debug } from "@sc07-canvas/lib/src/debug"; export const Header = () => { const { setSettingsSidebar } = useAppContext(); Loading @@ -12,6 +13,7 @@ export const Header = () => { <div className="box"> <User /> <Button onClick={() => setSettingsSidebar(true)}>Settings</Button> <Button onClick={() => Debug.openDebugTools()}>debug</Button> </div> </header> ); Loading
packages/lib/src/debug.ts 0 → 100644 +185 −0 Original line number Diff line number Diff line import EventEmitter from "eventemitter3"; interface DebugEvents { openTools(): void; } interface DebugArgs { point: [x: number, y: number, id?: string]; text: [str: any]; } export enum FlagCategory { "Renderer", "DebugMessages", "Uncategorized", } class ExperimentFlag { id: string; enabled: boolean; category: FlagCategory = FlagCategory.Uncategorized; constructor(id: string, defaultEnabled = false, category?: FlagCategory) { this.id = id; this.enabled = defaultEnabled; if (category) this.category = category; } } interface FlagEvents { enable(flag_id: string): void; disable(flag_id: string): void; } class FlagManager extends EventEmitter<FlagEvents> { flags: ExperimentFlag[]; constructor() { super(); this.flags = []; this.register( // RENDERER new ExperimentFlag( "PANZOOM_PINCH_TRANSFORM_1", false, FlagCategory.Renderer ), new ExperimentFlag( "PANZOOM_PINCH_TRANSFORM_2", false, FlagCategory.Renderer ), // DEBUG MESSAGES new ExperimentFlag( "PANZOOM_PINCH_DEBUG_MESSAGES", false, FlagCategory.DebugMessages ) ); } register(...flags: ExperimentFlag[]) { this.flags.push(...flags); } getFlag(flag: string) { return this.flags.find((f) => f.id === flag); } enabled(flag: string) { return this.getFlag(flag)?.enabled; } setEnabled(flagID: string, enabled: boolean) { const flag = this.flags.find((f) => f.id === flagID); if (!flag) throw new Error("Unknown flag " + flagID); flag.enabled = enabled; if (enabled) { this.emit("enable", flagID); } else { this.emit("disable", flagID); } } getAll() { return [...this.flags].sort((a, b) => a.category - b.category); } } /** * Debug wrapper * * Goals: * - toggle debug flags (similar to Discord experiments) * - open blank debug tab with useragent and any flags */ class Debugcl extends EventEmitter<DebugEvents> { readonly flags = new FlagManager(); constructor() { super(); } openDebug() { const wind = window.open("about:blank", "_blank"); if (!wind) { alert( "Failed to open debug tab. Is your anti-popup too powerful? Or did this get triggered from not a trusted event" ); return; } wind.document.write(` <h1>debug menu</h1> <pre>${JSON.stringify( { userAgent: navigator.userAgent, flags: this.flags .getAll() .filter((f) => f.enabled) .map((f) => f.id), }, null, 2 )}</pre> `); wind.document.close(); } openDebugTools() { this.emit("openTools"); } /** * Create debug marker * * Useful on touchscreen devices * * @param type * @param args * @returns */ debug<T extends keyof DebugArgs>(type: T, ...args: DebugArgs[T]) { switch (type) { case "point": { const [x, y, id] = args; if (document.getElementById("debug-" + id)) { document.getElementById("debug-" + id)!.style.top = y + "px"; document.getElementById("debug-" + id)!.style.left = x + "px"; return; } let el = document.createElement("div"); if (id) el.id = "debug-" + id; el.classList.add("debug-point"); el.style.setProperty("top", y + "px"); el.style.setProperty("left", x + "px"); document.body.appendChild(el); break; } case "text": { const [str] = args; // create debug box in canvas-meta if it doesn't exist if (!document.getElementById("canvas-meta-debug")) { let debugBox = document.createElement("div"); debugBox.id = "canvas-meta-debug"; debugBox.style.whiteSpace = "pre"; debugBox.style.unicodeBidi = "embed"; document.getElementById("canvas-meta")!.prepend(debugBox); } document.getElementById("canvas-meta-debug")!.innerText = typeof str === "string" ? str : JSON.stringify(str, null, 2); break; } } } } export const Debug = new Debugcl();
packages/lib/src/renderer/lib/zoom.utils.ts +2 −1 Original line number Diff line number Diff line import { Debug } from "../../debug"; import { PanZoom } from "../PanZoom"; export function handleCalculateZoomPositions( Loading @@ -17,7 +18,7 @@ export function handleCalculateZoomPositions( const calculatedPositionX = x - mouseX * scaleDifference; const calculatedPositionY = y - mouseY * scaleDifference; contextInstance.debug(calculatedPositionX, calculatedPositionY, "zoom"); // Debug.debug("point", calculatedPositionX, calculatedPositionY, "zoom"); // do not limit to bounds when there is padding animation, // it causes animation strange behaviour Loading