mirror of
https://github.com/Xevion/dynamic-preauth.git
synced 2025-12-18 12:11:46 -06:00
feat(frontend): add platform icons and improve download button UX
Replace generic download icon with platform-specific icons (Windows, macOS, Linux) using react-icons. Show detected platform name in the main download button text and disable auto-download when platform cannot be detected, requiring manual selection from dropdown instead.
This commit is contained in:
@@ -22,6 +22,7 @@
|
|||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"react": "^19.0.0",
|
"react": "^19.0.0",
|
||||||
"react-dom": "^19.0.0",
|
"react-dom": "^19.0.0",
|
||||||
|
"react-icons": "^5.5.0",
|
||||||
"react-tooltip": "^5.28.0",
|
"react-tooltip": "^5.28.0",
|
||||||
"react-use-websocket": "^4.11.1",
|
"react-use-websocket": "^4.11.1",
|
||||||
"tailwind-merge": "^2.5.5",
|
"tailwind-merge": "^2.5.5",
|
||||||
|
|||||||
12
frontend/pnpm-lock.yaml
generated
12
frontend/pnpm-lock.yaml
generated
@@ -47,6 +47,9 @@ importers:
|
|||||||
react-dom:
|
react-dom:
|
||||||
specifier: ^19.0.0
|
specifier: ^19.0.0
|
||||||
version: 19.0.0(react@19.0.0)
|
version: 19.0.0(react@19.0.0)
|
||||||
|
react-icons:
|
||||||
|
specifier: ^5.5.0
|
||||||
|
version: 5.5.0(react@19.0.0)
|
||||||
react-tooltip:
|
react-tooltip:
|
||||||
specifier: ^5.28.0
|
specifier: ^5.28.0
|
||||||
version: 5.28.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
|
version: 5.28.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
|
||||||
@@ -2086,6 +2089,11 @@ packages:
|
|||||||
peerDependencies:
|
peerDependencies:
|
||||||
react: ^19.0.0
|
react: ^19.0.0
|
||||||
|
|
||||||
|
react-icons@5.5.0:
|
||||||
|
resolution: {integrity: sha512-MEFcXdkP3dLo8uumGI5xN3lDFNsRtrjbOEKDLD7yv76v4wpnEq2Lt2qeHaQOr34I/wPN3s3+N08WkQ+CW37Xiw==}
|
||||||
|
peerDependencies:
|
||||||
|
react: '*'
|
||||||
|
|
||||||
react-refresh@0.14.2:
|
react-refresh@0.14.2:
|
||||||
resolution: {integrity: sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==}
|
resolution: {integrity: sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
@@ -5086,6 +5094,10 @@ snapshots:
|
|||||||
react: 19.0.0
|
react: 19.0.0
|
||||||
scheduler: 0.25.0
|
scheduler: 0.25.0
|
||||||
|
|
||||||
|
react-icons@5.5.0(react@19.0.0):
|
||||||
|
dependencies:
|
||||||
|
react: 19.0.0
|
||||||
|
|
||||||
react-refresh@0.14.2: {}
|
react-refresh@0.14.2: {}
|
||||||
|
|
||||||
react-tooltip@5.28.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0):
|
react-tooltip@5.28.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0):
|
||||||
|
|||||||
@@ -9,10 +9,10 @@ import {
|
|||||||
MenuSeparator,
|
MenuSeparator,
|
||||||
} from "@headlessui/react";
|
} from "@headlessui/react";
|
||||||
import {
|
import {
|
||||||
ArrowDownTrayIcon,
|
|
||||||
BeakerIcon,
|
BeakerIcon,
|
||||||
ChevronDownIcon,
|
ChevronDownIcon,
|
||||||
} from "@heroicons/react/16/solid";
|
} from "@heroicons/react/16/solid";
|
||||||
|
import { FaWindows, FaApple, FaLinux } from "react-icons/fa";
|
||||||
import { useRef } from "react";
|
import { useRef } from "react";
|
||||||
|
|
||||||
type DownloadButtonProps = {
|
type DownloadButtonProps = {
|
||||||
@@ -36,6 +36,34 @@ function getSystemType(): SystemType | null {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getPlatformIcon(id: string, className?: string) {
|
||||||
|
const platformId = id.toLowerCase();
|
||||||
|
switch (platformId) {
|
||||||
|
case "windows":
|
||||||
|
return <FaWindows className={className} />;
|
||||||
|
case "macos":
|
||||||
|
return <FaApple className={className} />;
|
||||||
|
case "linux":
|
||||||
|
return <FaLinux className={className} />;
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPlatformDisplayName(id: string): string {
|
||||||
|
const platformId = id.toLowerCase();
|
||||||
|
switch (platformId) {
|
||||||
|
case "windows":
|
||||||
|
return "Windows";
|
||||||
|
case "macos":
|
||||||
|
return "macOS";
|
||||||
|
case "linux":
|
||||||
|
return "Linux";
|
||||||
|
default:
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export default function DownloadButton({
|
export default function DownloadButton({
|
||||||
disabled,
|
disabled,
|
||||||
executables,
|
executables,
|
||||||
@@ -47,6 +75,10 @@ export default function DownloadButton({
|
|||||||
return executables?.find((e) => e.id.toLowerCase() === id.toLowerCase());
|
return executables?.find((e) => e.id.toLowerCase() === id.toLowerCase());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const detectedPlatform = getSystemType();
|
||||||
|
const platformExecutable = detectedPlatform ? getExecutable(detectedPlatform) : null;
|
||||||
|
const canAutoDownload = platformExecutable != null;
|
||||||
|
|
||||||
async function handleDownload(id: string) {
|
async function handleDownload(id: string) {
|
||||||
const executable = getExecutable(id);
|
const executable = getExecutable(id);
|
||||||
if (executable == null) {
|
if (executable == null) {
|
||||||
@@ -59,16 +91,8 @@ export default function DownloadButton({
|
|||||||
}
|
}
|
||||||
|
|
||||||
function handleDownloadAutomatic() {
|
function handleDownloadAutomatic() {
|
||||||
const systemType = getSystemType();
|
if (canAutoDownload && detectedPlatform) {
|
||||||
|
handleDownload(detectedPlatform);
|
||||||
// If the system type is unknown/unavailable, open the menu for manual selection
|
|
||||||
if (systemType == null || getExecutable(systemType) == null) {
|
|
||||||
menuRef.current?.click();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise, download the executable automatically
|
|
||||||
else {
|
|
||||||
handleDownload(systemType);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,14 +107,17 @@ export default function DownloadButton({
|
|||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<Button
|
<Button
|
||||||
onClick={handleDownloadAutomatic}
|
onClick={canAutoDownload ? handleDownloadAutomatic : undefined}
|
||||||
suppressHydrationWarning
|
suppressHydrationWarning
|
||||||
disabled={disabled}
|
disabled={disabled || !canAutoDownload}
|
||||||
className={cn("pl-3 font-semibold pr-2.5", {
|
className={cn("pl-3 font-semibold pr-2.5", {
|
||||||
"hover:bg-white/5": !disabled,
|
"hover:bg-white/5 cursor-pointer": !disabled && canAutoDownload,
|
||||||
|
"cursor-default": !canAutoDownload,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
Download
|
{canAutoDownload && detectedPlatform
|
||||||
|
? `Download for ${getPlatformDisplayName(detectedPlatform)}`
|
||||||
|
: "Download"}
|
||||||
</Button>
|
</Button>
|
||||||
<Menu>
|
<Menu>
|
||||||
<MenuButton
|
<MenuButton
|
||||||
@@ -115,8 +142,8 @@ export default function DownloadButton({
|
|||||||
onClick={() => handleDownload(executable.id)}
|
onClick={() => handleDownload(executable.id)}
|
||||||
>
|
>
|
||||||
<div className="flex items-center gap-1.5">
|
<div className="flex items-center gap-1.5">
|
||||||
<ArrowDownTrayIcon className="size-4 fill-white/40" />
|
{getPlatformIcon(executable.id, "size-4 fill-white/40")}
|
||||||
{executable.id}
|
{getPlatformDisplayName(executable.id)}
|
||||||
</div>
|
</div>
|
||||||
<div className="text-xs text-zinc-500">
|
<div className="text-xs text-zinc-500">
|
||||||
{(executable.size / 1024 / 1024).toFixed(1)} MiB
|
{(executable.size / 1024 / 1024).toFixed(1)} MiB
|
||||||
|
|||||||
Reference in New Issue
Block a user