@hyperframes/studio 0.8.49 → 0.8.51
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/assets/{hyperframes-player-CqON2Rzo.js → hyperframes-player-Cn_PpHqP.js} +3 -3
- package/dist/assets/index-C05SNrvY.js +360 -0
- package/dist/assets/{index-mIgSsKqs.js → index-CPS3Cvj8.js} +1 -1
- package/dist/assets/{index-BGovDksE.js → index-Clrb11lj.js} +1 -1
- package/dist/assets/index-DUR9qzQM.css +1 -0
- package/dist/index.d.ts +29 -16
- package/dist/index.html +2 -2
- package/dist/index.js +7283 -8606
- package/dist/index.js.map +1 -1
- package/dist/styles/tailwind-preset.js.map +1 -1
- package/package.json +11 -12
- package/src/App.tsx +132 -143
- package/src/captions/components/CaptionAnimationPanel.tsx +4 -4
- package/src/captions/components/CaptionOverlayUtils.ts +2 -3
- package/src/captions/components/CaptionPropertyPanel.tsx +3 -3
- package/src/captions/components/CaptionTimeline.tsx +1 -1
- package/src/captions/components/shared.tsx +2 -2
- package/src/components/AskAgentModal.tsx +5 -5
- package/src/components/EditorShell.selectionSync.test.tsx +4 -0
- package/src/components/EditorShell.tsx +28 -7
- package/src/components/ExternalFileConflictBanner.tsx +16 -16
- package/src/components/LintModal.tsx +6 -16
- package/src/components/MediaPreview.tsx +2 -2
- package/src/components/SaveQueuePausedBanner.tsx +2 -2
- package/src/components/StudioHeader.tsx +2 -62
- package/src/components/StudioLeftSidebar.tsx +7 -4
- package/src/components/StudioOverlays.tsx +2 -6
- package/src/components/StudioRightPanel.tsx +4 -4
- package/src/components/StudioToast.tsx +2 -2
- package/src/components/TimelineToolbar.tsx +7 -7
- package/src/components/dock/Dock.test.tsx +192 -0
- package/src/components/dock/Dock.tsx +264 -0
- package/src/components/dock/dock.css +23 -0
- package/src/components/dock/dockLayout.ts +58 -0
- package/src/components/dock/dockLayoutSchema.ts +66 -0
- package/src/components/dock/dockLayoutStore.ts +91 -0
- package/src/components/dock/panelRegistry.ts +67 -0
- package/src/components/editor/AnimationCard.tsx +4 -4
- package/src/components/editor/AnimationCardParts.tsx +6 -6
- package/src/components/editor/BlockParamsPanel.tsx +4 -4
- package/src/components/editor/BorderRadiusEditor.tsx +1 -1
- package/src/components/editor/CanvasContextMenu.tsx +1 -1
- package/src/components/editor/ComputedTweenNotice.tsx +1 -1
- package/src/components/editor/DomEditOverlay.tsx +1 -1
- package/src/components/editor/EaseCurveSection.tsx +1 -1
- package/src/components/editor/EaseParamFields.tsx +5 -5
- package/src/components/editor/FileTree.tsx +4 -4
- package/src/components/editor/FileTreeIcons.tsx +1 -1
- package/src/components/editor/FileTreeNodes.tsx +13 -13
- package/src/components/editor/InlineTextToolbar.tsx +1 -1
- package/src/components/editor/InspectorHeaderActions.tsx +3 -3
- package/src/components/editor/KeyframeDiamond.tsx +1 -1
- package/src/components/editor/KeyframeEaseList.tsx +1 -1
- package/src/components/editor/LayersPanel.tsx +3 -3
- package/src/components/editor/MarqueeOverlay.tsx +1 -1
- package/src/components/editor/OffCanvasIndicators.tsx +1 -1
- package/src/components/editor/PreviewGuides.test.tsx +88 -0
- package/src/components/editor/PreviewGuides.tsx +125 -0
- package/src/components/editor/PromotableControl.tsx +2 -2
- package/src/components/editor/PropertyPanelEmptyState.tsx +7 -7
- package/src/components/editor/PropertyPanelFlatHeader.tsx +2 -2
- package/src/components/editor/SnapToolbar.test.tsx +21 -0
- package/src/components/editor/SnapToolbar.tsx +27 -3
- package/src/components/editor/TimelineFxPopover.tsx +1 -1
- package/src/components/editor/TopologyLens.tsx +4 -4
- package/src/components/editor/Transform3DCube.tsx +2 -2
- package/src/components/editor/audioFxRevealTarget.ts +1 -0
- package/src/components/editor/domEditing.test.ts +1 -1
- package/src/components/editor/domEditingAgentPrompt.test.ts +8 -6
- package/src/components/editor/domEditingAgentPrompt.ts +9 -3
- package/src/components/editor/previewGuidesStore.ts +26 -0
- package/src/components/editor/propertyPanelColor.tsx +11 -11
- package/src/components/editor/propertyPanelColorCurveGraph.tsx +1 -1
- package/src/components/editor/propertyPanelColorGradingControls.tsx +7 -9
- package/src/components/editor/propertyPanelColorGradingSection.tsx +6 -6
- package/src/components/editor/propertyPanelColorGradingSlider.tsx +5 -5
- package/src/components/editor/propertyPanelColorWheels.tsx +1 -1
- package/src/components/editor/propertyPanelCommitField.tsx +1 -1
- package/src/components/editor/propertyPanelFill.tsx +4 -4
- package/src/components/editor/propertyPanelFlatColorGradingAccessory.tsx +3 -3
- package/src/components/editor/propertyPanelFlatColorGradingSection.tsx +7 -7
- package/src/components/editor/propertyPanelFlatEffectsSection.tsx +4 -4
- package/src/components/editor/propertyPanelFlatMediaSection.tsx +3 -3
- package/src/components/editor/propertyPanelFlatOverlaysSection.tsx +1 -1
- package/src/components/editor/propertyPanelFlatPrimitives.tsx +10 -10
- package/src/components/editor/propertyPanelFlatSelectRow.tsx +3 -3
- package/src/components/editor/propertyPanelFlatTextSection.test.tsx +8 -9
- package/src/components/editor/propertyPanelFlatTextSection.tsx +5 -5
- package/src/components/editor/propertyPanelFlatToggle.tsx +1 -1
- package/src/components/editor/propertyPanelFont.tsx +5 -5
- package/src/components/editor/propertyPanelFxCarveModule.tsx +1 -1
- package/src/components/editor/propertyPanelFxControls.test.tsx +1 -1
- package/src/components/editor/propertyPanelFxControls.tsx +6 -6
- package/src/components/editor/propertyPanelFxEqModule.tsx +2 -2
- package/src/components/editor/propertyPanelFxPresetStyle.ts +2 -2
- package/src/components/editor/propertyPanelGradingNumberField.tsx +1 -1
- package/src/components/editor/propertyPanelMediaSection.tsx +1 -1
- package/src/components/editor/propertyPanelPrimitives.tsx +7 -7
- package/src/components/editor/propertyPanelSections.tsx +8 -8
- package/src/components/feedback/StudioFeedbackCard.tsx +7 -7
- package/src/components/feedback/feedbackTrigger.ts +0 -1
- package/src/components/nle/AssetPreviewOverlay.tsx +6 -2
- package/src/components/nle/CompositionBreadcrumb.tsx +3 -3
- package/src/components/nle/NLEPreview.test.ts +13 -0
- package/src/components/nle/NLEPreview.tsx +12 -7
- package/src/components/nle/PreviewOverlays.tsx +6 -6
- package/src/components/nle/PreviewPane.test.tsx +52 -0
- package/src/components/nle/PreviewPane.tsx +4 -2
- package/src/components/nle/TimelinePane.tsx +17 -3
- package/src/components/nle/TimelineResizeDivider.tsx +2 -2
- package/src/components/nle/useCanvasZOrderTimelineMirror.test.tsx +1 -1
- package/src/components/nle/useCanvasZOrderTimelineMirror.ts +3 -3
- package/src/components/panels/SlideshowPanel.tsx +2 -2
- package/src/components/panels/SlideshowSubPanels.tsx +20 -17
- package/src/components/panels/VariablesBindElement.tsx +2 -2
- package/src/components/panels/VariablesDeclarationForm.tsx +2 -2
- package/src/components/panels/VariablesOtherCompositions.tsx +1 -1
- package/src/components/panels/VariablesPanel.tsx +3 -3
- package/src/components/panels/VariablesValueControls.tsx +2 -2
- package/src/components/renders/FfmpegRequiredNotice.tsx +5 -5
- package/src/components/renders/RenderQueue.test.tsx +7 -0
- package/src/components/renders/RenderQueue.tsx +6 -6
- package/src/components/renders/RenderQueueItem.tsx +6 -6
- package/src/components/sidebar/AssetCard.tsx +8 -8
- package/src/components/sidebar/AssetContextMenu.tsx +8 -8
- package/src/components/sidebar/AssetsTab.tsx +2 -2
- package/src/components/sidebar/AudioRow.tsx +6 -6
- package/src/components/sidebar/BlocksTab.tsx +6 -6
- package/src/components/sidebar/CompositionsTab.tsx +5 -5
- package/src/components/sidebar/GlobalAssetsView.tsx +1 -1
- package/src/components/sidebar/LeftSidebar.lintBadge.test.tsx +58 -0
- package/src/components/sidebar/LeftSidebar.tsx +19 -5
- package/src/components/sidebar/PromptPreviewModal.tsx +3 -3
- package/src/components/ui/Button.test.tsx +60 -0
- package/src/components/ui/Button.tsx +4 -4
- package/src/components/ui/SearchInput.tsx +2 -2
- package/src/components/ui/Tooltip.tsx +1 -1
- package/src/hooks/appHotkeysDispatch.ts +11 -0
- package/src/hooks/timelineAudioGroupCreate.ts +2 -2
- package/src/hooks/timelineTrackVisibility.ts +8 -11
- package/src/hooks/useAppHotkeys.textEditing.test.tsx +1 -0
- package/src/hooks/useAppHotkeys.ts +4 -1
- package/src/hooks/useAskAgentModal.ts +2 -0
- package/src/hooks/useClipboard.test.ts +234 -0
- package/src/hooks/useClipboard.ts +264 -70
- package/src/hooks/useGroupCommits.test.ts +0 -1
- package/src/hooks/useLintModal.test.tsx +65 -0
- package/src/hooks/useLintModal.ts +3 -0
- package/src/hooks/useRazorSplit.history.test.tsx +0 -1
- package/src/hooks/useRazorSplit.test.ts +0 -2
- package/src/hooks/useRazorSplit.test.tsx +0 -1
- package/src/hooks/useSdkSession.lifecycle.test.tsx +49 -4
- package/src/hooks/useSdkSession.ts +43 -10
- package/src/hooks/useStudioContextValue.ts +5 -19
- package/src/hooks/useTimelineAssetDropOps.test.tsx +41 -1
- package/src/hooks/useTimelineAssetDropOps.ts +52 -11
- package/src/hooks/useTimelineEditing.test.tsx +0 -1
- package/src/main.tsx +9 -3
- package/src/player/components/AudioWaveform.tsx +1 -1
- package/src/player/components/AutomationSelectionMenu.tsx +2 -2
- package/src/player/components/ClipContextMenu.tsx +90 -10
- package/src/player/components/CompositionThumbnail.test.ts +0 -3
- package/src/player/components/CompositionThumbnail.tsx +3 -4
- package/src/player/components/EditModal.tsx +1 -1
- package/src/player/components/ImageThumbnail.tsx +1 -1
- package/src/player/components/KeyframeDiamondContextMenu.tsx +4 -4
- package/src/player/components/LayerDisclosureRow.tsx +2 -2
- package/src/player/components/PlayerControls.tsx +1 -1
- package/src/player/components/ShortcutsPanel.tsx +9 -9
- package/src/player/components/SpeedMenu.tsx +3 -5
- package/src/player/components/Timeline.tsx +16 -15
- package/src/player/components/TimelineCanvas.tsx +45 -8
- package/src/player/components/TimelineDiamondConnectors.tsx +1 -1
- package/src/player/components/TimelineEmptyState.tsx +5 -5
- package/src/player/components/TimelineFxButton.tsx +6 -6
- package/src/player/components/TimelineGestureOverlay.test.tsx +35 -1
- package/src/player/components/TimelineGestureOverlay.tsx +1 -1
- package/src/player/components/TimelineGroupHeader.tsx +5 -5
- package/src/player/components/TimelineGroupLaneLabels.tsx +1 -1
- package/src/player/components/TimelineGroupRow.tsx +1 -1
- package/src/player/components/TimelineLanes.test.tsx +54 -1
- package/src/player/components/TimelineLanes.tsx +2 -5
- package/src/player/components/TimelineLayerGroupHeader.tsx +2 -2
- package/src/player/components/TimelineOverlays.tsx +12 -0
- package/src/player/components/TimelineRuler.tsx +1 -1
- package/src/player/components/TimelineShortcutHint.tsx +1 -1
- package/src/player/components/TimelineTrackHeader.tsx +1 -1
- package/src/player/components/TimelineTrackPlainHeader.tsx +3 -3
- package/src/player/components/TimelineTypes.ts +6 -1
- package/src/player/components/TrackGapContextMenu.tsx +1 -1
- package/src/player/components/VideoThumbnail.tsx +4 -2
- package/src/player/components/VolumeControl.tsx +2 -2
- package/src/player/components/timelineAuthoredMoveTarget.ts +1 -2
- package/src/player/components/timelineCallbacks.ts +8 -8
- package/src/player/components/timelineClipChildren.test.ts +2 -2
- package/src/player/components/timelineClipChildren.tsx +2 -1
- package/src/player/components/timelineClipDragCommit.ts +2 -2
- package/src/player/components/timelineClipDragPreview.ts +51 -27
- package/src/player/components/timelineClipDragTypes.ts +3 -0
- package/src/player/components/timelineDragDrop.test.tsx +92 -1
- package/src/player/components/timelineDragDrop.ts +82 -33
- package/src/player/components/timelineEditCapabilities.ts +1 -2
- package/src/player/components/timelineEditing.test.ts +0 -16
- package/src/player/components/timelineGroupEditing.test.ts +1 -3
- package/src/player/components/timelineGroupEditing.ts +0 -1
- package/src/player/components/timelineLaneProps.ts +3 -0
- package/src/player/components/timelineSnapping.test.ts +27 -0
- package/src/player/components/timelineSnapping.ts +14 -1
- package/src/player/components/timelineTrackDisplay.ts +1 -1
- package/src/player/components/timelineTrackPersistPipeline.test.ts +0 -53
- package/src/player/components/trackHeaderLabelRows.tsx +4 -4
- package/src/player/components/useTimelineClipContextMenu.ts +32 -0
- package/src/player/components/useTimelineClipDrag.resize.test.tsx +136 -2
- package/src/player/components/useTimelineClipDrag.ts +30 -3
- package/src/player/components/useTimelineTrackDerivations.ts +1 -1
- package/src/player/hooks/timelineDomBinding.test.ts +0 -3
- package/src/player/hooks/timelineSyncHydration.test.ts +18 -0
- package/src/player/hooks/timelineSyncHydration.ts +37 -18
- package/src/player/hooks/useTimelinePlayer.test.ts +3 -20
- package/src/player/hooks/useTimelineRowElements.test.ts +28 -0
- package/src/player/hooks/useTimelineRowElements.ts +17 -0
- package/src/player/hooks/useTimelineSyncCallbacks.emptyManifest.test.tsx +41 -0
- package/src/player/hooks/useTimelineSyncCallbacks.ts +9 -10
- package/src/player/lib/describeClips.test.ts +95 -0
- package/src/player/lib/describeClips.ts +52 -0
- package/src/player/lib/timelineDOM.test.ts +0 -80
- package/src/player/lib/timelineDOM.ts +1 -61
- package/src/player/lib/timelineElementHelpers.ts +2 -53
- package/src/player/store/playerStore.ts +5 -0
- package/src/player/store/timelineElement.ts +1 -3
- package/src/shims/canvasBrowserStub.js +50 -0
- package/src/styles/iconTokens.ts +20 -0
- package/src/styles/palette-reset.css +6 -0
- package/src/styles/studio.css +24 -21
- package/src/styles/tailwind-preset.shared.js +3 -0
- package/src/styles/theme.css +213 -0
- package/src/styles/theme.test.ts +196 -0
- package/src/utils/clipboardPayload.test.ts +42 -2
- package/src/utils/clipboardPayload.ts +57 -32
- package/src/utils/previewSafeMargins.test.ts +34 -0
- package/src/utils/previewSafeMargins.ts +10 -0
- package/src/utils/razorSplitTransaction.test.ts +0 -1
- package/src/utils/sdkCanvasComposition.test.ts +77 -0
- package/src/utils/studioUiPreferences.test.ts +43 -0
- package/src/utils/studioUiPreferences.ts +34 -6
- package/src/utils/timelineDropTrackInsert.test.ts +134 -0
- package/src/utils/timelineDropTrackInsert.ts +83 -0
- package/src/utils/timelineElementSplit.test.ts +1 -2
- package/src/utils/timelineElementSplit.ts +0 -1
- package/src/webmcp/tools/lookTools.test.ts +40 -0
- package/src/webmcp/tools/lookTools.ts +32 -1
- package/dist/assets/index-B9LfWNyM.css +0 -1
- package/dist/assets/index-Bgmx2h7W.js +0 -441
- package/src/components/StudioGlobalDragOverlay.tsx +0 -24
- package/src/components/storyboard/AgentChatMessageButton.test.tsx +0 -47
- package/src/components/storyboard/AgentChatMessageButton.tsx +0 -45
- package/src/components/storyboard/FramePoster.test.tsx +0 -61
- package/src/components/storyboard/FramePoster.tsx +0 -86
- package/src/components/storyboard/StoryboardDirection.tsx +0 -45
- package/src/components/storyboard/StoryboardFrameFocus.tsx +0 -412
- package/src/components/storyboard/StoryboardFrameTile.tsx +0 -117
- package/src/components/storyboard/StoryboardGrid.tsx +0 -55
- package/src/components/storyboard/StoryboardLoaded.tsx +0 -307
- package/src/components/storyboard/StoryboardReviewGuide.tsx +0 -300
- package/src/components/storyboard/StoryboardScriptPanel.tsx +0 -26
- package/src/components/storyboard/StoryboardSourceEditor.tsx +0 -231
- package/src/components/storyboard/StoryboardStatusLegend.tsx +0 -21
- package/src/components/storyboard/StoryboardView.tsx +0 -169
- package/src/components/storyboard/StoryboardViewModeGuard.test.tsx +0 -187
- package/src/components/storyboard/frameComments.test.ts +0 -95
- package/src/components/storyboard/frameComments.ts +0 -115
- package/src/components/storyboard/frameStatus.ts +0 -36
- package/src/components/storyboard/storyboardReviewStage.test.ts +0 -40
- package/src/components/storyboard/storyboardReviewStage.ts +0 -45
- package/src/components/storyboard/useFrameComments.ts +0 -98
- package/src/contexts/ViewModeContext.tsx +0 -142
- package/src/hooks/useProjectSignaturePoll.test.tsx +0 -135
- package/src/hooks/useProjectSignaturePoll.ts +0 -68
- package/src/hooks/useStoryboard.ts +0 -99
- package/src/player/hooks/useExpandedTimelineElements.test.ts +0 -774
- package/src/player/hooks/useExpandedTimelineElements.ts +0 -460
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { create } from "zustand";
|
|
2
|
+
import {
|
|
3
|
+
PANEL_DEFINITIONS,
|
|
4
|
+
PANEL_IDS,
|
|
5
|
+
panelsInZone,
|
|
6
|
+
type PanelId,
|
|
7
|
+
type PanelZone,
|
|
8
|
+
} from "./panelRegistry";
|
|
9
|
+
|
|
10
|
+
/** The narrow surface Dock.Root exposes; dockview types never leave the dock folder. */
|
|
11
|
+
export interface DockController {
|
|
12
|
+
/** Adds the panel at its default place if it is closed; never moves focus. */
|
|
13
|
+
open: (id: PanelId) => void;
|
|
14
|
+
/** Focuses the panel, reopening it at its default place if it was closed. */
|
|
15
|
+
activate: (id: PanelId) => void;
|
|
16
|
+
setTitle: (id: PanelId, title: string) => void;
|
|
17
|
+
close: (id: PanelId) => void;
|
|
18
|
+
/** Hides or shows the panel's whole tab group without closing it. */
|
|
19
|
+
setGroupVisible: (id: PanelId, visible: boolean) => void;
|
|
20
|
+
reset: () => void;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface DockSnapshot {
|
|
24
|
+
openPanels: ReadonlySet<PanelId>;
|
|
25
|
+
/** Open panels whose tab is showing and whose group is not hidden. */
|
|
26
|
+
visiblePanels: ReadonlySet<PanelId>;
|
|
27
|
+
activePanel: PanelId | null;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
type LastActive = Partial<Record<PanelZone, PanelId>>;
|
|
31
|
+
|
|
32
|
+
interface DockLayoutState extends DockSnapshot {
|
|
33
|
+
controller: DockController | null;
|
|
34
|
+
lastActive: LastActive;
|
|
35
|
+
/** An activation requested before the dock mounted; Dock.Root applies it on ready. */
|
|
36
|
+
pendingActivation: PanelId | null;
|
|
37
|
+
attach: (controller: DockController) => void;
|
|
38
|
+
detach: () => void;
|
|
39
|
+
sync: (snapshot: DockSnapshot) => void;
|
|
40
|
+
takePendingActivation: () => PanelId | null;
|
|
41
|
+
activatePanel: (id: PanelId) => void;
|
|
42
|
+
closePanel: (id: PanelId) => void;
|
|
43
|
+
togglePanel: (id: PanelId) => void;
|
|
44
|
+
setZoneVisible: (zone: PanelZone, visible: boolean) => void;
|
|
45
|
+
resetLayout: () => void;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export const useDockLayoutStore = create<DockLayoutState>((set, get) => ({
|
|
49
|
+
controller: null,
|
|
50
|
+
openPanels: new Set(PANEL_IDS),
|
|
51
|
+
visiblePanels: new Set(PANEL_IDS),
|
|
52
|
+
activePanel: null,
|
|
53
|
+
lastActive: {},
|
|
54
|
+
pendingActivation: null,
|
|
55
|
+
attach: (controller) => set({ controller }),
|
|
56
|
+
detach: () => set({ controller: null }),
|
|
57
|
+
sync: (snapshot) =>
|
|
58
|
+
set((state) => {
|
|
59
|
+
const { activePanel } = snapshot;
|
|
60
|
+
if (!activePanel) return snapshot;
|
|
61
|
+
const zone = PANEL_DEFINITIONS[activePanel].zone;
|
|
62
|
+
return { ...snapshot, lastActive: { ...state.lastActive, [zone]: activePanel } };
|
|
63
|
+
}),
|
|
64
|
+
takePendingActivation: () => {
|
|
65
|
+
const { pendingActivation } = get();
|
|
66
|
+
set({ pendingActivation: null });
|
|
67
|
+
return pendingActivation;
|
|
68
|
+
},
|
|
69
|
+
activatePanel: (id) => {
|
|
70
|
+
const { controller } = get();
|
|
71
|
+
if (!controller) {
|
|
72
|
+
set({ pendingActivation: id });
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
controller.setGroupVisible(id, true);
|
|
76
|
+
controller.activate(id);
|
|
77
|
+
},
|
|
78
|
+
closePanel: (id) => get().controller?.close(id),
|
|
79
|
+
togglePanel: (id) => {
|
|
80
|
+
const { openPanels, activatePanel, closePanel } = get();
|
|
81
|
+
if (openPanels.has(id)) closePanel(id);
|
|
82
|
+
else activatePanel(id);
|
|
83
|
+
},
|
|
84
|
+
setZoneVisible: (zone, visible) => {
|
|
85
|
+
const { controller, openPanels } = get();
|
|
86
|
+
for (const id of panelsInZone(zone)) {
|
|
87
|
+
if (openPanels.has(id)) controller?.setGroupVisible(id, visible);
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
resetLayout: () => get().controller?.reset(),
|
|
91
|
+
}));
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { Direction } from "dockview-react";
|
|
2
|
+
|
|
3
|
+
export const PANEL_IDS = [
|
|
4
|
+
"preview",
|
|
5
|
+
"timeline",
|
|
6
|
+
"compositions",
|
|
7
|
+
"assets",
|
|
8
|
+
"code",
|
|
9
|
+
"catalog",
|
|
10
|
+
"design",
|
|
11
|
+
"layers",
|
|
12
|
+
"renders",
|
|
13
|
+
"variables",
|
|
14
|
+
"slideshow",
|
|
15
|
+
] as const;
|
|
16
|
+
|
|
17
|
+
export type PanelId = (typeof PANEL_IDS)[number];
|
|
18
|
+
export type PanelZone = "left" | "center" | "right";
|
|
19
|
+
|
|
20
|
+
export interface PanelDefinition {
|
|
21
|
+
title: string;
|
|
22
|
+
zone: PanelZone;
|
|
23
|
+
/** Where Window > <panel> puts it when it has no saved place: next to `near`. */
|
|
24
|
+
reopen: { near: PanelId; direction: Direction };
|
|
25
|
+
/** Content stays mounted while its tab is hidden (the preview iframe must not reload). */
|
|
26
|
+
keepMounted?: true;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export const PANEL_DEFINITIONS = {
|
|
30
|
+
preview: {
|
|
31
|
+
title: "Preview",
|
|
32
|
+
zone: "center",
|
|
33
|
+
reopen: { near: "timeline", direction: "above" },
|
|
34
|
+
keepMounted: true,
|
|
35
|
+
},
|
|
36
|
+
timeline: {
|
|
37
|
+
title: "Timeline",
|
|
38
|
+
zone: "center",
|
|
39
|
+
reopen: { near: "preview", direction: "below" },
|
|
40
|
+
keepMounted: true,
|
|
41
|
+
},
|
|
42
|
+
compositions: {
|
|
43
|
+
title: "Compositions",
|
|
44
|
+
zone: "left",
|
|
45
|
+
reopen: { near: "preview", direction: "left" },
|
|
46
|
+
},
|
|
47
|
+
assets: { title: "Assets", zone: "left", reopen: { near: "compositions", direction: "within" } },
|
|
48
|
+
code: { title: "Code", zone: "left", reopen: { near: "compositions", direction: "within" } },
|
|
49
|
+
catalog: {
|
|
50
|
+
title: "Catalog",
|
|
51
|
+
zone: "left",
|
|
52
|
+
reopen: { near: "compositions", direction: "within" },
|
|
53
|
+
},
|
|
54
|
+
design: { title: "Design", zone: "right", reopen: { near: "preview", direction: "right" } },
|
|
55
|
+
layers: { title: "Layers", zone: "right", reopen: { near: "design", direction: "within" } },
|
|
56
|
+
renders: { title: "Renders", zone: "right", reopen: { near: "design", direction: "within" } },
|
|
57
|
+
variables: { title: "Variables", zone: "right", reopen: { near: "design", direction: "within" } },
|
|
58
|
+
slideshow: { title: "Slideshow", zone: "right", reopen: { near: "design", direction: "within" } },
|
|
59
|
+
} as const satisfies Record<PanelId, PanelDefinition>;
|
|
60
|
+
|
|
61
|
+
export function isPanelId(value: unknown): value is PanelId {
|
|
62
|
+
return typeof value === "string" && (PANEL_IDS as readonly string[]).includes(value);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function panelsInZone(zone: PanelZone): PanelId[] {
|
|
66
|
+
return PANEL_IDS.filter((id) => PANEL_DEFINITIONS[id].zone === zone);
|
|
67
|
+
}
|
|
@@ -172,7 +172,7 @@ export const AnimationCard = memo(function AnimationCard({
|
|
|
172
172
|
return (
|
|
173
173
|
<div className="border-b border-neutral-800 pb-2">
|
|
174
174
|
<div className="flex items-center gap-2 py-1.5">
|
|
175
|
-
<span className="rounded bg-neutral-800 px-1.5 py-0.5 text-[10px] font-medium text-neutral-400">
|
|
175
|
+
<span className="rounded-sm bg-neutral-800 px-1.5 py-0.5 text-[10px] font-medium text-neutral-400">
|
|
176
176
|
Position
|
|
177
177
|
</span>
|
|
178
178
|
<span className="text-[11px] text-neutral-500">
|
|
@@ -201,7 +201,7 @@ export const AnimationCard = memo(function AnimationCard({
|
|
|
201
201
|
className="flex w-full items-center gap-2 py-1.5 active:scale-[0.99]"
|
|
202
202
|
>
|
|
203
203
|
<span
|
|
204
|
-
className="rounded bg-panel-accent/10 px-1.5 py-0.5 text-[10px] font-semibold text-panel-accent"
|
|
204
|
+
className="rounded-sm bg-panel-accent/10 px-1.5 py-0.5 text-[10px] font-semibold text-panel-accent"
|
|
205
205
|
title={METHOD_TOOLTIPS[animation.method]}
|
|
206
206
|
>
|
|
207
207
|
{methodLabel}
|
|
@@ -226,7 +226,7 @@ export const AnimationCard = memo(function AnimationCard({
|
|
|
226
226
|
height="10"
|
|
227
227
|
viewBox="0 0 10 10"
|
|
228
228
|
fill="currentColor"
|
|
229
|
-
className={`
|
|
229
|
+
className={`shrink-0 transition-transform ${flat ? "text-panel-text-5" : "text-neutral-500"} ${expanded ? "" : "-rotate-90"}`}
|
|
230
230
|
>
|
|
231
231
|
<path d="M2 3l3 4 3-4z" />
|
|
232
232
|
</svg>
|
|
@@ -262,7 +262,7 @@ export const AnimationCard = memo(function AnimationCard({
|
|
|
262
262
|
setCopied(true);
|
|
263
263
|
setTimeout(() => setCopied(false), 1500);
|
|
264
264
|
}}
|
|
265
|
-
className="
|
|
265
|
+
className="shrink-0 rounded-sm px-1.5 py-0.5 text-[9px] font-medium text-neutral-500 transition-colors hover:bg-neutral-800 hover:text-neutral-300"
|
|
266
266
|
title="Copy description to clipboard — paste into agent prompts"
|
|
267
267
|
>
|
|
268
268
|
{copied ? "Copied" : "Copy"}
|
|
@@ -46,7 +46,7 @@ function RemoveButton({ onClick, title }: { onClick: () => void; title: string }
|
|
|
46
46
|
<button
|
|
47
47
|
type="button"
|
|
48
48
|
onClick={onClick}
|
|
49
|
-
className="relative
|
|
49
|
+
className="relative shrink-0 rounded-sm p-1.5 text-neutral-600 transition-colors hover:bg-neutral-800 hover:text-red-400 active:scale-[0.95]"
|
|
50
50
|
title={title}
|
|
51
51
|
aria-label={title}
|
|
52
52
|
>
|
|
@@ -91,7 +91,7 @@ export function PropertyRow({
|
|
|
91
91
|
role="switch"
|
|
92
92
|
aria-checked={isVisible}
|
|
93
93
|
onClick={() => onCommit(isVisible ? "hidden" : "visible")}
|
|
94
|
-
className="
|
|
94
|
+
className="shrink-0 rounded-full transition-colors duration-200 relative"
|
|
95
95
|
style={{ width: 28, height: 16, background: isVisible ? P.accent : P.borderInput }}
|
|
96
96
|
title={isVisible ? "Visible — click to hide" : "Hidden — click to show"}
|
|
97
97
|
>
|
|
@@ -117,13 +117,13 @@ export function PropertyRow({
|
|
|
117
117
|
<div className="flex flex-col gap-1">
|
|
118
118
|
<div className="flex items-center gap-1">
|
|
119
119
|
<div className="min-w-0 flex-1 flex items-center gap-2 px-2 py-1 rounded-lg bg-neutral-900 border border-neutral-800">
|
|
120
|
-
<span className="
|
|
120
|
+
<span className="shrink-0 text-[11px] font-medium text-neutral-500">
|
|
121
121
|
{PROP_LABELS[prop] ?? prop}
|
|
122
122
|
</span>
|
|
123
123
|
<input
|
|
124
124
|
type="text"
|
|
125
125
|
defaultValue={String(val)}
|
|
126
|
-
className="flex-1 bg-transparent text-[11px] text-neutral-200 outline-
|
|
126
|
+
className="flex-1 bg-transparent text-[11px] text-neutral-200 outline-hidden"
|
|
127
127
|
onBlur={(e) => onCommit(e.currentTarget.value)}
|
|
128
128
|
onKeyDown={(e) => {
|
|
129
129
|
if (e.key === "Enter") e.currentTarget.blur();
|
|
@@ -139,7 +139,7 @@ export function PropertyRow({
|
|
|
139
139
|
key={p.value}
|
|
140
140
|
type="button"
|
|
141
141
|
onClick={() => onCommit(p.value)}
|
|
142
|
-
className="px-1.5 py-0.5 rounded text-[9px] font-medium text-neutral-500 bg-neutral-800/50 hover:bg-neutral-800 hover:text-neutral-300 transition-colors"
|
|
142
|
+
className="px-1.5 py-0.5 rounded-sm text-[9px] font-medium text-neutral-500 bg-neutral-800/50 hover:bg-neutral-800 hover:text-neutral-300 transition-colors"
|
|
143
143
|
>
|
|
144
144
|
{p.label}
|
|
145
145
|
</button>
|
|
@@ -190,7 +190,7 @@ export function AddPropertyTrigger({
|
|
|
190
190
|
return (
|
|
191
191
|
<select
|
|
192
192
|
autoFocus
|
|
193
|
-
className="min-w-0 rounded-lg border border-neutral-700 bg-neutral-900 px-2 py-1 text-[11px] text-neutral-100 outline-
|
|
193
|
+
className="min-w-0 rounded-lg border border-neutral-700 bg-neutral-900 px-2 py-1 text-[11px] text-neutral-100 outline-hidden"
|
|
194
194
|
defaultValue=""
|
|
195
195
|
onChange={(e) => {
|
|
196
196
|
if (e.target.value) onAdd(e.target.value);
|
|
@@ -222,7 +222,7 @@ function ParamControl({
|
|
|
222
222
|
disabled={disabled}
|
|
223
223
|
aria-label={`${param.label} color`}
|
|
224
224
|
onChange={(e) => onChange(e.target.value)}
|
|
225
|
-
className="w-7 h-7 rounded border border-neutral-700 bg-transparent cursor-pointer disabled:cursor-not-allowed disabled:opacity-50"
|
|
225
|
+
className="w-7 h-7 rounded-sm border border-neutral-700 bg-transparent cursor-pointer disabled:cursor-not-allowed disabled:opacity-50"
|
|
226
226
|
/>
|
|
227
227
|
<input
|
|
228
228
|
type="text"
|
|
@@ -230,7 +230,7 @@ function ParamControl({
|
|
|
230
230
|
disabled={disabled}
|
|
231
231
|
aria-label={`${param.label} value`}
|
|
232
232
|
onChange={(e) => onChange(e.target.value)}
|
|
233
|
-
className="flex-1 bg-neutral-900 border border-neutral-800 rounded px-2 py-1 text-[10px] text-neutral-200 font-mono focus:outline-
|
|
233
|
+
className="flex-1 bg-neutral-900 border border-neutral-800 rounded-sm px-2 py-1 text-[10px] text-neutral-200 font-mono focus:outline-hidden focus:border-neutral-700 disabled:cursor-not-allowed disabled:opacity-50"
|
|
234
234
|
/>
|
|
235
235
|
</div>
|
|
236
236
|
)}
|
|
@@ -259,7 +259,7 @@ function ParamControl({
|
|
|
259
259
|
disabled={disabled}
|
|
260
260
|
aria-label={param.label}
|
|
261
261
|
onChange={(e) => onChange(e.target.value)}
|
|
262
|
-
className="w-full bg-neutral-900 border border-neutral-800 rounded px-2 py-1 text-[10px] text-neutral-200 focus:outline-
|
|
262
|
+
className="w-full bg-neutral-900 border border-neutral-800 rounded-sm px-2 py-1 text-[10px] text-neutral-200 focus:outline-hidden focus:border-neutral-700 disabled:cursor-not-allowed disabled:opacity-50"
|
|
263
263
|
/>
|
|
264
264
|
)}
|
|
265
265
|
|
|
@@ -269,7 +269,7 @@ function ParamControl({
|
|
|
269
269
|
disabled={disabled}
|
|
270
270
|
aria-label={param.label}
|
|
271
271
|
onChange={(e) => onChange(e.target.value)}
|
|
272
|
-
className="w-full bg-neutral-900 border border-neutral-800 rounded px-2 py-1 text-[10px] text-neutral-200 focus:outline-
|
|
272
|
+
className="w-full bg-neutral-900 border border-neutral-800 rounded-sm px-2 py-1 text-[10px] text-neutral-200 focus:outline-hidden focus:border-neutral-700 disabled:cursor-not-allowed disabled:opacity-50"
|
|
273
273
|
>
|
|
274
274
|
{param.options.map((opt) => (
|
|
275
275
|
<option key={opt.value} value={opt.value}>
|
|
@@ -212,7 +212,7 @@ export const CanvasContextMenu = memo(function CanvasContextMenu({
|
|
|
212
212
|
return createPortal(
|
|
213
213
|
<div
|
|
214
214
|
ref={menuRef}
|
|
215
|
-
className="fixed z-
|
|
215
|
+
className="fixed z-200 bg-neutral-900 border border-neutral-700 rounded-md shadow-lg py-1 min-w-[180px]"
|
|
216
216
|
style={{ left: adjustedX, top: adjustedY }}
|
|
217
217
|
onPointerDown={stopBubble}
|
|
218
218
|
onMouseDown={stopBubble}
|
|
@@ -29,7 +29,7 @@ export function ComputedTweenNotice({
|
|
|
29
29
|
<button
|
|
30
30
|
type="button"
|
|
31
31
|
onClick={onUnroll}
|
|
32
|
-
className="
|
|
32
|
+
className="shrink-0 rounded-sm px-1.5 py-0.5 text-[9px] font-medium text-panel-accent hover:bg-neutral-800"
|
|
33
33
|
title="Rewrite the helper/loop into explicit tweens so this keyframe edits directly"
|
|
34
34
|
>
|
|
35
35
|
Unroll to edit
|
|
@@ -465,7 +465,7 @@ export const DomEditOverlay = memo(function DomEditOverlay({
|
|
|
465
465
|
ref={overlayRef}
|
|
466
466
|
// Standing aside is the only way the caret below can be reached, and is
|
|
467
467
|
// what keeps selection, drag and marquee from firing mid-edit.
|
|
468
|
-
className={`absolute inset-0 z-10 outline-
|
|
468
|
+
className={`absolute inset-0 z-10 outline-hidden ${
|
|
469
469
|
inlineText.editing ? "pointer-events-none" : "pointer-events-auto"
|
|
470
470
|
}`}
|
|
471
471
|
data-editing-text={inlineText.editing ? "true" : undefined}
|
|
@@ -518,7 +518,7 @@ export function EaseCurveSection({
|
|
|
518
518
|
aria-valuemax={1}
|
|
519
519
|
aria-valuenow={key === "p1" ? x1 : x2}
|
|
520
520
|
aria-valuetext={`x ${key === "p1" ? x1 : x2}, y ${key === "p1" ? y1 : y2}`}
|
|
521
|
-
className="cursor-grab stroke-transparent outline-
|
|
521
|
+
className="cursor-grab stroke-transparent outline-hidden active:cursor-grabbing focus-visible:stroke-white focus-visible:stroke-[2px]"
|
|
522
522
|
onPointerDown={(e) => handlePointerDown(key, e)}
|
|
523
523
|
onKeyDown={(event) => handleKeyDown(key, event)}
|
|
524
524
|
onPointerEnter={() => setHover(key)}
|
|
@@ -93,7 +93,7 @@ export function EaseBezierField({
|
|
|
93
93
|
}
|
|
94
94
|
}}
|
|
95
95
|
onBlur={(event) => commit(event.currentTarget.value)}
|
|
96
|
-
className={`w-full rounded border bg-black/20 px-1.5 py-1 font-mono text-[10px] text-neutral-300 outline-
|
|
96
|
+
className={`w-full rounded border bg-black/20 px-1.5 py-1 font-mono text-[10px] text-neutral-300 outline-hidden ${
|
|
97
97
|
error
|
|
98
98
|
? "border-red-500/70 focus:border-red-400"
|
|
99
99
|
: "border-white/10 focus:border-panel-accent/50"
|
|
@@ -183,7 +183,7 @@ export function SpringBounceField({
|
|
|
183
183
|
const bounce = parseSpringBounce(`spring(${value})`);
|
|
184
184
|
if (bounce !== null) onCommit(`spring(${round2(bounce)})`);
|
|
185
185
|
}}
|
|
186
|
-
className="w-16 rounded border border-white/10 bg-black/20 px-1.5 py-1 font-mono text-[10px] text-neutral-300 outline-
|
|
186
|
+
className="w-16 rounded-sm border border-white/10 bg-black/20 px-1.5 py-1 font-mono text-[10px] text-neutral-300 outline-hidden focus:border-panel-accent/50"
|
|
187
187
|
/>
|
|
188
188
|
</div>
|
|
189
189
|
);
|
|
@@ -207,7 +207,7 @@ export function WiggleField({
|
|
|
207
207
|
min={1}
|
|
208
208
|
step={1}
|
|
209
209
|
onCommit={(value) => commitWiggle(onCommit, value, config.type, amplitude)}
|
|
210
|
-
className="w-14 rounded border border-white/10 bg-black/20 px-1.5 py-1 font-mono text-[10px] text-neutral-300 outline-
|
|
210
|
+
className="w-14 rounded-sm border border-white/10 bg-black/20 px-1.5 py-1 font-mono text-[10px] text-neutral-300 outline-hidden focus:border-panel-accent/50"
|
|
211
211
|
/>
|
|
212
212
|
</div>
|
|
213
213
|
<div className="flex items-center gap-1">
|
|
@@ -220,7 +220,7 @@ export function WiggleField({
|
|
|
220
220
|
commitWiggle(onCommit, config.wiggles, event.currentTarget.value, amplitude);
|
|
221
221
|
}
|
|
222
222
|
}}
|
|
223
|
-
className="rounded border border-white/10 bg-black/20 px-1.5 py-1 text-[10px] text-neutral-300 outline-
|
|
223
|
+
className="rounded-sm border border-white/10 bg-black/20 px-1.5 py-1 text-[10px] text-neutral-300 outline-hidden focus:border-panel-accent/50"
|
|
224
224
|
>
|
|
225
225
|
{WIGGLE_TYPES.map((type) => (
|
|
226
226
|
<option key={type} value={type}>
|
|
@@ -238,7 +238,7 @@ export function WiggleField({
|
|
|
238
238
|
max={1}
|
|
239
239
|
step={0.01}
|
|
240
240
|
onCommit={(value) => commitWiggle(onCommit, config.wiggles, config.type, value)}
|
|
241
|
-
className="w-16 rounded border border-white/10 bg-black/20 px-1.5 py-1 font-mono text-[10px] text-neutral-300 outline-
|
|
241
|
+
className="w-16 rounded-sm border border-white/10 bg-black/20 px-1.5 py-1 font-mono text-[10px] text-neutral-300 outline-hidden focus:border-panel-accent/50"
|
|
242
242
|
/>
|
|
243
243
|
</div>
|
|
244
244
|
</div>
|
|
@@ -235,14 +235,14 @@ export const FileTree = memo(function FileTree({
|
|
|
235
235
|
<div className="flex flex-col h-full min-h-0">
|
|
236
236
|
{/* FILES header with action buttons */}
|
|
237
237
|
{hasFileOps && (
|
|
238
|
-
<div className="flex items-center justify-between px-2.5 py-1.5 border-b border-neutral-800/50
|
|
238
|
+
<div className="flex items-center justify-between px-2.5 py-1.5 border-b border-neutral-800/50 shrink-0">
|
|
239
239
|
<span className="text-[10px] font-semibold tracking-wider text-neutral-600 uppercase">
|
|
240
240
|
Files
|
|
241
241
|
</span>
|
|
242
242
|
<div className="flex items-center gap-0.5">
|
|
243
243
|
<button
|
|
244
244
|
onClick={() => handleNewFile("")}
|
|
245
|
-
className="p-1.5 rounded hover:bg-neutral-800 text-neutral-600 hover:text-neutral-400 active:scale-[0.97] transition-colors"
|
|
245
|
+
className="p-1.5 rounded-sm hover:bg-neutral-800 text-neutral-600 hover:text-neutral-400 active:scale-[0.97] transition-colors"
|
|
246
246
|
title="New File"
|
|
247
247
|
aria-label="New File"
|
|
248
248
|
>
|
|
@@ -250,7 +250,7 @@ export const FileTree = memo(function FileTree({
|
|
|
250
250
|
</button>
|
|
251
251
|
<button
|
|
252
252
|
onClick={() => handleNewFolder("")}
|
|
253
|
-
className="p-1.5 rounded hover:bg-neutral-800 text-neutral-600 hover:text-neutral-400 active:scale-[0.97] transition-colors"
|
|
253
|
+
className="p-1.5 rounded-sm hover:bg-neutral-800 text-neutral-600 hover:text-neutral-400 active:scale-[0.97] transition-colors"
|
|
254
254
|
title="New Folder"
|
|
255
255
|
aria-label="New Folder"
|
|
256
256
|
>
|
|
@@ -263,7 +263,7 @@ export const FileTree = memo(function FileTree({
|
|
|
263
263
|
<div
|
|
264
264
|
className={`flex-1 overflow-y-auto py-1 transition-colors ${
|
|
265
265
|
dragOverFolder === ""
|
|
266
|
-
? "bg-[#3CE6AC]/5 outline outline-1 outline-[#3CE6AC]/30 -outline-offset-1"
|
|
266
|
+
? "bg-[#3CE6AC]/5 outline-solid outline-1 outline-[#3CE6AC]/30 -outline-offset-1"
|
|
267
267
|
: ""
|
|
268
268
|
}`}
|
|
269
269
|
onContextMenu={handleRootContextMenu}
|
|
@@ -23,7 +23,7 @@ const W = "duotone" as const;
|
|
|
23
23
|
|
|
24
24
|
export function FileIcon({ path }: { path: string }) {
|
|
25
25
|
const ext = path.split(".").pop()?.toLowerCase() ?? "";
|
|
26
|
-
const c = "
|
|
26
|
+
const c = "shrink-0";
|
|
27
27
|
if (ext === "html") return <FileHtml size={SZ} weight={W} color="#E44D26" className={c} />;
|
|
28
28
|
if (ext === "css") return <FileCss size={SZ} weight={W} color="#264DE4" className={c} />;
|
|
29
29
|
if (ext === "js" || ext === "mjs" || ext === "cjs")
|
|
@@ -107,7 +107,7 @@ export function ContextMenu({
|
|
|
107
107
|
<>
|
|
108
108
|
<button
|
|
109
109
|
role="menuitem"
|
|
110
|
-
className="w-full flex items-center gap-2 px-3 py-1.5 text-xs text-neutral-300 hover:bg-neutral-800 focus-visible:bg-neutral-800 active:bg-neutral-700 outline-
|
|
110
|
+
className="w-full flex items-center gap-2 px-3 py-1.5 text-xs text-neutral-300 hover:bg-neutral-800 focus-visible:bg-neutral-800 active:bg-neutral-700 outline-hidden cursor-pointer text-left"
|
|
111
111
|
onClick={() => {
|
|
112
112
|
onNewFile(state.targetPath);
|
|
113
113
|
onClose();
|
|
@@ -118,7 +118,7 @@ export function ContextMenu({
|
|
|
118
118
|
</button>
|
|
119
119
|
<button
|
|
120
120
|
role="menuitem"
|
|
121
|
-
className="w-full flex items-center gap-2 px-3 py-1.5 text-xs text-neutral-300 hover:bg-neutral-800 focus-visible:bg-neutral-800 active:bg-neutral-700 outline-
|
|
121
|
+
className="w-full flex items-center gap-2 px-3 py-1.5 text-xs text-neutral-300 hover:bg-neutral-800 focus-visible:bg-neutral-800 active:bg-neutral-700 outline-hidden cursor-pointer text-left"
|
|
122
122
|
onClick={() => {
|
|
123
123
|
onNewFolder(state.targetPath);
|
|
124
124
|
onClose();
|
|
@@ -134,7 +134,7 @@ export function ContextMenu({
|
|
|
134
134
|
<>
|
|
135
135
|
<button
|
|
136
136
|
role="menuitem"
|
|
137
|
-
className="w-full flex items-center gap-2 px-3 py-1.5 text-xs text-neutral-300 hover:bg-neutral-800 focus-visible:bg-neutral-800 active:bg-neutral-700 outline-
|
|
137
|
+
className="w-full flex items-center gap-2 px-3 py-1.5 text-xs text-neutral-300 hover:bg-neutral-800 focus-visible:bg-neutral-800 active:bg-neutral-700 outline-hidden cursor-pointer text-left"
|
|
138
138
|
onClick={() => {
|
|
139
139
|
onNewFile(parentPath);
|
|
140
140
|
onClose();
|
|
@@ -148,7 +148,7 @@ export function ContextMenu({
|
|
|
148
148
|
)}
|
|
149
149
|
<button
|
|
150
150
|
role="menuitem"
|
|
151
|
-
className="w-full flex items-center gap-2 px-3 py-1.5 text-xs text-neutral-300 hover:bg-neutral-800 focus-visible:bg-neutral-800 active:bg-neutral-700 outline-
|
|
151
|
+
className="w-full flex items-center gap-2 px-3 py-1.5 text-xs text-neutral-300 hover:bg-neutral-800 focus-visible:bg-neutral-800 active:bg-neutral-700 outline-hidden cursor-pointer text-left"
|
|
152
152
|
onClick={() => {
|
|
153
153
|
onRename(state.targetPath);
|
|
154
154
|
onClose();
|
|
@@ -160,7 +160,7 @@ export function ContextMenu({
|
|
|
160
160
|
{!state.targetIsFolder && (
|
|
161
161
|
<button
|
|
162
162
|
role="menuitem"
|
|
163
|
-
className="w-full flex items-center gap-2 px-3 py-1.5 text-xs text-neutral-300 hover:bg-neutral-800 focus-visible:bg-neutral-800 active:bg-neutral-700 outline-
|
|
163
|
+
className="w-full flex items-center gap-2 px-3 py-1.5 text-xs text-neutral-300 hover:bg-neutral-800 focus-visible:bg-neutral-800 active:bg-neutral-700 outline-hidden cursor-pointer text-left"
|
|
164
164
|
onClick={() => {
|
|
165
165
|
onDuplicate(state.targetPath);
|
|
166
166
|
onClose();
|
|
@@ -173,7 +173,7 @@ export function ContextMenu({
|
|
|
173
173
|
<div className="border-t border-neutral-700 my-1" />
|
|
174
174
|
<button
|
|
175
175
|
role="menuitem"
|
|
176
|
-
className="w-full flex items-center gap-2 px-3 py-1.5 text-xs text-red-400 hover:bg-red-900/30 focus-visible:bg-red-900/30 active:bg-red-900/50 outline-
|
|
176
|
+
className="w-full flex items-center gap-2 px-3 py-1.5 text-xs text-red-400 hover:bg-red-900/30 focus-visible:bg-red-900/30 active:bg-red-900/50 outline-hidden cursor-pointer text-left"
|
|
177
177
|
onClick={() => {
|
|
178
178
|
onDelete(state.targetPath);
|
|
179
179
|
onClose();
|
|
@@ -263,7 +263,7 @@ export function InlineInput({
|
|
|
263
263
|
style={{ paddingLeft: `${8 + depth * 12 + (isFolder ? 0 : 14)}px` }}
|
|
264
264
|
>
|
|
265
265
|
{isFolder ? (
|
|
266
|
-
<FolderSimple size={SZ_ICON} weight="duotone" color="#6B7280" className="
|
|
266
|
+
<FolderSimple size={SZ_ICON} weight="duotone" color="#6B7280" className="shrink-0" />
|
|
267
267
|
) : (
|
|
268
268
|
<FileIcon path={value} />
|
|
269
269
|
)}
|
|
@@ -278,7 +278,7 @@ export function InlineInput({
|
|
|
278
278
|
onKeyDown={handleKeyDown}
|
|
279
279
|
onBlur={handleBlur}
|
|
280
280
|
aria-invalid={error ? true : undefined}
|
|
281
|
-
className={`w-full min-w-0 bg-neutral-800 text-neutral-200 text-xs px-1.5 py-0.5 rounded border outline-
|
|
281
|
+
className={`w-full min-w-0 bg-neutral-800 text-neutral-200 text-xs px-1.5 py-0.5 rounded border outline-hidden ${
|
|
282
282
|
error ? "border-red-500/70" : "border-neutral-600 focus:border-[#3CE6AC]"
|
|
283
283
|
}`}
|
|
284
284
|
spellCheck={false}
|
|
@@ -344,13 +344,13 @@ export function DeleteConfirm({
|
|
|
344
344
|
<div className="flex gap-1.5">
|
|
345
345
|
<button
|
|
346
346
|
onClick={onCancel}
|
|
347
|
-
className="flex-1 px-2 py-1 rounded bg-neutral-700 text-neutral-300 hover:bg-neutral-600 transition-colors"
|
|
347
|
+
className="flex-1 px-2 py-1 rounded-sm bg-neutral-700 text-neutral-300 hover:bg-neutral-600 transition-colors"
|
|
348
348
|
>
|
|
349
349
|
Cancel
|
|
350
350
|
</button>
|
|
351
351
|
<button
|
|
352
352
|
onClick={onConfirm}
|
|
353
|
-
className="flex-1 px-2 py-1 rounded bg-red-900/60 text-red-300 hover:bg-red-800/60 transition-colors"
|
|
353
|
+
className="flex-1 px-2 py-1 rounded-sm bg-red-900/60 text-red-300 hover:bg-red-800/60 transition-colors"
|
|
354
354
|
>
|
|
355
355
|
Delete
|
|
356
356
|
</button>
|
|
@@ -419,7 +419,7 @@ export const TreeFile = memo(function TreeFile({
|
|
|
419
419
|
<span className="truncate flex-1">{node.name}</span>
|
|
420
420
|
{lintInfo && lintInfo.count > 0 && (
|
|
421
421
|
<span
|
|
422
|
-
className="
|
|
422
|
+
className="shrink-0 min-w-[16px] rounded-full bg-amber-500/20 px-1 text-[8px] font-bold text-amber-400 text-center mr-1"
|
|
423
423
|
title={lintInfo.messages.join("\n")}
|
|
424
424
|
>
|
|
425
425
|
{lintInfo.count}
|
|
@@ -505,11 +505,11 @@ export const TreeFolder = memo(function TreeFolder({
|
|
|
505
505
|
}}
|
|
506
506
|
onDragLeave={onDragLeave}
|
|
507
507
|
className={`w-full flex items-center gap-1.5 px-2.5 py-1 min-h-7 text-left text-xs text-neutral-400 hover:bg-neutral-800/30 hover:text-neutral-300 transition-colors ${
|
|
508
|
-
isDragOver ? "bg-[#3CE6AC]/10 outline outline-1 outline-[#3CE6AC]/40" : ""
|
|
508
|
+
isDragOver ? "bg-[#3CE6AC]/10 outline-solid outline-1 outline-[#3CE6AC]/40" : ""
|
|
509
509
|
}`}
|
|
510
510
|
style={{ paddingLeft: `${8 + depth * 12}px` }}
|
|
511
511
|
>
|
|
512
|
-
<Chevron size={10} className="
|
|
512
|
+
<Chevron size={10} className="shrink-0 text-neutral-600" />
|
|
513
513
|
<span className="truncate font-medium">{node.name}</span>
|
|
514
514
|
</button>
|
|
515
515
|
{isOpen && (
|
|
@@ -77,7 +77,7 @@ export function InlineTextToolbar({
|
|
|
77
77
|
data-inline-text-toolbar="true"
|
|
78
78
|
role="toolbar"
|
|
79
79
|
aria-label="Text formatting"
|
|
80
|
-
className="pointer-events-auto fixed z-
|
|
80
|
+
className="pointer-events-auto fixed z-200 flex items-center gap-1 rounded-lg border border-white/10 bg-[#15171c] p-1 shadow-[0_8px_24px_rgba(0,0,0,0.55)]"
|
|
81
81
|
style={{
|
|
82
82
|
left: placement.left,
|
|
83
83
|
top: placement.top,
|
|
@@ -37,7 +37,7 @@ export function InspectorHeaderActions({
|
|
|
37
37
|
track("toggle", "Element visibility");
|
|
38
38
|
void onToggleHidden(selectedElementId, !selectedElementHidden);
|
|
39
39
|
}}
|
|
40
|
-
className="flex h-6 w-6 items-center justify-center rounded text-neutral-500 transition-colors hover:bg-neutral-800 hover:text-neutral-300"
|
|
40
|
+
className="flex h-6 w-6 items-center justify-center rounded-sm text-neutral-500 transition-colors hover:bg-neutral-800 hover:text-neutral-300"
|
|
41
41
|
>
|
|
42
42
|
{selectedElementHidden ? (
|
|
43
43
|
<EyeSlash size={13} weight="bold" aria-hidden="true" />
|
|
@@ -54,7 +54,7 @@ export function InspectorHeaderActions({
|
|
|
54
54
|
onUngroup();
|
|
55
55
|
}}
|
|
56
56
|
title="Ungroup (⌘⇧G)"
|
|
57
|
-
className="flex h-6 items-center rounded px-2 text-[11px] font-medium text-neutral-400 transition-colors hover:bg-neutral-800 hover:text-neutral-200"
|
|
57
|
+
className="flex h-6 items-center rounded-sm px-2 text-[11px] font-medium text-neutral-400 transition-colors hover:bg-neutral-800 hover:text-neutral-200"
|
|
58
58
|
>
|
|
59
59
|
Ungroup
|
|
60
60
|
</button>
|
|
@@ -91,7 +91,7 @@ export function InspectorHeaderActions({
|
|
|
91
91
|
track("button", "Clear selection");
|
|
92
92
|
onClear();
|
|
93
93
|
}}
|
|
94
|
-
className="flex h-6 w-6 items-center justify-center rounded text-neutral-500 transition-colors hover:bg-neutral-800 hover:text-neutral-300"
|
|
94
|
+
className="flex h-6 w-6 items-center justify-center rounded-sm text-neutral-500 transition-colors hover:bg-neutral-800 hover:text-neutral-300"
|
|
95
95
|
>
|
|
96
96
|
<X size={13} />
|
|
97
97
|
</button>
|
|
@@ -29,7 +29,7 @@ export const KeyframeDiamond = memo(function KeyframeDiamond({
|
|
|
29
29
|
e.stopPropagation();
|
|
30
30
|
onClick();
|
|
31
31
|
}}
|
|
32
|
-
className="relative
|
|
32
|
+
className="relative shrink-0 p-0.5 transition-opacity hover:opacity-100 before:absolute before:-inset-1.5 before:content-['']"
|
|
33
33
|
style={{ color, opacity }}
|
|
34
34
|
title={title}
|
|
35
35
|
aria-label={title}
|
|
@@ -74,7 +74,7 @@ export function KeyframeEaseList({
|
|
|
74
74
|
const next = e.target.value;
|
|
75
75
|
if (next) onApplyAll(next);
|
|
76
76
|
}}
|
|
77
|
-
className="ml-auto cursor-pointer rounded bg-neutral-800 px-1.5 py-0.5 text-[9px] text-neutral-300 outline-
|
|
77
|
+
className="ml-auto cursor-pointer rounded-sm bg-neutral-800 px-1.5 py-0.5 text-[9px] text-neutral-300 outline-hidden hover:bg-neutral-700 focus:ring-1 focus:ring-panel-accent/40"
|
|
78
78
|
>
|
|
79
79
|
<option value="" disabled>
|
|
80
80
|
Set all…
|
|
@@ -485,7 +485,7 @@ export const LayersPanel = memo(function LayersPanel() {
|
|
|
485
485
|
onClick={(e) => toggleCollapse(layer.key, e)}
|
|
486
486
|
aria-expanded={!isCollapsed}
|
|
487
487
|
aria-label={isCollapsed ? "Expand children" : "Collapse children"}
|
|
488
|
-
className="relative flex h-4 w-4
|
|
488
|
+
className="relative flex h-4 w-4 shrink-0 items-center justify-center rounded-sm text-neutral-500 hover:text-neutral-300 before:absolute before:-inset-1.5 before:content-['']"
|
|
489
489
|
>
|
|
490
490
|
<svg
|
|
491
491
|
width="8"
|
|
@@ -498,10 +498,10 @@ export const LayersPanel = memo(function LayersPanel() {
|
|
|
498
498
|
</svg>
|
|
499
499
|
</button>
|
|
500
500
|
) : (
|
|
501
|
-
<span className="w-4
|
|
501
|
+
<span className="w-4 shrink-0" />
|
|
502
502
|
)}
|
|
503
503
|
<span
|
|
504
|
-
className={`flex h-5 w-5
|
|
504
|
+
className={`flex h-5 w-5 shrink-0 items-center justify-center rounded text-[8px] font-bold uppercase ${
|
|
505
505
|
selected
|
|
506
506
|
? "bg-panel-accent/18 text-panel-accent"
|
|
507
507
|
: isCompHost
|
|
@@ -19,7 +19,7 @@ export function MarqueeOverlay({ candidateRects, marqueeRect }: MarqueeOverlayPr
|
|
|
19
19
|
<div
|
|
20
20
|
key={i}
|
|
21
21
|
aria-hidden="true"
|
|
22
|
-
className="pointer-events-none absolute rounded-
|
|
22
|
+
className="pointer-events-none absolute rounded-xs border border-studio-accent bg-studio-accent/5"
|
|
23
23
|
style={{ left: r.left, top: r.top, width: r.width, height: r.height }}
|
|
24
24
|
/>
|
|
25
25
|
))}
|
|
@@ -167,7 +167,7 @@ export function ChildRectOutlines({
|
|
|
167
167
|
{rects.map((rect, index) => (
|
|
168
168
|
<div
|
|
169
169
|
key={index}
|
|
170
|
-
className="pointer-events-none absolute border border-dashed border-white/20 rounded-
|
|
170
|
+
className="pointer-events-none absolute border border-dashed border-white/20 rounded-xs"
|
|
171
171
|
style={{
|
|
172
172
|
left: rect.left,
|
|
173
173
|
top: rect.top,
|