Skip to content
Open
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
153 changes: 46 additions & 107 deletions apps/desktop/src/routes/editor/ConfigSidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ import IconLucideTimer from "~icons/lucide/timer";
import IconLucideType from "~icons/lucide/type";
import IconLucideWind from "~icons/lucide/wind";
import { CaptionsTab } from "./CaptionsTab";
import { type CornerRoundingType, useEditorContext } from "./context";
import { useEditorContext } from "./context";
import { evaluateMask, type MaskKind, type MaskSegment } from "./masks";
import {
DEFAULT_GRADIENT_FROM,
Expand Down Expand Up @@ -219,11 +219,6 @@ const CAMERA_SHAPES = [
},
] satisfies Array<{ name: string; value: CameraShape }>;

const CORNER_STYLE_OPTIONS = [
{ name: "Squircle", value: "squircle" },
{ name: "Rounded", value: "rounded" },
] satisfies Array<{ name: string; value: CornerRoundingType }>;

const BACKGROUND_THEMES = {
macOS: "macOS",
dark: "Dark",
Expand Down Expand Up @@ -1718,9 +1713,9 @@ function BackgroundConfig(props: { scrollRef: HTMLDivElement }) {
if (!file) return;

/*
this is a Tauri bug in WebKit so we need to validate the file type manually
https://github.com/tauri-apps/tauri/issues/9158
*/
this is a Tauri bug in WebKit so we need to validate the file type manually
https://github.com/tauri-apps/tauri/issues/9158
*/
Comment on lines 1715 to +1718
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Remove the Tauri bug comment block to match “no comments” guideline

The multi‑line /* ... */ comment about the Tauri WebKit bug was modified in this PR and violates the guideline that .ts/.tsx/.js/.jsx/.rs files should not contain code comments. The surrounding code (manual extension validation) is already self‑explanatory.

Consider deleting this block entirely and, if needed, capturing the context in commit messages or external docs instead.

🤖 Prompt for AI Agents
In apps/desktop/src/routes/editor/ConfigSidebar.tsx around lines 1715 to 1718,
remove the multi-line comment block (/* this is a Tauri bug in WebKit so we need
to validate the file type manually
https://github.com/tauri-apps/tauri/issues/9158 */) so the file complies with
the "no comments" guideline; delete the block only and keep the surrounding
manual extension validation code unchanged, and capture any needed rationale in
the PR description or external docs instead.

const validExtensions = [
"jpg",
"jpeg",
Expand Down Expand Up @@ -1986,23 +1981,27 @@ function BackgroundConfig(props: { scrollRef: HTMLDivElement }) {
/>
</Field>
<Field name="Rounded Corners" icon={<IconCapCorners class="size-4" />}>
<div class="flex flex-col gap-3">
<Slider
value={[project.background.rounding]}
onChange={(v) => setProject("background", "rounding", v[0])}
minValue={0}
maxValue={100}
step={0.1}
formatTooltip="%"
/>
<CornerStyleSelect
label="Corner Style"
value={project.background.roundingType}
onChange={(value) =>
setProject("background", "roundingType", value)
}
/>
</div>
<Slider
value={[project.background.rounding]}
onChange={(v) => setProject("background", "rounding", v[0])}
minValue={0}
maxValue={100}
step={0.1}
formatTooltip="%"
/>
</Field>
<Field
name="Corner Smoothness"
icon={<IconLucideSquareRoundCorner class="size-4" />}
>
<Slider
value={[project.background.roundingSmoothness ?? 0]}
onChange={(v) => setProject("background", "roundingSmoothness", v[0])}
minValue={0}
maxValue={1}
step={0.01}
formatTooltip={(value) => `${Math.round(value * 100)}%`}
/>
</Field>
<Field name="Motion Blur" icon={<IconLucideWind class="size-4" />}>
<Slider
Expand Down Expand Up @@ -2340,21 +2339,27 @@ function CameraConfig(props: { scrollRef: HTMLDivElement }) {
/>
</Field>
<Field name="Rounded Corners" icon={<IconCapCorners class="size-4" />}>
<div class="flex flex-col gap-3">
<Slider
value={[project.camera.rounding!]}
onChange={(v) => setProject("camera", "rounding", v[0])}
minValue={0}
maxValue={100}
step={0.1}
formatTooltip="%"
/>
<CornerStyleSelect
label="Corner Style"
value={project.camera.roundingType}
onChange={(value) => setProject("camera", "roundingType", value)}
/>
</div>
<Slider
value={[project.camera.rounding ?? 0]}
onChange={(v) => setProject("camera", "rounding", v[0])}
minValue={0}
maxValue={100}
step={0.1}
formatTooltip="%"
/>
</Field>
<Field
name="Corner Smoothness"
icon={<IconLucideSquareRoundCorner class="size-4" />}
>
<Slider
value={[project.camera.roundingSmoothness ?? 0]}
onChange={(v) => setProject("camera", "roundingSmoothness", v[0])}
minValue={0}
maxValue={1}
step={0.01}
formatTooltip={(value) => `${Math.round(value * 100)}%`}
/>
</Field>
<Field name="Shadow" icon={<IconCapShadow class="size-4" />}>
<div class="space-y-8">
Expand Down Expand Up @@ -2425,72 +2430,6 @@ function CameraConfig(props: { scrollRef: HTMLDivElement }) {
);
}

function CornerStyleSelect(props: {
label?: string;
value: CornerRoundingType;
onChange: (value: CornerRoundingType) => void;
}) {
return (
<div class="flex flex-col gap-1.5">
<Show when={props.label}>
{(label) => (
<span class="text-[0.65rem] uppercase tracking-wide text-gray-11">
{label()}
</span>
)}
</Show>
<KSelect<{ name: string; value: CornerRoundingType }>
options={CORNER_STYLE_OPTIONS}
optionValue="value"
optionTextValue="name"
value={CORNER_STYLE_OPTIONS.find(
(option) => option.value === props.value,
)}
onChange={(option) => option && props.onChange(option.value)}
disallowEmptySelection
itemComponent={(itemProps) => (
<MenuItem<typeof KSelect.Item>
as={KSelect.Item}
item={itemProps.item}
>
<KSelect.ItemLabel class="flex-1">
{itemProps.item.rawValue.name}
</KSelect.ItemLabel>
</MenuItem>
)}
>
<KSelect.Trigger class="flex flex-row gap-2 items-center px-2 w-full h-8 rounded-lg transition-colors bg-gray-3 disabled:text-gray-11">
<KSelect.Value<{
name: string;
value: CornerRoundingType;
}> class="flex-1 text-sm text-left truncate text-[--gray-500] font-normal">
{(state) => <span>{state.selectedOption().name}</span>}
</KSelect.Value>
<KSelect.Icon<ValidComponent>
as={(iconProps) => (
<IconCapChevronDown
{...iconProps}
class="size-4 shrink-0 transform transition-transform ui-expanded:rotate-180 text-[--gray-500]"
/>
)}
/>
</KSelect.Trigger>
<KSelect.Portal>
<PopperContent<typeof KSelect.Content>
as={KSelect.Content}
class={cx(topSlideAnimateClasses, "z-50")}
>
<MenuItemList<typeof KSelect.Listbox>
class="overflow-y-auto max-h-32"
as={KSelect.Listbox}
/>
</PopperContent>
</KSelect.Portal>
</KSelect>
</div>
);
}

const normalizeHexInput = (value: string, fallback: string) => {
const trimmed = value.trim();
const withHash = trimmed.startsWith("#") ? trimmed : `#${trimmed}`;
Expand Down
36 changes: 4 additions & 32 deletions apps/desktop/src/routes/editor/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,10 +96,6 @@ export type CustomDomainResponse = {
domain_verified: boolean | null;
};

export type CornerRoundingType = "rounded" | "squircle";

type WithCornerStyle<T> = T & { roundingType: CornerRoundingType };

type EditorTimelineConfiguration = Omit<
TimelineConfiguration,
"sceneSegments" | "maskSegments"
Expand All @@ -113,25 +109,12 @@ export type EditorProjectConfiguration = Omit<
ProjectConfiguration,
"background" | "camera" | "timeline"
> & {
background: WithCornerStyle<ProjectConfiguration["background"]>;
camera: WithCornerStyle<ProjectConfiguration["camera"]>;
background: ProjectConfiguration["background"];
camera: ProjectConfiguration["camera"];
timeline?: EditorTimelineConfiguration | null;
hiddenTextSegments?: number[];
};

function withCornerDefaults<
T extends {
roundingType?: CornerRoundingType;
rounding_type?: CornerRoundingType;
},
>(value: T): T & { roundingType: CornerRoundingType } {
const roundingType = value.roundingType ?? value.rounding_type ?? "squircle";
return {
...value,
roundingType,
};
}

export function normalizeProject(
config: ProjectConfiguration,
): EditorProjectConfiguration {
Expand All @@ -157,18 +140,13 @@ export function normalizeProject(
return {
...config,
timeline,
background: withCornerDefaults(config.background),
camera: withCornerDefaults(config.camera),
};
}

export function serializeProjectConfiguration(
project: EditorProjectConfiguration,
): ProjectConfiguration {
const { background, camera, ...rest } = project;
const { roundingType: backgroundRoundingType, ...backgroundRest } =
background;
const { roundingType: cameraRoundingType, ...cameraRest } = camera;

const timeline = project.timeline
? {
Expand All @@ -181,14 +159,8 @@ export function serializeProjectConfiguration(
return {
...rest,
timeline: timeline as unknown as ProjectConfiguration["timeline"],
background: {
...backgroundRest,
roundingType: backgroundRoundingType,
},
camera: {
...cameraRest,
roundingType: cameraRoundingType,
},
background,
camera,
};
}

Expand Down
Loading
Loading