@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,373 @@
|
|
|
1
|
+
// "ADD A COMPONENT" (Paper SB4): the Component tool's picker, hung above its
|
|
2
|
+
// button. Four sections, each from the builder the surface that owns it
|
|
3
|
+
// already reads, so the picker never lists a set of its own:
|
|
4
|
+
//
|
|
5
|
+
// In this project Components' This project (`componentsListOf`), then
|
|
6
|
+
// the folder-mates the board has always offered
|
|
7
|
+
// (`projectComponents`, which leaves out a file another
|
|
8
|
+
// Project holds): written for this film, not placed yet
|
|
9
|
+
// Your library Components' other half (`libraryComponentsOf`): code
|
|
10
|
+
// made for no Project, a Dailies Library install, or
|
|
11
|
+
// what someone added to the library; a Studio-made one
|
|
12
|
+
// of another Project is COPIED IN first
|
|
13
|
+
// (`importWorkspaceComponent`, which reuses a copy
|
|
14
|
+
// already here)
|
|
15
|
+
// Built in the catalog's built-ins under the server's groups, by
|
|
16
|
+
// the Insert drawer's names. A built-in's row id is its
|
|
17
|
+
// registry id, so it is added as itself and never
|
|
18
|
+
// installed
|
|
19
|
+
// Dailies Library the shipped components (`shippedRows`), which install
|
|
20
|
+
// on add
|
|
21
|
+
//
|
|
22
|
+
// Every add lands as a CARD PINNED TO THIS SHOT (a requirement, "In the shot")
|
|
23
|
+
// and then its item in the middle of the open sketch, so the Studio's
|
|
24
|
+
// checklist still works ("Every item points at a card. Nothing floats."). A
|
|
25
|
+
// card the plan already holds for the same component is reused. Only a
|
|
26
|
+
// `three` component can draw in the shot: a dom one the Project or the
|
|
27
|
+
// workspace holds shows disabled with the reason, as Components shows it, and
|
|
28
|
+
// the catalogs offer three only. "Browse the Dailies Library…" opens the whole
|
|
29
|
+
// Library, whose Pin to board lands a Style card the sketch can take by drag.
|
|
30
|
+
import { useEffect, useMemo, useState } from "react";
|
|
31
|
+
import type { RefObject } from "react";
|
|
32
|
+
import { addReference } from "@dailies-studio/shot/doc";
|
|
33
|
+
import type { Doc3D, ReferenceItem3D } from "@dailies-studio/shot/doc";
|
|
34
|
+
import { Popover } from "@dailies-studio/ui";
|
|
35
|
+
import { promotedBuiltinLabel } from "../../../addFamilies.js";
|
|
36
|
+
import type { ComponentFileHome, ComponentRow, LibraryItem, WorkspaceComponent } from "../../../api.js";
|
|
37
|
+
import { ADD_ICON, CHEVRON_RIGHT_ICON, CLOSE_ICON, COMPONENT_ICON, SEARCH_ICON } from "../../../icons.js";
|
|
38
|
+
import { useShotEditor, useStore } from "../../../state/context.js";
|
|
39
|
+
import { projectComponents } from "../../../state/projectComponents.js";
|
|
40
|
+
import type { ShotEditorStore } from "../../../state/store.js";
|
|
41
|
+
import { componentsListOf, libraryComponentsOf, libraryHomeLabel } from "../../../state/workspace.js";
|
|
42
|
+
import type { ComponentsListRow } from "../../../state/workspace.js";
|
|
43
|
+
import { placesAsLayer, shippedRows } from "../../library/libraryModel.js";
|
|
44
|
+
import { partNumberOf } from "../PlanPanel.js";
|
|
45
|
+
|
|
46
|
+
/** Where a row lists, top to bottom. */
|
|
47
|
+
export type ComponentPickSection = "project" | "workspace" | "builtin" | "library";
|
|
48
|
+
|
|
49
|
+
/** One picker row, and what adding it does. */
|
|
50
|
+
export interface ComponentPickRow {
|
|
51
|
+
key: string;
|
|
52
|
+
name: string;
|
|
53
|
+
kind: "code" | "studio";
|
|
54
|
+
section: ComponentPickSection;
|
|
55
|
+
/** A built-in's server group, its sub-head under Built in. */
|
|
56
|
+
group?: string;
|
|
57
|
+
/** Where a Your library component comes from (`libraryHomeLabel`). */
|
|
58
|
+
where?: string;
|
|
59
|
+
thumb?: string;
|
|
60
|
+
/** Why it cannot be a sketch item (a dom component): shown disabled. */
|
|
61
|
+
refusal?: string;
|
|
62
|
+
/** What a press does, where the name alone does not say. */
|
|
63
|
+
title?: string;
|
|
64
|
+
add: (store: ShotEditorStore, partId: string) => Promise<void>;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const cardIds = (doc: Doc3D | null): Set<string> => new Set((doc?.resources?.references ?? []).map((r) => r.id));
|
|
68
|
+
|
|
69
|
+
/** The plan's own card for a component (`matches`), or the component card
|
|
70
|
+
* the add `make` pins to the plan; then its item. */
|
|
71
|
+
async function landCard(
|
|
72
|
+
store: ShotEditorStore,
|
|
73
|
+
partId: string,
|
|
74
|
+
matches: (card: ReferenceItem3D) => boolean,
|
|
75
|
+
make: () => Promise<void> | void,
|
|
76
|
+
): Promise<void> {
|
|
77
|
+
let card = store.getState().doc?.resources?.references?.find((r) => r.part === partId && matches(r));
|
|
78
|
+
if (card === undefined) {
|
|
79
|
+
const before = cardIds(store.getState().doc);
|
|
80
|
+
await make();
|
|
81
|
+
card = (store.getState().doc?.resources?.references ?? []).find((r) => !before.has(r.id) && r.part === partId && r.type === "component");
|
|
82
|
+
}
|
|
83
|
+
if (card !== undefined) await store.addSketchItemFromCard(card.id);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** A definition of this document, as a card pinned to the part. */
|
|
87
|
+
const addDefinition =
|
|
88
|
+
(defId: string) =>
|
|
89
|
+
(store: ShotEditorStore, partId: string): Promise<void> =>
|
|
90
|
+
landCard(
|
|
91
|
+
store,
|
|
92
|
+
partId,
|
|
93
|
+
(card) => card.type === "component" && card.def === defId,
|
|
94
|
+
() => {
|
|
95
|
+
const label = store.getState().doc?.components?.[defId]?.name ?? "Component";
|
|
96
|
+
store.edit((base) => addReference(base, {}, { type: "component", label, def: defId, props: {}, use: "asset", part: partId }, "component"));
|
|
97
|
+
},
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
/** A registry component, as the card `addStoryboardComponent` pins. */
|
|
101
|
+
const addRegistered =
|
|
102
|
+
(componentId: string) =>
|
|
103
|
+
(store: ShotEditorStore, partId: string): Promise<void> =>
|
|
104
|
+
landCard(
|
|
105
|
+
store,
|
|
106
|
+
partId,
|
|
107
|
+
(card) => card.type === "component" && card.component === componentId,
|
|
108
|
+
() => store.addStoryboardComponent(componentId, partId, { use: "asset", select: false }),
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
/** A row that never adds: a press says why instead. */
|
|
112
|
+
const refused =
|
|
113
|
+
(refusal: string) =>
|
|
114
|
+
async (store: ShotEditorStore): Promise<void> => {
|
|
115
|
+
store.reportError(refusal);
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
/** Every row the picker offers, filtered by `query` on the name. */
|
|
119
|
+
export function componentRows(
|
|
120
|
+
doc: Doc3D,
|
|
121
|
+
library: readonly ComponentRow[],
|
|
122
|
+
workspace: readonly WorkspaceComponent[] | null,
|
|
123
|
+
homes: readonly ComponentFileHome[] | null,
|
|
124
|
+
catalog: readonly LibraryItem[],
|
|
125
|
+
query: string,
|
|
126
|
+
): ComponentPickRow[] {
|
|
127
|
+
const q = query.trim().toLowerCase();
|
|
128
|
+
const rows: ComponentPickRow[] = [];
|
|
129
|
+
const codeRow = (componentId: string, name: string, section: ComponentPickSection, refusal: string | null): ComponentPickRow => ({
|
|
130
|
+
key: `code:${componentId}`,
|
|
131
|
+
name,
|
|
132
|
+
kind: "code",
|
|
133
|
+
section,
|
|
134
|
+
...(refusal === null ? { add: addRegistered(componentId) } : { refusal, add: refused(refusal) }),
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
// IN THIS PROJECT. A folder-mate the stage cannot draw is left out, as it
|
|
138
|
+
// always was: the Project's own generated film sits in the fold, and it is
|
|
139
|
+
// dom by design.
|
|
140
|
+
const listed = componentsListOf(doc, library);
|
|
141
|
+
const mates = projectComponents(doc, library, homes)
|
|
142
|
+
.project.filter((row) => row.host === "three" && !listed.some((r) => r.sel.kind === "code" && r.sel.module === row.id))
|
|
143
|
+
.map((row): ComponentsListRow => ({ sel: { kind: "code", module: row.id }, name: row.name, refusal: null }));
|
|
144
|
+
const projectRows = [...listed, ...mates];
|
|
145
|
+
for (const r of projectRows) {
|
|
146
|
+
const sel = r.sel;
|
|
147
|
+
rows.push(
|
|
148
|
+
sel.kind === "studio"
|
|
149
|
+
? { key: `def:${sel.def}`, name: r.name, kind: "studio", section: "project", add: addDefinition(sel.def) }
|
|
150
|
+
: codeRow(sel.module, r.name, "project", r.refusal),
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
const shown = new Set(projectRows.flatMap((r) => (r.sel.kind === "code" ? [r.sel.module] : [])));
|
|
154
|
+
|
|
155
|
+
// YOUR LIBRARY. Its code is the registry's own rows, so each is pinned by
|
|
156
|
+
// its module, recorded or not.
|
|
157
|
+
for (const entry of libraryComponentsOf(doc, library, workspace, homes, projectRows)) {
|
|
158
|
+
const where = libraryHomeLabel(entry);
|
|
159
|
+
if (entry.kind === "code") {
|
|
160
|
+
shown.add(entry.module);
|
|
161
|
+
rows.push({ ...codeRow(entry.module, entry.name, "workspace", entry.refusal), key: `ws:${entry.module}`, where });
|
|
162
|
+
continue;
|
|
163
|
+
}
|
|
164
|
+
const c = entry.component;
|
|
165
|
+
rows.push({
|
|
166
|
+
key: `ws:${c.id}`,
|
|
167
|
+
name: c.name,
|
|
168
|
+
kind: "studio",
|
|
169
|
+
section: "workspace",
|
|
170
|
+
where,
|
|
171
|
+
title: `Adds a copy of ${c.name} to this Project`,
|
|
172
|
+
add: async (store, partId) => {
|
|
173
|
+
// ITS BODY LIVES IN ITS HOME PROJECT: copied in first, then pinned.
|
|
174
|
+
const defId = await store.importWorkspaceComponent(c.id);
|
|
175
|
+
if (defId !== null) await addDefinition(defId)(store, partId);
|
|
176
|
+
},
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// BUILT IN, by the server's groups ("GROUPING IS SERVER-SIDE",
|
|
181
|
+
// libraryCatalog.ts).
|
|
182
|
+
for (const item of catalog) {
|
|
183
|
+
if (item.source !== "builtin" || !placesAsLayer(item)) continue;
|
|
184
|
+
rows.push({
|
|
185
|
+
key: `builtin:${item.id}`,
|
|
186
|
+
name: promotedBuiltinLabel(item.id) ?? item.displayName ?? item.name,
|
|
187
|
+
kind: "code",
|
|
188
|
+
section: "builtin",
|
|
189
|
+
group: item.group,
|
|
190
|
+
...(item.thumb === undefined ? {} : { thumb: item.thumb }),
|
|
191
|
+
add: addRegistered(item.id),
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// THE DAILIES LIBRARY, less what the sections above already show.
|
|
196
|
+
for (const item of shippedRows(catalog)) {
|
|
197
|
+
if (!placesAsLayer(item) || (item.installedAs !== undefined && shown.has(item.installedAs))) continue;
|
|
198
|
+
rows.push({
|
|
199
|
+
key: `lib:${item.id}`,
|
|
200
|
+
name: item.displayName ?? item.name,
|
|
201
|
+
kind: "code",
|
|
202
|
+
section: "library",
|
|
203
|
+
...(item.thumb === undefined ? {} : { thumb: item.thumb }),
|
|
204
|
+
add: (store, partId) =>
|
|
205
|
+
landCard(
|
|
206
|
+
store,
|
|
207
|
+
partId,
|
|
208
|
+
// NOT INSTALLED YET, no card can be its: any other component card
|
|
209
|
+
// the plan holds is a different component.
|
|
210
|
+
(card) => card.type === "component" && item.installedAs !== undefined && card.component === item.installedAs,
|
|
211
|
+
() => store.addStoryboardLibraryItem(item.id, partId, { use: "asset", select: false }),
|
|
212
|
+
),
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
return rows.filter((row) => q === "" || row.name.toLowerCase().includes(q));
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/** "effects" -> "Effects": a server group as its sub-head. */
|
|
219
|
+
const groupLabel = (group: string): string => group.charAt(0).toUpperCase() + group.slice(1);
|
|
220
|
+
|
|
221
|
+
export function ComponentPicker(props: { open: boolean; anchor: RefObject<HTMLElement | null>; onClose(): void; partId: string }) {
|
|
222
|
+
const store = useStore();
|
|
223
|
+
const doc = useShotEditor((s) => s.doc);
|
|
224
|
+
const library = useShotEditor((s) => s.library);
|
|
225
|
+
const libraryLoaded = useShotEditor((s) => s.libraryLoaded);
|
|
226
|
+
const workspace = useShotEditor((s) => s.workspaceComponents);
|
|
227
|
+
const homes = useShotEditor((s) => s.componentHomes);
|
|
228
|
+
const catalog = useShotEditor((s) => s.libraryCatalog);
|
|
229
|
+
const catalogLoaded = useShotEditor((s) => s.libraryCatalogLoaded);
|
|
230
|
+
const [query, setQuery] = useState("");
|
|
231
|
+
const [adding, setAdding] = useState<string | null>(null);
|
|
232
|
+
|
|
233
|
+
// THE REGISTRY AND THE CATALOG, fetched on open as the board fetches them.
|
|
234
|
+
useEffect(() => {
|
|
235
|
+
if (!props.open) return;
|
|
236
|
+
if (!libraryLoaded) void store.refreshLibrary();
|
|
237
|
+
if (!catalogLoaded) void store.refreshLibraryCatalog();
|
|
238
|
+
}, [props.open, libraryLoaded, catalogLoaded, store]);
|
|
239
|
+
// AND THE WORKSPACE'S COMPONENTS AND HOMES, read on every open as
|
|
240
|
+
// Components reads them once a visit: one added since shows the next time.
|
|
241
|
+
// A read that fails keeps both as they were, null included, so the section
|
|
242
|
+
// never says it is reading: it says what it would hold, as Components does.
|
|
243
|
+
useEffect(() => {
|
|
244
|
+
if (props.open) void store.refreshWorkspaceComponents();
|
|
245
|
+
}, [props.open, store]);
|
|
246
|
+
|
|
247
|
+
const rows = useMemo(
|
|
248
|
+
() => (doc === null ? [] : componentRows(doc, library, workspace, homes, catalog, query)),
|
|
249
|
+
[doc, library, workspace, homes, catalog, query],
|
|
250
|
+
);
|
|
251
|
+
if (doc === null) return null;
|
|
252
|
+
const number = partNumberOf(doc, props.partId) ?? "this shot";
|
|
253
|
+
const searching = query.trim() !== "";
|
|
254
|
+
|
|
255
|
+
const add = (row: ComponentPickRow): void => {
|
|
256
|
+
if (adding !== null) return;
|
|
257
|
+
if (row.refusal !== undefined) {
|
|
258
|
+
store.reportError(row.refusal);
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
setAdding(row.key);
|
|
262
|
+
void row.add(store, props.partId).finally(() => {
|
|
263
|
+
setAdding(null);
|
|
264
|
+
props.onClose();
|
|
265
|
+
});
|
|
266
|
+
};
|
|
267
|
+
|
|
268
|
+
const list = (of: readonly ComponentPickRow[]) => (
|
|
269
|
+
<ul className="sketch-picker-rows">
|
|
270
|
+
{of.map((row) => (
|
|
271
|
+
<li key={row.key} className="sketch-picker-row">
|
|
272
|
+
<button
|
|
273
|
+
type="button"
|
|
274
|
+
className="sketch-picker-row-main"
|
|
275
|
+
data-testid={`component-picker-${row.key}`}
|
|
276
|
+
disabled={adding !== null}
|
|
277
|
+
aria-disabled={row.refusal === undefined ? undefined : true}
|
|
278
|
+
aria-label={`Add ${row.name}`}
|
|
279
|
+
title={row.refusal ?? row.title}
|
|
280
|
+
onClick={() => add(row)}
|
|
281
|
+
>
|
|
282
|
+
<span className="sketch-picker-thumb" aria-hidden="true">
|
|
283
|
+
{row.thumb === undefined ? COMPONENT_ICON : <img src={row.thumb} alt="" draggable={false} />}
|
|
284
|
+
</span>
|
|
285
|
+
<span className="sketch-picker-name">{row.name}</span>
|
|
286
|
+
{row.where === undefined ? null : <span className="sketch-picker-where">{row.where}</span>}
|
|
287
|
+
<span className="sketch-picker-kind">
|
|
288
|
+
<span className="badge">{row.kind === "studio" ? "3D" : "CODE"}</span>
|
|
289
|
+
</span>
|
|
290
|
+
<span className="sketch-picker-add" aria-hidden="true">
|
|
291
|
+
{ADD_ICON}
|
|
292
|
+
</span>
|
|
293
|
+
</button>
|
|
294
|
+
</li>
|
|
295
|
+
))}
|
|
296
|
+
</ul>
|
|
297
|
+
);
|
|
298
|
+
|
|
299
|
+
/** One section: its head, then its rows (Built in under its groups), or
|
|
300
|
+
* what it would hold. A search hides a section it emptied. */
|
|
301
|
+
const section = (id: ComponentPickSection, title: string, none: string, hint?: string) => {
|
|
302
|
+
const of = rows.filter((row) => row.section === id);
|
|
303
|
+
if (searching && of.length === 0) return null;
|
|
304
|
+
const groups = id === "builtin" ? [...new Set(of.map((row) => row.group ?? ""))] : null;
|
|
305
|
+
return (
|
|
306
|
+
<div className="sketch-picker-section" data-testid={`component-picker-section-${id}`}>
|
|
307
|
+
<div className="sketch-picker-section-head">
|
|
308
|
+
<h4 className="caps">{title}</h4>
|
|
309
|
+
{hint === undefined ? null : <span className="sketch-picker-hint">{hint}</span>}
|
|
310
|
+
</div>
|
|
311
|
+
{of.length === 0 ? (
|
|
312
|
+
<p className="sketch-picker-none">{none}</p>
|
|
313
|
+
) : groups === null ? (
|
|
314
|
+
list(of)
|
|
315
|
+
) : (
|
|
316
|
+
groups.map((group) => (
|
|
317
|
+
<div key={group}>
|
|
318
|
+
<h5 className="sketch-picker-group">{groupLabel(group)}</h5>
|
|
319
|
+
{list(of.filter((row) => (row.group ?? "") === group))}
|
|
320
|
+
</div>
|
|
321
|
+
))
|
|
322
|
+
)}
|
|
323
|
+
</div>
|
|
324
|
+
);
|
|
325
|
+
};
|
|
326
|
+
|
|
327
|
+
return (
|
|
328
|
+
<Popover open={props.open} anchor={props.anchor} onClose={props.onClose} side="above" gap={10} className="sketch-picker">
|
|
329
|
+
<section className="sketch-picker-body" aria-label="Add a component" data-testid="component-picker">
|
|
330
|
+
<header className="sketch-picker-head">
|
|
331
|
+
<h3 className="sketch-picker-title">Add a component</h3>
|
|
332
|
+
<button type="button" className="sketch-icon-button" aria-label="Close" onClick={props.onClose}>
|
|
333
|
+
{CLOSE_ICON}
|
|
334
|
+
</button>
|
|
335
|
+
</header>
|
|
336
|
+
<label className="sketch-picker-search">
|
|
337
|
+
{SEARCH_ICON}
|
|
338
|
+
<input value={query} placeholder="Search components" aria-label="Search components" onChange={(event) => setQuery(event.target.value)} />
|
|
339
|
+
</label>
|
|
340
|
+
<div className="sketch-picker-sections">
|
|
341
|
+
{section("project", "In this project", libraryLoaded ? "No components in this Project yet." : "Reading the components…")}
|
|
342
|
+
{section(
|
|
343
|
+
"workspace",
|
|
344
|
+
"Your library",
|
|
345
|
+
"Code made for no Project, Dailies Library installs and components you add to your library show here.",
|
|
346
|
+
)}
|
|
347
|
+
{section("builtin", "Built in", catalogLoaded ? "No built-in components in this build." : "Reading the Library…")}
|
|
348
|
+
{section(
|
|
349
|
+
"library",
|
|
350
|
+
"Dailies Library",
|
|
351
|
+
catalogLoaded ? "Nothing more to add from the Dailies Library." : "Reading the Library…",
|
|
352
|
+
"Installs on add",
|
|
353
|
+
)}
|
|
354
|
+
{searching && rows.length === 0 ? <p className="sketch-picker-none">{`No component matches “${query.trim()}”.`}</p> : null}
|
|
355
|
+
</div>
|
|
356
|
+
<footer className="sketch-picker-foot is-split">
|
|
357
|
+
<button
|
|
358
|
+
type="button"
|
|
359
|
+
className="link-button sketch-picker-browse"
|
|
360
|
+
onClick={() => {
|
|
361
|
+
props.onClose();
|
|
362
|
+
store.setLibraryBrowserOpen(true, "component");
|
|
363
|
+
}}
|
|
364
|
+
>
|
|
365
|
+
Browse the Dailies Library…
|
|
366
|
+
{CHEVRON_RIGHT_ICON}
|
|
367
|
+
</button>
|
|
368
|
+
<span className="sketch-picker-hint">{`Lands as a card on ${number}`}</span>
|
|
369
|
+
</footer>
|
|
370
|
+
</section>
|
|
371
|
+
</Popover>
|
|
372
|
+
);
|
|
373
|
+
}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
// "ADD AN IMAGE" (Paper SB4): the Image tool's picker, hung above its button.
|
|
2
|
+
//
|
|
3
|
+
// Two lists: the Project's pictures (its image and video assets) and the
|
|
4
|
+
// Style's picture cards. A pick lands as an item in the middle of the open
|
|
5
|
+
// sketch through the store's verbs, which pin a requirement card for a
|
|
6
|
+
// Project file the plan does not hold yet (`addSketchItemFromAsset`) and take
|
|
7
|
+
// a Style card as it is (`addSketchItemFromCard`). Upload is the board's own
|
|
8
|
+
// file lane (`addSketchItemsFromFiles`). One picker at a time; a pick, the
|
|
9
|
+
// close button, Escape or a press outside closes it back to Select.
|
|
10
|
+
//
|
|
11
|
+
// `onPick` replaces what a pick does: the image inspector's Replace.
|
|
12
|
+
import { useMemo, useRef, useState } from "react";
|
|
13
|
+
import type { RefObject } from "react";
|
|
14
|
+
import type { Doc3D, ShotAsset } from "@dailies-studio/shot/doc";
|
|
15
|
+
import { Popover, SegmentedControl } from "@dailies-studio/ui";
|
|
16
|
+
import { CLOSE_ICON, IMAGE_UP_ICON, SEARCH_ICON } from "../../../icons.js";
|
|
17
|
+
import { useShotEditor, useStore } from "../../../state/context.js";
|
|
18
|
+
import { useImageThumb } from "../../../state/imageThumbs.js";
|
|
19
|
+
import { styleItemsOf } from "../../../state/storyboardModel.js";
|
|
20
|
+
import { MediaPoster } from "../ReferencePreview.js";
|
|
21
|
+
import { assetUrl } from "../ReferencePreview.js";
|
|
22
|
+
import { ACCEPTED_MEDIA_EXTENSIONS } from "../storyboardDrop.js";
|
|
23
|
+
import { fileNameOf } from "./sketchModel.js";
|
|
24
|
+
|
|
25
|
+
/** What a pick names: a Project file, or a Style card. */
|
|
26
|
+
export type ImagePick = { kind: "asset"; asset: string } | { kind: "card"; card: string };
|
|
27
|
+
|
|
28
|
+
interface Tile {
|
|
29
|
+
key: string;
|
|
30
|
+
name: string;
|
|
31
|
+
asset: ShotAsset;
|
|
32
|
+
pick: ImagePick;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** The picker's two lists, filtered by `query` on the name. */
|
|
36
|
+
export function imageTiles(doc: Doc3D, query: string): { assets: Tile[]; style: Tile[] } {
|
|
37
|
+
const q = query.trim().toLowerCase();
|
|
38
|
+
const hit = (name: string): boolean => q === "" || name.toLowerCase().includes(q);
|
|
39
|
+
const pictures = (asset: ShotAsset | undefined): asset is ShotAsset => asset?.kind === "image" || asset?.kind === "video";
|
|
40
|
+
const assets = Object.values(doc.assets)
|
|
41
|
+
.filter(pictures)
|
|
42
|
+
.map((asset) => ({ key: asset.id, name: fileNameOf(asset.path), asset, pick: { kind: "asset" as const, asset: asset.id } }));
|
|
43
|
+
const style = styleItemsOf(doc).flatMap((card) => {
|
|
44
|
+
const asset = card.type === "asset" ? doc.assets[card.asset] : undefined;
|
|
45
|
+
return pictures(asset) ? [{ key: card.id, name: card.label, asset, pick: { kind: "card" as const, card: card.id } }] : [];
|
|
46
|
+
});
|
|
47
|
+
return { assets: assets.filter((t) => hit(t.name)), style: style.filter((t) => hit(t.name)) };
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function ImagePicker(props: {
|
|
51
|
+
open: boolean;
|
|
52
|
+
anchor: RefObject<HTMLElement | null>;
|
|
53
|
+
onClose(): void;
|
|
54
|
+
title?: string;
|
|
55
|
+
onPick?: (pick: ImagePick) => void;
|
|
56
|
+
}) {
|
|
57
|
+
const store = useStore();
|
|
58
|
+
const doc = useShotEditor((s) => s.doc);
|
|
59
|
+
const [query, setQuery] = useState("");
|
|
60
|
+
const [list, setList] = useState<"assets" | "style">("assets");
|
|
61
|
+
const upload = useRef<HTMLInputElement>(null);
|
|
62
|
+
const tiles = useMemo(() => (doc === null ? { assets: [], style: [] } : imageTiles(doc, query)), [doc, query]);
|
|
63
|
+
if (doc === null) return null;
|
|
64
|
+
const shown = tiles[list];
|
|
65
|
+
|
|
66
|
+
const pick = (choice: ImagePick): void => {
|
|
67
|
+
props.onClose();
|
|
68
|
+
if (props.onPick !== undefined) props.onPick(choice);
|
|
69
|
+
else if (choice.kind === "asset") void store.addSketchItemFromAsset(choice.asset);
|
|
70
|
+
else void store.addSketchItemFromCard(choice.card);
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
return (
|
|
74
|
+
<Popover open={props.open} anchor={props.anchor} onClose={props.onClose} side="above" gap={10} className="sketch-picker">
|
|
75
|
+
<section className="sketch-picker-body" aria-label={props.title ?? "Add an image"} data-testid="image-picker">
|
|
76
|
+
<header className="sketch-picker-head">
|
|
77
|
+
<h3 className="sketch-picker-title">{props.title ?? "Add an image"}</h3>
|
|
78
|
+
<button type="button" className="sketch-icon-button" aria-label="Close" onClick={props.onClose}>
|
|
79
|
+
{CLOSE_ICON}
|
|
80
|
+
</button>
|
|
81
|
+
</header>
|
|
82
|
+
<label className="sketch-picker-search">
|
|
83
|
+
{SEARCH_ICON}
|
|
84
|
+
<input value={query} placeholder="Search images" aria-label="Search images" onChange={(event) => setQuery(event.target.value)} />
|
|
85
|
+
</label>
|
|
86
|
+
<SegmentedControl
|
|
87
|
+
ariaLabel="Where from"
|
|
88
|
+
value={list}
|
|
89
|
+
options={[
|
|
90
|
+
{ value: "assets", label: <>Project assets <span className="sketch-picker-count">{tiles.assets.length}</span></>, testId: "image-picker-assets" },
|
|
91
|
+
{ value: "style", label: <>Style <span className="sketch-picker-count">{tiles.style.length}</span></>, testId: "image-picker-style" },
|
|
92
|
+
]}
|
|
93
|
+
onChange={(value) => setList(value === "style" ? "style" : "assets")}
|
|
94
|
+
/>
|
|
95
|
+
{shown.length === 0 ? (
|
|
96
|
+
<p className="sketch-picker-none">{list === "style" ? "No Style pictures yet." : "No pictures in this Project yet. Upload one."}</p>
|
|
97
|
+
) : (
|
|
98
|
+
<div className="sketch-picker-grid">
|
|
99
|
+
{shown.map((tile) => (
|
|
100
|
+
<PictureTile key={tile.key} tile={tile} onPick={() => pick(tile.pick)} />
|
|
101
|
+
))}
|
|
102
|
+
</div>
|
|
103
|
+
)}
|
|
104
|
+
{props.onPick === undefined ? (
|
|
105
|
+
<footer className="sketch-picker-foot">
|
|
106
|
+
<button type="button" className="btn" onClick={() => upload.current?.click()}>
|
|
107
|
+
{IMAGE_UP_ICON}
|
|
108
|
+
Upload…
|
|
109
|
+
</button>
|
|
110
|
+
<span className="sketch-picker-hint">or drop files on the sketch, or paste</span>
|
|
111
|
+
<input
|
|
112
|
+
ref={upload}
|
|
113
|
+
type="file"
|
|
114
|
+
hidden
|
|
115
|
+
multiple
|
|
116
|
+
accept={`${ACCEPTED_MEDIA_EXTENSIONS.join(",")},image/*,video/*`}
|
|
117
|
+
data-testid="image-picker-upload"
|
|
118
|
+
onChange={(event) => {
|
|
119
|
+
const files = Array.from(event.currentTarget.files ?? []);
|
|
120
|
+
event.currentTarget.value = "";
|
|
121
|
+
if (files.length === 0) return;
|
|
122
|
+
props.onClose();
|
|
123
|
+
void store.addSketchItemsFromFiles(files);
|
|
124
|
+
}}
|
|
125
|
+
/>
|
|
126
|
+
</footer>
|
|
127
|
+
) : null}
|
|
128
|
+
</section>
|
|
129
|
+
</Popover>
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function PictureTile({ tile, onPick }: { tile: Tile; onPick(): void }) {
|
|
134
|
+
const image = tile.asset.kind === "image";
|
|
135
|
+
const thumb = useImageThumb(image ? assetUrl(tile.asset.path) : "", image ? tile.asset.hash : "", 106);
|
|
136
|
+
return (
|
|
137
|
+
<button type="button" className="sketch-picker-tile" title={tile.name} aria-label={tile.name} onClick={onPick}>
|
|
138
|
+
{image ? (
|
|
139
|
+
thumb === null ? null : <img src={thumb} alt="" draggable={false} />
|
|
140
|
+
) : (
|
|
141
|
+
<MediaPoster className="sketch-picker-media" src={assetUrl(tile.asset.path)} atSeconds={null} />
|
|
142
|
+
)}
|
|
143
|
+
</button>
|
|
144
|
+
);
|
|
145
|
+
}
|