mirror of
https://github.com/fankes/komari-theme-purcarte.git
synced 2025-10-19 03:49:22 +08:00
feat: 添加列表视图进度条选项并优化进度条显示
This commit is contained in:
@@ -129,6 +129,13 @@
|
|||||||
"default": true,
|
"default": true,
|
||||||
"help": "启用后默认显示 SWAP 信息"
|
"help": "启用后默认显示 SWAP 信息"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"key": "enableListItemProgressBar",
|
||||||
|
"name": "启用列表视图进度条",
|
||||||
|
"type": "switch",
|
||||||
|
"default": true,
|
||||||
|
"help": "启用后列表视图中将会显示进度条来表示存储使用率"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "Instance 设置",
|
"name": "Instance 设置",
|
||||||
"type": "title"
|
"type": "title"
|
||||||
|
@@ -33,12 +33,6 @@ export const NodeCard = ({ node, enableSwap }: NodeCardProps) => {
|
|||||||
trafficPercentage,
|
trafficPercentage,
|
||||||
} = useNodeCommons(node);
|
} = useNodeCommons(node);
|
||||||
|
|
||||||
const getProgressBarClass = (percentage: number) => {
|
|
||||||
if (percentage > 90) return "bg-red-600";
|
|
||||||
if (percentage > 50) return "bg-yellow-400";
|
|
||||||
return "bg-green-500";
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card
|
<Card
|
||||||
className={`flex flex-col mx-auto purcarte-blur w-full min-w-[280px] max-w-sm ${
|
className={`flex flex-col mx-auto purcarte-blur w-full min-w-[280px] max-w-sm ${
|
||||||
@@ -88,20 +82,14 @@ export const NodeCard = ({ node, enableSwap }: NodeCardProps) => {
|
|||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<span className="text-secondary-foreground">CPU</span>
|
<span className="text-secondary-foreground">CPU</span>
|
||||||
<div className="w-3/4 flex items-center gap-2">
|
<div className="w-3/4 flex items-center gap-2">
|
||||||
<ProgressBar
|
<ProgressBar value={cpuUsage} />
|
||||||
value={cpuUsage}
|
|
||||||
className={getProgressBarClass(cpuUsage)}
|
|
||||||
/>
|
|
||||||
<span className="w-12 text-right">{cpuUsage.toFixed(0)}%</span>
|
<span className="w-12 text-right">{cpuUsage.toFixed(0)}%</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<span className="text-secondary-foreground">内存</span>
|
<span className="text-secondary-foreground">内存</span>
|
||||||
<div className="w-3/4 flex items-center gap-2">
|
<div className="w-3/4 flex items-center gap-2">
|
||||||
<ProgressBar
|
<ProgressBar value={memUsage} />
|
||||||
value={memUsage}
|
|
||||||
className={getProgressBarClass(memUsage)}
|
|
||||||
/>
|
|
||||||
<span className="w-12 text-right">{memUsage.toFixed(0)}%</span>
|
<span className="w-12 text-right">{memUsage.toFixed(0)}%</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -109,10 +97,7 @@ export const NodeCard = ({ node, enableSwap }: NodeCardProps) => {
|
|||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<span className="text-secondary-foreground">SWAP</span>
|
<span className="text-secondary-foreground">SWAP</span>
|
||||||
<div className="w-3/4 flex items-center gap-2">
|
<div className="w-3/4 flex items-center gap-2">
|
||||||
<ProgressBar
|
<ProgressBar value={swapUsage} />
|
||||||
value={swapUsage}
|
|
||||||
className={getProgressBarClass(swapUsage)}
|
|
||||||
/>
|
|
||||||
{node.swap_total > 0 ? (
|
{node.swap_total > 0 ? (
|
||||||
<span className="w-12 text-right">{swapUsage.toFixed(0)}%</span>
|
<span className="w-12 text-right">{swapUsage.toFixed(0)}%</span>
|
||||||
) : (
|
) : (
|
||||||
@@ -124,10 +109,7 @@ export const NodeCard = ({ node, enableSwap }: NodeCardProps) => {
|
|||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<span className="text-secondary-foreground">硬盘</span>
|
<span className="text-secondary-foreground">硬盘</span>
|
||||||
<div className="w-3/4 flex items-center gap-2">
|
<div className="w-3/4 flex items-center gap-2">
|
||||||
<ProgressBar
|
<ProgressBar value={diskUsage} />
|
||||||
value={diskUsage}
|
|
||||||
className={getProgressBarClass(diskUsage)}
|
|
||||||
/>
|
|
||||||
<span className="w-12 text-right">{diskUsage.toFixed(0)}%</span>
|
<span className="w-12 text-right">{diskUsage.toFixed(0)}%</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -6,13 +6,19 @@ import Flag from "./Flag";
|
|||||||
import { Tag } from "../ui/tag";
|
import { Tag } from "../ui/tag";
|
||||||
import { useNodeCommons } from "@/hooks/useNodeCommons";
|
import { useNodeCommons } from "@/hooks/useNodeCommons";
|
||||||
import { CircleProgress } from "../ui/circle-progress";
|
import { CircleProgress } from "../ui/circle-progress";
|
||||||
|
import { ProgressBar } from "../ui/progress-bar";
|
||||||
|
|
||||||
interface NodeListItemProps {
|
interface NodeListItemProps {
|
||||||
node: NodeWithStatus;
|
node: NodeWithStatus;
|
||||||
enableSwap: boolean | undefined;
|
enableSwap: boolean | undefined;
|
||||||
|
enableListItemProgressBar: boolean | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const NodeListItem = ({ node, enableSwap }: NodeListItemProps) => {
|
export const NodeListItem = ({
|
||||||
|
node,
|
||||||
|
enableSwap,
|
||||||
|
enableListItemProgressBar,
|
||||||
|
}: NodeListItemProps) => {
|
||||||
const {
|
const {
|
||||||
stats,
|
stats,
|
||||||
isOnline,
|
isOnline,
|
||||||
@@ -60,16 +66,32 @@ export const NodeListItem = ({ node, enableSwap }: NodeListItemProps) => {
|
|||||||
<CpuIcon className="inline-block size-5 flex-shrink-0 text-blue-600" />
|
<CpuIcon className="inline-block size-5 flex-shrink-0 text-blue-600" />
|
||||||
<div className="ml-1 w-full items-center justify-center">
|
<div className="ml-1 w-full items-center justify-center">
|
||||||
<div>{node.cpu_cores} Cores</div>
|
<div>{node.cpu_cores} Cores</div>
|
||||||
<div>{isOnline ? `${cpuUsage.toFixed(1)}%` : "N/A"}</div>
|
{enableListItemProgressBar ? (
|
||||||
|
<div className="flex items-center gap-1">
|
||||||
|
<ProgressBar value={cpuUsage} h="h-2" />
|
||||||
|
<span className="w-10 text-right text-xs">
|
||||||
|
{isOnline ? `${cpuUsage.toFixed(0)}%` : "N/A"}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div>{isOnline ? `${cpuUsage.toFixed(0)}%` : "N/A"}</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="col-span-1 flex items-center text-left">
|
<div className="col-span-1 flex items-center text-left">
|
||||||
<MemoryStickIcon className="inline-block size-5 flex-shrink-0 text-green-600" />
|
<MemoryStickIcon className="inline-block size-5 flex-shrink-0 text-green-600" />
|
||||||
<div className="ml-1 w-full items-center justify-center">
|
<div className="ml-1 w-full items-center justify-center">
|
||||||
<div>{formatBytes(node.mem_total)}</div>
|
<div>{formatBytes(node.mem_total)}</div>
|
||||||
<div className="mt-1">
|
{enableListItemProgressBar ? (
|
||||||
{isOnline ? `${memUsage.toFixed(1)}%` : "N/A"}
|
<div className="flex items-center gap-1">
|
||||||
</div>
|
<ProgressBar value={memUsage} h="h-2" />
|
||||||
|
<span className="w-10 text-right text-xs">
|
||||||
|
{isOnline ? `${memUsage.toFixed(0)}%` : "N/A"}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div>{isOnline ? `${memUsage.toFixed(0)}%` : "N/A"}</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{enableSwap && (
|
{enableSwap && (
|
||||||
@@ -78,9 +100,16 @@ export const NodeListItem = ({ node, enableSwap }: NodeListItemProps) => {
|
|||||||
{node.swap_total > 0 ? (
|
{node.swap_total > 0 ? (
|
||||||
<div className="ml-1 w-full items-center justify-center">
|
<div className="ml-1 w-full items-center justify-center">
|
||||||
<div>{formatBytes(node.swap_total)}</div>
|
<div>{formatBytes(node.swap_total)}</div>
|
||||||
<div className="mt-1">
|
{enableListItemProgressBar ? (
|
||||||
{isOnline ? `${swapUsage.toFixed(1)}%` : "N/A"}
|
<div className="flex items-center gap-1">
|
||||||
</div>
|
<ProgressBar value={swapUsage} h="h-2" />
|
||||||
|
<span className="w-10 text-right text-xs">
|
||||||
|
{isOnline ? `${swapUsage.toFixed(0)}%` : "N/A"}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div>{isOnline ? `${swapUsage.toFixed(0)}%` : "N/A"}</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="ml-1 w-full item-center justify-center">OFF</div>
|
<div className="ml-1 w-full item-center justify-center">OFF</div>
|
||||||
@@ -91,9 +120,16 @@ export const NodeListItem = ({ node, enableSwap }: NodeListItemProps) => {
|
|||||||
<HardDriveIcon className="inline-block size-5 flex-shrink-0 text-red-600" />
|
<HardDriveIcon className="inline-block size-5 flex-shrink-0 text-red-600" />
|
||||||
<div className="ml-1 w-full items-center justify-center">
|
<div className="ml-1 w-full items-center justify-center">
|
||||||
<div>{formatBytes(node.disk_total)}</div>
|
<div>{formatBytes(node.disk_total)}</div>
|
||||||
<div className="mt-1">
|
{enableListItemProgressBar ? (
|
||||||
{isOnline ? `${diskUsage.toFixed(1)}%` : "N/A"}
|
<div className="flex items-center gap-1">
|
||||||
</div>
|
<ProgressBar value={diskUsage} h="h-2" />
|
||||||
|
<span className="w-10 text-right text-xs">
|
||||||
|
{isOnline ? `${diskUsage.toFixed(0)}%` : "N/A"}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div>{isOnline ? `${diskUsage.toFixed(0)}%` : "N/A"}</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="col-span-1">
|
<div className="col-span-1">
|
||||||
|
@@ -1,13 +1,19 @@
|
|||||||
|
import { getProgressBarClass } from "@/utils";
|
||||||
|
|
||||||
export const ProgressBar = ({
|
export const ProgressBar = ({
|
||||||
value,
|
value,
|
||||||
|
h = "h-3",
|
||||||
className,
|
className,
|
||||||
}: {
|
}: {
|
||||||
value: number;
|
value: number;
|
||||||
|
h?: string;
|
||||||
className?: string;
|
className?: string;
|
||||||
}) => (
|
}) => (
|
||||||
<div className="w-full bg-gray-200 rounded-full h-3 dark:bg-gray-700">
|
<div className={`w-full bg-gray-200 rounded-full ${h} dark:bg-gray-700`}>
|
||||||
<div
|
<div
|
||||||
className={`h-3 rounded-full transition-all duration-500 ${className}`}
|
className={`${h} rounded-full transition-all duration-500 ${getProgressBarClass(
|
||||||
|
value
|
||||||
|
)} ${className}`}
|
||||||
style={{ width: `${value}%` }}></div>
|
style={{ width: `${value}%` }}></div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@@ -105,6 +105,9 @@ export function ConfigProvider({
|
|||||||
blurValue,
|
blurValue,
|
||||||
blurBackgroundColor,
|
blurBackgroundColor,
|
||||||
enableSwap: theme.enableSwap ?? DEFAULT_CONFIG.enableSwap,
|
enableSwap: theme.enableSwap ?? DEFAULT_CONFIG.enableSwap,
|
||||||
|
enableListItemProgressBar:
|
||||||
|
theme.enableListItemProgressBar ??
|
||||||
|
DEFAULT_CONFIG.enableListItemProgressBar,
|
||||||
}),
|
}),
|
||||||
[
|
[
|
||||||
theme,
|
theme,
|
||||||
|
@@ -19,6 +19,7 @@ export interface ConfigOptions {
|
|||||||
enableConnectBreaks?: boolean; // 是否启用连接断点
|
enableConnectBreaks?: boolean; // 是否启用连接断点
|
||||||
pingChartMaxPoints?: number; // 延迟图表最大点数
|
pingChartMaxPoints?: number; // 延迟图表最大点数
|
||||||
enableSwap?: boolean; // 是否启用SWAP显示
|
enableSwap?: boolean; // 是否启用SWAP显示
|
||||||
|
enableListItemProgressBar?: boolean; // 是否启用列表视图进度条
|
||||||
}
|
}
|
||||||
|
|
||||||
// 默认配置值
|
// 默认配置值
|
||||||
@@ -43,4 +44,5 @@ export const DEFAULT_CONFIG: ConfigOptions = {
|
|||||||
enableConnectBreaks: false,
|
enableConnectBreaks: false,
|
||||||
pingChartMaxPoints: 0,
|
pingChartMaxPoints: 0,
|
||||||
enableSwap: true,
|
enableSwap: true,
|
||||||
|
enableListItemProgressBar: true,
|
||||||
};
|
};
|
||||||
|
@@ -26,7 +26,12 @@ const HomePage: React.FC<HomePageProps> = ({ viewMode, searchTerm }) => {
|
|||||||
const [selectedGroup, setSelectedGroup] = useState(
|
const [selectedGroup, setSelectedGroup] = useState(
|
||||||
homeStateCache.selectedGroup
|
homeStateCache.selectedGroup
|
||||||
);
|
);
|
||||||
const { enableGroupedBar, enableStatsBar, enableSwap } = useAppConfig();
|
const {
|
||||||
|
enableGroupedBar,
|
||||||
|
enableStatsBar,
|
||||||
|
enableSwap,
|
||||||
|
enableListItemProgressBar,
|
||||||
|
} = useAppConfig();
|
||||||
const [displayOptions, setDisplayOptions] = useState({
|
const [displayOptions, setDisplayOptions] = useState({
|
||||||
time: true,
|
time: true,
|
||||||
online: true,
|
online: true,
|
||||||
@@ -173,6 +178,7 @@ const HomePage: React.FC<HomePageProps> = ({ viewMode, searchTerm }) => {
|
|||||||
key={node.uuid}
|
key={node.uuid}
|
||||||
node={node}
|
node={node}
|
||||||
enableSwap={enableSwap}
|
enableSwap={enableSwap}
|
||||||
|
enableListItemProgressBar={enableListItemProgressBar}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
)}
|
)}
|
||||||
|
@@ -105,3 +105,9 @@ export const formatTrafficLimit = (
|
|||||||
|
|
||||||
return `总 ${limitText} (${typeText})`;
|
return `总 ${limitText} (${typeText})`;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getProgressBarClass = (percentage: number) => {
|
||||||
|
if (percentage > 90) return "bg-red-600";
|
||||||
|
if (percentage > 50) return "bg-yellow-400";
|
||||||
|
return "bg-green-500";
|
||||||
|
};
|
||||||
|
Reference in New Issue
Block a user