@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,349 @@
|
|
|
1
|
+
// The Library's right column (the selected item, larger, its action and Pin) and
|
|
2
|
+
// the centre column's EXPANDED PREVIEW, which replaces the catalog while it is
|
|
3
|
+
// open. A sound pack's column is `LibrarySoundPanel`: a pack is a list of
|
|
4
|
+
// files to audition one at a time, not one thing to look at.
|
|
5
|
+
//
|
|
6
|
+
// THE PROPS ARE THE CONTRACT. The browser owns selection, the expanded flag
|
|
7
|
+
// and the one-add-at-a-time rule (a double click on a card adds too, so the
|
|
8
|
+
// guard and the add's error cannot live here); this panel renders the
|
|
9
|
+
// selected row and asks.
|
|
10
|
+
//
|
|
11
|
+
// PREVIEWING NEVER INSTALLS. A shipped component draws live only once it is
|
|
12
|
+
// in this Project's registry (`installedAs` names a row of `s.library`): the
|
|
13
|
+
// stage and the harness can only load a registry id, and installing as a side
|
|
14
|
+
// effect of LOOKING would write files into the author's source tree. Before
|
|
15
|
+
// the Add, the expanded preview is the item's thumb and a sentence that says
|
|
16
|
+
// so. The live picture is the inspector's: a second shot stage
|
|
17
|
+
// (`ComponentStage`, framed as a Shot frames it). Components are React Three
|
|
18
|
+
// Fiber, so a dom host shows its thumb and says it is not supported.
|
|
19
|
+
//
|
|
20
|
+
// A SHOT'S ACTION IS ITS OWN PROJECT. A shot has no layer to place, so its
|
|
21
|
+
// primary is "Use as new Project" (`claimLibraryShot`, the pinned card's Claim
|
|
22
|
+
// as Project): the shot copied into a Project of its own and opened. Pin to
|
|
23
|
+
// board stays the second action, as it is a component's.
|
|
24
|
+
//
|
|
25
|
+
// PLAY AND STOP, NOT A SCRUBBER. `ComponentStage` loops on its own rAF clock
|
|
26
|
+
// and exposes no seek and no position, so the transport is the one control it
|
|
27
|
+
// can honour: play loops, stop holds the first frame (a card with
|
|
28
|
+
// `frame: 0`). A scrubber would claim a position nothing reports.
|
|
29
|
+
import { useEffect, useMemo, useRef, useState } from "react";
|
|
30
|
+
import type { ReactNode } from "react";
|
|
31
|
+
import type { Value } from "@dailies-studio/engine";
|
|
32
|
+
import type { ReferenceItem3D } from "@dailies-studio/shot/doc";
|
|
33
|
+
import type { LibraryItem } from "../../api.js";
|
|
34
|
+
import { ADD_ICON, CHEVRON_DOWN_ICON, CHEVRON_LEFT_ICON, COLLAPSE_ICON, FIT_ICON, LIBRARY_CATEGORY_ICONS, PLAY_ICON, STOP_ICON } from "../../icons.js";
|
|
35
|
+
import { useShotEditor, useStore } from "../../state/context.js";
|
|
36
|
+
import { placeInShotRefusal } from "../../state/store.js";
|
|
37
|
+
import { instanceHostRefusal } from "../../state/storyboardModel.js";
|
|
38
|
+
import { ComponentStage } from "../storyboard/ComponentStage.js";
|
|
39
|
+
import { formatDuration } from "../timeline/model.js";
|
|
40
|
+
import { DOM_NOT_SUPPORTED } from "../../state/workspace.js";
|
|
41
|
+
import { displayNameOf, kindOf } from "./libraryModel.js";
|
|
42
|
+
import { LibrarySoundPanel } from "./LibrarySoundPanel.js";
|
|
43
|
+
|
|
44
|
+
type ComponentCard = Extract<ReferenceItem3D, { type: "component" }>;
|
|
45
|
+
|
|
46
|
+
const NO_PROPS: Record<string, Value> = {};
|
|
47
|
+
|
|
48
|
+
/** One item of a kind, for the metadata row and "About this …". */
|
|
49
|
+
const KIND_NOUN: Record<ReturnType<typeof kindOf>, string> = {
|
|
50
|
+
component: "Component",
|
|
51
|
+
blueprint: "Blueprint",
|
|
52
|
+
material: "Material",
|
|
53
|
+
shot: "Shot",
|
|
54
|
+
images: "Image pack",
|
|
55
|
+
sounds: "Sound pack",
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
/** Only a component has motion to open larger: every other kind is a still. */
|
|
59
|
+
export const canExpand = (item: LibraryItem): boolean => kindOf(item) === "component";
|
|
60
|
+
|
|
61
|
+
export interface LibraryPreviewPanelProps {
|
|
62
|
+
/** The selected catalog row, or null before the author picks one. */
|
|
63
|
+
item: LibraryItem | null;
|
|
64
|
+
/** Where a PIN lands, as printed: "Project storyboard", the whole film. */
|
|
65
|
+
destination: string;
|
|
66
|
+
/** Cards on this Project's board that cite `item` (0 when none, or no item). */
|
|
67
|
+
onBoard: number;
|
|
68
|
+
/** False with no Project open: the catalog still browses, nothing adds. */
|
|
69
|
+
canAdd: boolean;
|
|
70
|
+
/** An add is in flight somewhere on the surface; every Add waits for it. */
|
|
71
|
+
adding: boolean;
|
|
72
|
+
/** ADD (D2): place a component in the open Shot, selected. It installs
|
|
73
|
+
* first. Only a component has the button. */
|
|
74
|
+
onAdd: () => void;
|
|
75
|
+
/** USE AS NEW PROJECT: copy a shot into a new Project and open it. Only a
|
|
76
|
+
* shot has the button. */
|
|
77
|
+
onClaim: () => void;
|
|
78
|
+
/** PIN TO INSPIRATION: the item as a board card for the agent. The one
|
|
79
|
+
* action of a material, an image pack or a blueprint, and the second of a
|
|
80
|
+
* component and a shot. Not for a sound pack, which pins one sound at a
|
|
81
|
+
* time. */
|
|
82
|
+
onPin: () => void;
|
|
83
|
+
/** Why the last add of THIS item failed, printed under its button. The
|
|
84
|
+
* shell's error strip is under the dialog, so without this a refused add
|
|
85
|
+
* would only re-enable the button. */
|
|
86
|
+
error: string | null;
|
|
87
|
+
/** The centre column is showing this item's expanded preview. */
|
|
88
|
+
expanded: boolean;
|
|
89
|
+
onExpand: (open: boolean) => void;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export function LibraryPreviewPanel(props: LibraryPreviewPanelProps) {
|
|
93
|
+
const { item, destination, onBoard, canAdd, adding, onAdd, onClaim, onPin, error, expanded, onExpand } = props;
|
|
94
|
+
const [more, setMore] = useState(false);
|
|
95
|
+
// Why Add would refuse (no Shot open, a definition open), and the Shot it
|
|
96
|
+
// lands in: strings, so these selectors allocate nothing.
|
|
97
|
+
const shotRefusal = useShotEditor((s) => placeInShotRefusal(s));
|
|
98
|
+
// The board enters no Shot: one the Studio left open behind it is not where
|
|
99
|
+
// an Add lands (Add is refused there, `placeInShotRefusal`).
|
|
100
|
+
const shotName = useShotEditor((s) =>
|
|
101
|
+
s.storyboardOpen || s.enteredScene === null ? null : (s.doc?.scenesById[s.enteredScene]?.name ?? null),
|
|
102
|
+
);
|
|
103
|
+
const boardOpen = useShotEditor((s) => s.storyboardOpen);
|
|
104
|
+
// FOCUS COMES BACK HERE ON COLLAPSE. The expanded view's two closes unmount
|
|
105
|
+
// with it, so focus falls to <body>; put it on the button that opens the
|
|
106
|
+
// view again. Only when it fell: a rail pick also collapses, and the rail
|
|
107
|
+
// row keeps its focus.
|
|
108
|
+
const expandRef = useRef<HTMLButtonElement>(null);
|
|
109
|
+
const wasExpanded = useRef(expanded);
|
|
110
|
+
useEffect(() => {
|
|
111
|
+
const collapsed = wasExpanded.current && !expanded;
|
|
112
|
+
wasExpanded.current = expanded;
|
|
113
|
+
if (collapsed && (document.activeElement === null || document.activeElement === document.body)) expandRef.current?.focus();
|
|
114
|
+
}, [expanded]);
|
|
115
|
+
if (item === null) {
|
|
116
|
+
return (
|
|
117
|
+
<aside className="library-preview" aria-label="Preview">
|
|
118
|
+
<p className="library-preview-empty">Click an item to preview it.</p>
|
|
119
|
+
</aside>
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
const kind = kindOf(item);
|
|
123
|
+
const name = displayNameOf(item);
|
|
124
|
+
// Only a three host can be a layer, so a dom component's Add says why up front.
|
|
125
|
+
const placeRefusal = item.host === "three" ? shotRefusal : instanceHostRefusal(item.host);
|
|
126
|
+
if (kind === "sounds") {
|
|
127
|
+
return (
|
|
128
|
+
<LibrarySoundPanel
|
|
129
|
+
key={item.id}
|
|
130
|
+
item={item}
|
|
131
|
+
canAdd={canAdd}
|
|
132
|
+
adding={adding}
|
|
133
|
+
/>
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
const opens = canExpand(item);
|
|
137
|
+
// The kinds whose primary is their own button, so Pin is the outlined second.
|
|
138
|
+
const primary = kind === "component" || kind === "shot";
|
|
139
|
+
const where = kind === "component" ? (shotName ?? "no Shot open") : kind === "shot" ? "a new Project" : destination;
|
|
140
|
+
return (
|
|
141
|
+
<aside className="library-preview" aria-label={`Preview: ${name}`} data-testid="library-preview">
|
|
142
|
+
<header className="library-preview-head">
|
|
143
|
+
<h2>{expanded ? `About this ${KIND_NOUN[kind].toLowerCase()}` : "Preview"}</h2>
|
|
144
|
+
{opens && !expanded ? (
|
|
145
|
+
<button ref={expandRef} type="button" className="btn is-ghost is-icon" aria-label="Open a larger preview" title="Open a larger preview" onClick={() => onExpand(true)}>
|
|
146
|
+
{FIT_ICON}
|
|
147
|
+
</button>
|
|
148
|
+
) : null}
|
|
149
|
+
</header>
|
|
150
|
+
{expanded ? null : (
|
|
151
|
+
<div className="library-preview-thumb">
|
|
152
|
+
<LibraryArt item={item} />
|
|
153
|
+
{opens ? (
|
|
154
|
+
<button type="button" className="library-preview-play" aria-label={`Play ${name}`} title="Play it larger" onClick={() => onExpand(true)}>
|
|
155
|
+
{PLAY_ICON}
|
|
156
|
+
</button>
|
|
157
|
+
) : null}
|
|
158
|
+
</div>
|
|
159
|
+
)}
|
|
160
|
+
<div className="library-preview-purpose">
|
|
161
|
+
<h3 className="library-preview-name">{name}</h3>
|
|
162
|
+
{item.description === undefined ? null : <p className="library-preview-note">{item.description}</p>}
|
|
163
|
+
</div>
|
|
164
|
+
<div className="library-preview-add">
|
|
165
|
+
<p className="library-preview-destination">
|
|
166
|
+
<span data-testid="library-destination">Destination: {where}</span>
|
|
167
|
+
{onBoard > 0 ? <span data-testid="library-preview-on-board">On the board ×{onBoard}</span> : null}
|
|
168
|
+
</p>
|
|
169
|
+
{kind === "component" ? (
|
|
170
|
+
<button
|
|
171
|
+
type="button"
|
|
172
|
+
className="btn is-primary is-lg"
|
|
173
|
+
data-testid="library-add"
|
|
174
|
+
disabled={!canAdd || adding}
|
|
175
|
+
aria-disabled={placeRefusal !== null || undefined}
|
|
176
|
+
title={
|
|
177
|
+
!canAdd
|
|
178
|
+
? "Open a Project to add library items."
|
|
179
|
+
: (placeRefusal ?? `Install into this Project and place it in ${shotName ?? "the open Shot"}. Undo removes the layer; the installed files stay.`)
|
|
180
|
+
}
|
|
181
|
+
onClick={() => {
|
|
182
|
+
if (placeRefusal === null) onAdd();
|
|
183
|
+
}}
|
|
184
|
+
>
|
|
185
|
+
{ADD_ICON}
|
|
186
|
+
{adding ? "Adding…" : "Add to shot"}
|
|
187
|
+
</button>
|
|
188
|
+
) : null}
|
|
189
|
+
{kind === "shot" ? (
|
|
190
|
+
<button
|
|
191
|
+
type="button"
|
|
192
|
+
className="btn is-primary is-lg"
|
|
193
|
+
data-testid="library-claim"
|
|
194
|
+
disabled={!canAdd || adding}
|
|
195
|
+
title={canAdd ? "Copy this shot into a new Project of its own and open it. This Project stays as it is." : "Open a Project to add library items."}
|
|
196
|
+
onClick={onClaim}
|
|
197
|
+
>
|
|
198
|
+
{ADD_ICON}
|
|
199
|
+
Use as new Project
|
|
200
|
+
</button>
|
|
201
|
+
) : null}
|
|
202
|
+
<button
|
|
203
|
+
type="button"
|
|
204
|
+
className={primary ? "btn is-outline is-lg" : "btn is-primary is-lg"}
|
|
205
|
+
data-testid="library-pin"
|
|
206
|
+
disabled={!canAdd || adding}
|
|
207
|
+
title={canAdd ? `Pin a card to ${destination}. The agent reads it when it builds.${boardOpen ? "" : " Opens the storyboard."}` : "Open a Project to add library items."}
|
|
208
|
+
onClick={onPin}
|
|
209
|
+
>
|
|
210
|
+
{primary ? null : ADD_ICON}
|
|
211
|
+
Pin to board
|
|
212
|
+
</button>
|
|
213
|
+
{error === null ? null : (
|
|
214
|
+
<p className="library-preview-error" role="alert" data-testid="library-add-error">
|
|
215
|
+
{error}
|
|
216
|
+
</p>
|
|
217
|
+
)}
|
|
218
|
+
<p className="library-preview-hint">
|
|
219
|
+
{kind === "component"
|
|
220
|
+
? "Add places it in the open Shot. Pin saves it for later."
|
|
221
|
+
: kind === "shot"
|
|
222
|
+
? "Use as new Project copies it into a Project of its own and opens it. Pin saves it on this board for the agent."
|
|
223
|
+
: "This has no layer of its own. Pin it so the agent can use it."}
|
|
224
|
+
</p>
|
|
225
|
+
</div>
|
|
226
|
+
{item.useFor === undefined ? null : (
|
|
227
|
+
<section className="library-preview-usage" aria-label="Good for">
|
|
228
|
+
<h3>Good for</h3>
|
|
229
|
+
<p>{item.useFor}</p>
|
|
230
|
+
</section>
|
|
231
|
+
)}
|
|
232
|
+
{item.avoidFor === undefined ? null : (
|
|
233
|
+
<div className="library-preview-more">
|
|
234
|
+
<button type="button" aria-expanded={more} onClick={() => setMore((v) => !v)}>
|
|
235
|
+
More usage guidance
|
|
236
|
+
{CHEVRON_DOWN_ICON}
|
|
237
|
+
</button>
|
|
238
|
+
{more ? <p>Not for: {item.avoidFor}</p> : null}
|
|
239
|
+
</div>
|
|
240
|
+
)}
|
|
241
|
+
<footer className="library-preview-meta">
|
|
242
|
+
<span>
|
|
243
|
+
{KIND_NOUN[kind]}
|
|
244
|
+
{kind === "component" ? ` · ${item.host === "three" ? "3D" : "2D"}` : ""}
|
|
245
|
+
</span>
|
|
246
|
+
{item.version === undefined ? null : <span>v{item.version}</span>}
|
|
247
|
+
</footer>
|
|
248
|
+
</aside>
|
|
249
|
+
);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/** The item's thumb, or its category glyph on the well when it ships none. */
|
|
253
|
+
function LibraryArt({ item }: { item: LibraryItem }) {
|
|
254
|
+
return item.thumb === undefined ? (
|
|
255
|
+
<span className="library-preview-placeholder" aria-hidden="true">
|
|
256
|
+
{LIBRARY_CATEGORY_ICONS[kindOf(item)]}
|
|
257
|
+
</span>
|
|
258
|
+
) : (
|
|
259
|
+
<img className="library-preview-art" src={item.thumb} alt="" />
|
|
260
|
+
);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* The centre column's larger preview of one component: the way back, the
|
|
265
|
+
* live picture (or the thumb and why), and play / stop. The browser mounts it
|
|
266
|
+
* in place of the catalog, so the rail and the right column stay put.
|
|
267
|
+
*/
|
|
268
|
+
// ponytail: Escape closes the whole Library, not just this view (the Dialog
|
|
269
|
+
// owns the key); give the browser a keydown guard if authors expect a step back.
|
|
270
|
+
export function LibraryExpandedPreview({ item, backTo, onClose }: { item: LibraryItem; backTo: string; onClose: () => void }) {
|
|
271
|
+
const store = useStore();
|
|
272
|
+
const name = displayNameOf(item);
|
|
273
|
+
const doc = useShotEditor((s) => s.doc);
|
|
274
|
+
const registryId = item.installedAs ?? null;
|
|
275
|
+
const row = useShotEditor((s) => (registryId === null ? undefined : s.library.find((r) => r.id === registryId)));
|
|
276
|
+
const contract = useShotEditor((s) => (registryId === null ? undefined : s.contracts[registryId]));
|
|
277
|
+
const [playing, setPlaying] = useState(true);
|
|
278
|
+
// The button that opened this view unmounted with the right column's thumb
|
|
279
|
+
// and head, so focus starts on the way back, not on <body>.
|
|
280
|
+
const backRef = useRef<HTMLButtonElement>(null);
|
|
281
|
+
useEffect(() => backRef.current?.focus(), []);
|
|
282
|
+
useEffect(() => {
|
|
283
|
+
if (registryId !== null && row?.host === "three") void store.loadContract(registryId);
|
|
284
|
+
}, [registryId, row?.host, store]);
|
|
285
|
+
// A STABLE CARD per play state: `ComponentStage` reloads its document when
|
|
286
|
+
// the card object changes, so a fresh literal per render would reload the
|
|
287
|
+
// stage on every store write.
|
|
288
|
+
const card = useMemo<ComponentCard | null>(
|
|
289
|
+
() =>
|
|
290
|
+
registryId === null
|
|
291
|
+
? null
|
|
292
|
+
: { id: "ref_library_preview", type: "component", component: registryId, label: name, props: NO_PROPS, ...(playing ? {} : { frame: 0 }) },
|
|
293
|
+
[registryId, name, playing],
|
|
294
|
+
);
|
|
295
|
+
const live = doc !== null && card !== null && row?.host === "three";
|
|
296
|
+
|
|
297
|
+
let picture: ReactNode;
|
|
298
|
+
if (live && row !== undefined) {
|
|
299
|
+
picture = <ComponentStage doc={doc} item={card} contract={contract} availability={row.contractAvailability} lengthFrames={item.lengthFrames} />;
|
|
300
|
+
} else {
|
|
301
|
+
picture = (
|
|
302
|
+
<div className="library-expanded-still">
|
|
303
|
+
<LibraryArt item={item} />
|
|
304
|
+
<p>
|
|
305
|
+
{doc === null
|
|
306
|
+
? "Open a Project to play this live."
|
|
307
|
+
: row?.host === "dom"
|
|
308
|
+
? DOM_NOT_SUPPORTED
|
|
309
|
+
: "Add or pin it to play it live here. Previewing never installs it."}
|
|
310
|
+
</p>
|
|
311
|
+
</div>
|
|
312
|
+
);
|
|
313
|
+
}
|
|
314
|
+
const fps = doc === null ? 0 : doc.fps.num / doc.fps.den;
|
|
315
|
+
|
|
316
|
+
return (
|
|
317
|
+
<section className="library-expanded" aria-label={`Preview: ${name}`} data-testid="library-expanded">
|
|
318
|
+
<header className="library-expanded-head">
|
|
319
|
+
<div>
|
|
320
|
+
<button ref={backRef} type="button" className="library-expanded-back" onClick={onClose}>
|
|
321
|
+
{CHEVRON_LEFT_ICON}
|
|
322
|
+
Back to {backTo}
|
|
323
|
+
</button>
|
|
324
|
+
<h2>{name}</h2>
|
|
325
|
+
</div>
|
|
326
|
+
<button type="button" className="btn is-outline is-icon is-lg" aria-label="Close the larger preview" title="Close the larger preview" onClick={onClose}>
|
|
327
|
+
{COLLAPSE_ICON}
|
|
328
|
+
</button>
|
|
329
|
+
</header>
|
|
330
|
+
<div className="library-expanded-stage">{picture}</div>
|
|
331
|
+
{live ? (
|
|
332
|
+
<div className="library-expanded-transport">
|
|
333
|
+
<button
|
|
334
|
+
type="button"
|
|
335
|
+
className="library-preview-play"
|
|
336
|
+
aria-label={playing ? `Stop ${name}` : `Play ${name}`}
|
|
337
|
+
onClick={() => setPlaying((v) => !v)}
|
|
338
|
+
>
|
|
339
|
+
{playing ? STOP_ICON : PLAY_ICON}
|
|
340
|
+
</button>
|
|
341
|
+
{item.lengthFrames === undefined || !(fps > 0) ? null : (
|
|
342
|
+
<span className="library-expanded-length">Loops every {formatDuration(item.lengthFrames / fps)}</span>
|
|
343
|
+
)}
|
|
344
|
+
</div>
|
|
345
|
+
) : null}
|
|
346
|
+
</section>
|
|
347
|
+
);
|
|
348
|
+
}
|
|
349
|
+
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
// The Library's left column: the way back, the categories, and the Project an
|
|
2
|
+
// Add lands in.
|
|
3
|
+
//
|
|
4
|
+
// THE BACK ROW IS THE CLOSE. The library has no Done button any more: the
|
|
5
|
+
// author came from somewhere, and the row names it ("Back to <Shot>", or the
|
|
6
|
+
// board, or the Project) so leaving says where it lands. Escape does the same
|
|
7
|
+
// through `Dialog`.
|
|
8
|
+
//
|
|
9
|
+
// EACH ROW IS A BUTTON WITH `aria-pressed`, not a tab: the rows filter one
|
|
10
|
+
// catalog column and own no panel of their own, so a tablist would promise a
|
|
11
|
+
// tabpanel per row that does not exist.
|
|
12
|
+
import type { ReactNode } from "react";
|
|
13
|
+
import { CHEVRON_LEFT_ICON, LIBRARY_CATEGORY_ICONS } from "../../icons.js";
|
|
14
|
+
import { CATEGORY_LABEL, LIBRARY_CATEGORIES, plural } from "./libraryModel.js";
|
|
15
|
+
import type { LibraryCategory } from "./libraryModel.js";
|
|
16
|
+
|
|
17
|
+
export function LibraryRail({
|
|
18
|
+
category,
|
|
19
|
+
counts,
|
|
20
|
+
onCategory,
|
|
21
|
+
backLabel,
|
|
22
|
+
onBack,
|
|
23
|
+
project,
|
|
24
|
+
onBoard,
|
|
25
|
+
}: {
|
|
26
|
+
category: LibraryCategory;
|
|
27
|
+
counts: ReadonlyMap<LibraryCategory, number>;
|
|
28
|
+
onCategory: (category: LibraryCategory) => void;
|
|
29
|
+
/** "Back to Fold reel", "Back to storyboard", "Back to <Project>". */
|
|
30
|
+
backLabel: string;
|
|
31
|
+
onBack: () => void;
|
|
32
|
+
/** The open Project's display name, or null with none open. */
|
|
33
|
+
project: string | null;
|
|
34
|
+
/** Shipped items with at least one card on this Project's board. */
|
|
35
|
+
onBoard: number;
|
|
36
|
+
}) {
|
|
37
|
+
let foot: ReactNode;
|
|
38
|
+
if (project === null) {
|
|
39
|
+
foot = (
|
|
40
|
+
<>
|
|
41
|
+
<span className="library-rail-project">No Project open</span>
|
|
42
|
+
<span>Open a Project to add library items.</span>
|
|
43
|
+
</>
|
|
44
|
+
);
|
|
45
|
+
} else {
|
|
46
|
+
foot = (
|
|
47
|
+
<>
|
|
48
|
+
<span className="library-rail-project">Project · {project}</span>
|
|
49
|
+
<span data-testid="library-on-board">{plural(onBoard, "library item")} on the storyboard</span>
|
|
50
|
+
</>
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
return (
|
|
54
|
+
<nav className="library-rail" aria-label="Library categories">
|
|
55
|
+
<button type="button" className="library-back" data-testid="library-back" onClick={onBack}>
|
|
56
|
+
{CHEVRON_LEFT_ICON}
|
|
57
|
+
<span>{backLabel}</span>
|
|
58
|
+
</button>
|
|
59
|
+
{/* The dialog's own title carries the accessible name "Library"; this
|
|
60
|
+
is its visible face, so the repeat is hidden from a reader. */}
|
|
61
|
+
<div className="library-rail-title">
|
|
62
|
+
<span aria-hidden="true">Library</span>
|
|
63
|
+
<span className="library-rail-sub">Pieces for your next shot</span>
|
|
64
|
+
</div>
|
|
65
|
+
<div className="library-rail-rows">
|
|
66
|
+
{LIBRARY_CATEGORIES.map((c) => (
|
|
67
|
+
<button
|
|
68
|
+
key={c}
|
|
69
|
+
type="button"
|
|
70
|
+
className="library-rail-row"
|
|
71
|
+
data-category={c}
|
|
72
|
+
aria-pressed={c === category}
|
|
73
|
+
onClick={() => onCategory(c)}
|
|
74
|
+
>
|
|
75
|
+
{LIBRARY_CATEGORY_ICONS[c]}
|
|
76
|
+
<span className="library-rail-label">{CATEGORY_LABEL[c]}</span>
|
|
77
|
+
{counts.has(c) ? <span className="library-rail-count">{counts.get(c)}</span> : null}
|
|
78
|
+
</button>
|
|
79
|
+
))}
|
|
80
|
+
</div>
|
|
81
|
+
<div className="library-rail-foot">{foot}</div>
|
|
82
|
+
</nav>
|
|
83
|
+
);
|
|
84
|
+
}
|