@bycrux/editor 1.2.2 → 1.3.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/package.json +1 -1
- package/src/ControlsInfoModal.tsx +4 -4
- package/src/__tests__/no-opacity-modifier-on-editor-vars.test.ts +84 -0
- package/src/__tests__/node-shims.d.ts +19 -0
- package/src/carousel/AddElementMenu.tsx +1 -1
- package/src/carousel/CarouselEditor.tsx +11 -11
- package/src/carousel/CarouselRenderModal.tsx +11 -11
- package/src/carousel/OverlayPicker.tsx +3 -3
- package/src/carousel/SlidePropertyPanel.tsx +6 -6
- package/src/carousel/__tests__/CarouselEditor.test.tsx +12 -0
- package/src/components/FilmstripScrubber.tsx +1 -1
- package/src/crop/VideoSourceCropModal.tsx +4 -4
- package/src/state/__tests__/use-project-sync.test.tsx +76 -0
- package/src/state/use-project-sync.ts +21 -1
- package/src/text/FontPicker.tsx +3 -3
- package/src/text/TextFormattingToolbar.tsx +3 -3
- package/src/types.ts +16 -0
- package/src/ui/Loader.tsx +1 -1
- package/src/ui/NumberField.tsx +3 -3
- package/src/ui/SwatchInput.tsx +1 -1
- package/src/ui/Tooltip.tsx +1 -1
- package/src/ui/input.tsx +1 -1
- package/src/ui/label.tsx +1 -1
- package/src/ui/textarea.tsx +1 -1
- package/src/video/AudioPolishModal.tsx +21 -21
- package/src/video/CaptionListPanel.test.tsx +8 -7
- package/src/video/CaptionListPanel.tsx +17 -17
- package/src/video/CaptionRegenModal.tsx +7 -7
- package/src/video/CaptionStyleGallery.tsx +1 -1
- package/src/video/CommandPalette.tsx +7 -7
- package/src/video/ImageToneMenu.tsx +7 -7
- package/src/video/OverlayInspector.tsx +7 -7
- package/src/video/RenderModal.tsx +52 -52
- package/src/video/VersionCompare.tsx +7 -7
- package/src/video/VersionPanel.tsx +2 -2
- package/src/video/VideoEditor.tsx +43 -23
- package/src/video/__tests__/VideoEditor.pendingSurface.test.tsx +233 -0
- package/src/video/__tests__/VideoEditor.saveError.test.tsx +105 -0
- package/src/video/panels/ClipPropertiesPanel.tsx +4 -4
- package/src/video/panels/OverlayContentPanel.tsx +5 -5
- package/src/video/preview/OverlayItemsLayer.tsx +7 -2
- package/src/video/preview/SocialPreviewMenu.tsx +5 -5
- package/src/video/preview/__tests__/resolveOverlayPropPaths.test.ts +21 -0
- package/src/video/timeline/EditableSegment.tsx +1 -1
- package/src/video/timeline/Scrubber.tsx +2 -2
- package/src/video/timeline/SpeedControl.tsx +3 -3
- package/src/video/timeline/Timeline.tsx +3 -3
- package/src/video/timeline/TrackGutter.tsx +6 -6
- package/src/video/timeline/TrackSettingsPopover.tsx +3 -3
- package/src/video/timeline/VolumeControl.tsx +3 -3
|
@@ -63,7 +63,7 @@ export default function ImageToneMenu({ value, onChange, variant = 'icon', mode
|
|
|
63
63
|
title="How photos and logos are converted for the HDR render"
|
|
64
64
|
aria-haspopup="menu"
|
|
65
65
|
aria-expanded={open}
|
|
66
|
-
className="flex items-center gap-1.5 text-xs px-2.5 py-1.5 rounded-md border border-[var(--editor-border)] bg-[var(--editor-surface)] text-[var(--editor-text)]
|
|
66
|
+
className="flex items-center gap-1.5 text-xs px-2.5 py-1.5 rounded-md border border-[var(--editor-border)] bg-[var(--editor-surface)] text-[color-mix(in_srgb,var(--editor-text)_80%,transparent)] hover:text-[var(--editor-text)] transition-colors"
|
|
67
67
|
>
|
|
68
68
|
<Palette size={12} className="opacity-70" />
|
|
69
69
|
<span className="opacity-60">Image color:</span>
|
|
@@ -79,7 +79,7 @@ export default function ImageToneMenu({ value, onChange, variant = 'icon', mode
|
|
|
79
79
|
className={`flex items-center justify-center w-5 h-5 rounded transition-colors ${
|
|
80
80
|
open
|
|
81
81
|
? (mode === 'light' ? 'text-violet-600 bg-violet-400/15 hover:bg-violet-400/25' : 'text-violet-400 bg-violet-400/15 hover:bg-violet-400/25')
|
|
82
|
-
: 'text-[var(--editor-text)]
|
|
82
|
+
: 'text-[color-mix(in_srgb,var(--editor-text)_60%,transparent)] bg-transparent hover:text-[var(--editor-text)]'
|
|
83
83
|
}`}
|
|
84
84
|
>
|
|
85
85
|
<Palette size={12} />
|
|
@@ -91,9 +91,9 @@ export default function ImageToneMenu({ value, onChange, variant = 'icon', mode
|
|
|
91
91
|
role="menu"
|
|
92
92
|
className={`${menuPosition} z-40 w-[300px] rounded-xl border border-[var(--editor-border)] bg-[var(--editor-surface)] shadow-2xl p-2 flex flex-col gap-1`}
|
|
93
93
|
>
|
|
94
|
-
<p className="px-2 pt-1 pb-1.5 text-[11px] font-semibold text-[var(--editor-text)]
|
|
94
|
+
<p className="px-2 pt-1 pb-1.5 text-[11px] font-semibold text-[color-mix(in_srgb,var(--editor-text)_80%,transparent)]">
|
|
95
95
|
Image color mapping
|
|
96
|
-
<span className="block font-normal text-[10px] text-[var(--editor-text)]
|
|
96
|
+
<span className="block font-normal text-[10px] text-[color-mix(in_srgb,var(--editor-text)_50%,transparent)]">
|
|
97
97
|
How photos and logos are converted for the HDR render.
|
|
98
98
|
</span>
|
|
99
99
|
</p>
|
|
@@ -108,7 +108,7 @@ export default function ImageToneMenu({ value, onChange, variant = 'icon', mode
|
|
|
108
108
|
className={`flex items-start gap-2.5 rounded-lg p-2 text-left transition-colors border ${
|
|
109
109
|
active
|
|
110
110
|
? 'border-violet-400/60 bg-violet-400/10'
|
|
111
|
-
: 'border-transparent hover:bg-[var(--editor-text)]
|
|
111
|
+
: 'border-transparent hover:bg-[color-mix(in_srgb,var(--editor-text)_5%,transparent)]'
|
|
112
112
|
}`}
|
|
113
113
|
>
|
|
114
114
|
<img
|
|
@@ -120,10 +120,10 @@ export default function ImageToneMenu({ value, onChange, variant = 'icon', mode
|
|
|
120
120
|
<span className="text-xs font-semibold text-[var(--editor-text)] flex items-center gap-1.5">
|
|
121
121
|
{tone.label}
|
|
122
122
|
{tone.id === DEFAULT_IMAGE_TONE && (
|
|
123
|
-
<span className="text-[9px] font-normal px-1 py-px rounded bg-[var(--editor-text)]
|
|
123
|
+
<span className="text-[9px] font-normal px-1 py-px rounded bg-[color-mix(in_srgb,var(--editor-text)_10%,transparent)] text-[color-mix(in_srgb,var(--editor-text)_55%,transparent)]">default</span>
|
|
124
124
|
)}
|
|
125
125
|
</span>
|
|
126
|
-
<span className="text-[10px] leading-snug text-[var(--editor-text)]
|
|
126
|
+
<span className="text-[10px] leading-snug text-[color-mix(in_srgb,var(--editor-text)_60%,transparent)]">
|
|
127
127
|
{tone.summary}
|
|
128
128
|
</span>
|
|
129
129
|
</span>
|
|
@@ -216,9 +216,9 @@ function normalizeDegrees(deg: number): number {
|
|
|
216
216
|
|
|
217
217
|
// ── Shared chrome ────────────────────────────────────────────────────────
|
|
218
218
|
|
|
219
|
-
const ROW_LABEL_CLASS = 'w-14 shrink-0 text-[11px] text-[var(--editor-text)]
|
|
219
|
+
const ROW_LABEL_CLASS = 'w-14 shrink-0 text-[11px] text-[color-mix(in_srgb,var(--editor-text)_55%,transparent)]'
|
|
220
220
|
const ICON_BUTTON_CLASS =
|
|
221
|
-
'flex h-5 w-5 shrink-0 items-center justify-center rounded text-[var(--editor-text)]
|
|
221
|
+
'flex h-5 w-5 shrink-0 items-center justify-center rounded text-[color-mix(in_srgb,var(--editor-text)_45%,transparent)] transition-colors hover:bg-[var(--editor-surface)] hover:text-[var(--editor-text)] disabled:pointer-events-none disabled:opacity-25'
|
|
222
222
|
|
|
223
223
|
function IconButton({
|
|
224
224
|
label,
|
|
@@ -282,10 +282,10 @@ function KeyframeNav({
|
|
|
282
282
|
// invites a support question; one that is visibly unavailable and
|
|
283
283
|
// says why reads as a limitation, which is what it is.
|
|
284
284
|
diamondDisabled
|
|
285
|
-
? 'cursor-not-allowed text-[var(--editor-text)]
|
|
285
|
+
? 'cursor-not-allowed text-[color-mix(in_srgb,var(--editor-text)_20%,transparent)]'
|
|
286
286
|
: pressed
|
|
287
287
|
? 'text-[var(--editor-accent)]'
|
|
288
|
-
: 'text-[var(--editor-text)]
|
|
288
|
+
: 'text-[color-mix(in_srgb,var(--editor-text)_40%,transparent)] hover:text-[color-mix(in_srgb,var(--editor-text)_70%,transparent)]',
|
|
289
289
|
)}
|
|
290
290
|
>
|
|
291
291
|
<Diamond size={11} fill={pressed ? 'currentColor' : 'none'} />
|
|
@@ -518,7 +518,7 @@ export default function OverlayInspector({ item, clock, onPreview, onCommit, onC
|
|
|
518
518
|
if (!canKeyframe(item)) {
|
|
519
519
|
return (
|
|
520
520
|
<div className={SECTION_CLASS}>
|
|
521
|
-
<div className="px-3 py-6 text-center text-[11px] text-[var(--editor-text)]
|
|
521
|
+
<div className="px-3 py-6 text-center text-[11px] text-[color-mix(in_srgb,var(--editor-text)_45%,transparent)]">
|
|
522
522
|
Select an overlay to edit its properties.
|
|
523
523
|
</div>
|
|
524
524
|
</div>
|
|
@@ -769,7 +769,7 @@ export default function OverlayInspector({ item, clock, onPreview, onCommit, onC
|
|
|
769
769
|
only hosts the ALL-properties actions (reset-all + keyframe-all); the
|
|
770
770
|
muted "All" scopes them apart from each row's own per-property unit. */}
|
|
771
771
|
<div className="shrink-0 flex items-center gap-1 border-b border-[var(--editor-border)] px-2 py-1.5">
|
|
772
|
-
<span className="px-1 py-0.5 text-[10px] font-medium uppercase tracking-wide text-[var(--editor-text)]
|
|
772
|
+
<span className="px-1 py-0.5 text-[10px] font-medium uppercase tracking-wide text-[color-mix(in_srgb,var(--editor-text)_40%,transparent)]">
|
|
773
773
|
All
|
|
774
774
|
</span>
|
|
775
775
|
<div className="ml-auto flex items-center gap-1">
|
|
@@ -857,7 +857,7 @@ export default function OverlayInspector({ item, clock, onPreview, onCommit, onC
|
|
|
857
857
|
(Space/Enter both fire click), so it needs no key handler of its
|
|
858
858
|
own — only a visible focus ring. */}
|
|
859
859
|
<div className="flex items-center gap-2">
|
|
860
|
-
<span className="shrink-0 text-[11px] text-[var(--editor-text)]
|
|
860
|
+
<span className="shrink-0 text-[11px] text-[color-mix(in_srgb,var(--editor-text)_55%,transparent)]">Uniform scale</span>
|
|
861
861
|
<button
|
|
862
862
|
type="button"
|
|
863
863
|
role="checkbox"
|
|
@@ -290,10 +290,10 @@ function PhaseStepper({ current, phases }: { current: RenderPhase; phases: Rende
|
|
|
290
290
|
<span
|
|
291
291
|
className={
|
|
292
292
|
complete
|
|
293
|
-
? 'text-sm text-[var(--editor-text)]
|
|
293
|
+
? 'text-sm text-[color-mix(in_srgb,var(--editor-text)_70%,transparent)]'
|
|
294
294
|
: active
|
|
295
295
|
? 'text-sm font-semibold text-[var(--editor-text)]'
|
|
296
|
-
: 'text-sm text-[var(--editor-text)]
|
|
296
|
+
: 'text-sm text-[color-mix(in_srgb,var(--editor-text)_35%,transparent)]'
|
|
297
297
|
}
|
|
298
298
|
>
|
|
299
299
|
{phaseLabel(phase)}
|
|
@@ -309,15 +309,15 @@ function PhaseStepper({ current, phases }: { current: RenderPhase; phases: Rende
|
|
|
309
309
|
|
|
310
310
|
function LogLine({ text }: { text: string }) {
|
|
311
311
|
const t = text.replace(/^\[montaj render\]\s*/, '')
|
|
312
|
-
let color = 'text-[var(--editor-text)]
|
|
312
|
+
let color = 'text-[color-mix(in_srgb,var(--editor-text)_60%,transparent)]'
|
|
313
313
|
if (/ready|complete|done|encoded|assembled/i.test(t)) color = 'text-green-400'
|
|
314
314
|
else if (/rendering|bundling|launching|browsers/i.test(t)) color = 'text-sky-400'
|
|
315
315
|
else if (/trimming|building|composing/i.test(t)) color = 'text-amber-400'
|
|
316
|
-
else if (/frame\s+\d+\/\d+/i.test(t)) color = 'text-[var(--editor-text)]
|
|
316
|
+
else if (/frame\s+\d+\/\d+/i.test(t)) color = 'text-[color-mix(in_srgb,var(--editor-text)_55%,transparent)]'
|
|
317
317
|
else if (/error|fail|warn/i.test(t)) color = 'text-red-400'
|
|
318
318
|
|
|
319
319
|
const prefix = text.startsWith('[montaj render]')
|
|
320
|
-
? <span className="text-[var(--editor-text)]
|
|
320
|
+
? <span className="text-[color-mix(in_srgb,var(--editor-text)_40%,transparent)]">[render] </span>
|
|
321
321
|
: null
|
|
322
322
|
|
|
323
323
|
return (
|
|
@@ -385,7 +385,7 @@ function ProgressBar({ value }: { value: number | null }) {
|
|
|
385
385
|
return (
|
|
386
386
|
<div className="w-full max-w-xs" role="progressbar" aria-label="Render progress"
|
|
387
387
|
aria-valuenow={pct === null ? undefined : Math.round(pct)} aria-valuemin={0} aria-valuemax={100}>
|
|
388
|
-
<div className="h-1.5 w-full overflow-hidden rounded-full bg-[var(--editor-text)]
|
|
388
|
+
<div className="h-1.5 w-full overflow-hidden rounded-full bg-[color-mix(in_srgb,var(--editor-text)_10%,transparent)]">
|
|
389
389
|
{pct === null ? (
|
|
390
390
|
<>
|
|
391
391
|
<style>{'@keyframes montajRenderIndet{0%{transform:translateX(-100%)}100%{transform:translateX(320%)}}'}</style>
|
|
@@ -801,7 +801,7 @@ export default function RenderModal<P extends Project = Project>({ projectId, ad
|
|
|
801
801
|
<button
|
|
802
802
|
onClick={handleCancel}
|
|
803
803
|
aria-label="Close"
|
|
804
|
-
className="text-[var(--editor-text)]
|
|
804
|
+
className="text-[color-mix(in_srgb,var(--editor-text)_55%,transparent)] hover:text-[var(--editor-text)] transition-colors text-lg leading-none"
|
|
805
805
|
>
|
|
806
806
|
×
|
|
807
807
|
</button>
|
|
@@ -827,7 +827,7 @@ export default function RenderModal<P extends Project = Project>({ projectId, ad
|
|
|
827
827
|
) : coverLoading ? (
|
|
828
828
|
<Loader size="md" label="Loading cover" />
|
|
829
829
|
) : (
|
|
830
|
-
<span className="text-[11px] text-[var(--editor-text)]
|
|
830
|
+
<span className="text-[11px] text-[color-mix(in_srgb,var(--editor-text)_40%,transparent)]">No preview</span>
|
|
831
831
|
)}
|
|
832
832
|
</div>
|
|
833
833
|
{adapter.getSampleFrame && (
|
|
@@ -835,7 +835,7 @@ export default function RenderModal<P extends Project = Project>({ projectId, ad
|
|
|
835
835
|
<button
|
|
836
836
|
onClick={() => setCoverEditing(o => !o)}
|
|
837
837
|
aria-expanded={coverEditing}
|
|
838
|
-
className="self-start text-xs text-[var(--editor-text)]
|
|
838
|
+
className="self-start text-xs text-[color-mix(in_srgb,var(--editor-text)_70%,transparent)] hover:text-[var(--editor-text)] transition-colors"
|
|
839
839
|
>
|
|
840
840
|
{coverEditing ? 'Done' : 'Edit cover'}
|
|
841
841
|
</button>
|
|
@@ -869,7 +869,7 @@ export default function RenderModal<P extends Project = Project>({ projectId, ad
|
|
|
869
869
|
})}
|
|
870
870
|
</div>
|
|
871
871
|
) : (
|
|
872
|
-
<p className="text-[11px] text-[var(--editor-text)]
|
|
872
|
+
<p className="text-[11px] text-[color-mix(in_srgb,var(--editor-text)_40%,transparent)]">No frames to pick from.</p>
|
|
873
873
|
)
|
|
874
874
|
)}
|
|
875
875
|
</>
|
|
@@ -880,7 +880,7 @@ export default function RenderModal<P extends Project = Project>({ projectId, ad
|
|
|
880
880
|
<div className="flex-1 min-w-0 flex flex-col gap-4">
|
|
881
881
|
{/* Name */}
|
|
882
882
|
<label className="flex flex-col gap-1.5">
|
|
883
|
-
<span className="text-[11px] font-semibold uppercase tracking-wide text-[var(--editor-text)]
|
|
883
|
+
<span className="text-[11px] font-semibold uppercase tracking-wide text-[color-mix(in_srgb,var(--editor-text)_50%,transparent)]">Name</span>
|
|
884
884
|
<input
|
|
885
885
|
type="text"
|
|
886
886
|
value={name}
|
|
@@ -892,9 +892,9 @@ export default function RenderModal<P extends Project = Project>({ projectId, ad
|
|
|
892
892
|
|
|
893
893
|
{/* Save to */}
|
|
894
894
|
<div className="flex flex-col gap-1">
|
|
895
|
-
<span className="text-[11px] font-semibold uppercase tracking-wide text-[var(--editor-text)]
|
|
896
|
-
<span className="text-xs font-mono text-[var(--editor-text)]
|
|
897
|
-
<span className="text-[11px] text-[var(--editor-text)]
|
|
895
|
+
<span className="text-[11px] font-semibold uppercase tracking-wide text-[color-mix(in_srgb,var(--editor-text)_50%,transparent)]">Save to</span>
|
|
896
|
+
<span className="text-xs font-mono text-[color-mix(in_srgb,var(--editor-text)_70%,transparent)] truncate">output/{outputName}.mp4</span>
|
|
897
|
+
<span className="text-[11px] text-[color-mix(in_srgb,var(--editor-text)_45%,transparent)]">Download after export.</span>
|
|
898
898
|
</div>
|
|
899
899
|
|
|
900
900
|
{/* Resolution — source-capped tier picker. Only rendered when the
|
|
@@ -908,7 +908,7 @@ export default function RenderModal<P extends Project = Project>({ projectId, ad
|
|
|
908
908
|
const currentShort = Math.min(...res.value)
|
|
909
909
|
return (
|
|
910
910
|
<div className="flex flex-col gap-2">
|
|
911
|
-
<p className="text-[11px] font-semibold uppercase tracking-wide text-[var(--editor-text)]
|
|
911
|
+
<p className="text-[11px] font-semibold uppercase tracking-wide text-[color-mix(in_srgb,var(--editor-text)_50%,transparent)]">Resolution</p>
|
|
912
912
|
<div role="radiogroup" aria-label="Resolution" className="grid grid-cols-2 sm:grid-cols-4 gap-2">
|
|
913
913
|
{res.available.map(([w, h]) => {
|
|
914
914
|
const short = Math.min(w, h)
|
|
@@ -922,11 +922,11 @@ export default function RenderModal<P extends Project = Project>({ projectId, ad
|
|
|
922
922
|
className={`flex flex-col gap-1 rounded-lg border p-2.5 text-left transition-colors ${
|
|
923
923
|
active
|
|
924
924
|
? 'border-violet-400/60 bg-violet-400/10'
|
|
925
|
-
: 'border-[var(--editor-border)] hover:bg-[var(--editor-text)]
|
|
925
|
+
: 'border-[var(--editor-border)] hover:bg-[color-mix(in_srgb,var(--editor-text)_5%,transparent)]'
|
|
926
926
|
}`}
|
|
927
927
|
>
|
|
928
928
|
<span className="text-xs font-semibold text-[var(--editor-text)]">{resLabel([w, h])}</span>
|
|
929
|
-
<span className="text-[10px] leading-snug text-[var(--editor-text)]
|
|
929
|
+
<span className="text-[10px] leading-snug text-[color-mix(in_srgb,var(--editor-text)_55%,transparent)]">{w} × {h}</span>
|
|
930
930
|
</button>
|
|
931
931
|
)
|
|
932
932
|
})}
|
|
@@ -940,7 +940,7 @@ export default function RenderModal<P extends Project = Project>({ projectId, ad
|
|
|
940
940
|
const fps = preRenderOptions.fps
|
|
941
941
|
return (
|
|
942
942
|
<div className="flex flex-col gap-2">
|
|
943
|
-
<p className="text-[11px] font-semibold uppercase tracking-wide text-[var(--editor-text)]
|
|
943
|
+
<p className="text-[11px] font-semibold uppercase tracking-wide text-[color-mix(in_srgb,var(--editor-text)_50%,transparent)]">Frame rate</p>
|
|
944
944
|
<div role="radiogroup" aria-label="Frame rate" className="grid grid-cols-3 gap-2">
|
|
945
945
|
{fps.available.map(f => {
|
|
946
946
|
const active = f === fps.value
|
|
@@ -954,11 +954,11 @@ export default function RenderModal<P extends Project = Project>({ projectId, ad
|
|
|
954
954
|
className={`flex flex-col gap-1 rounded-lg border p-2.5 text-left transition-colors ${
|
|
955
955
|
active
|
|
956
956
|
? 'border-violet-400/60 bg-violet-400/10'
|
|
957
|
-
: 'border-[var(--editor-border)] hover:bg-[var(--editor-text)]
|
|
957
|
+
: 'border-[var(--editor-border)] hover:bg-[color-mix(in_srgb,var(--editor-text)_5%,transparent)]'
|
|
958
958
|
}`}
|
|
959
959
|
>
|
|
960
960
|
<span className="text-xs font-semibold text-[var(--editor-text)]">{f} fps</span>
|
|
961
|
-
<span className="text-[10px] leading-snug text-[var(--editor-text)]
|
|
961
|
+
<span className="text-[10px] leading-snug text-[color-mix(in_srgb,var(--editor-text)_55%,transparent)]">{hint}</span>
|
|
962
962
|
</button>
|
|
963
963
|
)
|
|
964
964
|
})}
|
|
@@ -972,7 +972,7 @@ export default function RenderModal<P extends Project = Project>({ projectId, ad
|
|
|
972
972
|
<>
|
|
973
973
|
{/* Format */}
|
|
974
974
|
<div className="flex flex-col gap-2">
|
|
975
|
-
<p className="text-[11px] font-semibold uppercase tracking-wide text-[var(--editor-text)]
|
|
975
|
+
<p className="text-[11px] font-semibold uppercase tracking-wide text-[color-mix(in_srgb,var(--editor-text)_50%,transparent)]">Format</p>
|
|
976
976
|
<div role="radiogroup" aria-label="Format" className="grid grid-cols-3 gap-2">
|
|
977
977
|
{EXPORT_CHOICES.map(choice => {
|
|
978
978
|
const active = choice.id === exportChoice
|
|
@@ -985,11 +985,11 @@ export default function RenderModal<P extends Project = Project>({ projectId, ad
|
|
|
985
985
|
className={`flex flex-col gap-1 rounded-lg border p-2.5 text-left transition-colors ${
|
|
986
986
|
active
|
|
987
987
|
? 'border-violet-400/60 bg-violet-400/10'
|
|
988
|
-
: 'border-[var(--editor-border)] hover:bg-[var(--editor-text)]
|
|
988
|
+
: 'border-[var(--editor-border)] hover:bg-[color-mix(in_srgb,var(--editor-text)_5%,transparent)]'
|
|
989
989
|
}`}
|
|
990
990
|
>
|
|
991
991
|
<span className="text-xs font-semibold text-[var(--editor-text)]">{choice.label}</span>
|
|
992
|
-
<span className="text-[10px] leading-snug text-[var(--editor-text)]
|
|
992
|
+
<span className="text-[10px] leading-snug text-[color-mix(in_srgb,var(--editor-text)_55%,transparent)]">{choice.blurb}</span>
|
|
993
993
|
</button>
|
|
994
994
|
)
|
|
995
995
|
})}
|
|
@@ -1010,7 +1010,7 @@ export default function RenderModal<P extends Project = Project>({ projectId, ad
|
|
|
1010
1010
|
<button
|
|
1011
1011
|
onClick={() => setImageColor(o => !o)}
|
|
1012
1012
|
aria-expanded={imageColorOpen}
|
|
1013
|
-
className="flex items-center gap-1.5 self-start text-xs text-[var(--editor-text)]
|
|
1013
|
+
className="flex items-center gap-1.5 self-start text-xs text-[color-mix(in_srgb,var(--editor-text)_70%,transparent)] hover:text-[var(--editor-text)] transition-colors"
|
|
1014
1014
|
>
|
|
1015
1015
|
{imageColorOpen ? <ChevronDown size={13} /> : <ChevronRight size={13} />}
|
|
1016
1016
|
Image color
|
|
@@ -1018,7 +1018,7 @@ export default function RenderModal<P extends Project = Project>({ projectId, ad
|
|
|
1018
1018
|
|
|
1019
1019
|
{imageColorOpen ? (
|
|
1020
1020
|
<div className="flex flex-col gap-2">
|
|
1021
|
-
<p className="text-[11px] font-semibold uppercase tracking-wide text-[var(--editor-text)]
|
|
1021
|
+
<p className="text-[11px] font-semibold uppercase tracking-wide text-[color-mix(in_srgb,var(--editor-text)_50%,transparent)]">
|
|
1022
1022
|
How photos and logos convert for HDR
|
|
1023
1023
|
</p>
|
|
1024
1024
|
<div role="radiogroup" aria-label="Image color" className="grid grid-cols-2 gap-2">
|
|
@@ -1033,7 +1033,7 @@ export default function RenderModal<P extends Project = Project>({ projectId, ad
|
|
|
1033
1033
|
className={`flex flex-col gap-1.5 rounded-lg border p-2 text-left transition-colors ${
|
|
1034
1034
|
active
|
|
1035
1035
|
? 'border-violet-400/60 bg-violet-400/10'
|
|
1036
|
-
: 'border-[var(--editor-border)] hover:bg-[var(--editor-text)]
|
|
1036
|
+
: 'border-[var(--editor-border)] hover:bg-[color-mix(in_srgb,var(--editor-text)_5%,transparent)]'
|
|
1037
1037
|
}`}
|
|
1038
1038
|
>
|
|
1039
1039
|
<img
|
|
@@ -1044,17 +1044,17 @@ export default function RenderModal<P extends Project = Project>({ projectId, ad
|
|
|
1044
1044
|
<span className="text-xs font-semibold text-[var(--editor-text)] flex items-center gap-1.5">
|
|
1045
1045
|
{t.label}
|
|
1046
1046
|
{t.id === DEFAULT_IMAGE_TONE && (
|
|
1047
|
-
<span className="text-[9px] font-normal px-1 py-px rounded bg-[var(--editor-text)]
|
|
1047
|
+
<span className="text-[9px] font-normal px-1 py-px rounded bg-[color-mix(in_srgb,var(--editor-text)_10%,transparent)] text-[color-mix(in_srgb,var(--editor-text)_55%,transparent)]">default</span>
|
|
1048
1048
|
)}
|
|
1049
1049
|
</span>
|
|
1050
|
-
<span className="text-[10px] leading-snug text-[var(--editor-text)]
|
|
1050
|
+
<span className="text-[10px] leading-snug text-[color-mix(in_srgb,var(--editor-text)_60%,transparent)]">{t.summary}</span>
|
|
1051
1051
|
</button>
|
|
1052
1052
|
)
|
|
1053
1053
|
})}
|
|
1054
1054
|
</div>
|
|
1055
1055
|
</div>
|
|
1056
1056
|
) : (
|
|
1057
|
-
<p className="text-[11px] text-[var(--editor-text)]
|
|
1057
|
+
<p className="text-[11px] text-[color-mix(in_srgb,var(--editor-text)_45%,transparent)]">
|
|
1058
1058
|
Photos and logos use the {toneInfo.label} conversion. Open to change.
|
|
1059
1059
|
</p>
|
|
1060
1060
|
)}
|
|
@@ -1067,7 +1067,7 @@ export default function RenderModal<P extends Project = Project>({ projectId, ad
|
|
|
1067
1067
|
<button
|
|
1068
1068
|
onClick={() => setAdvanced(o => !o)}
|
|
1069
1069
|
aria-expanded={advancedOpen}
|
|
1070
|
-
className="flex items-center gap-1.5 self-start text-xs text-[var(--editor-text)]
|
|
1070
|
+
className="flex items-center gap-1.5 self-start text-xs text-[color-mix(in_srgb,var(--editor-text)_70%,transparent)] hover:text-[var(--editor-text)] transition-colors"
|
|
1071
1071
|
>
|
|
1072
1072
|
{advancedOpen ? <ChevronDown size={13} /> : <ChevronRight size={13} />}
|
|
1073
1073
|
Advanced
|
|
@@ -1075,7 +1075,7 @@ export default function RenderModal<P extends Project = Project>({ projectId, ad
|
|
|
1075
1075
|
|
|
1076
1076
|
{advancedOpen ? (
|
|
1077
1077
|
<div className="flex flex-col gap-2">
|
|
1078
|
-
<p className="text-[11px] font-semibold uppercase tracking-wide text-[var(--editor-text)]
|
|
1078
|
+
<p className="text-[11px] font-semibold uppercase tracking-wide text-[color-mix(in_srgb,var(--editor-text)_50%,transparent)]">
|
|
1079
1079
|
Tone curve for SDR
|
|
1080
1080
|
</p>
|
|
1081
1081
|
<div role="radiogroup" aria-label="Tone curve for SDR" className="grid grid-cols-2 gap-2">
|
|
@@ -1091,7 +1091,7 @@ export default function RenderModal<P extends Project = Project>({ projectId, ad
|
|
|
1091
1091
|
className={`flex flex-col gap-1.5 rounded-lg border p-2 text-left transition-colors ${
|
|
1092
1092
|
active
|
|
1093
1093
|
? 'border-violet-400/60 bg-violet-400/10'
|
|
1094
|
-
: 'border-[var(--editor-border)] hover:bg-[var(--editor-text)]
|
|
1094
|
+
: 'border-[var(--editor-border)] hover:bg-[color-mix(in_srgb,var(--editor-text)_5%,transparent)]'
|
|
1095
1095
|
}`}
|
|
1096
1096
|
>
|
|
1097
1097
|
{thumb ? (
|
|
@@ -1120,17 +1120,17 @@ export default function RenderModal<P extends Project = Project>({ projectId, ad
|
|
|
1120
1120
|
</span>
|
|
1121
1121
|
</span>
|
|
1122
1122
|
) : thumbsPending ? (
|
|
1123
|
-
<span style={{ aspectRatio: coverAspect }} className="w-full rounded border border-[var(--editor-border)] bg-[var(--editor-text)]
|
|
1123
|
+
<span style={{ aspectRatio: coverAspect }} className="w-full rounded border border-[var(--editor-border)] bg-[color-mix(in_srgb,var(--editor-text)_5%,transparent)] flex items-center justify-center">
|
|
1124
1124
|
<Loader size="sm" />
|
|
1125
1125
|
</span>
|
|
1126
1126
|
) : null}
|
|
1127
1127
|
<span className="text-xs font-semibold text-[var(--editor-text)] flex items-center gap-1.5">
|
|
1128
1128
|
{curve.label}
|
|
1129
1129
|
{curve.id === DEFAULT_SDR_CURVE && (
|
|
1130
|
-
<span className="text-[9px] font-normal px-1 py-px rounded bg-[var(--editor-text)]
|
|
1130
|
+
<span className="text-[9px] font-normal px-1 py-px rounded bg-[color-mix(in_srgb,var(--editor-text)_10%,transparent)] text-[color-mix(in_srgb,var(--editor-text)_55%,transparent)]">default</span>
|
|
1131
1131
|
)}
|
|
1132
1132
|
</span>
|
|
1133
|
-
<span className="text-[10px] leading-snug text-[var(--editor-text)]
|
|
1133
|
+
<span className="text-[10px] leading-snug text-[color-mix(in_srgb,var(--editor-text)_60%,transparent)]">{curve.blurb}</span>
|
|
1134
1134
|
</button>
|
|
1135
1135
|
)
|
|
1136
1136
|
})}
|
|
@@ -1139,7 +1139,7 @@ export default function RenderModal<P extends Project = Project>({ projectId, ad
|
|
|
1139
1139
|
data-testid="sdr-honesty-line"
|
|
1140
1140
|
className={`text-[11px] leading-snug ${
|
|
1141
1141
|
sdrCurve === DEFAULT_SDR_CURVE
|
|
1142
|
-
? 'text-[var(--editor-text)]
|
|
1142
|
+
? 'text-[color-mix(in_srgb,var(--editor-text)_55%,transparent)]'
|
|
1143
1143
|
: (mode === 'light' ? 'text-amber-700' : 'text-amber-400/90')
|
|
1144
1144
|
}`}
|
|
1145
1145
|
>
|
|
@@ -1147,7 +1147,7 @@ export default function RenderModal<P extends Project = Project>({ projectId, ad
|
|
|
1147
1147
|
</p>
|
|
1148
1148
|
</div>
|
|
1149
1149
|
) : (
|
|
1150
|
-
<p className="text-[11px] text-[var(--editor-text)]
|
|
1150
|
+
<p className="text-[11px] text-[color-mix(in_srgb,var(--editor-text)_45%,transparent)]">
|
|
1151
1151
|
SDR files use the {curveInfo.label} look. Open Advanced to compare curves.
|
|
1152
1152
|
</p>
|
|
1153
1153
|
)}
|
|
@@ -1159,13 +1159,13 @@ export default function RenderModal<P extends Project = Project>({ projectId, ad
|
|
|
1159
1159
|
|
|
1160
1160
|
{/* Footer — duration on the left, actions on the right. */}
|
|
1161
1161
|
<div className="flex items-center justify-between gap-2 px-5 py-3 border-t border-[var(--editor-border)]">
|
|
1162
|
-
<span className="text-xs text-[var(--editor-text)]
|
|
1162
|
+
<span className="text-xs text-[color-mix(in_srgb,var(--editor-text)_50%,transparent)] tabular-nums">
|
|
1163
1163
|
{durationSec > 0 ? formatTimecode(durationSec) : ''}
|
|
1164
1164
|
</span>
|
|
1165
1165
|
<div className="flex items-center gap-2">
|
|
1166
1166
|
<button
|
|
1167
1167
|
onClick={handleCancel}
|
|
1168
|
-
className="text-sm px-4 py-1.5 rounded-md bg-[var(--editor-surface)] border border-[var(--editor-border)] text-[var(--editor-text)]
|
|
1168
|
+
className="text-sm px-4 py-1.5 rounded-md bg-[var(--editor-surface)] border border-[var(--editor-border)] text-[color-mix(in_srgb,var(--editor-text)_80%,transparent)] hover:opacity-90 transition-colors"
|
|
1169
1169
|
>
|
|
1170
1170
|
Cancel
|
|
1171
1171
|
</button>
|
|
@@ -1257,7 +1257,7 @@ export default function RenderModal<P extends Project = Project>({ projectId, ad
|
|
|
1257
1257
|
className="h-full w-full object-contain"
|
|
1258
1258
|
/>
|
|
1259
1259
|
) : (
|
|
1260
|
-
<p className="text-sm text-[var(--editor-text)]
|
|
1260
|
+
<p className="text-sm text-[color-mix(in_srgb,var(--editor-text)_60%,transparent)]">Render complete.</p>
|
|
1261
1261
|
)}
|
|
1262
1262
|
</div>
|
|
1263
1263
|
|
|
@@ -1268,10 +1268,10 @@ export default function RenderModal<P extends Project = Project>({ projectId, ad
|
|
|
1268
1268
|
<span className="w-2 h-2 rounded-full bg-green-400" />
|
|
1269
1269
|
<div>
|
|
1270
1270
|
<p className="text-sm font-semibold text-[var(--editor-text)]">Render complete</p>
|
|
1271
|
-
<p className="text-xs text-[var(--editor-text)]
|
|
1271
|
+
<p className="text-xs text-[color-mix(in_srgb,var(--editor-text)_60%,transparent)]">Saved to your library.</p>
|
|
1272
1272
|
</div>
|
|
1273
1273
|
</div>
|
|
1274
|
-
<button onClick={onClose} className="text-[var(--editor-text)]
|
|
1274
|
+
<button onClick={onClose} className="text-[color-mix(in_srgb,var(--editor-text)_55%,transparent)] hover:text-[var(--editor-text)] transition-colors text-lg leading-none">×</button>
|
|
1275
1275
|
</div>
|
|
1276
1276
|
|
|
1277
1277
|
<div className="flex flex-col gap-3 p-5 flex-1">
|
|
@@ -1299,7 +1299,7 @@ export default function RenderModal<P extends Project = Project>({ projectId, ad
|
|
|
1299
1299
|
))}
|
|
1300
1300
|
<button
|
|
1301
1301
|
onClick={onClose}
|
|
1302
|
-
className="w-full text-center text-sm px-4 py-2.5 rounded-lg bg-[var(--editor-surface)] border border-[var(--editor-border)] text-[var(--editor-text)]
|
|
1302
|
+
className="w-full text-center text-sm px-4 py-2.5 rounded-lg bg-[var(--editor-surface)] border border-[var(--editor-border)] text-[color-mix(in_srgb,var(--editor-text)_80%,transparent)] hover:opacity-90 transition-colors"
|
|
1303
1303
|
>
|
|
1304
1304
|
Close
|
|
1305
1305
|
</button>
|
|
@@ -1325,7 +1325,7 @@ export default function RenderModal<P extends Project = Project>({ projectId, ad
|
|
|
1325
1325
|
</h2>
|
|
1326
1326
|
</div>
|
|
1327
1327
|
{status !== 'running' && (
|
|
1328
|
-
<button onClick={onClose} className="text-[var(--editor-text)]
|
|
1328
|
+
<button onClick={onClose} className="text-[color-mix(in_srgb,var(--editor-text)_55%,transparent)] hover:text-[var(--editor-text)] transition-colors text-lg leading-none">×</button>
|
|
1329
1329
|
)}
|
|
1330
1330
|
</div>
|
|
1331
1331
|
|
|
@@ -1336,7 +1336,7 @@ export default function RenderModal<P extends Project = Project>({ projectId, ad
|
|
|
1336
1336
|
|
|
1337
1337
|
<div className="flex flex-col items-center gap-1 text-center">
|
|
1338
1338
|
<h3 className="text-base font-semibold text-[var(--editor-text)]">Exporting your video</h3>
|
|
1339
|
-
<p className="text-xs text-[var(--editor-text)]
|
|
1339
|
+
<p className="text-xs text-[color-mix(in_srgb,var(--editor-text)_50%,transparent)]">This can take a few minutes for longer videos.</p>
|
|
1340
1340
|
</div>
|
|
1341
1341
|
|
|
1342
1342
|
{/* Progress bar — always visible while rendering, above the stepper
|
|
@@ -1366,7 +1366,7 @@ export default function RenderModal<P extends Project = Project>({ projectId, ad
|
|
|
1366
1366
|
<button
|
|
1367
1367
|
onClick={() => setShowLog(o => !o)}
|
|
1368
1368
|
aria-expanded={showLog}
|
|
1369
|
-
className="mx-auto flex items-center gap-1 text-[11px] text-[var(--editor-text)]
|
|
1369
|
+
className="mx-auto flex items-center gap-1 text-[11px] text-[color-mix(in_srgb,var(--editor-text)_50%,transparent)] hover:text-[color-mix(in_srgb,var(--editor-text)_80%,transparent)] transition-colors"
|
|
1370
1370
|
>
|
|
1371
1371
|
{showLog ? <ChevronDown size={13} /> : <ChevronRight size={13} />}
|
|
1372
1372
|
{showLog ? 'Hide render log' : 'Show render log'}
|
|
@@ -1375,17 +1375,17 @@ export default function RenderModal<P extends Project = Project>({ projectId, ad
|
|
|
1375
1375
|
<div className="relative mt-2">
|
|
1376
1376
|
<button
|
|
1377
1377
|
onClick={() => navigator.clipboard.writeText(logs.join('\n'))}
|
|
1378
|
-
className="absolute top-2 right-2 z-10 rounded border border-white/10 bg-[#0a0e17] px-2 py-0.5 text-[10px] text-[var(--editor-text)]
|
|
1378
|
+
className="absolute top-2 right-2 z-10 rounded border border-white/10 bg-[#0a0e17] px-2 py-0.5 text-[10px] text-[color-mix(in_srgb,var(--editor-text)_60%,transparent)] hover:text-[var(--editor-text)] transition-colors"
|
|
1379
1379
|
title="Copy logs"
|
|
1380
1380
|
>
|
|
1381
1381
|
Copy
|
|
1382
1382
|
</button>
|
|
1383
1383
|
<div
|
|
1384
1384
|
ref={logRef}
|
|
1385
|
-
className="flex h-52 flex-col gap-0.5 overflow-y-auto rounded-lg border border-white/10 bg-[#0a0e17] px-3 py-2 font-mono text-[11px] text-[var(--editor-text)]
|
|
1385
|
+
className="flex h-52 flex-col gap-0.5 overflow-y-auto rounded-lg border border-white/10 bg-[#0a0e17] px-3 py-2 font-mono text-[11px] text-[color-mix(in_srgb,var(--editor-text)_80%,transparent)]"
|
|
1386
1386
|
>
|
|
1387
1387
|
{logs.length === 0
|
|
1388
|
-
? <span className="italic text-[var(--editor-text)]
|
|
1388
|
+
? <span className="italic text-[color-mix(in_srgb,var(--editor-text)_40%,transparent)]">Starting render engine…</span>
|
|
1389
1389
|
: logs.map((line, i) => <LogLine key={i} text={line} />)}
|
|
1390
1390
|
</div>
|
|
1391
1391
|
</div>
|
|
@@ -1400,14 +1400,14 @@ export default function RenderModal<P extends Project = Project>({ projectId, ad
|
|
|
1400
1400
|
<div className="relative">
|
|
1401
1401
|
<button
|
|
1402
1402
|
onClick={() => navigator.clipboard.writeText(logs.join('\n') + (errorMsg ? '\n' + errorMsg : ''))}
|
|
1403
|
-
className="absolute top-2 right-2 z-10 rounded border border-white/10 bg-[#0a0e17] px-2 py-0.5 text-[10px] text-[var(--editor-text)]
|
|
1403
|
+
className="absolute top-2 right-2 z-10 rounded border border-white/10 bg-[#0a0e17] px-2 py-0.5 text-[10px] text-[color-mix(in_srgb,var(--editor-text)_60%,transparent)] hover:text-[var(--editor-text)] transition-colors"
|
|
1404
1404
|
title="Copy logs"
|
|
1405
1405
|
>
|
|
1406
1406
|
Copy
|
|
1407
1407
|
</button>
|
|
1408
1408
|
<div
|
|
1409
1409
|
ref={logRef}
|
|
1410
|
-
className="flex h-72 flex-col gap-0.5 overflow-y-auto rounded-lg border border-white/10 bg-[#0a0e17] px-3 py-2 font-mono text-[11px] text-[var(--editor-text)]
|
|
1410
|
+
className="flex h-72 flex-col gap-0.5 overflow-y-auto rounded-lg border border-white/10 bg-[#0a0e17] px-3 py-2 font-mono text-[11px] text-[color-mix(in_srgb,var(--editor-text)_80%,transparent)]"
|
|
1411
1411
|
>
|
|
1412
1412
|
{logs.map((line, i) => <LogLine key={i} text={line} />)}
|
|
1413
1413
|
{errorMsg && <span className="mt-1 text-red-400">{errorMsg}</span>}
|
|
@@ -1426,7 +1426,7 @@ export default function RenderModal<P extends Project = Project>({ projectId, ad
|
|
|
1426
1426
|
{status === 'running' ? (
|
|
1427
1427
|
<button
|
|
1428
1428
|
onClick={handleCancel}
|
|
1429
|
-
className={`text-sm px-4 py-1.5 rounded-md bg-[#0e131f] border border-white/10 text-[var(--editor-text)]
|
|
1429
|
+
className={`text-sm px-4 py-1.5 rounded-md bg-[#0e131f] border border-white/10 text-[color-mix(in_srgb,var(--editor-text)_80%,transparent)] transition-colors ${mode === 'light' ? 'hover:bg-red-50 hover:border-red-300 hover:text-red-700' : 'hover:bg-red-900/40 hover:border-red-700 hover:text-red-300'}`}
|
|
1430
1430
|
>
|
|
1431
1431
|
Cancel
|
|
1432
1432
|
</button>
|
|
@@ -86,7 +86,7 @@ function VersionFramePane({
|
|
|
86
86
|
|
|
87
87
|
return (
|
|
88
88
|
<div className="flex-1 min-w-0 flex flex-col gap-1.5">
|
|
89
|
-
<span className="text-[11px] font-medium text-[var(--editor-text)]
|
|
89
|
+
<span className="text-[11px] font-medium text-[color-mix(in_srgb,var(--editor-text)_60%,transparent)] truncate" title={label}>
|
|
90
90
|
{label}
|
|
91
91
|
</span>
|
|
92
92
|
<div className="relative aspect-video w-full overflow-hidden rounded-lg border border-[var(--editor-border)] bg-[var(--editor-bg)] flex items-center justify-center">
|
|
@@ -101,7 +101,7 @@ function VersionFramePane({
|
|
|
101
101
|
style={error ? { display: 'none' } : undefined}
|
|
102
102
|
/>
|
|
103
103
|
{loading && !error && (
|
|
104
|
-
<span className="absolute inset-0 flex items-center justify-center text-xs text-[var(--editor-text)]
|
|
104
|
+
<span className="absolute inset-0 flex items-center justify-center text-xs text-[color-mix(in_srgb,var(--editor-text)_50%,transparent)]">
|
|
105
105
|
Loading…
|
|
106
106
|
</span>
|
|
107
107
|
)}
|
|
@@ -178,7 +178,7 @@ export default function VersionCompare({
|
|
|
178
178
|
<button
|
|
179
179
|
onClick={onClose}
|
|
180
180
|
aria-label="Close"
|
|
181
|
-
className="text-[var(--editor-text)]
|
|
181
|
+
className="text-[color-mix(in_srgb,var(--editor-text)_55%,transparent)] hover:text-[var(--editor-text)] transition-colors text-lg leading-none"
|
|
182
182
|
>
|
|
183
183
|
×
|
|
184
184
|
</button>
|
|
@@ -190,7 +190,7 @@ export default function VersionCompare({
|
|
|
190
190
|
{/* Picker row */}
|
|
191
191
|
<div className="flex flex-col sm:flex-row gap-3">
|
|
192
192
|
<label className="flex-1 min-w-0 flex flex-col gap-1.5">
|
|
193
|
-
<span className="text-[11px] font-semibold uppercase tracking-wide text-[var(--editor-text)]
|
|
193
|
+
<span className="text-[11px] font-semibold uppercase tracking-wide text-[color-mix(in_srgb,var(--editor-text)_50%,transparent)]">Left</span>
|
|
194
194
|
<select
|
|
195
195
|
value={leftHash}
|
|
196
196
|
onChange={(e) => setLeftHash(e.target.value)}
|
|
@@ -202,7 +202,7 @@ export default function VersionCompare({
|
|
|
202
202
|
</select>
|
|
203
203
|
</label>
|
|
204
204
|
<label className="flex-1 min-w-0 flex flex-col gap-1.5">
|
|
205
|
-
<span className="text-[11px] font-semibold uppercase tracking-wide text-[var(--editor-text)]
|
|
205
|
+
<span className="text-[11px] font-semibold uppercase tracking-wide text-[color-mix(in_srgb,var(--editor-text)_50%,transparent)]">Right</span>
|
|
206
206
|
<select
|
|
207
207
|
value={rightHash}
|
|
208
208
|
onChange={(e) => setRightHash(e.target.value)}
|
|
@@ -238,8 +238,8 @@ export default function VersionCompare({
|
|
|
238
238
|
{/* Time-scrub slider */}
|
|
239
239
|
<div className="flex flex-col gap-1.5">
|
|
240
240
|
<div className="flex items-center justify-between">
|
|
241
|
-
<span className="text-[11px] font-semibold uppercase tracking-wide text-[var(--editor-text)]
|
|
242
|
-
<span className="text-xs text-[var(--editor-text)]
|
|
241
|
+
<span className="text-[11px] font-semibold uppercase tracking-wide text-[color-mix(in_srgb,var(--editor-text)_50%,transparent)]">Time</span>
|
|
242
|
+
<span className="text-xs text-[color-mix(in_srgb,var(--editor-text)_60%,transparent)] tabular-nums">{formatT(t)}</span>
|
|
243
243
|
</div>
|
|
244
244
|
<Slider
|
|
245
245
|
min={0}
|
|
@@ -87,7 +87,7 @@ export default function VersionPanel({ versions, restoring, onRestore, onSaveVer
|
|
|
87
87
|
IS the list. The count sits on the right as an explicit "N versions"
|
|
88
88
|
label so it reads as a quantity rather than part of the title. */}
|
|
89
89
|
<div className="shrink-0 flex items-center justify-between px-3 py-2 border-b border-[var(--editor-border)]">
|
|
90
|
-
<span className="text-xs font-medium text-[var(--editor-text)]
|
|
90
|
+
<span className="text-xs font-medium text-[color-mix(in_srgb,var(--editor-text)_60%,transparent)] uppercase tracking-wide">Versions</span>
|
|
91
91
|
{rows.length > 0 && (
|
|
92
92
|
<span className="text-[10px] text-[var(--editor-text)] opacity-50">
|
|
93
93
|
{rows.length} {rows.length === 1 ? 'version' : 'versions'}
|
|
@@ -106,7 +106,7 @@ export default function VersionPanel({ versions, restoring, onRestore, onSaveVer
|
|
|
106
106
|
onChange={e => setNameInput(e.target.value)}
|
|
107
107
|
placeholder="Name (optional)"
|
|
108
108
|
disabled={saving || !onSaveVersion}
|
|
109
|
-
className="min-w-0 flex-1 h-8 text-[11px] bg-[var(--editor-bg)] border border-[var(--editor-border)] rounded-md px-2 text-[var(--editor-text)] placeholder:text-[var(--editor-text)]
|
|
109
|
+
className="min-w-0 flex-1 h-8 text-[11px] bg-[var(--editor-bg)] border border-[var(--editor-border)] rounded-md px-2 text-[var(--editor-text)] placeholder:text-[color-mix(in_srgb,var(--editor-text)_40%,transparent)] focus:outline-none focus:border-[var(--editor-accent)] disabled:opacity-40"
|
|
110
110
|
/>
|
|
111
111
|
<button
|
|
112
112
|
onClick={handleSaveClick}
|