diff --git a/src/components/widgets/datetime/datetime.jsx b/src/components/widgets/datetime/datetime.jsx
index fc883ec35b3388c07586e710d6858d985941088f..454d004dc0f0236b8e5973aa82ee1c5d4d040e61 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 92e0076a142b3bb12dc87a663995794047359d8f..0000000000000000000000000000000000000000
--- 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 b6daba7b78980e0c7d59461ac82ae9f90b594707..debb09c7348c38cd14b2aafb8441eeaf70f03d83 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 2e129560ceec5eeca625f9703ae0748f2e2ae1bb..11de571c816c705103d57dd4ddb957672f2254d5 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 514993da3ebc3a10eabb37814928e4a222e34253..2d1f55e4b0fd8870fac7ebf4d51566b741a98ad6 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 7a7c322d47713fa7177c41aa4d8e580f9b05bebd..cc864be68b4ce50bd1bf06ef39d56b8efc41d185 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 c817db4c4b4a797370ab25a416bec4b9e74305e0..0000000000000000000000000000000000000000
--- 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 6cba17bf777d69bed0ab9ae4392613b2e27a7946..3a4a256514b28083a8c28abe05f8635604315dba 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 5139f00add9d0f7f061ad2efec58792f77df1047..c0169ceb944cf0635acbc2693948ec2fe0934181 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 e0ee69afb75872889b25c02e669230b77ef4e537..9983486e3196e0ea8692d79e2852f667ab775957 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 1381cc55a7e214d27c3328eafa0bc1d65770598e..040a3b6b18db8f0c372bf9c9f5f5201d863a29e8 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 b404039ff8109dac5f246b10b4ceb3a2e3c9243b..3053151393e87e784e0db2094107bd223d6a0972 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 7069e3c4a657abc17296de98fa4abc53a0a46e50..242e7a3db1d0dc148ea644abafbe50859b36e708 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 571e6c8a70debf417d0669d677b477c8eddf9ce9..1a62aa31c2cd60b7b152e5df02a9f818afcfd915 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 ca09c0958381124cb9e7885012eb21df257be653..742ff9d7dbd7125a9560267260c5ed5fb74c0120 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 30b7c8eb8c79c1941577bf466ba0bd3d8f5a4317..97c74acceadafd27a1f171cbc1c79dd353992ca1 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 5727a2a00182c3cb2f00ef21ef398ab606ed0d85..0cc2c30137b741ea853735dce5ecdef06ff6ed6e 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 3bf785b1eb02c635d09526063580eba606ea7c3c..6cc2b8c5e9e9fe71d00819d4bf0fbec29a9afde5 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 bca3eb58bfd7a3c22eabf9d586a0730fdbb82fbb..1bac4a6194ac51ba1522914cf0b28b0b6f6b288c 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 518014552f02e7d6f057a76f225b1e84aa9827ea..702ea66934133340ba1e524a1f8898e3eeb8410c 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 4714188722393aeb92cc42a4062d0663562b3f3a..b4fdb143406aa765bfcc9457ae64058473ab41c2 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 0000000000000000000000000000000000000000..3a4a9f57ecacfc8385e8d795784b4794e0ea7c8e
--- /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 0000000000000000000000000000000000000000..92d8a41667623c2056e5be88e6feffeba39bec1b
--- /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 0000000000000000000000000000000000000000..7d28a1bb3418bb8dd935aca29e22f4265eac243c
--- /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 0000000000000000000000000000000000000000..8ef0e80aa6dcce550d2c5238c239a528519ac309
--- /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 0000000000000000000000000000000000000000..a3dbab85e2ee64a44c0f3aaa95573f9f496d023e
--- /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 0000000000000000000000000000000000000000..3418b92c7914dafea192bae7420eb34b4b0718f1
--- /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 0000000000000000000000000000000000000000..44e3dddc4f0e6bd31b93320629664b92807c7e1c
--- /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 0000000000000000000000000000000000000000..87f2ad22bb47895afba921ec3514f5c8ca3d1244
--- /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 0000000000000000000000000000000000000000..8971c748d4586f30ffd921f3678224333857abe8
--- /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 0000000000000000000000000000000000000000..0771ec5e8b9635c78fc2c9c311cd05ed3dba345a
--- /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 0000000000000000000000000000000000000000..363d1bd04869508cfd119d82227a2c62cb10864e
--- /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 0000000000000000000000000000000000000000..7a83d8bedd4954f4467e14af47dc6936598c798b
--- /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 0000000000000000000000000000000000000000..9766a87914bd29835f5b794b2a3470a10c5914e0
--- /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 0000000000000000000000000000000000000000..dcb9b9e96aafc49cb26d23e7496f298e0961044c
--- /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 06e5501016a785710e3d14a4baf777900df136bf..902c79dffd46e289c7cf4bc90b35a9e25bfcb79f 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) => (
-
+
))}
>