fix(dns-controls): improve responsive styles (#2534)
* fix(dns-controls): improve responsive styles * fix: further dns-control improvements
This commit is contained in:
@@ -3,7 +3,20 @@
|
|||||||
import "../../widgets-common.css";
|
import "../../widgets-common.css";
|
||||||
|
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { ActionIcon, Badge, Button, Card, Flex, ScrollArea, Stack, Text, Tooltip, UnstyledButton } from "@mantine/core";
|
import {
|
||||||
|
ActionIcon,
|
||||||
|
Badge,
|
||||||
|
Button,
|
||||||
|
Card,
|
||||||
|
Flex,
|
||||||
|
Group,
|
||||||
|
Indicator,
|
||||||
|
ScrollArea,
|
||||||
|
Stack,
|
||||||
|
Text,
|
||||||
|
Tooltip,
|
||||||
|
UnstyledButton,
|
||||||
|
} from "@mantine/core";
|
||||||
import { useDisclosure } from "@mantine/hooks";
|
import { useDisclosure } from "@mantine/hooks";
|
||||||
import { IconCircleFilled, IconClockPause, IconPlayerPlay, IconPlayerStop } from "@tabler/icons-react";
|
import { IconCircleFilled, IconClockPause, IconPlayerPlay, IconPlayerStop } from "@tabler/icons-react";
|
||||||
import combineClasses from "clsx";
|
import combineClasses from "clsx";
|
||||||
@@ -30,6 +43,7 @@ export default function DnsHoleControlsWidget({
|
|||||||
options,
|
options,
|
||||||
integrationIds,
|
integrationIds,
|
||||||
isEditMode,
|
isEditMode,
|
||||||
|
width,
|
||||||
}: WidgetComponentProps<typeof widgetKind>) {
|
}: WidgetComponentProps<typeof widgetKind>) {
|
||||||
const board = useRequiredBoard();
|
const board = useRequiredBoard();
|
||||||
// DnsHole integrations with interaction permissions
|
// DnsHole integrations with interaction permissions
|
||||||
@@ -177,10 +191,10 @@ export default function DnsHoleControlsWidget({
|
|||||||
const controlAllButtonsVisible = options.showToggleAllButtons && integrationsWithInteractions.length > 0;
|
const controlAllButtonsVisible = options.showToggleAllButtons && integrationsWithInteractions.length > 0;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flex
|
<Stack
|
||||||
className="dns-hole-controls-stack"
|
className="dns-hole-controls-stack"
|
||||||
|
justify="space-between"
|
||||||
h="100%"
|
h="100%"
|
||||||
direction="column"
|
|
||||||
p="sm"
|
p="sm"
|
||||||
gap="sm"
|
gap="sm"
|
||||||
style={{ pointerEvents: isEditMode ? "none" : undefined }}
|
style={{ pointerEvents: isEditMode ? "none" : undefined }}
|
||||||
@@ -189,23 +203,25 @@ export default function DnsHoleControlsWidget({
|
|||||||
<Flex className="dns-hole-controls-buttons" gap="sm">
|
<Flex className="dns-hole-controls-buttons" gap="sm">
|
||||||
<Tooltip label={t("widget.dnsHoleControls.controls.enableAll")}>
|
<Tooltip label={t("widget.dnsHoleControls.controls.enableAll")}>
|
||||||
<Button
|
<Button
|
||||||
|
size="xs"
|
||||||
|
p={0}
|
||||||
className="dns-hole-controls-enable-all-button"
|
className="dns-hole-controls-enable-all-button"
|
||||||
onClick={() => integrationsSummaries.disabled.forEach((integrationId) => toggleDns(integrationId))}
|
onClick={() => integrationsSummaries.disabled.forEach((integrationId) => toggleDns(integrationId))}
|
||||||
disabled={integrationsSummaries.disabled.length === 0}
|
disabled={integrationsSummaries.disabled.length === 0}
|
||||||
variant="light"
|
variant="light"
|
||||||
color="green"
|
color="green"
|
||||||
h="fit-content"
|
|
||||||
p="xs"
|
|
||||||
bd={0}
|
bd={0}
|
||||||
radius={board.itemRadius}
|
radius={board.itemRadius}
|
||||||
flex={1}
|
flex={1}
|
||||||
>
|
>
|
||||||
<IconPlayerPlay className="dns-hole-controls-enable-all-icon" size={24} />
|
<IconPlayerPlay className="dns-hole-controls-enable-all-icon" size={16} />
|
||||||
</Button>
|
</Button>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
|
||||||
<Tooltip label={t("widget.dnsHoleControls.controls.setTimer")}>
|
<Tooltip label={t("widget.dnsHoleControls.controls.setTimer")}>
|
||||||
<Button
|
<Button
|
||||||
|
size="xs"
|
||||||
|
p={0}
|
||||||
className="dns-hole-controls-timer-all-button"
|
className="dns-hole-controls-timer-all-button"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setSelectedIntegrationIds(integrationsSummaries.enabled);
|
setSelectedIntegrationIds(integrationsSummaries.enabled);
|
||||||
@@ -214,36 +230,34 @@ export default function DnsHoleControlsWidget({
|
|||||||
disabled={integrationsSummaries.enabled.length === 0}
|
disabled={integrationsSummaries.enabled.length === 0}
|
||||||
variant="light"
|
variant="light"
|
||||||
color="yellow"
|
color="yellow"
|
||||||
h="fit-content"
|
|
||||||
p="xs"
|
|
||||||
bd={0}
|
bd={0}
|
||||||
radius={board.itemRadius}
|
radius={board.itemRadius}
|
||||||
flex={1}
|
flex={1}
|
||||||
>
|
>
|
||||||
<IconClockPause className="dns-hole-controls-timer-all-icon" size={24} />
|
<IconClockPause className="dns-hole-controls-timer-all-icon" size={16} />
|
||||||
</Button>
|
</Button>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
|
||||||
<Tooltip label={t("widget.dnsHoleControls.controls.disableAll")}>
|
<Tooltip label={t("widget.dnsHoleControls.controls.disableAll")}>
|
||||||
<Button
|
<Button
|
||||||
|
size="xs"
|
||||||
|
p={0}
|
||||||
className="dns-hole-controls-disable-all-button"
|
className="dns-hole-controls-disable-all-button"
|
||||||
onClick={() => integrationsSummaries.enabled.forEach((integrationId) => toggleDns(integrationId))}
|
onClick={() => integrationsSummaries.enabled.forEach((integrationId) => toggleDns(integrationId))}
|
||||||
disabled={integrationsSummaries.enabled.length === 0}
|
disabled={integrationsSummaries.enabled.length === 0}
|
||||||
variant="light"
|
variant="light"
|
||||||
color="red"
|
color="red"
|
||||||
h="fit-content"
|
|
||||||
p="xs"
|
|
||||||
bd={0}
|
bd={0}
|
||||||
radius={board.itemRadius}
|
radius={board.itemRadius}
|
||||||
flex={1}
|
flex={1}
|
||||||
>
|
>
|
||||||
<IconPlayerStop className="dns-hole-controls-disable-all-icon" size={24} />
|
<IconPlayerStop className="dns-hole-controls-disable-all-icon" size={16} />
|
||||||
</Button>
|
</Button>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</Flex>
|
</Flex>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<ScrollArea className="dns-hole-controls-integration-list-scroll-area flexed-scroll-area">
|
<ScrollArea.Autosize className="dns-hole-controls-integration-list-scroll-area flexed-scroll-area">
|
||||||
<Stack
|
<Stack
|
||||||
className="dns-hole-controls-integration-list"
|
className="dns-hole-controls-integration-list"
|
||||||
gap="sm"
|
gap="sm"
|
||||||
@@ -260,10 +274,11 @@ export default function DnsHoleControlsWidget({
|
|||||||
open={open}
|
open={open}
|
||||||
t={t}
|
t={t}
|
||||||
hasIconColor={board.iconColor !== null}
|
hasIconColor={board.iconColor !== null}
|
||||||
|
rootWidth={width}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</Stack>
|
</Stack>
|
||||||
</ScrollArea>
|
</ScrollArea.Autosize>
|
||||||
|
|
||||||
<TimerModal
|
<TimerModal
|
||||||
opened={opened}
|
opened={opened}
|
||||||
@@ -271,7 +286,7 @@ export default function DnsHoleControlsWidget({
|
|||||||
selectedIntegrationIds={selectedIntegrationIds}
|
selectedIntegrationIds={selectedIntegrationIds}
|
||||||
disableDns={disableDns}
|
disableDns={disableDns}
|
||||||
/>
|
/>
|
||||||
</Flex>
|
</Stack>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -283,6 +298,7 @@ interface ControlsCardProps {
|
|||||||
open: () => void;
|
open: () => void;
|
||||||
t: TranslationFunction;
|
t: TranslationFunction;
|
||||||
hasIconColor: boolean;
|
hasIconColor: boolean;
|
||||||
|
rootWidth: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ControlsCard: React.FC<ControlsCardProps> = ({
|
const ControlsCard: React.FC<ControlsCardProps> = ({
|
||||||
@@ -293,6 +309,7 @@ const ControlsCard: React.FC<ControlsCardProps> = ({
|
|||||||
open,
|
open,
|
||||||
t,
|
t,
|
||||||
hasIconColor,
|
hasIconColor,
|
||||||
|
rootWidth,
|
||||||
}) => {
|
}) => {
|
||||||
const isConnected = useIntegrationConnected(data.integration.updatedAt, { timeout: 30000 });
|
const isConnected = useIntegrationConnected(data.integration.updatedAt, { timeout: 30000 });
|
||||||
const isEnabled = data.summary.status ? data.summary.status === "enabled" : undefined;
|
const isEnabled = data.summary.status ? data.summary.status === "enabled" : undefined;
|
||||||
@@ -302,95 +319,161 @@ const ControlsCard: React.FC<ControlsCardProps> = ({
|
|||||||
const board = useRequiredBoard();
|
const board = useRequiredBoard();
|
||||||
|
|
||||||
const iconUrl = integrationDefs[data.integration.kind].iconUrl;
|
const iconUrl = integrationDefs[data.integration.kind].iconUrl;
|
||||||
|
const layout = rootWidth < 256 ? "sm" : "md";
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card
|
<Indicator
|
||||||
className={combineClasses(
|
disabled={!isConnected || layout !== "sm"}
|
||||||
"dns-hole-controls-integration-item-outer-shell",
|
color={dnsLightStatus(isEnabled)}
|
||||||
`dns-hole-controls-integration-item-${data.integration.id}`,
|
position="top-end"
|
||||||
`dns-hole-controls-integration-item-${data.integration.name}`,
|
offset={14}
|
||||||
classes.card,
|
|
||||||
)}
|
|
||||||
key={data.integration.id}
|
|
||||||
p="sm"
|
|
||||||
py={8}
|
|
||||||
radius={board.itemRadius}
|
|
||||||
>
|
>
|
||||||
<Flex className="dns-hole-controls-item-container" gap="md" align="center" direction="row">
|
<Card
|
||||||
<MaskedOrNormalImage
|
className={combineClasses(
|
||||||
imageUrl={iconUrl}
|
"dns-hole-controls-integration-item-outer-shell",
|
||||||
hasColor={hasIconColor}
|
`dns-hole-controls-integration-item-${data.integration.id}`,
|
||||||
alt={data.integration.name}
|
`dns-hole-controls-integration-item-${data.integration.name}`,
|
||||||
className="dns-hole-controls-item-icon"
|
classes.card,
|
||||||
style={{
|
)}
|
||||||
height: 30,
|
key={data.integration.id}
|
||||||
width: 30,
|
p="sm"
|
||||||
filter: !isConnected ? "grayscale(100%)" : undefined,
|
py={8}
|
||||||
}}
|
radius={board.itemRadius}
|
||||||
/>
|
>
|
||||||
<Flex className="dns-hole-controls-item-data-stack" direction="column" gap={5}>
|
<Flex className="dns-hole-controls-item-container" gap="md" align="center" direction="row" w="100%">
|
||||||
<Text className="dns-hole-controls-item-integration-name" fz="md" fw={"bold"}>
|
{layout === "md" && (
|
||||||
{data.integration.name}
|
<MaskedOrNormalImage
|
||||||
</Text>
|
imageUrl={iconUrl}
|
||||||
<Flex className="dns-hole-controls-item-controls" direction="row" gap="lg">
|
hasColor={hasIconColor}
|
||||||
<UnstyledButton
|
alt={data.integration.name}
|
||||||
className="dns-hole-controls-item-toggle-button"
|
className="dns-hole-controls-item-icon"
|
||||||
disabled={!controlEnabled}
|
style={{
|
||||||
display="contents"
|
height: 30,
|
||||||
style={{ cursor: controlEnabled ? "pointer" : "default" }}
|
width: 30,
|
||||||
onClick={() => toggleDns(data.integration.id)}
|
filter: !isConnected ? "grayscale(100%)" : undefined,
|
||||||
>
|
}}
|
||||||
<Badge
|
/>
|
||||||
className={`dns-hole-controls-item-toggle-button-styling${controlEnabled ? " hoverable-component clickable-component" : ""}`}
|
)}
|
||||||
bd="1px solid var(--border-color)"
|
|
||||||
px="sm"
|
<Flex className="dns-hole-controls-item-data-stack" direction="column" w="100%" gap={5}>
|
||||||
h="lg"
|
<Group gap="xs" align="center" wrap="nowrap">
|
||||||
color="var(--background-color)"
|
{layout === "sm" && (
|
||||||
c="var(--mantine-color-text)"
|
<MaskedOrNormalImage
|
||||||
styles={{ section: { marginInlineEnd: "sm" }, root: { cursor: "inherit" } }}
|
imageUrl={iconUrl}
|
||||||
leftSection={
|
hasColor={hasIconColor}
|
||||||
isConnected && (
|
alt={data.integration.name}
|
||||||
<IconCircleFilled
|
className="dns-hole-controls-item-icon"
|
||||||
className="dns-hole-controls-item-status-icon"
|
style={{
|
||||||
color={dnsLightStatus(isEnabled)}
|
height: 16,
|
||||||
size={16}
|
width: 16,
|
||||||
/>
|
filter: !isConnected ? "grayscale(100%)" : undefined,
|
||||||
)
|
}}
|
||||||
}
|
/>
|
||||||
>
|
)}
|
||||||
{t(
|
<Text className="dns-hole-controls-item-integration-name" fz="sm">
|
||||||
`widget.dnsHoleControls.controls.${
|
{data.integration.name}
|
||||||
!isConnected
|
</Text>
|
||||||
? "disconnected"
|
</Group>
|
||||||
: typeof isEnabled === "undefined"
|
<Flex className="dns-hole-controls-item-controls" direction="row" gap="sm" w="100%">
|
||||||
? "processing"
|
{layout === "sm" && (
|
||||||
: isEnabled
|
<Group gap="xs" grow wrap="nowrap" w="100%">
|
||||||
? "enabled"
|
{!isEnabled ? (
|
||||||
: "disabled"
|
<ActionIcon
|
||||||
}`,
|
onClick={() => toggleDns(data.integration.id)}
|
||||||
)}
|
disabled={!controlEnabled}
|
||||||
</Badge>
|
size="sm"
|
||||||
</UnstyledButton>
|
color="green"
|
||||||
|
variant="light"
|
||||||
|
>
|
||||||
|
<IconPlayerPlay size={12} />
|
||||||
|
</ActionIcon>
|
||||||
|
) : (
|
||||||
|
<ActionIcon
|
||||||
|
onClick={() => toggleDns(data.integration.id)}
|
||||||
|
disabled={!controlEnabled}
|
||||||
|
size="sm"
|
||||||
|
color="red"
|
||||||
|
variant="light"
|
||||||
|
>
|
||||||
|
<IconPlayerStop size={12} />
|
||||||
|
</ActionIcon>
|
||||||
|
)}
|
||||||
|
<ActionIcon
|
||||||
|
onClick={() => {
|
||||||
|
setSelectedIntegrationIds([data.integration.id]);
|
||||||
|
open();
|
||||||
|
}}
|
||||||
|
size="sm"
|
||||||
|
color="yellow"
|
||||||
|
variant="light"
|
||||||
|
>
|
||||||
|
<IconClockPause size={12} />
|
||||||
|
</ActionIcon>
|
||||||
|
</Group>
|
||||||
|
)}
|
||||||
|
{layout === "md" && (
|
||||||
|
<UnstyledButton
|
||||||
|
className="dns-hole-controls-item-toggle-button"
|
||||||
|
disabled={!controlEnabled}
|
||||||
|
display="contents"
|
||||||
|
style={{ cursor: controlEnabled ? "pointer" : "default" }}
|
||||||
|
onClick={() => toggleDns(data.integration.id)}
|
||||||
|
>
|
||||||
|
<Badge
|
||||||
|
className={`dns-hole-controls-item-toggle-button-styling${controlEnabled ? " hoverable-component clickable-component" : ""}`}
|
||||||
|
bd="1px solid var(--border-color)"
|
||||||
|
px="sm"
|
||||||
|
h="lg"
|
||||||
|
color="var(--background-color)"
|
||||||
|
c="var(--mantine-color-text)"
|
||||||
|
styles={{ section: { marginInlineEnd: "sm" }, root: { cursor: "inherit" } }}
|
||||||
|
leftSection={
|
||||||
|
isConnected && (
|
||||||
|
<IconCircleFilled
|
||||||
|
className="dns-hole-controls-item-status-icon"
|
||||||
|
color={dnsLightStatus(isEnabled)}
|
||||||
|
size={16}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{t(
|
||||||
|
`widget.dnsHoleControls.controls.${
|
||||||
|
!isConnected
|
||||||
|
? "disconnected"
|
||||||
|
: typeof isEnabled === "undefined"
|
||||||
|
? "processing"
|
||||||
|
: isEnabled
|
||||||
|
? "enabled"
|
||||||
|
: "disabled"
|
||||||
|
}`,
|
||||||
|
)}
|
||||||
|
</Badge>
|
||||||
|
</UnstyledButton>
|
||||||
|
)}
|
||||||
|
</Flex>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
{layout === "md" && (
|
||||||
|
<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>
|
</Flex>
|
||||||
<ActionIcon
|
</Card>
|
||||||
className="dns-hole-controls-item-timer-button"
|
</Indicator>
|
||||||
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>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -62,14 +62,3 @@
|
|||||||
.text-flash {
|
.text-flash {
|
||||||
animation: glow 1s ease-in-out;
|
animation: glow 1s ease-in-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*To apply to any ScrollArea that we want to flex. Same weird workaround as before*/
|
|
||||||
.flexed-scroll-area {
|
|
||||||
height: 100%;
|
|
||||||
.mantine-ScrollArea-viewport {
|
|
||||||
& div[style="min-width: 100%; display: table;"] {
|
|
||||||
display: flex !important;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user