@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,219 @@
|
|
|
1
|
+
// THE SHOT BOARD'S ARITHMETIC: pure, so the suite pins it without a DOM.
|
|
2
|
+
//
|
|
3
|
+
// Every number here is a LAYER UNIT (design px, origin at the frame's centre,
|
|
4
|
+
// +y down, types.ts), the unit the sketch stores and the Studio inspector
|
|
5
|
+
// shows. The canvas turns a client point into one with `designPointAt` and
|
|
6
|
+
// back with MiniSketch's `boxStyle` (percentages of the paper), so a zoom only
|
|
7
|
+
// changes the paper's width and nothing else is re-derived.
|
|
8
|
+
import { ALIGN_AXIS, DISTRIBUTE_MODES, MIN_DISTRIBUTE, applyToTransform, sketchCardOf } from "@dailies-studio/shot/doc";
|
|
9
|
+
import type { AlignMode, Doc3D, ResizeHandle, SketchItem3D, SketchItemPatch, Transform3D } from "@dailies-studio/shot/doc";
|
|
10
|
+
import { marqueeHits } from "../../timeline/marquee.js";
|
|
11
|
+
import type { MarqueeRect } from "../../timeline/marquee.js";
|
|
12
|
+
|
|
13
|
+
/** An item's box: its centre and its size. An arrow's is the box its two ends
|
|
14
|
+
* span. */
|
|
15
|
+
export interface SketchRect {
|
|
16
|
+
x: number;
|
|
17
|
+
y: number;
|
|
18
|
+
w: number;
|
|
19
|
+
h: number;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function itemRect(item: SketchItem3D): SketchRect {
|
|
23
|
+
if (item.kind === "arrow") {
|
|
24
|
+
const [ax, ay] = item.from;
|
|
25
|
+
const [bx, by] = item.to;
|
|
26
|
+
return { x: (ax + bx) / 2, y: (ay + by) / 2, w: Math.abs(bx - ax), h: Math.abs(by - ay) };
|
|
27
|
+
}
|
|
28
|
+
return { x: item.position[0], y: item.position[1], w: item.size[0], h: item.size[1] };
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** The patch that moves an item by (dx, dy): its box, or both arrow ends. */
|
|
32
|
+
export function movedPatch(item: SketchItem3D, dx: number, dy: number): SketchItemPatch {
|
|
33
|
+
if (item.kind === "arrow") {
|
|
34
|
+
return { from: [item.from[0] + dx, item.from[1] + dy], to: [item.to[0] + dx, item.to[1] + dy] };
|
|
35
|
+
}
|
|
36
|
+
return { position: [item.position[0] + dx, item.position[1] + dy] };
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** The file name a Project asset shows: its stored name without the hash
|
|
40
|
+
* prefix, as the Assets panel and `sketchLines` print it. */
|
|
41
|
+
export function fileNameOf(path: string): string {
|
|
42
|
+
return path.replace(/^[0-9a-f]{8}-/, "");
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** What an item is, in one word: the Layers row's trailing kind (Paper SB4). */
|
|
46
|
+
export type SketchItemKind = "Title" | "Body" | "Caption" | "Image" | "Video" | "Component" | "Box" | "Arrow" | "Missing";
|
|
47
|
+
|
|
48
|
+
export function itemKindOf(doc: Doc3D, item: SketchItem3D): SketchItemKind {
|
|
49
|
+
switch (item.kind) {
|
|
50
|
+
case "text":
|
|
51
|
+
return item.role === "title" ? "Title" : item.role === "body" ? "Body" : "Caption";
|
|
52
|
+
case "box":
|
|
53
|
+
return "Box";
|
|
54
|
+
case "arrow":
|
|
55
|
+
return "Arrow";
|
|
56
|
+
case "ref": {
|
|
57
|
+
const card = sketchCardOf(doc, item);
|
|
58
|
+
if (card?.type === "component") return "Component";
|
|
59
|
+
if (card?.type === "asset") {
|
|
60
|
+
const kind = doc.assets[card.asset]?.kind;
|
|
61
|
+
if (kind === "video") return "Video";
|
|
62
|
+
if (kind === "image") return "Image";
|
|
63
|
+
}
|
|
64
|
+
return "Missing";
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** A component card's name: its definition's, else the export's, else the
|
|
70
|
+
* card's own label. */
|
|
71
|
+
export function componentNameOf(doc: Doc3D, card: Extract<NonNullable<ReturnType<typeof sketchCardOf>>, { type: "component" }>): string {
|
|
72
|
+
if (card.def !== undefined) {
|
|
73
|
+
const def = doc.components?.[card.def];
|
|
74
|
+
if (def !== undefined) return def.name;
|
|
75
|
+
}
|
|
76
|
+
if (card.component !== undefined) return card.component.split("#").at(-1)!;
|
|
77
|
+
return card.label;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* The Layers row's name (Paper SB3): a component reads "<label prop> ·
|
|
82
|
+
* <component name>" when its card sets a text `label`, a picture its file
|
|
83
|
+
* name, text its words, a box or an arrow its label, else its kind.
|
|
84
|
+
*/
|
|
85
|
+
export function itemNameOf(doc: Doc3D, item: SketchItem3D): string {
|
|
86
|
+
switch (item.kind) {
|
|
87
|
+
case "text":
|
|
88
|
+
return item.text;
|
|
89
|
+
case "box":
|
|
90
|
+
return item.label ?? "Box";
|
|
91
|
+
case "arrow":
|
|
92
|
+
return item.label ?? "Arrow";
|
|
93
|
+
case "ref": {
|
|
94
|
+
const card = sketchCardOf(doc, item);
|
|
95
|
+
if (card === undefined) return "Missing card";
|
|
96
|
+
if (card.type === "component") {
|
|
97
|
+
const name = componentNameOf(doc, card);
|
|
98
|
+
const label = card.props["label"];
|
|
99
|
+
return typeof label === "string" && label.trim() !== "" ? `${label.trim()} · ${name}` : name;
|
|
100
|
+
}
|
|
101
|
+
if (card.type === "asset") {
|
|
102
|
+
const asset = doc.assets[card.asset];
|
|
103
|
+
return asset === undefined ? card.label : fileNameOf(asset.path);
|
|
104
|
+
}
|
|
105
|
+
return card.label;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/** The design point under a client point, on a paper drawn at `paper` (its
|
|
111
|
+
* client box). */
|
|
112
|
+
export function designPointAt(
|
|
113
|
+
paper: { left: number; top: number; width: number; height: number },
|
|
114
|
+
frame: { width: number; height: number },
|
|
115
|
+
clientX: number,
|
|
116
|
+
clientY: number,
|
|
117
|
+
): [number, number] {
|
|
118
|
+
const scale = paper.width / frame.width;
|
|
119
|
+
return [Math.round((clientX - paper.left) / scale - frame.width / 2), Math.round((clientY - paper.top) / scale - frame.height / 2)];
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/** The ids a marquee (in layer units) touches, in front of `add` (the
|
|
123
|
+
* selection frozen at a Shift press). `marqueeHits`' touching rule. */
|
|
124
|
+
export function marqueeItems(items: readonly SketchItem3D[], rect: MarqueeRect, add: readonly string[]): string[] {
|
|
125
|
+
const bars = items.map((item) => {
|
|
126
|
+
const r = itemRect(item);
|
|
127
|
+
return { layerId: item.id, sceneId: "sketch", left: r.x - r.w / 2, right: r.x + r.w / 2, top: r.y - r.h / 2, bottom: r.y + r.h / 2 };
|
|
128
|
+
});
|
|
129
|
+
return marqueeHits(rect, bars, { sceneId: "sketch", add });
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* A box resized from `handle` by (dx, dy) layer units of handle travel, the
|
|
134
|
+
* stage's own resize arithmetic (`applyToTransform`): the opposite edge stays
|
|
135
|
+
* put, and the size never collapses. `keepAspect` (a picture) holds the box's
|
|
136
|
+
* aspect on every handle: a corner follows the axis the pointer committed to,
|
|
137
|
+
* an edge derives the other side about the centre.
|
|
138
|
+
*/
|
|
139
|
+
export function resizedRect(rect: SketchRect, handle: ResizeHandle, dx: number, dy: number, keepAspect: boolean): SketchRect {
|
|
140
|
+
const transform: Transform3D = { position: [rect.x, rect.y, 0], size: [rect.w, rect.h], tilt: [0, 0], rollDeg: 0, opacity: 1 };
|
|
141
|
+
const corner = handle.sx !== 0 && handle.sy !== 0;
|
|
142
|
+
const next = applyToTransform(transform, { kind: "resize", dx, dy, handle, keepAspect: keepAspect && corner });
|
|
143
|
+
let [w, h] = next.size;
|
|
144
|
+
if (keepAspect && !corner && rect.h > 0) {
|
|
145
|
+
const aspect = rect.w / rect.h;
|
|
146
|
+
if (handle.sx !== 0) h = Math.max(1, w / aspect);
|
|
147
|
+
else w = Math.max(1, h * aspect);
|
|
148
|
+
}
|
|
149
|
+
return { x: next.position[0], y: next.position[1], w: Math.round(w), h: Math.round(h) };
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Align or distribute items, `ALIGN_MODES`' words: ONE item aligns to the
|
|
154
|
+
* frame, two or more to the selection's own bounds, a distribution needs
|
|
155
|
+
* `MIN_DISTRIBUTE` and leaves equal gaps between the first and the last.
|
|
156
|
+
* Answers each moved item's patch.
|
|
157
|
+
*/
|
|
158
|
+
export function alignPatches(
|
|
159
|
+
items: readonly SketchItem3D[],
|
|
160
|
+
mode: AlignMode,
|
|
161
|
+
frame: { width: number; height: number },
|
|
162
|
+
): Record<string, SketchItemPatch> {
|
|
163
|
+
const axis = ALIGN_AXIS[mode];
|
|
164
|
+
const boxes = items.map((item) => {
|
|
165
|
+
const r = itemRect(item);
|
|
166
|
+
return axis === "x" ? { item, centre: r.x, extent: r.w } : { item, centre: r.y, extent: r.h };
|
|
167
|
+
});
|
|
168
|
+
const out: Record<string, SketchItemPatch> = {};
|
|
169
|
+
const move = (item: SketchItem3D, by: number): void => {
|
|
170
|
+
if (by === 0) return;
|
|
171
|
+
out[item.id] = axis === "x" ? movedPatch(item, by, 0) : movedPatch(item, 0, by);
|
|
172
|
+
};
|
|
173
|
+
if (DISTRIBUTE_MODES.has(mode)) {
|
|
174
|
+
if (boxes.length < MIN_DISTRIBUTE) return out;
|
|
175
|
+
const sorted = [...boxes].sort((a, b) => a.centre - b.centre);
|
|
176
|
+
const first = sorted[0]!;
|
|
177
|
+
const last = sorted.at(-1)!;
|
|
178
|
+
const span = last.centre + last.extent / 2 - (first.centre - first.extent / 2);
|
|
179
|
+
const gap = (span - sorted.reduce((sum, b) => sum + b.extent, 0)) / (sorted.length - 1);
|
|
180
|
+
let edge = first.centre + first.extent / 2;
|
|
181
|
+
for (const box of sorted.slice(1, -1)) {
|
|
182
|
+
move(box.item, edge + gap + box.extent / 2 - box.centre);
|
|
183
|
+
edge += gap + box.extent;
|
|
184
|
+
}
|
|
185
|
+
return out;
|
|
186
|
+
}
|
|
187
|
+
const half = (axis === "x" ? frame.width : frame.height) / 2;
|
|
188
|
+
const min = boxes.length === 1 ? -half : Math.min(...boxes.map((b) => b.centre - b.extent / 2));
|
|
189
|
+
const max = boxes.length === 1 ? half : Math.max(...boxes.map((b) => b.centre + b.extent / 2));
|
|
190
|
+
for (const box of boxes) {
|
|
191
|
+
const target =
|
|
192
|
+
mode === "left" || mode === "top"
|
|
193
|
+
? min + box.extent / 2
|
|
194
|
+
: mode === "right" || mode === "bottom"
|
|
195
|
+
? max - box.extent / 2
|
|
196
|
+
: (min + max) / 2;
|
|
197
|
+
move(box.item, target - box.centre);
|
|
198
|
+
}
|
|
199
|
+
return out;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// ── zoom ──────────────────────────────────────────────────────────────────
|
|
203
|
+
|
|
204
|
+
/** The zoom steps, as multiples of the fitted paper (100% is Fit). */
|
|
205
|
+
export const SKETCH_ZOOMS = [0.25, 0.5, 0.7, 1, 1.25, 1.5, 2, 3, 4] as const;
|
|
206
|
+
|
|
207
|
+
/** The next step in or out from `zoom`. */
|
|
208
|
+
export function stepZoom(zoom: number, by: 1 | -1): number {
|
|
209
|
+
if (by > 0) return SKETCH_ZOOMS.find((z) => z > zoom + 1e-6) ?? SKETCH_ZOOMS.at(-1)!;
|
|
210
|
+
return [...SKETCH_ZOOMS].reverse().find((z) => z < zoom - 1e-6) ?? SKETCH_ZOOMS[0];
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/** The paper's width at 100%: as wide as the desk allows, and short enough
|
|
214
|
+
* that the strip under it still shows (`below` px). Never under 160. */
|
|
215
|
+
export function fitPaperWidth(desk: { width: number; height: number }, frame: { width: number; height: number }, pad: number, below: number): number {
|
|
216
|
+
const byWidth = desk.width - pad * 2;
|
|
217
|
+
const byHeight = ((desk.height - pad * 2 - below) * frame.width) / frame.height;
|
|
218
|
+
return Math.max(160, Math.floor(Math.min(byWidth, byHeight)));
|
|
219
|
+
}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
// What lands on the board: files from the desktop, a card dragged to another
|
|
2
|
+
// lane, a planned shot dragged to a new place in the outline.
|
|
3
|
+
//
|
|
4
|
+
// One vendor MIME for the in-app payloads, mirrored to `text/plain` because
|
|
5
|
+
// Safari drops custom types on some paths; `readDragPayload` reads the vendor
|
|
6
|
+
// type first and trusts `text/plain` only when it parses as OUR json, so the
|
|
7
|
+
// outliner's plain-text layer ids never read as a card.
|
|
8
|
+
//
|
|
9
|
+
// Files are filtered by EXTENSION here, `AddMenu`'s rule: the server stores
|
|
10
|
+
// the bytes before it consults its kind map (`KIND_BY_EXT`), so a file the map
|
|
11
|
+
// does not know would leave an orphan blob nothing collects.
|
|
12
|
+
import { linkUrlProblem } from "@dailies-studio/shot/doc";
|
|
13
|
+
|
|
14
|
+
export const STORYBOARD_MIME = "application/x-dailies-storyboard";
|
|
15
|
+
|
|
16
|
+
/** What a board copy or cut writes under `STORYBOARD_MIME`: a marker that the
|
|
17
|
+
* in-memory clip is the clipboard's latest, not the clip itself. A board
|
|
18
|
+
* paste takes the clip only under it. */
|
|
19
|
+
export const CLIP_MARKER = "storyboard-clip";
|
|
20
|
+
|
|
21
|
+
/** What a board drag CARRIES: a card (dropped on a lane, it moves there), or
|
|
22
|
+
* a planned shot (dropped in the outline, it reorders). */
|
|
23
|
+
export type DragPayload = { kind: "reference"; id: string } | { kind: "part"; id: string };
|
|
24
|
+
|
|
25
|
+
/** The extensions the server's `KIND_BY_EXT` answers image or video for. */
|
|
26
|
+
export const ACCEPTED_MEDIA_EXTENSIONS = [
|
|
27
|
+
".png",
|
|
28
|
+
".jpg",
|
|
29
|
+
".jpeg",
|
|
30
|
+
".webp",
|
|
31
|
+
".avif",
|
|
32
|
+
".gif",
|
|
33
|
+
".svg",
|
|
34
|
+
".mp4",
|
|
35
|
+
".webm",
|
|
36
|
+
".mov",
|
|
37
|
+
".m4v",
|
|
38
|
+
] as const;
|
|
39
|
+
|
|
40
|
+
/** The extensions it answers audio for: each lands as a sound card. */
|
|
41
|
+
export const ACCEPTED_AUDIO_EXTENSIONS = [".mp3", ".wav", ".ogg", ".flac", ".m4a", ".aac"] as const;
|
|
42
|
+
|
|
43
|
+
export const AUDIO_ACCEPT_ATTRIBUTE = `${ACCEPTED_AUDIO_EXTENSIONS.join(",")},audio/mpeg,audio/wav,audio/x-wav,audio/ogg,audio/flac,audio/mp4,audio/x-m4a,audio/aac`;
|
|
44
|
+
|
|
45
|
+
export const ACCEPT_ATTRIBUTE = `${ACCEPTED_MEDIA_EXTENSIONS.join(",")},image/png,image/jpeg,image/webp,image/avif,image/gif,image/svg+xml,video/mp4,video/webm,video/quicktime,${AUDIO_ACCEPT_ATTRIBUTE}`;
|
|
46
|
+
|
|
47
|
+
const endsWithAny = (name: string, exts: readonly string[]): boolean => {
|
|
48
|
+
const lower = name.toLowerCase();
|
|
49
|
+
return exts.some((ext) => lower.endsWith(ext));
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
/** An audio file by its name: it lands as a sound card, not a reference. */
|
|
53
|
+
export function isAudioFile(name: string): boolean {
|
|
54
|
+
return endsWithAny(name, ACCEPTED_AUDIO_EXTENSIONS);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* What the board says about files it cannot take, or null when it takes them
|
|
59
|
+
* all. Built from the lists above, so the sentence cannot name a stale set.
|
|
60
|
+
* Every door that filters files (paste, a lane drop, the pickers) says it.
|
|
61
|
+
*/
|
|
62
|
+
export function refusedFilesMessage(files: readonly File[]): string | null {
|
|
63
|
+
const refused = files.filter((file) => !endsWithAny(file.name, ACCEPTED_MEDIA_EXTENSIONS) && !isAudioFile(file.name));
|
|
64
|
+
if (refused.length === 0) return null;
|
|
65
|
+
return (
|
|
66
|
+
`The board takes images, videos and audio (${ACCEPTED_AUDIO_EXTENSIONS.join(" ")}). ` +
|
|
67
|
+
`${refused.map((file) => file.name).join(", ")} ${refused.length === 1 ? "is" : "are"} not one.`
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** The files the board can take: images, videos and audio, by extension. */
|
|
72
|
+
export function acceptedFiles(files: Iterable<File>): File[] {
|
|
73
|
+
const out: File[] = [];
|
|
74
|
+
for (const file of files) {
|
|
75
|
+
if (endsWithAny(file.name, ACCEPTED_MEDIA_EXTENSIONS) || isAudioFile(file.name)) out.push(file);
|
|
76
|
+
}
|
|
77
|
+
return out;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function writeDrag(dataTransfer: DataTransfer, payload: DragPayload): void {
|
|
81
|
+
const text = JSON.stringify(payload);
|
|
82
|
+
dataTransfer.setData(STORYBOARD_MIME, text);
|
|
83
|
+
dataTransfer.setData("text/plain", text);
|
|
84
|
+
dataTransfer.effectAllowed = "move";
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function parsePayload(text: string): DragPayload | null {
|
|
88
|
+
try {
|
|
89
|
+
const parsed = JSON.parse(text) as unknown;
|
|
90
|
+
if (typeof parsed !== "object" || parsed === null) return null;
|
|
91
|
+
const row = parsed as Record<string, unknown>;
|
|
92
|
+
const kind = row["kind"];
|
|
93
|
+
if ((kind === "reference" || kind === "part") && typeof row["id"] === "string") {
|
|
94
|
+
return { kind, id: row["id"] };
|
|
95
|
+
}
|
|
96
|
+
return null;
|
|
97
|
+
} catch {
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/** The payload a board drag carries, or null for anything else (a file, a
|
|
103
|
+
* layer id from the outliner). Reads only `types` and `getData`, which is
|
|
104
|
+
* all a jsdom test can hand a synthetic drop. */
|
|
105
|
+
export function readDragPayload(dataTransfer: Pick<DataTransfer, "types" | "getData">): DragPayload | null {
|
|
106
|
+
const types = Array.from(dataTransfer.types ?? []);
|
|
107
|
+
if (types.includes(STORYBOARD_MIME)) return parsePayload(dataTransfer.getData(STORYBOARD_MIME));
|
|
108
|
+
return types.includes("text/plain") ? parsePayload(dataTransfer.getData("text/plain")) : null;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Every extension the server stores as a file of its own: the board's media
|
|
113
|
+
* and audio, plus the kinds only the Assets tab takes (models, fonts, HDRIs).
|
|
114
|
+
* The CLI's `KIND_BY_EXT` is the source; the shot editor cannot import it.
|
|
115
|
+
*/
|
|
116
|
+
const FILE_URL_EXTENSIONS: readonly string[] = [
|
|
117
|
+
...ACCEPTED_MEDIA_EXTENSIONS,
|
|
118
|
+
...ACCEPTED_AUDIO_EXTENSIONS,
|
|
119
|
+
".glb",
|
|
120
|
+
".gltf",
|
|
121
|
+
".ttf",
|
|
122
|
+
".otf",
|
|
123
|
+
".woff",
|
|
124
|
+
".woff2",
|
|
125
|
+
".hdr",
|
|
126
|
+
".exr",
|
|
127
|
+
];
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* True when a URL names a media FILE rather than a page, by its path's
|
|
131
|
+
* extension. Such a URL is not imported: links are never fetched, so the
|
|
132
|
+
* bytes would have to come from the author's own download.
|
|
133
|
+
*/
|
|
134
|
+
export function isMediaUrl(url: string): boolean {
|
|
135
|
+
try {
|
|
136
|
+
return endsWithAny(new URL(url).pathname, FILE_URL_EXTENSIONS);
|
|
137
|
+
} catch {
|
|
138
|
+
return false;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* The https address a drop or paste carries, or null when it carries none.
|
|
144
|
+
*
|
|
145
|
+
* `text/uri-list` first (a dragged link or a browser's address bar), whose
|
|
146
|
+
* lines starting with "#" are comments; then `text/plain`, which is how a
|
|
147
|
+
* paste of a copied address arrives. Only a value `linkUrlProblem` passes is
|
|
148
|
+
* returned, so a stray sentence never reads as a link, and the store's own
|
|
149
|
+
* check never sees anything this let through on a looser rule.
|
|
150
|
+
*/
|
|
151
|
+
export function urlFromTransfer(dataTransfer: Pick<DataTransfer, "types" | "getData">): string | null {
|
|
152
|
+
const types = Array.from(dataTransfer.types ?? []);
|
|
153
|
+
const candidates: string[] = [];
|
|
154
|
+
if (types.includes("text/uri-list")) {
|
|
155
|
+
const first = dataTransfer
|
|
156
|
+
.getData("text/uri-list")
|
|
157
|
+
.split(/\r?\n/)
|
|
158
|
+
.map((line) => line.trim())
|
|
159
|
+
.find((line) => line !== "" && !line.startsWith("#"));
|
|
160
|
+
if (first !== undefined) candidates.push(first);
|
|
161
|
+
}
|
|
162
|
+
if (types.includes("text/plain")) candidates.push(dataTransfer.getData("text/plain").trim());
|
|
163
|
+
return candidates.find((value) => linkUrlProblem(value) === null) ?? null;
|
|
164
|
+
}
|