Added progress info alert for displaying token usage (#2540)
This commit is contained in:
@@ -1,11 +1,12 @@
|
||||
import React from 'react';
|
||||
import { IoIosCloseCircle, IoIosWarning } from 'react-icons/io';
|
||||
import { IoIosCloseCircle, IoIosWarning, IoIosInformationCircle } from 'react-icons/io';
|
||||
import { cn } from '../../utils';
|
||||
import { Alert, AlertType } from './types';
|
||||
|
||||
const alertIcons: Record<AlertType, React.ReactNode> = {
|
||||
[AlertType.Error]: <IoIosCloseCircle className="h-5 w-5" />,
|
||||
[AlertType.Warning]: <IoIosWarning className="h-5 w-5" />,
|
||||
[AlertType.Info]: <IoIosInformationCircle className="h-5 w-5" />,
|
||||
};
|
||||
|
||||
interface AlertBoxProps {
|
||||
@@ -16,28 +17,73 @@ interface AlertBoxProps {
|
||||
const alertStyles: Record<AlertType, string> = {
|
||||
[AlertType.Error]: 'bg-[#d7040e] text-white',
|
||||
[AlertType.Warning]: 'bg-[#cc4b03] text-white',
|
||||
[AlertType.Info]: 'dark:bg-white dark:text-black bg-black text-white',
|
||||
};
|
||||
|
||||
export const AlertBox = ({ alert, className }: AlertBoxProps) => {
|
||||
return (
|
||||
<div className={cn('flex items-center gap-2 px-3 py-2', alertStyles[alert.type], className)}>
|
||||
<div className="flex-shrink-0">{alertIcons[alert.type]}</div>
|
||||
<div className="flex flex-col gap-2 flex-1">
|
||||
<span className="text-[11px] break-words whitespace-pre-line">{alert.message}</span>
|
||||
{alert.action && (
|
||||
<a
|
||||
role="button"
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
alert.action?.onClick();
|
||||
}}
|
||||
className="text-[11px] text-left underline hover:opacity-80 cursor-pointer outline-none"
|
||||
>
|
||||
{alert.action.text}
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
<div className={cn('flex flex-col gap-2 px-3 py-3', alertStyles[alert.type], className)}>
|
||||
{alert.progress ? (
|
||||
<div className="flex flex-col gap-2">
|
||||
<span className="text-[11px]">{alert.message}</span>
|
||||
<div className="flex justify-between w-full">
|
||||
{[...Array(30)].map((_, i) => (
|
||||
<div
|
||||
key={i}
|
||||
className={cn(
|
||||
'h-[2px] w-[2px] rounded-full',
|
||||
alert.type === AlertType.Info
|
||||
? i < Math.round((alert.progress.current / alert.progress.total) * 30)
|
||||
? 'dark:bg-black bg-white'
|
||||
: 'dark:bg-black/20 bg-white/20'
|
||||
: i < Math.round((alert.progress.current / alert.progress.total) * 30)
|
||||
? 'bg-white'
|
||||
: 'bg-white/20'
|
||||
)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
<div className="flex justify-between items-baseline text-[11px]">
|
||||
<div className="flex gap-1 items-baseline">
|
||||
<span className={'dark:text-black/60 text-white/60'}>
|
||||
{alert.progress.current >= 1000
|
||||
? (alert.progress.current / 1000).toFixed(1) + 'k'
|
||||
: alert.progress.current}
|
||||
</span>
|
||||
<span className={'dark:text-black/40 text-white/40'}>
|
||||
{Math.round((alert.progress.current / alert.progress.total) * 100)}%
|
||||
</span>
|
||||
</div>
|
||||
<span className={'dark:text-black/60 text-white/60'}>
|
||||
{alert.progress.total >= 1000
|
||||
? (alert.progress.total / 1000).toFixed(0) + 'k'
|
||||
: alert.progress.total}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="flex-shrink-0">{alertIcons[alert.type]}</div>
|
||||
<div className="flex flex-col gap-2 flex-1">
|
||||
<span className="text-[11px] break-words whitespace-pre-line">{alert.message}</span>
|
||||
{alert.action && (
|
||||
<a
|
||||
role="button"
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
alert.action?.onClick();
|
||||
}}
|
||||
className="text-[11px] text-left underline hover:opacity-80 cursor-pointer outline-none"
|
||||
>
|
||||
{alert.action.text}
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
export enum AlertType {
|
||||
Error = 'error',
|
||||
Warning = 'warning',
|
||||
Info = 'info',
|
||||
}
|
||||
|
||||
export interface Alert {
|
||||
@@ -11,4 +12,8 @@ export interface Alert {
|
||||
text: string;
|
||||
onClick: () => void;
|
||||
};
|
||||
progress?: {
|
||||
current: number;
|
||||
total: number;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,19 +1,9 @@
|
||||
import { useState, useCallback } from 'react';
|
||||
import { Alert, AlertType } from './types';
|
||||
|
||||
interface AlertOptions {
|
||||
type: AlertType;
|
||||
message: string;
|
||||
action?: {
|
||||
text: string;
|
||||
onClick: () => void;
|
||||
};
|
||||
autoShow?: boolean;
|
||||
}
|
||||
import { Alert } from './types';
|
||||
|
||||
interface UseAlerts {
|
||||
alerts: Alert[];
|
||||
addAlert: (options: AlertOptions) => void;
|
||||
addAlert: (options: Alert) => void;
|
||||
removeAlert: (index: number) => void;
|
||||
clearAlerts: () => void;
|
||||
}
|
||||
@@ -21,7 +11,7 @@ interface UseAlerts {
|
||||
export const useAlerts = (): UseAlerts => {
|
||||
const [alerts, setAlerts] = useState<Alert[]>([]);
|
||||
|
||||
const addAlert = useCallback((options: AlertOptions) => {
|
||||
const addAlert = useCallback((options: Alert) => {
|
||||
setAlerts((prev) => [...prev, options]);
|
||||
}, []);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user