Skip to content

Commit 4de3050

Browse files
Merge pull request #1474 from CapSoftware/frontend-bits
Frontend UI improvements and polish
2 parents f382e2c + ac41c35 commit 4de3050

File tree

11 files changed

+240
-54
lines changed

11 files changed

+240
-54
lines changed

apps/desktop/src-tauri/src/windows.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -182,10 +182,10 @@ impl CapWindowId {
182182
pub fn min_size(&self) -> Option<(f64, f64)> {
183183
Some(match self {
184184
Self::Setup => (600.0, 600.0),
185-
Self::Main => (310.0, 320.0),
185+
Self::Main => (330.0, 345.0),
186186
Self::Editor { .. } => (1275.0, 800.0),
187187
Self::ScreenshotEditor { .. } => (800.0, 600.0),
188-
Self::Settings => (600.0, 465.0),
188+
Self::Settings => (700.0, 540.0),
189189
Self::Camera => (200.0, 200.0),
190190
Self::Upgrade => (950.0, 850.0),
191191
Self::ModeSelect => (580.0, 340.0),

apps/desktop/src/components/Mode.tsx

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,27 @@ import Tooltip from "~/components/Tooltip";
44
import { useRecordingOptions } from "~/routes/(window-chrome)/OptionsContext";
55
import { commands } from "~/utils/tauri";
66

7-
const Mode = () => {
7+
interface ModeProps {
8+
onInfoClick?: () => void;
9+
}
10+
11+
const Mode = (props: ModeProps) => {
812
const { rawOptions, setOptions } = useRecordingOptions();
913
const [isInfoHovered, setIsInfoHovered] = createSignal(false);
1014

15+
const handleInfoClick = () => {
16+
if (props.onInfoClick) {
17+
props.onInfoClick();
18+
} else {
19+
commands.showWindow("ModeSelect");
20+
}
21+
};
22+
1123
return (
1224
<div class="flex gap-2 relative justify-end items-center p-1.5 rounded-full bg-gray-3 w-fit">
1325
<div
1426
class="absolute -left-1.5 -top-2 p-1 rounded-full w-fit bg-gray-5 group"
15-
onClick={() => commands.showWindow("ModeSelect")}
27+
onClick={handleInfoClick}
1628
onMouseEnter={() => setIsInfoHovered(true)}
1729
onMouseLeave={() => setIsInfoHovered(false)}
1830
>

apps/desktop/src/routes/(window-chrome)/new-main/CameraSelect.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ export default function CameraSelect(props: {
2020
<CameraSelectBase
2121
{...props}
2222
PillComponent={InfoPill}
23-
class="flex flex-row gap-2 items-center px-2 w-full h-10 rounded-lg transition-colors cursor-default disabled:opacity-70 bg-gray-3 disabled:text-gray-11 KSelect"
23+
class="flex flex-row gap-2 items-center px-2 w-full h-[42px] rounded-lg transition-colors cursor-default disabled:opacity-70 bg-gray-3 disabled:text-gray-11 KSelect"
2424
iconClass="text-gray-10 size-4"
2525
/>
2626
);

apps/desktop/src/routes/(window-chrome)/new-main/MicrophoneSelect.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ export default function MicrophoneSelect(props: {
2727
return (
2828
<MicrophoneSelectBase
2929
{...props}
30-
class="flex overflow-hidden relative z-10 flex-row gap-2 items-center px-2 w-full h-10 rounded-lg transition-colors cursor-default disabled:opacity-70 bg-gray-3 disabled:text-gray-11 KSelect"
30+
class="flex overflow-hidden relative z-10 flex-row gap-2 items-center px-2 w-full h-[42px] rounded-lg transition-colors cursor-default disabled:opacity-70 bg-gray-3 disabled:text-gray-11 KSelect"
3131
levelIndicatorClass="bg-blue-7"
3232
iconClass="text-gray-10 size-4"
3333
PillComponent={InfoPill}
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
import { cx } from "cva";
2+
import { For } from "solid-js";
3+
import { Transition } from "solid-transition-group";
4+
import { commands, type RecordingMode } from "~/utils/tauri";
5+
import IconLucideArrowLeft from "~icons/lucide/arrow-left";
6+
import { useRecordingOptions } from "../OptionsContext";
7+
8+
interface ModeInfoPanelProps {
9+
onBack: () => void;
10+
}
11+
12+
const modeOptions = [
13+
{
14+
mode: "instant" as RecordingMode,
15+
title: "Instant",
16+
description:
17+
"Share instantly with a link. Your recording uploads as you record, so you can share it immediately when you're done.",
18+
icon: IconCapInstant,
19+
},
20+
{
21+
mode: "studio" as RecordingMode,
22+
title: "Studio",
23+
description:
24+
"Record locally in the highest quality for editing later. Perfect for creating polished content with effects and transitions.",
25+
icon: IconCapFilmCut,
26+
},
27+
{
28+
mode: "screenshot" as RecordingMode,
29+
title: "Screenshot",
30+
description:
31+
"Capture and annotate screenshots instantly. Great for quick captures, bug reports, and visual communication.",
32+
icon: IconCapScreenshot,
33+
},
34+
];
35+
36+
export default function ModeInfoPanel(props: ModeInfoPanelProps) {
37+
const { rawOptions, setOptions } = useRecordingOptions();
38+
39+
const handleModeSelect = (mode: RecordingMode) => {
40+
setOptions({ mode });
41+
commands.setRecordingMode(mode);
42+
props.onBack();
43+
};
44+
45+
return (
46+
<div class="flex flex-col w-full h-full min-h-0">
47+
<div class="flex gap-3 justify-between items-center mt-3">
48+
<div
49+
onClick={() => props.onBack()}
50+
class="flex gap-1 items-center rounded-md px-1.5 text-xs cursor-pointer
51+
text-gray-11 transition-opacity hover:opacity-70 hover:text-gray-12
52+
focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-9 focus-visible:ring-offset-2 focus-visible:ring-offset-gray-1"
53+
>
54+
<IconLucideArrowLeft class="size-3 text-gray-11" />
55+
<span class="font-medium text-gray-12">Back</span>
56+
</div>
57+
<span class="text-xs font-medium text-gray-11">Recording Modes</span>
58+
</div>
59+
<div class="flex flex-col flex-1 min-h-0 pt-4">
60+
<div class="px-1 custom-scroll flex-1 overflow-y-auto">
61+
<div class="flex flex-col gap-2 pb-4">
62+
<For each={modeOptions}>
63+
{(option, index) => {
64+
const isSelected = () => rawOptions.mode === option.mode;
65+
66+
return (
67+
<Transition
68+
appear
69+
enterActiveClass="transition duration-200"
70+
enterClass="scale-95 opacity-0"
71+
enterToClass="scale-100 opacity-100"
72+
exitActiveClass="transition duration-200"
73+
exitClass="scale-100"
74+
exitToClass="scale-95"
75+
>
76+
<div style={{ "transition-delay": `${index() * 100}ms` }}>
77+
<div
78+
onClick={() => handleModeSelect(option.mode)}
79+
class={cx(
80+
"relative flex items-center gap-3 p-3 rounded-xl border-2 transition-all duration-200 cursor-pointer",
81+
isSelected()
82+
? "border-blue-9 bg-blue-3 dark:bg-blue-3/30"
83+
: "border-gray-4 dark:border-gray-5 bg-gray-2 dark:bg-gray-3 hover:border-gray-6 dark:hover:border-gray-6 hover:bg-gray-3 dark:hover:bg-gray-4",
84+
)}
85+
>
86+
{isSelected() && (
87+
<div class="absolute top-2 right-2 flex items-center justify-center size-4 rounded-full bg-blue-9">
88+
<IconLucideCheck class="size-2.5 text-white" />
89+
</div>
90+
)}
91+
92+
<div class="flex-shrink-0">
93+
<option.icon
94+
class={cx(
95+
"size-5 invert dark:invert-0",
96+
isSelected() && "text-blue-11",
97+
)}
98+
/>
99+
</div>
100+
101+
<div class="flex flex-col flex-1 min-w-0">
102+
<h3
103+
class={cx(
104+
"text-sm font-semibold",
105+
isSelected() ? "text-blue-11" : "text-gray-12",
106+
)}
107+
>
108+
{option.title}
109+
</h3>
110+
<p class="text-xs leading-relaxed text-gray-11">
111+
{option.description}
112+
</p>
113+
</div>
114+
</div>
115+
</div>
116+
</Transition>
117+
);
118+
}}
119+
</For>
120+
</div>
121+
</div>
122+
</div>
123+
</div>
124+
);
125+
}

apps/desktop/src/routes/(window-chrome)/new-main/SystemAudio.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import InfoPill from "./InfoPill";
1212
export default function SystemAudio() {
1313
return (
1414
<SystemAudioToggleRoot
15-
class="flex flex-row gap-2 items-center px-2 w-full h-10 rounded-lg transition-colors cursor-default disabled:opacity-70 bg-gray-3 disabled:text-gray-11 KSelect"
15+
class="flex flex-row gap-2 items-center px-2 w-full h-[42px] rounded-lg transition-colors cursor-default disabled:opacity-70 bg-gray-3 disabled:text-gray-11 KSelect"
1616
PillComponent={InfoPill}
1717
icon={<IconPhMonitorBold class="text-gray-10 size-4" />}
1818
/>

apps/desktop/src/routes/(window-chrome)/new-main/TargetCard.tsx

Lines changed: 30 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -386,33 +386,36 @@ export default function TargetCard(props: TargetCardProps) {
386386
</div>
387387
<Show when={local.variant === "screenshot"}>
388388
<div class="flex items-center justify-between px-2 pb-1.5 pt-0.5 gap-1">
389-
<div
390-
role="button"
391-
tabIndex={-1}
392-
onClick={handleOpenEditor}
393-
class="flex-1 flex items-center justify-center p-1 rounded hover:bg-gray-5 text-gray-11 hover:text-gray-12 transition-colors"
394-
title="Editor"
395-
>
396-
<IconLucideEdit class="size-3.5" />
397-
</div>
398-
<div
399-
role="button"
400-
tabIndex={-1}
401-
onClick={handleCopy}
402-
class="flex-1 flex items-center justify-center p-1 rounded hover:bg-gray-5 text-gray-11 hover:text-gray-12 transition-colors"
403-
title="Copy to clipboard"
404-
>
405-
<IconLucideCopy class="size-3.5" />
406-
</div>
407-
<div
408-
role="button"
409-
tabIndex={-1}
410-
onClick={handleSave}
411-
class="flex-1 flex items-center justify-center p-1 rounded hover:bg-gray-5 text-gray-11 hover:text-gray-12 transition-colors"
412-
title="Save as..."
413-
>
414-
<IconLucideSave class="size-3.5" />
415-
</div>
389+
<Tooltip content="Edit">
390+
<div
391+
role="button"
392+
tabIndex={-1}
393+
onClick={handleOpenEditor}
394+
class="flex-1 flex items-center justify-center p-1 rounded hover:bg-gray-5 text-gray-11 hover:text-gray-12 transition-colors"
395+
>
396+
<IconLucideEdit class="size-3.5" />
397+
</div>
398+
</Tooltip>
399+
<Tooltip content="Copy to clipboard">
400+
<div
401+
role="button"
402+
tabIndex={-1}
403+
onClick={handleCopy}
404+
class="flex-1 flex items-center justify-center p-1 rounded hover:bg-gray-5 text-gray-11 hover:text-gray-12 transition-colors"
405+
>
406+
<IconLucideCopy class="size-3.5" />
407+
</div>
408+
</Tooltip>
409+
<Tooltip content="Save as...">
410+
<div
411+
role="button"
412+
tabIndex={-1}
413+
onClick={handleSave}
414+
class="flex-1 flex items-center justify-center p-1 rounded hover:bg-gray-5 text-gray-11 hover:text-gray-12 transition-colors"
415+
>
416+
<IconLucideSave class="size-3.5" />
417+
</div>
418+
</Tooltip>
416419
</div>
417420
</Show>
418421
<Show when={local.variant === "recording"}>

apps/desktop/src/routes/(window-chrome)/new-main/TargetDropdownButton.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ export default function TargetDropdownButton<
2727
aria-expanded={local.expanded ? "true" : "false"}
2828
data-expanded={local.expanded ? "true" : "false"}
2929
class={cx(
30-
"flex h-[4rem] w-5 shrink-0 items-center justify-center rounded-lg bg-gray-4 text-gray-12 transition-colors duration-150 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-9 focus-visible:ring-offset-2 focus-visible:ring-offset-gray-1 hover:bg-gray-5",
30+
"flex w-5 shrink-0 items-center justify-center rounded-lg bg-gray-4 text-gray-12 transition-colors duration-150 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-9 focus-visible:ring-offset-2 focus-visible:ring-offset-gray-1 hover:bg-gray-5",
3131
local.expanded && "bg-gray-5",
3232
local.disabled && "pointer-events-none opacity-60",
3333
local.class,

apps/desktop/src/routes/(window-chrome)/new-main/TargetTypeButton.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ function TargetTypeButton(props: TargetTypeButtonProps) {
2424
disabled={local.disabled}
2525
aria-pressed={local.selected ? "true" : "false"}
2626
class={cx(
27-
"flex flex-1 flex-col items-center justify-end gap-2 rounded-lg bg-gray-3 py-1.5 text-center transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-9 focus-visible:ring-offset-2 focus-visible:ring-offset-gray-1",
27+
"flex flex-1 flex-col items-center justify-end gap-2 rounded-lg bg-gray-3 py-2.5 text-center transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-9 focus-visible:ring-offset-2 focus-visible:ring-offset-gray-1",
2828
local.selected ? "text-gray-12" : "text-gray-12 hover:bg-gray-4",
2929
local.disabled && "pointer-events-none opacity-60",
3030
local.class,

0 commit comments

Comments
 (0)