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
27 changes: 25 additions & 2 deletions apps/desktop/src/components/Tooltip.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,44 @@
import { Tooltip as KTooltip } from "@kobalte/core";
import { type as ostype } from "@tauri-apps/plugin-os";
import { cx } from "cva";
import type { ComponentProps, JSX } from "solid-js";

interface Props extends ComponentProps<typeof KTooltip.Root> {
content: JSX.Element;
childClass?: string;
kbd?: string[];
}

type Os = "android" | "ios" | "linux" | "macos" | "windows";

const kbdSymbolModifier = (key: string, os: Os) => {
const obj = {
meta: os === "macos" ? "⌘" : "ctrl",
shift: "⇧",
alt: os === "macos" ? "⌥" : "⎇",
};
return obj[key as keyof typeof obj] || key;
};

export default function Tooltip(props: Props) {
const os = ostype();
return (
<KTooltip.Root {...props} openDelay={props.openDelay ?? 200}>
<KTooltip.Trigger class={cx(props.childClass)}>
{props.children}
</KTooltip.Trigger>
<KTooltip.Portal>
<KTooltip.Content class="z-50 px-1.5 py-1 text-xs border border-gray-3 bg-gray-12 text-gray-1 rounded shadow-lg duration-100 animate-in fade-in slide-in-from-top-1 min-w-6 text-center">
{props.content}
<KTooltip.Content class="z-50 px-1.5 flex items-center py-1 text-xs border border-gray-3 bg-gray-12 text-gray-1 rounded-md shadow-lg duration-100 animate-in fade-in slide-in-from-top-1 min-w-6 gap-1.5 text-center">
<span>{props.content}</span>
{props.kbd && props.kbd.length > 0 && (
<div class="space-x-1">
{props.kbd?.map((kbd) => (
<kbd class="py-0.5 px-[5px] text-[10px] rounded-md text-gray-12 bg-gray-1">
{kbdSymbolModifier(kbd, os)}
</kbd>
))}
</div>
)}
<KTooltip.Arrow size={16} />
</KTooltip.Content>
</KTooltip.Portal>
Expand Down
159 changes: 87 additions & 72 deletions apps/desktop/src/routes/editor/AspectRatioSelect.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Select as KSelect } from "@kobalte/core/select";
import { Show } from "solid-js";

import { createEventListener } from "@solid-primitives/event-listener";
import { createSignal, Show } from "solid-js";
import Tooltip from "~/components/Tooltip";
import type { AspectRatio } from "~/utils/tauri";
import { useEditorContext } from "./context";
import { ASPECT_RATIOS } from "./projectConfig";
Expand All @@ -14,80 +15,94 @@ import {

function AspectRatioSelect() {
const { project, setProject } = useEditorContext();
return (
<KSelect<AspectRatio | "auto">
value={project.aspectRatio ?? "auto"}
onChange={(v) => {
if (v === null) return;
setProject("aspectRatio", v === "auto" ? null : v);
}}
defaultValue="auto"
options={
["auto", "wide", "vertical", "square", "classic", "tall"] as const
}
multiple={false}
itemComponent={(props) => {
const item = () =>
props.item.rawValue === "auto"
? null
: ASPECT_RATIOS[props.item.rawValue];
const [open, setOpen] = createSignal(false);
let triggerSelect: HTMLDivElement | undefined;
createEventListener(document, "keydown", (e: KeyboardEvent) => {
if (e.code === "KeyA" && e.target === document.body) {
e.preventDefault();
setOpen((prev) => !prev);
}
});

return (
<MenuItem<typeof KSelect.Item> as={KSelect.Item} item={props.item}>
<KSelect.ItemLabel class="flex-1">
{props.item.rawValue === "auto"
? "Auto"
: ASPECT_RATIOS[props.item.rawValue].name}
<Show when={item()}>
{(item) => (
<span class="text-gray-11">
{"⋅"}
{item().ratio[0]}:{item().ratio[1]}
</span>
)}
</Show>
</KSelect.ItemLabel>
<KSelect.ItemIndicator class="ml-auto">
<IconCapCircleCheck />
</KSelect.ItemIndicator>
</MenuItem>
);
}}
placement="top-start"
>
<EditorButton<typeof KSelect.Trigger>
as={KSelect.Trigger}
class="w-28"
leftIcon={<IconCapLayout />}
rightIcon={
<KSelect.Icon>
<IconCapChevronDown />
</KSelect.Icon>
return (
<Tooltip kbd={["A"]} content="Aspect Ratio">
<KSelect<AspectRatio | "auto">
open={open()}
onOpenChange={setOpen}
ref={triggerSelect}
value={project.aspectRatio ?? "auto"}
onChange={(v) => {
if (v === null) return;
setProject("aspectRatio", v === "auto" ? null : v);
}}
defaultValue="auto"
options={
["auto", "wide", "vertical", "square", "classic", "tall"] as const
}
rightIconEnd={true}
multiple={false}
itemComponent={(props) => {
const item = () =>
props.item.rawValue === "auto"
? null
: ASPECT_RATIOS[props.item.rawValue];

return (
<MenuItem<typeof KSelect.Item> as={KSelect.Item} item={props.item}>
<KSelect.ItemLabel class="flex-1">
{props.item.rawValue === "auto"
? "Auto"
: ASPECT_RATIOS[props.item.rawValue].name}
<Show when={item()}>
{(item) => (
<span class="text-gray-11">
{"⋅"}
{item().ratio[0]}:{item().ratio[1]}
</span>
)}
</Show>
</KSelect.ItemLabel>
<KSelect.ItemIndicator class="ml-auto">
<IconCapCircleCheck />
</KSelect.ItemIndicator>
</MenuItem>
);
}}
placement="top-start"
>
<KSelect.Value<AspectRatio | "auto">>
{(state) => {
const text = () => {
const option = state.selectedOption();
return option === "auto" ? "Auto" : ASPECT_RATIOS[option].name;
};
return <>{text()}</>;
}}
</KSelect.Value>
</EditorButton>
<KSelect.Portal>
<PopperContent<typeof KSelect.Content>
as={KSelect.Content}
class={topLeftAnimateClasses}
<EditorButton<typeof KSelect.Trigger>
as={KSelect.Trigger}
class="w-28"
leftIcon={<IconCapLayout />}
rightIcon={
<KSelect.Icon>
<IconCapChevronDown />
</KSelect.Icon>
}
rightIconEnd={true}
>
<MenuItemList<typeof KSelect.Listbox>
as={KSelect.Listbox}
class="w-[12.5rem]"
/>
</PopperContent>
</KSelect.Portal>
</KSelect>
<KSelect.Value<AspectRatio | "auto">>
{(state) => {
const text = () => {
const option = state.selectedOption();
return option === "auto" ? "Auto" : ASPECT_RATIOS[option].name;
};
return <>{text()}</>;
}}
</KSelect.Value>
</EditorButton>
<KSelect.Portal>
<PopperContent<typeof KSelect.Content>
as={KSelect.Content}
class={topLeftAnimateClasses}
>
<MenuItemList<typeof KSelect.Listbox>
as={KSelect.Listbox}
class="w-[12.5rem]"
/>
</PopperContent>
</KSelect.Portal>
</KSelect>
</Tooltip>
);
}

Expand Down
30 changes: 15 additions & 15 deletions apps/desktop/src/routes/editor/ExportDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -409,8 +409,8 @@ export function ExportDialog() {
)}
>
<p class="flex gap-4 items-center">
<span class="flex items-center text-[--gray-500]">
<IconCapCamera class="w-[14px] h-[14px] mr-1.5 text-[--gray-500]" />
<span class="flex items-center text-gray-12">
<IconCapCamera class="w-[14px] h-[14px] mr-1.5 text-gray-12" />
{(() => {
const totalSeconds = Math.round(
est().duration_seconds,
Expand All @@ -433,16 +433,16 @@ export function ExportDialog() {
.padStart(2, "0")}`;
})()}
</span>
<span class="flex items-center text-[--gray-500]">
<IconLucideMonitor class="w-[14px] h-[14px] mr-1.5 text-[--gray-500]" />
<span class="flex items-center text-gray-12">
<IconLucideMonitor class="w-[14px] h-[14px] mr-1.5 text-gray-12" />
{settings.resolution.width}×{settings.resolution.height}
</span>
<span class="flex items-center text-[--gray-500]">
<IconLucideHardDrive class="w-[14px] h-[14px] mr-1.5 text-[--gray-500]" />
<span class="flex items-center text-gray-12">
<IconLucideHardDrive class="w-[14px] h-[14px] mr-1.5 text-gray-12" />
{est().estimated_size_mb.toFixed(2)} MB
</span>
<span class="flex items-center text-[--gray-500]">
<IconLucideClock class="w-[14px] h-[14px] mr-1.5 text-[--gray-500]" />
<span class="flex items-center text-gray-12">
<IconLucideClock class="w-[14px] h-[14px] mr-1.5 text-gray-12" />
{(() => {
const totalSeconds = Math.round(
est().estimated_time_seconds,
Expand Down Expand Up @@ -474,7 +474,7 @@ export function ExportDialog() {
>
<div class="flex flex-wrap gap-3">
{/* Export to */}
<div class="flex-1 p-4 rounded-xl bg-gray-2">
<div class="flex-1 p-4 rounded-xl dark:bg-gray-2 bg-gray-3">
<div class="flex flex-col gap-3">
<h3 class="text-gray-12">Export to</h3>
<div class="flex gap-2">
Expand All @@ -497,7 +497,7 @@ export function ExportDialog() {
</div>
</div>
{/* Format */}
<div class="p-4 rounded-xl bg-gray-2">
<div class="p-4 rounded-xl dark:bg-gray-2 bg-gray-3">
<div class="flex flex-col gap-3">
<h3 class="text-gray-12">Format</h3>
<div class="flex flex-row gap-2">
Expand Down Expand Up @@ -552,7 +552,7 @@ export function ExportDialog() {
</div>
</div>
{/* Frame rate */}
<div class="overflow-hidden relative p-4 rounded-xl bg-gray-2">
<div class="overflow-hidden relative p-4 rounded-xl dark:bg-gray-2 bg-gray-3">
<div class="flex flex-col gap-3">
<h3 class="text-gray-12">Frame rate</h3>
<KSelect<{ label: string; value: number }>
Expand Down Expand Up @@ -585,7 +585,7 @@ export function ExportDialog() {
</MenuItem>
)}
>
<KSelect.Trigger class="flex flex-row gap-2 items-center px-3 w-full h-10 rounded-xl transition-colors bg-gray-3 disabled:text-gray-11">
<KSelect.Trigger class="flex flex-row gap-2 items-center px-3 w-full h-10 rounded-xl transition-colors dark:bg-gray-3 bg-gray-4 disabled:text-gray-11">
<KSelect.Value<
(typeof FPS_OPTIONS)[number]
> class="flex-1 text-sm text-left truncate tabular-nums text-[--gray-500]">
Expand All @@ -606,7 +606,7 @@ export function ExportDialog() {
class={cx(topSlideAnimateClasses, "z-50")}
>
<MenuItemList<typeof KSelect.Listbox>
class="overflow-y-auto max-h-32"
class="max-h-32 custom-scroll"
as={KSelect.Listbox}
/>
</PopperContent>
Expand All @@ -615,7 +615,7 @@ export function ExportDialog() {
</div>
</div>
{/* Compression */}
<div class="p-4 rounded-xl bg-gray-2">
<div class="p-4 rounded-xl dark:bg-gray-2 bg-gray-3">
<div class="flex flex-col gap-3">
<h3 class="text-gray-12">Compression</h3>
<div class="flex gap-2">
Expand All @@ -642,7 +642,7 @@ export function ExportDialog() {
</div>
</div>
{/* Resolution */}
<div class="flex-1 p-4 rounded-xl bg-gray-2">
<div class="flex-1 p-4 rounded-xl dark:bg-gray-2 bg-gray-3">
<div class="flex flex-col gap-3">
<h3 class="text-gray-12">Resolution</h3>
<div class="flex gap-2">
Expand Down
Loading
Loading