@1agh/maude 0.28.0 → 0.29.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/{plugins/design/dev-server → apps/studio}/ai-banner.tsx +1 -1
- package/{plugins/design/dev-server → apps/studio}/annotations-context-toolbar.tsx +286 -6
- package/{plugins/design/dev-server → apps/studio}/annotations-layer.tsx +1209 -122
- package/{plugins/design/dev-server → apps/studio}/api.ts +486 -32
- package/{plugins/design/dev-server → apps/studio}/artboard-activity-overlay.tsx +1 -1
- package/{plugins/design/dev-server → apps/studio}/artboard-marquee.tsx +1 -1
- package/apps/studio/bin/_motion-sample-playwright.mjs +129 -0
- package/{plugins/design/dev-server → apps/studio}/bin/canvas-edit.sh +1 -1
- package/{plugins/design/dev-server → apps/studio}/bin/draw-proof.sh +37 -2
- package/{plugins/design/dev-server → apps/studio}/bin/preflight.sh +1 -1
- package/apps/studio/bin/read-annotations.mjs +438 -0
- package/apps/studio/bin/read-annotations.sh +11 -0
- package/{plugins/design/dev-server → apps/studio}/bin/runtime-health.sh +1 -1
- package/{plugins/design/dev-server → apps/studio}/bin/scenario-report.mjs +1 -1
- package/{plugins/design/dev-server → apps/studio}/bin/screenshot.sh +62 -2
- package/apps/studio/bin/server-up.sh +234 -0
- package/apps/studio/bin/to-lottie-verify.html +68 -0
- package/apps/studio/bin/to-lottie.sh +128 -0
- package/{plugins/design/dev-server → apps/studio}/bin/visual-sanity.sh +19 -3
- package/{plugins/design/dev-server → apps/studio}/build.ts +5 -3
- package/{plugins/design/dev-server → apps/studio}/canvas-arrowheads.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/canvas-comment-mount.tsx +2 -2
- package/apps/studio/canvas-create.ts +104 -0
- package/{plugins/design/dev-server → apps/studio}/canvas-cursors.ts +47 -13
- package/{plugins/design/dev-server → apps/studio}/canvas-icons.tsx +60 -1
- package/{plugins/design/dev-server → apps/studio}/canvas-lib-inline.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/canvas-lib-resolver.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/canvas-lib.tsx +41 -33
- package/{plugins/design/dev-server → apps/studio}/canvas-shell.tsx +57 -42
- package/{plugins/design/dev-server → apps/studio}/client/app.jsx +1713 -530
- package/apps/studio/client/canvas-url.js +81 -0
- package/{plugins/design/dev-server → apps/studio}/client/comments-overlay.css +41 -27
- package/{plugins/design/dev-server → apps/studio}/client/index.html +2 -1
- package/apps/studio/client/styles/1-tokens-maude.css +296 -0
- package/apps/studio/client/styles/3-shell-maude.css +459 -0
- package/{plugins/design/dev-server → apps/studio}/client/styles/3-shell.css +129 -0
- package/apps/studio/client/styles/4-components-maude.css +74 -0
- package/{plugins/design/dev-server → apps/studio}/client/styles/4-components.css +357 -34
- package/apps/studio/client/styles/5-maude-overrides.css +123 -0
- package/{plugins/design/dev-server → apps/studio}/client/styles/_index.css +9 -0
- package/{plugins/design/dev-server → apps/studio}/client/styles.css +1 -1
- package/apps/studio/client/tour/overlay.jsx +191 -0
- package/apps/studio/client/tour/usage-tour.js +35 -0
- package/apps/studio/client/whats-new-seen.js +52 -0
- package/apps/studio/client/whats-new.jsx +250 -0
- package/{plugins/design/dev-server → apps/studio}/collab/index.ts +4 -4
- package/{plugins/design/dev-server → apps/studio}/collab/persistence.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/commands/annotation-strokes-command.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/commands/equal-spacing-command.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/commands/move-artboards-command.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/comments-overlay.tsx +25 -6
- package/{plugins/design/dev-server → apps/studio}/context-menu.tsx +2 -2
- package/{plugins/design/dev-server → apps/studio}/contextual-toolbar.tsx +4 -7
- package/{plugins/design/dev-server → apps/studio}/cursors-overlay.tsx +1 -1
- package/apps/studio/dist/client.bundle.js +22825 -0
- package/apps/studio/dist/comment-mount.js +1960 -0
- package/apps/studio/dist/runtime/lib0_decoding.js +1 -0
- package/apps/studio/dist/runtime/lib0_encoding.js +1 -0
- package/apps/studio/dist/runtime/motion.js +4 -0
- package/apps/studio/dist/runtime/motion_react.js +12 -0
- package/apps/studio/dist/runtime/pixi-js.js +3397 -0
- package/apps/studio/dist/runtime/react-dom.js +1 -0
- package/apps/studio/dist/runtime/react-dom_client.js +9 -0
- package/apps/studio/dist/runtime/react.js +1 -0
- package/apps/studio/dist/runtime/react_jsx-dev-runtime.js +1 -0
- package/apps/studio/dist/runtime/react_jsx-runtime.js +1 -0
- package/apps/studio/dist/runtime/y-protocols_awareness.js +1 -0
- package/apps/studio/dist/runtime/y-protocols_sync.js +1 -0
- package/apps/studio/dist/runtime/yjs.js +5 -0
- package/apps/studio/dist/styles.css +5695 -0
- package/{plugins/design/dev-server → apps/studio}/dom-selection.ts +75 -4
- package/apps/studio/draw/animate.ts +333 -0
- package/{plugins/design/dev-server → apps/studio}/draw/brush.ts +4 -4
- package/{plugins/design/dev-server → apps/studio}/draw/composition.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/draw/geometry.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/draw/index.ts +9 -6
- package/{plugins/design/dev-server → apps/studio}/draw/layout.ts +2 -2
- package/apps/studio/draw/morph.ts +204 -0
- package/{plugins/design/dev-server → apps/studio}/draw/optimize.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/draw/palette.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/draw/primitives.ts +1 -1
- package/apps/studio/draw/serialize-animate.ts +324 -0
- package/{plugins/design/dev-server → apps/studio}/draw/serialize.ts +9 -3
- package/apps/studio/draw/test/animate.test.ts +172 -0
- package/{plugins/design/dev-server → apps/studio}/draw/test/layout.test.ts +1 -1
- package/apps/studio/draw/test/morph.test.ts +107 -0
- package/apps/studio/draw/test/serialize-animate.test.ts +142 -0
- package/{plugins/design/dev-server → apps/studio}/draw/test/serialize.test.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/equal-spacing-detector.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/equal-spacing-handles.tsx +7 -29
- package/{plugins/design/dev-server → apps/studio}/examples/perf-100-artboards.tsx +1 -2
- package/{plugins/design/dev-server → apps/studio}/export-dialog.tsx +14 -2
- package/{plugins/design/dev-server → apps/studio}/exporters/index.ts +2 -2
- package/{plugins/design/dev-server → apps/studio}/http.ts +103 -2
- package/{plugins/design/dev-server → apps/studio}/input-router.tsx +8 -1
- package/{plugins/design/dev-server → apps/studio}/inspect.ts +20 -3
- package/{plugins/design/dev-server → apps/studio}/marquee-overlay.tsx +6 -3
- package/{plugins/design/dev-server → apps/studio}/participants-chrome.tsx +1 -1
- package/{plugins/design/dev-server → apps/studio}/paths.ts +15 -11
- package/{plugins/design/dev-server → apps/studio}/server.ts +19 -1
- package/{plugins/design/dev-server → apps/studio}/sync/index.ts +6 -6
- package/{plugins/design/dev-server → apps/studio}/sync/materialize.ts +2 -2
- package/{plugins/design/dev-server → apps/studio}/test/ai-activity.test.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/test/annotations-api.test.ts +1 -2
- package/{plugins/design/dev-server → apps/studio}/test/annotations-layer.test.ts +69 -6
- package/{plugins/design/dev-server → apps/studio}/test/annotations-roundtrip.test.ts +98 -1
- package/apps/studio/test/annotations-text-format.test.ts +396 -0
- package/apps/studio/test/asset-api.test.ts +149 -0
- package/{plugins/design/dev-server → apps/studio}/test/boot-self-heal.test.ts +1 -1
- package/apps/studio/test/canvas-create-api.test.ts +361 -0
- package/{plugins/design/dev-server → apps/studio}/test/canvas-cursors.test.ts +3 -1
- package/{plugins/design/dev-server → apps/studio}/test/canvas-edit.test.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/test/canvas-hmr-runtime.test.tsx +1 -1
- package/{plugins/design/dev-server → apps/studio}/test/canvas-lib-inline.test.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/test/canvas-lib-resolver.test.ts +2 -3
- package/apps/studio/test/canvas-media-drop.test.ts +158 -0
- package/{plugins/design/dev-server → apps/studio}/test/canvas-meta-api.test.ts +1 -2
- package/{plugins/design/dev-server → apps/studio}/test/canvas-origin-gate.test.ts +18 -3
- package/apps/studio/test/canvas-url.test.ts +99 -0
- package/{plugins/design/dev-server → apps/studio}/test/collab-annotations-bridge.test.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/test/collab-bridge.test.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/test/collab-room.test.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/test/collab-stress.test.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/test/comments-api.test.ts +1 -2
- package/{plugins/design/dev-server → apps/studio}/test/compile-entry.test.ts +1 -2
- package/{plugins/design/dev-server → apps/studio}/test/exporters/canva.test.ts +1 -2
- package/{plugins/design/dev-server → apps/studio}/test/exporters/history.test.ts +1 -2
- package/{plugins/design/dev-server → apps/studio}/test/exporters/pw-launch.test.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/test/exporters/scope.test.ts +1 -2
- package/{plugins/design/dev-server → apps/studio}/test/exporters/zip.test.ts +1 -2
- package/{plugins/design/dev-server → apps/studio}/test/git-lifecycle.test.ts +1 -2
- package/{plugins/design/dev-server → apps/studio}/test/handoff-static-frames.test.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/test/hmr-broadcast.test.ts +1 -1
- package/apps/studio/test/index-data-canvas-ds.test.ts +97 -0
- package/apps/studio/test/motion-sample.test.ts +35 -0
- package/{plugins/design/dev-server → apps/studio}/test/perf-harness.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/test/phase-3.6-smoke.test.ts +3 -1
- package/apps/studio/test/read-annotations.test.ts +409 -0
- package/{plugins/design/dev-server → apps/studio}/test/runtime-bundle.test.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/test/sanitize-annotation-svg.test.ts +108 -2
- package/{plugins/design/dev-server → apps/studio}/test/shared-doc-convergence.test.ts +2 -2
- package/{plugins/design/dev-server → apps/studio}/test/shared-doc-migrate.test.ts +2 -3
- package/{plugins/design/dev-server → apps/studio}/test/shared-doc-projection.test.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/test/snap-distance-pill.test.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/test/sync-agent.test.ts +2 -3
- package/{plugins/design/dev-server → apps/studio}/test/sync-atomic-write.test.ts +2 -3
- package/{plugins/design/dev-server → apps/studio}/test/sync-connection-state.test.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/test/sync-echo-guard.test.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/test/sync-fs-mirror.test.ts +1 -2
- package/{plugins/design/dev-server → apps/studio}/test/sync-hardening.test.ts +4 -5
- package/{plugins/design/dev-server → apps/studio}/test/sync-hubs-config.test.ts +1 -2
- package/{plugins/design/dev-server → apps/studio}/test/sync-runtime.test.ts +3 -8
- package/{plugins/design/dev-server → apps/studio}/test/sync-status.test.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/test/sync-untrusted.test.ts +1 -2
- package/apps/studio/test/tour-overlay.test.tsx +56 -0
- package/{plugins/design/dev-server → apps/studio}/test/use-agent-presence.test.tsx +4 -1
- package/{plugins/design/dev-server → apps/studio}/test/use-annotation-resize.test.ts +43 -0
- package/{plugins/design/dev-server → apps/studio}/test/use-snap-guides.test.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/test/use-tool-mode.test.tsx +4 -1
- package/apps/studio/test/whats-new.test.ts +101 -0
- package/apps/studio/text-imports.d.ts +9 -0
- package/{plugins/design/dev-server → apps/studio}/tool-palette.tsx +4 -69
- package/{plugins/design/dev-server → apps/studio}/undo-hud.tsx +1 -1
- package/{plugins/design/dev-server → apps/studio}/undo-stack.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/use-agent-presence.tsx +2 -2
- package/{plugins/design/dev-server → apps/studio}/use-annotation-resize.tsx +41 -12
- package/{plugins/design/dev-server → apps/studio}/use-annotation-selection.tsx +3 -7
- package/{plugins/design/dev-server → apps/studio}/use-annotations-visibility.tsx +2 -2
- package/{plugins/design/dev-server → apps/studio}/use-artboard-drag.tsx +2 -2
- package/{plugins/design/dev-server → apps/studio}/use-canvas-activity.tsx +2 -2
- package/apps/studio/use-canvas-media-drop.tsx +343 -0
- package/{plugins/design/dev-server → apps/studio}/use-collab.tsx +4 -5
- package/{plugins/design/dev-server → apps/studio}/use-cursor-modifiers.tsx +1 -1
- package/{plugins/design/dev-server → apps/studio}/use-keyboard-discipline.tsx +5 -2
- package/{plugins/design/dev-server → apps/studio}/use-selection-set.tsx +10 -2
- package/{plugins/design/dev-server → apps/studio}/use-snap-guides.tsx +1 -1
- package/{plugins/design/dev-server → apps/studio}/use-tool-mode.tsx +4 -2
- package/{plugins/design/dev-server → apps/studio}/use-undo-stack.tsx +5 -6
- package/apps/studio/whats-new.json +139 -0
- package/apps/studio/whats-new.schema.json +70 -0
- package/apps/studio/whats-new.ts +87 -0
- package/cli/bin/maude.mjs +10 -0
- package/cli/commands/design.mjs +84 -10
- package/cli/commands/design.test.mjs +133 -1
- package/cli/commands/help.mjs +8 -2
- package/cli/commands/hub.mjs +3 -3
- package/cli/commands/hub.test.mjs +1 -1
- package/cli/commands/scenario-report.mjs +2 -9
- package/cli/lib/cache.mjs +1 -1
- package/cli/lib/config-lint.mjs +1 -1
- package/cli/lib/copy-tree.mjs +1 -1
- package/cli/lib/design-link.mjs +1 -1
- package/cli/lib/flow-design-integration.test.mjs +2 -2
- package/cli/lib/gitignore-block.mjs +1 -0
- package/cli/lib/gitignore-block.test.mjs +2 -2
- package/cli/lib/plugin-cli-reachability.test.mjs +8 -7
- package/cli/lib/preflight.mjs +1 -1
- package/cli/lib/stack-detect.mjs +1 -1
- package/package.json +16 -16
- package/plugins/design/templates/_shell.html +3 -3
- package/plugins/design/templates/brief-board.tsx.template +61 -0
- package/plugins/design/templates/canvas.tsx.template +1 -1
- package/plugins/design/templates/design-system-inspiration/SUB-AGENT-PROMPTS.md +18 -3
- package/plugins/design/templates/design-system-inspiration/core/config.json.tpl +1 -1
- package/plugins/design/templates/design-system-inspiration/core/preview/_motion-readme.md.tpl +1 -1
- package/plugins/flow/.claude-plugin/config.schema.json +16 -0
- package/plugins/design/dev-server/bin/server-up.sh +0 -135
- package/plugins/design/dev-server/dist/client.bundle.js +0 -20692
- package/plugins/design/dev-server/dist/comment-mount.js +0 -1924
- package/plugins/design/dev-server/dist/runtime/lib0_decoding.js +0 -620
- package/plugins/design/dev-server/dist/runtime/lib0_encoding.js +0 -604
- package/plugins/design/dev-server/dist/runtime/motion.js +0 -4944
- package/plugins/design/dev-server/dist/runtime/motion_react.js +0 -10056
- package/plugins/design/dev-server/dist/runtime/pixi-js.js +0 -53104
- package/plugins/design/dev-server/dist/runtime/react-dom.js +0 -231
- package/plugins/design/dev-server/dist/runtime/react-dom_client.js +0 -10357
- package/plugins/design/dev-server/dist/runtime/react.js +0 -535
- package/plugins/design/dev-server/dist/runtime/react_jsx-dev-runtime.js +0 -60
- package/plugins/design/dev-server/dist/runtime/react_jsx-runtime.js +0 -85
- package/plugins/design/dev-server/dist/runtime/y-protocols_awareness.js +0 -376
- package/plugins/design/dev-server/dist/runtime/y-protocols_sync.js +0 -100
- package/plugins/design/dev-server/dist/runtime/yjs.js +0 -6687
- package/plugins/design/dev-server/dist/styles.css +0 -2710
- package/{plugins/design/dev-server → apps/studio}/activity.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/bin/_enumerate-artboards-playwright.mjs +0 -0
- package/{plugins/design/dev-server → apps/studio}/bin/_html-playwright.mjs +0 -0
- package/{plugins/design/dev-server → apps/studio}/bin/_pdf-playwright.mjs +0 -0
- package/{plugins/design/dev-server → apps/studio}/bin/_png-playwright.mjs +0 -0
- package/{plugins/design/dev-server → apps/studio}/bin/_pptx-playwright.mjs +0 -0
- package/{plugins/design/dev-server → apps/studio}/bin/_pw-launch.mjs +0 -0
- package/{plugins/design/dev-server → apps/studio}/bin/_screenshot-playwright.mjs +0 -0
- package/{plugins/design/dev-server → apps/studio}/bin/_svg-optimize.mjs +0 -0
- package/{plugins/design/dev-server → apps/studio}/bin/_svg-playwright.mjs +0 -0
- package/{plugins/design/dev-server → apps/studio}/bin/asset-sweep.sh +0 -0
- package/{plugins/design/dev-server → apps/studio}/bin/bootstrap-check.sh +0 -0
- package/{plugins/design/dev-server → apps/studio}/bin/check-runtime-bundles.sh +0 -0
- package/{plugins/design/dev-server → apps/studio}/bin/draw-build.sh +0 -0
- package/{plugins/design/dev-server → apps/studio}/bin/handoff.sh +0 -0
- package/{plugins/design/dev-server → apps/studio}/bin/prep.sh +0 -0
- package/{plugins/design/dev-server → apps/studio}/bin/slug.sh +0 -0
- package/{plugins/design/dev-server → apps/studio}/bin/smoke.sh +0 -0
- package/{plugins/design/dev-server → apps/studio}/bin/svg-optimize.sh +0 -0
- package/{plugins/design/dev-server → apps/studio}/boot-self-heal.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/canvas-build.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/canvas-edit.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/canvas-header.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/canvas-meta.schema.json +0 -0
- package/{plugins/design/dev-server → apps/studio}/canvas-pipeline.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/client/hmr.mjs +0 -0
- package/{plugins/design/dev-server → apps/studio}/client/iframe-lazy.mjs +0 -0
- package/{plugins/design/dev-server → apps/studio}/client/styles/0-reset.css +0 -0
- package/{plugins/design/dev-server → apps/studio}/client/styles/1-tokens.css +0 -0
- package/{plugins/design/dev-server → apps/studio}/client/styles/2-layout.css +0 -0
- package/{plugins/design/dev-server → apps/studio}/client/styles/5-utilities.css +0 -0
- package/{plugins/design/dev-server → apps/studio}/collab/ai-activity.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/collab/awareness-bridge.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/collab/git-lifecycle.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/collab/protocol.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/collab/registry.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/collab/room.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/config.schema.json +0 -0
- package/{plugins/design/dev-server → apps/studio}/context.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/dist/runtime/.min-sizes.json +0 -0
- package/{plugins/design/dev-server → apps/studio}/draw/test/brush.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/draw/test/composition.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/draw/test/geometry.test.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/draw/test/gradient.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/draw/test/optimize.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/draw/test/palette.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/draw/test/primitives.test.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/examples/README.md +0 -0
- package/{plugins/design/dev-server → apps/studio}/exporters/_browser-bundles.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/exporters/canva-handoff-prompt.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/exporters/canva.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/exporters/html.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/exporters/pdf.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/exporters/png.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/exporters/pptx.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/exporters/scope.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/exporters/svg.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/exporters/zip.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/fs-watch.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/handoff.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/history.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/hmr-broadcast.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/locator.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/mem.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/runtime-bundle.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/server.mjs +0 -0
- package/{plugins/design/dev-server → apps/studio}/sync/agent.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/sync/atomic-write.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/sync/codec.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/sync/connection-state.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/sync/echo-guard.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/sync/fs-mirror.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/sync/hubs-config.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/sync/migrate-seed.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/sync/origins.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/sync/projection.ts +3 -3
- package/{plugins/design/dev-server → apps/studio}/sync/status.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/sync/untrusted.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/_helpers.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/active-state.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/activity.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/annotation-strokes-command.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/annotations-draw-modifiers.test.ts +2 -2
- package/{plugins/design/dev-server → apps/studio}/test/artboard-activity-overlay.test.tsx +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/binary-smoke.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/bundle-smoke.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/canvas-build.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/canvas-header.test.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/test/canvas-lib-motion.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/canvas-pipeline.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/canvas-route.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/collab-awareness-bridge.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/collab-loopback.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/collab-protocol.test.ts +2 -2
- package/{plugins/design/dev-server → apps/studio}/test/collab-reseed-guard.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/comment-mount.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/context-resolve-tokens.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/csp-canvas-shell.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/equal-spacing-detector.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/exporters/endpoint.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/exporters/html.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/exporters/pdf.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/exporters/png.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/exporters/pptx-deck.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/exporters/pptx.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/exporters/svg.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/fixtures/phase-20-annotations.svg +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/fixtures/phase-21-annotations.svg +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/fs-watch.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/handoff.test.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/test/history-rollback.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/hmr-classify.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/input-router.test.ts +2 -2
- package/{plugins/design/dev-server → apps/studio}/test/locator.test.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/test/marquee-overlay.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/move-artboards-command.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/participants-chrome.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/paths.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/runtime-bundle-error-mapping.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/server-lifecycle.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/shared-doc-foundation.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/sync-codec.test.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/test/sync-meta-codec.test.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/test/system-endpoint.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/tool-palette.test.tsx +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/undo-stack.test.ts +2 -2
- package/{plugins/design/dev-server → apps/studio}/test/use-annotation-selection.test.tsx +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/use-artboard-drag.test.ts +3 -3
- package/{plugins/design/dev-server → apps/studio}/test/use-canvas-activity.test.tsx +2 -2
- package/{plugins/design/dev-server → apps/studio}/test/use-collab.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/use-cursor-modifiers.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/use-keyboard-discipline.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/use-selection-set.test.tsx +1 -1
- package/{plugins/design/dev-server → apps/studio}/test/use-undo-stack.test.tsx +2 -2
- /package/{plugins/design/dev-server → apps/studio}/test/ws-handshake.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/tsconfig.json +0 -0
- /package/{plugins/design/dev-server → apps/studio}/ws.ts +0 -0
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
// overlay.jsx — hand-rolled guided-tour engine (zero runtime dep, DDR-B).
|
|
2
|
+
//
|
|
3
|
+
// One <TourOverlay steps={[…]} open onClose onComplete/> drives both the
|
|
4
|
+
// per-feature spotlight tours (a What's New entry's `tour[]`) and the evergreen
|
|
5
|
+
// usage tour. A step = { target (CSS selector / [data-tour] anchor), title,
|
|
6
|
+
// body, placement? }. A step whose target can't be resolved still shows, just
|
|
7
|
+
// centered with no spotlight — the tour never dead-ends on a missing element.
|
|
8
|
+
//
|
|
9
|
+
// A11y: role="dialog" + aria-modal, focus moves to the primary button on each
|
|
10
|
+
// step and is trapped within the card, focus is restored on close, Esc skips,
|
|
11
|
+
// ←/→ navigate. prefers-reduced-motion disables the spotlight transition.
|
|
12
|
+
|
|
13
|
+
import { useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react';
|
|
14
|
+
|
|
15
|
+
function getRect(target) {
|
|
16
|
+
if (typeof document === 'undefined' || !target) return null;
|
|
17
|
+
try {
|
|
18
|
+
const el = document.querySelector(target);
|
|
19
|
+
if (!el) return null;
|
|
20
|
+
const r = el.getBoundingClientRect();
|
|
21
|
+
if (r.width === 0 && r.height === 0) return null;
|
|
22
|
+
return r;
|
|
23
|
+
} catch {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const CARD_W = 320;
|
|
29
|
+
const CARD_H_EST = 168;
|
|
30
|
+
|
|
31
|
+
function computeCardStyle(rect) {
|
|
32
|
+
if (typeof window === 'undefined' || !rect) {
|
|
33
|
+
return { top: '50%', left: '50%', transform: 'translate(-50%, -50%)', width: CARD_W };
|
|
34
|
+
}
|
|
35
|
+
const vw = window.innerWidth;
|
|
36
|
+
const vh = window.innerHeight;
|
|
37
|
+
const roomBelow = vh - rect.bottom;
|
|
38
|
+
const top =
|
|
39
|
+
roomBelow > CARD_H_EST + 24 ? rect.bottom + 12 : Math.max(12, rect.top - CARD_H_EST - 12);
|
|
40
|
+
const left = Math.min(Math.max(12, rect.left), vw - CARD_W - 12);
|
|
41
|
+
return { top, left, width: CARD_W };
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function TourOverlay({ steps, open, onClose, onComplete }) {
|
|
45
|
+
const [i, setI] = useState(0);
|
|
46
|
+
const [rect, setRect] = useState(null);
|
|
47
|
+
const cardRef = useRef(null);
|
|
48
|
+
const prevFocus = useRef(null);
|
|
49
|
+
|
|
50
|
+
const measure = useCallback(() => {
|
|
51
|
+
const step = steps[i];
|
|
52
|
+
setRect(step ? getRect(step.target) : null);
|
|
53
|
+
}, [steps, i]);
|
|
54
|
+
|
|
55
|
+
// Reset to the first step whenever a tour (re)opens.
|
|
56
|
+
useEffect(() => {
|
|
57
|
+
if (open) setI(0);
|
|
58
|
+
}, [open]);
|
|
59
|
+
|
|
60
|
+
useLayoutEffect(() => {
|
|
61
|
+
if (open) measure();
|
|
62
|
+
}, [open, measure]);
|
|
63
|
+
|
|
64
|
+
// Keep the spotlight glued to its target through scroll/resize; restore focus.
|
|
65
|
+
useEffect(() => {
|
|
66
|
+
if (!open) return;
|
|
67
|
+
prevFocus.current = document.activeElement;
|
|
68
|
+
const onMove = () => measure();
|
|
69
|
+
window.addEventListener('resize', onMove);
|
|
70
|
+
window.addEventListener('scroll', onMove, true);
|
|
71
|
+
return () => {
|
|
72
|
+
window.removeEventListener('resize', onMove);
|
|
73
|
+
window.removeEventListener('scroll', onMove, true);
|
|
74
|
+
try {
|
|
75
|
+
prevFocus.current?.focus?.();
|
|
76
|
+
} catch {}
|
|
77
|
+
};
|
|
78
|
+
}, [open, measure]);
|
|
79
|
+
|
|
80
|
+
const last = i >= steps.length - 1;
|
|
81
|
+
const next = useCallback(() => {
|
|
82
|
+
if (last) {
|
|
83
|
+
onComplete?.();
|
|
84
|
+
onClose?.();
|
|
85
|
+
} else {
|
|
86
|
+
setI((n) => Math.min(n + 1, steps.length - 1));
|
|
87
|
+
}
|
|
88
|
+
}, [last, onComplete, onClose, steps.length]);
|
|
89
|
+
const back = useCallback(() => setI((n) => Math.max(0, n - 1)), []);
|
|
90
|
+
|
|
91
|
+
// Keyboard: Esc skips, ←/→ navigate, Tab is trapped within the card buttons.
|
|
92
|
+
useEffect(() => {
|
|
93
|
+
if (!open) return;
|
|
94
|
+
function onKey(e) {
|
|
95
|
+
if (e.key === 'Escape') {
|
|
96
|
+
e.preventDefault();
|
|
97
|
+
onClose?.();
|
|
98
|
+
} else if (e.key === 'ArrowRight') {
|
|
99
|
+
e.preventDefault();
|
|
100
|
+
next();
|
|
101
|
+
} else if (e.key === 'ArrowLeft') {
|
|
102
|
+
e.preventDefault();
|
|
103
|
+
back();
|
|
104
|
+
} else if (e.key === 'Tab') {
|
|
105
|
+
const card = cardRef.current;
|
|
106
|
+
if (!card) return;
|
|
107
|
+
const f = card.querySelectorAll('button');
|
|
108
|
+
if (!f.length) return;
|
|
109
|
+
const first = f[0];
|
|
110
|
+
const lastEl = f[f.length - 1];
|
|
111
|
+
if (e.shiftKey && document.activeElement === first) {
|
|
112
|
+
e.preventDefault();
|
|
113
|
+
lastEl.focus();
|
|
114
|
+
} else if (!e.shiftKey && document.activeElement === lastEl) {
|
|
115
|
+
e.preventDefault();
|
|
116
|
+
first.focus();
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
window.addEventListener('keydown', onKey, true);
|
|
121
|
+
return () => window.removeEventListener('keydown', onKey, true);
|
|
122
|
+
}, [open, next, back, onClose]);
|
|
123
|
+
|
|
124
|
+
// Move focus to the primary action on each step (accessible dialog behavior).
|
|
125
|
+
useEffect(() => {
|
|
126
|
+
if (!open) return;
|
|
127
|
+
const t = setTimeout(() => {
|
|
128
|
+
const primary = cardRef.current?.querySelector('[data-tour-primary]');
|
|
129
|
+
try {
|
|
130
|
+
primary?.focus();
|
|
131
|
+
} catch {}
|
|
132
|
+
}, 0);
|
|
133
|
+
return () => clearTimeout(t);
|
|
134
|
+
}, [open, i]);
|
|
135
|
+
|
|
136
|
+
if (!open || !steps.length) return null;
|
|
137
|
+
const step = steps[i];
|
|
138
|
+
const pad = 6;
|
|
139
|
+
const spot = rect
|
|
140
|
+
? {
|
|
141
|
+
top: rect.top - pad,
|
|
142
|
+
left: rect.left - pad,
|
|
143
|
+
width: rect.width + pad * 2,
|
|
144
|
+
height: rect.height + pad * 2,
|
|
145
|
+
}
|
|
146
|
+
: null;
|
|
147
|
+
|
|
148
|
+
return (
|
|
149
|
+
<div className="mdcc-tour" role="presentation">
|
|
150
|
+
{spot ? (
|
|
151
|
+
<div className="mdcc-tour__spot" style={spot} aria-hidden="true" />
|
|
152
|
+
) : (
|
|
153
|
+
<div className="mdcc-tour__scrim" aria-hidden="true" />
|
|
154
|
+
)}
|
|
155
|
+
<div
|
|
156
|
+
className="mdcc-tour__card"
|
|
157
|
+
ref={cardRef}
|
|
158
|
+
role="dialog"
|
|
159
|
+
aria-modal="true"
|
|
160
|
+
aria-labelledby="mdcc-tour-title"
|
|
161
|
+
aria-describedby="mdcc-tour-body"
|
|
162
|
+
style={computeCardStyle(rect)}
|
|
163
|
+
>
|
|
164
|
+
<div className="mdcc-tour__step">
|
|
165
|
+
{i + 1} / {steps.length}
|
|
166
|
+
</div>
|
|
167
|
+
<div className="mdcc-tour__title" id="mdcc-tour-title">
|
|
168
|
+
{step.title}
|
|
169
|
+
</div>
|
|
170
|
+
<div className="mdcc-tour__body" id="mdcc-tour-body">
|
|
171
|
+
{step.body}
|
|
172
|
+
</div>
|
|
173
|
+
<div className="mdcc-tour__actions">
|
|
174
|
+
<button type="button" className="mdcc-tour__skip" onClick={onClose}>
|
|
175
|
+
Skip
|
|
176
|
+
</button>
|
|
177
|
+
<div className="mdcc-tour__nav">
|
|
178
|
+
{i > 0 && (
|
|
179
|
+
<button type="button" className="mdcc-tour__back" onClick={back}>
|
|
180
|
+
Back
|
|
181
|
+
</button>
|
|
182
|
+
)}
|
|
183
|
+
<button type="button" className="mdcc-tour__next" data-tour-primary onClick={next}>
|
|
184
|
+
{last ? 'Done' : 'Next'}
|
|
185
|
+
</button>
|
|
186
|
+
</div>
|
|
187
|
+
</div>
|
|
188
|
+
</div>
|
|
189
|
+
</div>
|
|
190
|
+
);
|
|
191
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// usage-tour.js — the evergreen "how the Maude UI works" walkthrough.
|
|
2
|
+
//
|
|
3
|
+
// Targets stable elements that exist at first load (no canvas open required):
|
|
4
|
+
// the sidebar, the empty viewport, the menus, the What's New badge, and Help.
|
|
5
|
+
// Steps whose target is missing are shown centered by the overlay, so this is
|
|
6
|
+
// resilient to chrome changes. Reached from Help → "Take the tour" and offered
|
|
7
|
+
// once on first run.
|
|
8
|
+
|
|
9
|
+
export const USAGE_TOUR = [
|
|
10
|
+
{
|
|
11
|
+
target: '.sidebar',
|
|
12
|
+
title: 'Your canvases live here',
|
|
13
|
+
body: 'Every mock in the project shows up in this tree. Click one to open it in a tab — or use “+ board” to spin up a blank brief-board, no command needed.',
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
target: '.viewport',
|
|
17
|
+
title: 'The canvas',
|
|
18
|
+
body: 'Open a canvas, then ⌘-hover to preview the element under your cursor and ⌘-click to select it. Right-click for Copy CSS / Fit / Reset.',
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
target: '.mb-menus',
|
|
22
|
+
title: 'Menus & tools',
|
|
23
|
+
body: 'View toggles panels (tree, comments, annotations); Selection and Tools act on the active canvas. Press ? for every shortcut.',
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
target: "[data-tour='whatsnew']",
|
|
27
|
+
title: 'What’s new',
|
|
28
|
+
body: 'New features land here. Click the ✦ badge any time to catch up on what shipped.',
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
target: "[data-tour='help']",
|
|
32
|
+
title: 'Help is one key away',
|
|
33
|
+
body: 'Press ? for the full keyboard cheat-sheet — and you can restart this tour from the Help menu whenever you like.',
|
|
34
|
+
},
|
|
35
|
+
];
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
// whats-new-seen.js — pure, browser-safe "what have I already seen?" logic.
|
|
2
|
+
//
|
|
3
|
+
// No React, no DOM, no node imports — so it's bundled into the client AND
|
|
4
|
+
// imported directly by bun:test (test/whats-new.test.ts). Keep it that way.
|
|
5
|
+
|
|
6
|
+
/** Parse a semver-ish string into a [major, minor, patch] triple, or null. */
|
|
7
|
+
export function parseVer(v) {
|
|
8
|
+
if (typeof v !== 'string') return null;
|
|
9
|
+
const m = v.match(/^(\d+)\.(\d+)\.(\d+)/);
|
|
10
|
+
return m ? [Number(m[1]), Number(m[2]), Number(m[3])] : null;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Is version `a` strictly newer than `b`?
|
|
15
|
+
* - Unparseable `a` (e.g. "dev") → not newer (false).
|
|
16
|
+
* - Unparseable `b` but parseable `a` → newer (true): a real release outranks
|
|
17
|
+
* a non-version "seen" marker, so the entry surfaces.
|
|
18
|
+
*/
|
|
19
|
+
export function verGt(a, b) {
|
|
20
|
+
const pa = parseVer(a);
|
|
21
|
+
const pb = parseVer(b);
|
|
22
|
+
if (!pa) return false;
|
|
23
|
+
if (!pb) return true;
|
|
24
|
+
for (let i = 0; i < 3; i++) {
|
|
25
|
+
if (pa[i] !== pb[i]) return pa[i] > pb[i];
|
|
26
|
+
}
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Entries the user hasn't seen yet, given the version they last acknowledged.
|
|
32
|
+
* A pending entry (version == null) is always unseen until acknowledged.
|
|
33
|
+
*/
|
|
34
|
+
export function computeUnseen(entries, seenVersion) {
|
|
35
|
+
if (!Array.isArray(entries)) return [];
|
|
36
|
+
return entries.filter((e) => e && (e.version == null || verGt(e.version, seenVersion)));
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* The version to persist as "seen" after the user reads the panel — the highest
|
|
41
|
+
* of the current feed version and every entry's version. Stamping this clears
|
|
42
|
+
* the unseen set (pending entries excepted — they have no version to outrank).
|
|
43
|
+
*/
|
|
44
|
+
export function bestSeenVersion(entries, currentVersion) {
|
|
45
|
+
let best = currentVersion;
|
|
46
|
+
if (Array.isArray(entries)) {
|
|
47
|
+
for (const e of entries) {
|
|
48
|
+
if (e && e.version && verGt(e.version, best)) best = e.version;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return best;
|
|
52
|
+
}
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
// whats-new.jsx — Maude UI "What's New" surfaces.
|
|
2
|
+
//
|
|
3
|
+
// useWhatsNew(version) → headless handle (fetch + seen-state + open-state)
|
|
4
|
+
// <WhatsNewBadge> → menubar entry point (✦ + unseen-count dot)
|
|
5
|
+
// <WhatsNewToast> → first-run notice (bottom-left, mirrors ai-banner.tsx)
|
|
6
|
+
// <WhatsNewPanel> → list of entries (reuses the help-modal backdrop)
|
|
7
|
+
//
|
|
8
|
+
// Styling lives in client/styles/4-components.css (.mdcc-wn-*). Spotlight tours
|
|
9
|
+
// (entry.tour[]) land in Phase 3 — the panel/toast leave a hook for them.
|
|
10
|
+
|
|
11
|
+
import { useCallback, useEffect, useState } from 'react';
|
|
12
|
+
import { bestSeenVersion, computeUnseen } from './whats-new-seen.js';
|
|
13
|
+
|
|
14
|
+
const WN_SEEN = 'mdcc-whatsnew-seen';
|
|
15
|
+
const WN_TOAST = 'mdcc-whatsnew-toast-dismissed';
|
|
16
|
+
|
|
17
|
+
// learnMore renders as <a href> in the privileged main origin. Only bind an
|
|
18
|
+
// http(s) URL — belt-and-suspenders next to React's built-in URL sanitizer and
|
|
19
|
+
// the schema's pattern (security review, defense-in-depth).
|
|
20
|
+
function isSafeHref(url) {
|
|
21
|
+
return typeof url === 'string' && /^https?:\/\//i.test(url);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function readSeen(currentVersion) {
|
|
25
|
+
try {
|
|
26
|
+
const v = localStorage.getItem(WN_SEEN);
|
|
27
|
+
if (v) return v;
|
|
28
|
+
// First ever run: acknowledge the current version silently so a brand-new
|
|
29
|
+
// user isn't greeted with the entire backlog as "new". Only true upgrades
|
|
30
|
+
// (and pending dev entries) surface after this.
|
|
31
|
+
localStorage.setItem(WN_SEEN, currentVersion);
|
|
32
|
+
} catch {}
|
|
33
|
+
return currentVersion;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function readToastDismissed() {
|
|
37
|
+
try {
|
|
38
|
+
return localStorage.getItem(WN_TOAST);
|
|
39
|
+
} catch {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function useWhatsNew(currentVersion) {
|
|
45
|
+
const [entries, setEntries] = useState([]);
|
|
46
|
+
const [feedVersion, setFeedVersion] = useState(currentVersion);
|
|
47
|
+
const [seenVersion, setSeenVersion] = useState(() => readSeen(currentVersion));
|
|
48
|
+
const [toastDismissed, setToastDismissed] = useState(() => readToastDismissed());
|
|
49
|
+
const [panelOpen, setPanelOpen] = useState(false);
|
|
50
|
+
|
|
51
|
+
useEffect(() => {
|
|
52
|
+
let cancelled = false;
|
|
53
|
+
fetch('/_api/whats-new')
|
|
54
|
+
.then((r) => r.json())
|
|
55
|
+
.then((j) => {
|
|
56
|
+
if (cancelled) return;
|
|
57
|
+
setEntries(Array.isArray(j?.entries) ? j.entries : []);
|
|
58
|
+
if (typeof j?.version === 'string') setFeedVersion(j.version);
|
|
59
|
+
})
|
|
60
|
+
.catch(() => {
|
|
61
|
+
/* offline / restart — no banner */
|
|
62
|
+
});
|
|
63
|
+
return () => {
|
|
64
|
+
cancelled = true;
|
|
65
|
+
};
|
|
66
|
+
}, []);
|
|
67
|
+
|
|
68
|
+
const unseen = computeUnseen(entries, seenVersion);
|
|
69
|
+
const showToast = unseen.length > 0 && toastDismissed !== feedVersion && !panelOpen;
|
|
70
|
+
const toastEntry = unseen[0] ?? null;
|
|
71
|
+
|
|
72
|
+
const markAllSeen = useCallback(() => {
|
|
73
|
+
const next = bestSeenVersion(entries, feedVersion);
|
|
74
|
+
setSeenVersion(next);
|
|
75
|
+
setToastDismissed(feedVersion);
|
|
76
|
+
try {
|
|
77
|
+
localStorage.setItem(WN_SEEN, next);
|
|
78
|
+
localStorage.setItem(WN_TOAST, feedVersion);
|
|
79
|
+
} catch {}
|
|
80
|
+
}, [entries, feedVersion]);
|
|
81
|
+
|
|
82
|
+
const dismissToast = useCallback(() => {
|
|
83
|
+
setToastDismissed(feedVersion);
|
|
84
|
+
try {
|
|
85
|
+
localStorage.setItem(WN_TOAST, feedVersion);
|
|
86
|
+
} catch {}
|
|
87
|
+
}, [feedVersion]);
|
|
88
|
+
|
|
89
|
+
const openPanel = useCallback(() => setPanelOpen(true), []);
|
|
90
|
+
const closePanel = useCallback(() => {
|
|
91
|
+
setPanelOpen(false);
|
|
92
|
+
markAllSeen();
|
|
93
|
+
}, [markAllSeen]);
|
|
94
|
+
|
|
95
|
+
return {
|
|
96
|
+
entries,
|
|
97
|
+
unseen,
|
|
98
|
+
feedVersion,
|
|
99
|
+
panelOpen,
|
|
100
|
+
openPanel,
|
|
101
|
+
closePanel,
|
|
102
|
+
showToast,
|
|
103
|
+
toastEntry,
|
|
104
|
+
dismissToast,
|
|
105
|
+
markAllSeen,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export function WhatsNewBadge({ count = 0, onOpen }) {
|
|
110
|
+
return (
|
|
111
|
+
<button
|
|
112
|
+
type="button"
|
|
113
|
+
className="mdcc-wn-badge"
|
|
114
|
+
data-tour="whatsnew"
|
|
115
|
+
onClick={onOpen}
|
|
116
|
+
title="What's new"
|
|
117
|
+
aria-label={count > 0 ? `What's new — ${count} new` : "What's new"}
|
|
118
|
+
>
|
|
119
|
+
<span aria-hidden="true">✦</span>
|
|
120
|
+
<span className="mdcc-wn-badge__label">New</span>
|
|
121
|
+
{count > 0 && (
|
|
122
|
+
<span className="mdcc-wn-badge__dot" aria-hidden="true">
|
|
123
|
+
{count}
|
|
124
|
+
</span>
|
|
125
|
+
)}
|
|
126
|
+
</button>
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export function WhatsNewToast({ wn }) {
|
|
131
|
+
if (!wn.showToast || !wn.toastEntry) return null;
|
|
132
|
+
const e = wn.toastEntry;
|
|
133
|
+
const total = wn.unseen.length;
|
|
134
|
+
// Plan C P6 — restyled to the maude `.st-toast` family (was `mdcc-wn-toast`),
|
|
135
|
+
// matching `.design/ui/Studio.tsx` AB-D. Behavior unchanged.
|
|
136
|
+
return (
|
|
137
|
+
<div className="st-toast" role="status" aria-live="polite">
|
|
138
|
+
<button
|
|
139
|
+
type="button"
|
|
140
|
+
className="st-toast-close"
|
|
141
|
+
aria-label="Dismiss"
|
|
142
|
+
onClick={wn.dismissToast}
|
|
143
|
+
>
|
|
144
|
+
×
|
|
145
|
+
</button>
|
|
146
|
+
<div className="st-toast-hd">
|
|
147
|
+
<span aria-hidden="true">✦</span>
|
|
148
|
+
What's new{e.version ? ` · v${e.version}` : ''}
|
|
149
|
+
</div>
|
|
150
|
+
<div className="st-toast-title">{e.title}</div>
|
|
151
|
+
<div className="st-toast-txt">{e.summary}</div>
|
|
152
|
+
<div className="st-toast-actions">
|
|
153
|
+
<button type="button" className="btn btn--primary btn--sm" onClick={wn.openPanel}>
|
|
154
|
+
{total > 1 ? `See all (${total})` : 'Details'}
|
|
155
|
+
</button>
|
|
156
|
+
<button type="button" className="btn btn--ghost btn--sm" onClick={wn.dismissToast}>
|
|
157
|
+
Dismiss
|
|
158
|
+
</button>
|
|
159
|
+
</div>
|
|
160
|
+
</div>
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export function WhatsNewPanel({ wn, onStartTour }) {
|
|
165
|
+
const { panelOpen, closePanel } = wn;
|
|
166
|
+
useEffect(() => {
|
|
167
|
+
if (!panelOpen) return;
|
|
168
|
+
function onKey(e) {
|
|
169
|
+
if (e.key === 'Escape') closePanel();
|
|
170
|
+
}
|
|
171
|
+
window.addEventListener('keydown', onKey);
|
|
172
|
+
return () => window.removeEventListener('keydown', onKey);
|
|
173
|
+
}, [panelOpen, closePanel]);
|
|
174
|
+
|
|
175
|
+
if (!panelOpen) return null;
|
|
176
|
+
const unseenIds = new Set(wn.unseen.map((e) => e.id));
|
|
177
|
+
return (
|
|
178
|
+
<div
|
|
179
|
+
className="help-modal-backdrop"
|
|
180
|
+
role="presentation"
|
|
181
|
+
onMouseDown={(e) => {
|
|
182
|
+
if (e.target === e.currentTarget) closePanel();
|
|
183
|
+
}}
|
|
184
|
+
>
|
|
185
|
+
<div
|
|
186
|
+
className="mdcc-wn-panel"
|
|
187
|
+
role="dialog"
|
|
188
|
+
aria-modal="true"
|
|
189
|
+
aria-labelledby="mdcc-wn-title"
|
|
190
|
+
>
|
|
191
|
+
<header className="help-modal-hd">
|
|
192
|
+
<span className="title" id="mdcc-wn-title">
|
|
193
|
+
✦ What’s new in maude
|
|
194
|
+
</span>
|
|
195
|
+
<button
|
|
196
|
+
type="button"
|
|
197
|
+
className="help-modal-close"
|
|
198
|
+
aria-label="Close (Esc)"
|
|
199
|
+
onClick={closePanel}
|
|
200
|
+
>
|
|
201
|
+
×
|
|
202
|
+
</button>
|
|
203
|
+
</header>
|
|
204
|
+
<div className="mdcc-wn-panel__body">
|
|
205
|
+
{wn.entries.length === 0 ? (
|
|
206
|
+
<p className="mdcc-wn-empty">Nothing new yet.</p>
|
|
207
|
+
) : (
|
|
208
|
+
<ul className="mdcc-wn-list">
|
|
209
|
+
{wn.entries.map((e) => (
|
|
210
|
+
<li
|
|
211
|
+
key={e.id}
|
|
212
|
+
className={'mdcc-wn-item' + (unseenIds.has(e.id) ? ' is-unseen' : '')}
|
|
213
|
+
>
|
|
214
|
+
<div className="mdcc-wn-item__hd">
|
|
215
|
+
<span className={'mdcc-wn-kind mdcc-wn-kind--' + e.kind}>{e.kind}</span>
|
|
216
|
+
<span className="mdcc-wn-item__title">{e.title}</span>
|
|
217
|
+
<span className="mdcc-wn-item__ver">{e.version ? `v${e.version}` : 'next'}</span>
|
|
218
|
+
</div>
|
|
219
|
+
<p className="mdcc-wn-item__summary">{e.summary}</p>
|
|
220
|
+
{isSafeHref(e.learnMore) && (
|
|
221
|
+
<a
|
|
222
|
+
className="mdcc-wn-item__more"
|
|
223
|
+
href={e.learnMore}
|
|
224
|
+
target="_blank"
|
|
225
|
+
rel="noreferrer"
|
|
226
|
+
>
|
|
227
|
+
Learn more →
|
|
228
|
+
</a>
|
|
229
|
+
)}
|
|
230
|
+
{onStartTour && Array.isArray(e.tour) && e.tour.length > 0 && (
|
|
231
|
+
<button
|
|
232
|
+
type="button"
|
|
233
|
+
className="mdcc-wn-item__tour"
|
|
234
|
+
onClick={() => {
|
|
235
|
+
closePanel();
|
|
236
|
+
onStartTour(e.tour);
|
|
237
|
+
}}
|
|
238
|
+
>
|
|
239
|
+
▶ Take tour
|
|
240
|
+
</button>
|
|
241
|
+
)}
|
|
242
|
+
</li>
|
|
243
|
+
))}
|
|
244
|
+
</ul>
|
|
245
|
+
)}
|
|
246
|
+
</div>
|
|
247
|
+
</div>
|
|
248
|
+
</div>
|
|
249
|
+
);
|
|
250
|
+
}
|
|
@@ -7,13 +7,13 @@ import path from 'node:path';
|
|
|
7
7
|
import type { Api } from '../api.ts';
|
|
8
8
|
import type { Context } from '../context.ts';
|
|
9
9
|
|
|
10
|
-
import {
|
|
11
|
-
import { type Registry
|
|
10
|
+
import { createPersistence, Y_TYPES } from './persistence.ts';
|
|
11
|
+
import { createRegistry, type Registry } from './registry.ts';
|
|
12
12
|
|
|
13
|
-
export {
|
|
13
|
+
export type { CollabConn } from './protocol.ts';
|
|
14
14
|
export type { Registry } from './registry.ts';
|
|
15
15
|
export type { Room, RoomConn } from './room.ts';
|
|
16
|
-
export
|
|
16
|
+
export { Y_TYPES };
|
|
17
17
|
|
|
18
18
|
export interface Collab {
|
|
19
19
|
registry: Registry;
|
|
@@ -8,7 +8,7 @@ import * as Y from 'yjs';
|
|
|
8
8
|
|
|
9
9
|
import type { Api } from '../api.ts';
|
|
10
10
|
import type { Context } from '../context.ts';
|
|
11
|
-
import { type RoomCallbacks
|
|
11
|
+
import { ensureStateDir, type RoomCallbacks } from './room.ts';
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
14
|
* Y.Doc shared-type names. Frozen on Task 1 so client + server agree even
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @file commands/annotation-strokes-command.ts — undo entry for annotation
|
|
3
3
|
* stroke add / erase / batch-translate.
|
|
4
|
-
* @scope
|
|
4
|
+
* @scope apps/studio/commands/annotation-strokes-command.ts
|
|
5
5
|
* @purpose Records a `Stroke[]` pair (before/after) and routes both
|
|
6
6
|
* directions through a single `putFn`. The server endpoint is
|
|
7
7
|
* `PUT /_api/annotations` which replaces the entire SVG; we
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @file commands/equal-spacing-command.ts — undo label helpers for
|
|
3
3
|
* equal-spacing / align gestures.
|
|
4
|
-
* @scope
|
|
4
|
+
* @scope apps/studio/commands/equal-spacing-command.ts
|
|
5
5
|
* @purpose Distribute + align both call `dragBus.commitPositions(moved)`,
|
|
6
6
|
* which wraps the move in a generic MoveArtboardsCommand. Per
|
|
7
7
|
* DDR-050 the underlying command type is shared (the inverse
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @file commands/move-artboards-command.ts — undo entry for artboard moves
|
|
3
|
-
* @scope
|
|
3
|
+
* @scope apps/studio/commands/move-artboards-command.ts
|
|
4
4
|
* @purpose Reversible record of an artboard-layout PATCH. Pairs the full
|
|
5
5
|
* `before` and `after` layout snapshots with an injected
|
|
6
6
|
* `patchFn` (in production, `applyArtboardLayout`; in tests, a
|