@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,52 @@
|
|
|
1
|
+
/** Plain-field clip facts from the player store; feeds the Ask-agent prompt and `studio_look`. */
|
|
2
|
+
import type { TimelineElement } from "../store/playerStore";
|
|
3
|
+
import { elementAutomationLanes } from "../components/automationLaneData";
|
|
4
|
+
import { byStart, formatClipLine, type ClipFact } from "@hyperframes/core/clip-facts";
|
|
5
|
+
export { byStart } from "@hyperframes/core/clip-facts";
|
|
6
|
+
export type { ClipFact } from "@hyperframes/core/clip-facts";
|
|
7
|
+
|
|
8
|
+
/** The store holds preview URLs; the agent edits project files, so drop the origin and preview prefix. */
|
|
9
|
+
function projectRelativeSrc(src: string): string {
|
|
10
|
+
return src.replace(/^https?:\/\/[^/]+/, "").replace(/^\/api\/projects\/[^/]+\/preview\//, "");
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function describeClip(element: TimelineElement): ClipFact {
|
|
14
|
+
return {
|
|
15
|
+
id: element.domId ?? element.id,
|
|
16
|
+
label: element.label ?? null,
|
|
17
|
+
kind: element.kind ?? element.tag.toLowerCase(),
|
|
18
|
+
start: element.start,
|
|
19
|
+
duration: element.duration,
|
|
20
|
+
end: element.start + element.duration,
|
|
21
|
+
trackIndex: element.authoredTrack ?? element.track,
|
|
22
|
+
src: element.src ? projectRelativeSrc(element.src) : null,
|
|
23
|
+
sourceFile: element.sourceFile ?? null,
|
|
24
|
+
volume: element.volume ?? null,
|
|
25
|
+
lanes: elementAutomationLanes(element).map((lane) => ({
|
|
26
|
+
target: lane.target,
|
|
27
|
+
points: lane.points.map(({ t, v }) => ({ t, v })),
|
|
28
|
+
})),
|
|
29
|
+
playbackRate: element.playbackRate === 1 ? null : (element.playbackRate ?? null),
|
|
30
|
+
audioGroup: element.audioGroup ?? null,
|
|
31
|
+
role: element.timelineRole ?? null,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function describeClips(elements: readonly TimelineElement[]): ClipFact[] {
|
|
36
|
+
return elements.map(describeClip).sort(byStart);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const PROMPT_CLIP_CAP = 200;
|
|
40
|
+
|
|
41
|
+
/** The Ask-agent prompt's Timeline block; empty when the timeline has no clips. */
|
|
42
|
+
export function formatTimelineBlock(elements: readonly TimelineElement[]): string {
|
|
43
|
+
const clips = describeClips(elements);
|
|
44
|
+
if (clips.length === 0) return "";
|
|
45
|
+
const shown = clips.slice(0, PROMPT_CLIP_CAP).map(formatClipLine);
|
|
46
|
+
const more = clips.length - shown.length;
|
|
47
|
+
return [
|
|
48
|
+
"Timeline (composition seconds; lane points are seconds from the clip start):",
|
|
49
|
+
...shown,
|
|
50
|
+
...(more > 0 ? [`(${more} more clips not listed)`] : []),
|
|
51
|
+
].join("\n");
|
|
52
|
+
}
|
|
@@ -3,7 +3,6 @@ import { describe, expect, it } from "vitest";
|
|
|
3
3
|
import {
|
|
4
4
|
createTimelineElementFromManifestClip,
|
|
5
5
|
parseTimelineFromDOM,
|
|
6
|
-
createImplicitTimelineLayersFromDOM,
|
|
7
6
|
mergeTimelineElementsPreservingDowngrades,
|
|
8
7
|
} from "./timelineDOM";
|
|
9
8
|
import { isTimelineIgnoredElement } from "./timelineElementHelpers";
|
|
@@ -302,19 +301,6 @@ describe("createTimelineElementFromManifestClip — source-scoped selector ident
|
|
|
302
301
|
// implicit-layer fallback happily gave it a track. Draggable and trimmable, and
|
|
303
302
|
// writing timing onto a bus means nothing.
|
|
304
303
|
describe("<hf-audio-group> is not a timeline layer", () => {
|
|
305
|
-
it("gets no implicit row of its own", () => {
|
|
306
|
-
const doc = makeDoc(`
|
|
307
|
-
<div data-composition-id="root">
|
|
308
|
-
<audio id="voice-1" data-start="0" data-duration="6" data-audio-group="voiceover"></audio>
|
|
309
|
-
<hf-audio-group id="voiceover" data-label="Voiceover"></hf-audio-group>
|
|
310
|
-
</div>
|
|
311
|
-
`);
|
|
312
|
-
|
|
313
|
-
const implicit = createImplicitTimelineLayersFromDOM(doc, 12, []);
|
|
314
|
-
|
|
315
|
-
expect(implicit.map((el) => el.domId)).not.toContain("voiceover");
|
|
316
|
-
});
|
|
317
|
-
|
|
318
304
|
it("is excluded by the shared ignore predicate", () => {
|
|
319
305
|
const doc = makeDoc(`<hf-audio-group id="vo"></hf-audio-group><div id="panel"></div>`);
|
|
320
306
|
expect(isTimelineIgnoredElement(doc.getElementById("vo") as Element)).toBe(true);
|
|
@@ -322,72 +308,6 @@ describe("<hf-audio-group> is not a timeline layer", () => {
|
|
|
322
308
|
});
|
|
323
309
|
});
|
|
324
310
|
|
|
325
|
-
describe("createImplicitTimelineLayersFromDOM — hfId from data-hf-id", () => {
|
|
326
|
-
it("uses the runtime root paint scope for implicit siblings of manifest clips", () => {
|
|
327
|
-
const doc = makeDoc(`
|
|
328
|
-
<div data-composition-id="root">
|
|
329
|
-
<div id="timed" data-start="0" data-duration="5"></div>
|
|
330
|
-
<div id="implicit"></div>
|
|
331
|
-
</div>
|
|
332
|
-
`);
|
|
333
|
-
const timedHost = doc.getElementById("timed");
|
|
334
|
-
const timed = createTimelineElementFromManifestClip({
|
|
335
|
-
clip: {
|
|
336
|
-
id: "timed",
|
|
337
|
-
label: "Timed",
|
|
338
|
-
start: 0,
|
|
339
|
-
duration: 5,
|
|
340
|
-
track: 0,
|
|
341
|
-
stackingContextId: "css:root",
|
|
342
|
-
kind: "element",
|
|
343
|
-
tagName: "div",
|
|
344
|
-
compositionId: null,
|
|
345
|
-
parentCompositionId: null,
|
|
346
|
-
compositionSrc: null,
|
|
347
|
-
assetUrl: null,
|
|
348
|
-
},
|
|
349
|
-
fallbackIndex: 0,
|
|
350
|
-
doc,
|
|
351
|
-
hostEl: timedHost,
|
|
352
|
-
});
|
|
353
|
-
const implicit = createImplicitTimelineLayersFromDOM(doc, 5, [timed])[0];
|
|
354
|
-
|
|
355
|
-
expect(implicit?.stackingContextId).toBe("css:root");
|
|
356
|
-
expect(implicit?.stackingContextId).toBe(timed.stackingContextId);
|
|
357
|
-
});
|
|
358
|
-
|
|
359
|
-
it("harvests hfId from an implicit layer child that has data-hf-id", () => {
|
|
360
|
-
const doc = makeDoc(`
|
|
361
|
-
<div data-composition-id="root">
|
|
362
|
-
<div id="layer" class="clip" data-hf-id="hf-xyz789"></div>
|
|
363
|
-
</div>
|
|
364
|
-
`);
|
|
365
|
-
|
|
366
|
-
const layers = createImplicitTimelineLayersFromDOM(doc, 10);
|
|
367
|
-
const layer = layers.find((el) => el.domId === "layer");
|
|
368
|
-
|
|
369
|
-
expect(layer).toBeDefined();
|
|
370
|
-
expect(layer?.hfId).toBe("hf-xyz789");
|
|
371
|
-
});
|
|
372
|
-
|
|
373
|
-
it("ignores runtime-owned color grading canvases as implicit layers", () => {
|
|
374
|
-
const doc = makeDoc(`
|
|
375
|
-
<div data-composition-id="root" data-duration="5">
|
|
376
|
-
<img id="photo" class="clip" data-start="0" data-duration="5" />
|
|
377
|
-
<canvas
|
|
378
|
-
class="__hf_color_grading_canvas__"
|
|
379
|
-
data-hf-color-grading-canvas="true"
|
|
380
|
-
data-hyperframes-ignore
|
|
381
|
-
></canvas>
|
|
382
|
-
</div>
|
|
383
|
-
`);
|
|
384
|
-
|
|
385
|
-
const layers = createImplicitTimelineLayersFromDOM(doc, 5);
|
|
386
|
-
|
|
387
|
-
expect(layers).toEqual([]);
|
|
388
|
-
});
|
|
389
|
-
});
|
|
390
|
-
|
|
391
311
|
describe("mergeTimelineElementsPreservingDowngrades — genuine removal vs transient downgrade", () => {
|
|
392
312
|
it("drops a removed TOP-LEVEL element (undo of a split) instead of ghosting it", () => {
|
|
393
313
|
const current = [el("a"), el("a-split")]; // post-split store: original + clone
|
|
@@ -17,8 +17,6 @@ import {
|
|
|
17
17
|
resolveMediaElement,
|
|
18
18
|
applyMediaMetadataFromElement,
|
|
19
19
|
getTimelineElementDisplayLabel,
|
|
20
|
-
getImplicitTimelineLayerLabel,
|
|
21
|
-
isImplicitTimelineLayerCandidate,
|
|
22
20
|
getTimelineElementSelector,
|
|
23
21
|
getTimelineElementSourceFile,
|
|
24
22
|
getTimelineElementSelectorIndex,
|
|
@@ -203,63 +201,6 @@ export function createTimelineElementFromManifestClip(params: {
|
|
|
203
201
|
return entry;
|
|
204
202
|
}
|
|
205
203
|
|
|
206
|
-
export function createImplicitTimelineLayersFromDOM(
|
|
207
|
-
doc: Document,
|
|
208
|
-
rootDuration: number,
|
|
209
|
-
existingElements: readonly TimelineElement[] = [],
|
|
210
|
-
): TimelineElement[] {
|
|
211
|
-
if (!Number.isFinite(rootDuration) || rootDuration <= 0) return [];
|
|
212
|
-
const rootComp = doc.querySelector("[data-composition-id]");
|
|
213
|
-
if (!rootComp) return [];
|
|
214
|
-
|
|
215
|
-
const existingKeys = new Set(existingElements.map(getTimelineElementIdentity));
|
|
216
|
-
const maxTrack = existingElements.reduce(
|
|
217
|
-
(max, element) => Math.max(max, Number.isFinite(element.track) ? element.track : 0),
|
|
218
|
-
-1,
|
|
219
|
-
);
|
|
220
|
-
const layers: TimelineElement[] = [];
|
|
221
|
-
|
|
222
|
-
for (const child of Array.from(rootComp.children)) {
|
|
223
|
-
if (!isImplicitTimelineLayerCandidate(rootComp, child)) continue;
|
|
224
|
-
|
|
225
|
-
const selector = getTimelineElementSelector(child);
|
|
226
|
-
if (!selector) continue;
|
|
227
|
-
const selectorIndex = getTimelineElementSelectorIndex(doc, child, selector);
|
|
228
|
-
const sourceFile = getTimelineElementSourceFile(child);
|
|
229
|
-
const label = getImplicitTimelineLayerLabel(child);
|
|
230
|
-
const identity = buildTimelineElementIdentity({
|
|
231
|
-
preferredId: child.id || null,
|
|
232
|
-
label,
|
|
233
|
-
fallbackIndex: existingElements.length + layers.length,
|
|
234
|
-
domId: child.id || undefined,
|
|
235
|
-
selector,
|
|
236
|
-
selectorIndex,
|
|
237
|
-
sourceFile,
|
|
238
|
-
});
|
|
239
|
-
if (existingKeys.has(identity.key) || existingKeys.has(identity.id)) continue;
|
|
240
|
-
|
|
241
|
-
layers.push({
|
|
242
|
-
domId: child.id || undefined,
|
|
243
|
-
hfId: child.getAttribute("data-hf-id") || undefined,
|
|
244
|
-
zIndex: readTimelineElementZIndex(child),
|
|
245
|
-
duration: rootDuration,
|
|
246
|
-
id: identity.id,
|
|
247
|
-
key: identity.key,
|
|
248
|
-
label,
|
|
249
|
-
selector,
|
|
250
|
-
selectorIndex,
|
|
251
|
-
sourceFile,
|
|
252
|
-
stackingContextId: resolveCssStackingContextId(child),
|
|
253
|
-
start: 0,
|
|
254
|
-
tag: child.tagName.toLowerCase(),
|
|
255
|
-
timingSource: "implicit",
|
|
256
|
-
track: maxTrack + 1 + layers.length,
|
|
257
|
-
});
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
return layers;
|
|
261
|
-
}
|
|
262
|
-
|
|
263
204
|
/**
|
|
264
205
|
* Parse [data-start] elements from a Document into TimelineElement[].
|
|
265
206
|
* Shared helper — used by onIframeLoad fallback, handleMessage, and enrichMissingCompositions.
|
|
@@ -330,7 +271,6 @@ export function parseTimelineFromDOM(doc: Document, rootDuration: number): Timel
|
|
|
330
271
|
selectorIndex,
|
|
331
272
|
sourceFile,
|
|
332
273
|
stackingContextId: resolveCssStackingContextId(el),
|
|
333
|
-
timingSource: "authored",
|
|
334
274
|
zIndex: readTimelineElementZIndex(el),
|
|
335
275
|
};
|
|
336
276
|
|
|
@@ -399,7 +339,7 @@ export function parseTimelineFromDOM(doc: Document, rootDuration: number): Timel
|
|
|
399
339
|
els.push(entry);
|
|
400
340
|
});
|
|
401
341
|
|
|
402
|
-
return
|
|
342
|
+
return els;
|
|
403
343
|
}
|
|
404
344
|
|
|
405
345
|
// ---------------------------------------------------------------------------
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Low-level helpers for building and identifying TimelineElement objects.
|
|
3
3
|
*
|
|
4
4
|
* Covers: duration reading, media-element metadata extraction, selector/key/
|
|
5
|
-
* identity builders, DOM node lookup
|
|
5
|
+
* identity builders, and DOM node lookup. These are
|
|
6
6
|
* intentionally dependency-free (no store, no hooks) so they can be used in
|
|
7
7
|
* both the React hook and test environments.
|
|
8
8
|
*/
|
|
@@ -82,13 +82,7 @@ function normalizePlaybackRate(raw: number): number {
|
|
|
82
82
|
}
|
|
83
83
|
|
|
84
84
|
export function isTimelineIgnoredElement(el: Element): boolean {
|
|
85
|
-
// An `<hf-audio-group>` is a mixer bus,
|
|
86
|
-
// label, fader, mute and FX chain, has no timing of its own, and is drawn as
|
|
87
|
-
// a GROUP ROW by the group derivation. Left in, the implicit-layer fallback
|
|
88
|
-
// also gave it an ordinary full-duration track — so a grouped composition
|
|
89
|
-
// showed "Voiceover • 0.0s – 12.0s" as a phantom clip directly above the real
|
|
90
|
-
// group header. Harmless-looking, but that row is draggable and trimmable,
|
|
91
|
-
// and writing timing onto the bus is meaningless.
|
|
85
|
+
// An `<hf-audio-group>` is a mixer bus with no timing of its own, drawn as a group row, never a clip.
|
|
92
86
|
if (el.tagName.toLowerCase() === HF_AUDIO_GROUP_TAG) return true;
|
|
93
87
|
return Boolean(
|
|
94
88
|
el.closest(
|
|
@@ -223,37 +217,6 @@ export function getTimelineElementDisplayLabel(input: {
|
|
|
223
217
|
return tag ? `${tag} clip` : "Timeline clip";
|
|
224
218
|
}
|
|
225
219
|
|
|
226
|
-
const IMPLICIT_TIMELINE_LAYER_SKIP_TAGS = new Set([
|
|
227
|
-
"base",
|
|
228
|
-
"link",
|
|
229
|
-
"meta",
|
|
230
|
-
"noscript",
|
|
231
|
-
"script",
|
|
232
|
-
"style",
|
|
233
|
-
"template",
|
|
234
|
-
]);
|
|
235
|
-
|
|
236
|
-
function humanizeTimelineIdentifier(value: string): string {
|
|
237
|
-
return value
|
|
238
|
-
.trim()
|
|
239
|
-
.replace(/[_-]+/g, " ")
|
|
240
|
-
.replace(/\s+/g, " ")
|
|
241
|
-
.replace(/\b\w/g, (match) => match.toUpperCase());
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
export function getImplicitTimelineLayerLabel(el: HTMLElement): string {
|
|
245
|
-
const explicitLabel =
|
|
246
|
-
el.getAttribute("data-timeline-label") ??
|
|
247
|
-
el.getAttribute("data-label") ??
|
|
248
|
-
el.getAttribute("aria-label");
|
|
249
|
-
if (explicitLabel?.trim()) return explicitLabel.trim();
|
|
250
|
-
if (el.id.trim()) return humanizeTimelineIdentifier(el.id);
|
|
251
|
-
const classes = el.className.split(/\s+/).filter(Boolean);
|
|
252
|
-
const className = classes.find((value) => value !== "clip") ?? classes[0];
|
|
253
|
-
if (className) return humanizeTimelineIdentifier(className);
|
|
254
|
-
return getTimelineElementDisplayLabel({ tag: el.tagName });
|
|
255
|
-
}
|
|
256
|
-
|
|
257
220
|
// ---------------------------------------------------------------------------
|
|
258
221
|
// Selector / identity / key builders
|
|
259
222
|
// ---------------------------------------------------------------------------
|
|
@@ -475,17 +438,3 @@ export function createTimelineDomNodeResolver(doc: Document) {
|
|
|
475
438
|
return node;
|
|
476
439
|
};
|
|
477
440
|
}
|
|
478
|
-
|
|
479
|
-
// ---------------------------------------------------------------------------
|
|
480
|
-
// Implicit layer detection
|
|
481
|
-
// ---------------------------------------------------------------------------
|
|
482
|
-
|
|
483
|
-
export function isImplicitTimelineLayerCandidate(root: Element, el: Element): el is HTMLElement {
|
|
484
|
-
if (!isHtmlElement(el)) return false;
|
|
485
|
-
if (isTimelineIgnoredElement(el)) return false;
|
|
486
|
-
if (el.parentElement !== root) return false;
|
|
487
|
-
const tagName = el.tagName.toLowerCase();
|
|
488
|
-
if (IMPLICIT_TIMELINE_LAYER_SKIP_TAGS.has(tagName)) return false;
|
|
489
|
-
if (el.hasAttribute("data-start") || el.hasAttribute("data-track-index")) return false;
|
|
490
|
-
return Boolean(getTimelineElementSelector(el));
|
|
491
|
-
}
|
|
@@ -200,6 +200,8 @@ interface PlayerState extends PlayerStoreSlices {
|
|
|
200
200
|
clipManifest: ClipManifestClip[] | null;
|
|
201
201
|
setClipManifest: (clips: ClipManifestClip[] | null) => void;
|
|
202
202
|
clipParentMap: Map<string, string>;
|
|
203
|
+
topLevelIds: ReadonlySet<string> | null;
|
|
204
|
+
setTopLevelIds: (ids: ReadonlySet<string> | null) => void;
|
|
203
205
|
setClipParentMap: (map: Map<string, string>) => void;
|
|
204
206
|
/**
|
|
205
207
|
* Sub-composition DOM descendants (groups + their children) that have no
|
|
@@ -288,6 +290,7 @@ export function createTimelineResetState() {
|
|
|
288
290
|
beatPersist: null,
|
|
289
291
|
clipManifest: null,
|
|
290
292
|
clipParentMap: new Map<string, string>(),
|
|
293
|
+
topLevelIds: null,
|
|
291
294
|
domClipChildren: [],
|
|
292
295
|
subCompositionHostState: new Map<string, SubCompositionHostState>(),
|
|
293
296
|
};
|
|
@@ -434,6 +437,8 @@ export const usePlayerStore = create<PlayerState>((set, get) => ({
|
|
|
434
437
|
setClipManifest: (clips) => set({ clipManifest: clips }),
|
|
435
438
|
clipParentMap: new Map(),
|
|
436
439
|
setClipParentMap: (map) => set({ clipParentMap: map }),
|
|
440
|
+
topLevelIds: null,
|
|
441
|
+
setTopLevelIds: (ids) => set({ topLevelIds: ids }),
|
|
437
442
|
domClipChildren: [],
|
|
438
443
|
setDomClipChildren: (children) => set({ domClipChildren: children }),
|
|
439
444
|
subCompositionHostState: new Map(),
|
|
@@ -59,8 +59,6 @@ export interface TimelineElement {
|
|
|
59
59
|
automation?: string;
|
|
60
60
|
/** Path from data-composition-src — identifies sub-composition elements */
|
|
61
61
|
compositionSrc?: string;
|
|
62
|
-
/** Whether this row came from authored clip timing or Studio's full-duration layer fallback. */
|
|
63
|
-
timingSource?: "authored" | "implicit";
|
|
64
62
|
/** Set by data-timeline-locked on the host element — disables move and trim in Studio. */
|
|
65
63
|
timelineLocked?: boolean;
|
|
66
64
|
/** Set by data-hidden on the host element — hides the clip in preview and render. */
|
|
@@ -79,7 +77,7 @@ export interface TimelineElement {
|
|
|
79
77
|
audioGroupFxChain?: string;
|
|
80
78
|
audioGroupAutomation?: string;
|
|
81
79
|
/**
|
|
82
|
-
* Set by
|
|
80
|
+
* Set by useTimelineRowElements on an inline-expanded sub-composition
|
|
83
81
|
* child: the absolute master-timeline start of the sub-comp host the child
|
|
84
82
|
* lives in. Presence marks the element as expanded; edits subtract it to get
|
|
85
83
|
* the child's local (sourceFile-relative) time. Works at any nesting depth.
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser stub for the Node-only `canvas` package.
|
|
3
|
+
*
|
|
4
|
+
* linkedom's `HTMLCanvasElement` constructor calls `createCanvas(300, 150)`
|
|
5
|
+
* (300x150 being the HTML canvas default size). linkedom guards that import in
|
|
6
|
+
* a try/catch: the try requires the native `canvas` package, and the catch
|
|
7
|
+
* falls back to linkedom's own bundled canvas shim.
|
|
8
|
+
*
|
|
9
|
+
* That guard only works with a *runtime* require. Vite resolves the specifier
|
|
10
|
+
* statically, so the bundled form is a plain assignment that cannot throw, the
|
|
11
|
+
* catch never runs, and `createCanvas` lands `undefined`. Parsing any `<canvas>`
|
|
12
|
+
* tag then throws inside `openComposition`, Studio loses its SDK session for the
|
|
13
|
+
* whole composition, and every edit silently falls back to the server path — the
|
|
14
|
+
* resolver shadow does not run either, so it was invisible until
|
|
15
|
+
* `studio:sdk_session_unavailable` shipped in v0.8.47.
|
|
16
|
+
*
|
|
17
|
+
* Production telemetry over the 72h after the flip: 1065 of 1544 session-open
|
|
18
|
+
* failures were this crash, across a large share of 197 users. Canvas is common
|
|
19
|
+
* in compositions (Three.js, shaders, particle effects, charts).
|
|
20
|
+
*
|
|
21
|
+
* Aliasing `canvas` to this file makes the browser build resolve to a
|
|
22
|
+
* measurement-only canvas, which is all linkedom's static parse needs — nothing
|
|
23
|
+
* in the SDK rasterizes through it. It mirrors linkedom's own
|
|
24
|
+
* `commonjs/canvas-shim.cjs`, reimplemented here because linkedom's `exports`
|
|
25
|
+
* map does not expose that file.
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
class BrowserCanvasStub {
|
|
29
|
+
constructor(width, height) {
|
|
30
|
+
this.width = width;
|
|
31
|
+
this.height = height;
|
|
32
|
+
}
|
|
33
|
+
/** linkedom only ever needs the element to exist; nothing draws through it. */
|
|
34
|
+
getContext() {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
toDataURL() {
|
|
38
|
+
return "";
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function createCanvas(width, height) {
|
|
43
|
+
return new BrowserCanvasStub(width, height);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// linkedom consumes this as a DEFAULT import — `import Canvas from
|
|
47
|
+
// '../../commonjs/canvas.cjs'` then `const {createCanvas} = Canvas` — so the
|
|
48
|
+
// default export is the load-bearing one; the named export above is interop
|
|
49
|
+
// belt-and-braces.
|
|
50
|
+
export default { createCanvas };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { IconWeight } from "@phosphor-icons/react";
|
|
2
|
+
|
|
3
|
+
const WEIGHTS = ["thin", "light", "regular", "bold", "fill", "duotone"] as const;
|
|
4
|
+
|
|
5
|
+
function asWeight(value: string): IconWeight | null {
|
|
6
|
+
return (WEIGHTS as readonly string[]).includes(value) ? (value as IconWeight) : null;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/** Studio's Phosphor defaults, read off `theme.css` so size and weight have one
|
|
10
|
+
* owner instead of a CSS variable and a JS constant that drift. A missing or
|
|
11
|
+
* unrecognized value falls back to Phosphor's own default. */
|
|
12
|
+
export function readIconTokens(root: Element = document.documentElement): {
|
|
13
|
+
size: string;
|
|
14
|
+
weight: IconWeight;
|
|
15
|
+
} {
|
|
16
|
+
const styles = getComputedStyle(root);
|
|
17
|
+
const size = styles.getPropertyValue("--icon-size").trim();
|
|
18
|
+
const weight = asWeight(styles.getPropertyValue("--icon-weight").trim());
|
|
19
|
+
return { size: size || "1em", weight: weight ?? "regular" };
|
|
20
|
+
}
|
package/src/styles/studio.css
CHANGED
|
@@ -1,6 +1,19 @@
|
|
|
1
|
-
@
|
|
2
|
-
@
|
|
3
|
-
@
|
|
1
|
+
@import "tailwindcss" source(none);
|
|
2
|
+
@import "./palette-reset.css";
|
|
3
|
+
@import "./theme.css";
|
|
4
|
+
|
|
5
|
+
/* Explicit sources: Studio's own TypeScript and its shell HTML. Automatic
|
|
6
|
+
* detection would walk up to the repo root and scan `data/projects`, gitignored user content. */
|
|
7
|
+
@source "../**/*.{ts,tsx}";
|
|
8
|
+
@source "../../index.html";
|
|
9
|
+
|
|
10
|
+
/* Tailwind v4 preflight no longer gives enabled buttons a pointer cursor. */
|
|
11
|
+
@layer base {
|
|
12
|
+
button:not(:disabled),
|
|
13
|
+
[role="button"]:not(:disabled) {
|
|
14
|
+
cursor: pointer;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
4
17
|
|
|
5
18
|
/*
|
|
6
19
|
* Studio is a dark-only UI — pin the user-agent color scheme to dark so that
|
|
@@ -14,9 +27,9 @@
|
|
|
14
27
|
body {
|
|
15
28
|
margin: 0;
|
|
16
29
|
padding: 0;
|
|
17
|
-
background:
|
|
18
|
-
color:
|
|
19
|
-
font-family: -
|
|
30
|
+
background: var(--color-bg-0);
|
|
31
|
+
color: var(--color-text-body);
|
|
32
|
+
font-family: var(--font-sans);
|
|
20
33
|
overflow: hidden;
|
|
21
34
|
}
|
|
22
35
|
|
|
@@ -290,7 +303,7 @@ body {
|
|
|
290
303
|
left: 12px;
|
|
291
304
|
overflow: hidden;
|
|
292
305
|
color: rgba(255, 255, 255, 0.34);
|
|
293
|
-
font-family:
|
|
306
|
+
font-family: var(--font-mono);
|
|
294
307
|
font-size: 9px;
|
|
295
308
|
font-variant-numeric: tabular-nums;
|
|
296
309
|
line-height: 1;
|
|
@@ -328,7 +341,7 @@ body {
|
|
|
328
341
|
}
|
|
329
342
|
|
|
330
343
|
.cm-editor .cm-scroller {
|
|
331
|
-
font-family:
|
|
344
|
+
font-family: var(--font-mono);
|
|
332
345
|
}
|
|
333
346
|
|
|
334
347
|
.cm-editor.cm-focused {
|
|
@@ -385,12 +398,7 @@ body {
|
|
|
385
398
|
}
|
|
386
399
|
|
|
387
400
|
.hf-loader-title {
|
|
388
|
-
font-family:
|
|
389
|
-
Inter,
|
|
390
|
-
-apple-system,
|
|
391
|
-
BlinkMacSystemFont,
|
|
392
|
-
"Segoe UI",
|
|
393
|
-
sans-serif;
|
|
401
|
+
font-family: var(--font-sans);
|
|
394
402
|
font-size: 1rem;
|
|
395
403
|
font-weight: 600;
|
|
396
404
|
letter-spacing: 0;
|
|
@@ -406,12 +414,7 @@ body {
|
|
|
406
414
|
min-height: 2.5rem;
|
|
407
415
|
overflow: hidden;
|
|
408
416
|
color: var(--hf-text-secondary, rgba(244, 244, 245, 0.68));
|
|
409
|
-
font-family:
|
|
410
|
-
Inter,
|
|
411
|
-
-apple-system,
|
|
412
|
-
BlinkMacSystemFont,
|
|
413
|
-
"Segoe UI",
|
|
414
|
-
sans-serif;
|
|
417
|
+
font-family: var(--font-sans);
|
|
415
418
|
font-size: 0.82rem;
|
|
416
419
|
line-height: 1.6;
|
|
417
420
|
}
|
|
@@ -423,7 +426,7 @@ body {
|
|
|
423
426
|
text-overflow: ellipsis;
|
|
424
427
|
white-space: nowrap;
|
|
425
428
|
color: var(--hf-text-tertiary, rgba(244, 244, 245, 0.46));
|
|
426
|
-
font-family:
|
|
429
|
+
font-family: var(--font-mono);
|
|
427
430
|
font-size: 0.75rem;
|
|
428
431
|
letter-spacing: 0;
|
|
429
432
|
font-variant-numeric: tabular-nums;
|