feat: modernize widget experience

This commit is contained in:
Thomas Camlong authored and ajnart committed 2026-08-14 11:07:08 +02:00
1 parent a607dff50a
commit 836a4cd46b
148 files changed
+3598 -1584

No files matched your search

@@ -11,6 +11,7 @@ import { clientApi } from "@homarr/api/client";
import { useScopedI18n } from "@homarr/translation/client";
import type { WidgetComponentProps } from "../../definition";
import { getNetworkControllerStatusLayout } from "./layout";
import { WifiVariant } from "./variants/wifi-variant";
import { WiredVariant } from "./variants/wired-variant";
@@ -36,12 +37,11 @@ export default function NetworkControllerNetworkStatusWidget({
const tCommon = useScopedI18n("common");
const data = useMemo(() => (summaries ?? []).flatMap(({ summary }) => summary), [summaries]);
const isAdvanced = displayMode === "advanced";
const countWifiGuests = data.reduce((sum, summary) => sum + summary.wifi.guests, 0);
const countWifiUsers = data.reduce((sum, summary) => sum + summary.wifi.users, 0);
const countLanGuests = data.reduce((sum, summary) => sum + summary.lan.guests, 0);
const countLanUsers = data.reduce((sum, summary) => sum + summary.lan.users, 0);
const useHorizontalStats = !isAdvanced && height < 150 && width >= 200;
const layout = getNetworkControllerStatusLayout({ width, height, displayMode, content: options.content });
if (error && summaries === undefined) throw error;
@@ -56,25 +56,25 @@ export default function NetworkControllerNetworkStatusWidget({
}
return (
<Box p={isAdvanced ? "md" : height < 120 ? "xs" : "sm"} h="100%">
<SimpleGrid cols={isAdvanced && width >= 560 ? 2 : 1} h="100%" spacing="sm">
{(isAdvanced || options.content === "wifi") && (
<Card p={isAdvanced ? "md" : 0} withBorder={isAdvanced}>
<Box p={layout.padding} h="100%">
<SimpleGrid cols={layout.columns} h="100%" spacing="sm">
{layout.showWifi && (
<Card p={layout.cardPadding} withBorder={layout.withBorder}>
<WifiVariant
countGuests={countWifiGuests}
countUsers={countWifiUsers}
compact={!isAdvanced}
horizontal={useHorizontalStats}
compact={layout.compact}
horizontal={layout.horizontalStats}
/>
</Card>
)}
{(isAdvanced || options.content === "wired") && (
<Card p={isAdvanced ? "md" : 0} withBorder={isAdvanced}>
{layout.showWired && (
<Card p={layout.cardPadding} withBorder={layout.withBorder}>
<WiredVariant
countGuests={countLanGuests}
countUsers={countLanUsers}
compact={!isAdvanced}
horizontal={useHorizontalStats}
compact={layout.compact}
horizontal={layout.horizontalStats}
/>
</Card>
)}
@@ -0,0 +1,49 @@
import { describe, expect, test } from "vitest";
import { getNetworkControllerStatusLayout } from "./layout";
describe("network controller status layout", () => {
test.each([
{
name: "minimum compact",
input: { width: 160, height: 90, displayMode: "compact" as const, content: "wifi" as const },
expected: { padding: "xs", columns: 1, showWifi: true, showWired: false, horizontalStats: false },
},
{
name: "short compact",
input: { width: 200, height: 149, displayMode: "compact" as const, content: "wired" as const },
expected: { padding: "sm", columns: 1, showWifi: false, showWired: true, horizontalStats: true },
},
{
name: "typical compact",
input: { width: 320, height: 220, displayMode: "compact" as const, content: "wifi" as const },
expected: { padding: "sm", columns: 1, showWifi: true, showWired: false, horizontalStats: false },
},
{
name: "advanced below wide boundary",
input: { width: 559, height: 320, displayMode: "advanced" as const, content: "wifi" as const },
expected: { padding: "md", columns: 1, showWifi: true, showWired: true, horizontalStats: false },
},
{
name: "wide advanced",
input: { width: 560, height: 320, displayMode: "advanced" as const, content: "wired" as const },
expected: { padding: "md", columns: 2, showWifi: true, showWired: true, horizontalStats: false },
},
{
name: "advanced at 200 percent zoom",
input: { width: 280, height: 320, displayMode: "advanced" as const, content: "wired" as const },
expected: { padding: "md", columns: 1, showWifi: true, showWired: true, horizontalStats: false },
},
])("selects the $name tier", ({ input, expected }) => {
expect(getNetworkControllerStatusLayout(input)).toMatchObject(expected);
});
test("keeps breakpoint boundaries explicit", () => {
expect(
getNetworkControllerStatusLayout({ width: 200, height: 150, displayMode: "compact", content: "wifi" }),
).toMatchObject({ padding: "sm", horizontalStats: false });
expect(
getNetworkControllerStatusLayout({ width: 199, height: 119, displayMode: "compact", content: "wifi" }),
).toMatchObject({ padding: "xs", horizontalStats: false });
});
});
@@ -0,0 +1,42 @@
import type { WidgetComponentProps } from "../../definition";
type NetworkStatusContent = WidgetComponentProps<"networkControllerStatus">["options"]["content"];
type NetworkStatusDisplayMode = WidgetComponentProps<"networkControllerStatus">["displayMode"];
interface NetworkControllerStatusLayoutInput {
width: number;
height: number;
displayMode: NetworkStatusDisplayMode;
content: NetworkStatusContent;
}
export interface NetworkControllerStatusLayout {
padding: "xs" | "sm" | "md";
columns: 1 | 2;
showWifi: boolean;
showWired: boolean;
cardPadding: 0 | "md";
withBorder: boolean;
compact: boolean;
horizontalStats: boolean;
}
export const getNetworkControllerStatusLayout = ({
width,
height,
displayMode,
content,
}: NetworkControllerStatusLayoutInput): NetworkControllerStatusLayout => {
const isAdvanced = displayMode === "advanced";
return {
padding: isAdvanced ? "md" : height < 120 ? "xs" : "sm",
columns: isAdvanced && width >= 560 ? 2 : 1,
showWifi: isAdvanced || content === "wifi",
showWired: isAdvanced || content === "wired",
cardPadding: isAdvanced ? "md" : 0,
withBorder: isAdvanced,
compact: !isAdvanced,
horizontalStats: !isAdvanced && height < 150 && width >= 200,
};
};