fix: matine ui fixes for concistency (#5733)

This commit is contained in:
Thomas authored and GitHub committed 2026-05-28 10:59:03 +02:00
1 parent c252b4f9ac
commit 4454e3fb7a
90 files changed
+307 -243

No files matched your search

@@ -194,8 +194,6 @@ const Item = <TItem, TOptionValue extends UniqueIdentifier>({
return (
<Card
withBorder
shadow="xs"
padding="sm"
radius="md"
style={
@@ -50,7 +50,7 @@ export function InstanceCard({ instance, options, isTiny, widgetKey }: InstanceC
).length;
return (
<Card p={0} radius="sm" withBorder>
<Card p={0} radius="sm">
<Group
p="xs"
justify="space-between"
@@ -11,7 +11,7 @@ import { buildServerResourceCounts } from "./coolify-utils";
import { ServersSection } from "./servers-section";
import { ServicesSection } from "./services-section";
import type { CoolifyOptions, InstanceData } from "./types";
import { COOLIFY_ICON_URL } from "./types";
import { COOLIFY_BRAND_COLOR, COOLIFY_ICON_URL } from "./types";
interface SingleInstanceLayoutProps {
instance: InstanceData;
@@ -44,10 +44,10 @@ export function SingleInstanceLayout({ instance, options, isTiny, widgetKey }: S
return (
<ScrollArea h="100%">
<Stack gap={0}>
<Group p="xs" justify="center" gap="xs" style={{ borderBottom: "2px solid #8B5CF6" }}>
<Group p="xs" justify="center" gap="xs" style={{ borderBottom: `2px solid ${COOLIFY_BRAND_COLOR}` }}>
<Group gap={2}>
<Image src={COOLIFY_ICON_URL} alt="Coolify" w={isTiny ? 18 : 24} h={isTiny ? 18 : 24} />
<Text fz={isTiny ? "xs" : "sm"} fw={700} style={{ color: "#8B5CF6" }}>
<Text fz={isTiny ? "xs" : "sm"} fw={700} style={{ color: COOLIFY_BRAND_COLOR }}>
oolify
</Text>
</Group>
@@ -75,7 +75,11 @@ export function SingleInstanceLayout({ instance, options, isTiny, widgetKey }: S
)}
</Accordion>
<Group justify="space-between" p={4} style={{ borderTop: "1px solid var(--mantine-color-dark-4)" }}>
<Group
justify="space-between"
p={4}
style={{ borderTop: "1px solid light-dark(var(--mantine-color-gray-3), var(--mantine-color-dark-4))" }}
>
<Group gap={2}>
<Image src={COOLIFY_ICON_URL} alt="Coolify" w={16} h={16} />
<Text size="xs" c="dimmed">
+1
View File
@@ -3,6 +3,7 @@ import type { CoolifyInstanceInfo } from "@homarr/integrations/types";
import type { WidgetComponentProps } from "../definition";
export const COOLIFY_ICON_URL = "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/coolify.svg";
export const COOLIFY_BRAND_COLOR = "#8B5CF6";
export interface InstanceData {
integrationId: string;
+1 -1
View File
@@ -62,7 +62,7 @@ const createColumns = (
Cell({ renderedCellValue, row }) {
return (
<Group gap="xs" wrap="nowrap">
<Avatar variant="outline" radius="md" size={20} src={row.original.iconUrl} />
<Avatar variant="outline" size={20} src={row.original.iconUrl} />
<Text p="0.5" size="sm" style={{ overflow: "hidden", textOverflow: "ellipsis" }}>
{renderedCellValue}
</Text>
+1 -1
View File
@@ -864,7 +864,7 @@ const ClientsControl = ({ clients, filters, setFilters, availableStatuses }: Cli
<Stack key={client.integration.id} gap="10px">
<Divider />
<Group wrap="nowrap" w="100%">
<Paper withBorder radius={999}>
<Paper radius={999}>
<Group gap={5} pl={10} pr={15} fz={16} w={275} justify="space-between" wrap="nowrap">
<Avatar radius={0} src={getIconUrl(client.integration.kind)} />
{client.status ? (
@@ -1,4 +1,4 @@
import { Group, Indicator, Popover, Table, TableTbody, TableThead, TableTr, Text } from "@mantine/core";
import { Group, Indicator, Popover, Table, TableTbody, TableTh, TableThead, TableTr, Text } from "@mantine/core";
import type { Resource } from "@homarr/integrations/types";
import { useI18n } from "@homarr/translation/client";
@@ -17,23 +17,23 @@ export const ResourceTable = ({ type, data, isTiny }: ResourceTableProps) => {
<Table highlightOnHover>
<TableThead>
<TableTr fz={isTiny ? "8px" : "xs"}>
<Table.Th ta="start" p={0}>
<TableTh ta="start" p={0}>
{t("widget.healthMonitoring.cluster.table.header.name")}
</Table.Th>
</TableTh>
{type !== "storage" ? (
<Table.Th ta="start" p={0}>
<TableTh ta="start" p={0}>
{t("widget.healthMonitoring.cluster.table.header.cpu")}
</Table.Th>
</TableTh>
) : null}
{type !== "storage" ? (
<Table.Th ta="start" p={0}>
<TableTh ta="start" p={0}>
{t("widget.healthMonitoring.cluster.table.header.memory")}
</Table.Th>
</TableTh>
) : null}
{type === "storage" ? (
<Table.Th ta="start" p={0}>
<TableTh ta="start" p={0}>
{t("widget.healthMonitoring.cluster.table.header.node")}
</Table.Th>
</TableTh>
) : null}
</TableTr>
</TableThead>
@@ -95,7 +95,6 @@ const MediaRequestCard = ({ request, isTiny, options }: MediaRequestCardProps) =
className={`mediaRequests-list-item-wrapper mediaRequests-list-item-${request.type} mediaRequests-list-item-${request.status}`}
radius={board.itemRadius}
p="xs"
withBorder
>
<Image
className="mediaRequests-list-item-background"
@@ -214,7 +213,6 @@ const DecisionButtons = ({ requestId, integrationId }: DecisionButtonsProps) =>
variant="light"
color="green"
size="xs"
radius="md"
onClick={() => {
handleDecision("approve");
}}
@@ -228,7 +226,6 @@ const DecisionButtons = ({ requestId, integrationId }: DecisionButtonsProps) =>
variant="light"
color="red"
size="xs"
radius="md"
onClick={() => {
handleDecision("decline");
}}
@@ -23,6 +23,9 @@ import type { WidgetComponentProps } from "../../definition";
import { NoIntegrationDataError } from "../../errors/no-data-integration";
import classes from "./component.module.css";
const OVERSEERR_COLOR = "#ECB000";
const JELLYSEERR_COLOR = "#6677CC";
export default function MediaServerWidget({
integrationIds,
isEditMode,
@@ -151,7 +154,7 @@ export default function MediaServerWidget({
className="mediaRequests-stats-users-user-avatar"
size={20}
src={user.avatar}
bd={`2px solid ${user.integration.kind === "overseerr" ? "#ECB000" : "#6677CC"}`}
bd={`2px solid ${user.integration.kind === "overseerr" ? OVERSEERR_COLOR : JELLYSEERR_COLOR}`}
/>
</Tooltip>
<Text className="mediaRequests-stats-users-user-userName" size="sm">
@@ -27,7 +27,11 @@ export function HealthCheckStatus(props: HealthCheckStatusProps) {
<IconHeartbeat size={16} />
</Indicator>
</HoverCard.Target>
<HoverCard.Dropdown bg={colorScheme === "light" ? "gray.2" : "dark.8"}>
<HoverCard.Dropdown
style={{
backgroundColor: "light-dark(var(--mantine-color-gray-2), var(--mantine-color-dark-8))",
}}
>
<Stack gap="sm" align="center">
<Group gap="xs">
<IconHeartbeat size={18} />
@@ -1,4 +1,17 @@
import { Center, Group, ScrollArea, Table, TableTd, TableTh, TableTr, Text, Title, Tooltip } from "@mantine/core";
import {
Center,
Group,
ScrollArea,
Table,
TableTbody,
TableTd,
TableTh,
TableThead,
TableTr,
Text,
Title,
Tooltip,
} from "@mantine/core";
import { IconHeartbeat, IconTransform } from "@tabler/icons-react";
import { humanFileSize } from "@homarr/common";
@@ -25,7 +38,7 @@ export function QueuePanel(props: QueuePanelProps) {
return (
<ScrollArea style={{ flex: "1" }}>
<Table style={{ tableLayout: "fixed" }}>
<Table.Thead>
<TableThead>
<TableTr>
<TableTh ta="start" py={4}>
<Text size="xs" fw="bold">
@@ -38,8 +51,8 @@ export function QueuePanel(props: QueuePanelProps) {
</Text>
</TableTh>
</TableTr>
</Table.Thead>
<Table.Tbody>
</TableThead>
<TableTbody>
{queue.array.map((item) => (
<TableTr key={item.id}>
<TableTd py={2}>
@@ -63,7 +76,7 @@ export function QueuePanel(props: QueuePanelProps) {
</TableTd>
</TableTr>
))}
</Table.Tbody>
</TableTbody>
</Table>
</ScrollArea>
);
@@ -91,7 +91,7 @@ function StatisticItem(props: StatisticItemProps) {
const board = useRequiredBoard();
return (
<Tooltip label={props.label}>
<Card p={0} withBorder radius={board.itemRadius} miw={48} flex={1}>
<Card p={0} radius={board.itemRadius} miw={48} flex={1}>
<Group justify="center" align="center" gap="xs" w="100%" wrap="nowrap">
<props.icon size={16} style={{ minWidth: 16 }} />
<Text size="md">{props.value}</Text>
@@ -4,8 +4,10 @@ import {
Progress,
ScrollArea,
Table,
TableTbody,
TableTd,
TableTh,
TableThead,
TableTr,
Text,
Title,
@@ -35,7 +37,7 @@ export function WorkersPanel(props: WorkersPanelProps) {
return (
<ScrollArea style={{ flex: "1" }}>
<Table style={{ tableLayout: "fixed" }}>
<Table.Thead>
<TableThead>
<TableTr>
<TableTh ta="start" py={4}>
<Text size="xs" fw="bold">
@@ -53,8 +55,8 @@ export function WorkersPanel(props: WorkersPanelProps) {
</Text>
</TableTh>
</TableTr>
</Table.Thead>
<Table.Tbody>
</TableThead>
<TableTbody>
{props.workers.map((worker) => {
const fileName = worker.filePath.split("\\").pop()?.split("/").pop() ?? worker.filePath;
return (
@@ -101,7 +103,7 @@ export function WorkersPanel(props: WorkersPanelProps) {
</TableTr>
);
})}
</Table.Tbody>
</TableTbody>
</Table>
</ScrollArea>
);
@@ -421,7 +421,6 @@ export function Notebook({ options, setOptions, isEditMode, boardId, itemId }: W
color={primaryColor}
variant="light"
size={30}
radius={"md"}
onClick={handleEditToggle}
>
{isEditing ? <IconDeviceFloppy {...iconProps} /> : <IconEdit {...iconProps} />}
@@ -438,7 +437,6 @@ export function Notebook({ options, setOptions, isEditMode, boardId, itemId }: W
color={primaryColor}
variant="light"
size={30}
radius={"md"}
onClick={handleEditCancel}
>
<IconX {...iconProps} />
@@ -67,7 +67,7 @@ export default function NotificationsWidget({ options, integrationIds }: WidgetC
<Stack w={"100%"} gap="sm">
{sortedNotifications.length > 0 ? (
sortedNotifications.map((notification) => (
<Card key={notification.id} withBorder radius={board.itemRadius} w="100%" p="sm">
<Card key={notification.id} radius={board.itemRadius} w="100%" p="sm">
<Flex gap="sm" direction="column" w="100%">
{notification.title && (
<Text fz="sm" lh="sm" lineClamp={2}>
@@ -1,10 +1,8 @@
.releasesRepository {
border-left: 2px solid transparent;
&:has(.releasesRepositoryHeader:hover),
&:has(.releasesRepositoryHeader.active),
&:has(.releasesRepositoryDetails:hover) {
border-left-color: var(--mantine-color-secondaryColor-text);
background-color: var(--mantine-color-secondaryColor-light);
}
}
@@ -57,7 +57,6 @@ export default function RssFeed({ options, width }: WidgetComponentProps<"rssFee
{feedEntries.map((feedEntry) => (
<Card
key={feedEntry.id}
withBorder
component={"a"}
href={feedEntry.link}
radius={board.itemRadius}
@@ -78,7 +78,7 @@ export default function SmartHomeTriggerAutomationWidget({
</Center>
</Overlay>
)}
<LoadingOverlay visible={isPending} zIndex={1000} overlayProps={{ radius: "sm", blur: 2 }} />
<LoadingOverlay visible={isPending} />
<Center w="100%" h="100%">
<Stack align="center" gap="md">
<IconAutomation size={isTiny ? 16 : undefined} />
@@ -38,7 +38,7 @@ export const CombinedNetworkTrafficChart = ({
tooltipProps={{
content: ({ payload }) => {
return (
<Paper px={3} py={2} withBorder shadow="md" radius="md">
<Paper px={3} py={2} shadow="md">
<Stack gap={0}>
{payload.map((payloadData) => (
<Group key={payloadData.key} gap={4}>
@@ -36,7 +36,7 @@ export const SystemResourceCPUChart = ({
content: ({ payload }) => {
const value = payload[0] ? Number(payload[0].value) : 0;
return (
<Paper px={3} py={2} withBorder shadow="md" radius="md">
<Paper px={3} py={2} shadow="md">
<Text c="dimmed" size="xs">
{value.toFixed(0)}%
</Text>
@@ -36,7 +36,7 @@ export const SystemResourceGPUChart = ({
content: ({ payload }) => {
const value = payload[0] ? Number(payload[0].value) : 0;
return (
<Paper px={3} py={2} withBorder shadow="md" radius="md">
<Paper px={3} py={2} shadow="md">
<Text c="dimmed" size="xs">
{value.toFixed(0)}%
</Text>
@@ -42,7 +42,7 @@ export const SystemResourceMemoryChart = ({
content: ({ payload }) => {
const value = payload[0] ? Number(payload[0].value) : 0;
return (
<Paper px={3} py={2} withBorder shadow="md" radius="md">
<Paper px={3} py={2} shadow="md">
<Text c="dimmed" size="xs">
{humanFileSize(Math.round(value))} / {humanFileSize(totalCapacityInBytes)} (
{Math.round((value / totalCapacityInBytes) * 100)}%)
@@ -39,7 +39,7 @@ export const NetworkTrafficChart = ({
content: ({ payload }) => {
const value = payload[0] ? Number(payload[0].value) : 0;
return (
<Paper px={3} py={2} withBorder shadow="md" radius="md">
<Paper px={3} py={2} shadow="md">
<Text c="dimmed" size="xs">
{humanFileSize(Math.round(value))}/s
</Text>
@@ -24,7 +24,7 @@ export function RecentActivityList({ sessions }: { sessions: TracearrHistorySess
: session.mediaTitle;
return (
<Paper key={session.id} p="sm" radius="lg" withBorder>
<Paper key={session.id} p="sm" radius="lg">
<Group justify="space-between" wrap="nowrap">
<Group gap="xs" wrap="nowrap" style={{ overflow: "hidden" }}>
<Avatar src={session.user.avatarUrl} alt={session.user.username} radius="xl" size="sm" />
@@ -32,7 +32,7 @@ export function StatsBar({
function StatCard({ icon, label, value }: { icon: React.ReactNode; label: string; value: string | number }) {
return (
<Paper p="xs" radius="lg" withBorder>
<Paper p="xs" radius="lg">
<Group gap={4} wrap="nowrap">
{icon}
<Stack gap={0} style={{ overflow: "hidden" }}>
@@ -45,7 +45,7 @@ function StreamCard({ stream, compact }: { stream: TracearrStream; compact: bool
: null;
return (
<Paper p="xs" radius="lg" withBorder style={{ position: "relative", overflow: "hidden" }}>
<Paper p="xs" radius="lg" style={{ position: "relative", overflow: "hidden" }}>
{stream.posterUrl && (
<Box
style={{
@@ -100,7 +100,7 @@ function StreamCard({ stream, compact }: { stream: TracearrStream; compact: bool
</Group>
</Group>
<Tooltip label={mediaLabel} openDelay={300}>
<Tooltip label={mediaLabel}>
<Text size="xs" c="dimmed" lineClamp={1}>
{mediaLabel}
</Text>
@@ -19,7 +19,7 @@ export function ViolationsList({ violations }: { violations: TracearrViolation[]
) : (
<Stack gap="xs">
{violations.map((violation) => (
<Paper key={violation.id} p="xs" radius="lg" withBorder>
<Paper key={violation.id} p="xs" radius="lg">
<Group justify="space-between" wrap="nowrap">
<Group gap="xs" wrap="nowrap" style={{ overflow: "hidden" }}>
<IconAlertTriangle