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
14 changes: 14 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,20 @@
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title></title>
<script>
// Apply the stored theme before first paint — src/hooks/useTheme.ts
// does the same thing, but only once the editor's code-split chunk
// mounts and its useEffect runs. Left to that alone, a dark-theme
// user sees the CSS-token-driven UI (the Suspense fallback, etc.)
// flash light on every load, since design-tokens.css's :root:root
// block (light) applies until data-theme="dark" lands.
try {
if (localStorage.getItem("openscreen-theme") === "dark") {
document.documentElement.setAttribute("data-theme", "dark");
document.documentElement.classList.add("dark");
}
} catch {}
</script>
</head>
<body style="background:#09090b;margin:0">
<div id="root"></div>
Expand Down
6 changes: 3 additions & 3 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -116,9 +116,9 @@ export default function App() {
<EditorDialogsProvider>
<Suspense
fallback={
<div className="flex flex-col items-center justify-center gap-3 h-screen bg-[#09090b]">
<div className="flex flex-col items-center justify-center gap-3 h-screen bg-[var(--bg)]">
<svg
className="animate-spin text-[#34B27B]"
className="animate-spin text-[var(--brand)]"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
Expand All @@ -139,7 +139,7 @@ export default function App() {
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"
/>
</svg>
<span className="text-white/50 text-sm">{tEditor("loadingEditor")}</span>
<span className="text-[var(--muted)] text-sm">{tEditor("loadingEditor")}</span>
</div>
}
>
Expand Down
2 changes: 1 addition & 1 deletion src/components/ai-edition/LeftPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1952,7 +1952,7 @@ function ChatStripPanel() {
background: "var(--accent)",
border: "1px solid var(--accent)",
borderRadius: "var(--r-sm)",
color: "var(--bg)",
color: "var(--accent-on)",
font: "500 12px var(--font-body)",
cursor: "pointer",
}}
Expand Down
2 changes: 1 addition & 1 deletion src/components/ai-edition/NewEditorShell.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -594,7 +594,7 @@
padding: var(--sp-3) var(--sp-4);
border-radius: var(--r-sm);
background: var(--primary, #34B27B);
color: #fff;
color: var(--accent-on);
border: none;
font-weight: 500;
font-size: 0.875rem;
Expand Down
29 changes: 16 additions & 13 deletions src/components/ai-edition/RightPanes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -143,22 +143,25 @@ function Pane({ title, icon, helpText, children }: PaneProps) {

// keep the gradient palette small and curated — every block renders
// in the picker and gets serialized to legacyEditor on save.
// Spans the same hues as COLOR_PALETTE below rather than leaning on the
// brand mint for half the grid — a wall of green reads as "we only
// have one color" rather than "pick a gradient."
const GRAD_PRESETS: readonly string[] = [
"linear-gradient(135deg, #eaebed, #bcc0c6)",
"linear-gradient(135deg, #10b981, #eaebed)",
"linear-gradient(135deg, #6b7280, #bcc0c6)",
"linear-gradient(135deg, #eaebed, #10b981)",
"linear-gradient(135deg, #16171d, #6b7280)",
"linear-gradient(135deg, #bcc0c6, #16171d)",
"linear-gradient(135deg, #10b981, #6b7280)",
"linear-gradient(135deg, #eaebed, #10b981)",
"linear-gradient(135deg, #3b82f6, #8b5cf6)",
"linear-gradient(135deg, #8b5cf6, #ec4899)",
"linear-gradient(135deg, #f97316, #ec4899)",
"linear-gradient(135deg, #f59e0b, #f97316)",
"linear-gradient(135deg, #10b981, #3b82f6)",
"linear-gradient(135deg, #22c55e, #10b981)",
"linear-gradient(135deg, #6b7280, #16171d)",
"linear-gradient(135deg, #bcc0c6, #10b981)",
"linear-gradient(135deg, #16171d, #6b7280)",
"linear-gradient(135deg, #eaebed, #bcc0c6)",
"linear-gradient(135deg, #10b981, #bcc0c6)",
"linear-gradient(135deg, #eaebed, #16171d)",
"linear-gradient(135deg, #6b7280, #10b981)",
"linear-gradient(135deg, #ec4899, #ef4444)",
"linear-gradient(135deg, #3b82f6, #22c55e)",
"linear-gradient(135deg, #8b5cf6, #3b82f6)",
"linear-gradient(135deg, #f59e0b, #ef4444)",
"linear-gradient(135deg, #16171d, #1e293b)",
"linear-gradient(135deg, #34d399, #3b82f6)",
"linear-gradient(135deg, #ef4444, #8b5cf6)",
"linear-gradient(135deg, #bcc0c6, #eaebed)",
];

Expand Down
1 change: 1 addition & 0 deletions src/components/ai-edition/VirtualPreview.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@

.iconButton:hover:not(:disabled) {
background: var(--accent);
color: var(--accent-on);
}

.iconButton:disabled {
Expand Down
5 changes: 3 additions & 2 deletions src/components/ai-edition/v4/EditorShellV4.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,7 @@
padding: 0 14px;
border-radius: 9px;
background: var(--accent);
color: #fff;
color: var(--accent-on);
border: 1px solid var(--accent);
font-size: 13px;
font-weight: 600;
Expand Down Expand Up @@ -1126,7 +1126,7 @@
padding: 0 26px;
border-radius: 16px;
border: 1px solid var(--accent);
color: #fff;
color: var(--accent-on);
background: var(--accent);
font-size: 14px;
font-weight: 600;
Expand All @@ -1140,6 +1140,7 @@
.bigRecBtn.recording {
border-color: var(--danger);
background: var(--danger);
color: #fff;
}
.bigRecDot {
width: 10px;
Expand Down
2 changes: 1 addition & 1 deletion src/components/ai-edition/v4/MediaStage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@ export function MediaStage({
borderRadius: 9,
border: "1px solid var(--accent)",
background: "var(--accent)",
color: "var(--on-accent, #fff)",
color: "var(--accent-on)",
fontSize: 12.5,
fontWeight: 650,
cursor: "pointer",
Expand Down
17 changes: 10 additions & 7 deletions src/components/ui/gradient-editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -462,7 +462,7 @@ export default function GradientEditor({ onChange }: GradientEditorProps) {
aria-valuemin={0}
aria-valuemax={360}
aria-valuenow={Math.round(((mainAngle % 360) + 360) % 360)}
className="absolute w-11 h-11 rounded-full cursor-grab shadow-[0_0_0_4px_#f5f5f5,0_4px_14px_rgba(0,0,0,0.35)] transition-shadow z-10 active:cursor-grabbing focus:outline-none focus:ring-2 focus:ring-[#34B27B]"
className="absolute w-11 h-11 rounded-full cursor-grab shadow-[0_0_0_4px_#f5f5f5,0_4px_14px_rgba(0,0,0,0.35)] transition-shadow z-10 active:cursor-grabbing focus:outline-none focus:ring-2 focus:ring-[var(--brand)]"
style={{
left: `${mainX}%`,
top: `${mainY}%`,
Expand All @@ -478,7 +478,7 @@ export default function GradientEditor({ onChange }: GradientEditorProps) {
type="button"
onClick={addPoint}
disabled={totalColors >= MAX_COLORS}
className={`w-6 h-6 rounded-full flex items-center justify-center border-none bg-transparent transition-all text-white/60 hover:text-white ${
className={`w-6 h-6 rounded-full flex items-center justify-center border-none bg-transparent transition-all text-white/80 hover:text-white ${
totalColors >= MAX_COLORS
? "opacity-40 cursor-not-allowed"
: "hover:bg-white/10 cursor-pointer"
Expand All @@ -492,7 +492,7 @@ export default function GradientEditor({ onChange }: GradientEditorProps) {
type="button"
onClick={removePoint}
disabled={totalColors <= 1}
className={`w-6 h-6 rounded-full flex items-center justify-center border-none bg-transparent transition-all text-white/60 hover:text-white ${
className={`w-6 h-6 rounded-full flex items-center justify-center border-none bg-transparent transition-all text-white/80 hover:text-white ${
totalColors <= 1
? "opacity-40 cursor-not-allowed"
: "hover:bg-white/10 cursor-pointer"
Expand All @@ -506,7 +506,7 @@ export default function GradientEditor({ onChange }: GradientEditorProps) {
type="button"
onClick={cycleHarmony}
disabled={eligibleHarmonies.length <= 1}
className={`w-6 h-6 rounded-full flex items-center justify-center border-none bg-transparent transition-all text-white/60 hover:text-white ${
className={`w-6 h-6 rounded-full flex items-center justify-center border-none bg-transparent transition-all text-white/80 hover:text-white ${
eligibleHarmonies.length <= 1
? "opacity-40 cursor-not-allowed"
: "hover:bg-white/10 cursor-pointer"
Expand All @@ -520,7 +520,10 @@ export default function GradientEditor({ onChange }: GradientEditorProps) {

{/* Bottom controls: Brightness + Angle */}
<div className="flex items-center gap-3.5 mt-3.5">
{/* Brightness wavy slider */}
{/* Brightness wavy slider. Its thumb/track are colored for the dark
canvas above, so it needs its own dark backing here too — this row
otherwise sits directly on the (theme-dependent) popover background,
where the light thumb disappears in light mode. */}
<div
ref={trackRef}
onPointerDown={onSliderPointerDown}
Expand All @@ -531,7 +534,7 @@ export default function GradientEditor({ onChange }: GradientEditorProps) {
aria-valuemin={0}
aria-valuemax={100}
aria-valuenow={Math.round(brightness)}
className="relative flex-1 h-10 flex items-center cursor-pointer focus:outline-none focus:ring-2 focus:ring-[#34B27B] rounded"
className="relative flex-1 h-10 flex items-center cursor-pointer bg-[#141414] rounded-full focus:outline-none focus:ring-2 focus:ring-[var(--brand)]"
>
<svg
width="100%"
Expand Down Expand Up @@ -571,7 +574,7 @@ export default function GradientEditor({ onChange }: GradientEditorProps) {
aria-valuemin={0}
aria-valuemax={360}
aria-valuenow={angle}
className="relative w-[42px] h-[42px] rounded-full bg-[radial-gradient(circle_at_35%_30%,#2b2b2b,#0c0c0c)] shadow-[0_3px_10px_rgba(0,0,0,0.4)] cursor-grab flex-shrink-0 active:cursor-grabbing focus:outline-none focus:ring-2 focus:ring-[#34B27B]"
className="relative w-[42px] h-[42px] rounded-full bg-[radial-gradient(circle_at_35%_30%,#2b2b2b,#0c0c0c)] shadow-[0_3px_10px_rgba(0,0,0,0.4)] cursor-grab flex-shrink-0 active:cursor-grabbing focus:outline-none focus:ring-2 focus:ring-[var(--brand)]"
title="Gradient angle"
>
<div className="absolute inset-0" style={{ transform: `rotate(${angleKnobAngle}deg)` }}>
Expand Down
38 changes: 19 additions & 19 deletions src/components/video-editor/ShortcutsConfigDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -138,26 +138,26 @@ export function ShortcutsConfigDialog() {
if (!open) handleClose();
}}
>
<DialogContent className="bg-[#09090b] border-white/10 text-white max-w-[420px] max-h-[85vh] flex flex-col">
<DialogContent className="bg-[var(--surface-1)] border-[var(--border)] text-[var(--fg)] max-w-[420px] max-h-[85vh] flex flex-col">
<DialogHeader className="shrink-0">
<DialogTitle className="flex items-center gap-2 text-sm">
<Keyboard className="w-4 h-4 text-[#34B27B]" />
<Keyboard className="w-4 h-4 text-[var(--brand)]" />
{t("title")}
</DialogTitle>
</DialogHeader>

<div className="flex-1 min-h-0 overflow-y-auto pr-1 -mr-1">
<div className="space-y-0.5">
<p className="text-[10px] text-slate-500 mb-2 uppercase tracking-wide font-semibold">
<p className="text-[10px] text-[var(--muted)] mb-2 uppercase tracking-wide font-semibold">
{t("configurable")}
</p>
{SHORTCUT_ACTIONS.map((action) => {
const isCapturing = captureFor === action;
const hasConflict = conflict?.forAction === action;
return (
<div key={action}>
<div className="flex items-center justify-between py-1.5 px-1 border-b border-white/5">
<span className="text-sm text-slate-300">{t(`actions.${action}`)}</span>
<div className="flex items-center justify-between py-1.5 px-1 border-b border-[var(--border-soft)]">
<span className="text-sm text-[var(--fg-2)]">{t(`actions.${action}`)}</span>
<button
type="button"
onClick={() => {
Expand All @@ -168,18 +168,18 @@ export function ShortcutsConfigDialog() {
className={[
"px-2 py-1 rounded text-xs font-mono border transition-all min-w-[90px] text-center select-none",
isCapturing
? "bg-[#34B27B]/20 border-[#34B27B] text-[#34B27B] animate-pulse"
? "bg-[var(--brand-soft)] border-[var(--brand)] text-[var(--brand)] animate-pulse"
: hasConflict
? "bg-amber-500/10 border-amber-500/50 text-amber-400"
: "bg-white/5 border-white/10 text-slate-200 hover:border-[#34B27B]/50 hover:text-[#34B27B] cursor-pointer",
? "bg-[var(--warn-soft)] border-[var(--warn)] text-[var(--warn)]"
: "bg-[var(--surface-2)] border-[var(--border)] text-[var(--fg-2)] hover:border-[var(--brand)] hover:text-[var(--brand)] cursor-pointer",
].join(" ")}
>
{isCapturing ? t("pressKey") : formatBinding(draft[action], isMac)}
</button>
</div>
{hasConflict && conflict?.conflictWith.type === "configurable" && (
<div className="flex items-center justify-between px-1 py-1.5 mb-0.5 bg-amber-500/10 border border-amber-500/20 rounded text-xs">
<span className="text-amber-400">
<div className="flex items-center justify-between px-1 py-1.5 mb-0.5 bg-[var(--warn-soft)] border border-[var(--warn)] rounded text-xs">
<span className="text-[var(--warn)]">
⚠{" "}
{t("alreadyUsedBy", {
action: t(`actions.${conflict.conflictWith.action}`),
Expand All @@ -189,14 +189,14 @@ export function ShortcutsConfigDialog() {
<button
type="button"
onClick={handleSwap}
className="px-2 py-0.5 bg-amber-500/20 hover:bg-amber-500/30 border border-amber-500/40 rounded text-amber-300 font-medium transition-colors"
className="px-2 py-0.5 bg-[var(--warn-soft)] hover:bg-[color-mix(in_srgb,var(--warn)_28%,transparent)] border border-[var(--warn)] rounded text-[var(--warn)] font-medium transition-colors"
>
{t("swap")}
</button>
<button
type="button"
onClick={handleCancelConflict}
className="px-2 py-0.5 bg-white/5 hover:bg-white/10 border border-white/10 rounded text-slate-400 transition-colors"
className="px-2 py-0.5 bg-[var(--surface-2)] hover:bg-[var(--surface-3)] border border-[var(--border)] rounded text-[var(--muted)] transition-colors"
>
{tc("actions.cancel")}
</button>
Expand All @@ -209,32 +209,32 @@ export function ShortcutsConfigDialog() {
</div>

<div className="space-y-0.5 mt-2">
<p className="text-[10px] text-slate-500 mb-2 uppercase tracking-wide font-semibold">
<p className="text-[10px] text-[var(--muted)] mb-2 uppercase tracking-wide font-semibold">
{t("fixed")}
</p>
{FIXED_SHORTCUTS.map(({ i18nKey, label, display }) => (
<div
key={i18nKey}
className="flex items-center justify-between py-1.5 px-1 border-b border-white/5 last:border-0"
className="flex items-center justify-between py-1.5 px-1 border-b border-[var(--border-soft)] last:border-0"
>
<span className="text-sm text-slate-400">
<span className="text-sm text-[var(--muted)]">
{t(`fixedActions.${i18nKey}`, { defaultValue: label })}
</span>
<kbd className="px-2 py-1 bg-white/5 border border-white/10 rounded text-xs font-mono text-slate-400 min-w-[90px] text-center">
<kbd className="px-2 py-1 bg-[var(--surface-2)] border border-[var(--border)] rounded text-xs font-mono text-[var(--muted)] min-w-[90px] text-center">
{display}
</kbd>
</div>
))}
</div>

<p className="text-[10px] text-slate-500 mt-1">{t("helpText")}</p>
<p className="text-[10px] text-[var(--muted)] mt-1">{t("helpText")}</p>
</div>

<DialogFooter className="shrink-0 flex gap-2 sm:justify-between mt-2">
<Button
variant="ghost"
size="sm"
className="text-slate-400 gap-1.5"
className="text-[var(--muted)] gap-1.5"
onClick={handleReset}
>
<RotateCcw className="w-3 h-3" />
Expand All @@ -246,7 +246,7 @@ export function ShortcutsConfigDialog() {
</Button>
<Button
size="sm"
className="bg-[#34B27B] hover:bg-[#2d9e6c] text-white"
className="bg-[var(--brand)] hover:bg-[var(--brand-lo)] text-[var(--accent-on)]"
onClick={handleSave}
>
{tc("actions.save")}
Expand Down
Loading