From 510de963937f8460f2abf7c7f9dd20541b05331d Mon Sep 17 00:00:00 2001 From: zhom <2717306+zhom@users.noreply.github.com> Date: Fri, 8 Aug 2025 15:08:56 +0400 Subject: [PATCH] style: consistent flow for no proxies and no groups --- src/components/camoufox-config-dialog.tsx | 2 +- src/components/create-profile-dialog.tsx | 339 +++++++++++---------- src/components/group-assignment-dialog.tsx | 24 +- src/components/home-header.tsx | 3 +- src/components/ui/combobox.tsx | 5 +- 5 files changed, 214 insertions(+), 159 deletions(-) diff --git a/src/components/camoufox-config-dialog.tsx b/src/components/camoufox-config-dialog.tsx index 436f1ea..4b9dd20 100644 --- a/src/components/camoufox-config-dialog.tsx +++ b/src/components/camoufox-config-dialog.tsx @@ -107,7 +107,7 @@ export function CamoufoxConfigDialog({ - +
({}); const [supportedBrowsers, setSupportedBrowsers] = useState([]); const [storedProxies, setStoredProxies] = useState([]); + const [showProxyForm, setShowProxyForm] = useState(false); const [isCreating, setIsCreating] = useState(false); const loadingBrowserRef = useRef(null); @@ -334,7 +337,7 @@ export function CreateProfileDialog({ setCamoufoxConfig({ geoip: true, // Reset to automatic geoip }); - setActiveTab("regular"); + setActiveTab("anti-detect"); onClose(); }; @@ -375,7 +378,7 @@ export function CreateProfileDialog({ return ( - + Create New Profile @@ -385,197 +388,219 @@ export function CreateProfileDialog({ onValueChange={handleTabChange} className="flex flex-col flex-1 w-full min-h-0" > - - Regular Browsers + Anti-Detect + Regular - -
- {/* Profile Name - Common to both tabs */} -
- - setProfileName(e.target.value)} - placeholder="Enter profile name" - /> -
+ +
+
+ {/* Profile Name - Common to both tabs */} +
+ + setProfileName(e.target.value)} + placeholder="Enter profile name" + /> +
- -
-
- - - supportedBrowsers.includes(browser.value), - ) - .map((browser) => { - const IconComponent = getBrowserIcon(browser.value); - return { - value: browser.value, - label: browser.label, - icon: IconComponent, - }; - })} - value={selectedBrowser || ""} - onValueChange={(value) => - setSelectedBrowser(value as BrowserTypeString) - } - placeholder="Select a browser..." - searchPlaceholder="Search browsers..." - /> -
+ +
+
+ + + supportedBrowsers.includes(browser.value), + ) + .map((browser) => { + const IconComponent = getBrowserIcon(browser.value); + return { + value: browser.value, + label: browser.label, + icon: IconComponent, + }; + })} + value={selectedBrowser || ""} + onValueChange={(value) => + setSelectedBrowser(value as BrowserTypeString) + } + placeholder="Select a browser..." + searchPlaceholder="Search browsers..." + /> +
- {selectedBrowser && ( -
- {!isBrowserCurrentlyDownloading(selectedBrowser) && - !isBrowserVersionAvailable(selectedBrowser) && - getBestAvailableVersion( - availableReleaseTypes, - selectedBrowser, - ) && ( -
-

+ {selectedBrowser && ( +

+ {!isBrowserCurrentlyDownloading(selectedBrowser) && + !isBrowserVersionAvailable(selectedBrowser) && + getBestAvailableVersion( + availableReleaseTypes, + selectedBrowser, + ) && ( +
+

+ {(() => { + const bestVersion = getBestAvailableVersion( + availableReleaseTypes, + selectedBrowser, + ); + return `${bestVersion?.releaseType === "stable" ? "Latest stable" : "Latest nightly"} version (${bestVersion?.version}) needs to be downloaded`; + })()} +

+ handleDownload(selectedBrowser)} + isLoading={isBrowserCurrentlyDownloading( + selectedBrowser, + )} + size="sm" + disabled={isBrowserCurrentlyDownloading( + selectedBrowser, + )} + > + Download + +
+ )} + {!isBrowserCurrentlyDownloading(selectedBrowser) && + isBrowserVersionAvailable(selectedBrowser) && ( +
{(() => { const bestVersion = getBestAvailableVersion( availableReleaseTypes, selectedBrowser, ); - return `${bestVersion?.releaseType === "stable" ? "Latest stable" : "Latest nightly"} version (${bestVersion?.version}) needs to be downloaded`; + return `✓ ${bestVersion?.releaseType === "stable" ? "Latest stable" : "Latest nightly"} version (${bestVersion?.version}) is available`; })()} -

- handleDownload(selectedBrowser)} - isLoading={isBrowserCurrentlyDownloading( - selectedBrowser, - )} - size="sm" - disabled={isBrowserCurrentlyDownloading( - selectedBrowser, - )} - > - Download - -
- )} - {!isBrowserCurrentlyDownloading(selectedBrowser) && - isBrowserVersionAvailable(selectedBrowser) && ( +
+ )} + {isBrowserCurrentlyDownloading(selectedBrowser) && (
{(() => { const bestVersion = getBestAvailableVersion( availableReleaseTypes, selectedBrowser, ); - return `✓ ${bestVersion?.releaseType === "stable" ? "Latest stable" : "Latest nightly"} version (${bestVersion?.version}) is available`; + return `Downloading ${bestVersion?.releaseType === "stable" ? "stable" : "nightly"} version (${bestVersion?.version})...`; })()}
)} - {isBrowserCurrentlyDownloading(selectedBrowser) && ( -
- {(() => { - const bestVersion = getBestAvailableVersion( - availableReleaseTypes, - selectedBrowser, - ); - return `Downloading ${bestVersion?.releaseType === "stable" ? "stable" : "nightly"} version (${bestVersion?.version})...`; - })()} +
+ )} +
+ + + +
+ {/* Camoufox Download Status */} + {!isBrowserCurrentlyDownloading("camoufox") && + !isBrowserVersionAvailable("camoufox") && + getBestAvailableVersion( + camoufoxReleaseTypes, + "camoufox", + ) && ( +
+

+ {(() => { + const bestVersion = getBestAvailableVersion( + camoufoxReleaseTypes, + "camoufox", + ); + return `Camoufox ${bestVersion?.releaseType} version (${bestVersion?.version}) needs to be downloaded`; + })()} +

+ handleDownload("camoufox")} + isLoading={isBrowserCurrentlyDownloading( + "camoufox", + )} + size="sm" + disabled={isBrowserCurrentlyDownloading("camoufox")} + > + {isBrowserCurrentlyDownloading("camoufox") + ? "Downloading..." + : "Download"} +
)} -
- )} -
- - - -
- {/* Camoufox Download Status */} - {!isBrowserCurrentlyDownloading("camoufox") && - !isBrowserVersionAvailable("camoufox") && - getBestAvailableVersion( - camoufoxReleaseTypes, - "camoufox", - ) && ( -
-

+ {!isBrowserCurrentlyDownloading("camoufox") && + isBrowserVersionAvailable("camoufox") && ( +

{(() => { const bestVersion = getBestAvailableVersion( camoufoxReleaseTypes, "camoufox", ); - return `Camoufox ${bestVersion?.releaseType} version (${bestVersion?.version}) needs to be downloaded`; + return `✓ Camoufox ${bestVersion?.releaseType} version (${bestVersion?.version}) is available`; })()} -

- handleDownload("camoufox")} - isLoading={isBrowserCurrentlyDownloading("camoufox")} - size="sm" - disabled={isBrowserCurrentlyDownloading("camoufox")} - > - {isBrowserCurrentlyDownloading("camoufox") - ? "Downloading..." - : "Download"} - -
- )} - {!isBrowserCurrentlyDownloading("camoufox") && - isBrowserVersionAvailable("camoufox") && ( +
+ )} + {isBrowserCurrentlyDownloading("camoufox") && (
{(() => { const bestVersion = getBestAvailableVersion( camoufoxReleaseTypes, "camoufox", ); - return `✓ Camoufox ${bestVersion?.releaseType} version (${bestVersion?.version}) is available`; + return `Downloading Camoufox ${bestVersion?.releaseType} version (${bestVersion?.version})...`; })()}
)} - {isBrowserCurrentlyDownloading("camoufox") && ( -
- {(() => { - const bestVersion = getBestAvailableVersion( - camoufoxReleaseTypes, - "camoufox", - ); - return `Downloading Camoufox ${bestVersion?.releaseType} version (${bestVersion?.version})...`; - })()} + + +
+ + + {/* Proxy Selection - Common to both tabs - Always visible */} +
+
+ + setShowProxyForm(true)} + className="px-2 h-7 text-xs" + > + Add Proxy + +
+ {storedProxies.length > 0 ? ( + + ) : ( +
+ No proxies available. Add one to route this profile's + traffic.
)} - -
- - - {/* Proxy Selection - Common to both tabs - Compact without card */} - {storedProxies.length > 0 && ( -
- - -
- )} +
@@ -593,6 +618,14 @@ export function CreateProfileDialog({ + setShowProxyForm(false)} + onSave={(proxy) => { + setStoredProxies((prev) => [...prev, proxy]); + setSelectedProxyId(proxy.id); + }} + />
); } diff --git a/src/components/group-assignment-dialog.tsx b/src/components/group-assignment-dialog.tsx index 7fca1ea..28fe5e9 100644 --- a/src/components/group-assignment-dialog.tsx +++ b/src/components/group-assignment-dialog.tsx @@ -2,7 +2,9 @@ import { invoke } from "@tauri-apps/api/core"; import { useCallback, useEffect, useState } from "react"; +import { GoPlus } from "react-icons/go"; import { toast } from "sonner"; +import { CreateGroupDialog } from "@/components/create-group-dialog"; import { LoadingButton } from "@/components/loading-button"; import { Dialog, @@ -41,6 +43,7 @@ export function GroupAssignmentDialog({ const [isLoading, setIsLoading] = useState(false); const [isAssigning, setIsAssigning] = useState(false); const [error, setError] = useState(null); + const [createDialogOpen, setCreateDialogOpen] = useState(false); const loadGroups = useCallback(async () => { setIsLoading(true); @@ -126,7 +129,17 @@ export function GroupAssignmentDialog({
- +
+ + setCreateDialogOpen(true)} + > + Create Group + +
{isLoading ? (
Loading groups... @@ -177,6 +190,15 @@ export function GroupAssignmentDialog({ + setCreateDialogOpen(false)} + onGroupCreated={(group) => { + setGroups((prev) => [...prev, group]); + setSelectedGroupId(group.id); + setCreateDialogOpen(false); + }} + /> ); } diff --git a/src/components/home-header.tsx b/src/components/home-header.tsx index 445388b..a5e6254 100644 --- a/src/components/home-header.tsx +++ b/src/components/home-header.tsx @@ -49,8 +49,9 @@ const HomeHeader = ({ type="button" className="p-1 cursor-pointer" title="Open donutbrowser.com" + onClick={_handleLogoClick} > - + {selectedProfiles.length > 0 ? (
diff --git a/src/components/ui/combobox.tsx b/src/components/ui/combobox.tsx index 18bf624..14e57a1 100644 --- a/src/components/ui/combobox.tsx +++ b/src/components/ui/combobox.tsx @@ -18,7 +18,6 @@ import { PopoverTrigger, } from "@/components/ui/popover"; import { cn } from "@/lib/utils"; -import { RippleButton } from "./ripple"; interface ComboboxOption { value: string; @@ -48,7 +47,7 @@ export function Combobox({ return ( - option.value === value)?.label : placeholder} - +