@dailies-studio/shot-editor 0.1.0 → 0.2.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/dist/.vite/manifest.json +382 -0
- package/dist/assets/AgentPanel-CQejLbiX.js +2 -0
- package/dist/assets/AgentPanel-DJEphah0.css +1 -0
- package/dist/assets/AgentQuestionDialog-BqkD0kXF.js +1 -0
- package/dist/assets/CodeStudio-Dv4ihHpz.js +23 -0
- package/dist/assets/CommentsPanel-B4yhhT1T.js +1 -0
- package/dist/assets/ComponentLibraryRail-Ch_dsAru.js +1 -0
- package/dist/assets/ComponentStage-BRhRotyH.js +1 -0
- package/dist/assets/CurvePane-BjFVabKX.css +1 -0
- package/dist/assets/CurvePane-R22WzllJ.js +1 -0
- package/dist/assets/ExportDialog-CWLQWTmG.js +2 -0
- package/dist/assets/FontPicker-DWKaYL7F.js +1 -0
- package/dist/assets/FontPicker-v0IOIArM.css +1 -0
- package/dist/assets/GenerateDrawer-Bh3SqDKt.js +2 -0
- package/dist/assets/InsertDrawer-Ce1fod1L.js +1 -0
- package/dist/assets/LibraryBrowser-D9sEGz5w.js +2 -0
- package/dist/assets/MakeItYoursSection-CMO4319_.js +2 -0
- package/dist/assets/MaterialGraphCanvas-BFzl4wWR.js +23 -0
- package/dist/assets/MaterialGraphCanvas-BIUD59ik.css +1 -0
- package/dist/assets/MaterialWorkspace-CqTWqaRA.js +14 -0
- package/dist/assets/PreferencesDialog-CBf9_OoD.js +1 -0
- package/dist/assets/PresetsSection-CUEaoCVU.js +1 -0
- package/dist/assets/SoundHistory-BeS8EW1h.js +1 -0
- package/dist/assets/SoundMode-BmcZru3i.js +3 -0
- package/dist/assets/StockSounds-DdAUGRYK.js +1 -0
- package/dist/assets/TemplateFieldSection-CaeXpLFo.js +1 -0
- package/dist/assets/VersionHistoryPanel-CxG6XhNP.js +1 -0
- package/dist/assets/board-B88EPuLO.css +1 -0
- package/dist/assets/board-CL-he7SL.js +3 -0
- package/dist/assets/components-0oOSPN0l.js +1 -0
- package/dist/assets/googleFontRanges-gp32wJMo.js +1 -0
- package/dist/assets/googleFonts-BNon6M7X.js +1 -0
- package/dist/assets/iconsAndAliases-DL7gXP5j.js +1863 -0
- package/dist/assets/index-4F5NQmI8.css +1 -0
- package/dist/assets/index-BGHQGV5z.js +117 -0
- package/dist/assets/inter-cyrillic-ext-wght-normal-BOeWTOD4.woff2 +0 -0
- package/dist/assets/inter-cyrillic-wght-normal-DqGufNeO.woff2 +0 -0
- package/dist/assets/inter-greek-ext-wght-normal-DlzME5K_.woff2 +0 -0
- package/dist/assets/inter-greek-wght-normal-CkhJZR-_.woff2 +0 -0
- package/dist/assets/inter-latin-ext-wght-normal-DO1Apj_S.woff2 +0 -0
- package/dist/assets/inter-latin-wght-normal-Dx4kXJAl.woff2 +0 -0
- package/dist/assets/inter-vietnamese-wght-normal-CBcvBZtf.woff2 +0 -0
- package/dist/assets/libraryModel-CpIwfFha.js +1 -0
- package/dist/assets/lucide-6iK64tTB.js +9319 -0
- package/dist/assets/motionStamp-CH-Hew4E.js +1 -0
- package/dist/assets/takeMeasure-Tdg0TxEi.js +1 -0
- package/dist/assets/webmcp-BsB9gxWC.js +2 -0
- package/dist/index.html +34 -3
- package/package.json +12 -9
- package/src/addFamilies.ts +66 -0
- package/src/api.ts +1631 -55
- package/src/app/App.tsx +977 -198
- package/src/app/lazyPanel.tsx +137 -0
- package/src/app/lazySurfaces.tsx +203 -0
- package/src/audio/index.tsx +41 -10
- package/src/audio/meter.ts +485 -0
- package/src/audio/meterMath.ts +273 -0
- package/src/audio/meterStore.ts +155 -0
- package/src/audio/offlineMix.ts +289 -0
- package/src/audio/preview.ts +928 -118
- package/src/bridge.ts +15 -5
- package/src/bridgeTypes.ts +1611 -36
- package/src/channels.ts +17 -32
- package/src/fonts/googleFonts.ts +4 -0
- package/src/hostApi.ts +174 -0
- package/src/icons.tsx +770 -0
- package/src/layerWords.ts +61 -0
- package/src/main.tsx +56 -4
- package/src/panels/ResizeHandle.tsx +33 -43
- package/src/panels/agent/AgentDots.tsx +36 -0
- package/src/panels/agent/AgentPanel.tsx +119 -43
- package/src/panels/agent/AgentQuestionDialog.tsx +202 -0
- package/src/panels/agent/agent.css +113 -97
- package/src/panels/agent/agentGate.ts +35 -0
- package/src/panels/code/CodeDefaultsPanel.tsx +345 -0
- package/src/panels/code/CodeStudio.tsx +373 -0
- package/src/panels/code/FileTree.tsx +265 -0
- package/src/panels/code/codeBufferGuard.ts +52 -0
- package/src/panels/code/codeParts.tsx +321 -0
- package/src/panels/comments/CommentComposer.tsx +239 -0
- package/src/panels/comments/CommentThread.tsx +346 -0
- package/src/panels/comments/CommentsPanel.tsx +336 -0
- package/src/panels/comments/InboxButton.tsx +131 -0
- package/src/panels/comments/MentionMenu.tsx +98 -0
- package/src/panels/comments/parts.tsx +171 -0
- package/src/panels/export/ExportDialog.tsx +919 -96
- package/src/panels/export/ExportScrim.tsx +57 -0
- package/src/panels/files/AssetsTab.tsx +656 -0
- package/src/panels/files/FilePanel.tsx +1466 -216
- package/src/panels/files/LayerMarks.tsx +40 -0
- package/src/panels/files/LeftColumn.tsx +37 -0
- package/src/panels/files/McpSection.tsx +690 -47
- package/src/panels/files/MissingAssetsNotice.tsx +60 -0
- package/src/panels/files/assetDrag.ts +79 -0
- package/src/panels/files/resourceParts.tsx +255 -0
- package/src/panels/fonts/FontPicker.tsx +762 -0
- package/src/panels/fonts/faceCache.ts +207 -0
- package/src/panels/fonts/fontPicker.css +271 -0
- package/src/panels/fonts/pickerModel.ts +265 -0
- package/src/panels/fonts/pickerRequest.ts +46 -0
- package/src/panels/header/AccountAvatar.tsx +76 -0
- package/src/panels/header/AgentChip.tsx +77 -0
- package/src/panels/header/AppMenu.tsx +213 -0
- package/src/panels/header/Header.tsx +564 -84
- package/src/panels/header/HistoryControls.tsx +31 -5
- package/src/panels/header/PresenceStack.tsx +329 -0
- package/src/panels/header/ProjectTitle.tsx +232 -0
- package/src/panels/header/ShareButton.tsx +59 -0
- package/src/panels/header/StatusBadges.tsx +358 -27
- package/src/panels/header/SyncDeletedDialog.tsx +88 -0
- package/src/panels/header/ZoomControls.tsx +46 -15
- package/src/panels/header/agentHandoff.ts +52 -0
- package/src/panels/header/leave.ts +26 -0
- package/src/panels/help/HelpSection.tsx +189 -163
- package/src/panels/insert/InsertDrawer.tsx +723 -0
- package/src/panels/insert/iconSet.ts +109 -0
- package/src/panels/inspector/ExposeDot.tsx +117 -0
- package/src/panels/inspector/FramingRows.tsx +314 -44
- package/src/panels/inspector/InspectorFooter.tsx +91 -0
- package/src/panels/inspector/InspectorHead.tsx +425 -0
- package/src/panels/inspector/InspectorPanel.tsx +408 -124
- package/src/panels/inspector/KeyframeDot.tsx +373 -0
- package/src/panels/inspector/KeyframeSection.tsx +257 -0
- package/src/panels/inspector/MarkerSection.tsx +55 -11
- package/src/panels/inspector/ParamRow.tsx +84 -53
- package/src/panels/inspector/RightColumn.tsx +152 -0
- package/src/panels/inspector/TimeSection.tsx +866 -0
- package/src/panels/inspector/animate/EaseControl.tsx +244 -0
- package/src/panels/inspector/animate/PresetsSection.tsx +135 -0
- package/src/panels/inspector/animate/ShotSection.tsx +562 -48
- package/src/panels/inspector/design/AlignRow.tsx +95 -31
- package/src/panels/inspector/design/AppearanceSection.tsx +118 -9
- package/src/panels/inspector/design/ClonerSection.tsx +323 -62
- package/src/panels/inspector/design/ComponentSection.tsx +50 -43
- package/src/panels/inspector/design/CornerSection.tsx +45 -14
- package/src/panels/inspector/design/DefinitionProps.tsx +315 -0
- package/src/panels/inspector/design/DefinitionSection.tsx +136 -0
- package/src/panels/inspector/design/DeviceSection.tsx +210 -0
- package/src/panels/inspector/design/FillSection.tsx +83 -51
- package/src/panels/inspector/design/FontField.tsx +196 -0
- package/src/panels/inspector/design/HtmlSection.tsx +23 -12
- package/src/panels/inspector/design/InstanceSection.tsx +373 -154
- package/src/panels/inspector/design/MaskSection.tsx +84 -0
- package/src/panels/inspector/design/MaterialSection.tsx +177 -0
- package/src/panels/inspector/design/MediaSection.tsx +273 -120
- package/src/panels/inspector/design/MeshSection.tsx +910 -82
- package/src/panels/inspector/design/PaintRows.tsx +550 -0
- package/src/panels/inspector/design/PlateStyleSection.tsx +177 -0
- package/src/panels/inspector/design/ShadowSection.tsx +221 -48
- package/src/panels/inspector/design/SplineFollowSection.tsx +235 -0
- package/src/panels/inspector/design/StrokeSection.tsx +228 -43
- package/src/panels/inspector/design/TemplateFieldSection.tsx +57 -0
- package/src/panels/inspector/design/TransformSection.tsx +244 -50
- package/src/panels/inspector/design/TypographySection.tsx +679 -110
- package/src/panels/inspector/layout.ts +295 -0
- package/src/panels/inspector/propValue.ts +199 -0
- package/src/panels/inspector/scene/CameraSection.tsx +232 -22
- package/src/panels/inspector/scene/EffectsSection.tsx +722 -71
- package/src/panels/inspector/scene/MakeItYoursSection.tsx +180 -0
- package/src/panels/inspector/scene/SceneDocSection.tsx +191 -0
- package/src/panels/inspector/scene/SceneSection.tsx +219 -44
- package/src/panels/inspector/scene/TransitionSection.tsx +523 -72
- package/src/panels/inspector/storyboard/StoryboardReferenceSection.tsx +593 -0
- package/src/panels/inspector/storyboard/VideoStill.tsx +120 -0
- package/src/panels/inspector/timeModel.ts +190 -0
- package/src/panels/inspector/useDocWrite.ts +438 -146
- package/src/panels/library/LibraryBrowser.tsx +435 -0
- package/src/panels/library/LibraryGrid.tsx +190 -0
- package/src/panels/library/LibraryPreviewPanel.tsx +349 -0
- package/src/panels/library/LibraryRail.tsx +84 -0
- package/src/panels/library/LibrarySoundPanel.tsx +293 -0
- package/src/panels/library/SoundHistory.tsx +245 -0
- package/src/panels/library/StockSounds.tsx +390 -0
- package/src/panels/library/libraryModel.ts +147 -0
- package/src/panels/library/stockSearch.ts +77 -0
- package/src/panels/maskMarks.tsx +117 -0
- package/src/panels/material/MaterialCommentNode.tsx +54 -0
- package/src/panels/material/MaterialGraphCanvas.tsx +861 -0
- package/src/panels/material/MaterialGraphMenu.tsx +45 -0
- package/src/panels/material/MaterialGroupNode.tsx +56 -0
- package/src/panels/material/MaterialLibrary.tsx +253 -0
- package/src/panels/material/MaterialNode.tsx +453 -0
- package/src/panels/material/MaterialNodePalette.tsx +349 -0
- package/src/panels/material/MaterialParameterControls.tsx +525 -0
- package/src/panels/material/MaterialRerouteNode.tsx +42 -0
- package/src/panels/material/MaterialWorkspace.tsx +501 -0
- package/src/panels/material/NodePreview.tsx +70 -0
- package/src/panels/material/flowModel.ts +441 -0
- package/src/panels/material/parameterValues.ts +231 -0
- package/src/panels/material/previewScheduler.ts +235 -0
- package/src/panels/material/reactFlow.css +6 -0
- package/src/panels/material/socketGlyph.ts +85 -0
- package/src/panels/material/viewportMemory.ts +58 -0
- package/src/panels/preferences/PreferencesDialog.tsx +215 -0
- package/src/panels/share/ShareComponentDialog.tsx +247 -0
- package/src/panels/stage/StageMenu.tsx +35 -5
- package/src/panels/stage/StagePanel.tsx +338 -23
- package/src/panels/stage/cellSlots.tsx +70 -0
- package/src/panels/storyboard/BoardCanvas.tsx +739 -0
- package/src/panels/storyboard/BoardCursors.tsx +158 -0
- package/src/panels/storyboard/BoardDropDialog.tsx +161 -0
- package/src/panels/storyboard/BoardPlan.tsx +42 -0
- package/src/panels/storyboard/ComponentSheet.tsx +187 -0
- package/src/panels/storyboard/ComponentStage.tsx +235 -0
- package/src/panels/storyboard/MiniSketch.tsx +173 -0
- package/src/panels/storyboard/PartPicker.tsx +64 -0
- package/src/panels/storyboard/PlanPanel.tsx +617 -0
- package/src/panels/storyboard/ReferencePreview.tsx +217 -0
- package/src/panels/storyboard/ShotBrief.tsx +360 -0
- package/src/panels/storyboard/ShotCard.tsx +251 -0
- package/src/panels/storyboard/StagePreview.tsx +348 -0
- package/src/panels/storyboard/StillThumbs.tsx +162 -0
- package/src/panels/storyboard/StoryboardView.tsx +79 -0
- package/src/panels/storyboard/board.css +1065 -0
- package/src/panels/storyboard/board.ts +12 -0
- package/src/panels/storyboard/boardClipboard.ts +111 -0
- package/src/panels/storyboard/boardOrder.ts +68 -0
- package/src/panels/storyboard/boardRows.tsx +425 -0
- package/src/panels/storyboard/liveCap.ts +90 -0
- package/src/panels/storyboard/plan.css +295 -0
- package/src/panels/storyboard/posterCache.ts +133 -0
- package/src/panels/storyboard/shotboard/ComponentPicker.tsx +373 -0
- package/src/panels/storyboard/shotboard/ImagePicker.tsx +145 -0
- package/src/panels/storyboard/shotboard/ShotBoard.tsx +292 -0
- package/src/panels/storyboard/shotboard/SketchCanvas.tsx +443 -0
- package/src/panels/storyboard/shotboard/SketchInspector.tsx +471 -0
- package/src/panels/storyboard/shotboard/SketchItem.tsx +240 -0
- package/src/panels/storyboard/shotboard/SketchLayers.tsx +130 -0
- package/src/panels/storyboard/shotboard/SketchPlay.tsx +108 -0
- package/src/panels/storyboard/shotboard/SketchStrip.tsx +178 -0
- package/src/panels/storyboard/shotboard/SketchToolFooter.tsx +99 -0
- package/src/panels/storyboard/shotboard/sketch.css +1392 -0
- package/src/panels/storyboard/shotboard/sketchModel.ts +219 -0
- package/src/panels/storyboard/storyboardDrop.ts +164 -0
- package/src/panels/studio/ComponentLibraryRail.tsx +346 -0
- package/src/panels/studio/ComponentSidePanel.tsx +355 -0
- package/src/panels/studio/ComponentStudio.tsx +243 -0
- package/src/panels/studio/ComponentsHome.tsx +318 -0
- package/src/panels/studio/ComponentsPreview.tsx +179 -0
- package/src/panels/studio/EveryUse.tsx +244 -0
- package/src/panels/studio/ThisUsePanel.tsx +679 -0
- package/src/panels/studio/componentParts.tsx +341 -0
- package/src/panels/studio/components.ts +6 -0
- package/src/panels/studio/newCodeComponent.ts +66 -0
- package/src/panels/timeline/AudioFxButton.tsx +290 -0
- package/src/panels/timeline/AudioLane.tsx +674 -85
- package/src/panels/timeline/BlockRow.tsx +154 -85
- package/src/panels/timeline/ChannelRow.tsx +378 -129
- package/src/panels/timeline/CurvePane.tsx +508 -0
- package/src/panels/timeline/Filmstrip.tsx +361 -0
- package/src/panels/timeline/GenerateDrawer.tsx +407 -0
- package/src/panels/timeline/KeyStretch.tsx +115 -0
- package/src/panels/timeline/LifespanRow.tsx +730 -47
- package/src/panels/timeline/MarkerLane.tsx +46 -8
- package/src/panels/timeline/PlayButton.tsx +91 -0
- package/src/panels/timeline/PropertyPicker.tsx +254 -0
- package/src/panels/timeline/ShotRow.tsx +400 -0
- package/src/panels/timeline/SoundMode.tsx +1406 -0
- package/src/panels/timeline/TimelineDock.tsx +2338 -272
- package/src/panels/timeline/TransportVolume.tsx +163 -0
- package/src/panels/timeline/beatRuler.ts +74 -0
- package/src/panels/timeline/curveModel.ts +500 -0
- package/src/panels/timeline/duckUnderVoice.ts +68 -0
- package/src/panels/timeline/keyframeMenu.ts +138 -0
- package/src/panels/timeline/labelWidth.ts +49 -0
- package/src/panels/timeline/marquee.ts +155 -0
- package/src/panels/timeline/model.ts +1860 -199
- package/src/panels/timeline/snap.ts +125 -43
- package/src/panels/timeline/staggerPreview.tsx +92 -0
- package/src/panels/timeline/takeMeasure.ts +72 -0
- package/src/panels/timeline/useLive.ts +48 -0
- package/src/panels/timeline/viewport.ts +234 -0
- package/src/panels/toolbar/BackChip.tsx +116 -0
- package/src/panels/toolbar/CameraViewBar.tsx +118 -49
- package/src/panels/toolbar/CanvasBar.tsx +117 -0
- package/src/panels/toolbar/InsertButton.tsx +38 -0
- package/src/panels/toolbar/IsolationTrail.tsx +156 -0
- package/src/panels/toolbar/PanelToggles.tsx +86 -0
- package/src/panels/toolbar/ShadingBar.tsx +119 -26
- package/src/panels/toolbar/ToolDockBar.tsx +329 -80
- package/src/panels/toolbar/ToolFooter.tsx +102 -0
- package/src/panels/toolbar/ViewModeBar.tsx +247 -38
- package/src/panels/toolbar/WorkPlaneBar.tsx +94 -0
- package/src/panels/toolbar/useAddRows.tsx +326 -0
- package/src/panels/toolbar/useDismiss.ts +122 -0
- package/src/panels/versions/VersionHistoryPanel.tsx +274 -0
- package/src/panels/versions/versionModel.ts +103 -0
- package/src/panels/virtualWindow.ts +271 -0
- package/src/shotTokens.css +151 -60
- package/src/stage/FrustumGizmo.tsx +504 -84
- package/src/stage/GridPlane.tsx +225 -16
- package/src/stage/NodePreviews.tsx +628 -0
- package/src/stage/PerfHud.tsx +437 -47
- package/src/stage/SplitRenderer.tsx +816 -169
- package/src/stage/StageApp.tsx +4274 -486
- package/src/stage/StageRootBoundary.tsx +114 -0
- package/src/stage/StageTools.tsx +651 -151
- package/src/stage/TransformGizmo.tsx +696 -0
- package/src/stage/adaptivePresentation.ts +145 -0
- package/src/stage/bridgeClient.ts +2522 -41
- package/src/stage/exportWorker.ts +9 -0
- package/src/stage/feed.ts +305 -14
- package/src/stage/fontPreview.ts +176 -0
- package/src/stage/frustumGeometry.ts +319 -1
- package/src/stage/furnitureTokens.ts +33 -0
- package/src/stage/gizmoMath.ts +508 -16
- package/src/stage/gpuTimer.ts +276 -0
- package/src/stage/instanceModules.ts +194 -33
- package/src/stage/interactions/move.ts +24 -5
- package/src/stage/isolation.ts +291 -33
- package/src/stage/jsSelfProfiler.ts +325 -0
- package/src/stage/main.tsx +116 -16
- package/src/stage/modalState.ts +222 -23
- package/src/stage/moduleEpoch.ts +60 -0
- package/src/stage/motionPathStage.ts +279 -0
- package/src/stage/motionPreview.ts +74 -0
- package/src/stage/overlays/Overlays.tsx +1112 -159
- package/src/stage/overlays/Rulers.tsx +495 -0
- package/src/stage/panes.ts +159 -10
- package/src/stage/project.ts +68 -3
- package/src/stage/renderScaleController.ts +730 -0
- package/src/stage/rulers.ts +129 -0
- package/src/stage/sceneExtent.ts +75 -0
- package/src/stage/shading.ts +20 -0
- package/src/stage/splineStage.ts +632 -0
- package/src/stage/stagePerformanceTelemetry.ts +717 -0
- package/src/stage/stageTheme.ts +36 -0
- package/src/stage/stageWarmup.ts +11 -0
- package/src/stage/textAutoSize.ts +124 -0
- package/src/stage/tier1Export.ts +641 -0
- package/src/stage/tokenColor.ts +14 -9
- package/src/stage/view.ts +56 -9
- package/src/stage/workingView.ts +277 -33
- package/src/state/accountPrefs.ts +261 -0
- package/src/state/agentActions.ts +173 -15
- package/src/state/agentActivity.ts +198 -0
- package/src/state/agentQuestion.ts +239 -0
- package/src/state/bootOpen.ts +42 -0
- package/src/state/cameraVerbs.ts +139 -0
- package/src/state/clientId.ts +6 -1
- package/src/state/comments.ts +1099 -0
- package/src/state/context.tsx +19 -1
- package/src/state/editorPrefs.ts +220 -0
- package/src/state/errorReports.ts +121 -0
- package/src/state/fieldWrite.ts +161 -0
- package/src/state/fontRecents.ts +70 -0
- package/src/state/fonts.ts +656 -0
- package/src/state/graphClipboard.ts +414 -0
- package/src/state/imageThumbs.ts +216 -0
- package/src/state/insert.ts +444 -67
- package/src/state/isolationTrail.ts +92 -0
- package/src/state/keyMoves.ts +134 -0
- package/src/state/keyframeClipboard.ts +177 -0
- package/src/state/keymap.ts +1153 -117
- package/src/state/layoutPrefs.ts +272 -0
- package/src/state/layouts.ts +205 -0
- package/src/state/measureMedia.ts +167 -0
- package/src/state/menu.ts +2341 -28
- package/src/state/motionStamp.ts +7 -0
- package/src/state/panelSize.ts +375 -5
- package/src/state/pendingChanges.ts +119 -0
- package/src/state/playHold.ts +78 -0
- package/src/state/playbackPreparation.ts +562 -0
- package/src/state/posterCapture.ts +242 -0
- package/src/state/presence.ts +254 -0
- package/src/state/projectComponents.ts +160 -0
- package/src/state/renderEvents.ts +298 -18
- package/src/state/runtimeErrors.ts +46 -0
- package/src/state/selection.ts +12 -0
- package/src/state/shortcuts.ts +1606 -0
- package/src/state/sketchGuide.ts +51 -0
- package/src/state/splineRefs.ts +87 -0
- package/src/state/stageHealth.ts +259 -0
- package/src/state/stageWatchdog.ts +47 -0
- package/src/state/stillStage.ts +330 -0
- package/src/state/stillThumbs.ts +474 -0
- package/src/state/store.ts +23591 -2982
- package/src/state/storyboardModel.ts +528 -0
- package/src/state/sync.ts +1257 -0
- package/src/state/syncCache.ts +159 -0
- package/src/state/triangles.ts +13 -0
- package/src/state/types.ts +1698 -55
- package/src/state/unsavedGuard.ts +49 -0
- package/src/state/viewMode.ts +200 -0
- package/src/state/webmcp.ts +1128 -0
- package/src/state/workspace.ts +1147 -0
- package/src/styles/assets-tab.css +304 -0
- package/src/styles/canvas.css +545 -0
- package/src/styles/comments.css +1435 -0
- package/src/styles/controls.css +162 -0
- package/src/styles/dialogs.css +390 -0
- package/src/styles/insert-drawer.css +586 -0
- package/src/styles/inspector-board.css +207 -0
- package/src/styles/inspector-object.css +486 -0
- package/src/styles/inspector-shot.css +252 -0
- package/src/styles/inspector.css +360 -0
- package/src/styles/left-column.css +1628 -0
- package/src/styles/library-preview.css +575 -0
- package/src/styles/library.css +512 -0
- package/src/styles/modes/code.css +569 -0
- package/src/styles/modes/component.css +1561 -0
- package/src/styles/modes/material.css +1201 -0
- package/src/styles/modes/storyboard.css +518 -0
- package/src/styles/share-component.css +49 -0
- package/src/styles/shell.css +653 -0
- package/src/styles/shot-brief.css +360 -0
- package/src/styles/states.css +76 -0
- package/src/styles/sync.css +380 -0
- package/src/styles/timeline-graph.css +384 -0
- package/src/styles/timeline-meters.css +89 -0
- package/src/styles/timeline-rows.css +1959 -0
- package/src/styles/timeline-sound.css +1003 -0
- package/src/styles/timeline.css +754 -0
- package/src/styles/tool-footer.css +525 -0
- package/src/styles/topbar.css +886 -0
- package/src/styles/versions.css +262 -0
- package/src/styles.css +72 -2921
- package/src/tools.ts +108 -23
- package/dist/assets/index-B7notge7.css +0 -1
- package/dist/assets/index-BBE6Ta9L.js +0 -52
- package/src/panels/files/icons.tsx +0 -118
- package/src/panels/header/DocSwitcher.tsx +0 -85
- package/src/panels/header/TransportBar.tsx +0 -86
- package/src/panels/inspector/animate/BlockTiming.tsx +0 -341
- package/src/panels/inspector/animate/DuringBlocks.tsx +0 -85
- package/src/panels/inspector/animate/InOutPresets.tsx +0 -57
- package/src/panels/inspector/animate/ResolvedChannels.tsx +0 -150
- package/src/panels/inspector/animate/useBlocks.ts +0 -43
- package/src/panels/material/MaterialPicker.tsx +0 -172
- package/src/panels/timeline/SceneStrip.tsx +0 -145
- package/src/panels/toolbar/AddMenu.tsx +0 -230
- package/src/stage/MoveGizmo.tsx +0 -411
|
@@ -0,0 +1,471 @@
|
|
|
1
|
+
// THE SHOT BOARD'S ITEM INSPECTOR (Paper SB3, SB5): the right column while
|
|
2
|
+
// items on the sketch are selected (`boardRightPanel` answers "sketch").
|
|
3
|
+
//
|
|
4
|
+
// THE STUDIO INSPECTOR'S LOOK: static sections (`InspectorSection`) of rows
|
|
5
|
+
// (`InspectorRow`) with each label inside its pill, and Position as the
|
|
6
|
+
// Transform section's grid of fields with their names inside (X, Y, W, H).
|
|
7
|
+
//
|
|
8
|
+
// image its picture, Fit and Replace, then its card (Use, Importance:
|
|
9
|
+
// the card-use block every board panel shares, and the note),
|
|
10
|
+
// then Position
|
|
11
|
+
// component Open in Components, its props on the card (`ThisUsePanel`, so a
|
|
12
|
+
// tweak rides on `card.props`, live while it plays), its card
|
|
13
|
+
// (Frame, Use, Importance, the note), Position; while playing,
|
|
14
|
+
// what the stage holds
|
|
15
|
+
// text its words, role and alignment; box: label and tone; arrow:
|
|
16
|
+
// label
|
|
17
|
+
// several align and distribute (`ALIGN_MODES`' words, `alignPatches`)
|
|
18
|
+
//
|
|
19
|
+
// THE ITEM'S OWN FIELDS write through the store's sketch verbs, which lock
|
|
20
|
+
// the layout while it plays (X/Y/W/H show it read-only then); the card's
|
|
21
|
+
// fields through `updateReference`. Every write is one undo step, and a drag
|
|
22
|
+
// on X, Y, W or H is one too, drawn on the paper as it moves
|
|
23
|
+
// (`beginSketchDrag`). A viewer reads it all with the writes off
|
|
24
|
+
// (`LockedControls`).
|
|
25
|
+
import { useEffect, useRef, useState } from "react";
|
|
26
|
+
import type { ReactNode } from "react";
|
|
27
|
+
import { ALIGN_LABELS, MIN_DISTRIBUTE, DISTRIBUTE_MODES, SKETCH_LABEL_MAX, SKETCH_TEXT_MAX, addReference, findSketchItem, sketchCardOf, updateSketchItem } from "@dailies-studio/shot/doc";
|
|
28
|
+
import type { AlignMode, Doc3D, ReferenceItem3D, SketchItem3D, SketchItemPatch, SketchRef3D } from "@dailies-studio/shot/doc";
|
|
29
|
+
import { InspectorRow, InspectorSection, LockedControls, NumberField, PropertyGrid, SegmentedControl, TextField, useLocked } from "@dailies-studio/ui";
|
|
30
|
+
import { COMPONENT_ICON, OPEN_ELSEWHERE_ICON, SPARKLES_ICON, kindIcon } from "../../../icons.js";
|
|
31
|
+
import { useShotEditor, useStore } from "../../../state/context.js";
|
|
32
|
+
import { useImageThumb } from "../../../state/imageThumbs.js";
|
|
33
|
+
import { SKETCH_PLAYING } from "../../../state/store.js";
|
|
34
|
+
import { BUILTIN_NO_MASTER, cardUseKey, isBuiltinComponent } from "../../../state/workspace.js";
|
|
35
|
+
import { ThisUsePanel } from "../../studio/ThisUsePanel.js";
|
|
36
|
+
import { CardNoteRow, CardUseRows } from "../boardRows.js";
|
|
37
|
+
import { assetUrl } from "../ReferencePreview.js";
|
|
38
|
+
import { ImagePicker } from "./ImagePicker.js";
|
|
39
|
+
import type { ImagePick } from "./ImagePicker.js";
|
|
40
|
+
import { alignPatches, componentNameOf, fileNameOf, itemKindOf, itemNameOf } from "./sketchModel.js";
|
|
41
|
+
|
|
42
|
+
/** The align and distribute glyphs, AlignRow's own 24-grid strokes. */
|
|
43
|
+
const ALIGN_PATHS = {
|
|
44
|
+
left: "M5 3V21M8 7H20V10H8M8 14H16V17H8",
|
|
45
|
+
hcenter: "M12 3V21M5 7H19V10H5M8 14H16V17H8",
|
|
46
|
+
right: "M19 3V21M4 7H16V10H4M8 14H16V17H8",
|
|
47
|
+
top: "M3 5H21M7 8V20H10V8M14 8V16H17V8",
|
|
48
|
+
vcenter: "M3 12H21M7 5V19H10V5M14 8V16H17V8",
|
|
49
|
+
bottom: "M3 19H21M7 4V16H10V4M14 8V16H17V8",
|
|
50
|
+
hdistribute: "M3 4V20M21 4V20M7 8V16M12 5V19M17 8V16",
|
|
51
|
+
vdistribute: "M4 3H20M4 21H20M8 7H16M5 12H19M8 17H16",
|
|
52
|
+
} as const satisfies Record<AlignMode, string>;
|
|
53
|
+
const ALIGN_ORDER: readonly AlignMode[] = ["left", "hcenter", "right", "hdistribute", "top", "vcenter", "bottom", "vdistribute"];
|
|
54
|
+
|
|
55
|
+
export function SketchInspector() {
|
|
56
|
+
const doc = useShotEditor((s) => s.doc);
|
|
57
|
+
const selection = useShotEditor((s) => s.sketchSelection);
|
|
58
|
+
if (doc === null) return null;
|
|
59
|
+
const items = selection.flatMap((id) => {
|
|
60
|
+
const at = findSketchItem(doc, id);
|
|
61
|
+
return at === null ? [] : [at.item];
|
|
62
|
+
});
|
|
63
|
+
if (items.length === 0) return null;
|
|
64
|
+
if (items.length > 1) {
|
|
65
|
+
return (
|
|
66
|
+
<Shell icon={kindIcon("rect")} title={`${items.length} items`}>
|
|
67
|
+
<AlignSection doc={doc} items={items} />
|
|
68
|
+
</Shell>
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
const item = items[0]!;
|
|
72
|
+
switch (item.kind) {
|
|
73
|
+
case "text":
|
|
74
|
+
return <TextInspector doc={doc} item={item} />;
|
|
75
|
+
case "box":
|
|
76
|
+
return <BoxInspector doc={doc} item={item} />;
|
|
77
|
+
case "arrow":
|
|
78
|
+
return <ArrowInspector doc={doc} item={item} />;
|
|
79
|
+
case "ref": {
|
|
80
|
+
const card = sketchCardOf(doc, item);
|
|
81
|
+
if (card?.type === "component") return <ComponentInspector doc={doc} item={item} card={card} />;
|
|
82
|
+
return <PictureInspector doc={doc} item={item} card={card?.type === "asset" ? card : undefined} />;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// ── the frame of every inspector ─────────────────────────────────────────
|
|
88
|
+
|
|
89
|
+
function Shell(props: { icon: ReactNode; title: string; badge?: string; children: ReactNode }) {
|
|
90
|
+
const readOnly = useShotEditor((s) => s.readOnly);
|
|
91
|
+
const playing = useShotEditor((s) => s.sketchPlaying);
|
|
92
|
+
return (
|
|
93
|
+
<section className="sketch-inspector" aria-label={props.title} data-testid="sketch-inspector">
|
|
94
|
+
<header className="panel-head sketch-inspector-head">
|
|
95
|
+
<span className="sketch-inspector-icon" aria-hidden="true">
|
|
96
|
+
{props.icon}
|
|
97
|
+
</span>
|
|
98
|
+
<h3 className="sketch-inspector-title">{props.title}</h3>
|
|
99
|
+
{props.badge === undefined ? null : <span className="badge">{props.badge}</span>}
|
|
100
|
+
</header>
|
|
101
|
+
{playing ? (
|
|
102
|
+
<div className="sketch-inspector-playing" data-testid="sketch-inspector-playing">
|
|
103
|
+
<span className="sketch-live-dot" aria-hidden="true" />
|
|
104
|
+
<span className="sketch-inspector-playing-word">Playing in one stage</span>
|
|
105
|
+
<span className="sketch-inspector-meta">1 context</span>
|
|
106
|
+
</div>
|
|
107
|
+
) : null}
|
|
108
|
+
<LockedControls value={readOnly}>
|
|
109
|
+
<div className="sketch-inspector-body">{props.children}</div>
|
|
110
|
+
</LockedControls>
|
|
111
|
+
<footer className="panel-foot is-note">
|
|
112
|
+
{SPARKLES_ICON}
|
|
113
|
+
The agent reads this item as layout text.
|
|
114
|
+
</footer>
|
|
115
|
+
</section>
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/** One of the inspector's groups: a static section, the Studio's. */
|
|
120
|
+
function Group(props: { title: string; children: ReactNode }) {
|
|
121
|
+
return (
|
|
122
|
+
<InspectorSection title={props.title} collapsible={false}>
|
|
123
|
+
{props.children}
|
|
124
|
+
</InspectorSection>
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* X, Y, W and H in layer units (design px), the Transform section's grid:
|
|
130
|
+
* each name inside its field. Read-only while it plays. A drag is the store's
|
|
131
|
+
* sketch drag, one undo step, the item moving on the paper as it goes; a
|
|
132
|
+
* typed value lands on the whole pixel.
|
|
133
|
+
*
|
|
134
|
+
* Each cell is a row (`InspectorRow`), as every Studio grid's is: the
|
|
135
|
+
* inspector's type scale (12px values, 11px names and units) is the row's,
|
|
136
|
+
* and a bare field in the grid kept the field's own 13px beside the panel's
|
|
137
|
+
* 12px rows.
|
|
138
|
+
*/
|
|
139
|
+
function Position({ item }: { item: Exclude<SketchItem3D, { kind: "arrow" }> }) {
|
|
140
|
+
const store = useStore();
|
|
141
|
+
const playing = useShotEditor((s) => s.sketchPlaying);
|
|
142
|
+
const [x, y] = item.position;
|
|
143
|
+
const [w, h] = item.size;
|
|
144
|
+
const field = (label: string, name: string, value: number, patchOf: (v: number) => SketchItemPatch, min?: number) => (
|
|
145
|
+
<InspectorRow>
|
|
146
|
+
<NumberField
|
|
147
|
+
label={label}
|
|
148
|
+
ariaLabel={name}
|
|
149
|
+
value={value}
|
|
150
|
+
unit="px"
|
|
151
|
+
readOnly={playing}
|
|
152
|
+
{...(min === undefined ? {} : { min })}
|
|
153
|
+
onCommit={(next) => store.updateSketchItem(item.id, patchOf(Math.round(next)))}
|
|
154
|
+
onScrubStart={() => store.beginSketchDrag()}
|
|
155
|
+
onScrub={(next) => store.dragSketchItems({ [item.id]: patchOf(Math.round(next)) })}
|
|
156
|
+
onScrubEnd={(commit) => store.endSketchDrag(commit)}
|
|
157
|
+
/>
|
|
158
|
+
</InspectorRow>
|
|
159
|
+
);
|
|
160
|
+
return (
|
|
161
|
+
<Group title="Position">
|
|
162
|
+
<PropertyGrid>
|
|
163
|
+
{field("X", "Position X", x, (v) => ({ position: [v, y] }))}
|
|
164
|
+
{field("Y", "Position Y", y, (v) => ({ position: [x, v] }))}
|
|
165
|
+
{field("W", "Width", w, (v) => ({ size: [v, h] }), 1)}
|
|
166
|
+
{field("H", "Height", h, (v) => ({ size: [w, v] }), 1)}
|
|
167
|
+
</PropertyGrid>
|
|
168
|
+
{playing ? <p className="insp-note">{SKETCH_PLAYING}</p> : null}
|
|
169
|
+
</Group>
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/** The card a ref item draws: what it is for, how hard it binds, and the
|
|
174
|
+
* note, the rows every board panel shows for a card. */
|
|
175
|
+
function CardGroup({ card }: { card: Extract<ReferenceItem3D, { type: "asset" | "component" }> }) {
|
|
176
|
+
return (
|
|
177
|
+
<Group title="Card">
|
|
178
|
+
<CardUseRows card={card} />
|
|
179
|
+
<CardNoteRow card={card} />
|
|
180
|
+
</Group>
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// ── a picture ────────────────────────────────────────────────────────────
|
|
185
|
+
|
|
186
|
+
function PictureInspector({ doc, item, card }: { doc: Doc3D; item: SketchRef3D; card: Extract<ReferenceItem3D, { type: "asset" }> | undefined }) {
|
|
187
|
+
const store = useStore();
|
|
188
|
+
const playing = useShotEditor((s) => s.sketchPlaying);
|
|
189
|
+
// Replace writes, so a viewer's panel takes it with the fields. Read off
|
|
190
|
+
// the store: this component renders the Shell, so the Shell's
|
|
191
|
+
// `LockedControls` sits below it.
|
|
192
|
+
const readOnly = useShotEditor((s) => s.readOnly);
|
|
193
|
+
const [replacing, setReplacing] = useState(false);
|
|
194
|
+
const replaceButton = useRef<HTMLButtonElement>(null);
|
|
195
|
+
const asset = card === undefined ? undefined : doc.assets[card.asset];
|
|
196
|
+
const image = asset?.kind === "image" ? asset : undefined;
|
|
197
|
+
const thumb = useImageThumb(image === undefined ? "" : assetUrl(image.path), image?.hash ?? "", 272);
|
|
198
|
+
const kind = itemKindOf(doc, item);
|
|
199
|
+
|
|
200
|
+
// REPLACE points the item at another picture, in one edit: the plan's card
|
|
201
|
+
// for that file, made when it has none, or the Style card picked.
|
|
202
|
+
const replace = (pick: ImagePick): void => {
|
|
203
|
+
const plan = store.getState().storyboardPlan;
|
|
204
|
+
store.edit((base) => {
|
|
205
|
+
let next = base;
|
|
206
|
+
let ref = pick.kind === "card" ? pick.card : undefined;
|
|
207
|
+
if (pick.kind === "asset") {
|
|
208
|
+
const file = base.assets[pick.asset];
|
|
209
|
+
if (file === undefined || plan === null) return base;
|
|
210
|
+
ref = base.resources?.references?.find((r) => r.type === "asset" && r.asset === pick.asset && r.part === plan)?.id;
|
|
211
|
+
if (ref === undefined) {
|
|
212
|
+
const before = new Set((base.resources?.references ?? []).map((r) => r.id));
|
|
213
|
+
next = addReference(base, {}, { type: "asset", label: fileNameOf(file.path), asset: pick.asset, use: "asset", part: plan }, "pin");
|
|
214
|
+
ref = next.resources?.references?.find((r) => !before.has(r.id))?.id;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
return ref === undefined ? base : updateSketchItem(next, item.id, { ref });
|
|
218
|
+
});
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
return (
|
|
222
|
+
<Shell icon={kindIcon(kind === "Video" ? "video" : "image")} title={itemNameOf(doc, item)} badge={kind.toLowerCase()}>
|
|
223
|
+
<Group title="Picture">
|
|
224
|
+
{image !== undefined ? (
|
|
225
|
+
<div className="sketch-preview" style={{ aspectRatio: `${item.size[0]} / ${item.size[1]}` }}>
|
|
226
|
+
{thumb === null ? null : <img src={thumb} alt="" draggable={false} style={{ objectFit: item.fit ?? "cover" }} />}
|
|
227
|
+
</div>
|
|
228
|
+
) : card === undefined ? (
|
|
229
|
+
<p className="insp-note">This card is gone from the Project. Replace it, or delete the item.</p>
|
|
230
|
+
) : null}
|
|
231
|
+
<InspectorRow label="Fit">
|
|
232
|
+
<SegmentedControl
|
|
233
|
+
ariaLabel="Fit"
|
|
234
|
+
value={item.fit ?? "cover"}
|
|
235
|
+
options={[
|
|
236
|
+
{ value: "cover", label: "Fill" },
|
|
237
|
+
{ value: "contain", label: "Fit" },
|
|
238
|
+
]}
|
|
239
|
+
onChange={(value) => store.updateSketchItem(item.id, { fit: value === "contain" ? "contain" : null })}
|
|
240
|
+
/>
|
|
241
|
+
</InspectorRow>
|
|
242
|
+
{/* The house row of buttons: one 28px house button across the row. */}
|
|
243
|
+
<div className="insp-buttons">
|
|
244
|
+
<button ref={replaceButton} type="button" className="btn" disabled={playing || readOnly} onClick={() => setReplacing(true)}>
|
|
245
|
+
Replace…
|
|
246
|
+
</button>
|
|
247
|
+
</div>
|
|
248
|
+
</Group>
|
|
249
|
+
{card === undefined ? null : <CardGroup card={card} />}
|
|
250
|
+
<Position item={item} />
|
|
251
|
+
<ImagePicker open={replacing} anchor={replaceButton} title="Replace the picture" onPick={replace} onClose={() => setReplacing(false)} />
|
|
252
|
+
</Shell>
|
|
253
|
+
);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// ── a component ──────────────────────────────────────────────────────────
|
|
257
|
+
|
|
258
|
+
function ComponentInspector({ doc, item, card }: { doc: Doc3D; item: SketchRef3D; card: Extract<ReferenceItem3D, { type: "component" }> }) {
|
|
259
|
+
const store = useStore();
|
|
260
|
+
const playing = useShotEditor((s) => s.sketchPlaying);
|
|
261
|
+
const componentId = card.def !== undefined && doc.components?.[card.def] !== undefined ? null : (card.component ?? null);
|
|
262
|
+
// A built-in has no source to open in Components.
|
|
263
|
+
const builtin = useShotEditor((s) => isBuiltinComponent(s.library, componentId ?? undefined));
|
|
264
|
+
// The props rows read the contract.
|
|
265
|
+
useEffect(() => {
|
|
266
|
+
if (componentId !== null) void store.loadContract(componentId);
|
|
267
|
+
}, [componentId, store]);
|
|
268
|
+
const open = (): void => {
|
|
269
|
+
// Leaving for Components closes the board and keeps this shot board, so
|
|
270
|
+
// the way back lands here (`returnTarget`, `storyboardPlan`).
|
|
271
|
+
if (componentId === null && card.def !== undefined) void store.selectComponent({ kind: "studio", def: card.def });
|
|
272
|
+
else if (componentId !== null) void store.selectComponent({ kind: "code", module: componentId });
|
|
273
|
+
};
|
|
274
|
+
return (
|
|
275
|
+
<Shell icon={COMPONENT_ICON} title={componentNameOf(doc, card)} badge="component">
|
|
276
|
+
<Group title="Component">
|
|
277
|
+
{/* A door on the house row of buttons: one 28px house button across
|
|
278
|
+
the row, its words and glyph together. */}
|
|
279
|
+
<div className="insp-buttons">
|
|
280
|
+
<button
|
|
281
|
+
type="button"
|
|
282
|
+
className="btn sketch-door"
|
|
283
|
+
data-testid="sketch-open-component"
|
|
284
|
+
disabled={builtin}
|
|
285
|
+
title={builtin ? BUILTIN_NO_MASTER : undefined}
|
|
286
|
+
onClick={open}
|
|
287
|
+
>
|
|
288
|
+
Open in Components
|
|
289
|
+
{OPEN_ELSEWHERE_ICON}
|
|
290
|
+
</button>
|
|
291
|
+
</div>
|
|
292
|
+
{playing ? <p className="insp-note">Edits show live while playing.</p> : null}
|
|
293
|
+
</Group>
|
|
294
|
+
<ThisUsePanel useKey={cardUseKey(card.id)} propsLabel="Props" />
|
|
295
|
+
<CardGroup card={card} />
|
|
296
|
+
<Position item={item} />
|
|
297
|
+
{playing ? <InThisStage doc={doc} /> : null}
|
|
298
|
+
</Shell>
|
|
299
|
+
);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/** SB5's "In this stage": what moves, what holds, and what is overlay. */
|
|
303
|
+
function InThisStage({ doc }: { doc: Doc3D }) {
|
|
304
|
+
const sketchId = useShotEditor((s) => s.storyboardSketch);
|
|
305
|
+
const items = doc.storyboard?.parts.flatMap((p) => p.sketches ?? []).find((s) => s.id === sketchId)?.items ?? [];
|
|
306
|
+
const components = items.flatMap((item) => {
|
|
307
|
+
if (item.kind !== "ref") return [];
|
|
308
|
+
const card = sketchCardOf(doc, item);
|
|
309
|
+
return card?.type === "component" ? [componentNameOf(doc, card)] : [];
|
|
310
|
+
});
|
|
311
|
+
const rows: { name: string; badge: string; moving: boolean }[] = [
|
|
312
|
+
...[...new Set(components)].map((name) => ({ name, badge: "Moving", moving: true })),
|
|
313
|
+
{ name: "Image, text, box", badge: "Holding", moving: false },
|
|
314
|
+
{ name: "Arrow, box label", badge: "Overlay", moving: false },
|
|
315
|
+
];
|
|
316
|
+
return (
|
|
317
|
+
<Group title="In this stage">
|
|
318
|
+
<ul className="sketch-stage-list">
|
|
319
|
+
{rows.map((row) => (
|
|
320
|
+
<li key={row.name} className={`sketch-stage-row${row.moving ? " is-moving" : ""}`}>
|
|
321
|
+
<span className="sketch-stage-dot" aria-hidden="true" />
|
|
322
|
+
<span className="sketch-stage-name">{row.name}</span>
|
|
323
|
+
<span className={`badge${row.moving ? " is-success" : ""}`}>{row.badge}</span>
|
|
324
|
+
</li>
|
|
325
|
+
))}
|
|
326
|
+
</ul>
|
|
327
|
+
</Group>
|
|
328
|
+
);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// ── text, box, arrow ─────────────────────────────────────────────────────
|
|
332
|
+
|
|
333
|
+
function TextInspector({ doc, item }: { doc: Doc3D; item: Extract<SketchItem3D, { kind: "text" }> }) {
|
|
334
|
+
const store = useStore();
|
|
335
|
+
return (
|
|
336
|
+
<Shell icon={kindIcon("text")} title={itemNameOf(doc, item)} badge="text">
|
|
337
|
+
<Group title="Text">
|
|
338
|
+
<InspectorRow label="Content" align="start">
|
|
339
|
+
<TextField
|
|
340
|
+
multiline
|
|
341
|
+
value={item.text}
|
|
342
|
+
ariaLabel="Content"
|
|
343
|
+
onCommit={(text) => {
|
|
344
|
+
// A text item is never stored empty: an emptied field keeps the words.
|
|
345
|
+
const next = text.trim().slice(0, SKETCH_TEXT_MAX).trim();
|
|
346
|
+
if (next !== "" && next !== item.text) store.updateSketchItem(item.id, { text: next });
|
|
347
|
+
}}
|
|
348
|
+
/>
|
|
349
|
+
</InspectorRow>
|
|
350
|
+
<InspectorRow label="Role">
|
|
351
|
+
<SegmentedControl
|
|
352
|
+
ariaLabel="Role"
|
|
353
|
+
value={item.role}
|
|
354
|
+
options={[
|
|
355
|
+
{ value: "title", label: "Title" },
|
|
356
|
+
{ value: "body", label: "Body" },
|
|
357
|
+
{ value: "caption", label: "Caption" },
|
|
358
|
+
]}
|
|
359
|
+
onChange={(value) => {
|
|
360
|
+
if (value === "title" || value === "body" || value === "caption") store.updateSketchItem(item.id, { role: value });
|
|
361
|
+
}}
|
|
362
|
+
/>
|
|
363
|
+
</InspectorRow>
|
|
364
|
+
<InspectorRow label="Align">
|
|
365
|
+
<SegmentedControl
|
|
366
|
+
ariaLabel="Align"
|
|
367
|
+
value={item.align ?? "start"}
|
|
368
|
+
options={[
|
|
369
|
+
{ value: "start", label: "Start" },
|
|
370
|
+
{ value: "center", label: "Centre" },
|
|
371
|
+
{ value: "end", label: "End" },
|
|
372
|
+
]}
|
|
373
|
+
onChange={(value) => store.updateSketchItem(item.id, { align: value === "center" || value === "end" ? value : null })}
|
|
374
|
+
/>
|
|
375
|
+
</InspectorRow>
|
|
376
|
+
</Group>
|
|
377
|
+
<Position item={item} />
|
|
378
|
+
</Shell>
|
|
379
|
+
);
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
function LabelRow({ itemId, label }: { itemId: string; label: string | undefined }) {
|
|
383
|
+
const store = useStore();
|
|
384
|
+
return (
|
|
385
|
+
<InspectorRow label="Label">
|
|
386
|
+
<TextField
|
|
387
|
+
value={label ?? ""}
|
|
388
|
+
placeholder="What this stands for"
|
|
389
|
+
ariaLabel="Label"
|
|
390
|
+
onCommit={(text) => {
|
|
391
|
+
const next = text.trim().slice(0, SKETCH_LABEL_MAX).trim();
|
|
392
|
+
if (next !== (label ?? "")) store.updateSketchItem(itemId, { label: next === "" ? null : next });
|
|
393
|
+
}}
|
|
394
|
+
/>
|
|
395
|
+
</InspectorRow>
|
|
396
|
+
);
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
function BoxInspector({ doc, item }: { doc: Doc3D; item: Extract<SketchItem3D, { kind: "box" }> }) {
|
|
400
|
+
const store = useStore();
|
|
401
|
+
return (
|
|
402
|
+
<Shell icon={kindIcon("rect")} title={itemNameOf(doc, item)} badge="box">
|
|
403
|
+
<Group title="Box">
|
|
404
|
+
<LabelRow itemId={item.id} label={item.label} />
|
|
405
|
+
<InspectorRow label="Tone">
|
|
406
|
+
<SegmentedControl
|
|
407
|
+
ariaLabel="Tone"
|
|
408
|
+
value={item.tone ?? "light"}
|
|
409
|
+
options={[
|
|
410
|
+
{ value: "light", label: "Light" },
|
|
411
|
+
{ value: "dark", label: "Dark" },
|
|
412
|
+
{ value: "accent", label: "Accent" },
|
|
413
|
+
]}
|
|
414
|
+
onChange={(value) => store.updateSketchItem(item.id, { tone: value === "dark" || value === "accent" ? value : null })}
|
|
415
|
+
/>
|
|
416
|
+
</InspectorRow>
|
|
417
|
+
</Group>
|
|
418
|
+
<Position item={item} />
|
|
419
|
+
</Shell>
|
|
420
|
+
);
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
function ArrowInspector({ doc, item }: { doc: Doc3D; item: Extract<SketchItem3D, { kind: "arrow" }> }) {
|
|
424
|
+
return (
|
|
425
|
+
<Shell icon={kindIcon("arrow")} title={itemNameOf(doc, item)} badge="arrow">
|
|
426
|
+
<Group title="Arrow">
|
|
427
|
+
<LabelRow itemId={item.id} label={item.label} />
|
|
428
|
+
<p className="insp-note">An arrow stays a note: the Studio never makes it a layer.</p>
|
|
429
|
+
</Group>
|
|
430
|
+
</Shell>
|
|
431
|
+
);
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
// ── several ──────────────────────────────────────────────────────────────
|
|
435
|
+
|
|
436
|
+
function AlignSection({ doc, items }: { doc: Doc3D; items: readonly SketchItem3D[] }) {
|
|
437
|
+
const store = useStore();
|
|
438
|
+
const playing = useShotEditor((s) => s.sketchPlaying);
|
|
439
|
+
// The buttons write, so a viewer's locked panel takes them with the fields.
|
|
440
|
+
const locked = useLocked();
|
|
441
|
+
const run = (mode: AlignMode): void => {
|
|
442
|
+
const patches = alignPatches(items, mode, doc.size);
|
|
443
|
+
if (Object.keys(patches).length === 0) return;
|
|
444
|
+
store.edit((base) => Object.entries(patches).reduce((next, [id, patch]) => updateSketchItem(next, id, patch), base));
|
|
445
|
+
};
|
|
446
|
+
return (
|
|
447
|
+
<Group title="Align">
|
|
448
|
+
<div className="sketch-align" role="group" aria-label="Align and distribute" data-testid="sketch-align">
|
|
449
|
+
{ALIGN_ORDER.map((mode) => {
|
|
450
|
+
const needsThree = DISTRIBUTE_MODES.has(mode) && items.length < MIN_DISTRIBUTE;
|
|
451
|
+
const label = ALIGN_LABELS[mode];
|
|
452
|
+
return (
|
|
453
|
+
<button
|
|
454
|
+
key={mode}
|
|
455
|
+
type="button"
|
|
456
|
+
className="align-button"
|
|
457
|
+
aria-label={label}
|
|
458
|
+
title={playing ? SKETCH_PLAYING : needsThree ? `${label}: needs ${MIN_DISTRIBUTE} or more items` : label}
|
|
459
|
+
disabled={needsThree || playing || locked}
|
|
460
|
+
onClick={() => run(mode)}
|
|
461
|
+
>
|
|
462
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={1.5} strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
|
|
463
|
+
<path d={ALIGN_PATHS[mode]} />
|
|
464
|
+
</svg>
|
|
465
|
+
</button>
|
|
466
|
+
);
|
|
467
|
+
})}
|
|
468
|
+
</div>
|
|
469
|
+
</Group>
|
|
470
|
+
);
|
|
471
|
+
}
|