optimize: update menu bar UI

This commit is contained in:
wj-xiao
2025-12-22 15:52:16 +08:00
parent 9a925dd49a
commit 758449cdc0
12 changed files with 74 additions and 71 deletions

View File

@@ -44,10 +44,8 @@ export const Direction = (): ReactElement => {
return (
<Popover content={content} placement="rightTop" arrow={false} align={{ offset: [13, 0] }}>
<div className="flex h-[30px] cursor-pointer items-center space-x-1 rounded px-3 text-neutral-300 hover:bg-neutral-700/50">
<div className="flex h-[14px] w-[20px] items-end">
<ArrowDownUpIcon size={16} />
</div>
<div className="flex h-[32px] cursor-pointer items-center space-x-2 rounded px-3 text-neutral-300 hover:bg-neutral-700/50">
<ArrowDownUpIcon size={18} />
<span>{t('mouse.direction')}</span>
</div>
</Popover>

View File

@@ -1,5 +1,5 @@
import { useEffect, useState } from 'react';
import { Popover } from 'antd';
import { Divider, Popover } from 'antd';
import { useAtom, useSetAtom } from 'jotai';
import { MouseIcon } from 'lucide-react';
@@ -59,13 +59,15 @@ export const Mouse = () => {
}
const content = (
<>
<div className="flex flex-col space-y-0.5">
<Style />
<Mode />
<Direction />
<Speed />
<Divider style={{ margin: '5px 0 5px 0' }} />
<Jiggler />
</>
</div>
);
return (

View File

@@ -2,7 +2,7 @@ import { useEffect } from 'react';
import { Popover } from 'antd';
import clsx from 'clsx';
import { useAtom } from 'jotai';
import { MousePointerIcon } from 'lucide-react';
import { MousePointerClickIcon } from 'lucide-react';
import { useTranslation } from 'react-i18next';
import { mouseJigglerModeAtom } from '@/jotai/mouse.ts';
@@ -33,7 +33,7 @@ export const Jiggler = () => {
<div
key={mode.value}
className={clsx(
'my-1 flex cursor-pointer items-center space-x-1 rounded py-1 pr-5 pl-2 hover:bg-neutral-700/50',
'my-1 flex cursor-pointer items-center space-x-1 rounded py-1 pl-2 pr-5 hover:bg-neutral-700/50',
mode.value === jigglerMode ? 'text-blue-500' : 'text-neutral-300'
)}
onClick={() => update(mode.value)}
@@ -43,12 +43,11 @@ export const Jiggler = () => {
))}
</>
);
return (
<Popover content={content} placement="rightTop" arrow={false} align={{ offset: [13, 0] }}>
<div className="flex h-[30px] cursor-pointer items-center space-x-1 rounded px-3 text-neutral-300 hover:bg-neutral-700/50">
<div className="flex h-[14px] w-[20px] items-end">
<MousePointerIcon size={16} />
</div>
<div className="flex h-[32px] cursor-pointer items-center space-x-2 rounded px-3 text-neutral-300 hover:bg-neutral-700/50">
<MousePointerClickIcon size={18} />
<span>{t('mouse.jiggler.title')}</span>
</div>
</Popover>

View File

@@ -40,8 +40,8 @@ export const Mode = () => {
return (
<Popover content={content} placement="rightTop" arrow={false} align={{ offset: [13, 0] }}>
<div className="flex h-[30px] cursor-pointer items-center space-x-1 rounded px-3 text-neutral-300 hover:bg-neutral-700/50">
<div className="flex h-[14px] w-[20px] items-end">
<div className="flex h-[32px] cursor-pointer items-center space-x-2 rounded px-3 text-neutral-300 hover:bg-neutral-700/50">
<div className="flex size-[18px] items-center justify-center">
<SquareMousePointerIcon size={16} />
</div>
<span>{t('mouse.mode')}</span>

View File

@@ -57,10 +57,8 @@ export const Speed = (): ReactElement => {
return (
<Popover content={content} placement="rightTop" arrow={false} align={{ offset: [13, 0] }}>
<div className="flex h-[30px] cursor-pointer items-center space-x-1 rounded px-3 text-neutral-300 hover:bg-neutral-700/50">
<div className="flex h-[14px] w-[20px] items-end">
<GaugeIcon size={16} />
</div>
<div className="flex h-[32px] cursor-pointer items-center space-x-2 rounded px-3 text-neutral-300 hover:bg-neutral-700/50">
<GaugeIcon size={18} />
<span>{t('mouse.speed')}</span>
</div>
</Popover>

View File

@@ -34,7 +34,7 @@ export const Style = () => {
<div
key={style.value}
className={clsx(
'flex cursor-pointer select-none items-center space-x-1 rounded py-1.5 pl-3 pr-5 hover:bg-neutral-700/50',
'flex cursor-pointer select-none items-center space-x-1 rounded py-1 pl-3 pr-5 hover:bg-neutral-700/50',
style.value === mouseStyle ? 'text-blue-500' : 'text-neutral-300'
)}
onClick={() => updateStyle(style.value)}
@@ -48,8 +48,8 @@ export const Style = () => {
return (
<Popover content={content} placement="rightTop" arrow={false} align={{ offset: [13, 0] }}>
<div className="flex h-[30px] cursor-pointer items-center space-x-2 rounded px-3 text-neutral-300 hover:bg-neutral-700">
<MousePointerIcon size={16} />
<div className="flex h-[32px] cursor-pointer items-center space-x-2 rounded px-3 text-neutral-300 hover:bg-neutral-700/50">
<MousePointerIcon size={18} />
<span className="select-none text-sm">{t('mouse.cursor.title')}</span>
</div>
</Popover>

View File

@@ -12,11 +12,11 @@ export const Settings = () => {
}
const content = (
<div className="flex flex-col space-y-1">
<div className="flex flex-col space-y-0.5">
<Language />
<div
className="flex h-[30px] cursor-pointer items-center space-x-2 rounded px-3 text-neutral-300 hover:bg-neutral-700"
className="flex h-[32px] cursor-pointer items-center space-x-2 rounded px-3 text-neutral-300 hover:bg-neutral-700/50"
onClick={() => openPage('https://wiki.sipeed.com/nanokvmusb')}
>
<BookIcon size={18} />
@@ -24,7 +24,7 @@ export const Settings = () => {
</div>
<div
className="flex h-[30px] cursor-pointer items-center space-x-2 rounded px-3 text-neutral-300 hover:bg-neutral-700"
className="flex h-[32px] cursor-pointer items-center space-x-2 rounded px-3 text-neutral-300 hover:bg-neutral-700/50"
onClick={() => openPage('https://github.com/sipeed/NanoKVM-USB/releases')}
>
<DownloadIcon size={18} />
@@ -35,7 +35,7 @@ export const Settings = () => {
return (
<Popover content={content} placement="bottomLeft" trigger="click" arrow={false}>
<div className="flex h-[28px] w-[28px] cursor-pointer items-center justify-center rounded text-white hover:bg-neutral-700/70">
<div className="flex h-[28px] w-[28px] cursor-pointer items-center justify-center rounded text-white hover:bg-neutral-700/50">
<SettingsIcon size={18} />
</div>
</Popover>

View File

@@ -35,7 +35,7 @@ export const Language = () => {
return (
<Popover content={content} placement="rightTop">
<div className="flex h-[30px] cursor-pointer items-center space-x-2 rounded px-3 text-neutral-300 hover:bg-neutral-700">
<div className="flex h-[32px] cursor-pointer items-center space-x-2 rounded px-3 text-neutral-300 hover:bg-neutral-700/50">
<LanguagesIcon size={18} />
<span>{t('settings.language')}</span>
</div>

View File

@@ -78,7 +78,7 @@ export const Device = () => {
<div
key={device.videoId}
className={clsx(
'cursor-pointer rounded px-2 py-1.5 hover:bg-neutral-700/60',
'max-w-[320px] cursor-pointer truncate rounded px-2 py-1.5 hover:bg-neutral-700/60',
device.videoId === videoDeviceId ? 'text-blue-500' : 'text-white'
)}
onClick={() => selectDevice(device)}
@@ -91,7 +91,7 @@ export const Device = () => {
return (
<Popover content={content} placement="rightTop" arrow={false} align={{ offset: [13, 0] }}>
<div className="flex h-[30px] cursor-pointer items-center space-x-2 rounded px-3 text-neutral-300 hover:bg-neutral-700">
<div className="flex h-[32px] cursor-pointer items-center space-x-2 rounded px-3 text-neutral-300 hover:bg-neutral-700/50">
<VideoIcon size={18} />
<span className="select-none text-sm">{t('video.device')}</span>
</div>

View File

@@ -7,7 +7,7 @@ import { Scale } from './scale.tsx';
export const Video = () => {
const content = (
<div className="flex flex-col space-y-1">
<div className="flex flex-col space-y-0.5">
<Resolution />
<Scale />
<Device />

View File

@@ -102,7 +102,7 @@ export const Resolution = () => {
<div
key={res.width}
className={clsx(
'flex cursor-pointer select-none items-center space-x-1 rounded px-3 py-1.5 hover:bg-neutral-700/60',
'flex cursor-pointer select-none items-center space-x-1 rounded px-4 py-1.5 hover:bg-neutral-700/60',
resolution.width === res.width && resolution.height === res.height
? 'text-blue-500'
: 'text-white'
@@ -119,13 +119,13 @@ export const Resolution = () => {
{/* custom resolution */}
<div
className="flex cursor-pointer select-none items-center justify-between space-x-3 rounded px-3 py-1.5 text-sm hover:bg-neutral-700/60"
className="flex cursor-pointer select-none items-center justify-between space-x-3 rounded px-4 py-1.5 text-sm hover:bg-neutral-700/60"
onClick={showModal}
>
<span>{t('video.customResolution')}</span>
{customResolutions.length > 0 && (
<span className="hover:text-red-500" onClick={removeCustomResolution}>
<Trash2Icon size={16} />
<Trash2Icon size={14} />
</span>
)}
</div>
@@ -134,7 +134,7 @@ export const Resolution = () => {
<div
key={res.width}
className={clsx(
'flex cursor-pointer select-none items-center space-x-1 rounded px-3 py-1.5 hover:bg-neutral-700/60',
'flex cursor-pointer select-none items-center space-x-1 rounded px-4 py-1.5 hover:bg-neutral-700/60',
resolution.width === res.width && resolution.height === res.height
? 'text-blue-500'
: 'text-white'
@@ -152,7 +152,7 @@ export const Resolution = () => {
return (
<>
<Popover content={content} placement="rightTop" arrow={false} align={{ offset: [13, 0] }}>
<div className="flex h-[30px] cursor-pointer items-center space-x-2 rounded px-3 text-neutral-300 hover:bg-neutral-700">
<div className="flex h-[32px] cursor-pointer items-center space-x-2 rounded px-3 text-neutral-300 hover:bg-neutral-700/50">
<RatioIcon size={18} />
<span className="select-none text-sm">{t('video.resolution')}</span>
</div>

View File

@@ -1,58 +1,64 @@
import { ReactElement, useEffect } from 'react'
import { Popover, Slider } from 'antd'
import { useAtom } from 'jotai'
import { ScalingIcon } from 'lucide-react'
import { useTranslation } from 'react-i18next'
import { ReactElement, useEffect } from 'react';
import { Popover } from 'antd';
import clsx from 'clsx';
import { useAtom } from 'jotai';
import { PercentIcon, ScalingIcon } from 'lucide-react';
import { useTranslation } from 'react-i18next';
import { videoScaleAtom } from '@/jotai/device.ts';
import * as storage from '@/libs/storage';
export const Scale = (): ReactElement => {
const { t } = useTranslation()
const ScaleList = [
{ label: '200', value: 2 },
{ label: '150', value: 1.5 },
{ label: '100', value: 1 },
{ label: '75', value: 0.75 },
{ label: '50', value: 0.5 }
];
const [videoScale, setVideoScale] = useAtom(videoScaleAtom)
export const Scale = (): ReactElement => {
const { t } = useTranslation();
const [videoScale, setVideoScale] = useAtom(videoScaleAtom);
useEffect(() => {
const scale = storage.getVideoScale()
const scale = storage.getVideoScale();
if (scale) {
setVideoScale(scale)
setVideoScale(scale);
}
}, [])
}, []);
async function updateScale(scale: number): Promise<void> {
setVideoScale(scale)
storage.setVideoScale(scale)
setVideoScale(scale);
storage.setVideoScale(scale);
}
const content = (
<div className="h-[150px] w-[60px] py-3">
<Slider
vertical
marks={{
0.5: <span>x0.5</span>,
1: <span>x1.0</span>,
1.5: <span>x1.5</span>,
2: <span>x2.0</span>
}}
range={false}
included={false}
min={0.5}
max={2}
step={0.1}
defaultValue={videoScale}
onChange={updateScale}
/>
</div>
)
<>
{ScaleList.map((item) => (
<div
key={item.value}
className={clsx(
'flex cursor-pointer select-none items-center space-x-0.5 rounded px-5 py-1.5 hover:bg-neutral-700/60',
item.value === videoScale ? 'text-blue-500' : 'text-white'
)}
onClick={() => updateScale(item.value)}
>
<span>{item.label}</span>
<PercentIcon size={12} />
</div>
))}
</>
);
return (
<Popover content={content} placement="rightTop" arrow={false} align={{ offset: [13, 0] }}>
<div className="flex h-[30px] cursor-pointer items-center space-x-1 rounded px-3 text-neutral-300 hover:bg-neutral-700/50">
<div className="flex h-[14px] w-[20px] items-end">
<div className="flex h-[32px] cursor-pointer items-center space-x-2 rounded px-3 text-neutral-300 hover:bg-neutral-700/50">
<div className="flex size-[18px] items-center justify-center">
<ScalingIcon size={16} />
</div>
<span>{t('video.scale')}</span>
</div>
</Popover>
)
}
);
};