feat: update icon alert warning and copies tooltip model dropdown (#3021)
* feat: update icon alert warning and copies tooltip model dropdown * chore: update loader when user click download model dropdown
This commit is contained in:
parent
aecc645a1a
commit
cf8f401dab
50
web/containers/Loader/ProgressCircle.tsx
Normal file
50
web/containers/Loader/ProgressCircle.tsx
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
interface ProgressCircleProps {
|
||||||
|
percentage: number
|
||||||
|
size?: number
|
||||||
|
strokeWidth?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
const ProgressCircle: React.FC<ProgressCircleProps> = ({
|
||||||
|
percentage,
|
||||||
|
size = 100,
|
||||||
|
strokeWidth = 14,
|
||||||
|
}) => {
|
||||||
|
const radius = (size - strokeWidth) / 2
|
||||||
|
const circumference = 2 * Math.PI * radius
|
||||||
|
const offset = circumference - (percentage / 100) * circumference
|
||||||
|
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
className="ml-0.5 h-4 w-4 rotate-[-90deg] transform text-[hsla(var(--primary-bg))]"
|
||||||
|
height={size}
|
||||||
|
width={size}
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox={`0 0 ${size} ${size}`}
|
||||||
|
>
|
||||||
|
<circle
|
||||||
|
className="opacity-25"
|
||||||
|
cx={size / 2}
|
||||||
|
cy={size / 2}
|
||||||
|
r={radius}
|
||||||
|
stroke="currentColor"
|
||||||
|
strokeWidth={strokeWidth}
|
||||||
|
fill="none"
|
||||||
|
></circle>
|
||||||
|
<circle
|
||||||
|
className="transition-stroke-dashoffset duration-300"
|
||||||
|
cx={size / 2}
|
||||||
|
cy={size / 2}
|
||||||
|
r={radius}
|
||||||
|
stroke="currentColor"
|
||||||
|
strokeWidth={strokeWidth}
|
||||||
|
fill="none"
|
||||||
|
strokeDasharray={circumference}
|
||||||
|
strokeDashoffset={offset}
|
||||||
|
></circle>
|
||||||
|
</svg>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ProgressCircle
|
||||||
@ -8,16 +8,19 @@ import { useAtom, useAtomValue, useSetAtom } from 'jotai'
|
|||||||
import { ChevronDownIcon, DownloadCloudIcon, XIcon } from 'lucide-react'
|
import { ChevronDownIcon, DownloadCloudIcon, XIcon } from 'lucide-react'
|
||||||
import { twMerge } from 'tailwind-merge'
|
import { twMerge } from 'tailwind-merge'
|
||||||
|
|
||||||
|
import ProgressCircle from '@/containers/Loader/ProgressCircle'
|
||||||
|
|
||||||
import ModelLabel from '@/containers/ModelLabel'
|
import ModelLabel from '@/containers/ModelLabel'
|
||||||
|
|
||||||
import SetupRemoteModel from '@/containers/SetupRemoteModel'
|
import SetupRemoteModel from '@/containers/SetupRemoteModel'
|
||||||
|
|
||||||
import useDownloadModel from '@/hooks/useDownloadModel'
|
import useDownloadModel from '@/hooks/useDownloadModel'
|
||||||
|
import { modelDownloadStateAtom } from '@/hooks/useDownloadState'
|
||||||
import useRecommendedModel from '@/hooks/useRecommendedModel'
|
import useRecommendedModel from '@/hooks/useRecommendedModel'
|
||||||
|
|
||||||
import useUpdateModelParameters from '@/hooks/useUpdateModelParameters'
|
import useUpdateModelParameters from '@/hooks/useUpdateModelParameters'
|
||||||
|
|
||||||
import { toGibibytes } from '@/utils/converter'
|
import { formatDownloadPercentage, toGibibytes } from '@/utils/converter'
|
||||||
|
|
||||||
import { extensionManager } from '@/extension'
|
import { extensionManager } from '@/extension'
|
||||||
|
|
||||||
@ -64,6 +67,7 @@ const ModelDropdown = ({
|
|||||||
const [dropdownOptions, setDropdownOptions] = useState<HTMLDivElement | null>(
|
const [dropdownOptions, setDropdownOptions] = useState<HTMLDivElement | null>(
|
||||||
null
|
null
|
||||||
)
|
)
|
||||||
|
const downloadStates = useAtomValue(modelDownloadStateAtom)
|
||||||
const setThreadModelParams = useSetAtom(setThreadModelParamsAtom)
|
const setThreadModelParams = useSetAtom(setThreadModelParamsAtom)
|
||||||
const { updateModelParameter } = useUpdateModelParameters()
|
const { updateModelParameter } = useUpdateModelParameters()
|
||||||
|
|
||||||
@ -351,12 +355,29 @@ const ModelDropdown = ({
|
|||||||
<span className="font-medium">
|
<span className="font-medium">
|
||||||
{toGibibytes(model.metadata.size)}
|
{toGibibytes(model.metadata.size)}
|
||||||
</span>
|
</span>
|
||||||
{!isDownloading && (
|
{!isDownloading ? (
|
||||||
<DownloadCloudIcon
|
<DownloadCloudIcon
|
||||||
size={18}
|
size={18}
|
||||||
className="cursor-pointer text-[hsla(var(--app-link))]"
|
className="cursor-pointer text-[hsla(var(--app-link))]"
|
||||||
onClick={() => downloadModel(model)}
|
onClick={() => downloadModel(model)}
|
||||||
/>
|
/>
|
||||||
|
) : (
|
||||||
|
Object.values(downloadStates)
|
||||||
|
.filter((x) => x.modelId === model.id)
|
||||||
|
.map((item) => (
|
||||||
|
<ProgressCircle
|
||||||
|
key={item.modelId}
|
||||||
|
percentage={
|
||||||
|
formatDownloadPercentage(
|
||||||
|
item?.percent,
|
||||||
|
{
|
||||||
|
hidePercentage: true,
|
||||||
|
}
|
||||||
|
) as number
|
||||||
|
}
|
||||||
|
size={100}
|
||||||
|
/>
|
||||||
|
))
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
@ -397,12 +418,29 @@ const ModelDropdown = ({
|
|||||||
<span className="font-medium">
|
<span className="font-medium">
|
||||||
{toGibibytes(model.metadata.size)}
|
{toGibibytes(model.metadata.size)}
|
||||||
</span>
|
</span>
|
||||||
{!isDownloading && (
|
{!isDownloading ? (
|
||||||
<DownloadCloudIcon
|
<DownloadCloudIcon
|
||||||
size={18}
|
size={18}
|
||||||
className="cursor-pointer text-[hsla(var(--app-link))]"
|
className="cursor-pointer text-[hsla(var(--app-link))]"
|
||||||
onClick={() => downloadModel(model)}
|
onClick={() => downloadModel(model)}
|
||||||
/>
|
/>
|
||||||
|
) : (
|
||||||
|
Object.values(downloadStates)
|
||||||
|
.filter((x) => x.modelId === model.id)
|
||||||
|
.map((item) => (
|
||||||
|
<ProgressCircle
|
||||||
|
key={item.modelId}
|
||||||
|
percentage={
|
||||||
|
formatDownloadPercentage(
|
||||||
|
item?.percent,
|
||||||
|
{
|
||||||
|
hidePercentage: true,
|
||||||
|
}
|
||||||
|
) as number
|
||||||
|
}
|
||||||
|
size={100}
|
||||||
|
/>
|
||||||
|
))
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
|
|||||||
@ -1,32 +1,49 @@
|
|||||||
import { memo } from 'react'
|
import { Fragment, memo } from 'react'
|
||||||
|
|
||||||
import { Badge, Tooltip } from '@janhq/joi'
|
import { Badge, Tooltip } from '@janhq/joi'
|
||||||
import { InfoIcon } from 'lucide-react'
|
import { AlertTriangleIcon, InfoIcon } from 'lucide-react'
|
||||||
import { twMerge } from 'tailwind-merge'
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
compact?: boolean
|
compact?: boolean
|
||||||
unit: string
|
unit: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const tooltipContent = `Your device doesn't have enough RAM to run this model. Consider upgrading your RAM or using a device with more memory capacity.`
|
||||||
|
|
||||||
const NotEnoughMemoryLabel = ({ unit, compact }: Props) => (
|
const NotEnoughMemoryLabel = ({ unit, compact }: Props) => (
|
||||||
<Badge
|
<>
|
||||||
theme="destructive"
|
{compact ? (
|
||||||
variant="soft"
|
<div className="flex h-5 w-5 items-center">
|
||||||
className={twMerge(compact && 'h-5 w-5 p-1')}
|
<Tooltip
|
||||||
>
|
trigger={
|
||||||
{!compact && <span className="line-clamp-1">Not enough {unit}</span>}
|
<AlertTriangleIcon
|
||||||
<Tooltip
|
size={14}
|
||||||
trigger={
|
className="cursor-pointer text-[hsla(var(--destructive-bg))]"
|
||||||
compact ? (
|
/>
|
||||||
<div className="h-2 w-2 cursor-pointer rounded-full bg-[hsla(var(--destructive-bg))]" />
|
}
|
||||||
) : (
|
content={
|
||||||
<InfoIcon size={14} className="ml-2 flex-shrink-0 cursor-pointer" />
|
<Fragment>
|
||||||
)
|
<b>Not enough RAM:</b> <span>{tooltipContent}</span>
|
||||||
}
|
</Fragment>
|
||||||
content="This tag signals insufficient RAM for optimal model performance. It's dynamic and may change with your system's RAM availability."
|
}
|
||||||
/>
|
/>
|
||||||
</Badge>
|
</div>
|
||||||
|
) : (
|
||||||
|
<Badge theme="destructive" variant="soft">
|
||||||
|
<span className="line-clamp-1">Not enough {unit}</span>
|
||||||
|
<Tooltip
|
||||||
|
trigger={
|
||||||
|
<InfoIcon size={14} className="ml-2 flex-shrink-0 cursor-pointer" />
|
||||||
|
}
|
||||||
|
content={
|
||||||
|
<Fragment>
|
||||||
|
<b>Not enough RAM:</b> <span>{tooltipContent}</span>
|
||||||
|
</Fragment>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Badge>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
)
|
)
|
||||||
|
|
||||||
export default memo(NotEnoughMemoryLabel)
|
export default memo(NotEnoughMemoryLabel)
|
||||||
|
|||||||
@ -1,32 +1,49 @@
|
|||||||
import { memo } from 'react'
|
import { Fragment, memo } from 'react'
|
||||||
|
|
||||||
import { Badge, Tooltip } from '@janhq/joi'
|
import { Badge, Tooltip } from '@janhq/joi'
|
||||||
|
|
||||||
import { InfoIcon } from 'lucide-react'
|
import { AlertTriangleIcon, InfoIcon } from 'lucide-react'
|
||||||
import { twMerge } from 'tailwind-merge'
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
compact?: boolean
|
compact?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const tooltipContent = `Your device may be running low on available RAM, which can affect the speed of this model. Try closing any unnecessary applications to free up system memory.`
|
||||||
|
|
||||||
const SlowOnYourDeviceLabel = ({ compact }: Props) => (
|
const SlowOnYourDeviceLabel = ({ compact }: Props) => (
|
||||||
<Badge
|
<>
|
||||||
theme="warning"
|
{compact ? (
|
||||||
variant="soft"
|
<div className="flex h-5 w-5 items-center">
|
||||||
className={twMerge(compact && 'h-5 w-5 p-1')}
|
<Tooltip
|
||||||
>
|
trigger={
|
||||||
{!compact && <span className="line-clamp-1">Slow on your device</span>}
|
<AlertTriangleIcon
|
||||||
<Tooltip
|
size={14}
|
||||||
trigger={
|
className="cursor-pointer text-[hsla(var(--warning-bg))]"
|
||||||
compact ? (
|
/>
|
||||||
<div className="h-2 w-2 cursor-pointer rounded-full bg-[hsla(var(--warning-bg))] p-0" />
|
}
|
||||||
) : (
|
content={
|
||||||
<InfoIcon size={14} className="ml-2 flex-shrink-0 cursor-pointer" />
|
<Fragment>
|
||||||
)
|
<b>Slow on your device:</b> <span>{tooltipContent}</span>
|
||||||
}
|
</Fragment>
|
||||||
content="This tag indicates that your current RAM performance may affect model speed. It can change based on other active apps. To improve, consider closing unnecessary applications to free up RAM."
|
}
|
||||||
/>
|
/>
|
||||||
</Badge>
|
</div>
|
||||||
|
) : (
|
||||||
|
<Badge theme="warning" variant="soft">
|
||||||
|
<span className="line-clamp-1">Slow on your device</span>
|
||||||
|
<Tooltip
|
||||||
|
trigger={
|
||||||
|
<InfoIcon size={14} className="ml-2 flex-shrink-0 cursor-pointer" />
|
||||||
|
}
|
||||||
|
content={
|
||||||
|
<Fragment>
|
||||||
|
<b>Slow on your device:</b> <span>{tooltipContent}</span>
|
||||||
|
</Fragment>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Badge>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
)
|
)
|
||||||
|
|
||||||
export default memo(SlowOnYourDeviceLabel)
|
export default memo(SlowOnYourDeviceLabel)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user