From 91a1c954e563e14ef0483a8a9620ce3ebb276acc Mon Sep 17 00:00:00 2001 From: Abraham Date: Tue, 28 Jul 2026 11:12:54 -0700 Subject: [PATCH] chore(visimer): mention alt-drag connect in the preview hint (#2970) * chore(visimer): mention alt-drag connect in the preview hint * feat(visimer): track canvas zoom control clicks, trim pan hint GitOrigin-RevId: af0b1bc7cea5b5fd8cefd663dd2f05c07f2470f1 --- apps/site/src/App.tsx | 4 +++- apps/site/src/PlaygroundPage.tsx | 4 +++- apps/site/src/analytics.ts | 6 ++++++ apps/site/src/playground-shared.tsx | 21 +++++++++++++++++++++ 4 files changed, 33 insertions(+), 2 deletions(-) diff --git a/apps/site/src/App.tsx b/apps/site/src/App.tsx index 585679f..e7593fc 100644 --- a/apps/site/src/App.tsx +++ b/apps/site/src/App.tsx @@ -10,6 +10,7 @@ import { mono, playgroundUrl, themeConfig, + useCanvasControlTracking, } from './playground-shared' const REPO = 'inkeep/visimer' @@ -155,6 +156,7 @@ export default function App() { const [type, setType] = useState('flowchart') const [skin, setSkin] = useState<'light' | 'dark'>('light') const { editor } = useMermaidEditor(PRESETS.flowchart) + useCanvasControlTracking() // Expanding hands off to the dedicated /playground page, carrying the // current source in the URL hash so nothing is lost in the jump. @@ -705,7 +707,7 @@ export default function App() { > Preview - click to select · double-click to edit · drag empty space to pan · pinch to zoom + click to select · double-click to edit · alt + drag to connect · pinch to zoom tap to select · double-tap to edit · pinch to zoom diff --git a/apps/site/src/PlaygroundPage.tsx b/apps/site/src/PlaygroundPage.tsx index f4d7f1b..cce0bc8 100644 --- a/apps/site/src/PlaygroundPage.tsx +++ b/apps/site/src/PlaygroundPage.tsx @@ -11,6 +11,7 @@ import { encodeCode, mono, themeConfig, + useCanvasControlTracking, } from './playground-shared' /** @@ -22,6 +23,7 @@ import { export default function PlaygroundPage() { const initialCode = useMemo(() => codeFromHash(window.location.hash) ?? PRESETS.flowchart, []) const { editor } = useMermaidEditor(initialCode) + useCanvasControlTracking() const [skin, setSkin] = useState<'light' | 'dark'>('light') const [menuOpen, setMenuOpen] = useState(false) @@ -312,7 +314,7 @@ export default function PlaygroundPage() { > Preview - click to select · double-click to edit · drag empty space to pan · pinch to zoom + click to select · double-click to edit · alt + drag to connect · pinch to zoom tap to select · double-tap to edit · pinch to zoom diff --git a/apps/site/src/analytics.ts b/apps/site/src/analytics.ts index a9841ef..5b64f8d 100644 --- a/apps/site/src/analytics.ts +++ b/apps/site/src/analytics.ts @@ -23,6 +23,12 @@ if (key) { } export function track(event: string, properties?: Record) { + // dev only: mirror event names onto the window so wiring is verifiable + // in the browser without a key or a network tap + if (import.meta.env.DEV) { + const w = window as unknown as { __phEvents?: string[] } + ;(w.__phEvents ??= []).push(event) + } if (!key) return posthog.capture(event, properties) } diff --git a/apps/site/src/playground-shared.tsx b/apps/site/src/playground-shared.tsx index 32854a7..94b1b60 100644 --- a/apps/site/src/playground-shared.tsx +++ b/apps/site/src/playground-shared.tsx @@ -2,6 +2,7 @@ import { useEffect, useRef } from 'react' import { EditorView } from '@codemirror/view' import { MermaidCodeMirror } from '@visimer/codemirror' import type { MermaidWysiwygEditor } from '@visimer/core' +import { track } from './analytics' /** Sample diagrams + chrome shared by the inline demo and /playground. */ @@ -178,6 +179,26 @@ export function CodeMirrorPane({ editor }: { editor: MermaidWysiwygEditor }) { return
} +/** + * Tracks clicks on the canvas corner zoom controls (zoom in / zoom out / + * fit). The buttons are rendered by @visimer/dom, so the site listens by + * delegation instead of teaching the package about analytics. + */ +export function useCanvasControlTracking() { + useEffect(() => { + const onClick = (e: MouseEvent) => { + const btn = (e.target as Element | null)?.closest?.('.mw-zoom-btn') + if (!btn) return + const title = btn.getAttribute('title') ?? '' + const control = /out/i.test(title) ? 'zoom-out' : /in\b/i.test(title) ? 'zoom-in' : 'fit' + track('canvas_zoom_control', { control }) + } + // capture phase: the package's buttons stopPropagation on their clicks + document.addEventListener('click', onClick, true) + return () => document.removeEventListener('click', onClick, true) + }, []) +} + // ---- code <-> URL hash codec ---- // The playground keeps the current source in `#code=` so the // address bar is always a share link. No compression: sample-sized diagrams