Added ids and classes for services and bookmarks

This commit is contained in:
Yann Le Vagueres 2023-09-10 14:50:25 +02:00
parent a6d5530d6f
commit a30a4cab78
No known key found for this signature in database
GPG Key ID: EF41B255CD47BC5E
13 changed files with 56 additions and 49 deletions

View File

@ -13,6 +13,7 @@ export default function BookmarksGroup({ bookmarks, layout, disableCollapse }) {
<div <div
key={bookmarks.name} key={bookmarks.name}
className={classNames( className={classNames(
"bookmark-group",
layout?.style === "row" ? "basis-full" : "basis-full md:basis-1/4 lg:basis-1/5 xl:basis-1/6", layout?.style === "row" ? "basis-full" : "basis-full md:basis-1/4 lg:basis-1/5 xl:basis-1/6",
layout?.header === false ? "flex-1 px-1 -my-1" : "flex-1 p-1" layout?.header === false ? "flex-1 px-1 -my-1" : "flex-1 p-1"
)} )}
@ -23,11 +24,11 @@ export default function BookmarksGroup({ bookmarks, layout, disableCollapse }) {
{layout?.header !== false && ( {layout?.header !== false && (
<Disclosure.Button disabled={disableCollapse} className="flex w-full select-none items-center group"> <Disclosure.Button disabled={disableCollapse} className="flex w-full select-none items-center group">
{layout?.icon && ( {layout?.icon && (
<div className="flex-shrink-0 mr-2 w-7 h-7"> <div className="flex-shrink-0 mr-2 w-7 h-7 bookmark-group-icon">
<ResolvedIcon icon={layout.icon} /> <ResolvedIcon icon={layout.icon} />
</div> </div>
)} )}
<h2 className="text-theme-800 dark:text-theme-300 text-xl font-medium">{bookmarks.name}</h2> <h2 className="text-theme-800 dark:text-theme-300 text-xl font-medium bookmark-group-name">{bookmarks.name}</h2>
<MdKeyboardArrowDown <MdKeyboardArrowDown
className={classNames( className={classNames(
disableCollapse ? "hidden" : "", disableCollapse ? "hidden" : "",

View File

@ -9,7 +9,7 @@ export default function Item({ bookmark }) {
const { settings } = useContext(SettingsContext); const { settings } = useContext(SettingsContext);
return ( return (
<li key={bookmark.name}> <li key={bookmark.name} id={bookmark.id} className="bookmark">
<a <a
href={bookmark.href} href={bookmark.href}
title={bookmark.name} title={bookmark.name}
@ -20,7 +20,7 @@ export default function Item({ bookmark }) {
)} )}
> >
<div className="flex"> <div className="flex">
<div className="flex-shrink-0 flex items-center justify-center w-11 bg-theme-500/10 dark:bg-theme-900/50 text-theme-700 hover:text-theme-700 dark:text-theme-200 text-sm font-medium rounded-l-md"> <div className="flex-shrink-0 flex items-center justify-center w-11 bg-theme-500/10 dark:bg-theme-900/50 text-theme-700 hover:text-theme-700 dark:text-theme-200 text-sm font-medium rounded-l-md bookmark-icon">
{bookmark.icon && {bookmark.icon &&
<div className="flex-shrink-0 w-5 h-5"> <div className="flex-shrink-0 w-5 h-5">
<ResolvedIcon icon={bookmark.icon} alt={bookmark.abbr} /> <ResolvedIcon icon={bookmark.icon} alt={bookmark.abbr} />
@ -28,9 +28,9 @@ export default function Item({ bookmark }) {
} }
{!bookmark.icon && bookmark.abbr} {!bookmark.icon && bookmark.abbr}
</div> </div>
<div className="flex-1 flex items-center justify-between rounded-r-md"> <div className="flex-1 flex items-center justify-between rounded-r-md bookmark-text">
<div className="flex-1 grow pl-3 py-2 text-xs">{bookmark.name}</div> <div className="flex-1 grow pl-3 py-2 text-xs bookmark-name">{bookmark.name}</div>
<div className="px-2 py-2 truncate text-theme-500 dark:text-theme-300 text-xs">{hostname}</div> <div className="px-2 py-2 truncate text-theme-500 dark:text-theme-300 text-xs bookmark-hostname">{hostname}</div>
</div> </div>
</div> </div>
</a> </a>

View File

@ -9,7 +9,7 @@ export default function List({ bookmarks, layout }) {
<ul <ul
className={classNames( className={classNames(
layout?.style === "row" ? `grid ${columnMap[layout?.columns]} gap-x-2` : "flex flex-col", layout?.style === "row" ? `grid ${columnMap[layout?.columns]} gap-x-2` : "flex flex-col",
"mt-3" "mt-3 bookmark-list"
)} )}
> >
{bookmarks.map((bookmark) => ( {bookmarks.map((bookmark) => (

View File

@ -14,6 +14,7 @@ export default function ServicesGroup({ group, services, layout, fiveColumns, di
<div <div
key={services.name} key={services.name}
className={classNames( className={classNames(
"services-group",
layout?.style === "row" ? "basis-full" : "basis-full md:basis-1/2 lg:basis-1/3 xl:basis-1/4", layout?.style === "row" ? "basis-full" : "basis-full md:basis-1/2 lg:basis-1/3 xl:basis-1/4",
layout?.style !== "row" && fiveColumns ? "3xl:basis-1/5" : "", layout?.style !== "row" && fiveColumns ? "3xl:basis-1/5" : "",
layout?.header === false ? "flex-1 px-1 -my-1" : "flex-1 p-1", layout?.header === false ? "flex-1 px-1 -my-1" : "flex-1 p-1",
@ -25,11 +26,11 @@ export default function ServicesGroup({ group, services, layout, fiveColumns, di
{ layout?.header !== false && { layout?.header !== false &&
<Disclosure.Button disabled={disableCollapse} className="flex w-full select-none items-center group"> <Disclosure.Button disabled={disableCollapse} className="flex w-full select-none items-center group">
{layout?.icon && {layout?.icon &&
<div className="flex-shrink-0 mr-2 w-7 h-7"> <div className="flex-shrink-0 mr-2 w-7 h-7 service-group-icon">
<ResolvedIcon icon={layout.icon} /> <ResolvedIcon icon={layout.icon} />
</div> </div>
} }
<h2 className="flex text-theme-800 dark:text-theme-300 text-xl font-medium">{services.name}</h2> <h2 className="flex text-theme-800 dark:text-theme-300 text-xl font-medium service-group-name">{services.name}</h2>
<MdKeyboardArrowDown className={classNames( <MdKeyboardArrowDown className={classNames(
disableCollapse ? 'hidden' : '', disableCollapse ? 'hidden' : '',
'transition-all opacity-0 group-hover:opacity-100 ml-auto text-theme-800 dark:text-theme-300 text-xl', 'transition-all opacity-0 group-hover:opacity-100 ml-auto text-theme-800 dark:text-theme-300 text-xl',

View File

@ -29,28 +29,30 @@ export default function Item({ service, group }) {
} }
}; };
return ( return (
<li key={service.name}> <li key={service.name} id={service.id} className="service" data-name={service.name || ""}>
<div <div
className={classNames( className={classNames(
settings.cardBlur !== undefined && `backdrop-blur${settings.cardBlur.length ? '-' : ""}${settings.cardBlur}`, settings.cardBlur !== undefined && `backdrop-blur${settings.cardBlur.length ? '-' : ""}${settings.cardBlur}`,
hasLink && "cursor-pointer", 'transition-all h-15 mb-2 p-1 rounded-md font-medium text-theme-700 dark:text-theme-200 dark:hover:text-theme-300 shadow-md shadow-theme-900/10 dark:shadow-theme-900/20 bg-theme-100/20 hover:bg-theme-300/20 dark:bg-white/5 dark:hover:bg-white/10 relative overflow-clip',
'transition-all h-15 mb-2 p-1 rounded-md font-medium text-theme-700 dark:text-theme-200 dark:hover:text-theme-300 shadow-md shadow-theme-900/10 dark:shadow-theme-900/20 bg-theme-100/20 hover:bg-theme-300/20 dark:bg-white/5 dark:hover:bg-white/10 relative overflow-clip' 'service-card'
)} )}
> >
<div className="flex select-none z-0"> <div className="flex select-none z-0 service-title">
{service.icon && {service.icon &&
(hasLink ? ( (hasLink ? (
<a <a
href={service.href} href={service.href}
target={service.target ?? settings.target ?? "_blank"} target={service.target ?? settings.target ?? "_blank"}
rel="noreferrer" rel="noreferrer"
className="flex-shrink-0 flex items-center justify-center w-12 " className="flex-shrink-0 flex items-center justify-center w-12 service-icon"
> >
<ResolvedIcon icon={service.icon} /> <ResolvedIcon icon={service.icon} />
</a> </a>
) : ( ) : (
<div className="flex-shrink-0 flex items-center justify-center w-12 "> <div className="flex-shrink-0 flex items-center justify-center w-12 service-icon">
<ResolvedIcon icon={service.icon} /> <ResolvedIcon icon={service.icon} />
</div> </div>
))} ))}
@ -60,25 +62,25 @@ export default function Item({ service, group }) {
href={service.href} href={service.href}
target={service.target ?? settings.target ?? "_blank"} target={service.target ?? settings.target ?? "_blank"}
rel="noreferrer" rel="noreferrer"
className="flex-1 flex items-center justify-between rounded-r-md " className="flex-1 flex items-center justify-between rounded-r-md service-title-text"
> >
<div className="flex-1 px-2 py-2 text-sm text-left z-10"> <div className="flex-1 px-2 py-2 text-sm text-left z-10 service-name">
{service.name} {service.name}
<p className="text-theme-500 dark:text-theme-300 text-xs font-light">{service.description}</p> <p className="text-theme-500 dark:text-theme-300 text-xs font-light service-description">{service.description}</p>
</div> </div>
</a> </a>
) : ( ) : (
<div className="flex-1 flex items-center justify-between rounded-r-md "> <div className="flex-1 flex items-center justify-between rounded-r-md service-title-text">
<div className="flex-1 px-2 py-2 text-sm text-left z-10"> <div className="flex-1 px-2 py-2 text-sm text-left z-10 service-name">
{service.name} {service.name}
<p className="text-theme-500 dark:text-theme-300 text-xs font-light">{service.description}</p> <p className="text-theme-500 dark:text-theme-300 text-xs font-light service-description">{service.description}</p>
</div> </div>
</div> </div>
)} )}
<div className="absolute top-0 right-0 w-1/2 flex flex-row justify-end gap-2 mr-2 z-30 pointer-events-none"> <div className="absolute top-0 right-0 flex flex-row justify-end gap-2 mr-2 z-30 pointer-events-none service-tags">
{service.ping && ( {service.ping && (
<div className="flex-shrink-0 flex items-center justify-center cursor-pointer"> <div className="flex-shrink-0 flex items-center justify-center service-tag service-ping">
<Ping group={group} service={service.name} /> <Ping group={group} service={service.name} />
<span className="sr-only">Ping status</span> <span className="sr-only">Ping status</span>
</div> </div>
@ -88,7 +90,7 @@ export default function Item({ service, group }) {
<button <button
type="button" type="button"
onClick={() => (statsOpen ? closeStats() : setStatsOpen(true))} onClick={() => (statsOpen ? closeStats() : setStatsOpen(true))}
className="flex-shrink-0 flex items-center justify-center cursor-pointer" className="flex-shrink-0 flex items-center justify-center cursor-pointer pointer-events-auto service-tag service-container-stats"
> >
<Status service={service} /> <Status service={service} />
<span className="sr-only">View container stats</span> <span className="sr-only">View container stats</span>
@ -98,7 +100,7 @@ export default function Item({ service, group }) {
<button <button
type="button" type="button"
onClick={() => (statsOpen ? closeStats() : setStatsOpen(true))} onClick={() => (statsOpen ? closeStats() : setStatsOpen(true))}
className="flex-shrink-0 flex items-center justify-center cursor-pointer" className="flex-shrink-0 flex items-center justify-center cursor-pointer pointer-events-auto service-tag service-app"
> >
<KubernetesStatus service={service} /> <KubernetesStatus service={service} />
<span className="sr-only">View container stats</span> <span className="sr-only">View container stats</span>
@ -111,7 +113,8 @@ export default function Item({ service, group }) {
<div <div
className={classNames( className={classNames(
showStats || (statsOpen && !statsClosing) ? "max-h-[110px] opacity-100" : " max-h-[0] opacity-0", showStats || (statsOpen && !statsClosing) ? "max-h-[110px] opacity-100" : " max-h-[0] opacity-0",
"w-full overflow-hidden transition-all duration-300 ease-in-out" "w-full overflow-hidden transition-all duration-300 ease-in-out",
"service-stats"
)} )}
> >
{(showStats || statsOpen) && <Docker service={{ widget: { container: service.container, server: service.server } }} />} {(showStats || statsOpen) && <Docker service={{ widget: { container: service.container, server: service.server } }} />}
@ -121,7 +124,8 @@ export default function Item({ service, group }) {
<div <div
className={classNames( className={classNames(
showStats || (statsOpen && !statsClosing) ? "max-h-[55px] opacity-100" : " max-h-[0] opacity-0", showStats || (statsOpen && !statsClosing) ? "max-h-[55px] opacity-100" : " max-h-[0] opacity-0",
"w-full overflow-hidden transition-all duration-300 ease-in-out" "w-full overflow-hidden transition-all duration-300 ease-in-out",
"service-stats"
)} )}
> >
{(showStats || statsOpen) && <Kubernetes service={{ widget: { namespace: service.namespace, app: service.app, podSelector: service.podSelector } }} />} {(showStats || statsOpen) && <Kubernetes service={{ widget: { namespace: service.namespace, app: service.app, podSelector: service.podSelector } }} />}

View File

@ -6,14 +6,14 @@ export default function KubernetesStatus({ service }) {
const { data, error } = useSWR(`/api/kubernetes/status/${service.namespace}/${service.app}?${podSelectorString}`); const { data, error } = useSWR(`/api/kubernetes/status/${service.namespace}/${service.app}?${podSelectorString}`);
if (error) { if (error) {
<div className="w-auto px-1.5 py-0.5 text-center bg-theme-500/10 dark:bg-theme-900/50 rounded-b-[3px] overflow-hidden" title={t("docker.error")}> <div className="w-auto px-1.5 py-0.5 text-center bg-theme-500/10 dark:bg-theme-900/50 rounded-b-[3px] overflow-hidden k8s-status-error" title={t("docker.error")}>
<div className="text-[8px] font-bold text-rose-500/80 uppercase">{t("docker.error")}</div> <div className="text-[8px] font-bold text-rose-500/80 uppercase">{t("docker.error")}</div>
</div> </div>
} }
if (data && data.status === "running") { if (data && data.status === "running") {
return ( return (
<div className="w-auto px-1.5 py-0.5 text-center bg-theme-500/10 dark:bg-theme-900/50 rounded-b-[3px] overflow-hidden" title={data.health ?? data.status}> <div className="w-auto px-1.5 py-0.5 text-center bg-theme-500/10 dark:bg-theme-900/50 rounded-b-[3px] overflow-hidden k8s-status" title={data.health ?? data.status}>
<div className="text-[8px] font-bold text-emerald-500/80 uppercase">{data.health ?? data.status}</div> <div className="text-[8px] font-bold text-emerald-500/80 uppercase">{data.health ?? data.status}</div>
</div> </div>
); );
@ -21,14 +21,14 @@ export default function KubernetesStatus({ service }) {
if (data && (data.status === "not found" || data.status === "down" || data.status === "partial")) { if (data && (data.status === "not found" || data.status === "down" || data.status === "partial")) {
return ( return (
<div className="w-auto px-1.5 py-0.5 text-center bg-theme-500/10 dark:bg-theme-900/50 rounded-b-[3px] overflow-hidden" title={data.status}> <div className="w-auto px-1.5 py-0.5 text-center bg-theme-500/10 dark:bg-theme-900/50 rounded-b-[3px] overflow-hidden k8s-status-warning" title={data.status}>
<div className="text-[8px] font-bold text-orange-400/50 dark:text-orange-400/80 uppercase">{data.status}</div> <div className="text-[8px] font-bold text-orange-400/50 dark:text-orange-400/80 uppercase">{data.status}</div>
</div> </div>
); );
} }
return ( return (
<div className="w-auto px-1.5 py-0.5 text-center bg-theme-500/10 dark:bg-theme-900/50 rounded-b-[3px] overflow-hidden"> <div className="w-auto px-1.5 py-0.5 text-center bg-theme-500/10 dark:bg-theme-900/50 rounded-b-[3px] overflow-hidden k8s-status-unknown">
<div className="text-[8px] font-bold text-black/20 dark:text-white/40 uppercase">{t("docker.unknown")}</div> <div className="text-[8px] font-bold text-black/20 dark:text-white/40 uppercase">{t("docker.unknown")}</div>
</div> </div>
); );

View File

@ -9,7 +9,7 @@ export default function List({ group, services, layout }) {
<ul <ul
className={classNames( className={classNames(
layout?.style === "row" ? `grid ${columnMap[layout?.columns]} gap-x-2` : "flex flex-col", layout?.style === "row" ? `grid ${columnMap[layout?.columns]} gap-x-2` : "flex flex-col",
"mt-3" "mt-3 services-list"
)} )}
> >
{services.map((service) => ( {services.map((service) => (

View File

@ -9,7 +9,7 @@ export default function Ping({ group, service }) {
if (error) { if (error) {
return ( return (
<div className="w-auto px-1.5 py-0.5 text-center bg-theme-500/10 dark:bg-theme-900/50 rounded-b-[3px] overflow-hidden"> <div className="w-auto px-1.5 py-0.5 text-center bg-theme-500/10 dark:bg-theme-900/50 rounded-b-[3px] overflow-hidden ping-error">
<div className="text-[8px] font-bold text-rose-500 uppercase">{t("ping.error")}</div> <div className="text-[8px] font-bold text-rose-500 uppercase">{t("ping.error")}</div>
</div> </div>
); );
@ -17,7 +17,7 @@ export default function Ping({ group, service }) {
if (!data) { if (!data) {
return ( return (
<div className="w-auto px-1.5 py-0.5 text-center bg-theme-500/10 dark:bg-theme-900/50 rounded-b-[3px] overflow-hidden"> <div className="w-auto px-1.5 py-0.5 text-center bg-theme-500/10 dark:bg-theme-900/50 rounded-b-[3px] overflow-hidden ping-ping">
<div className="text-[8px] font-bold text-black/20 dark:text-white/40 uppercase">{t("ping.ping")}</div> <div className="text-[8px] font-bold text-black/20 dark:text-white/40 uppercase">{t("ping.ping")}</div>
</div> </div>
); );
@ -27,14 +27,14 @@ export default function Ping({ group, service }) {
if (data.status > 403) { if (data.status > 403) {
return ( return (
<div className="w-auto px-1.5 py-0.5 text-center bg-theme-500/10 dark:bg-theme-900/50 rounded-b-[3px] overflow-hidden" title={statusText}> <div className="w-auto px-1.5 py-0.5 text-center bg-theme-500/10 dark:bg-theme-900/50 rounded-b-[3px] overflow-hidden ping-status-invalid" title={statusText}>
<div className="text-[8px] font-bold text-rose-500/80">{data.status}</div> <div className="text-[8px] font-bold text-rose-500/80">{data.status}</div>
</div> </div>
); );
} }
return ( return (
<div className="w-auto px-1.5 py-0.5 text-center bg-theme-500/10 dark:bg-theme-900/50 rounded-b-[3px] overflow-hidden" title={statusText}> <div className="w-auto px-1.5 py-0.5 text-center bg-theme-500/10 dark:bg-theme-900/50 rounded-b-[3px] overflow-hidden ping-status-valid" title={statusText}>
<div className="text-[8px] font-bold text-emerald-500/80">{t("common.ms", { value: data.latency, style: "unit", unit: "millisecond", maximumFractionDigits: 0 })}</div> <div className="text-[8px] font-bold text-emerald-500/80">{t("common.ms", { value: data.latency, style: "unit", unit: "millisecond", maximumFractionDigits: 0 })}</div>
</div> </div>
); );

View File

@ -7,7 +7,7 @@ export default function Status({ service }) {
const { data, error } = useSWR(`/api/docker/status/${service.container}/${service.server || ""}`); const { data, error } = useSWR(`/api/docker/status/${service.container}/${service.server || ""}`);
if (error) { if (error) {
<div className="w-auto px-1.5 py-0.5 text-center bg-theme-500/10 dark:bg-theme-900/50 rounded-b-[3px] overflow-hidden" title={t("docker.error")}> <div className="w-auto px-1.5 py-0.5 text-center bg-theme-500/10 dark:bg-theme-900/50 rounded-b-[3px] overflow-hidden docker-error" title={t("docker.error")}>
<div className="text-[8px] font-bold text-rose-500/80 uppercase">{t("docker.error")}</div> <div className="text-[8px] font-bold text-rose-500/80 uppercase">{t("docker.error")}</div>
</div> </div>
} }
@ -18,7 +18,7 @@ export default function Status({ service }) {
if (data.status?.includes("running")) { if (data.status?.includes("running")) {
if (data.health === "starting") { if (data.health === "starting") {
return ( return (
<div className="w-auto px-1.5 py-0.5 text-center bg-theme-500/10 dark:bg-theme-900/50 rounded-b-[3px] overflow-hidden" title={t("docker.starting")}> <div className="w-auto px-1.5 py-0.5 text-center bg-theme-500/10 dark:bg-theme-900/50 rounded-b-[3px] overflow-hidden docker-starting" title={t("docker.starting")}>
<div className="text-[8px] font-bold text-blue-500/80 uppercase">{t("docker.starting")}</div> <div className="text-[8px] font-bold text-blue-500/80 uppercase">{t("docker.starting")}</div>
</div> </div>
); );
@ -26,7 +26,7 @@ export default function Status({ service }) {
if (data.health === "unhealthy") { if (data.health === "unhealthy") {
return ( return (
<div className="w-auto px-1.5 py-0.5 text-center bg-theme-500/10 dark:bg-theme-900/50 rounded-b-[3px] overflow-hidden" title={t("docker.unhealthy")}> <div className="w-auto px-1.5 py-0.5 text-center bg-theme-500/10 dark:bg-theme-900/50 rounded-b-[3px] overflow-hidden docker-unhealthy" title={t("docker.unhealthy")}>
<div className="text-[8px] font-bold text-orange-400/50 dark:text-orange-400/80 uppercase">{t("docker.unhealthy")}</div> <div className="text-[8px] font-bold text-orange-400/50 dark:text-orange-400/80 uppercase">{t("docker.unhealthy")}</div>
</div> </div>
); );
@ -39,7 +39,7 @@ export default function Status({ service }) {
} }
return ( return (
<div className="w-auto px-1.5 py-0.5 text-center bg-theme-500/10 dark:bg-theme-900/50 rounded-b-[3px] overflow-hidden" title={statusLabel}> <div className="w-auto px-1.5 py-0.5 text-center bg-theme-500/10 dark:bg-theme-900/50 rounded-b-[3px] overflow-hidden docker-status" title={statusLabel}>
<div className="text-[8px] font-bold text-emerald-500/80 uppercase">{statusLabel}</div> <div className="text-[8px] font-bold text-emerald-500/80 uppercase">{statusLabel}</div>
</div> </div>
); );
@ -50,7 +50,7 @@ export default function Status({ service }) {
else if (data.status === "exited") statusLabel = t("docker.exited") else if (data.status === "exited") statusLabel = t("docker.exited")
else statusLabel = data.status.replace("partial", t("docker.partial")) else statusLabel = data.status.replace("partial", t("docker.partial"))
return ( return (
<div className="w-auto px-1.5 py-0.5 text-center bg-theme-500/10 dark:bg-theme-900/50 rounded-b-[3px] overflow-hidden" title={statusLabel}> <div className="w-auto px-1.5 py-0.5 text-center bg-theme-500/10 dark:bg-theme-900/50 rounded-b-[3px] overflow-hidden docker-status-warning" title={statusLabel}>
<div className="text-[8px] font-bold text-orange-400/50 dark:text-orange-400/80 uppercase">{statusLabel}</div> <div className="text-[8px] font-bold text-orange-400/50 dark:text-orange-400/80 uppercase">{statusLabel}</div>
</div> </div>
); );
@ -58,7 +58,7 @@ export default function Status({ service }) {
} }
return ( return (
<div className="w-auto px-1.5 py-0.5 text-center bg-theme-500/10 dark:bg-theme-900/50 rounded-b-[3px] overflow-hidden"> <div className="w-auto px-1.5 py-0.5 text-center bg-theme-500/10 dark:bg-theme-900/50 rounded-b-[3px] overflow-hidden docker-status-unknown">
<div className="text-[8px] font-bold text-black/20 dark:text-white/40 uppercase">{t("docker.unknown")}</div> <div className="text-[8px] font-bold text-black/20 dark:text-white/40 uppercase">{t("docker.unknown")}</div>
</div> </div>
); );

View File

@ -17,7 +17,7 @@ export default function Widget({ service }) {
} }
return ( return (
<div className="bg-theme-200/50 dark:bg-theme-900/20 rounded m-1 flex-1 flex flex-col items-center justify-center p-1"> <div className="bg-theme-200/50 dark:bg-theme-900/20 rounded m-1 flex-1 flex flex-col items-center justify-center p-1 service-missing">
<div className="font-thin text-sm">{t("widget.missing_type", { type: service.widget.type })}</div> <div className="font-thin text-sm">{t("widget.missing_type", { type: service.widget.type })}</div>
</div> </div>
); );

View File

@ -8,7 +8,8 @@ export default function Block({ value, label }) {
<div <div
className={classNames( className={classNames(
"bg-theme-200/50 dark:bg-theme-900/20 rounded m-1 flex-1 flex flex-col items-center justify-center text-center p-1", "bg-theme-200/50 dark:bg-theme-900/20 rounded m-1 flex-1 flex flex-col items-center justify-center text-center p-1",
value === undefined ? "animate-pulse" : "" value === undefined ? "animate-pulse" : "",
"service-block"
)} )}
> >
<div className="font-thin text-sm">{value === undefined || value === null ? "-" : value}</div> <div className="font-thin text-sm">{value === undefined || value === null ? "-" : value}</div>

View File

@ -36,5 +36,5 @@ export default function Container({ error = false, children, service }) {
})); }));
} }
return <div className="relative flex flex-row w-full">{visibleChildren}</div>; return <div className="relative flex flex-row w-full service-container">{visibleChildren}</div>;
} }

View File

@ -240,7 +240,7 @@ function Home({ initialSettings }) {
const bookmarkGroups = bookmarks.filter(group => settings.layout?.[group.name] === undefined); const bookmarkGroups = bookmarks.filter(group => settings.layout?.[group.name] === undefined);
return <> return <>
{layoutGroups.length > 0 && <div key="layoutGroups" className="flex flex-wrap p-4 sm:p-8 sm:pt-4 items-start pb-2"> {layoutGroups.length > 0 && <div key="layoutGroups" id="layout-groups" className="flex flex-wrap p-4 sm:p-8 sm:pt-4 items-start pb-2">
{layoutGroups.map((group) => ( {layoutGroups.map((group) => (
group.services ? group.services ?
(<ServicesGroup (<ServicesGroup
@ -260,7 +260,7 @@ function Home({ initialSettings }) {
) )
)} )}
</div>} </div>}
{serviceGroups?.length > 0 && <div key="services" className="flex flex-wrap p-4 sm:p-8 sm:pt-4 items-start pb-2"> {serviceGroups?.length > 0 && <div key="services" id="services" className="flex flex-wrap p-4 sm:p-8 sm:pt-4 items-start pb-2">
{serviceGroups.map((group) => ( {serviceGroups.map((group) => (
<ServicesGroup <ServicesGroup
key={group.name} key={group.name}
@ -272,7 +272,7 @@ function Home({ initialSettings }) {
/> />
))} ))}
</div>} </div>}
{bookmarkGroups?.length > 0 && <div key="bookmarks" className="flex flex-wrap p-4 sm:p-8 sm:pt-4 items-start pb-2"> {bookmarkGroups?.length > 0 && <div key="bookmarks" id="bookmarks" className="flex flex-wrap p-4 sm:p-8 sm:pt-4 items-start pb-2">
{bookmarkGroups.map((group) => ( {bookmarkGroups.map((group) => (
<BookmarksGroup <BookmarksGroup
key={group.name} key={group.name}