Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ export const CaptionAnimationPanel = memo(function CaptionAnimationPanel() {
<div className="flex flex-col h-full min-h-0">
{gated && (
<div className="shrink-0 mx-3 mt-2 px-2 py-1.5 rounded-sm border border-amber-500/30 bg-amber-500/10">
<p className="text-2xs text-amber-300/90 leading-snug">
<p className="text-2xs text-warning-ink leading-snug">
Animation editing isn&apos;t applied to playback or saved yet, so these controls are
disabled.
</p>
Expand Down Expand Up @@ -292,7 +292,7 @@ export const CaptionAnimationPanel = memo(function CaptionAnimationPanel() {
onClick={handleApplyToAll}
disabled={gated}
title={gated ? "Disabled until animation editing is applied to playback" : undefined}
className="w-full py-1.5 rounded-sm border border-neutral-700 text-2xs text-neutral-300 hover:border-studio-accent/50 hover:text-studio-accent transition-colors disabled:opacity-40 disabled:cursor-not-allowed disabled:hover:border-neutral-700 disabled:hover:text-neutral-300"
className="w-full py-1.5 rounded-sm border border-neutral-700 text-2xs text-neutral-300 hover:border-studio-accent/50 hover:text-accent-ink transition-colors disabled:opacity-40 disabled:cursor-not-allowed disabled:hover:border-neutral-700 disabled:hover:text-neutral-300"
>
Apply to all groups
</button>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ export const CaptionPropertyPanel = memo(function CaptionPropertyPanel({
className={[
"flex-1 py-0.5 rounded-sm text-2xs font-medium transition-colors",
activeTab === "style"
? "bg-studio-accent/20 text-studio-accent border border-studio-accent/50"
? "bg-studio-accent/20 text-accent-ink border border-studio-accent/50"
: "text-neutral-500 border border-neutral-800 hover:text-neutral-300 hover:border-neutral-600",
].join(" ")}
>
Expand All @@ -241,7 +241,7 @@ export const CaptionPropertyPanel = memo(function CaptionPropertyPanel({
className={[
"flex-1 py-0.5 rounded-sm text-2xs font-medium transition-colors",
activeTab === "animation"
? "bg-studio-accent/20 text-studio-accent border border-studio-accent/50"
? "bg-studio-accent/20 text-accent-ink border border-studio-accent/50"
: "text-neutral-500 border border-neutral-800 hover:text-neutral-300 hover:border-neutral-600",
].join(" ")}
>
Expand Down
6 changes: 3 additions & 3 deletions packages/studio/src/captions/components/CaptionTimeline.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,8 @@ export const CaptionTimeline = memo(function CaptionTimeline({
tabIndex={0}
aria-label={`Caption word "${seg.text}"`}
aria-pressed={isSelected}
className={`absolute top-1 bottom-1 rounded flex items-center overflow-hidden cursor-pointer focus-visible:ring-1 focus-visible:ring-white outline-hidden${
isSelected ? " ring-1 ring-white/50 z-10" : ""
className={`absolute top-1 bottom-1 rounded flex items-center overflow-hidden cursor-pointer focus-visible:ring-1 focus-visible:ring-text-0 outline-hidden${
isSelected ? " ring-1 ring-text-0/50 z-10" : ""
}`}
style={{
left,
Expand All @@ -135,7 +135,7 @@ export const CaptionTimeline = memo(function CaptionTimeline({

{/* Playhead — correlates blocks with the current frame */}
<div
className="absolute top-0 bottom-0 w-px bg-white/70 pointer-events-none z-20"
className="absolute top-0 bottom-0 w-px bg-text-0/70 pointer-events-none z-20"
style={{ left: playheadLeft }}
aria-hidden="true"
/>
Expand Down
2 changes: 1 addition & 1 deletion packages/studio/src/components/AskAgentModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ export function AskAgentModal({
{navigator.platform.includes("Mac") ? "⌘" : "Ctrl"}+Enter to copy
</span>
<button
className="px-4 py-1.5 rounded-lg bg-studio-accent/90 text-xs font-medium text-neutral-950 hover:bg-studio-accent disabled:opacity-40 disabled:cursor-not-allowed"
className="px-4 py-1.5 rounded-lg bg-accent text-xs font-medium text-on-accent hover:bg-accent-hover disabled:opacity-40 disabled:cursor-not-allowed"
disabled={!value.trim()}
onClick={handleSubmit}
>
Expand Down
70 changes: 35 additions & 35 deletions packages/studio/src/components/LintModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -75,11 +75,11 @@ export function LintModal({
<div className="flex items-center gap-3">
{hasIssues ? (
<div className="w-8 h-8 rounded-full bg-red-500/10 flex items-center justify-center">
<WarningIcon size={18} className="text-red-400" weight="fill" />
<WarningIcon size={18} className="text-danger-ink" weight="fill" />
</div>
) : (
<div className="w-8 h-8 rounded-full bg-studio-accent/10 flex items-center justify-center">
<CheckCircleIcon size={18} className="text-studio-accent" weight="fill" />
<CheckCircleIcon size={18} className="text-accent-ink" weight="fill" />
</div>
)}
<div>
Expand Down Expand Up @@ -107,10 +107,10 @@ export function LintModal({
onClick={handleCopyToAgent}
className={`px-3 py-1 text-xs font-medium rounded-lg transition-colors active:scale-[0.98] ${
copied
? "bg-green-600 text-white"
? "bg-accent text-on-accent"
: copyFailed
? "bg-red-600 text-white"
: "bg-studio-accent hover:bg-studio-accent/80 text-white"
? "bg-danger text-on-danger"
: "bg-accent hover:bg-accent-hover text-on-accent"
}`}
>
{copied
Expand All @@ -128,41 +128,41 @@ export function LintModal({
</div>
)}
{errors.map((f, i) => (
<div key={`e-${i}`} className="py-3 border-b border-neutral-800/50 last:border-0">
<div className="flex items-start gap-2">
<WarningIcon size={14} className="text-red-400 shrink-0 mt-0.5" weight="fill" />
<div className="min-w-0">
<p className="text-sm text-neutral-200">{f.message}</p>
{f.file && <p className="text-xs text-neutral-600 font-mono mt-0.5">{f.file}</p>}
{f.fixHint && (
<div className="flex items-start gap-1 mt-1.5">
<CaretRightIcon size={10} className="text-studio-accent shrink-0 mt-0.5" />
<p className="text-xs text-studio-accent">{f.fixHint}</p>
</div>
)}
</div>
</div>
</div>
<LintFindingRow key={`e-${i}`} finding={f} tone="error" />
))}
{warnings.map((f, i) => (
<div key={`w-${i}`} className="py-3 border-b border-neutral-800/50 last:border-0">
<div className="flex items-start gap-2">
<WarningIcon size={14} className="text-amber-400 shrink-0 mt-0.5" />
<div className="min-w-0">
<p className="text-sm text-neutral-300">{f.message}</p>
{f.file && <p className="text-xs text-neutral-600 font-mono mt-0.5">{f.file}</p>}
{f.fixHint && (
<div className="flex items-start gap-1 mt-1.5">
<CaretRightIcon size={10} className="text-studio-accent shrink-0 mt-0.5" />
<p className="text-xs text-studio-accent">{f.fixHint}</p>
</div>
)}
</div>
</div>
</div>
<LintFindingRow key={`w-${i}`} finding={f} tone="warning" />
))}
</div>
</div>
</div>
);
}

function LintFindingRow({ finding, tone }: { finding: LintFinding; tone: "error" | "warning" }) {
return (
<div className="py-3 border-b border-border last:border-0">
<div className="flex items-start gap-2">
<WarningIcon
size={14}
className={`${tone === "error" ? "text-danger-ink" : "text-warning-ink"} shrink-0 mt-0.5`}
weight={tone === "error" ? "fill" : undefined}
/>
<div className="min-w-0">
<p className={`text-sm ${tone === "error" ? "text-text-0" : "text-text-2"}`}>
{finding.message}
</p>
{finding.file && (
<p className="text-xs text-text-muted font-mono mt-0.5">{finding.file}</p>
)}
{finding.fixHint && (
<div className="flex items-start gap-1 mt-1.5">
<CaretRightIcon size={10} className="text-accent-ink shrink-0 mt-0.5" />
<p className="text-xs text-accent-ink">{finding.fixHint}</p>
</div>
)}
</div>
</div>
</div>
);
}
2 changes: 1 addition & 1 deletion packages/studio/src/components/StudioErrorBoundary.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export class StudioErrorBoundary extends Component<Props, State> {
<div className="mt-2 flex items-center gap-2">
<button
onClick={() => this.setState({ error: null })}
className="rounded-md bg-studio-accent px-5 py-2 text-sm font-medium text-neutral-950 transition-[filter] hover:brightness-110 active:scale-[0.98]"
className="rounded-md bg-accent px-5 py-2 text-sm font-medium text-on-accent transition-colors hover:bg-accent-hover active:scale-[0.98]"
>
Try again
</button>
Expand Down
8 changes: 4 additions & 4 deletions packages/studio/src/components/StudioHeader.dom.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -139,16 +139,16 @@ it("shows Inspector pressed and filled only when on", () => {
const host = mount({ inspectorButtonActive: true });
const on = query(host, '[aria-label="Inspector"]');
expect(on.getAttribute("aria-pressed")).toBe("true");
expect(hasToken(on.className, "text-accent")).toBe(true);
expect(hasToken(on.className, "bg-hover")).toBe(true);
expect(hasToken(on.className, "text-accent-ink")).toBe(true);
expect(hasToken(on.className, "bg-on")).toBe(true);
act(() => mounted?.root.unmount());
mounted?.host.remove();
mounted = null;

const off = query(mount(), '[aria-label="Inspector"]');
expect(off.getAttribute("aria-pressed")).toBe("false");
expect(hasToken(off.className, "text-accent")).toBe(false);
expect(hasToken(off.className, "bg-hover")).toBe(false);
expect(hasToken(off.className, "text-accent-ink")).toBe(false);
expect(hasToken(off.className, "bg-on")).toBe(false);
});

it("keeps Capture a real download link rather than a button", () => {
Expand Down
3 changes: 2 additions & 1 deletion packages/studio/src/components/StudioHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,8 @@ export function StudioHeader({
aria-pressed={inspectorButtonActive}
className={cn(
"h-full rounded-none",
inspectorButtonActive && "bg-hover text-accent enabled:hover:text-accent",
inspectorButtonActive &&
"bg-on text-accent-ink enabled:hover:bg-on-hover enabled:hover:text-accent-ink",
)}
icon={<InspectorIcon size={16} />}
onClick={() => {
Expand Down
23 changes: 7 additions & 16 deletions packages/studio/src/components/StudioToast.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,31 +14,18 @@ export function StudioToast({ message, tone, leaving, onDismiss }: StudioToastPr
className={`motion-reduce:animate-none ${leaving ? "hf-toast-exit" : "hf-toast-enter"}`}
>
<div
className="relative flex max-w-[min(420px,calc(100vw-48px))] items-center gap-3 overflow-hidden rounded-2xl py-3 pl-4 pr-2 text-[12px]"
style={{
background: isError
? "linear-gradient(135deg, rgba(127,29,29,0.55), rgba(80,10,10,0.45))"
: "linear-gradient(135deg, rgba(38,38,38,0.55), rgba(23,23,23,0.45))",
backdropFilter: "blur(16px) saturate(1.6)",
WebkitBackdropFilter: "blur(16px) saturate(1.6)",
border: `1px solid ${isError ? "rgba(239,68,68,0.18)" : "rgba(255,255,255,0.08)"}`,
boxShadow: [
"0 8px 32px rgba(0,0,0,0.35)",
`inset 0 1px 0 ${isError ? "rgba(239,68,68,0.12)" : "rgba(255,255,255,0.06)"}`,
`inset 0 -1px 0 rgba(0,0,0,0.15)`,
].join(", "),
}}
className={`relative flex max-w-[min(420px,calc(100vw-48px))] items-center gap-3 overflow-hidden rounded-2xl py-3 pl-4 pr-2 text-[12px] ${toastSurface(isError)}`}
>
<span
className={`min-w-0 wrap-break-word leading-5 ${isError ? "text-red-200" : "text-neutral-200"}`}
className={`min-w-0 wrap-break-word leading-5 ${isError ? "text-danger-ink" : "text-text-0"}`}
>
{message}
</span>
{onDismiss && (
<button
type="button"
onClick={onDismiss}
className="flex h-5 w-5 shrink-0 items-center justify-center rounded-md text-neutral-500 transition-colors hover:bg-white/10 hover:text-neutral-300"
className="flex h-5 w-5 shrink-0 items-center justify-center rounded-md text-neutral-500 transition-colors hover:bg-hover hover:text-neutral-300"
aria-label="Dismiss"
>
<svg
Expand All @@ -57,3 +44,7 @@ export function StudioToast({ message, tone, leaving, onDismiss }: StudioToastPr
</div>
);
}

export function toastSurface(isError: boolean): string {
return `border shadow-popover backdrop-blur-md ${isError ? "border-danger/40 bg-raised" : "border-border bg-raised/95"}`;
}
2 changes: 1 addition & 1 deletion packages/studio/src/components/TimelineToolPicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ export function TimelineToolPicker({ showSelectAroundPlayhead = true }) {
shortcut={row.shortcut}
onClick={row.run}
data-active={row.active || undefined}
className={row.active ? "bg-neutral-800 text-white" : undefined}
className={row.active ? "bg-press text-text-0" : undefined}
>
<span className="flex items-center gap-2">
{row.icon}
Expand Down
22 changes: 11 additions & 11 deletions packages/studio/src/components/TimelineToolbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -307,11 +307,11 @@ export function TimelineToolbar({
className={
!onToggleKeyframe
? flatDisabled
: `${flatBtn} active:scale-[0.98] hover:bg-white/6 ${
: `${flatBtn} active:scale-[0.98] hover:bg-hover ${
keyframeState === "active"
? "text-studio-accent"
? "text-accent-ink"
: keyframeState === "inactive"
? "text-neutral-400 hover:text-studio-accent"
? "text-neutral-400 hover:text-accent-ink"
: "text-neutral-600 hover:text-neutral-400"
}`
}
Expand Down Expand Up @@ -342,9 +342,9 @@ export function TimelineToolbar({
onClick={() => setAutoKeyframeEnabled(!autoKeyframeEnabled)}
aria-label="Auto-record manual edits as keyframes"
aria-pressed={autoKeyframeEnabled}
className={`${flatBtn} active:scale-[0.98] hover:bg-white/6 ${
className={`${flatBtn} active:scale-[0.98] hover:bg-hover ${
autoKeyframeEnabled
? "text-red-400 hover:text-red-300"
? "text-danger-ink"
: "text-neutral-600 hover:text-neutral-400"
}`}
>
Expand Down Expand Up @@ -442,7 +442,7 @@ export function TimelineToolbar({
}}
className={
canAdd
? `${flatBtn} text-neutral-400 hover:bg-white/6 hover:text-[#22c55e] active:scale-[0.98]`
? `${flatBtn} text-text-2 hover:bg-hover hover:text-accent-ink active:scale-[0.98]`
: flatDisabled
}
>
Expand Down Expand Up @@ -479,8 +479,8 @@ export function TimelineToolbar({
onClick={() => setThumbnailMode(thumbnailsVisible ? "hidden" : "adaptive")}
className={`h-7 px-2 rounded-md text-[11px] font-medium transition-colors ${
thumbnailsVisible
? "bg-studio-accent/10 text-studio-accent"
: "text-neutral-400 hover:bg-white/6 hover:text-neutral-200"
? "bg-studio-accent/10 text-accent-ink"
: "text-neutral-400 hover:bg-hover hover:text-neutral-200"
}`}
>
<Image size={16} aria-hidden="true" />
Expand All @@ -494,8 +494,8 @@ export function TimelineToolbar({
aria-pressed={zoomMode === "fit"}
className={`h-7 px-2 rounded-md text-[11px] font-medium transition-colors ${
zoomMode === "fit"
? "bg-studio-accent/10 text-studio-accent"
: "text-neutral-400 hover:bg-white/6 hover:text-neutral-200"
? "bg-studio-accent/10 text-accent-ink"
: "text-neutral-400 hover:bg-hover hover:text-neutral-200"
}`}
>
<ArrowsOutLineHorizontal size={16} aria-hidden="true" />
Expand Down Expand Up @@ -531,7 +531,7 @@ export function TimelineToolbar({
}}
// h-6 on the input is the 24x24 WCAG 2.2 (2.5.8) target: the visible
// track stays 2px and the thumb 10px, only the pointer box grows.
className="mx-1 h-6 w-[96px] cursor-pointer appearance-none bg-transparent [&::-webkit-slider-runnable-track]:h-[2px] [&::-webkit-slider-runnable-track]:rounded-full [&::-webkit-slider-runnable-track]:bg-neutral-700 [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:w-[10px] [&::-webkit-slider-thumb]:h-[10px] [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:bg-white [&::-webkit-slider-thumb]:-mt-1 [&::-webkit-slider-thumb]:shadow-[0_0_0_2px_#0a0a0a,0_1px_3px_rgba(0,0,0,0.5)] [&::-webkit-slider-thumb]:cursor-grab [&::-webkit-slider-thumb:active]:cursor-grabbing"
className="mx-1 h-6 w-[96px] cursor-pointer appearance-none bg-transparent [&::-webkit-slider-runnable-track]:h-[2px] [&::-webkit-slider-runnable-track]:rounded-full [&::-webkit-slider-runnable-track]:bg-neutral-700 [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:w-[10px] [&::-webkit-slider-thumb]:h-[10px] [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:bg-text-0 [&::-webkit-slider-thumb]:-mt-1 [&::-webkit-slider-thumb]:shadow-[0_0_0_2px_#0a0a0a,0_1px_3px_rgba(0,0,0,0.5)] [&::-webkit-slider-thumb]:cursor-grab [&::-webkit-slider-thumb:active]:cursor-grabbing"
/>
<Tooltip label="Zoom in">
<button
Expand Down
2 changes: 1 addition & 1 deletion packages/studio/src/components/dock/Dock.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,7 @@ function WindowMenu() {
onClick={() => togglePanel(id)}
className="flex w-full items-center gap-2 px-3 py-1.5 text-left text-[11px] text-neutral-300 hover:bg-neutral-800"
>
<span className="w-3 text-panel-accent">{openPanels.has(id) ? "✓" : ""}</span>
<span className="w-3 text-accent-ink">{openPanels.has(id) ? "✓" : ""}</span>
{PANEL_DEFINITIONS[id].title}
</button>
))}
Expand Down
10 changes: 9 additions & 1 deletion packages/studio/src/components/dock/dock.css
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
@import "dockview-react/dist/styles/dockview.css";

.dv-shell:has(.hf-dock) {
/* dockview's runtime stylesheet pins `color-scheme: dark` on its theme class, which sits on
* the shell around the dock. */
color-scheme: inherit;
}

.hf-dock {
--dv-group-view-background-color: var(--panel-card-bg);
--dv-tabs-and-actions-container-background-color: var(--panel-strip-bg);
--dv-tabs-and-actions-container-height: 36px;
--dv-icon-hover-background-color: var(--color-hover);
--dv-tabs-container-scrollbar-color: var(--color-text-muted);
/* The fill paints the shown tab, so every tab state is transparent. */
--dv-activegroup-visiblepanel-tab-background-color: transparent;
--dv-activegroup-hiddenpanel-tab-background-color: transparent;
Expand Down Expand Up @@ -178,7 +186,7 @@
}

.dv-groupview:hover .hf-dock-strip-actions {
opacity: 0.5;
opacity: 0.8;
}

.hf-dock-strip-actions:hover,
Expand Down
Loading
Loading