Files
homarr/packages/widgets/src/app/component.tsx
T
Meier Lukas ce1ef3cbe7 feat: add improved search (#1051)
* feat: add improved search

* wip: add support for sorting, rename use-options to use-query-options, add use-options for local usage, add pages search group

* feat: add help links from manage layout to help search mode

* feat: add additional search engines

* feat: add group search details

* refactor: improve users search group type

* feat: add apps search group, add disabled search interaction

* feat: add integrations and boards for search

* wip: hook issue with react

* fix: hook issue regarding actions and interactions

* chore: address pull request feedback

* fix: format issues

* feat: add additional global actions to search

* chore: remove unused code

* fix: search engine short key

* fix: typecheck issues

* fix: deepsource issues

* fix: eslint issue

* fix: lint issues

* fix: unordered dependencies

* chore: address pull request feedback
2024-09-20 16:51:42 +02:00

88 lines
2.5 KiB
TypeScript

"use client";
import type { PropsWithChildren } from "react";
import { Suspense } from "react";
import { Flex, Text, Tooltip, UnstyledButton } from "@mantine/core";
import combineClasses from "clsx";
import { clientApi } from "@homarr/api/client";
import { parseAppHrefWithVariablesClient } from "@homarr/common/client";
import { useI18n } from "@homarr/translation/client";
import type { WidgetComponentProps } from "../definition";
import classes from "./app.module.css";
import { PingDot } from "./ping/ping-dot";
import { PingIndicator } from "./ping/ping-indicator";
export default function AppWidget({ options, isEditMode }: WidgetComponentProps<"app">) {
const t = useI18n();
const [app] = clientApi.app.byId.useSuspenseQuery(
{
id: options.appId,
},
{
refetchOnMount: false,
refetchOnWindowFocus: false,
refetchOnReconnect: false,
retry: false,
},
);
return (
<AppLink
href={parseAppHrefWithVariablesClient(app.href ?? "")}
openInNewTab={options.openInNewTab}
enabled={Boolean(app.href) && !isEditMode}
>
<Tooltip.Floating
label={app.description}
position="right-start"
multiline
disabled={!options.showDescriptionTooltip || !app.description}
styles={{ tooltip: { maxWidth: 300 } }}
>
<Flex
className={combineClasses("app-flex-wrapper", app.name, app.id)}
h="100%"
w="100%"
direction="column"
p="7.5cqmin"
justify="center"
align="center"
>
{options.showTitle && (
<Text className="app-title" fw={700} ta="center" size="12.5cqmin">
{app.name}
</Text>
)}
<img src={app.iconUrl} alt={app.name} className={combineClasses(classes.appIcon, "app-icon")} />
</Flex>
</Tooltip.Floating>
{options.pingEnabled && app.href ? (
<Suspense
fallback={
<PingDot color="blue" tooltip={t("common.rtl", { symbol: "…", value: t("common.action.loading") })} />
}
>
<PingIndicator href={app.href} />
</Suspense>
) : null}
</AppLink>
);
}
interface AppLinkProps {
href: string;
openInNewTab: boolean;
enabled: boolean;
}
const AppLink = ({ href, openInNewTab, enabled, children }: PropsWithChildren<AppLinkProps>) =>
enabled ? (
<UnstyledButton component="a" href={href} target={openInNewTab ? "_blank" : undefined} h="100%" w="100%">
{children}
</UnstyledButton>
) : (
children
);