mirror of
				https://github.com/karl0ss/homepage.git
				synced 2025-10-31 06:24:02 +00:00 
			
		
		
		
	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
							
								
									caa1b94fd6
								
							
						
					
					
						commit
						c79d45f91e
					
				| @ -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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Denis Papec
						Denis Papec