fix: balance app and health widget scaling
This commit is contained in:
1 parent
3aac106156
commit
3f2f26bea7
10 files changed
+63
-12
No files matched your search
@@ -1,8 +1,16 @@
|
||||
.appText {
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
flex-shrink: 1;
|
||||
overflow-wrap: anywhere;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.appIcon {
|
||||
max-height: 100%;
|
||||
max-width: 100%;
|
||||
overflow: auto;
|
||||
flex: 1 !important;
|
||||
flex: 1;
|
||||
object-fit: contain;
|
||||
scale: 0.8;
|
||||
transition: scale 0.2s ease-in-out;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import type { PropsWithChildren } from "react";
|
||||
import { Fragment, Suspense } from "react";
|
||||
import { Box, Flex, rem, Stack, Text, Tooltip, UnstyledButton } from "@mantine/core";
|
||||
import { Box, Flex, Stack, Text, Tooltip, UnstyledButton } from "@mantine/core";
|
||||
import { IconMinus } from "@tabler/icons-react";
|
||||
import combineClasses from "clsx";
|
||||
|
||||
@@ -21,7 +21,13 @@ import classes from "./app.module.css";
|
||||
import { PingDot } from "./ping/ping-dot";
|
||||
import { PingIndicator } from "./ping/ping-indicator";
|
||||
|
||||
export default function AppWidget({ options, isEditMode, height, width }: WidgetComponentProps<"app">) {
|
||||
export default function AppWidget({
|
||||
options,
|
||||
isEditMode,
|
||||
height,
|
||||
width,
|
||||
displayScale = 1,
|
||||
}: WidgetComponentProps<"app">) {
|
||||
const tCommon = useI18n("common");
|
||||
const settings = useSettings();
|
||||
const board = useRequiredBoard();
|
||||
@@ -33,7 +39,13 @@ export default function AppWidget({ options, isEditMode, height, width }: Widget
|
||||
if (isInitialWidgetQueryPending(appQuery)) return <WidgetQueryLoadingState />;
|
||||
if (!app) return <WidgetEmptyState />;
|
||||
|
||||
const isTiny = height < 100 || width < 100;
|
||||
// Readable board tokens stay fixed on screen, but must yield space to the icon
|
||||
// when the tile itself becomes small. Below 100px, scale the whole composition.
|
||||
let scale = 1;
|
||||
if (Number.isFinite(displayScale) && displayScale > 0) scale = displayScale;
|
||||
const contentScale = Math.min(1 / Math.min(scale, 1), Math.min(width, height) / 100);
|
||||
const textSize = `${14 * contentScale}px`;
|
||||
const spacing = 12 * contentScale;
|
||||
const isColumnLayout = options.layout.startsWith("column");
|
||||
|
||||
return (
|
||||
@@ -44,22 +56,26 @@ export default function AppWidget({ options, isEditMode, height, width }: Widget
|
||||
enabled={options.descriptionDisplayMode === "tooltip" && Boolean(app.description) && !isEditMode}
|
||||
>
|
||||
<Flex
|
||||
p={isTiny ? 4 : "sm"}
|
||||
className={combineClasses("app-flex-wrapper", app.name, app.id, href && classes.appWithUrl)}
|
||||
h="100%"
|
||||
w="100%"
|
||||
direction={options.layout}
|
||||
justify="center"
|
||||
align="center"
|
||||
gap={isColumnLayout ? 0 : "sm"}
|
||||
style={{ padding: spacing, gap: isColumnLayout ? 0 : spacing / 2 }}
|
||||
onContextMenu={isEditMode ? (e) => e.preventDefault() : undefined}
|
||||
>
|
||||
<Stack gap={0}>
|
||||
<Stack
|
||||
gap={0}
|
||||
className={classes.appText}
|
||||
style={{ maxWidth: isColumnLayout ? "100%" : "50%", maxHeight: isColumnLayout ? "50%" : "100%" }}
|
||||
>
|
||||
{options.showTitle && (
|
||||
<Text
|
||||
className="app-title"
|
||||
fw={700}
|
||||
size={isTiny ? rem(8) : "sm"}
|
||||
lineClamp={2}
|
||||
style={{ fontSize: textSize }}
|
||||
ta={isColumnLayout ? "center" : undefined}
|
||||
>
|
||||
{app.name}
|
||||
@@ -68,10 +84,10 @@ export default function AppWidget({ options, isEditMode, height, width }: Widget
|
||||
{options.descriptionDisplayMode === "normal" && (
|
||||
<Text
|
||||
className="app-description"
|
||||
size={isTiny ? rem(8) : "sm"}
|
||||
style={{ fontSize: textSize }}
|
||||
ta={isColumnLayout ? "center" : undefined}
|
||||
c="dimmed"
|
||||
lineClamp={4}
|
||||
lineClamp={2}
|
||||
>
|
||||
{app.description?.split("\n").map((line, index) => (
|
||||
<Fragment key={index}>
|
||||
@@ -88,9 +104,11 @@ export default function AppWidget({ options, isEditMode, height, width }: Widget
|
||||
alt={app.name}
|
||||
className={combineClasses(classes.appIcon, "app-icon")}
|
||||
style={{
|
||||
flex: isColumnLayout ? undefined : "0 0 50%",
|
||||
height: "100%",
|
||||
width: "100%",
|
||||
minWidth: "20%",
|
||||
minWidth: 0,
|
||||
minHeight: 0,
|
||||
maxWidth: isColumnLayout ? undefined : "50%",
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -5,6 +5,7 @@ import { IconCpu } from "@tabler/icons-react";
|
||||
import { zoomCompensatedSize } from "@homarr/ui";
|
||||
|
||||
import { progressColor } from "../system-health";
|
||||
import classes from "../system-health.module.css";
|
||||
|
||||
export const CpuRing = ({
|
||||
cpuUtilization,
|
||||
@@ -17,6 +18,7 @@ export const CpuRing = ({
|
||||
}) => {
|
||||
return (
|
||||
<GaugeChart
|
||||
classNames={{ label: classes.gaugeLabel }}
|
||||
className="health-monitoring-cpu"
|
||||
aria-label={ariaLabel}
|
||||
roundCaps
|
||||
|
||||
@@ -5,6 +5,7 @@ import { IconCpu } from "@tabler/icons-react";
|
||||
import { zoomCompensatedSize } from "@homarr/ui";
|
||||
|
||||
import { progressColor } from "../system-health";
|
||||
import classes from "../system-health.module.css";
|
||||
|
||||
const CPU_TEMPERATURE_MIN_CELSIUS = 0;
|
||||
const CPU_TEMPERATURE_MAX_CELSIUS = 100;
|
||||
@@ -31,6 +32,7 @@ export const CpuTempRing = ({
|
||||
|
||||
return (
|
||||
<GaugeChart
|
||||
classNames={{ label: classes.gaugeLabel }}
|
||||
className="health-monitoring-cpu-temperature"
|
||||
aria-label={ariaLabel}
|
||||
roundCaps
|
||||
|
||||
@@ -5,6 +5,7 @@ import { IconDeviceDesktop } from "@tabler/icons-react";
|
||||
import { zoomCompensatedSize } from "@homarr/ui";
|
||||
|
||||
import { progressColor } from "../system-health";
|
||||
import classes from "../system-health.module.css";
|
||||
|
||||
interface GpuRingProps {
|
||||
gpu: {
|
||||
@@ -43,6 +44,7 @@ export const GpuRing = ({ gpu, isTiny, fahrenheit, ariaLabel }: GpuRingProps) =>
|
||||
multiline
|
||||
>
|
||||
<GaugeChart
|
||||
classNames={{ label: classes.gaugeLabel }}
|
||||
className={`health-monitoring-gpu health-monitoring-gpu-${gpu.gpuId}`}
|
||||
aria-label={ariaLabel}
|
||||
roundCaps
|
||||
|
||||
@@ -6,6 +6,7 @@ import { useByteFormatter } from "@homarr/settings";
|
||||
import { zoomCompensatedSize } from "@homarr/ui";
|
||||
|
||||
import { progressColor } from "../system-health";
|
||||
import classes from "../system-health.module.css";
|
||||
|
||||
export const MemoryRing = ({
|
||||
available,
|
||||
@@ -24,6 +25,7 @@ export const MemoryRing = ({
|
||||
return (
|
||||
<Tooltip label={`${memoryUsage.memUsed.percent}%`}>
|
||||
<GaugeChart
|
||||
classNames={{ label: classes.gaugeLabel }}
|
||||
className="health-monitoring-memory"
|
||||
aria-label={ariaLabel}
|
||||
roundCaps
|
||||
|
||||
@@ -33,3 +33,12 @@
|
||||
transition: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* Gauge labels live inside an SVG foreignObject. The SVG already scales its
|
||||
* coordinate system to the compensated gauge size; compensating again makes
|
||||
* the label grow as the board shrinks. */
|
||||
.gaugeLabel {
|
||||
--mantine-scale: 1;
|
||||
--board-canvas-ui-scale: 1;
|
||||
--mantine-font-size-xs: 0.75rem;
|
||||
}
|
||||
@@ -61,6 +61,8 @@ export const SystemHealthMonitoring = ({
|
||||
options,
|
||||
integrationIds,
|
||||
width,
|
||||
height,
|
||||
displayScale = 1,
|
||||
displayMode,
|
||||
withScrollArea = true,
|
||||
}: WidgetComponentProps<"healthMonitoring"> & { withScrollArea?: boolean }) => {
|
||||
@@ -75,7 +77,9 @@ export const SystemHealthMonitoring = ({
|
||||
const { formatBytes, formatBytesPair } = useByteFormatter();
|
||||
|
||||
const isAdvanced = displayMode === "advanced";
|
||||
const isTiny = !isAdvanced && width < 256;
|
||||
let scale = 1;
|
||||
if (!isAdvanced && Number.isFinite(displayScale) && displayScale > 0) scale = displayScale;
|
||||
const isTiny = !isAdvanced && (width * scale < 256 || height * scale < 160);
|
||||
const showCpu = isAdvanced || options.cpu;
|
||||
const showMemory = isAdvanced || options.memory;
|
||||
const showGpu = isAdvanced || options.gpu;
|
||||
|
||||
Reference in new issue
Block a user