feat: remove cqmin system (#2407)
* feat: remove cqmin system * fix: improve weather widget --------- Co-authored-by: Meier Lukas <meierschlumpf@gmail.com>
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
[data-mantine-color-scheme="light"] .card {
|
||||
background-color: var(--mantine-color-gray-1);
|
||||
}
|
||||
|
||||
[data-mantine-color-scheme="dark"] .card {
|
||||
background-color: var(--mantine-color-dark-7);
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import { useState } from "react";
|
||||
import { ActionIcon, Badge, Button, Card, Flex, ScrollArea, Stack, Text, Tooltip, UnstyledButton } from "@mantine/core";
|
||||
import { useDisclosure } from "@mantine/hooks";
|
||||
import { IconCircleFilled, IconClockPause, IconPlayerPlay, IconPlayerStop } from "@tabler/icons-react";
|
||||
import combineClasses from "clsx";
|
||||
|
||||
import type { RouterOutputs } from "@homarr/api";
|
||||
import { clientApi } from "@homarr/api/client";
|
||||
@@ -19,6 +20,7 @@ import { MaskedOrNormalImage } from "@homarr/ui";
|
||||
|
||||
import type { widgetKind } from ".";
|
||||
import type { WidgetComponentProps } from "../../definition";
|
||||
import classes from "./component.module.css";
|
||||
import TimerModal from "./TimerModal";
|
||||
|
||||
const dnsLightStatus = (enabled: boolean | undefined) =>
|
||||
@@ -179,12 +181,12 @@ export default function DnsHoleControlsWidget({
|
||||
className="dns-hole-controls-stack"
|
||||
h="100%"
|
||||
direction="column"
|
||||
p="2.5cqmin"
|
||||
gap="2.5cqmin"
|
||||
p="sm"
|
||||
gap="sm"
|
||||
style={{ pointerEvents: isEditMode ? "none" : undefined }}
|
||||
>
|
||||
{controlAllButtonsVisible && (
|
||||
<Flex className="dns-hole-controls-buttons" gap="2.5cqmin">
|
||||
<Flex className="dns-hole-controls-buttons" gap="sm">
|
||||
<Tooltip label={t("widget.dnsHoleControls.controls.enableAll")}>
|
||||
<Button
|
||||
className="dns-hole-controls-enable-all-button"
|
||||
@@ -193,15 +195,12 @@ export default function DnsHoleControlsWidget({
|
||||
variant="light"
|
||||
color="green"
|
||||
h="fit-content"
|
||||
p="1.25cqmin"
|
||||
p="xs"
|
||||
bd={0}
|
||||
radius="2.5cqmin"
|
||||
radius={board.itemRadius}
|
||||
flex={1}
|
||||
>
|
||||
<IconPlayerPlay
|
||||
className="dns-hole-controls-enable-all-icon"
|
||||
style={{ height: "7.5cqmin", width: "7.5cqmin" }}
|
||||
/>
|
||||
<IconPlayerPlay className="dns-hole-controls-enable-all-icon" size={24} />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
|
||||
@@ -216,15 +215,12 @@ export default function DnsHoleControlsWidget({
|
||||
variant="light"
|
||||
color="yellow"
|
||||
h="fit-content"
|
||||
p="1.25cqmin"
|
||||
p="xs"
|
||||
bd={0}
|
||||
radius="2.5cqmin"
|
||||
radius={board.itemRadius}
|
||||
flex={1}
|
||||
>
|
||||
<IconClockPause
|
||||
className="dns-hole-controls-timer-all-icon"
|
||||
style={{ height: "7.5cqmin", width: "7.5cqmin" }}
|
||||
/>
|
||||
<IconClockPause className="dns-hole-controls-timer-all-icon" size={24} />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
|
||||
@@ -236,15 +232,12 @@ export default function DnsHoleControlsWidget({
|
||||
variant="light"
|
||||
color="red"
|
||||
h="fit-content"
|
||||
p="1.25cqmin"
|
||||
p="xs"
|
||||
bd={0}
|
||||
radius="2.5cqmin"
|
||||
radius={board.itemRadius}
|
||||
flex={1}
|
||||
>
|
||||
<IconPlayerStop
|
||||
className="dns-hole-controls-disable-all-icon"
|
||||
style={{ height: "7.5cqmin", width: "7.5cqmin" }}
|
||||
/>
|
||||
<IconPlayerStop className="dns-hole-controls-disable-all-icon" size={24} />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</Flex>
|
||||
@@ -253,7 +246,7 @@ export default function DnsHoleControlsWidget({
|
||||
<ScrollArea className="dns-hole-controls-integration-list-scroll-area flexed-scroll-area">
|
||||
<Stack
|
||||
className="dns-hole-controls-integration-list"
|
||||
gap="2.5cqmin"
|
||||
gap="sm"
|
||||
flex={1}
|
||||
justify={controlAllButtonsVisible ? "flex-end" : "space-evenly"}
|
||||
>
|
||||
@@ -306,34 +299,40 @@ const ControlsCard: React.FC<ControlsCardProps> = ({
|
||||
const isInteractPermitted = integrationsWithInteractions.includes(data.integration.id);
|
||||
// Use all factors to infer the state of the action buttons
|
||||
const controlEnabled = isInteractPermitted && isEnabled !== undefined && isConnected;
|
||||
const board = useRequiredBoard();
|
||||
|
||||
const iconUrl = integrationDefs[data.integration.kind].iconUrl;
|
||||
|
||||
return (
|
||||
<Card
|
||||
className={`dns-hole-controls-integration-item-outer-shell dns-hole-controls-integration-item-${data.integration.id} dns-hole-controls-integration-item-${data.integration.name}`}
|
||||
className={combineClasses(
|
||||
"dns-hole-controls-integration-item-outer-shell",
|
||||
`dns-hole-controls-integration-item-${data.integration.id}`,
|
||||
`dns-hole-controls-integration-item-${data.integration.name}`,
|
||||
classes.card,
|
||||
)}
|
||||
key={data.integration.id}
|
||||
withBorder
|
||||
p="2.5cqmin"
|
||||
radius="2.5cqmin"
|
||||
p="sm"
|
||||
py={8}
|
||||
radius={board.itemRadius}
|
||||
>
|
||||
<Flex className="dns-hole-controls-item-container" gap="4cqmin" align="center" direction="row">
|
||||
<Flex className="dns-hole-controls-item-container" gap="md" align="center" direction="row">
|
||||
<MaskedOrNormalImage
|
||||
imageUrl={iconUrl}
|
||||
hasColor={hasIconColor}
|
||||
alt={data.integration.name}
|
||||
className="dns-hole-controls-item-icon"
|
||||
style={{
|
||||
height: "20cqmin",
|
||||
width: "20cqmin",
|
||||
height: 30,
|
||||
width: 30,
|
||||
filter: !isConnected ? "grayscale(100%)" : undefined,
|
||||
}}
|
||||
/>
|
||||
<Flex className="dns-hole-controls-item-data-stack" direction="column" gap="1.5cqmin">
|
||||
<Text className="dns-hole-controls-item-integration-name" fz="7cqmin">
|
||||
<Flex className="dns-hole-controls-item-data-stack" direction="column" gap={5}>
|
||||
<Text className="dns-hole-controls-item-integration-name" fz="md" fw={"bold"}>
|
||||
{data.integration.name}
|
||||
</Text>
|
||||
<Flex className="dns-hole-controls-item-controls" direction="row" gap="1.5cqmin">
|
||||
<Flex className="dns-hole-controls-item-controls" direction="row" gap="lg">
|
||||
<UnstyledButton
|
||||
className="dns-hole-controls-item-toggle-button"
|
||||
disabled={!controlEnabled}
|
||||
@@ -343,20 +342,18 @@ const ControlsCard: React.FC<ControlsCardProps> = ({
|
||||
>
|
||||
<Badge
|
||||
className={`dns-hole-controls-item-toggle-button-styling${controlEnabled ? " hoverable-component clickable-component" : ""}`}
|
||||
bd="0.1cqmin solid var(--border-color)"
|
||||
px="2.5cqmin"
|
||||
h="7.5cqmin"
|
||||
fz="4.5cqmin"
|
||||
lts="0.1cqmin"
|
||||
bd="1px solid var(--border-color)"
|
||||
px="sm"
|
||||
h="lg"
|
||||
color="var(--background-color)"
|
||||
c="var(--mantine-color-text)"
|
||||
styles={{ section: { marginInlineEnd: "2.5cqmin" }, root: { cursor: "inherit" } }}
|
||||
styles={{ section: { marginInlineEnd: "sm" }, root: { cursor: "inherit" } }}
|
||||
leftSection={
|
||||
isConnected && (
|
||||
<IconCircleFilled
|
||||
className="dns-hole-controls-item-status-icon"
|
||||
color={dnsLightStatus(isEnabled)}
|
||||
style={{ height: "3.5cqmin", width: "3.5cqmin" }}
|
||||
size={16}
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -374,27 +371,25 @@ const ControlsCard: React.FC<ControlsCardProps> = ({
|
||||
)}
|
||||
</Badge>
|
||||
</UnstyledButton>
|
||||
<ActionIcon
|
||||
className="dns-hole-controls-item-timer-button"
|
||||
display={isInteractPermitted ? undefined : "none"}
|
||||
disabled={!controlEnabled || !isEnabled}
|
||||
color="yellow"
|
||||
size="fit-content"
|
||||
radius="999px 999px 0px 999px"
|
||||
bd={0}
|
||||
variant="subtle"
|
||||
onClick={() => {
|
||||
setSelectedIntegrationIds([data.integration.id]);
|
||||
open();
|
||||
}}
|
||||
>
|
||||
<IconClockPause
|
||||
className="dns-hole-controls-item-timer-icon"
|
||||
style={{ height: "7.5cqmin", width: "7.5cqmin" }}
|
||||
/>
|
||||
</ActionIcon>
|
||||
</Flex>
|
||||
</Flex>
|
||||
<ActionIcon
|
||||
className="dns-hole-controls-item-timer-button"
|
||||
display={isInteractPermitted ? undefined : "none"}
|
||||
disabled={!controlEnabled || !isEnabled}
|
||||
color="yellow"
|
||||
size={30}
|
||||
radius={board.itemRadius}
|
||||
bd={0}
|
||||
ms={"auto"}
|
||||
variant="subtle"
|
||||
onClick={() => {
|
||||
setSelectedIntegrationIds([data.integration.id]);
|
||||
open();
|
||||
}}
|
||||
>
|
||||
<IconClockPause className="dns-hole-controls-item-timer-icon" size={20} />
|
||||
</ActionIcon>
|
||||
</Flex>
|
||||
</Card>
|
||||
);
|
||||
|
||||
@@ -2,11 +2,12 @@
|
||||
|
||||
import { useMemo } from "react";
|
||||
import type { BoxProps } from "@mantine/core";
|
||||
import { Avatar, AvatarGroup, Box, Card, Flex, Stack, Text, Tooltip, TooltipFloating } from "@mantine/core";
|
||||
import { Avatar, AvatarGroup, Card, Flex, SimpleGrid, Stack, Text, Tooltip, TooltipFloating } from "@mantine/core";
|
||||
import { useElementSize } from "@mantine/hooks";
|
||||
import { IconBarrierBlock, IconPercentage, IconSearch, IconWorldWww } from "@tabler/icons-react";
|
||||
|
||||
import { clientApi } from "@homarr/api/client";
|
||||
import { useRequiredBoard } from "@homarr/boards/context";
|
||||
import { formatNumber } from "@homarr/common";
|
||||
import { integrationDefs } from "@homarr/definitions";
|
||||
import type { DnsHoleSummary } from "@homarr/integrations/types";
|
||||
@@ -62,26 +63,26 @@ export default function DnsHoleSummaryWidget({ options, integrationIds }: Widget
|
||||
const data = useMemo(() => summaries.flatMap(({ summary }) => summary), [summaries]);
|
||||
|
||||
return (
|
||||
<Box h="100%" {...boxPropsByLayout(options.layout)} p="2cqmin">
|
||||
<SimpleGrid cols={2} h="100%" p={"xs"} {...boxPropsByLayout(options.layout)}>
|
||||
{data.length > 0 ? (
|
||||
stats.map((item) => (
|
||||
<StatCard key={item.color} item={item} usePiHoleColors={options.usePiHoleColors} data={data} t={t} />
|
||||
))
|
||||
) : (
|
||||
<Stack h="100%" w="100%" justify="center" align="center" gap="2.5cqmin" p="2.5cqmin">
|
||||
<AvatarGroup spacing="10cqmin">
|
||||
<Stack h="100%" w="100%" justify="center" align="center" gap="sm" p="sm">
|
||||
<AvatarGroup spacing="md">
|
||||
{summaries.map(({ integration }) => (
|
||||
<Tooltip key={integration.id} label={integration.name}>
|
||||
<Avatar h="35cqmin" w="35cqmin" src={integrationDefs[integration.kind].iconUrl} />
|
||||
<Avatar h={30} w={30} src={integrationDefs[integration.kind].iconUrl} />
|
||||
</Tooltip>
|
||||
))}
|
||||
</AvatarGroup>
|
||||
<Text fz="10cqmin" ta="center">
|
||||
<Text fz="md" ta="center">
|
||||
{t("widget.dnsHoleSummary.error.integrationsDisconnected")}
|
||||
</Text>
|
||||
</Stack>
|
||||
)}
|
||||
</Box>
|
||||
</SimpleGrid>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -152,30 +153,30 @@ const StatCard = ({ item, data, usePiHoleColors, t }: StatCardProps) => {
|
||||
const { ref, height, width } = useElementSize();
|
||||
const isLong = width > height + 20;
|
||||
const tooltip = item.tooltip?.(data, t);
|
||||
const board = useRequiredBoard();
|
||||
|
||||
return (
|
||||
<TooltipFloating label={tooltip} disabled={!tooltip} w={250} multiline>
|
||||
<Card
|
||||
ref={ref}
|
||||
className="summary-card"
|
||||
m="2cqmin"
|
||||
p="2.5cqmin"
|
||||
p="sm"
|
||||
radius={board.itemRadius}
|
||||
bg={usePiHoleColors ? item.color : "rgba(96, 96, 96, 0.1)"}
|
||||
style={{
|
||||
flex: 1,
|
||||
}}
|
||||
withBorder
|
||||
>
|
||||
<Flex
|
||||
className="summary-card-elements"
|
||||
h="100%"
|
||||
w="100%"
|
||||
align="center"
|
||||
justify="space-evenly"
|
||||
justify="center"
|
||||
direction={isLong ? "row" : "column"}
|
||||
style={{ containerType: "size" }}
|
||||
>
|
||||
<item.icon className="summary-card-icon" size="40cqmin" style={{ margin: "2.5cqmin" }} />
|
||||
<item.icon className="summary-card-icon" size={50} />
|
||||
<Flex
|
||||
className="summary-card-texts"
|
||||
justify="center"
|
||||
@@ -183,22 +184,15 @@ const StatCard = ({ item, data, usePiHoleColors, t }: StatCardProps) => {
|
||||
style={{
|
||||
flex: isLong ? 1 : undefined,
|
||||
}}
|
||||
mt={"xs"}
|
||||
w="100%"
|
||||
h="100%"
|
||||
gap="1cqmin"
|
||||
gap={0}
|
||||
>
|
||||
<Text
|
||||
key={item.value(data)}
|
||||
className="summary-card-value text-flash"
|
||||
ta="center"
|
||||
size="20cqmin"
|
||||
fw="bold"
|
||||
style={{ "--glow-size": "2.5cqmin" }}
|
||||
>
|
||||
<Text key={item.value(data)} className="summary-card-value text-flash" ta="center" size="lg" fw="bold">
|
||||
{item.value(data)}
|
||||
</Text>
|
||||
{item.label && (
|
||||
<Text className="summary-card-label" ta="center" size="15cqmin">
|
||||
<Text className="summary-card-label" ta="center" size="md">
|
||||
{translateIfNecessary(t, item.label)}
|
||||
</Text>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user