mirror of
https://github.com/Crosstalk-Solutions/project-nomad.git
synced 2026-03-28 11:39:26 +01:00
fix(UI): switch to tabler icons only for consistency
This commit is contained in:
parent
243f749090
commit
0da050c5a3
|
|
@ -1,5 +1,6 @@
|
|||
import * as Icons from '@heroicons/react/24/solid'
|
||||
import * as Icons from '@tabler/icons-react'
|
||||
import classNames from '~/lib/classNames'
|
||||
import DynamicIcon from './DynamicIcon'
|
||||
|
||||
export type AlertProps = React.HTMLAttributes<HTMLDivElement> & {
|
||||
title: string
|
||||
|
|
@ -26,26 +27,18 @@ export default function Alert({
|
|||
const getDefaultIcon = (): keyof typeof Icons => {
|
||||
switch (type) {
|
||||
case 'warning':
|
||||
return 'ExclamationTriangleIcon'
|
||||
return 'IconAlertTriangle'
|
||||
case 'error':
|
||||
return 'XCircleIcon'
|
||||
return 'IconXboxX'
|
||||
case 'success':
|
||||
return 'CheckCircleIcon'
|
||||
return 'IconCircleCheck'
|
||||
case 'info':
|
||||
return 'InformationCircleIcon'
|
||||
return 'IconInfoCircle'
|
||||
default:
|
||||
return 'InformationCircleIcon'
|
||||
return 'IconInfoCircle'
|
||||
}
|
||||
}
|
||||
|
||||
const IconComponent = () => {
|
||||
const iconName = icon || getDefaultIcon()
|
||||
const Icon = Icons[iconName]
|
||||
if (!Icon) return null
|
||||
|
||||
return <Icon aria-hidden="true" className={classNames('size-5 shrink-0', getIconColor())} />
|
||||
}
|
||||
|
||||
const getIconColor = () => {
|
||||
if (variant === 'solid') return 'text-desert-white'
|
||||
switch (type) {
|
||||
|
|
@ -165,7 +158,7 @@ export default function Alert({
|
|||
return (
|
||||
<div {...props} className={classNames(getVariantStyles(), 'p-4', props.className)} role="alert">
|
||||
<div className="flex gap-3">
|
||||
<IconComponent />
|
||||
<DynamicIcon icon={getDefaultIcon()} className={getIconColor() + ' size-5 shrink-0'} />
|
||||
|
||||
<div className="flex-1 min-w-0">
|
||||
<h3 className={classNames('text-sm font-semibold', getTitleColor())}>{title}</h3>
|
||||
|
|
@ -192,7 +185,7 @@ export default function Alert({
|
|||
)}
|
||||
aria-label="Dismiss alert"
|
||||
>
|
||||
<Icons.XMarkIcon className="size-5" />
|
||||
<DynamicIcon icon="IconX" className="size-5" />
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { IconRefresh } from '@tabler/icons-react'
|
||||
import { useState, useEffect } from 'react'
|
||||
import { ArrowPathIcon } from '@heroicons/react/24/outline'
|
||||
import {
|
||||
ADJECTIVES,
|
||||
NOUNS,
|
||||
|
|
@ -118,7 +118,7 @@ export default function BuilderTagSelector({
|
|||
className="p-2 text-desert-stone-dark hover:text-desert-green hover:bg-desert-stone-lighter rounded-lg transition-colors disabled:opacity-50"
|
||||
title="Randomize"
|
||||
>
|
||||
<ArrowPathIcon className="w-5 h-5" />
|
||||
<IconRefresh className="w-5 h-5" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ const DownloadURLModal: React.FC<DownloadURLModalProps> = ({
|
|||
onConfirm={() => runPreflightCheck(url)}
|
||||
open={true}
|
||||
confirmText="Download"
|
||||
confirmIcon="ArrowDownTrayIcon"
|
||||
confirmIcon="IconDownload"
|
||||
cancelText="Cancel"
|
||||
confirmVariant="primary"
|
||||
confirmLoading={loading}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { InformationCircleIcon } from '@heroicons/react/24/outline'
|
||||
import { IconInfoCircle } from '@tabler/icons-react'
|
||||
import { useState } from 'react'
|
||||
|
||||
interface InfoTooltipProps {
|
||||
|
|
@ -20,7 +20,7 @@ export default function InfoTooltip({ text, className = '' }: InfoTooltipProps)
|
|||
onBlur={() => setIsVisible(false)}
|
||||
aria-label="More information"
|
||||
>
|
||||
<InformationCircleIcon className="w-4 h-4" />
|
||||
<IconInfoCircle className="w-4 h-4" />
|
||||
</button>
|
||||
{isVisible && (
|
||||
<div className="absolute bottom-full left-1/2 -translate-x-1/2 mb-2 z-50">
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { CheckCircleIcon } from '@heroicons/react/24/outline'
|
||||
import { IconCircleCheck } from '@tabler/icons-react'
|
||||
import classNames from '~/lib/classNames'
|
||||
|
||||
export type InstallActivityFeedProps = {
|
||||
|
|
@ -41,7 +41,7 @@ const InstallActivityFeed: React.FC<InstallActivityFeedProps> = ({ activity, cla
|
|||
<>
|
||||
<div className="relative flex size-6 flex-none items-center justify-center bg-transparent">
|
||||
{activityItem.type === 'completed' ? (
|
||||
<CheckCircleIcon aria-hidden="true" className="size-6 text-indigo-600" />
|
||||
<IconCircleCheck aria-hidden="true" className="size-6 text-indigo-600" />
|
||||
) : (
|
||||
<div className="size-1.5 rounded-full bg-gray-100 ring-1 ring-gray-300" />
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
import * as Icons from '@heroicons/react/24/outline'
|
||||
import { useMemo } from 'react'
|
||||
import clsx from 'clsx'
|
||||
import DynamicIcon, { DynamicIconName} from './DynamicIcon'
|
||||
import { IconRefresh } from '@tabler/icons-react'
|
||||
|
||||
export interface StyledButtonProps extends React.HTMLAttributes<HTMLButtonElement> {
|
||||
children: React.ReactNode
|
||||
// icon should be one of the HeroIcon names, e.g. ArrowTopRightOnSquareIcon
|
||||
icon?: keyof typeof Icons
|
||||
icon?: DynamicIconName
|
||||
disabled?: boolean
|
||||
variant?: 'primary' | 'secondary' | 'danger' | 'action' | 'success' | 'ghost' | 'outline'
|
||||
size?: 'sm' | 'md' | 'lg'
|
||||
|
|
@ -26,12 +26,6 @@ const StyledButton: React.FC<StyledButtonProps> = ({
|
|||
return props.disabled || loading
|
||||
}, [props.disabled, loading])
|
||||
|
||||
const IconComponent = () => {
|
||||
if (!icon) return null
|
||||
const Icon = Icons[icon]
|
||||
return Icon ? <Icon className={getIconSize()} /> : null
|
||||
}
|
||||
|
||||
const getIconSize = () => {
|
||||
switch (size) {
|
||||
case 'sm':
|
||||
|
|
@ -136,7 +130,7 @@ const StyledButton: React.FC<StyledButtonProps> = ({
|
|||
const getLoadingSpinner = () => {
|
||||
const spinnerSize = size === 'sm' ? 'h-3.5 w-3.5' : size === 'lg' ? 'h-5 w-5' : 'h-4 w-4'
|
||||
return (
|
||||
<Icons.ArrowPathIcon
|
||||
<IconRefresh
|
||||
className={clsx(spinnerSize, 'animate-spin')}
|
||||
/>
|
||||
)
|
||||
|
|
@ -168,7 +162,7 @@ const StyledButton: React.FC<StyledButtonProps> = ({
|
|||
getLoadingSpinner()
|
||||
) : (
|
||||
<>
|
||||
{icon && <IconComponent />}
|
||||
{icon && <DynamicIcon icon={icon} className={getIconSize()} />}
|
||||
{children}
|
||||
</>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
import { useMemo, useState } from 'react'
|
||||
import { Dialog, DialogBackdrop, DialogPanel, TransitionChild } from '@headlessui/react'
|
||||
import { Bars3Icon, XMarkIcon } from '@heroicons/react/24/outline'
|
||||
import classNames from '~/lib/classNames'
|
||||
import { IconArrowLeft } from '@tabler/icons-react'
|
||||
import { usePage } from '@inertiajs/react'
|
||||
import { UsePageProps } from '../../types/system'
|
||||
import { IconMenu2, IconX } from '@tabler/icons-react'
|
||||
|
||||
type SidebarItem = {
|
||||
name: string
|
||||
|
|
@ -89,7 +89,7 @@ const StyledSidebar: React.FC<StyledSidebarProps> = ({ title, items }) => {
|
|||
className="absolute left-4 top-4 z-50 xl:hidden"
|
||||
onClick={() => setSidebarOpen(true)}
|
||||
>
|
||||
<Bars3Icon aria-hidden="true" className="size-8" />
|
||||
<IconMenu2 aria-hidden="true" className="size-8" />
|
||||
</button>
|
||||
{/* Mobile sidebar */}
|
||||
<Dialog open={sidebarOpen} onClose={setSidebarOpen} className="relative z-50 xl:hidden">
|
||||
|
|
@ -111,7 +111,7 @@ const StyledSidebar: React.FC<StyledSidebarProps> = ({ title, items }) => {
|
|||
className="-m-2.5 p-2.5"
|
||||
>
|
||||
<span className="sr-only">Close sidebar</span>
|
||||
<XMarkIcon aria-hidden="true" className="size-6 text-white" />
|
||||
<IconX aria-hidden="true" className="size-6 text-white" />
|
||||
</button>
|
||||
</div>
|
||||
</TransitionChild>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { ChatBubbleLeftRightIcon } from '@heroicons/react/24/outline'
|
||||
import { IconMessages } from '@tabler/icons-react'
|
||||
|
||||
interface ChatButtonProps {
|
||||
onClick: () => void
|
||||
|
|
@ -11,7 +11,7 @@ export default function ChatButton({ onClick }: ChatButtonProps) {
|
|||
className="fixed bottom-6 right-6 z-40 p-4 bg-desert-green text-white rounded-full shadow-lg hover:bg-desert-green/90 transition-all duration-200 hover:scale-110 focus:outline-none focus:ring-2 focus:ring-desert-green focus:ring-offset-2 cursor-pointer"
|
||||
aria-label="Open chat"
|
||||
>
|
||||
<ChatBubbleLeftRightIcon className="h-6 w-6" />
|
||||
<IconMessages className="h-6 w-6" />
|
||||
</button>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import { PaperAirplaneIcon } from '@heroicons/react/24/outline'
|
||||
import { IconWand } from '@tabler/icons-react'
|
||||
import { IconSend, IconWand } from '@tabler/icons-react'
|
||||
import { useState, useRef, useEffect } from 'react'
|
||||
import classNames from '~/lib/classNames'
|
||||
import { ChatMessage } from '../../../types/chat'
|
||||
|
|
@ -139,7 +138,7 @@ export default function ChatInterface({
|
|||
{isLoading ? (
|
||||
<div className="h-6 w-6 border-2 border-white border-t-transparent rounded-full animate-spin" />
|
||||
) : (
|
||||
<PaperAirplaneIcon className="h-6 w-6" />
|
||||
<IconSend className="h-6 w-6" />
|
||||
)}
|
||||
</button>
|
||||
</form>
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { ChatBubbleLeftIcon } from '@heroicons/react/24/outline'
|
||||
import classNames from '~/lib/classNames'
|
||||
import StyledButton from '../StyledButton'
|
||||
import { router } from '@inertiajs/react'
|
||||
import { ChatSession } from '../../../types/chat'
|
||||
import { IconMessage } from '@tabler/icons-react'
|
||||
|
||||
interface ChatSidebarProps {
|
||||
sessions: ChatSession[]
|
||||
|
|
@ -24,7 +24,7 @@ export default function ChatSidebar({
|
|||
return (
|
||||
<div className="w-64 bg-gray-50 border-r border-gray-200 flex flex-col h-full">
|
||||
<div className="p-4 border-b border-gray-200 h-[75px] flex items-center justify-center">
|
||||
<StyledButton onClick={onNewChat} icon="PlusIcon" variant="primary" fullWidth>
|
||||
<StyledButton onClick={onNewChat} icon="IconPlus" variant="primary" fullWidth>
|
||||
New Chat
|
||||
</StyledButton>
|
||||
</div>
|
||||
|
|
@ -46,7 +46,7 @@ export default function ChatSidebar({
|
|||
)}
|
||||
>
|
||||
<div className="flex items-start gap-2">
|
||||
<ChatBubbleLeftIcon
|
||||
<IconMessage
|
||||
className={classNames(
|
||||
'h-5 w-5 mt-0.5 flex-shrink-0',
|
||||
activeSessionId === session.id ? 'text-white' : 'text-gray-400'
|
||||
|
|
@ -83,7 +83,7 @@ export default function ChatSidebar({
|
|||
router.visit('/home')
|
||||
}
|
||||
}}
|
||||
icon={isInModal ? 'ArrowTopRightOnSquareIcon' : 'HomeIcon'}
|
||||
icon={isInModal ? 'IconExternalLink' : 'IconHome'}
|
||||
variant="outline"
|
||||
size="sm"
|
||||
fullWidth
|
||||
|
|
@ -94,7 +94,7 @@ export default function ChatSidebar({
|
|||
onClick={() => {
|
||||
router.visit('/settings/models')
|
||||
}}
|
||||
icon="CircleStackIcon"
|
||||
icon="IconDatabase"
|
||||
variant="primary"
|
||||
size="sm"
|
||||
fullWidth
|
||||
|
|
@ -105,7 +105,7 @@ export default function ChatSidebar({
|
|||
onClick={() => {
|
||||
router.visit('/knowledge-base')
|
||||
}}
|
||||
icon="AcademicCapIcon"
|
||||
icon="IconBrain"
|
||||
variant="primary"
|
||||
size="sm"
|
||||
fullWidth
|
||||
|
|
@ -114,7 +114,7 @@ export default function ChatSidebar({
|
|||
</StyledButton>
|
||||
<StyledButton
|
||||
onClick={onClearHistory}
|
||||
icon="TrashIcon"
|
||||
icon="IconTrash"
|
||||
variant="danger"
|
||||
size="sm"
|
||||
fullWidth
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import { XMarkIcon } from '@heroicons/react/24/outline'
|
||||
import { useState, useCallback, useEffect } from 'react'
|
||||
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
|
||||
import ChatSidebar from './ChatSidebar'
|
||||
|
|
@ -9,6 +8,7 @@ import { formatBytes } from '~/lib/util'
|
|||
import { useModals } from '~/context/ModalContext'
|
||||
import { ChatMessage } from '../../../types/chat'
|
||||
import classNames from '~/lib/classNames'
|
||||
import { IconX } from '@tabler/icons-react'
|
||||
|
||||
interface ChatProps {
|
||||
enabled: boolean
|
||||
|
|
@ -254,7 +254,7 @@ export default function Chat({ enabled, isInModal, onClose }: ChatProps) {
|
|||
}}
|
||||
className="rounded-lg hover:bg-gray-100 transition-colors"
|
||||
>
|
||||
<XMarkIcon className="h-6 w-6 text-gray-500" />
|
||||
<IconX className="h-6 w-6 text-gray-500" />
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,26 +1,24 @@
|
|||
import {
|
||||
ChartBarIcon,
|
||||
Cog6ToothIcon,
|
||||
CommandLineIcon,
|
||||
FolderIcon,
|
||||
MagnifyingGlassIcon,
|
||||
} from '@heroicons/react/24/outline'
|
||||
import {
|
||||
IconArrowBigUpLines,
|
||||
IconChartBar,
|
||||
IconDashboard,
|
||||
IconDatabaseStar,
|
||||
IconFolder,
|
||||
IconGavel,
|
||||
IconMapRoute,
|
||||
IconSettings,
|
||||
IconTerminal2,
|
||||
IconZoom
|
||||
} from '@tabler/icons-react'
|
||||
import StyledSidebar from '~/components/StyledSidebar'
|
||||
import { getServiceLink } from '~/lib/navigation'
|
||||
|
||||
const navigation = [
|
||||
{ name: 'AI Model Manager', href: '/settings/models', icon: IconDatabaseStar, current: false },
|
||||
{ name: 'Apps', href: '/settings/apps', icon: CommandLineIcon, current: false },
|
||||
{ name: 'Benchmark', href: '/settings/benchmark', icon: ChartBarIcon, current: false },
|
||||
{ name: 'Content Explorer', href: '/settings/zim/remote-explorer', icon: MagnifyingGlassIcon, current: false },
|
||||
{ name: 'Content Manager', href: '/settings/zim', icon: FolderIcon, current: false },
|
||||
{ name: 'Apps', href: '/settings/apps', icon: IconTerminal2, current: false },
|
||||
{ name: 'Benchmark', href: '/settings/benchmark', icon: IconChartBar, current: false },
|
||||
{ name: 'Content Explorer', href: '/settings/zim/remote-explorer', icon: IconZoom, current: false },
|
||||
{ name: 'Content Manager', href: '/settings/zim', icon: IconFolder, current: false },
|
||||
{ name: 'Maps Manager', href: '/settings/maps', icon: IconMapRoute, current: false },
|
||||
{
|
||||
name: 'Service Logs & Metrics',
|
||||
|
|
@ -35,7 +33,7 @@ const navigation = [
|
|||
icon: IconArrowBigUpLines,
|
||||
current: false,
|
||||
},
|
||||
{ name: 'System', href: '/settings/system', icon: Cog6ToothIcon, current: false },
|
||||
{ name: 'System', href: '/settings/system', icon: IconSettings, current: false },
|
||||
{ name: 'Legal Notices', href: '/settings/legal', icon: IconGavel, current: false },
|
||||
]
|
||||
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ export default function EasySetupWizardComplete() {
|
|||
/>
|
||||
<div className="flex justify-center mt-8 pt-4 border-t border-desert-stone-light">
|
||||
<div className="flex space-x-4">
|
||||
<StyledButton onClick={() => router.visit('/home')} icon="HomeIcon">
|
||||
<StyledButton onClick={() => router.visit('/home')} icon="IconHome">
|
||||
Go to Home
|
||||
</StyledButton>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1210,7 +1210,7 @@ export default function EasySetupWizard(props: { system: { services: ServiceSlim
|
|||
onClick={handleBack}
|
||||
disabled={isProcessing}
|
||||
variant="outline"
|
||||
icon="ChevronLeftIcon"
|
||||
icon="IconChevronLeft"
|
||||
>
|
||||
Back
|
||||
</StyledButton>
|
||||
|
|
@ -1244,7 +1244,7 @@ export default function EasySetupWizard(props: { system: { services: ServiceSlim
|
|||
onClick={handleNext}
|
||||
disabled={!canProceedToNextStep() || isProcessing}
|
||||
variant="primary"
|
||||
icon="ChevronRightIcon"
|
||||
icon="IconChevronRight"
|
||||
>
|
||||
Next
|
||||
</StyledButton>
|
||||
|
|
@ -1254,7 +1254,7 @@ export default function EasySetupWizard(props: { system: { services: ServiceSlim
|
|||
disabled={isProcessing || !isOnline || !anySelectionMade}
|
||||
loading={isProcessing}
|
||||
variant="success"
|
||||
icon="CheckIcon"
|
||||
icon="IconCheck"
|
||||
>
|
||||
Complete Setup
|
||||
</StyledButton>
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ export default function KnowledgeBase() {
|
|||
<StyledButton
|
||||
variant="primary"
|
||||
size="lg"
|
||||
icon="ArrowUpCircleIcon"
|
||||
icon="IconUpload"
|
||||
onClick={handleUpload}
|
||||
disabled={files.length === 0 || uploadMutation.isPending}
|
||||
loading={uploadMutation.isPending}
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ export default function Maps(props: {
|
|||
<p className="text-lg text-gray-600">Back to Home</p>
|
||||
</Link>
|
||||
<Link href="/settings/maps">
|
||||
<StyledButton variant="primary" icon="Cog6ToothIcon">
|
||||
<StyledButton variant="primary" icon="IconSettings">
|
||||
Manage Map Regions
|
||||
</StyledButton>
|
||||
</Link>
|
||||
|
|
@ -39,7 +39,7 @@ export default function Maps(props: {
|
|||
buttonProps={{
|
||||
variant: 'secondary',
|
||||
children: 'Go to Map Settings',
|
||||
icon: 'Cog6ToothIcon',
|
||||
icon: 'IconSettings',
|
||||
onClick: () => {
|
||||
window.location.href = '/settings/maps'
|
||||
},
|
||||
|
|
|
|||
|
|
@ -13,8 +13,7 @@ import LoadingSpinner from '~/components/LoadingSpinner'
|
|||
import useErrorNotification from '~/hooks/useErrorNotification'
|
||||
import useInternetStatus from '~/hooks/useInternetStatus'
|
||||
import useServiceInstallationActivity from '~/hooks/useServiceInstallationActivity'
|
||||
import { ArrowDownTrayIcon } from '@heroicons/react/24/outline'
|
||||
import { IconCheck } from '@tabler/icons-react'
|
||||
import { IconCheck, IconDownload } from '@tabler/icons-react'
|
||||
|
||||
export default function SettingsPage(props: { system: { services: ServiceSlim[] } }) {
|
||||
const { openModal, closeAllModals } = useModals()
|
||||
|
|
@ -48,7 +47,7 @@ export default function SettingsPage(props: { system: { services: ServiceSlim[]
|
|||
confirmText="Install"
|
||||
cancelText="Cancel"
|
||||
confirmVariant="primary"
|
||||
icon={<ArrowDownTrayIcon className="h-12 w-12 text-desert-green" />}
|
||||
icon={<IconDownload className="h-12 w-12 text-desert-green" />}
|
||||
>
|
||||
<p className="text-gray-700">
|
||||
Are you sure you want to install {service.friendly_name || service.service_name}? This
|
||||
|
|
@ -132,7 +131,7 @@ export default function SettingsPage(props: { system: { services: ServiceSlim[]
|
|||
const AppActions = ({ record }: { record: ServiceSlim }) => {
|
||||
const ForceReinstallButton = () => (
|
||||
<StyledButton
|
||||
icon="ExclamationTriangleIcon"
|
||||
icon="IconDownload"
|
||||
variant="action"
|
||||
onClick={() => {
|
||||
openModal(
|
||||
|
|
@ -165,7 +164,7 @@ export default function SettingsPage(props: { system: { services: ServiceSlim[]
|
|||
return (
|
||||
<div className="flex space-x-2">
|
||||
<StyledButton
|
||||
icon={'ArrowDownTrayIcon'}
|
||||
icon={'IconDownload'}
|
||||
variant="primary"
|
||||
onClick={() => handleInstallService(record)}
|
||||
disabled={isInstalling || !isOnline}
|
||||
|
|
@ -181,7 +180,7 @@ export default function SettingsPage(props: { system: { services: ServiceSlim[]
|
|||
return (
|
||||
<div className="flex space-x-2">
|
||||
<StyledButton
|
||||
icon={'ArrowTopRightOnSquareIcon'}
|
||||
icon={'IconExternalLink'}
|
||||
onClick={() => {
|
||||
window.open(getServiceLink(record.ui_location || 'unknown'), '_blank')
|
||||
}}
|
||||
|
|
@ -191,7 +190,7 @@ export default function SettingsPage(props: { system: { services: ServiceSlim[]
|
|||
{record.status && record.status !== 'unknown' && (
|
||||
<>
|
||||
<StyledButton
|
||||
icon={record.status === 'running' ? 'StopIcon' : 'PlayIcon'}
|
||||
icon={record.status === 'running' ? 'IconPlayerStop' : 'IconPlayerPlay'}
|
||||
variant={record.status === 'running' ? 'action' : undefined}
|
||||
onClick={() => {
|
||||
openModal(
|
||||
|
|
@ -219,7 +218,7 @@ export default function SettingsPage(props: { system: { services: ServiceSlim[]
|
|||
</StyledButton>
|
||||
{record.status === 'running' && (
|
||||
<StyledButton
|
||||
icon="ArrowPathIcon"
|
||||
icon="IconRefresh"
|
||||
variant="action"
|
||||
onClick={() => {
|
||||
openModal(
|
||||
|
|
|
|||
|
|
@ -8,15 +8,7 @@ import Alert from '~/components/Alert'
|
|||
import StyledButton from '~/components/StyledButton'
|
||||
import InfoTooltip from '~/components/InfoTooltip'
|
||||
import BuilderTagSelector from '~/components/BuilderTagSelector'
|
||||
import {
|
||||
ChartBarIcon,
|
||||
CpuChipIcon,
|
||||
CircleStackIcon,
|
||||
ServerIcon,
|
||||
ChevronDownIcon,
|
||||
ClockIcon,
|
||||
} from '@heroicons/react/24/outline'
|
||||
import { IconRobot } from '@tabler/icons-react'
|
||||
import { IconRobot, IconChartBar, IconCpu, IconDatabase, IconServer, IconChevronDown, IconClock } from '@tabler/icons-react'
|
||||
import { useTransmit } from 'react-adonis-transmit'
|
||||
import { BenchmarkProgress, BenchmarkStatus } from '../../../types/benchmark'
|
||||
import BenchmarkResult from '#models/benchmark_result'
|
||||
|
|
@ -378,7 +370,7 @@ export default function BenchmarkPage(props: {
|
|||
<StyledButton
|
||||
onClick={handleFullBenchmarkClick}
|
||||
disabled={runBenchmark.isPending}
|
||||
icon='PlayIcon'
|
||||
icon='IconPlayerPlay'
|
||||
>
|
||||
Run Full Benchmark
|
||||
</StyledButton>
|
||||
|
|
@ -386,7 +378,7 @@ export default function BenchmarkPage(props: {
|
|||
variant="secondary"
|
||||
onClick={() => runBenchmark.mutate('system')}
|
||||
disabled={runBenchmark.isPending}
|
||||
icon='CpuChipIcon'
|
||||
icon='IconCpu'
|
||||
>
|
||||
System Only
|
||||
</StyledButton>
|
||||
|
|
@ -394,7 +386,7 @@ export default function BenchmarkPage(props: {
|
|||
variant="secondary"
|
||||
onClick={() => runBenchmark.mutate('ai')}
|
||||
disabled={runBenchmark.isPending || !aiInstalled}
|
||||
icon='SparklesIcon'
|
||||
icon='IconWand'
|
||||
title={!aiInstalled ? 'AI Assistant must be installed to run AI benchmark' : undefined}
|
||||
>
|
||||
AI Only
|
||||
|
|
@ -431,7 +423,7 @@ export default function BenchmarkPage(props: {
|
|||
size="lg"
|
||||
variant="cpu"
|
||||
subtext="out of 100"
|
||||
icon={<ChartBarIcon className="w-8 h-8" />}
|
||||
icon={<IconChartBar className="w-8 h-8" />}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex-1 space-y-4">
|
||||
|
|
@ -482,7 +474,7 @@ export default function BenchmarkPage(props: {
|
|||
anonymous: shareAnonymously
|
||||
})}
|
||||
disabled={submitResult.isPending}
|
||||
icon='CloudArrowUpIcon'
|
||||
icon='IconCloudUpload'
|
||||
>
|
||||
{submitResult.isPending ? 'Submitting...' : 'Share with Community'}
|
||||
</StyledButton>
|
||||
|
|
@ -544,7 +536,7 @@ export default function BenchmarkPage(props: {
|
|||
label="CPU"
|
||||
size="md"
|
||||
variant="cpu"
|
||||
icon={<CpuChipIcon className="w-6 h-6" />}
|
||||
icon={<IconCpu className="w-6 h-6" />}
|
||||
/>
|
||||
</div>
|
||||
<div className="bg-desert-white rounded-lg p-6 border border-desert-stone-light shadow-sm">
|
||||
|
|
@ -553,7 +545,7 @@ export default function BenchmarkPage(props: {
|
|||
label="Memory"
|
||||
size="md"
|
||||
variant="memory"
|
||||
icon={<CircleStackIcon className="w-6 h-6" />}
|
||||
icon={<IconDatabase className="w-6 h-6" />}
|
||||
/>
|
||||
</div>
|
||||
<div className="bg-desert-white rounded-lg p-6 border border-desert-stone-light shadow-sm">
|
||||
|
|
@ -562,7 +554,7 @@ export default function BenchmarkPage(props: {
|
|||
label="Disk Read"
|
||||
size="md"
|
||||
variant="disk"
|
||||
icon={<ServerIcon className="w-6 h-6" />}
|
||||
icon={<IconServer className="w-6 h-6" />}
|
||||
/>
|
||||
</div>
|
||||
<div className="bg-desert-white rounded-lg p-6 border border-desert-stone-light shadow-sm">
|
||||
|
|
@ -571,7 +563,7 @@ export default function BenchmarkPage(props: {
|
|||
label="Disk Write"
|
||||
size="md"
|
||||
variant="disk"
|
||||
icon={<ServerIcon className="w-6 h-6" />}
|
||||
icon={<IconServer className="w-6 h-6" />}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -646,7 +638,7 @@ export default function BenchmarkPage(props: {
|
|||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
||||
<InfoCard
|
||||
title="Processor"
|
||||
icon={<CpuChipIcon className="w-6 h-6" />}
|
||||
icon={<IconCpu className="w-6 h-6" />}
|
||||
variant="elevated"
|
||||
data={[
|
||||
{ label: 'Model', value: latestResult.cpu_model },
|
||||
|
|
@ -656,7 +648,7 @@ export default function BenchmarkPage(props: {
|
|||
/>
|
||||
<InfoCard
|
||||
title="System"
|
||||
icon={<ServerIcon className="w-6 h-6" />}
|
||||
icon={<IconServer className="w-6 h-6" />}
|
||||
variant="elevated"
|
||||
data={[
|
||||
{ label: 'RAM', value: formatBytes(latestResult.ram_bytes) },
|
||||
|
|
@ -697,7 +689,7 @@ export default function BenchmarkPage(props: {
|
|||
<div className="font-bold text-desert-green">{latestResult.nomad_score.toFixed(1)}</div>
|
||||
</div>
|
||||
</div>
|
||||
<ChevronDownIcon
|
||||
<IconChevronDown
|
||||
className={`w-5 h-5 text-desert-stone-dark transition-transform ${showDetails ? 'rotate-180' : ''}`}
|
||||
/>
|
||||
</button>
|
||||
|
|
@ -799,12 +791,12 @@ export default function BenchmarkPage(props: {
|
|||
className="w-full p-4 flex items-center justify-between hover:bg-desert-stone-lighter/30 transition-colors"
|
||||
>
|
||||
<div className="flex items-center gap-2">
|
||||
<ClockIcon className="w-5 h-5 text-desert-stone-dark" />
|
||||
<IconClock className="w-5 h-5 text-desert-stone-dark" />
|
||||
<span className="font-medium text-desert-green">
|
||||
{benchmarkHistory.length} benchmark{benchmarkHistory.length !== 1 ? 's' : ''} recorded
|
||||
</span>
|
||||
</div>
|
||||
<ChevronDownIcon
|
||||
<IconChevronDown
|
||||
className={`w-5 h-5 text-desert-stone-dark transition-transform ${showHistory ? 'rotate-180' : ''}`}
|
||||
/>
|
||||
</button>
|
||||
|
|
|
|||
|
|
@ -198,7 +198,7 @@ export default function MapsManager(props: {
|
|||
variant="primary"
|
||||
onClick={openDownloadModal}
|
||||
loading={downloading}
|
||||
icon="CloudArrowDownIcon"
|
||||
icon="IconCloudDownload"
|
||||
>
|
||||
Download Custom Map File
|
||||
</StyledButton>
|
||||
|
|
@ -213,7 +213,7 @@ export default function MapsManager(props: {
|
|||
buttonProps={{
|
||||
variant: 'secondary',
|
||||
children: 'Download Base Assets',
|
||||
icon: 'ArrowDownTrayIcon',
|
||||
icon: 'IconDownload',
|
||||
loading: downloading,
|
||||
onClick: () => downloadBaseAssets(),
|
||||
}}
|
||||
|
|
@ -223,7 +223,7 @@ export default function MapsManager(props: {
|
|||
<StyledButton
|
||||
onClick={() => fetchLatestCollections.mutate()}
|
||||
disabled={fetchLatestCollections.isPending}
|
||||
icon="CloudArrowDownIcon"
|
||||
icon="IconCloudDownload"
|
||||
>
|
||||
Fetch Latest Collections
|
||||
</StyledButton>
|
||||
|
|
@ -254,7 +254,7 @@ export default function MapsManager(props: {
|
|||
<div className="flex space-x-2">
|
||||
<StyledButton
|
||||
variant="danger"
|
||||
icon={'TrashIcon'}
|
||||
icon={'IconTrash'}
|
||||
onClick={() => {
|
||||
confirmDeleteFile(record)
|
||||
}}
|
||||
|
|
|
|||
|
|
@ -5,15 +5,10 @@ import { formatBytes } from '~/lib/util'
|
|||
import CircularGauge from '~/components/systeminfo/CircularGauge'
|
||||
import HorizontalBarChart from '~/components/HorizontalBarChart'
|
||||
import InfoCard from '~/components/systeminfo/InfoCard'
|
||||
import {
|
||||
CpuChipIcon,
|
||||
CircleStackIcon,
|
||||
ServerIcon,
|
||||
ComputerDesktopIcon,
|
||||
} from '@heroicons/react/24/outline'
|
||||
import Alert from '~/components/Alert'
|
||||
import { useSystemInfo } from '~/hooks/useSystemInfo'
|
||||
import StatusCard from '~/components/systeminfo/StatusCard'
|
||||
import { IconCpu, IconDatabase, IconServer, IconDeviceDesktop } from '@tabler/icons-react'
|
||||
|
||||
export default function SettingsPage(props: {
|
||||
system: { info: SystemInformationResponse | undefined }
|
||||
|
|
@ -35,7 +30,13 @@ export default function SettingsPage(props: {
|
|||
// Build storage display items - fall back to fsSize when disk array is empty
|
||||
// (Same approach as Easy Setup wizard fix from PR #90)
|
||||
const validDisks = info?.disk?.filter((d) => d.totalSize > 0) || []
|
||||
let storageItems: { label: string; value: number; total: string; used: string; subtext: string }[] = []
|
||||
let storageItems: {
|
||||
label: string
|
||||
value: number
|
||||
total: string
|
||||
used: string
|
||||
subtext: string
|
||||
}[] = []
|
||||
if (validDisks.length > 0) {
|
||||
storageItems = validDisks.map((disk) => ({
|
||||
label: disk.name || 'Unknown',
|
||||
|
|
@ -100,7 +101,7 @@ export default function SettingsPage(props: {
|
|||
size="lg"
|
||||
variant="cpu"
|
||||
subtext={`${info?.cpu.cores || 0} cores`}
|
||||
icon={<CpuChipIcon className="w-8 h-8" />}
|
||||
icon={<IconCpu className="w-8 h-8" />}
|
||||
/>
|
||||
</div>
|
||||
<div className="bg-desert-white rounded-lg p-6 border border-desert-stone-light shadow-sm hover:shadow-lg transition-shadow">
|
||||
|
|
@ -110,7 +111,7 @@ export default function SettingsPage(props: {
|
|||
size="lg"
|
||||
variant="memory"
|
||||
subtext={`${formatBytes(info?.mem.used || 0)} / ${formatBytes(info?.mem.total || 0)}`}
|
||||
icon={<CircleStackIcon className="w-8 h-8" />}
|
||||
icon={<IconDatabase className="w-8 h-8" />}
|
||||
/>
|
||||
</div>
|
||||
<div className="bg-desert-white rounded-lg p-6 border border-desert-stone-light shadow-sm hover:shadow-lg transition-shadow">
|
||||
|
|
@ -120,7 +121,7 @@ export default function SettingsPage(props: {
|
|||
size="lg"
|
||||
variant="disk"
|
||||
subtext={`${formatBytes(info?.mem.swapused || 0)} / ${formatBytes(info?.mem.swaptotal || 0)}`}
|
||||
icon={<ServerIcon className="w-8 h-8" />}
|
||||
icon={<IconServer className="w-8 h-8" />}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -134,7 +135,7 @@ export default function SettingsPage(props: {
|
|||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
||||
<InfoCard
|
||||
title="Operating System"
|
||||
icon={<ComputerDesktopIcon className="w-6 h-6" />}
|
||||
icon={<IconDeviceDesktop className="w-6 h-6" />}
|
||||
variant="elevated"
|
||||
data={[
|
||||
{ label: 'Distribution', value: info?.os.distro },
|
||||
|
|
@ -146,7 +147,7 @@ export default function SettingsPage(props: {
|
|||
/>
|
||||
<InfoCard
|
||||
title="Processor"
|
||||
icon={<CpuChipIcon className="w-6 h-6" />}
|
||||
icon={<IconCpu className="w-6 h-6" />}
|
||||
variant="elevated"
|
||||
data={[
|
||||
{ label: 'Manufacturer', value: info?.cpu.manufacturer },
|
||||
|
|
|
|||
|
|
@ -261,7 +261,7 @@ export default function SystemUpdatePage(props: {
|
|||
<StyledButton
|
||||
variant="primary"
|
||||
size="lg"
|
||||
icon="ArrowDownTrayIcon"
|
||||
icon="IconDownload"
|
||||
onClick={handleStartUpdate}
|
||||
disabled={!props.system.updateAvailable}
|
||||
>
|
||||
|
|
@ -270,7 +270,7 @@ export default function SystemUpdatePage(props: {
|
|||
<StyledButton
|
||||
variant="ghost"
|
||||
size="lg"
|
||||
icon="ArrowPathIcon"
|
||||
icon="IconRefresh"
|
||||
onClick={() => window.location.reload()}
|
||||
>
|
||||
Check Again
|
||||
|
|
@ -323,7 +323,7 @@ export default function SystemUpdatePage(props: {
|
|||
<StyledButton
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
icon="DocumentTextIcon"
|
||||
icon="IconLogs"
|
||||
onClick={handleViewLogs}
|
||||
fullWidth
|
||||
>
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ export default function ZimPage() {
|
|||
<div className="flex space-x-2">
|
||||
<StyledButton
|
||||
variant="danger"
|
||||
icon={'TrashIcon'}
|
||||
icon={'IconTrash'}
|
||||
onClick={() => {
|
||||
confirmDeleteFile(record)
|
||||
}}
|
||||
|
|
|
|||
|
|
@ -303,7 +303,7 @@ export default function ZimRemoteExplorer() {
|
|||
<StyledButton
|
||||
onClick={() => fetchLatestCollections.mutate()}
|
||||
disabled={fetchLatestCollections.isPending}
|
||||
icon="CloudArrowDownIcon"
|
||||
icon="IconCloudDownload"
|
||||
>
|
||||
Fetch Latest Collections
|
||||
</StyledButton>
|
||||
|
|
@ -404,7 +404,7 @@ export default function ZimRemoteExplorer() {
|
|||
return (
|
||||
<div className="flex space-x-2">
|
||||
<StyledButton
|
||||
icon={'ArrowDownTrayIcon'}
|
||||
icon={'IconDownload'}
|
||||
onClick={() => {
|
||||
confirmDownload(record)
|
||||
}}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,6 @@
|
|||
import { useState } from 'react'
|
||||
import { NotificationContext, Notification } from '../context/NotificationContext'
|
||||
import {
|
||||
CheckCircleIcon,
|
||||
InformationCircleIcon,
|
||||
ExclamationTriangleIcon,
|
||||
} from '@heroicons/react/24/outline'
|
||||
import { IconExclamationCircle, IconCircleCheck, IconInfoCircle } from '@tabler/icons-react'
|
||||
|
||||
const NotificationsProvider = ({ children }: { children: React.ReactNode }) => {
|
||||
const [notifications, setNotifications] = useState<(Notification & { id: string })[]>([])
|
||||
|
|
@ -32,13 +28,13 @@ const NotificationsProvider = ({ children }: { children: React.ReactNode }) => {
|
|||
const Icon = ({ type }: { type: string }) => {
|
||||
switch (type) {
|
||||
case 'error':
|
||||
return <ExclamationTriangleIcon className="h-5 w-5 text-red-500" />
|
||||
return <IconExclamationCircle className="h-5 w-5 text-red-500" />
|
||||
case 'success':
|
||||
return <CheckCircleIcon className="h-5 w-5 text-green-500" />
|
||||
return <IconCircleCheck className="h-5 w-5 text-green-500" />
|
||||
case 'info':
|
||||
return <InformationCircleIcon className="h-5 w-5 text-blue-500" />
|
||||
return <IconInfoCircle className="h-5 w-5 text-blue-500" />
|
||||
default:
|
||||
return <InformationCircleIcon className="h-5 w-5 text-blue-500" />
|
||||
return <IconInfoCircle className="h-5 w-5 text-blue-500" />
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
10
admin/package-lock.json
generated
10
admin/package-lock.json
generated
|
|
@ -21,7 +21,6 @@
|
|||
"@adonisjs/transmit-client": "^1.0.0",
|
||||
"@adonisjs/vite": "^4.0.0",
|
||||
"@headlessui/react": "^2.2.4",
|
||||
"@heroicons/react": "^2.2.0",
|
||||
"@inertiajs/react": "^2.0.13",
|
||||
"@markdoc/markdoc": "^0.5.2",
|
||||
"@protomaps/basemaps": "^5.7.0",
|
||||
|
|
@ -2021,15 +2020,6 @@
|
|||
"react-dom": "^18 || ^19 || ^19.0.0-rc"
|
||||
}
|
||||
},
|
||||
"node_modules/@heroicons/react": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@heroicons/react/-/react-2.2.0.tgz",
|
||||
"integrity": "sha512-LMcepvRaS9LYHJGsF0zzmgKCUim/X3N/DQKc4jepAXJ7l8QxJ1PmxJzqplF2Z3FE4PqBAIGyJAQ/w4B5dsqbtQ==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"react": ">= 16 || ^19.0.0-rc"
|
||||
}
|
||||
},
|
||||
"node_modules/@humanfs/core": {
|
||||
"version": "0.19.1",
|
||||
"resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz",
|
||||
|
|
|
|||
|
|
@ -72,7 +72,6 @@
|
|||
"@adonisjs/transmit-client": "^1.0.0",
|
||||
"@adonisjs/vite": "^4.0.0",
|
||||
"@headlessui/react": "^2.2.4",
|
||||
"@heroicons/react": "^2.2.0",
|
||||
"@inertiajs/react": "^2.0.13",
|
||||
"@markdoc/markdoc": "^0.5.2",
|
||||
"@protomaps/basemaps": "^5.7.0",
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user