Apply uniform design system across all routes and components: - Consistent header pattern with gradient-text titles, dimmed subtitles - Loader type="dots" replacing text-based loading states - Icon + text empty/error states with Paper+glass containers - Full STATUS_COLOR/STATUS_LABEL maps for all BugStatus values - dayjs timestamps, Tooltip on action icons, size="sm" on badges/pagination - Modals with overlayProps blur and gradient save buttons - Replace left-border Papers with clean Stack headers - Translate all remaining Indonesian UI strings to English - New monitoring-themed SVG logo and redesigned splash screen
94 lines
2.9 KiB
TypeScript
94 lines
2.9 KiB
TypeScript
import { Avatar, Badge, Button, Card, Group, Stack, Text, useComputedColorScheme } from '@mantine/core'
|
|
import { Link } from '@tanstack/react-router'
|
|
import { TbAlertTriangle, TbChevronRight, TbDeviceMobile } from 'react-icons/tb'
|
|
|
|
interface AppCardProps {
|
|
id: string
|
|
name: string
|
|
status: 'active' | 'warning' | 'error'
|
|
users?: number
|
|
errors: number
|
|
version: string
|
|
maintenance?: boolean
|
|
}
|
|
|
|
export function AppCard({ id, name, status, errors, version, maintenance }: AppCardProps) {
|
|
const statusColor = maintenance ? 'gray' : status === 'active' ? 'teal' : status === 'warning' ? 'orange' : 'red'
|
|
const statusLabel = maintenance ? 'Maintenance' : status === 'active' ? 'Active' : status === 'warning' ? 'Warning' : 'Error'
|
|
const scheme = useComputedColorScheme('light', { getInitialValueInEffect: true })
|
|
|
|
return (
|
|
<Card
|
|
withBorder
|
|
padding="xl"
|
|
radius="2xl"
|
|
className="premium-card glass"
|
|
styles={(theme) => ({
|
|
root: {
|
|
backgroundColor: 'var(--mantine-color-body)',
|
|
borderColor: scheme === 'dark' ? 'rgba(255,255,255,0.08)' : 'rgba(0,0,0,0.05)',
|
|
transition: 'transform 0.2s ease, box-shadow 0.2s ease, background-color 0.2s ease, border-color 0.2s ease',
|
|
'&:hover': {
|
|
transform: 'translateY(-4px)',
|
|
boxShadow: theme.shadows.md,
|
|
borderColor: 'rgba(37, 99, 235, 0.3)',
|
|
},
|
|
},
|
|
})}
|
|
>
|
|
<Group justify="space-between" mb="md">
|
|
<Group gap="md">
|
|
<Avatar
|
|
variant="gradient"
|
|
gradient={{ from: '#2563EB', to: '#7C3AED', deg: 135 }}
|
|
radius="lg"
|
|
size="lg"
|
|
>
|
|
<TbDeviceMobile size={26} />
|
|
</Avatar>
|
|
<Stack gap={2}>
|
|
<Text fw={700} size="lg" style={{ letterSpacing: '-0.3px' }}>{name}</Text>
|
|
{/* <Text size="xs" c="dimmed" fw={600} tt="uppercase">v{version}</Text> */}
|
|
</Stack>
|
|
</Group>
|
|
<Badge color={statusColor} variant="dot" size="sm">
|
|
{statusLabel}
|
|
</Badge>
|
|
</Group>
|
|
|
|
<Group justify="space-between" align="center" mb="xs">
|
|
<Text size="xs" c="dimmed" fw={500}>Open Errors</Text>
|
|
<Badge
|
|
color={errors > 0 ? 'red' : 'teal'}
|
|
variant="light"
|
|
size="sm"
|
|
leftSection={errors > 0 ? <TbAlertTriangle size={10} /> : undefined}
|
|
>
|
|
{errors > 0 ? errors : 'None'}
|
|
</Badge>
|
|
</Group>
|
|
|
|
<Button
|
|
component={Link}
|
|
to={`/apps/${id}`}
|
|
variant="light"
|
|
color="brand-blue"
|
|
fullWidth
|
|
mt="md"
|
|
radius="md"
|
|
rightSection={<TbChevronRight size={16} />}
|
|
styles={{
|
|
root: {
|
|
height: '44px',
|
|
'&:hover': {
|
|
backgroundColor: 'rgba(37, 99, 235, 0.15)',
|
|
}
|
|
}
|
|
}}
|
|
>
|
|
Open Dashboard
|
|
</Button>
|
|
</Card>
|
|
)
|
|
}
|