mirror of
https://github.com/idanoo/autobrr
synced 2025-07-25 01:39:13 +00:00
fix(web): tooltips (#1154)
* fix broken tooltips, replace react-tooltip with react-popper-tooltip * make tooltips use ExternalLink component * fix import * get rid of unused import * fix(tooltip): set delayHide * removed unecessary comment * fix tooltip on mobile * stop tooltip label propagation (mainly for mobile devices) * added onClick convenience prop for label component wrapper (since onClick isn't propagated down) --------- Co-authored-by: soup <soup@r4tio.dev>
This commit is contained in:
parent
98df0c9040
commit
3e3454724b
32 changed files with 1171 additions and 396 deletions
20
web/src/components/ExternalLink.tsx
Normal file
20
web/src/components/ExternalLink.tsx
Normal file
|
@ -0,0 +1,20 @@
|
|||
type ExternalLinkProps = {
|
||||
href: string;
|
||||
className?: string;
|
||||
children?: React.ReactNode;
|
||||
};
|
||||
|
||||
export const ExternalLink = ({ href, className, children }: ExternalLinkProps) => (
|
||||
<a
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
href={href}
|
||||
className={className}
|
||||
>
|
||||
{children}
|
||||
</a>
|
||||
);
|
||||
|
||||
export const DocsLink = ({ href }: { href: string; }) => (
|
||||
<ExternalLink href={href} className="text-blue-400 visited:text-blue-400">{href}</ExternalLink>
|
||||
);
|
|
@ -6,6 +6,7 @@
|
|||
import StackTracey from "stacktracey";
|
||||
import type { FallbackProps } from "react-error-boundary";
|
||||
import { ArrowPathIcon } from "@heroicons/react/24/solid";
|
||||
import { ExternalLink } from "@components/ExternalLink";
|
||||
|
||||
export const ErrorPage = ({ error, resetErrorBoundary }: FallbackProps) => {
|
||||
const stack = new StackTracey(error);
|
||||
|
@ -35,23 +36,19 @@ export const ErrorPage = ({ error, resetErrorBoundary }: FallbackProps) => {
|
|||
<h3 className="text-xl leading-6 text-gray-700 dark:text-gray-400 mb-4">
|
||||
Please consider reporting this error to our
|
||||
{" "}
|
||||
<a
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
<ExternalLink
|
||||
href="https://github.com/autobrr/autobrr"
|
||||
className="text-gray-700 dark:text-gray-200 underline font-semibold underline-offset-2 decoration-sky-500 hover:decoration-2 hover:text-black hover:dark:text-gray-100"
|
||||
>
|
||||
GitHub page
|
||||
</a>
|
||||
</ExternalLink>
|
||||
{" or to "}
|
||||
<a
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
<ExternalLink
|
||||
href="https://discord.gg/WQ2eUycxyT"
|
||||
className="text-gray-700 dark:text-gray-200 underline font-semibold underline-offset-2 decoration-purple-500 hover:decoration-2 hover:text-black hover:dark:text-gray-100"
|
||||
>
|
||||
our official Discord channel
|
||||
</a>
|
||||
</ExternalLink>
|
||||
.
|
||||
</h3>
|
||||
<div
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
import { Link } from "react-router-dom";
|
||||
import { ReactComponent as Logo } from "@app/logo.svg";
|
||||
import { ExternalLink } from "@components/ExternalLink";
|
||||
|
||||
export const NotFound = () => {
|
||||
return (
|
||||
|
@ -21,23 +22,19 @@ export const NotFound = () => {
|
|||
<h3 className="text-xl text-center text-gray-700 dark:text-gray-400 mb-1 px-2">
|
||||
feel free to report this to our
|
||||
{" "}
|
||||
<a
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
<ExternalLink
|
||||
href="https://github.com/autobrr/autobrr"
|
||||
className="text-gray-700 dark:text-gray-200 underline font-semibold underline-offset-2 decoration-sky-500 hover:decoration-2 hover:text-black hover:dark:text-gray-100"
|
||||
>
|
||||
GitHub page
|
||||
</a>
|
||||
</ExternalLink>
|
||||
{" or to "}
|
||||
<a
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
<ExternalLink
|
||||
href="https://discord.gg/WQ2eUycxyT"
|
||||
className="text-gray-700 dark:text-gray-200 underline font-semibold underline-offset-2 decoration-purple-500 hover:decoration-2 hover:text-black hover:dark:text-gray-100"
|
||||
>
|
||||
our official Discord channel
|
||||
</a>
|
||||
</ExternalLink>
|
||||
.
|
||||
</h3>
|
||||
<h3 className="text-xl text-center leading-6 text-gray-700 dark:text-gray-400 mb-8 px-2">
|
||||
|
|
|
@ -4,18 +4,18 @@
|
|||
*/
|
||||
|
||||
import * as React from "react";
|
||||
import { toast } from "react-hot-toast";
|
||||
import { formatDistanceToNowStrict } from "date-fns";
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
import { ArrowPathIcon, CheckIcon } from "@heroicons/react/24/solid";
|
||||
import { ClockIcon, ExclamationCircleIcon, NoSymbolIcon } from "@heroicons/react/24/outline";
|
||||
|
||||
import { classNames, simplifyDate } from "@utils";
|
||||
import { Tooltip } from "@components/tooltips/Tooltip";
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
import { APIClient } from "@api/APIClient";
|
||||
import { classNames, simplifyDate } from "@utils";
|
||||
import { filterKeys } from "@screens/filters/List";
|
||||
import { toast } from "react-hot-toast";
|
||||
import Toast from "@components/notifications/Toast";
|
||||
import { RingResizeSpinner } from "@components/Icons";
|
||||
import { Tooltip } from "@components/tooltips/Tooltip";
|
||||
|
||||
interface CellProps {
|
||||
value: string;
|
||||
|
@ -35,6 +35,7 @@ export const IndexerCell = ({ value }: CellProps) => (
|
|||
)}
|
||||
>
|
||||
<Tooltip
|
||||
requiresClick
|
||||
label={value}
|
||||
maxWidth="max-w-[90vw]"
|
||||
>
|
||||
|
@ -53,6 +54,7 @@ export const TitleCell = ({ value }: CellProps) => (
|
|||
)}
|
||||
>
|
||||
<Tooltip
|
||||
requiresClick
|
||||
label={value}
|
||||
maxWidth="max-w-[90vw]"
|
||||
>
|
||||
|
@ -221,6 +223,7 @@ export const ReleaseStatusCell = ({ value }: ReleaseStatusCellProps) => (
|
|||
)}
|
||||
>
|
||||
<Tooltip
|
||||
requiresClick
|
||||
label={StatusCellMap[v.status].icon}
|
||||
title={StatusCellMap[v.status].textFormatter(v)}
|
||||
>
|
||||
|
|
|
@ -15,6 +15,7 @@ import Toast from "@components/notifications/Toast";
|
|||
import { LeftNav } from "./LeftNav";
|
||||
import { RightNav } from "./RightNav";
|
||||
import { MobileNav } from "./MobileNav";
|
||||
import { ExternalLink } from "@components/ExternalLink";
|
||||
|
||||
export const Header = () => {
|
||||
const { data: config } = useQuery({
|
||||
|
@ -77,13 +78,13 @@ export const Header = () => {
|
|||
</div>
|
||||
|
||||
{data?.html_url && (
|
||||
<a href={data.html_url} target="_blank" rel="noopener noreferrer">
|
||||
<ExternalLink href={data.html_url}>
|
||||
<div className="flex mt-4 py-2 bg-blue-500 rounded justify-center">
|
||||
<MegaphoneIcon className="h-6 w-6 text-blue-100" />
|
||||
<span className="text-blue-100 font-medium mx-3">New update available!</span>
|
||||
<span className="inline-flex items-center rounded-md bg-blue-100 px-2.5 py-0.5 text-sm font-medium text-blue-800">{data?.name}</span>
|
||||
</div>
|
||||
</a>
|
||||
</ExternalLink>
|
||||
)}
|
||||
</div>
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ import { classNames } from "@utils";
|
|||
import { ReactComponent as Logo } from "@app/logo.svg";
|
||||
|
||||
import { NAV_ROUTES } from "./_shared";
|
||||
import { ExternalLink } from "@components/ExternalLink";
|
||||
|
||||
export const LeftNav = () => (
|
||||
<div className="flex items-center">
|
||||
|
@ -38,9 +39,7 @@ export const LeftNav = () => (
|
|||
{item.name}
|
||||
</NavLink>
|
||||
))}
|
||||
<a
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
<ExternalLink
|
||||
href="https://autobrr.com"
|
||||
className={classNames(
|
||||
"text-gray-600 dark:text-gray-500 hover:bg-gray-200 dark:hover:bg-gray-800 hover:text-gray-900 dark:hover:text-white px-3 py-2 rounded-2xl text-sm font-medium",
|
||||
|
@ -52,7 +51,7 @@ export const LeftNav = () => (
|
|||
className="inline ml-1 h-5 w-5"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</a>
|
||||
</ExternalLink>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
import { Field, FieldProps } from "formik";
|
||||
import { classNames } from "@utils";
|
||||
import { CustomTooltip } from "@components/tooltips/CustomTooltip";
|
||||
import { DocsTooltip } from "@components/tooltips/DocsTooltip";
|
||||
|
||||
interface ErrorFieldProps {
|
||||
name: string;
|
||||
|
@ -63,10 +63,9 @@ const CheckboxField = ({
|
|||
<div className="ml-3 text-sm">
|
||||
<label htmlFor={name} className="flex mb-2 text-xs font-bold text-gray-700 dark:text-gray-200 uppercase tracking-wide">
|
||||
<div className="flex">
|
||||
{label}
|
||||
{tooltip && (
|
||||
<CustomTooltip anchorId={name}>{tooltip}</CustomTooltip>
|
||||
)}
|
||||
{tooltip ? (
|
||||
<DocsTooltip label={label}>{tooltip}</DocsTooltip>
|
||||
) : label}
|
||||
</div>
|
||||
</label>
|
||||
<p className="text-gray-500">{sublabel}</p>
|
||||
|
@ -74,4 +73,4 @@ const CheckboxField = ({
|
|||
</div>
|
||||
);
|
||||
|
||||
export { ErrorField, RequiredField, CheckboxField };
|
||||
export { ErrorField, RequiredField, CheckboxField };
|
||||
|
|
|
@ -9,7 +9,7 @@ import { EyeIcon, EyeSlashIcon, CheckCircleIcon, XCircleIcon } from "@heroicons/
|
|||
import TextareaAutosize from "react-textarea-autosize";
|
||||
|
||||
import { useToggle } from "@hooks/hooks";
|
||||
import { CustomTooltip } from "@components/tooltips/CustomTooltip";
|
||||
import { DocsTooltip } from "@components/tooltips/DocsTooltip";
|
||||
import { classNames } from "@utils";
|
||||
|
||||
type COL_WIDTHS = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12;
|
||||
|
@ -46,10 +46,9 @@ export const TextField = ({
|
|||
{label && (
|
||||
<label htmlFor={name} className="flex float-left mb-2 text-xs font-bold text-gray-700 dark:text-gray-200 uppercase tracking-wide">
|
||||
<div className="flex">
|
||||
{label}
|
||||
{tooltip && (
|
||||
<CustomTooltip anchorId={name}>{tooltip}</CustomTooltip>
|
||||
)}
|
||||
{tooltip ? (
|
||||
<DocsTooltip label={label}>{tooltip}</DocsTooltip>
|
||||
) : label}
|
||||
</div>
|
||||
</label>
|
||||
)}
|
||||
|
@ -185,8 +184,9 @@ export const RegexField = ({
|
|||
className="flex float-left mb-2 text-xs font-bold text-gray-700 dark:text-gray-200 uppercase tracking-wide"
|
||||
>
|
||||
<div className="flex">
|
||||
{label}
|
||||
<span className="z-10">{tooltip && <CustomTooltip anchorId={name}>{tooltip}</CustomTooltip>}</span>
|
||||
{tooltip ? (
|
||||
<DocsTooltip label={label}>{tooltip}</DocsTooltip>
|
||||
) : label}
|
||||
</div>
|
||||
</label>
|
||||
)}
|
||||
|
@ -324,9 +324,10 @@ export const RegexTextAreaField = ({
|
|||
htmlFor={name}
|
||||
className="flex float-left mb-2 text-xs font-bold text-gray-700 dark:text-gray-200 uppercase tracking-wide"
|
||||
>
|
||||
<div className="flex">
|
||||
{label}
|
||||
<span className="z-10">{tooltip && <CustomTooltip anchorId={name}>{tooltip}</CustomTooltip>}</span>
|
||||
<div className="flex z-10">
|
||||
{tooltip ? (
|
||||
<DocsTooltip label={label}>{tooltip}</DocsTooltip>
|
||||
) : label}
|
||||
</div>
|
||||
</label>
|
||||
)}
|
||||
|
@ -412,10 +413,9 @@ export const TextArea = ({
|
|||
{label && (
|
||||
<label htmlFor={name} className="flex float-left mb-2 text-xs font-bold text-gray-700 dark:text-gray-200 uppercase tracking-wide">
|
||||
<div className="flex">
|
||||
{label}
|
||||
{tooltip && (
|
||||
<CustomTooltip anchorId={name}>{tooltip}</CustomTooltip>
|
||||
)}
|
||||
{tooltip ? (
|
||||
<DocsTooltip label={label}>{tooltip}</DocsTooltip>
|
||||
) : label}
|
||||
</div>
|
||||
</label>
|
||||
)}
|
||||
|
@ -484,10 +484,9 @@ export const TextAreaAutoResize = ({
|
|||
{label && (
|
||||
<label htmlFor={name} className="flex float-left mb-2 text-xs font-bold text-gray-700 dark:text-gray-200 uppercase tracking-wide">
|
||||
<div className="flex">
|
||||
{label}
|
||||
{tooltip && (
|
||||
<CustomTooltip anchorId={name}>{tooltip}</CustomTooltip>
|
||||
)}
|
||||
{tooltip ? (
|
||||
<DocsTooltip label={label}>{tooltip}</DocsTooltip>
|
||||
) : label}
|
||||
</div>
|
||||
</label>
|
||||
)}
|
||||
|
@ -630,8 +629,9 @@ export const NumberField = ({
|
|||
className="flex float-left mb-2 text-xs font-bold text-gray-700 dark:text-gray-200 uppercase tracking-wide"
|
||||
>
|
||||
<div className="flex">
|
||||
{label}
|
||||
{tooltip && <CustomTooltip anchorId={name}>{tooltip}</CustomTooltip>}
|
||||
{tooltip ? (
|
||||
<DocsTooltip label={label}>{tooltip}</DocsTooltip>
|
||||
) : label}
|
||||
</div>
|
||||
</label>
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ import { Switch } from "@headlessui/react";
|
|||
import { ErrorField, RequiredField } from "./common";
|
||||
import Select, { components, ControlProps, InputProps, MenuProps, OptionProps } from "react-select";
|
||||
import { SelectFieldProps } from "./select";
|
||||
import { CustomTooltip } from "@components/tooltips/CustomTooltip";
|
||||
import { DocsTooltip } from "@components/tooltips/DocsTooltip";
|
||||
|
||||
interface TextFieldWideProps {
|
||||
name: string;
|
||||
|
@ -43,7 +43,9 @@ export const TextFieldWide = ({
|
|||
<div>
|
||||
<label htmlFor={name} className="flex text-sm font-medium text-gray-900 dark:text-white sm:mt-px sm:pt-2">
|
||||
<div className="flex">
|
||||
{label} {tooltip && (<CustomTooltip anchorId={name}>{tooltip}</CustomTooltip>)}
|
||||
{tooltip ? (
|
||||
<DocsTooltip label={label}>{tooltip}</DocsTooltip>
|
||||
) : label}
|
||||
<RequiredField required={required} />
|
||||
</div>
|
||||
</label>
|
||||
|
@ -108,7 +110,9 @@ export const PasswordFieldWide = ({
|
|||
<div>
|
||||
<label htmlFor={name} className="flex text-sm font-medium text-gray-900 dark:text-white sm:mt-px sm:pt-2">
|
||||
<div className="flex">
|
||||
{label} {tooltip && (<CustomTooltip anchorId={name}>{tooltip}</CustomTooltip>)}
|
||||
{tooltip ? (
|
||||
<DocsTooltip label={label}>{tooltip}</DocsTooltip>
|
||||
) : label}
|
||||
<RequiredField required={required} />
|
||||
</div>
|
||||
</label>
|
||||
|
@ -172,7 +176,9 @@ export const NumberFieldWide = ({
|
|||
className="block text-sm font-medium text-gray-900 dark:text-white sm:mt-px sm:pt-2"
|
||||
>
|
||||
<div className="flex">
|
||||
{label} {tooltip && (<CustomTooltip anchorId={name}>{tooltip}</CustomTooltip>)}
|
||||
{tooltip ? (
|
||||
<DocsTooltip label={label}>{tooltip}</DocsTooltip>
|
||||
) : label}
|
||||
<RequiredField required={required} />
|
||||
</div>
|
||||
</label>
|
||||
|
@ -232,10 +238,11 @@ export const SwitchGroupWide = ({
|
|||
<ul className="px-4 divide-y divide-gray-200 dark:divide-gray-700">
|
||||
<Switch.Group as="li" className="py-4 flex items-center justify-between">
|
||||
<div className="flex flex-col">
|
||||
<Switch.Label as="div" className="text-sm font-medium text-gray-900 dark:text-white"
|
||||
passive>
|
||||
<Switch.Label as="div" passive className="text-sm font-medium text-gray-900 dark:text-white">
|
||||
<div className="flex">
|
||||
{label} {tooltip && (<CustomTooltip anchorId={name}>{tooltip}</CustomTooltip>)}
|
||||
{tooltip ? (
|
||||
<DocsTooltip label={label}>{tooltip}</DocsTooltip>
|
||||
) : label}
|
||||
</div>
|
||||
</Switch.Label>
|
||||
{description && (
|
||||
|
@ -396,8 +403,9 @@ export const SelectFieldWide = ({
|
|||
className="flex text-sm font-medium text-gray-900 dark:text-white"
|
||||
>
|
||||
<div className="flex">
|
||||
{label}
|
||||
{tooltip && (<CustomTooltip anchorId={name}>{tooltip}</CustomTooltip>)}
|
||||
{tooltip ? (
|
||||
<DocsTooltip label={label}>{tooltip}</DocsTooltip>
|
||||
) : label}
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
|
|
|
@ -11,7 +11,7 @@ import { MultiSelect as RMSC } from "react-multi-select-component";
|
|||
|
||||
import { classNames, COL_WIDTHS } from "@utils";
|
||||
import { SettingsContext } from "@utils/Context";
|
||||
import { CustomTooltip } from "@components/tooltips/CustomTooltip";
|
||||
import { DocsTooltip } from "@components/tooltips/DocsTooltip";
|
||||
|
||||
export interface MultiSelectOption {
|
||||
value: string | number;
|
||||
|
@ -56,10 +56,9 @@ export const MultiSelect = ({
|
|||
<label
|
||||
htmlFor={label} className="flex mb-2 text-xs font-bold tracking-wide text-gray-700 uppercase dark:text-gray-200">
|
||||
<div className="flex">
|
||||
{label}
|
||||
{tooltip && (
|
||||
<CustomTooltip anchorId={name}>{tooltip}</CustomTooltip>
|
||||
)}
|
||||
{tooltip ? (
|
||||
<DocsTooltip label={label}>{tooltip}</DocsTooltip>
|
||||
) : label}
|
||||
</div>
|
||||
</label>
|
||||
|
||||
|
@ -297,10 +296,9 @@ export const Select = ({
|
|||
<>
|
||||
<Listbox.Label className="flex float-left mb-2 text-xs font-bold text-gray-700 dark:text-gray-200 uppercase tracking-wide">
|
||||
<div className="flex">
|
||||
{label}
|
||||
{tooltip && (
|
||||
<CustomTooltip anchorId={name}>{tooltip}</CustomTooltip>
|
||||
)}
|
||||
{tooltip ? (
|
||||
<DocsTooltip label={label}>{tooltip}</DocsTooltip>
|
||||
) : label}
|
||||
</div>
|
||||
</Listbox.Label>
|
||||
<div className="mt-2 relative">
|
||||
|
|
|
@ -8,7 +8,7 @@ import { Field } from "formik";
|
|||
import Select, { components, ControlProps, InputProps, MenuProps, OptionProps } from "react-select";
|
||||
import { OptionBasicTyped } from "@domain/constants";
|
||||
import CreatableSelect from "react-select/creatable";
|
||||
import { CustomTooltip } from "@components/tooltips/CustomTooltip";
|
||||
import { DocsTooltip } from "@components/tooltips/DocsTooltip";
|
||||
|
||||
interface SelectFieldProps<T> {
|
||||
name: string;
|
||||
|
@ -29,7 +29,9 @@ export function SelectFieldCreatable<T>({ name, label, help, placeholder, toolti
|
|||
className="block text-sm font-medium text-gray-900 dark:text-white sm:pt-2"
|
||||
>
|
||||
<div className="flex">
|
||||
{label} {tooltip && (<CustomTooltip anchorId={name}>{tooltip}</CustomTooltip>)}
|
||||
{tooltip ? (
|
||||
<DocsTooltip label={label}>{tooltip}</DocsTooltip>
|
||||
) : label}
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
|
@ -200,7 +202,9 @@ export function SelectFieldBasic<T>({ name, label, help, placeholder, tooltip, d
|
|||
className="block text-sm font-medium text-gray-900 dark:text-white sm:pt-2"
|
||||
>
|
||||
<div className="flex">
|
||||
{label} {tooltip && (<CustomTooltip anchorId={name}>{tooltip}</CustomTooltip>)}
|
||||
{tooltip ? (
|
||||
<DocsTooltip label={label}>{tooltip}</DocsTooltip>
|
||||
) : label}
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
|
|
|
@ -9,7 +9,7 @@ import { Field } from "formik";
|
|||
import { Switch as HeadlessSwitch } from "@headlessui/react";
|
||||
|
||||
import { classNames } from "@utils";
|
||||
import { CustomTooltip } from "@components/tooltips/CustomTooltip";
|
||||
import { DocsTooltip } from "@components/tooltips/DocsTooltip";
|
||||
|
||||
type SwitchProps<V = unknown> = {
|
||||
label?: string
|
||||
|
@ -88,13 +88,18 @@ const SwitchGroup = ({
|
|||
}: SwitchGroupProps) => (
|
||||
<HeadlessSwitch.Group as="ol" className="py-4 flex items-center justify-between">
|
||||
{label && <div className="flex flex-col">
|
||||
<HeadlessSwitch.Label as={heading ? "h2" : "span"} className={classNames("flex float-left cursor-default mb-2 text-xs font-bold text-gray-700 dark:text-gray-200 uppercase tracking-wide", heading ? "text-lg" : "text-sm")}
|
||||
passive>
|
||||
<HeadlessSwitch.Label
|
||||
passive
|
||||
as={heading ? "h2" : "span"}
|
||||
className={classNames(
|
||||
"flex float-left cursor-default mb-2 text-xs font-bold text-gray-700 dark:text-gray-200 uppercase tracking-wide",
|
||||
heading ? "text-lg" : "text-sm"
|
||||
)}
|
||||
>
|
||||
<div className="flex">
|
||||
{label}
|
||||
{tooltip && (
|
||||
<CustomTooltip anchorId={name}>{tooltip}</CustomTooltip>
|
||||
)}
|
||||
{tooltip ? (
|
||||
<DocsTooltip label={label}>{tooltip}</DocsTooltip>
|
||||
) : label}
|
||||
</div>
|
||||
</HeadlessSwitch.Label>
|
||||
{description && (
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2021 - 2023, Ludvig Lundgren and the autobrr contributors.
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
.react-tooltip code {
|
||||
background-color: rgb(63, 71, 94);
|
||||
padding-left: 4px;
|
||||
padding-right: 4px;
|
||||
padding-top: 2px;
|
||||
padding-bottom: 2px;
|
||||
}
|
||||
|
||||
.react-tooltip a:hover {
|
||||
text-decoration-line: underline;
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2021 - 2023, Ludvig Lundgren and the autobrr contributors.
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
import { PlacesType, Tooltip } from "react-tooltip";
|
||||
import "./CustomTooltip.css";
|
||||
|
||||
|
||||
interface CustomTooltipProps {
|
||||
anchorId: string;
|
||||
children?: React.ReactNode;
|
||||
clickable?: boolean;
|
||||
place?: PlacesType;
|
||||
}
|
||||
|
||||
export const CustomTooltip = ({
|
||||
anchorId,
|
||||
children,
|
||||
clickable = true,
|
||||
place = "top"
|
||||
}: CustomTooltipProps) => {
|
||||
const id = `${anchorId}-tooltip`;
|
||||
return (
|
||||
<div className="flex items-center">
|
||||
<svg id={id} className="ml-1 w-4 h-4 text-gray-500 dark:text-gray-400 fill-current" viewBox="0 0 72 72"><path d="M32 2C15.432 2 2 15.432 2 32s13.432 30 30 30s30-13.432 30-30S48.568 2 32 2m5 49.75H27v-24h10v24m-5-29.5a5 5 0 1 1 0-10a5 5 0 0 1 0 10"/></svg>
|
||||
<Tooltip
|
||||
style={{ maxWidth: "350px", fontSize: "12px", textTransform: "none", fontWeight: "normal", borderRadius: "0.375rem", backgroundColor: "#34343A", color: "#fff" }}
|
||||
delayShow={100}
|
||||
delayHide={150}
|
||||
place={place}
|
||||
anchorSelect={id}
|
||||
data-html={true}
|
||||
clickable={clickable}
|
||||
>
|
||||
{children}
|
||||
</Tooltip>
|
||||
</div>
|
||||
);
|
||||
};
|
25
web/src/components/tooltips/DocsTooltip.tsx
Normal file
25
web/src/components/tooltips/DocsTooltip.tsx
Normal file
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Copyright (c) 2021 - 2023, Ludvig Lundgren and the autobrr contributors.
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
import { Tooltip } from "./Tooltip";
|
||||
|
||||
interface DocsTooltipProps {
|
||||
label?: React.ReactNode;
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
|
||||
export const DocsTooltip = ({ label, children }: DocsTooltipProps) => (
|
||||
<Tooltip
|
||||
label={
|
||||
<div className="flex flex-row items-center">
|
||||
{label ?? null}
|
||||
<svg className="ml-1 w-4 h-4 text-gray-500 dark:text-gray-400 fill-current" viewBox="0 0 72 72"><path d="M32 2C15.432 2 2 15.432 2 32s13.432 30 30 30s30-13.432 30-30S48.568 2 32 2m5 49.75H27v-24h10v24m-5-29.5a5 5 0 1 1 0-10a5 5 0 0 1 0 10" /></svg>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
{children}
|
||||
</Tooltip>
|
||||
);
|
||||
|
|
@ -3,22 +3,30 @@
|
|||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
import * as React from "react";
|
||||
import type { ReactNode } from "react";
|
||||
import { Transition } from "@headlessui/react";
|
||||
import { usePopperTooltip } from "react-popper-tooltip";
|
||||
|
||||
import { classNames } from "@utils";
|
||||
|
||||
interface TooltipProps {
|
||||
label: ReactNode;
|
||||
onLabelClick?: (e: React.MouseEvent<HTMLDivElement>) => void;
|
||||
title?: ReactNode;
|
||||
maxWidth?: string;
|
||||
requiresClick?: boolean;
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
// NOTE(stacksmash76): onClick is not propagated
|
||||
// to the label (always-visible) component, so you will have
|
||||
// to use the `onLabelClick` prop in this case.
|
||||
export const Tooltip = ({
|
||||
label,
|
||||
onLabelClick,
|
||||
title,
|
||||
children,
|
||||
requiresClick,
|
||||
maxWidth = "max-w-sm"
|
||||
}: TooltipProps) => {
|
||||
const {
|
||||
|
@ -28,22 +36,46 @@ export const Tooltip = ({
|
|||
setTriggerRef,
|
||||
visible
|
||||
} = usePopperTooltip({
|
||||
trigger: ["click"],
|
||||
interactive: false
|
||||
trigger: requiresClick ? ["click"] : ["click", "hover"],
|
||||
interactive: !requiresClick,
|
||||
delayHide: 200
|
||||
});
|
||||
|
||||
if (!children || Array.isArray(children) && !children.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div ref={setTriggerRef} className="truncate">
|
||||
<div
|
||||
ref={setTriggerRef}
|
||||
className="truncate"
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
e.nativeEvent.stopImmediatePropagation();
|
||||
|
||||
onLabelClick?.(e);
|
||||
}}
|
||||
>
|
||||
{label}
|
||||
</div>
|
||||
{visible && (
|
||||
<Transition
|
||||
show={visible}
|
||||
className="z-10"
|
||||
enter="transition duration-200 ease-out"
|
||||
enterFrom="opacity-0"
|
||||
enterTo="opacity-100"
|
||||
leave="transition duration-200 ease-in"
|
||||
leaveFrom="opacity-100"
|
||||
leaveTo="opacity-0"
|
||||
>
|
||||
<div
|
||||
ref={setTooltipRef}
|
||||
{...getTooltipProps({
|
||||
className: classNames(
|
||||
maxWidth,
|
||||
"rounded-md border border-gray-300 text-black text-xs shadow-lg dark:text-white dark:border-gray-700 dark:shadow-2xl"
|
||||
"rounded-md border border-gray-300 text-black text-xs normal-case tracking-normal font-normal shadow-lg dark:text-white dark:border-gray-700 dark:shadow-2xl"
|
||||
)
|
||||
})}
|
||||
>
|
||||
|
@ -55,13 +87,13 @@ export const Tooltip = ({
|
|||
<div
|
||||
className={classNames(
|
||||
title ? "" : "rounded-t-md",
|
||||
"py-1 px-2 rounded-b-md bg-white dark:bg-gray-900"
|
||||
"whitespace-normal break-words py-1 px-2 rounded-b-md bg-white dark:bg-gray-900"
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</Transition>
|
||||
</>
|
||||
);
|
||||
};
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue