diff --git a/src/components/widgets/datetime/datetime.jsx b/src/components/widgets/datetime/datetime.jsx
index fc883ec3..454d004d 100644
--- a/src/components/widgets/datetime/datetime.jsx
+++ b/src/components/widgets/datetime/datetime.jsx
@@ -1,6 +1,8 @@
import { useState, useEffect } from "react";
import { useTranslation } from "next-i18next";
-import classNames from "classnames";
+
+import Container from "../widget/container";
+import Raw from "../widget/raw";
const textSizes = {
"4xl": "text-4xl",
@@ -28,15 +30,14 @@ export default function DateTime({ options }) {
}, [date, setDate, dateLocale, format]);
return (
-
+
+
+
+
+ {date}
+
+
+
+
);
}
diff --git a/src/components/widgets/error.jsx b/src/components/widgets/error.jsx
deleted file mode 100644
index 92e0076a..00000000
--- a/src/components/widgets/error.jsx
+++ /dev/null
@@ -1,23 +0,0 @@
-import { useTranslation } from "react-i18next";
-import { BiError } from "react-icons/bi";
-import classNames from "classnames";
-
-export default function Error({ options }) {
- const { t } = useTranslation();
-
- return (
-
-
-
-
-
- {t("widget.api_error")}
-
-
-
-
- );
-}
diff --git a/src/components/widgets/glances/glances.jsx b/src/components/widgets/glances/glances.jsx
index b6daba7b..debb09c7 100644
--- a/src/components/widgets/glances/glances.jsx
+++ b/src/components/widgets/glances/glances.jsx
@@ -3,10 +3,15 @@ import { useContext } from "react";
import { FaMemory, FaRegClock, FaThermometerHalf } from "react-icons/fa";
import { FiCpu, FiHardDrive } from "react-icons/fi";
import { useTranslation } from "next-i18next";
-import classNames from "classnames";
import UsageBar from "../resources/usage-bar";
-import Error from "../error";
+import Error from "../widget/error";
+import SingleResource from "../widget/single_resource";
+import WidgetIcon from "../widget/widget_icon";
+import ResourceValue from "../widget/resource_value";
+import ResourceLabel from "../widget/resource_label";
+import Resources from "../widget/resources";
+import WidgetLabel from "../widget/widget_label";
import { SettingsContext } from "utils/contexts/settings";
@@ -31,40 +36,33 @@ export default function Widget({ options }) {
}
if (!data) {
- return (
-
-
-
-
-
-
-
- {t("glances.wait")}
-
-
-
-
-
-
-
-
-
-
- {t("glances.wait")}
-
-
-
-
-
-
- {options.label && (
-
{options.label}
- )}
-
- );
+ return
+
+
+ {t("glances.wait")}
+
+
+
+
+ {t("glances.wait")}
+
+
+ {options.cputemp &&
+
+
+ {t("glances.wait")}
+
+
+ }
+ {options.uptime &&
+
+
+ {t("glances.wait")}
+
+
+ }
+ {options.label && }
+ ;
}
const unit = options.units === "imperial" ? "fahrenheit" : "celsius";
@@ -94,134 +92,80 @@ export default function Widget({ options }) {
}
return (
-
-
-
-
-
-
-
- {t("common.number", {
- value: data.cpu.total,
- style: "unit",
- unit: "percent",
- maximumFractionDigits: 0,
- })}
-
-
{t("glances.cpu")}
-
- {options.expanded && (
-
-
- {t("common.number", {
- value: data.load.min15,
- style: "unit",
- unit: "percent",
- maximumFractionDigits: 0,
- })}
-
- {t("glances.load")}
-
- )}
-
-
-
-
-
-
-
-
- {t("common.bytes", {
- value: data.mem.free,
- maximumFractionDigits: 1,
- binary: true,
- })}
-
-
{t("glances.free")}
-
- {options.expanded && (
-
-
- {t("common.bytes", {
- value: data.mem.total,
- maximumFractionDigits: 1,
- binary: true,
- })}
-
- {t("glances.total")}
-
- )}
-
-
-
- {disks.map((disk) => (
-
-
-
-
- {t("common.bytes", { value: disk.free })}
- {t("glances.free")}
-
- {options.expanded && (
-
- {t("common.bytes", { value: disk.size })}
- {t("glances.total")}
-
- )}
-
-
-
))}
- {options.cputemp && mainTemp > 0 &&
- (
-
-
-
-
- {t("common.number", {
- value: mainTemp,
- maximumFractionDigits: 1,
- style: "unit",
- unit
- })}
-
- {t("glances.temp")}
-
- {options.expanded && (
-
-
- {t("common.number", {
- value: maxTemp,
- maximumFractionDigits: 1,
- style: "unit",
- unit
- })}
-
- {t("glances.warn")}
-
- )}
-
-
-
)}
- {options.uptime && data.uptime &&
- (
-
-
-
-
- {data.uptime.replace(" days,", t("glances.days")).replace(/:\d\d:\d\d$/g, t("glances.hours"))}
-
- {t("glances.uptime")}
-
-
-
-
)}
-
- {options.label && (
- {options.label}
- )}
-
+
+
+
+ {t("common.number", {
+ value: data.cpu.total,
+ style: "unit",
+ unit: "percent",
+ maximumFractionDigits: 0,
+ })}
+ {t("glances.cpu")}
+ {t("common.number", {
+ value: data.load.min15,
+ style: "unit",
+ unit: "percent",
+ maximumFractionDigits: 0,
+ })}
+ {t("glances.load")}
+
+
+
+
+ {t("common.bytes", {
+ value: data.mem.free,
+ maximumFractionDigits: 1,
+ binary: true,
+ })}
+ {t("glances.free")}
+ {t("common.bytes", {
+ value: data.mem.total,
+ maximumFractionDigits: 1,
+ binary: true,
+ })}
+ {t("glances.total")}
+
+
+ {disks.map((disk) => (
+
+
+ {t("common.bytes", { value: disk.free })}
+ {t("glances.free")}
+ {t("common.bytes", { value: disk.size })}
+ {t("glances.total")}
+
+
+ ))}
+ {options.cputemp && mainTemp > 0 &&
+
+
+ {t("common.number", {
+ value: mainTemp,
+ maximumFractionDigits: 1,
+ style: "unit",
+ unit
+ })}
+ {t("glances.temp")}
+ {t("common.number", {
+ value: maxTemp,
+ maximumFractionDigits: 1,
+ style: "unit",
+ unit
+ })}
+ {t("glances.warn")}
+
+
+ }
+ {options.uptime && data.uptime &&
+
+
+ {data.uptime.replace(" days,", t("glances.days")).replace(/:\d\d:\d\d$/g, t("glances.hours"))}
+ {t("glances.uptime")}
+
+
+ }
+ {options.label && }
+
);
}
diff --git a/src/components/widgets/greeting/greeting.jsx b/src/components/widgets/greeting/greeting.jsx
index 2e129560..11de571c 100644
--- a/src/components/widgets/greeting/greeting.jsx
+++ b/src/components/widgets/greeting/greeting.jsx
@@ -1,4 +1,5 @@
-import classNames from "classnames";
+import Container from "../widget/container";
+import Raw from "../widget/raw";
const textSizes = {
"4xl": "text-4xl",
@@ -13,15 +14,12 @@ const textSizes = {
export default function Greeting({ options }) {
if (options.text) {
- return (
-
+ return
+
{options.text}
-
- );
+
+ ;
}
}
diff --git a/src/components/widgets/kubernetes/kubernetes.jsx b/src/components/widgets/kubernetes/kubernetes.jsx
index 514993da..2d1f55e4 100644
--- a/src/components/widgets/kubernetes/kubernetes.jsx
+++ b/src/components/widgets/kubernetes/kubernetes.jsx
@@ -1,8 +1,9 @@
import useSWR from "swr";
import { useTranslation } from "next-i18next";
-import classNames from "classnames";
-import Error from "../error";
+import Error from "../widget/error";
+import Container from "../widget/container";
+import Raw from "../widget/raw";
import Node from "./node";
@@ -20,7 +21,7 @@ export default function Widget({ options }) {
used: 0,
total: 0,
free: 0,
- precent: 0
+ percent: 0
}
};
@@ -35,11 +36,8 @@ export default function Widget({ options }) {
}
if (!data) {
- return (
-
+ return
+
{cluster.show &&
@@ -48,15 +46,12 @@ export default function Widget({ options }) {
}
-
- );
+
+ ;
}
- return (
-
+ return
+
{cluster.show &&
@@ -66,6 +61,6 @@ export default function Widget({ options }) {
)
}
-
- );
+
+ ;
}
diff --git a/src/components/widgets/kubernetes/node.jsx b/src/components/widgets/kubernetes/node.jsx
index 7a7c322d..cc864be6 100644
--- a/src/components/widgets/kubernetes/node.jsx
+++ b/src/components/widgets/kubernetes/node.jsx
@@ -3,8 +3,7 @@ import { FiAlertTriangle, FiCpu, FiServer } from "react-icons/fi";
import { SiKubernetes } from "react-icons/si";
import { useTranslation } from "next-i18next";
-import UsageBar from "./usage-bar";
-
+import UsageBar from "../resources/usage-bar";
export default function Node({ type, options, data }) {
const { t } = useTranslation();
@@ -29,7 +28,7 @@ export default function Node({ type, options, data }) {
{t("common.number", {
- value: data.cpu.percent,
+ value: data?.cpu?.percent ?? 0,
style: "unit",
unit: "percent",
maximumFractionDigits: 0
@@ -37,18 +36,18 @@ export default function Node({ type, options, data }) {
-
+
{t("common.bytes", {
- value: data.memory.free,
+ value: data?.memory?.free ?? 0,
maximumFractionDigits: 0,
binary: true
})}
-
+
{options.showLabel && (
{type === "cluster" ? options.label : data.name}
)}
diff --git a/src/components/widgets/kubernetes/usage-bar.jsx b/src/components/widgets/kubernetes/usage-bar.jsx
deleted file mode 100644
index c817db4c..00000000
--- a/src/components/widgets/kubernetes/usage-bar.jsx
+++ /dev/null
@@ -1,12 +0,0 @@
-export default function UsageBar({ percent }) {
- return (
-
- );
-}
diff --git a/src/components/widgets/logo/logo.jsx b/src/components/widgets/logo/logo.jsx
index 6cba17bf..3a4a2565 100644
--- a/src/components/widgets/logo/logo.jsx
+++ b/src/components/widgets/logo/logo.jsx
@@ -1,14 +1,13 @@
-import classNames from "classnames";
+import Container from "../widget/container";
+import Raw from "../widget/raw";
import ResolvedIcon from "components/resolvedicon"
export default function Logo({ options }) {
return (
-
- {options.icon ?
+
+
+ {options.icon ?
:
// fallback to homepage logo
}
-
+
+
)
}
diff --git a/src/components/widgets/longhorn/longhorn.jsx b/src/components/widgets/longhorn/longhorn.jsx
index 5139f00a..c0169ceb 100644
--- a/src/components/widgets/longhorn/longhorn.jsx
+++ b/src/components/widgets/longhorn/longhorn.jsx
@@ -1,7 +1,8 @@
import useSWR from "swr";
-import classNames from "classnames";
-import Error from "../error";
+import Error from "../widget/error";
+import Container from "../widget/container";
+import Raw from "../widget/raw";
import Node from "./node";
@@ -16,21 +17,15 @@ export default function Longhorn({ options }) {
}
if (!data) {
- return (
-
- );
+
+ ;
}
- return (
-
+ return
+
{data.nodes
.filter((node) => {
@@ -51,6 +46,6 @@ export default function Longhorn({ options }) {
)}
-
- );
+
+ ;
}
diff --git a/src/components/widgets/longhorn/node.jsx b/src/components/widgets/longhorn/node.jsx
index e0ee69af..9983486e 100644
--- a/src/components/widgets/longhorn/node.jsx
+++ b/src/components/widgets/longhorn/node.jsx
@@ -1,32 +1,23 @@
-import { FiHardDrive } from "react-icons/fi";
import { useTranslation } from "next-i18next";
+import { FaThermometerHalf } from "react-icons/fa";
import UsageBar from "../resources/usage-bar";
+import SingleResource from "../widget/single_resource";
+import WidgetIcon from "../widget/widget_icon";
+import ResourceValue from "../widget/resource_value";
+import ResourceLabel from "../widget/resource_label";
+import WidgetLabel from "../widget/widget_label";
export default function Node({ data, expanded, labels }) {
const { t } = useTranslation();
- return (
- <>
-
-
-
-
- {t("common.bytes", { value: data.node.available })}
- {t("resources.free")}
-
- {expanded && (
-
- {t("common.bytes", { value: data.node.maximum })}
- {t("resources.total")}
-
- )}
-
-
-
- {labels && (
- {data.node.id}
- )}
- >
- );
+ return
+
+ {t("common.bytes", { value: data.node.available })}
+ {t("resources.free")}
+ {t("common.bytes", { value: data.node.maximum })}
+ {t("resources.total")}
+
+ { labels && }
+
}
diff --git a/src/components/widgets/openmeteo/openmeteo.jsx b/src/components/widgets/openmeteo/openmeteo.jsx
index 1381cc55..040a3b6b 100644
--- a/src/components/widgets/openmeteo/openmeteo.jsx
+++ b/src/components/widgets/openmeteo/openmeteo.jsx
@@ -3,9 +3,13 @@ import { useState } from "react";
import { WiCloudDown } from "react-icons/wi";
import { MdLocationDisabled, MdLocationSearching } from "react-icons/md";
import { useTranslation } from "next-i18next";
-import classNames from "classnames";
-import Error from "../error";
+import Error from "../widget/error";
+import Container from "../widget/container";
+import ContainerButton from "../widget/container_button";
+import WidgetIcon from "../widget/widget_icon";
+import PrimaryText from "../widget/primary_text";
+import SecondaryText from "../widget/secondary_text";
import Icon from "./icon";
@@ -21,50 +25,31 @@ function Widget({ options }) {
}
if (!data) {
- return (
-
-
-
-
-
-
- {t("weather.updating")}
- {t("weather.wait")}
-
-
-
- );
+ return
+ {t("weather.updating")}
+ {t("weather.wait")}
+
+ ;
}
const unit = options.units === "metric" ? "celsius" : "fahrenheit";
- const timeOfDay = data.current_weather.time > data.daily.sunrise[0] && data.current_weather.time < data.daily.sunset[0] ? "day" : "night";
+ const weatherInfo = {
+ condition: data.current_weather.weathercode,
+ timeOfDay: data.current_weather.time > data.daily.sunrise[0] && data.current_weather.time < data.daily.sunset[0] ? "day" : "night"
+ };
- return (
-
-
-
-
-
-
-
- {options.label && `${options.label}, `}
- {t("common.number", {
- value: data.current_weather.temperature,
- style: "unit",
- unit,
- })}
-
- {t(`wmo.${data.current_weather.weathercode}-${timeOfDay}`)}
-
-
-
- );
+ return
+
+ {options.label && `${options.label}, `}
+ {t("common.number", {
+ value: data.current_weather.temperature,
+ style: "unit",
+ unit,
+ })}
+
+ {t(`wmo.${data.current_weather.weathercode}-${weatherInfo.timeOfDay}`)}
+
+ ;
}
export default function OpenMeteo({ options }) {
@@ -99,29 +84,11 @@ export default function OpenMeteo({ options }) {
// if (!requesting && !location) requestLocation();
if (!location) {
- return (
-
- );
+ return
+ {t("weather.current")}
+ {t("weather.allow")}
+
+ ;
}
return ;
diff --git a/src/components/widgets/openweathermap/weather.jsx b/src/components/widgets/openweathermap/weather.jsx
index b404039f..30531513 100644
--- a/src/components/widgets/openweathermap/weather.jsx
+++ b/src/components/widgets/openweathermap/weather.jsx
@@ -3,12 +3,17 @@ import { useState } from "react";
import { WiCloudDown } from "react-icons/wi";
import { MdLocationDisabled, MdLocationSearching } from "react-icons/md";
import { useTranslation } from "next-i18next";
-import classNames from "classnames";
-import Error from "../error";
+import Error from "../widget/error";
+import Container from "../widget/container";
+import ContainerButton from "../widget/container_button";
+import PrimaryText from "../widget/primary_text";
+import SecondaryText from "../widget/secondary_text";
+import WidgetIcon from "../widget/widget_icon";
import Icon from "./icon";
+
function Widget({ options }) {
const { t, i18n } = useTranslation();
@@ -21,48 +26,26 @@ function Widget({ options }) {
}
if (!data) {
- return (
-
-
-
-
-
-
- {t("weather.updating")}
- {t("weather.wait")}
-
-
-
- );
+ return
+ {t("weather.updating")}
+ {t("weather.wait")}
+
+ ;
}
const unit = options.units === "metric" ? "celsius" : "fahrenheit";
- return (
-
-
-
- data.sys.sunrise && data.dt < data.sys.sunset ? "day" : "night"}
- />
-
-
-
- {options.label && `${options.label}, `}
- {t("common.number", { value: data.main.temp, style: "unit", unit })}
-
- {data.weather[0].description}
-
-
-
- );
+ const weatherInfo = {
+ condition: data.weather[0].id,
+ timeOfDay: data.dt > data.sys.sunrise && data.dt < data.sys.sunset ? "day" : "night"
+ };
+
+ return
+ {options.label && `${options.label}, `}
+ {t("common.number", { value: data.main.temp, style: "unit", unit })}
+ {data.weather[0].description}
+
+ ;
}
export default function OpenWeatherMap({ options }) {
@@ -94,33 +77,12 @@ export default function OpenWeatherMap({ options }) {
}
};
- // if (!requesting && !location) requestLocation();
-
if (!location) {
- return (
-
- );
+ return
+ {t("weather.current")}
+ {t("weather.allow")}
+
+ ;
}
return ;
diff --git a/src/components/widgets/resources/cpu.jsx b/src/components/widgets/resources/cpu.jsx
index 7069e3c4..242e7a3d 100644
--- a/src/components/widgets/resources/cpu.jsx
+++ b/src/components/widgets/resources/cpu.jsx
@@ -1,8 +1,13 @@
import useSWR from "swr";
import { FiCpu } from "react-icons/fi";
-import { BiError } from "react-icons/bi";
import { useTranslation } from "next-i18next";
+import SingleResource from "../widget/single_resource";
+import WidgetIcon from "../widget/widget_icon";
+import ResourceValue from "../widget/resource_value";
+import ResourceLabel from "../widget/resource_label";
+import Error from "../widget/error";
+
import UsageBar from "./usage-bar";
export default function Cpu({ expanded }) {
@@ -13,67 +18,38 @@ export default function Cpu({ expanded }) {
});
if (error || data?.error) {
- return (
-
-
-
- {t("widget.api_error")}
-
-
- );
+ return
}
if (!data) {
- return (
-
-
-
-
-
-
-
{t("resources.cpu")}
-
- {expanded && (
-
-
-
-
{t("resources.load")}
-
- )}
-
-
-
- );
+ return
+
+ -
+ {t("resources.cpu")}
+ -
+ {t("resources.load")}
+
+
}
- const percent = data.cpu.usage;
-
- return (
-
-
-
-
-
- {t("common.number", {
- value: data.cpu.usage,
- style: "unit",
- unit: "percent",
- maximumFractionDigits: 0,
- })}
-
-
{t("resources.cpu")}
-
- {expanded && (
-
-
- {t("common.number", {
- value: data.cpu.load,
- maximumFractionDigits: 2,
- })}
-
-
{t("resources.load")}
-
- )}
-
-
-
- );
+ return
+
+
+ {t("common.number", {
+ value: data.cpu.usage,
+ style: "unit",
+ unit: "percent",
+ maximumFractionDigits: 0,
+ })}
+
+ {t("resources.cpu")}
+
+ {t("common.number", {
+ value: data.cpu.load,
+ maximumFractionDigits: 2,
+ })}
+
+ {t("resources.load")}
+
+
}
diff --git a/src/components/widgets/resources/cputemp.jsx b/src/components/widgets/resources/cputemp.jsx
index 571e6c8a..1a62aa31 100644
--- a/src/components/widgets/resources/cputemp.jsx
+++ b/src/components/widgets/resources/cputemp.jsx
@@ -1,8 +1,13 @@
import useSWR from "swr";
import { FaThermometerHalf } from "react-icons/fa";
-import { BiError } from "react-icons/bi";
import { useTranslation } from "next-i18next";
+import SingleResource from "../widget/single_resource";
+import WidgetIcon from "../widget/widget_icon";
+import ResourceValue from "../widget/resource_value";
+import ResourceLabel from "../widget/resource_label";
+import Error from "../widget/error";
+
import UsageBar from "./usage-bar";
function convertToFahrenheit(t) {
@@ -17,34 +22,17 @@ export default function CpuTemp({ expanded, units }) {
});
if (error || data?.error) {
- return (
-
-
-
- {t("widget.api_error")}
-
-
- );
+ return
}
if (!data || !data.cputemp) {
- return (
-
-
-
-
- -
- {t("resources.temp")}
-
- {expanded && (
-
- -
- {t("resources.max")}
-
- )}
-
-
- );
+ return
+
+ -
+ {t("resources.temp")}
+ -
+ {t("resources.max")}
+
}
let mainTemp = data.cputemp.main;
@@ -54,38 +42,27 @@ export default function CpuTemp({ expanded, units }) {
const unit = units === "imperial" ? "fahrenheit" : "celsius";
mainTemp = (unit === "celsius") ? mainTemp : convertToFahrenheit(mainTemp);
const maxTemp = (unit === "celsius") ? data.cputemp.max : convertToFahrenheit(data.cputemp.max);
- const percent = Math.round((mainTemp / maxTemp) * 100);
- return (
-
-
-
-
-
- {t("common.number", {
- value: mainTemp,
- maximumFractionDigits: 1,
- style: "unit",
- unit
- })}
-
- {t("resources.temp")}
-
- {expanded && (
-
-
- {t("common.number", {
- value: maxTemp,
- maximumFractionDigits: 1,
- style: "unit",
- unit
- })}
-
- {t("resources.max")}
-
- )}
-
-
-
- );
+ return
+
+
+ {t("common.number", {
+ value: mainTemp,
+ maximumFractionDigits: 1,
+ style: "unit",
+ unit
+ })}
+
+ {t("resources.temp")}
+
+ {t("common.number", {
+ value: maxTemp,
+ maximumFractionDigits: 1,
+ style: "unit",
+ unit
+ })}
+
+ {t("resources.max")}
+
+ ;
}
diff --git a/src/components/widgets/resources/disk.jsx b/src/components/widgets/resources/disk.jsx
index ca09c095..742ff9d7 100644
--- a/src/components/widgets/resources/disk.jsx
+++ b/src/components/widgets/resources/disk.jsx
@@ -1,8 +1,13 @@
import useSWR from "swr";
import { FiHardDrive } from "react-icons/fi";
-import { BiError } from "react-icons/bi";
import { useTranslation } from "next-i18next";
+import SingleResource from "../widget/single_resource";
+import WidgetIcon from "../widget/widget_icon";
+import ResourceValue from "../widget/resource_value";
+import ResourceLabel from "../widget/resource_label";
+import Error from "../widget/error";
+
import UsageBar from "./usage-bar";
export default function Disk({ options, expanded }) {
@@ -13,56 +18,29 @@ export default function Disk({ options, expanded }) {
});
if (error || data?.error) {
- return (
-
-
-
- {t("widget.api_error")}
-
-
- );
+ return
}
if (!data) {
- return (
-
-
-
-
- -
- {t("resources.free")}
-
- {expanded && (
-
- -
- {t("resources.total")}
-
- )}
-
-
-
- );
+ return
+
+ -
+ {t("resources.free")}
+ -
+ {t("resources.total")}
+
+ ;
}
// data.drive.used not accurate?
const percent = Math.round(((data.drive.size - data.drive.available) / data.drive.size) * 100);
- return (
-
-
-
-
- {t("common.bytes", { value: data.drive.available })}
- {t("resources.free")}
-
- {expanded && (
-
- {t("common.bytes", { value: data.drive.size })}
- {t("resources.total")}
-
- )}
-
-
-
- );
+ return
+
+ {t("common.bytes", { value: data.drive.available })}
+ {t("resources.free")}
+ {t("common.bytes", { value: data.drive.size })}
+ {t("resources.total")}
+
+ ;
}
diff --git a/src/components/widgets/resources/memory.jsx b/src/components/widgets/resources/memory.jsx
index 30b7c8eb..97c74acc 100644
--- a/src/components/widgets/resources/memory.jsx
+++ b/src/components/widgets/resources/memory.jsx
@@ -1,8 +1,13 @@
import useSWR from "swr";
import { FaMemory } from "react-icons/fa";
-import { BiError } from "react-icons/bi";
import { useTranslation } from "next-i18next";
+import SingleResource from "../widget/single_resource";
+import WidgetIcon from "../widget/widget_icon";
+import ResourceValue from "../widget/resource_value";
+import ResourceLabel from "../widget/resource_label";
+import Error from "../widget/error";
+
import UsageBar from "./usage-bar";
export default function Memory({ expanded }) {
@@ -13,63 +18,34 @@ export default function Memory({ expanded }) {
});
if (error || data?.error) {
- return (
-
-
-
- {t("widget.api_error")}
-
-
- );
+ return
}
if (!data) {
- return (
-
-
-
-
- -
- {t("resources.free")}
-
- {expanded && (
-
- -
- {t("resources.total")}
-
- )}
-
-
-
- );
+ return
+
+ -
+ {t("resources.free")}
+ -
+ {t("resources.total")}
+
+ ;
}
const percent = Math.round((data.memory.active / data.memory.total) * 100);
- return (
-
-
-
-
-
- {t("common.bytes", { value: data.memory.available, maximumFractionDigits: 1, binary: true })}
-
- {t("resources.free")}
-
- {expanded && (
-
-
- {t("common.bytes", {
- value: data.memory.total,
- maximumFractionDigits: 1,
- binary: true,
- })}
-
- {t("resources.total")}
-
- )}
-
-
-
- );
+ return
+
+ {t("common.bytes", { value: data.memory.available, maximumFractionDigits: 1, binary: true })}
+ {t("resources.free")}
+
+ {t("common.bytes", {
+ value: data.memory.total,
+ maximumFractionDigits: 1,
+ binary: true,
+ })}
+
+ {t("resources.total")}
+
+ ;
}
diff --git a/src/components/widgets/resources/resources.jsx b/src/components/widgets/resources/resources.jsx
index 5727a2a0..0cc2c301 100644
--- a/src/components/widgets/resources/resources.jsx
+++ b/src/components/widgets/resources/resources.jsx
@@ -1,4 +1,5 @@
-import classNames from "classnames";
+import Container from "../widget/container";
+import Raw from "../widget/raw";
import Disk from "./disk";
import Cpu from "./cpu";
@@ -8,11 +9,8 @@ import Uptime from "./uptime";
export default function Resources({ options }) {
const { expanded, units } = options;
- return (
-
+ return
+
{options.cpu &&
}
{options.memory &&
}
@@ -25,6 +23,6 @@ export default function Resources({ options }) {
{options.label && (
{options.label}
)}
-
- );
+
+ ;
}
diff --git a/src/components/widgets/resources/uptime.jsx b/src/components/widgets/resources/uptime.jsx
index 3bf785b1..6cc2b8c5 100644
--- a/src/components/widgets/resources/uptime.jsx
+++ b/src/components/widgets/resources/uptime.jsx
@@ -1,8 +1,13 @@
import useSWR from "swr";
import { FaRegClock } from "react-icons/fa";
-import { BiError } from "react-icons/bi";
import { useTranslation } from "next-i18next";
+import SingleResource from "../widget/single_resource";
+import WidgetIcon from "../widget/widget_icon";
+import ResourceValue from "../widget/resource_value";
+import ResourceLabel from "../widget/resource_label";
+import Error from "../widget/error";
+
import UsageBar from "./usage-bar";
export default function Uptime() {
@@ -13,35 +18,22 @@ export default function Uptime() {
});
if (error || data?.error) {
- return (
-
-
-
- {t("widget.api_error")}
-
-
- );
+ return
}
if (!data) {
- return (
-
-
-
-
- -
- {t("resources.temp")}
-
-
-
- );
+ return
+
+ -
+ {t("resources.uptime")}
+ ;
}
const mo = Math.floor(data.uptime / (3600 * 24 * 31));
const d = Math.floor(data.uptime % (3600 * 24 * 31) / (3600 * 24));
const h = Math.floor(data.uptime % (3600 * 24) / 3600);
const m = Math.floor(data.uptime % 3600 / 60);
-
+
let uptime;
if (mo > 0) uptime = `${mo}${t("resources.months")} ${d}${t("resources.days")}`;
else if (d > 0) uptime = `${d}${t("resources.days")} ${h}${t("resources.hours")}`;
@@ -49,18 +41,10 @@ export default function Uptime() {
const percent = Math.round((new Date().getSeconds() / 60) * 100);
- return (
-
-
-
-
-
- {uptime}
-
- {t("resources.uptime")}
-
-
-
-
- );
+ return
+
+ {uptime}
+ {t("resources.uptime")}
+
+ ;
}
diff --git a/src/components/widgets/search/search.jsx b/src/components/widgets/search/search.jsx
index bca3eb58..1bac4a61 100644
--- a/src/components/widgets/search/search.jsx
+++ b/src/components/widgets/search/search.jsx
@@ -1,10 +1,13 @@
-import { useState, useEffect, Fragment } from "react";
+import { useState, useEffect, useCallback, Fragment } from "react";
import { useTranslation } from "next-i18next";
import { FiSearch } from "react-icons/fi";
import { SiDuckduckgo, SiMicrosoftbing, SiGoogle, SiBaidu, SiBrave } from "react-icons/si";
import { Listbox, Transition } from "@headlessui/react";
import classNames from "classnames";
+import ContainerForm from "../widget/container_form";
+import Raw from "../widget/raw";
+
export const searchProviders = {
google: {
name: "Google",
@@ -77,13 +80,8 @@ export default function Search({ options }) {
}
}, [availableProviderIds]);
- if (!availableProviderIds) {
- return null;
- }
-
- function handleSubmit(event) {
+ const submitCallback = useCallback(event => {
const q = encodeURIComponent(query);
-
const { url } = selectedProvider;
if (url) {
window.open(`${url}${q}`, options.target || "_blank");
@@ -94,6 +92,10 @@ export default function Search({ options }) {
event.preventDefault();
event.target.reset();
setQuery("");
+ }, [options.target, options.url, query, selectedProvider]);
+
+ if (!availableProviderIds) {
+ return null;
}
const onChangeProvider = (provider) => {
@@ -101,80 +103,79 @@ export default function Search({ options }) {
localStorage.setItem(localStorageKey, provider.name);
}
- return (
-
+
+
}
diff --git a/src/components/widgets/weather/weather.jsx b/src/components/widgets/weather/weather.jsx
index 51801455..702ea669 100644
--- a/src/components/widgets/weather/weather.jsx
+++ b/src/components/widgets/weather/weather.jsx
@@ -3,9 +3,13 @@ import { useState } from "react";
import { WiCloudDown } from "react-icons/wi";
import { MdLocationDisabled, MdLocationSearching } from "react-icons/md";
import { useTranslation } from "next-i18next";
-import classNames from "classnames";
-import Error from "../error";
+import Error from "../widget/error";
+import Container from "../widget/container";
+import PrimaryText from "../widget/primary_text";
+import SecondaryText from "../widget/secondary_text";
+import WidgetIcon from "../widget/widget_icon";
+import ContainerButton from "../widget/container_button";
import Icon from "./icon";
@@ -21,49 +25,31 @@ function Widget({ options }) {
}
if (!data) {
- return (
-
-
-
-
-
-
- {t("weather.updating")}
- {t("weather.wait")}
-
-
-
- );
+ return
+ {t("weather.updating")}
+ {t("weather.wait")}
+
+ ;
}
const unit = options.units === "metric" ? "celsius" : "fahrenheit";
+ const weatherInfo = {
+ condition: data.current.condition.code,
+ timeOfDay: data.current.is_day ? "day" : "night",
+ };
- return (
-
-
-
-
-
-
-
- {options.label && `${options.label}, `}
- {t("common.number", {
- value: options.units === "metric" ? data.current.temp_c : data.current.temp_f,
- style: "unit",
- unit,
- })}
-
- {data.current.condition.text}
-
-
-
- );
+ return
+
+ {options.label && `${options.label}, `}
+ {t("common.number", {
+ value: options.units === "metric" ? data.current.temp_c : data.current.temp_f,
+ style: "unit",
+ unit,
+ })}
+
+ {data.current.condition.text}
+
+ ;
}
export default function WeatherApi({ options }) {
@@ -95,33 +81,12 @@ export default function WeatherApi({ options }) {
}
};
- // if (!requesting && !location) requestLocation();
-
if (!location) {
- return (
-
- );
+ return
+ {t("weather.current")}
+ {t("weather.allow")}
+
+ ;
}
return ;
diff --git a/src/components/widgets/widget.jsx b/src/components/widgets/widget.jsx
index 47141887..b4fdb143 100644
--- a/src/components/widgets/widget.jsx
+++ b/src/components/widgets/widget.jsx
@@ -17,13 +17,13 @@ const widgetMappings = {
kubernetes: dynamic(() => import("components/widgets/kubernetes/kubernetes")),
};
-export default function Widget({ widget }) {
+export default function Widget({ widget, style }) {
const InfoWidget = widgetMappings[widget.type];
if (InfoWidget) {
return (
-
+
);
}
diff --git a/src/components/widgets/widget/container.jsx b/src/components/widgets/widget/container.jsx
new file mode 100644
index 00000000..3a4a9f57
--- /dev/null
+++ b/src/components/widgets/widget/container.jsx
@@ -0,0 +1,42 @@
+import classNames from "classnames";
+
+import WidgetIcon from "./widget_icon";
+import PrimaryText from "./primary_text";
+import SecondaryText from "./secondary_text";
+import Raw from "./raw";
+
+export function getAllClasses(options, additionalClassNames = '') {
+ return classNames(
+ "flex flex-col justify-center first:ml-0 ml-4 mr-2",
+ additionalClassNames,
+ options?.style === "boxedWidgets" && " ml-4 mt-2 m:mb-0 rounded-md shadow-md shadow-theme-900/10 dark:shadow-theme-900/20 bg-theme-100/20 dark:bg-white/5 p-2 pl-3",
+ );
+}
+
+export function getInnerBlock(children) {
+ // children won't be an array if it's Raw component
+ return Array.isArray(children) &&
+
{children.find(child => child.type === WidgetIcon)}
+
+ {children.find(child => child.type === PrimaryText)}
+ {children.find(child => child.type === SecondaryText)}
+
+
;
+}
+
+export function getBottomBlock(children) {
+ if (children.type !== Raw) {
+ return children.find(child => child.type === Raw) || [];
+ }
+
+ return [children];
+}
+
+export default function Container({ children = [], options, additionalClassNames = '' }) {
+ return (
+
+ {getInnerBlock(children)}
+ {getBottomBlock(children)}
+
+ );
+}
diff --git a/src/components/widgets/widget/container_button.jsx b/src/components/widgets/widget/container_button.jsx
new file mode 100644
index 00000000..92d8a416
--- /dev/null
+++ b/src/components/widgets/widget/container_button.jsx
@@ -0,0 +1,10 @@
+import { getAllClasses, getInnerBlock, getBottomBlock } from "./container";
+
+export default function ContainerButton ({ children = [], options, additionalClassNames = '', callback }) {
+ return (
+
+ );
+}
diff --git a/src/components/widgets/widget/container_form.jsx b/src/components/widgets/widget/container_form.jsx
new file mode 100644
index 00000000..7d28a1bb
--- /dev/null
+++ b/src/components/widgets/widget/container_form.jsx
@@ -0,0 +1,10 @@
+import { getAllClasses, getInnerBlock, getBottomBlock } from "./container";
+
+export default function ContainerForm ({ children = [], options, additionalClassNames = '', callback }) {
+ return (
+
+ );
+}
diff --git a/src/components/widgets/widget/container_link.jsx b/src/components/widgets/widget/container_link.jsx
new file mode 100644
index 00000000..8ef0e80a
--- /dev/null
+++ b/src/components/widgets/widget/container_link.jsx
@@ -0,0 +1,10 @@
+import { getAllClasses, getInnerBlock, getBottomBlock } from "./container";
+
+export default function ContainerLink ({ children = [], options, additionalClassNames = '', target }) {
+ return (
+
+ {getInnerBlock(children)}
+ {getBottomBlock(children)}
+
+ );
+}
diff --git a/src/components/widgets/widget/error.jsx b/src/components/widgets/widget/error.jsx
new file mode 100644
index 00000000..a3dbab85
--- /dev/null
+++ b/src/components/widgets/widget/error.jsx
@@ -0,0 +1,15 @@
+import { useTranslation } from "react-i18next";
+import { BiError } from "react-icons/bi";
+
+import Container from "./container";
+import PrimaryText from "./primary_text";
+import WidgetIcon from "./widget_icon";
+
+export default function Error({ options }) {
+ const { t } = useTranslation();
+
+ return
+ {t("widget.api_error")}
+
+ ;
+}
diff --git a/src/components/widgets/widget/primary_text.jsx b/src/components/widgets/widget/primary_text.jsx
new file mode 100644
index 00000000..3418b92c
--- /dev/null
+++ b/src/components/widgets/widget/primary_text.jsx
@@ -0,0 +1,5 @@
+export default function PrimaryText({ children }) {
+ return (
+ {children}
+ );
+}
diff --git a/src/components/widgets/widget/raw.jsx b/src/components/widgets/widget/raw.jsx
new file mode 100644
index 00000000..44e3dddc
--- /dev/null
+++ b/src/components/widgets/widget/raw.jsx
@@ -0,0 +1,7 @@
+export default function Raw({ children }) {
+ if (children.type === Raw) {
+ return [children];
+ }
+
+ return children;
+}
diff --git a/src/components/widgets/widget/resource_label.jsx b/src/components/widgets/widget/resource_label.jsx
new file mode 100644
index 00000000..87f2ad22
--- /dev/null
+++ b/src/components/widgets/widget/resource_label.jsx
@@ -0,0 +1,5 @@
+export default function ResourceLabel({ children }) {
+ return (
+ {children}
+ );
+}
diff --git a/src/components/widgets/widget/resource_value.jsx b/src/components/widgets/widget/resource_value.jsx
new file mode 100644
index 00000000..8971c748
--- /dev/null
+++ b/src/components/widgets/widget/resource_value.jsx
@@ -0,0 +1,5 @@
+export default function ResourceValue({ children }) {
+ return (
+ {children}
+ );
+}
diff --git a/src/components/widgets/widget/resources.jsx b/src/components/widgets/widget/resources.jsx
new file mode 100644
index 00000000..0771ec5e
--- /dev/null
+++ b/src/components/widgets/widget/resources.jsx
@@ -0,0 +1,15 @@
+import ContainerLink from "./container_link";
+import SingleResource from "./single_resource";
+import Raw from "./raw";
+import WidgetLabel from "./widget_label";
+
+export default function Resources({ options, children, target }) {
+ return
+
+
+ {children.filter(child => child && child.type === SingleResource)}
+
+ {children.filter(child => child && child.type === WidgetLabel)}
+
+ ;
+}
diff --git a/src/components/widgets/widget/secondary_text.jsx b/src/components/widgets/widget/secondary_text.jsx
new file mode 100644
index 00000000..363d1bd0
--- /dev/null
+++ b/src/components/widgets/widget/secondary_text.jsx
@@ -0,0 +1,5 @@
+export default function SecondaryText({ children }) {
+ return (
+ {children}
+ );
+}
diff --git a/src/components/widgets/widget/single_resource.jsx b/src/components/widgets/widget/single_resource.jsx
new file mode 100644
index 00000000..7a83d8be
--- /dev/null
+++ b/src/components/widgets/widget/single_resource.jsx
@@ -0,0 +1,28 @@
+import UsageBar from "../resources/usage-bar";
+
+import WidgetIcon from "./widget_icon";
+import ResourceValue from "./resource_value";
+import ResourceLabel from "./resource_label";
+import Raw from "./raw";
+
+export default function SingleResource({ children, key, expanded = false }) {
+ const values = children.filter(child => child.type === ResourceValue);
+ const labels = children.filter(child => child.type === ResourceLabel);
+
+ return
+ {children.find(child => child.type === WidgetIcon)}
+
+
+ {values.pop()}
+ {labels.pop()}
+
+ { expanded &&
+ {values.pop()}
+ {labels.pop()}
+
+ }
+ {children.find(child => child.type === UsageBar)}
+
+ {children.find(child => child.type === Raw)}
+
;
+}
diff --git a/src/components/widgets/widget/widget_icon.jsx b/src/components/widgets/widget/widget_icon.jsx
new file mode 100644
index 00000000..9766a879
--- /dev/null
+++ b/src/components/widgets/widget/widget_icon.jsx
@@ -0,0 +1,18 @@
+export default function WidgetIcon({ icon, size = "s", pulse = false, weatherInfo = {} }) {
+ const Icon = icon;
+ const { condition, timeOfDay } = weatherInfo;
+ let additionalClasses = "text-theme-800 dark:text-theme-200 ";
+
+ switch (size) {
+ case "m": additionalClasses += "w-6 h-6 "; break;
+ case "l": additionalClasses += "w-8 h-8 "; break;
+ case "xl": additionalClasses += "w-10 h-10 "; break;
+ default: additionalClasses += "w-5 h-5 ";
+ }
+
+ if (pulse) {
+ additionalClasses += "animate-pulse ";
+ }
+
+ return ;
+}
diff --git a/src/components/widgets/widget/widget_label.jsx b/src/components/widgets/widget/widget_label.jsx
new file mode 100644
index 00000000..dcb9b9e9
--- /dev/null
+++ b/src/components/widgets/widget/widget_label.jsx
@@ -0,0 +1,3 @@
+export default function WidgetLabel({ label = "" }) {
+ return {label}
+}
diff --git a/src/pages/index.jsx b/src/pages/index.jsx
index 06e55010..902c79df 100644
--- a/src/pages/index.jsx
+++ b/src/pages/index.jsx
@@ -160,6 +160,7 @@ const headerStyles = {
"m-4 mb-0 sm:m-8 sm:mb-0 rounded-md shadow-md shadow-theme-900/10 dark:shadow-theme-900/20 bg-theme-100/20 dark:bg-white/5 p-3",
underlined: "m-4 mb-0 sm:m-8 sm:mb-1 border-b-2 pb-4 border-theme-800 dark:border-theme-200/50",
clean: "m-4 mb-0 sm:m-8 sm:mb-0",
+ boxedWidgets: "m-4 mb-0 sm:m-8 sm:mb-0 sm:mt-1",
};
function Home({ initialSettings }) {
@@ -208,6 +209,7 @@ function Home({ initialSettings }) {
searchProvider = searchProviders[searchWidget.options?.provider];
}
}
+ const headerStyle = initialSettings?.headerStyle || "underlined";
useEffect(() => {
function handleKeyDown(e) {
@@ -256,7 +258,7 @@ function Home({ initialSettings }) {
!rightAlignedWidgets.includes(widget.type))
.map((widget, i) => (
-
+
))}
-
+
{widgets
.filter((widget) => rightAlignedWidgets.includes(widget.type))
.map((widget, i) => (
-
+
))}
>