mirror of
https://github.com/DI0IK/homepage-plus.git
synced 2025-07-09 06:48:47 +00:00
Custom JS and CSS (#1950)
* First commit for custom styles and JS * Adjusted classes * Added ids and classes for services and bookmarks * Apply suggestions from code review * Remove mime dependency * Update settings.json * Detect custom css / js changes, no refresh * Added preload to custom scripts and styles so they can load earlier * Added data attribute name for bookmarks too * Update [path].js * code style, revert some pointer changes --------- Co-authored-by: shamoon <4887959+shamoon@users.noreply.github.com>
This commit is contained in:
parent
0741ef0427
commit
b39c79bea1
46 changed files with 176 additions and 99 deletions
|
@ -30,7 +30,7 @@ export default function DateTime({ options }) {
|
|||
}, [date, setDate, dateLocale, format]);
|
||||
|
||||
return (
|
||||
<Container options={options}>
|
||||
<Container options={options} additionalClassNames="information-widget-datetime">
|
||||
<Raw>
|
||||
<div className="flex flex-row items-center grow justify-end">
|
||||
<span className={`text-theme-800 dark:text-theme-200 tabular-nums ${textSizes[textSize || "lg"]}`}>
|
||||
|
|
|
@ -3,6 +3,7 @@ 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 Error from "../widget/error";
|
||||
import Resource from "../widget/resource";
|
||||
|
@ -32,7 +33,7 @@ export default function Widget({ options }) {
|
|||
}
|
||||
|
||||
if (!data) {
|
||||
return <Resources options={options}>
|
||||
return <Resources options={options} additionalClassNames="information-widget-glances">
|
||||
{ options.cpu !== false && <Resource icon={FiCpu} label={t("glances.wait")} percentage="0" /> }
|
||||
{ options.mem !== false && <Resource icon={FaMemory} label={t("glances.wait")} percentage="0" /> }
|
||||
{ options.cputemp && <Resource icon={FaThermometerHalf} label={t("glances.wait")} percentage="0" /> }
|
||||
|
@ -69,8 +70,10 @@ export default function Widget({ options }) {
|
|||
: [data.fs.find((d) => d.mnt_point === options.disk)].filter((d) => d);
|
||||
}
|
||||
|
||||
const addedClasses = classNames('information-widget-glances', { 'expanded': options.expanded })
|
||||
|
||||
return (
|
||||
<Resources options={options} target={settings.target ?? "_blank"}>
|
||||
<Resources options={options} target={settings.target ?? "_blank"} additionalClassNames={addedClasses}>
|
||||
{options.cpu !== false && <Resource
|
||||
icon={FiCpu}
|
||||
value={t("common.number", {
|
||||
|
|
|
@ -14,7 +14,7 @@ const textSizes = {
|
|||
|
||||
export default function Greeting({ options }) {
|
||||
if (options.text) {
|
||||
return <Container options={options}>
|
||||
return <Container options={options} additionalClassNames="information-widget-greeting">
|
||||
<Raw>
|
||||
<span className={`text-theme-800 dark:text-theme-200 mr-3 ${textSizes[options.text_size || "xl"]}`}>
|
||||
{options.text}
|
||||
|
|
|
@ -36,7 +36,7 @@ export default function Widget({ options }) {
|
|||
}
|
||||
|
||||
if (!data) {
|
||||
return <Container options={options}>
|
||||
return <Container options={options} additionalClassNames="information-widget-kubernetes">
|
||||
<Raw>
|
||||
<div className="flex flex-row self-center flex-wrap justify-between">
|
||||
{cluster.show &&
|
||||
|
@ -50,7 +50,7 @@ export default function Widget({ options }) {
|
|||
</Container>;
|
||||
}
|
||||
|
||||
return <Container options={options}>
|
||||
return <Container options={options} additionalClassNames="information-widget-kubernetes">
|
||||
<Raw>
|
||||
<div className="flex flex-row self-center flex-wrap justify-between">
|
||||
{cluster.show &&
|
||||
|
|
|
@ -5,14 +5,14 @@ import ResolvedIcon from "components/resolvedicon"
|
|||
|
||||
export default function Logo({ options }) {
|
||||
return (
|
||||
<Container options={options}>
|
||||
<Container options={options} additionalClassNames={`information-widget-logo ${ options.icon ? 'resolved' : 'fallback'}`}>
|
||||
<Raw>
|
||||
{options.icon ?
|
||||
<div className="mr-3">
|
||||
<div className="resolved mr-3">
|
||||
<ResolvedIcon icon={options.icon} width={48} height={48} />
|
||||
</div> :
|
||||
// fallback to homepage logo
|
||||
<div className="w-12 h-12">
|
||||
<div className="fallback w-12 h-12">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 1024 1024"
|
||||
|
|
|
@ -17,14 +17,14 @@ export default function Longhorn({ options }) {
|
|||
}
|
||||
|
||||
if (!data) {
|
||||
return <Container options={options}>
|
||||
return <Container options={options} additionalClassNames="infomation-widget-longhorn">
|
||||
<Raw>
|
||||
<div className="flex flex-row self-center flex-wrap justify-between" />
|
||||
</Raw>
|
||||
</Container>;
|
||||
}
|
||||
|
||||
return <Container options={options}>
|
||||
return <Container options={options} additionalClassNames="infomation-widget-longhorn">
|
||||
<Raw>
|
||||
<div className="flex flex-row self-center flex-wrap justify-between">
|
||||
{data.nodes
|
||||
|
|
|
@ -8,6 +8,7 @@ export default function Node({ data, expanded, labels }) {
|
|||
const { t } = useTranslation();
|
||||
|
||||
return <Resource
|
||||
additionalClassNames="information-widget-longhorn-node"
|
||||
icon={FaThermometerHalf}
|
||||
value={t("common.bytes", { value: data.node.available })}
|
||||
label={t("resources.free")}
|
||||
|
|
|
@ -24,7 +24,7 @@ function Widget({ options }) {
|
|||
}
|
||||
|
||||
if (!data) {
|
||||
return <Container options={options}>
|
||||
return <Container options={options} additionalClassNames="information-widget-openmeteo">
|
||||
<PrimaryText>{t("weather.updating")}</PrimaryText>
|
||||
<SecondaryText>{t("weather.wait")}</SecondaryText>
|
||||
<WidgetIcon icon={WiCloudDown} size="l" />
|
||||
|
@ -35,7 +35,7 @@ function Widget({ options }) {
|
|||
const condition = data.current_weather.weathercode;
|
||||
const timeOfDay = data.current_weather.time > data.daily.sunrise[0] && data.current_weather.time < data.daily.sunset[0] ? "day" : "night";
|
||||
|
||||
return <Container options={options}>
|
||||
return <Container options={options} additionalClassNames="information-widget-openmeteo">
|
||||
<PrimaryText>
|
||||
{options.label && `${options.label}, `}
|
||||
{t("common.number", {
|
||||
|
@ -81,7 +81,7 @@ export default function OpenMeteo({ options }) {
|
|||
// if (!requesting && !location) requestLocation();
|
||||
|
||||
if (!location) {
|
||||
return <ContainerButton options={options} callback={requestLocation} >
|
||||
return <ContainerButton options={options} callback={requestLocation} additionalClassNames="information-widget-openmeteo-location-button">
|
||||
<PrimaryText>{t("weather.current")}</PrimaryText>
|
||||
<SecondaryText>{t("weather.allow")}</SecondaryText>
|
||||
<WidgetIcon icon={ requesting ? MdLocationSearching : MdLocationDisabled} size="m" pulse />
|
||||
|
|
|
@ -24,7 +24,7 @@ function Widget({ options }) {
|
|||
}
|
||||
|
||||
if (!data) {
|
||||
return <Container options={options}>
|
||||
return <Container options={options} additionalClassNames="information-widget-openweathermap">
|
||||
<PrimaryText>{t("weather.updating")}</PrimaryText>
|
||||
<SecondaryText>{t("weather.wait")}</SecondaryText>
|
||||
<WidgetIcon icon={WiCloudDown} size="l" />
|
||||
|
@ -36,7 +36,7 @@ function Widget({ options }) {
|
|||
const condition = data.weather[0].id;
|
||||
const timeOfDay = data.dt > data.sys.sunrise && data.dt < data.sys.sunset ? "day" : "night";
|
||||
|
||||
return <Container options={options}>
|
||||
return <Container options={options} additionalClassNames="information-widget-openweathermap">
|
||||
<PrimaryText>{options.label && `${options.label}, ` }{t("common.number", { value: data.main.temp, style: "unit", unit })}</PrimaryText>
|
||||
<SecondaryText>{data.weather[0].description}</SecondaryText>
|
||||
<WidgetIcon icon={mapIcon(condition, timeOfDay)} size="xl" />
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
export default function UsageBar({ percent }) {
|
||||
export default function UsageBar({ percent, additionalClassNames='' }) {
|
||||
return (
|
||||
<div className="mt-0.5 w-full bg-theme-800/30 rounded-full h-1 dark:bg-theme-200/20">
|
||||
<div className={`mt-0.5 w-full bg-theme-800/30 rounded-full h-1 dark:bg-theme-200/20 ${additionalClassNames}`}>
|
||||
<div
|
||||
className="bg-theme-800/70 h-1 rounded-full dark:bg-theme-200/50 transition-all duration-1000"
|
||||
style={{
|
||||
|
|
|
@ -103,7 +103,7 @@ export default function Search({ options }) {
|
|||
localStorage.setItem(localStorageKey, provider.name);
|
||||
}
|
||||
|
||||
return <ContainerForm options={options} callback={submitCallback} additionalClassNames="grow" >
|
||||
return <ContainerForm options={options} callback={submitCallback} additionalClassNames="grow information-widget-search" >
|
||||
<Raw>
|
||||
<div className="flex-col relative h-8 my-4 min-w-fit">
|
||||
<div className="flex absolute inset-y-0 left-0 items-center pl-3 pointer-events-none w-full text-theme-800 dark:text-white" />
|
||||
|
|
|
@ -25,7 +25,7 @@ export default function Widget({ options }) {
|
|||
const defaultSite = options.site ? statsData?.data.find(s => s.desc === options.site) : statsData?.data?.find(s => s.name === "default");
|
||||
|
||||
if (!defaultSite) {
|
||||
return <Container options={options}>
|
||||
return <Container options={options} additionalClassNames="information-widget-unifi-console">
|
||||
<PrimaryText>{t("unifi.wait")}</PrimaryText>
|
||||
<WidgetIcon icon={SiUbiquiti} />
|
||||
</Container>;
|
||||
|
@ -43,7 +43,7 @@ export default function Widget({ options }) {
|
|||
|
||||
const dataEmpty = !(wan.show || lan.show || wlan.show || uptime);
|
||||
|
||||
return <Container options={options}>
|
||||
return <Container options={options} additionalClassNames="information-widget-unifi-console">
|
||||
<Raw>
|
||||
<div className="flex-none flex flex-row items-center mr-3 py-1.5">
|
||||
<div className="flex flex-col">
|
||||
|
|
|
@ -24,7 +24,7 @@ function Widget({ options }) {
|
|||
}
|
||||
|
||||
if (!data) {
|
||||
return <Container options={options}>
|
||||
return <Container options={options} additionalClassNames="information-widget-weather">
|
||||
<PrimaryText>{t("weather.updating")}</PrimaryText>
|
||||
<SecondaryText>{t("weather.wait")}</SecondaryText>
|
||||
<WidgetIcon icon={WiCloudDown} size="l" />
|
||||
|
@ -35,7 +35,7 @@ function Widget({ options }) {
|
|||
const condition = data.current.condition.code;
|
||||
const timeOfDay = data.current.is_day ? "day" : "night";
|
||||
|
||||
return <Container options={options}>
|
||||
return <Container options={options} additionalClassNames="information-widget-weather">
|
||||
<PrimaryText>
|
||||
{options.label && `${options.label}, `}
|
||||
{t("common.number", {
|
||||
|
|
|
@ -35,9 +35,9 @@ export function getAllClasses(options, additionalClassNames = '') {
|
|||
|
||||
export function getInnerBlock(children) {
|
||||
// children won't be an array if it's Raw component
|
||||
return Array.isArray(children) && <div className="flex flex-row items-center justify-end">
|
||||
<div className="flex flex-col items-center">{children.find(child => child.type === WidgetIcon)}</div>
|
||||
<div className="flex flex-col ml-3 text-left">
|
||||
return Array.isArray(children) && <div className="flex flex-row items-center justify-end widget-inner">
|
||||
<div className="flex flex-col items-center widget-inner-icon">{children.find(child => child.type === WidgetIcon)}</div>
|
||||
<div className="flex flex-col ml-3 text-left widget-inner-text">
|
||||
{children.find(child => child.type === PrimaryText)}
|
||||
{children.find(child => child.type === SecondaryText)}
|
||||
</div>
|
||||
|
@ -54,7 +54,7 @@ export function getBottomBlock(children) {
|
|||
|
||||
export default function Container({ children = [], options, additionalClassNames = '' }) {
|
||||
return (
|
||||
<div className={getAllClasses(options, additionalClassNames)}>
|
||||
<div className={getAllClasses(options, `${ additionalClassNames } widget-container`)}>
|
||||
{getInnerBlock(children)}
|
||||
{getBottomBlock(children)}
|
||||
</div>
|
||||
|
|
|
@ -2,7 +2,7 @@ import { getAllClasses, getInnerBlock, getBottomBlock } from "./container";
|
|||
|
||||
export default function ContainerButton ({ children = [], options, additionalClassNames = '', callback }) {
|
||||
return (
|
||||
<button type="button" onClick={callback} className={getAllClasses(options, additionalClassNames)}>
|
||||
<button type="button" onClick={callback} className={`${ getAllClasses(options, additionalClassNames) } information-widget-container-button`}>
|
||||
{getInnerBlock(children)}
|
||||
{getBottomBlock(children)}
|
||||
</button>
|
||||
|
|
|
@ -2,7 +2,7 @@ import { getAllClasses, getInnerBlock, getBottomBlock } from "./container";
|
|||
|
||||
export default function ContainerForm ({ children = [], options, additionalClassNames = '', callback }) {
|
||||
return (
|
||||
<form type="button" onSubmit={callback} className={getAllClasses(options, additionalClassNames)}>
|
||||
<form type="button" onSubmit={callback} className={`${ getAllClasses(options, additionalClassNames) } information-widget-form`}>
|
||||
{getInnerBlock(children)}
|
||||
{getBottomBlock(children)}
|
||||
</form>
|
||||
|
|
|
@ -2,7 +2,7 @@ import { getAllClasses, getInnerBlock, getBottomBlock } from "./container";
|
|||
|
||||
export default function ContainerLink ({ children = [], options, additionalClassNames = '', target }) {
|
||||
return (
|
||||
<a href={options.url} target={target} className={getAllClasses(options, additionalClassNames)}>
|
||||
<a href={options.url} target={target} className={`${ getAllClasses(options, additionalClassNames) } information-widget-link`}>
|
||||
{getInnerBlock(children)}
|
||||
{getBottomBlock(children)}
|
||||
</a>
|
||||
|
|
|
@ -8,7 +8,7 @@ import WidgetIcon from "./widget_icon";
|
|||
export default function Error({ options }) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return <Container options={options}>
|
||||
return <Container options={options} additionalClassNames="information-widget-error">
|
||||
<PrimaryText>{t("widget.api_error")}</PrimaryText>
|
||||
<WidgetIcon icon={BiError} size="l" />
|
||||
</Container>;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
export default function PrimaryText({ children }) {
|
||||
return (
|
||||
<span className="text-theme-800 dark:text-theme-200 text-sm">{children}</span>
|
||||
<span className="primary-text text-theme-800 dark:text-theme-200 text-sm">{children}</span>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import UsageBar from "../resources/usage-bar";
|
||||
|
||||
export default function Resource({ children, icon, value, label, expandedValue = "", expandedLabel = "", percentage, expanded = false }) {
|
||||
export default function Resource({ children, icon, value, label, expandedValue = "", expandedLabel = "", percentage, expanded = false, additionalClassNames='' }) {
|
||||
const Icon = icon;
|
||||
|
||||
return <div className="flex-none flex flex-row items-center mr-3 py-1.5">
|
||||
<Icon className="text-theme-800 dark:text-theme-200 w-5 h-5"/>
|
||||
<div className="flex flex-col ml-3 text-left min-w-[85px]">
|
||||
return <div className={`flex-none flex flex-row items-center mr-3 py-1.5 information-widget-resource ${ additionalClassNames }`}>
|
||||
<Icon className="text-theme-800 dark:text-theme-200 w-5 h-5 resource-icon"/>
|
||||
<div className={ `flex flex-col ml-3 text-left min-w-[85px] ${ expanded ? ' expanded' : ''}`}>
|
||||
<div className="text-theme-800 dark:text-theme-200 text-xs flex flex-row justify-between">
|
||||
<div className="pl-0.5">{value}</div>
|
||||
<div className="pr-1">{label}</div>
|
||||
|
@ -15,7 +15,7 @@ export default function Resource({ children, icon, value, label, expandedValue =
|
|||
<div className="pr-1">{expandedLabel}</div>
|
||||
</div>
|
||||
}
|
||||
{ percentage >= 0 && <UsageBar percent={percentage} /> }
|
||||
{ percentage >= 0 && <UsageBar percent={percentage} additionalClassNames="resource-usage" /> }
|
||||
{ children }
|
||||
</div>
|
||||
</div>;
|
||||
|
|
|
@ -1,12 +1,15 @@
|
|||
import classNames from "classnames";
|
||||
|
||||
import ContainerLink from "./container_link";
|
||||
import Resource from "./resource";
|
||||
import Raw from "./raw";
|
||||
import WidgetLabel from "./widget_label";
|
||||
|
||||
export default function Resources({ options, children, target }) {
|
||||
export default function Resources({ options, children, target, additionalClassNames }) {
|
||||
const widgetParts = [].concat(...children);
|
||||
const addedClassNames = classNames('information-widget-resources', additionalClassNames);
|
||||
|
||||
return <ContainerLink options={options} target={target}>
|
||||
return <ContainerLink options={options} target={target} additionalClassNames={ addedClassNames }>
|
||||
<Raw>
|
||||
<div className="flex flex-row self-center flex-wrap justify-between">
|
||||
{ widgetParts.filter(child => child && child.type === Resource) }
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
export default function SecondaryText({ children }) {
|
||||
return (
|
||||
<span className="text-theme-800 dark:text-theme-200 text-xs">{children}</span>
|
||||
<span className="secondary-text text-theme-800 dark:text-theme-200 text-xs">{children}</span>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
export default function WidgetIcon({ icon, size = "s", pulse = false }) {
|
||||
const Icon = icon;
|
||||
let additionalClasses = "text-theme-800 dark:text-theme-200 ";
|
||||
let additionalClasses = "information-widget-icon text-theme-800 dark:text-theme-200 ";
|
||||
|
||||
switch (size) {
|
||||
case "m": additionalClasses += "w-6 h-6 "; break;
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
export default function WidgetLabel({ label = "" }) {
|
||||
return <div className="pt-1 text-center text-theme-800 dark:text-theme-200 text-xs">{label}</div>
|
||||
return <div className="information-widget-label pt-1 text-center text-theme-800 dark:text-theme-200 text-xs">{label}</div>
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue