Add optional boxed styling and error component to information widgets
Signed-off-by: Denis Papec <denis.papec@gmail.com>
This commit is contained in:
parent
3e01fc12e4
commit
c5b6dcc1e0
14 changed files with 153 additions and 122 deletions
|
@ -1,5 +1,6 @@
|
|||
import { useState, useEffect } from "react";
|
||||
import { useTranslation } from "next-i18next";
|
||||
import classNames from "classnames";
|
||||
|
||||
const textSizes = {
|
||||
"4xl": "text-4xl",
|
||||
|
@ -17,7 +18,7 @@ export default function DateTime({ options }) {
|
|||
const { i18n } = useTranslation();
|
||||
const [date, setDate] = useState("");
|
||||
const dateLocale = locale ?? i18n.language;
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
const dateFormat = new Intl.DateTimeFormat(dateLocale, { ...format });
|
||||
const interval = setInterval(() => {
|
||||
|
@ -27,7 +28,10 @@ export default function DateTime({ options }) {
|
|||
}, [date, setDate, dateLocale, format]);
|
||||
|
||||
return (
|
||||
<div className="flex flex-col justify-center first:ml-0 ml-4">
|
||||
<div className={classNames(
|
||||
"flex flex-col justify-center first:ml-0 ml-4",
|
||||
options?.styleBoxed === true && " 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-3",
|
||||
)}>
|
||||
<div className="flex flex-row items-center grow justify-end">
|
||||
<span className={`text-theme-800 dark:text-theme-200 tabular-nums ${textSizes[textSize || "lg"]}`}>
|
||||
{date}
|
||||
|
|
23
src/components/widgets/error.jsx
Normal file
23
src/components/widgets/error.jsx
Normal file
|
@ -0,0 +1,23 @@
|
|||
import { useTranslation } from "react-i18next";
|
||||
import { BiError } from "react-icons/bi";
|
||||
import classNames from "classnames";
|
||||
|
||||
export default function Error({ options }) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<div className={classNames(
|
||||
"flex flex-col justify-center first:ml-0 ml-4 mr-2",
|
||||
options?.styleBoxed === true && " 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-3",
|
||||
)}>
|
||||
<div className="flex flex-row items-center justify-end">
|
||||
<div className="flex flex-col items-center">
|
||||
<BiError className="w-8 h-8 text-theme-800 dark:text-theme-200" />
|
||||
<div className="flex flex-col ml-3 text-left">
|
||||
<span className="text-theme-800 dark:text-theme-200 text-sm">{t("widget.api_error")}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -1,11 +1,12 @@
|
|||
import useSWR from "swr";
|
||||
import { useContext } from "react";
|
||||
import { BiError } from "react-icons/bi";
|
||||
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 { SettingsContext } from "utils/contexts/settings";
|
||||
|
||||
|
@ -26,23 +27,15 @@ export default function Widget({ options }) {
|
|||
);
|
||||
|
||||
if (error || data?.error) {
|
||||
return (
|
||||
<div className="flex flex-col justify-center first:ml-0 ml-4">
|
||||
<div className="flex flex-row items-center justify-end">
|
||||
<div className="flex flex-row items-center">
|
||||
<BiError className="w-8 h-8 text-theme-800 dark:text-theme-200" />
|
||||
<div className="flex flex-col ml-3 text-left">
|
||||
<span className="text-theme-800 dark:text-theme-200 text-sm">{t("widget.api_error")}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
return <Error options={options} />
|
||||
}
|
||||
|
||||
if (!data) {
|
||||
return (
|
||||
<div className="flex flex-col max-w:full sm:basis-auto self-center grow-0 flex-wrap ml-4">
|
||||
<div className={classNames(
|
||||
"flex flex-col max-w:full sm:basis-auto self-center grow-0 flex-wrap ml-4",
|
||||
options?.styleBoxed === true && " mb-0 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",
|
||||
)}>
|
||||
<div className="flex flex-row self-center flex-wrap justify-between">
|
||||
<div className="flex-none flex flex-row items-center mr-3 py-1.5">
|
||||
<FiCpu className="text-theme-800 dark:text-theme-200 w-5 h-5" />
|
||||
|
@ -101,7 +94,10 @@ export default function Widget({ options }) {
|
|||
}
|
||||
|
||||
return (
|
||||
<a href={options.url} target={settings.target ?? "_blank"} className="flex flex-col max-w:full sm:basis-auto self-center grow-0 flex-wrap">
|
||||
<a href={options.url} target={settings.target ?? "_blank"} className={classNames(
|
||||
"flex flex-col max-w:full sm:basis-auto self-center grow-0 flex-wrap",
|
||||
options?.styleBoxed === true && " mb-0 mt-2 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",
|
||||
)}>
|
||||
<div className="flex flex-row self-center flex-wrap justify-between">
|
||||
<div className="flex-none flex flex-row items-center mr-3 py-1.5">
|
||||
<FiCpu className="text-theme-800 dark:text-theme-200 w-5 h-5" />
|
||||
|
@ -184,7 +180,7 @@ export default function Widget({ options }) {
|
|||
<div className="flex flex-col ml-3 text-left min-w-[85px]">
|
||||
<span className="text-theme-800 dark:text-theme-200 text-xs flex flex-row justify-between">
|
||||
<div className="pl-0.5">
|
||||
{t("common.number", {
|
||||
{t("common.number", {
|
||||
value: mainTemp,
|
||||
maximumFractionDigits: 1,
|
||||
style: "unit",
|
||||
|
@ -196,7 +192,7 @@ export default function Widget({ options }) {
|
|||
{options.expanded && (
|
||||
<span className="text-theme-800 dark:text-theme-200 text-xs flex flex-row justify-between">
|
||||
<div className="pl-0.5 pr-1">
|
||||
{t("common.number", {
|
||||
{t("common.number", {
|
||||
value: maxTemp,
|
||||
maximumFractionDigits: 1,
|
||||
style: "unit",
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import classNames from "classnames";
|
||||
|
||||
const textSizes = {
|
||||
"4xl": "text-4xl",
|
||||
"3xl": "text-3xl",
|
||||
|
@ -12,7 +14,10 @@ const textSizes = {
|
|||
export default function Greeting({ options }) {
|
||||
if (options.text) {
|
||||
return (
|
||||
<div className="flex flex-row items-center justify-start">
|
||||
<div className={classNames(
|
||||
"flex flex-row items-center justify-start",
|
||||
options?.styleBoxed === true && " 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-3",
|
||||
)}>
|
||||
<span className={`text-theme-800 dark:text-theme-200 mr-3 ${textSizes[options.text_size || "xl"]}`}>
|
||||
{options.text}
|
||||
</span>
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
import useSWR from "swr";
|
||||
import { BiError } from "react-icons/bi";
|
||||
import { useTranslation } from "next-i18next";
|
||||
import classNames from "classnames";
|
||||
|
||||
import Error from "../error";
|
||||
|
||||
import Node from "./node";
|
||||
|
||||
export default function Widget({ options }) {
|
||||
const { cluster, nodes } = options;
|
||||
const { t, i18n } = useTranslation();
|
||||
const { i18n } = useTranslation();
|
||||
|
||||
const defaultData = {
|
||||
cpu: {
|
||||
|
@ -29,23 +31,15 @@ export default function Widget({ options }) {
|
|||
);
|
||||
|
||||
if (error || data?.error) {
|
||||
return (
|
||||
<div className="flex flex-col justify-center first:ml-0 ml-4">
|
||||
<div className="flex flex-row items-center justify-end">
|
||||
<div className="flex flex-row items-center">
|
||||
<BiError className="w-8 h-8 text-theme-800 dark:text-theme-200" />
|
||||
<div className="flex flex-col ml-3 text-left">
|
||||
<span className="text-theme-800 dark:text-theme-200 text-sm">{t("widget.api_error")}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
return <Error options={options} />
|
||||
}
|
||||
|
||||
if (!data) {
|
||||
return (
|
||||
<div className="flex flex-col max-w:full sm:basis-auto self-center grow-0 flex-wrap">
|
||||
<div className={classNames(
|
||||
"flex flex-col max-w:full sm:basis-auto self-center grow-0 flex-wrap",
|
||||
options?.styleBoxed === true && " 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-3",
|
||||
)}>
|
||||
<div className="flex flex-row self-center flex-wrap justify-between">
|
||||
{cluster.show &&
|
||||
<Node type="cluster" key="cluster" options={options.cluster} data={defaultData} />
|
||||
|
@ -59,7 +53,10 @@ export default function Widget({ options }) {
|
|||
}
|
||||
|
||||
return (
|
||||
<div className="flex flex-col max-w:full sm:basis-auto self-center grow-0 flex-wrap">
|
||||
<div className={classNames(
|
||||
"flex flex-col max-w:full sm:basis-auto self-center grow-0 flex-wrap",
|
||||
options?.styleBoxed === true && " 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-3",
|
||||
)}>
|
||||
<div className="flex flex-row self-center flex-wrap justify-between">
|
||||
{cluster.show &&
|
||||
<Node key="cluster" type="cluster" options={options.cluster} data={data.cluster} />
|
||||
|
|
|
@ -1,8 +1,13 @@
|
|||
import classNames from "classnames";
|
||||
|
||||
import ResolvedIcon from "components/resolvedicon"
|
||||
|
||||
export default function Logo({ options }) {
|
||||
return (
|
||||
<div className="w-12 h-12 flex flex-row items-center align-middle mr-3 self-center">
|
||||
<div className={classNames(
|
||||
"w-12 h-12 flex flex-row items-center align-middle mr-3 self-center",
|
||||
options?.styleBoxed === true && " 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-3",
|
||||
)}>
|
||||
{options.icon ?
|
||||
<ResolvedIcon icon={options.icon} width={48} height={48} /> :
|
||||
// fallback to homepage logo
|
||||
|
|
|
@ -1,37 +1,36 @@
|
|||
import useSWR from "swr";
|
||||
import { BiError } from "react-icons/bi";
|
||||
import { useTranslation } from "next-i18next";
|
||||
import classNames from "classnames";
|
||||
|
||||
import Error from "../error";
|
||||
|
||||
import Node from "./node";
|
||||
|
||||
export default function Longhorn({ options }) {
|
||||
const { expanded, total, labels, include, nodes } = options;
|
||||
const { t } = useTranslation();
|
||||
const { data, error } = useSWR(`/api/widgets/longhorn`, {
|
||||
refreshInterval: 1500
|
||||
});
|
||||
|
||||
if (error || data?.error) {
|
||||
return (
|
||||
<div className="flex flex-col max-w:full sm:basis-auto self-center grow-0 flex-wrap">
|
||||
<BiError className="text-theme-800 dark:text-theme-200 w-5 h-5" />
|
||||
<div className="flex flex-col ml-3 text-left">
|
||||
<span className="text-theme-800 dark:text-theme-200 text-xs">{t("widget.api_error")}</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
return <Error options={options} />
|
||||
}
|
||||
|
||||
if (!data) {
|
||||
return (
|
||||
<div className="flex flex-col max-w:full sm:basis-auto self-center grow-0 flex-wrap">
|
||||
<div className={classNames(
|
||||
"flex flex-col max-w:full sm:basis-auto self-center grow-0 flex-wrap",
|
||||
options?.styleBoxed === true && " 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-3",
|
||||
)}>
|
||||
<div className="flex flex-row self-center flex-wrap justify-between" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex flex-col max-w:full sm:basis-auto self-center grow-0 flex-wrap">
|
||||
<div className={classNames(
|
||||
"flex flex-col max-w:full sm:basis-auto self-center grow-0 flex-wrap",
|
||||
options?.styleBoxed === true && " 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-3",
|
||||
)}>
|
||||
<div className="flex flex-row self-center flex-wrap justify-between">
|
||||
{data.nodes
|
||||
.filter((node) => {
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
import useSWR from "swr";
|
||||
import { useState } from "react";
|
||||
import { BiError } from "react-icons/bi";
|
||||
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 Icon from "./icon";
|
||||
|
||||
|
@ -15,24 +17,15 @@ function Widget({ options }) {
|
|||
);
|
||||
|
||||
if (error || data?.error) {
|
||||
return (
|
||||
<div className="flex flex-col justify-center first:ml-0 ml-4 mr-2">
|
||||
<div className="flex flex-row items-center justify-end">
|
||||
<div className="flex flex-col items-center">
|
||||
<BiError className="w-8 h-8 text-theme-800 dark:text-theme-200" />
|
||||
<div className="flex flex-col ml-3 text-left">
|
||||
<span className="text-theme-800 dark:text-theme-200 text-sm">{t("widget.api_error")}</span>
|
||||
<span className="text-theme-800 dark:text-theme-200 text-xs">-</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
return <Error options={options} />
|
||||
}
|
||||
|
||||
if (!data) {
|
||||
return (
|
||||
<div className="flex flex-col justify-center first:ml-0 ml-4 mr-2">
|
||||
<div className={classNames(
|
||||
"flex flex-col justify-center first:ml-0 ml-4 mr-2",
|
||||
options?.styleBoxed === true && " 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-3",
|
||||
)}>
|
||||
<div className="flex flex-row items-center justify-end">
|
||||
<div className="flex flex-col items-center">
|
||||
<WiCloudDown className="w-8 h-8 text-theme-800 dark:text-theme-200" />
|
||||
|
@ -50,7 +43,10 @@ function Widget({ options }) {
|
|||
const timeOfDay = data.current_weather.time > data.daily.sunrise[0] && data.current_weather.time < data.daily.sunset[0] ? "day" : "night";
|
||||
|
||||
return (
|
||||
<div className="flex flex-col justify-center first:ml-0 ml-4 mr-2">
|
||||
<div className={classNames(
|
||||
"flex flex-col justify-center first:ml-0 ml-4 mr-2",
|
||||
options?.styleBoxed === true && " 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-3",
|
||||
)}>
|
||||
<div className="flex flex-row items-center justify-end">
|
||||
<div className="flex flex-col items-center">
|
||||
<Icon condition={data.current_weather.weathercode} timeOfDay={timeOfDay} />
|
||||
|
@ -107,8 +103,10 @@ export default function OpenMeteo({ options }) {
|
|||
<button
|
||||
type="button"
|
||||
onClick={() => requestLocation()}
|
||||
className="flex flex-col justify-center first:ml-0 ml-4 mr-2"
|
||||
>
|
||||
className={classNames(
|
||||
"flex flex-col justify-center first:ml-0 ml-4 mr-2",
|
||||
options?.styleBoxed === true && " 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-3",
|
||||
)}>
|
||||
<div className="flex flex-row items-center justify-end">
|
||||
<div className="flex flex-col items-center">
|
||||
{requesting ? (
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
import useSWR from "swr";
|
||||
import { useState } from "react";
|
||||
import { BiError } from "react-icons/bi";
|
||||
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 Icon from "./icon";
|
||||
|
||||
|
@ -15,24 +17,15 @@ function Widget({ options }) {
|
|||
);
|
||||
|
||||
if (error || data?.cod === 401 || data?.error) {
|
||||
return (
|
||||
<div className="flex flex-col justify-center first:ml-auto ml-4 mr-2">
|
||||
<div className="flex flex-row items-center justify-end">
|
||||
<div className="hidden sm:flex flex-col items-center">
|
||||
<BiError className="w-8 h-8 text-theme-800 dark:text-theme-200" />
|
||||
<div className="flex flex-col ml-3 text-left">
|
||||
<span className="text-theme-800 dark:text-theme-200 text-sm">{t("widget.api_error")}</span>
|
||||
<span className="text-theme-800 dark:text-theme-200 text-xs">-</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
return <Error options={options} />
|
||||
}
|
||||
|
||||
if (!data) {
|
||||
return (
|
||||
<div className="flex flex-col justify-center first:ml-auto ml-4 mr-2">
|
||||
<div className={classNames(
|
||||
"flex flex-col justify-center first:ml-auto ml-4 mr-2",
|
||||
options?.styleBoxed === true && " 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-3",
|
||||
)}>
|
||||
<div className="flex flex-row items-center justify-end">
|
||||
<div className="hidden sm:flex flex-col items-center">
|
||||
<WiCloudDown className="w-8 h-8 text-theme-800 dark:text-theme-200" />
|
||||
|
@ -49,7 +42,10 @@ function Widget({ options }) {
|
|||
const unit = options.units === "metric" ? "celsius" : "fahrenheit";
|
||||
|
||||
return (
|
||||
<div className="flex flex-col justify-center first:ml-auto ml-2 mr-2">
|
||||
<div className={classNames(
|
||||
"flex flex-col justify-center first:ml-auto ml-2 mr-2",
|
||||
options?.styleBoxed === true && " 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-3",
|
||||
)}>
|
||||
<div className="flex flex-row items-center justify-end">
|
||||
<div className="hidden sm:flex flex-col items-center">
|
||||
<Icon
|
||||
|
@ -105,7 +101,10 @@ export default function OpenWeatherMap({ options }) {
|
|||
<button
|
||||
type="button"
|
||||
onClick={() => requestLocation()}
|
||||
className="flex flex-col justify-center first:ml-auto ml-4 mr-2"
|
||||
className={classNames(
|
||||
"flex flex-col justify-center first:ml-auto ml-4 mr-2",
|
||||
options?.styleBoxed === true && " 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-3",
|
||||
)}
|
||||
>
|
||||
<div className="flex flex-row items-center justify-end">
|
||||
<div className="hidden sm:flex flex-col items-center">
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import classNames from "classnames";
|
||||
|
||||
import Disk from "./disk";
|
||||
import Cpu from "./cpu";
|
||||
import Memory from "./memory";
|
||||
|
@ -7,7 +9,10 @@ import Uptime from "./uptime";
|
|||
export default function Resources({ options }) {
|
||||
const { expanded, units } = options;
|
||||
return (
|
||||
<div className="flex flex-col max-w:full sm:basis-auto self-center grow-0 flex-wrap">
|
||||
<div className={classNames(
|
||||
"flex flex-col max-w:full sm:basis-auto self-center grow-0 flex-wrap",
|
||||
options?.styleBoxed === true && " 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-3",
|
||||
)}>
|
||||
<div className="flex flex-row self-center flex-wrap justify-between">
|
||||
{options.cpu && <Cpu expanded={expanded} />}
|
||||
{options.memory && <Memory expanded={expanded} />}
|
||||
|
|
|
@ -76,7 +76,7 @@ export default function Search({ options }) {
|
|||
setSelectedProvider(storedProvider);
|
||||
}
|
||||
}, [availableProviderIds]);
|
||||
|
||||
|
||||
if (!availableProviderIds) {
|
||||
return null;
|
||||
}
|
||||
|
@ -102,7 +102,10 @@ export default function Search({ options }) {
|
|||
}
|
||||
|
||||
return (
|
||||
<form className="flex-col relative h-8 my-4 min-w-fit grow first:ml-0 ml-4" onSubmit={handleSubmit}>
|
||||
<form className={classNames(
|
||||
"flex-col relative h-8 my-4 min-w-fit grow first:ml-0 ml-4",
|
||||
options?.styleBoxed === true && " h-14 ml-4 mt-4 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-3",
|
||||
)} onSubmit={handleSubmit}>
|
||||
<div className="flex absolute inset-y-0 left-0 items-center pl-3 pointer-events-none w-full text-theme-800 dark:text-white" />
|
||||
<input
|
||||
type="text"
|
||||
|
@ -146,8 +149,8 @@ export default function Search({ options }) {
|
|||
leaveTo="transform opacity-0 scale-95"
|
||||
>
|
||||
<Listbox.Options
|
||||
className="absolute right-0 z-10 mt-1 origin-top-right rounded-md
|
||||
bg-theme-100 dark:bg-theme-600 shadow-lg
|
||||
className="absolute right-0 z-10 mt-1 origin-top-right rounded-md
|
||||
bg-theme-100 dark:bg-theme-600 shadow-lg
|
||||
ring-1 ring-black ring-opacity-5 focus:outline-none"
|
||||
>
|
||||
<div className="flex flex-col">
|
||||
|
|
|
@ -2,6 +2,9 @@ import { BiError, BiWifi, BiCheckCircle, BiXCircle, BiNetworkChart } from "react
|
|||
import { MdSettingsEthernet } from "react-icons/md";
|
||||
import { useTranslation } from "next-i18next";
|
||||
import { SiUbiquiti } from "react-icons/si";
|
||||
import classNames from "classnames";
|
||||
|
||||
import Error from "../error";
|
||||
|
||||
import useWidgetAPI from "utils/proxy/use-widget-api";
|
||||
|
||||
|
@ -13,25 +16,17 @@ export default function Widget({ options }) {
|
|||
const { data: statsData, error: statsError } = useWidgetAPI(options, "stat/sites", { index: options.index });
|
||||
|
||||
if (statsError) {
|
||||
return (
|
||||
<div className="flex flex-col justify-center first:ml-0 ml-4">
|
||||
<div className="flex flex-row items-center justify-end">
|
||||
<div className="flex flex-col items-center">
|
||||
<BiError className="w-8 h-8 text-theme-800 dark:text-theme-200" />
|
||||
<div className="flex flex-col ml-3 text-left">
|
||||
<span className="text-theme-800 dark:text-theme-200 text-sm">{t("widget.api_error")}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
return <Error options={options} />
|
||||
}
|
||||
|
||||
const defaultSite = options.site ? statsData?.data.find(s => s.desc === options.site) : statsData?.data?.find(s => s.name === "default");
|
||||
|
||||
if (!defaultSite) {
|
||||
return (
|
||||
<div className="flex flex-col justify-center first:ml-0 ml-4">
|
||||
<div className={classNames(
|
||||
"flex flex-col justify-center first:ml-0 ml-4",
|
||||
options?.styleBoxed === true && " 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-3",
|
||||
)}>
|
||||
<div className="flex flex-row items-center justify-end">
|
||||
<div className="flex flex-col items-center">
|
||||
<SiUbiquiti className="w-5 h-5 text-theme-800 dark:text-theme-200" />
|
||||
|
@ -57,7 +52,10 @@ export default function Widget({ options }) {
|
|||
const dataEmpty = !(wan.show || lan.show || wlan.show || uptime);
|
||||
|
||||
return (
|
||||
<div className="flex-none flex flex-row items-center mr-3 py-1.5">
|
||||
<div className={classNames(
|
||||
"flex-none flex flex-row items-center mr-3 py-1.5",
|
||||
options?.styleBoxed === true && " 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-3",
|
||||
)}>
|
||||
<div className="flex flex-col">
|
||||
<div className="flex flex-row ml-3 mb-0.5">
|
||||
<SiUbiquiti className="text-theme-800 dark:text-theme-200 w-3 h-3 mr-1" />
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
import useSWR from "swr";
|
||||
import { useState } from "react";
|
||||
import { BiError } from "react-icons/bi";
|
||||
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 Icon from "./icon";
|
||||
|
||||
|
@ -15,24 +17,15 @@ function Widget({ options }) {
|
|||
);
|
||||
|
||||
if (error || data?.error) {
|
||||
return (
|
||||
<div className="flex flex-col justify-center first:ml-0 ml-4 mr-2">
|
||||
<div className="flex flex-row items-center justify-end">
|
||||
<div className="flex flex-col items-center">
|
||||
<BiError className="w-8 h-8 text-theme-800 dark:text-theme-200" />
|
||||
<div className="flex flex-col ml-3 text-left">
|
||||
<span className="text-theme-800 dark:text-theme-200 text-sm">{t("widget.api_error")}</span>
|
||||
<span className="text-theme-800 dark:text-theme-200 text-xs">-</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
return <Error options={options} />
|
||||
}
|
||||
|
||||
if (!data) {
|
||||
return (
|
||||
<div className="flex flex-col justify-center first:ml-0 ml-4 mr-2">
|
||||
<div className={classNames(
|
||||
"flex flex-col justify-center first:ml-0 ml-4 mr-2",
|
||||
options?.styleBoxed === true && " 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-3",
|
||||
)}>
|
||||
<div className="flex flex-row items-center justify-end">
|
||||
<div className="flex flex-col items-center">
|
||||
<WiCloudDown className="w-8 h-8 text-theme-800 dark:text-theme-200" />
|
||||
|
@ -49,7 +42,10 @@ function Widget({ options }) {
|
|||
const unit = options.units === "metric" ? "celsius" : "fahrenheit";
|
||||
|
||||
return (
|
||||
<div className="flex flex-col justify-center first:ml-0 ml-4 mr-2">
|
||||
<div className={classNames(
|
||||
"flex flex-col justify-center first:ml-0 ml-4 mr-2",
|
||||
options?.styleBoxed === true && " 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-3",
|
||||
)}>
|
||||
<div className="flex flex-row items-center justify-end">
|
||||
<div className="flex flex-col items-center">
|
||||
<Icon condition={data.current.condition.code} timeOfDay={data.current.is_day ? "day" : "night"} />
|
||||
|
@ -106,7 +102,10 @@ export default function WeatherApi({ options }) {
|
|||
<button
|
||||
type="button"
|
||||
onClick={() => requestLocation()}
|
||||
className="flex flex-col justify-center first:ml-0 ml-4 mr-2"
|
||||
className={classNames(
|
||||
"flex flex-col justify-center first:ml-0 ml-4 mr-2",
|
||||
options?.styleBoxed === true && " 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-3",
|
||||
)}
|
||||
>
|
||||
<div className="flex flex-row items-center justify-end">
|
||||
<div className="flex flex-col items-center">
|
||||
|
|
|
@ -46,7 +46,7 @@ function parseLonghornData(data) {
|
|||
|
||||
export default async function handler(req, res) {
|
||||
const settings = getSettings();
|
||||
const longhornSettings = settings?.providers?.longhorn;
|
||||
const longhornSettings = settings?.providers?.longhorn || {};
|
||||
const {url, username, password} = longhornSettings;
|
||||
|
||||
if (!url) {
|
||||
|
|
Loading…
Add table
Reference in a new issue