Tooltip for widget options

This commit is contained in:
Tagaishi
2023-07-25 21:07:43 +02:00
parent 18e0e2a8ff
commit 5cc2fac8bc
2 changed files with 141 additions and 58 deletions

View File

@@ -13,16 +13,17 @@ import {
Text, Text,
TextInput, TextInput,
Title, Title,
Tooltip,
useMantineTheme,
} from '@mantine/core'; } from '@mantine/core';
import { ContextModalProps } from '@mantine/modals'; import { ContextModalProps } from '@mantine/modals';
import { IconAlertTriangle, IconPlaylistX, IconPlus } from '@tabler/icons-react'; import { IconAlertTriangle, IconPlaylistX, IconPlus, IconAlertCircle } from '@tabler/icons-react';
import { Trans, useTranslation } from 'next-i18next'; import { Trans, useTranslation } from 'next-i18next';
import { FC, useState } from 'react'; import { FC, useState } from 'react';
import { useConfigContext } from '../../../../config/provider'; import { useConfigContext } from '../../../../config/provider';
import { useConfigStore } from '../../../../config/store'; import { useConfigStore } from '../../../../config/store';
import { mapObject } from '../../../../tools/client/objects'; import { mapObject } from '../../../../tools/client/objects';
import { useColorTheme } from '../../../../tools/color';
import Widgets from '../../../../widgets'; import Widgets from '../../../../widgets';
import type { IDraggableListInputValue, IWidgetOptionValue } from '../../../../widgets/widgets'; import type { IDraggableListInputValue, IWidgetOptionValue } from '../../../../widgets/widgets';
import { IWidget } from '../../../../widgets/widgets'; import { IWidget } from '../../../../widgets/widgets';
@@ -135,70 +136,120 @@ const WidgetOptionTypeSwitch: FC<{
handleChange: (key: string, value: IntegrationOptionsValueType) => void; handleChange: (key: string, value: IntegrationOptionsValueType) => void;
}> = ({ option, widgetId, propName: key, value, handleChange }) => { }> = ({ option, widgetId, propName: key, value, handleChange }) => {
const { t } = useTranslation([`modules/${widgetId}`, 'common']); const { t } = useTranslation([`modules/${widgetId}`, 'common']);
const { primaryColor } = useColorTheme(); const { fn } = useMantineTheme();
switch (option.type) { switch (option.type) {
case 'switch': case 'switch':
return ( return (
<Switch <Group align="center" spacing="sm">
label={t(`descriptor.settings.${key}.label`)} <Switch
checked={value as boolean} label={t(`descriptor.settings.${key}.label`)}
onChange={(ev) => handleChange(key, ev.currentTarget.checked)} checked={value as boolean}
/> onChange={(ev) => handleChange(key, ev.currentTarget.checked)}
{...option.inputProps}
/>
{option.info?
<Tooltip.Floating label={t(`descriptor.settings.${key}.info`)} position="right-start" color={fn.darken(fn.primaryColor(), 0.5)}>
<IconAlertCircle size="1.25rem" style={{ display: 'block', opacity: 0.5 }} />
</Tooltip.Floating> : undefined
}
</Group>
); );
case 'text': case 'text':
return ( return (
<TextInput <Stack spacing={0}>
color={primaryColor} <Group align="center" spacing="sm">
label={t(`descriptor.settings.${key}.label`)} <Text size="0.875rem" weight="500">{t(`descriptor.settings.${key}.label`)}</Text>
value={value as string} {option.info?
onChange={(ev) => handleChange(key, ev.currentTarget.value)} <Tooltip.Floating label={t(`descriptor.settings.${key}.info`)} position="right-start" color={fn.darken(fn.primaryColor(), 0.5)}>
/> <IconAlertCircle size="1.25rem" style={{ display: 'block', opacity: 0.5 }} />
</Tooltip.Floating> : undefined
}
</Group>
<TextInput
value={value as string}
onChange={(ev) => handleChange(key, ev.currentTarget.value)}
{...option.inputProps}
/>
</Stack>
); );
case 'multi-select': case 'multi-select':
return ( return (
<MultiSelect <Stack spacing={0}>
color={primaryColor} <Group align="center" spacing="sm">
data={option.data} <Text size="0.875rem" weight="500">{t(`descriptor.settings.${key}.label`)}</Text>
label={t(`descriptor.settings.${key}.label`)} {option.info?
value={value as string[]} <Tooltip.Floating label={t(`descriptor.settings.${key}.info`)} position="right-start" color={fn.darken(fn.primaryColor(), 0.5)}>
defaultValue={option.defaultValue} <IconAlertCircle size="1.25rem" style={{ display: 'block', opacity: 0.5 }} />
onChange={(v) => handleChange(key, v)} </Tooltip.Floating> : undefined
/> }
</Group>
<MultiSelect
data={option.data}
value={value as string[]}
defaultValue={option.defaultValue}
onChange={(v) => handleChange(key, v)}
{...option.inputProps}
/>
</Stack>
); );
case 'select': case 'select':
return ( return (
<Select <Stack spacing={0}>
color={primaryColor} <Group align="center" spacing="sm">
defaultValue={option.defaultValue} <Text size="0.875rem" weight="500">{t(`descriptor.settings.${key}.label`)}</Text>
data={option.data} {option.info?
label={t(`descriptor.settings.${key}.label`)} <Tooltip.Floating label={t(`descriptor.settings.${key}.info`)} position="right-start" color={fn.darken(fn.primaryColor(), 0.5)}>
value={value as string} <IconAlertCircle size="1.25rem" style={{ display: 'block', opacity: 0.5 }} />
onChange={(v) => handleChange(key, v ?? option.defaultValue)} </Tooltip.Floating> : undefined
/> }
</Group>
<Select
defaultValue={option.defaultValue}
data={option.data}
value={value as string}
onChange={(v) => handleChange(key, v ?? option.defaultValue)}
{...option.inputProps}
/>
</Stack>
); );
case 'number': case 'number':
return ( return (
<NumberInput <Stack spacing={0}>
color={primaryColor} <Group align="center" spacing="sm">
label={t(`descriptor.settings.${key}.label`)} <Text size="0.875rem" weight="500">{t(`descriptor.settings.${key}.label`)}</Text>
value={value as number} {option.info?
onChange={(v) => handleChange(key, v!)} <Tooltip.Floating label={t(`descriptor.settings.${key}.info`)} position="right-start" color={fn.darken(fn.primaryColor(), 0.5)}>
{...option.inputProps} <IconAlertCircle size="1.25rem" style={{ display: 'block', opacity: 0.5 }} />
/> </Tooltip.Floating> : undefined
}
</Group>
<NumberInput
value={value as number}
onChange={(v) => handleChange(key, v!)}
{...option.inputProps}
/>
</Stack>
); );
case 'slider': case 'slider':
return ( return (
<Stack spacing="xs"> <Stack spacing={0}>
<Text>{t(`descriptor.settings.${key}.label`)}</Text> <Group align="center" spacing="sm">
<Text size="0.875rem" weight="500">{t(`descriptor.settings.${key}.label`)}</Text>
{option.info?
<Tooltip.Floating label={t(`descriptor.settings.${key}.info`)} position="right-start" color={fn.darken(fn.primaryColor(), 0.5)}>
<IconAlertCircle size="1.25rem" style={{ display: 'block', opacity: 0.5 }} />
</Tooltip.Floating> : undefined
}
</Group>
<Slider <Slider
color={primaryColor}
label={value} label={value}
value={value as number} value={value as number}
min={option.min} min={option.min}
max={option.max} max={option.max}
step={option.step} step={option.step}
onChange={(v) => handleChange(key, v)} onChange={(v) => handleChange(key, v)}
{...option.inputProps}
/> />
</Stack> </Stack>
); );
@@ -237,7 +288,14 @@ const WidgetOptionTypeSwitch: FC<{
return ( return (
<Stack spacing="xs"> <Stack spacing="xs">
<Text>{t(`descriptor.settings.${key}.label`)}</Text> <Group align="center" spacing="sm">
<Text>{t(`descriptor.settings.${key}.label`)}</Text>
{option.info?
<Tooltip.Floating label={t(`descriptor.settings.${key}.info`)} position="right-start" color={fn.darken(fn.primaryColor(), 0.5)}>
<IconAlertCircle size="1.25rem" style={{ display: 'block', opacity: 0.5 }} />
</Tooltip.Floating> : undefined
}
</Group>
<StaticDraggableList <StaticDraggableList
value={typedVal} value={typedVal}
onChange={(v) => handleChange(key, v)} onChange={(v) => handleChange(key, v)}
@@ -262,28 +320,44 @@ const WidgetOptionTypeSwitch: FC<{
); );
case 'multiple-text': case 'multiple-text':
return ( return (
<MultiSelect <Stack spacing={0}>
data={value.map((name: any) => ({ value: name, label: name }))} <Group align="center" spacing="sm">
label={t(`descriptor.settings.${key}.label`)} <Text size="0.875rem" weight="500">{t(`descriptor.settings.${key}.label`)}</Text>
description={t(`descriptor.settings.${key}.description`)} {option.info?
defaultValue={value as string[]} <Tooltip.Floating label={t(`descriptor.settings.${key}.info`)} position="right-start" color={fn.darken(fn.primaryColor(), 0.5)}>
withinPortal <IconAlertCircle size="1.25rem" style={{ display: 'block', opacity: 0.5 }} />
searchable </Tooltip.Floating> : undefined
creatable }
getCreateLabel={(query) => t('common:createItem', { item: query })} </Group>
onChange={(values) => <MultiSelect
handleChange( data={value.map((name: any) => ({ value: name, label: name }))}
key, description={t(`descriptor.settings.${key}.description`)}
values.map((item: string) => item) defaultValue={value as string[]}
) withinPortal
} searchable
/> creatable
getCreateLabel={(query) => t('common:createItem', { item: query })}
onChange={(values) =>
handleChange(
key,
values.map((item: string) => item)
)
}
/>
</Stack>
); );
case 'draggable-editable-list': case 'draggable-editable-list':
const { t: translateDraggableList } = useTranslation('widgets/draggable-list'); const { t: translateDraggableList } = useTranslation('widgets/draggable-list');
return ( return (
<Stack spacing="xs"> <Stack spacing="xs">
<Text>{t(`descriptor.settings.${key}.label`)}</Text> <Group align="center" spacing="sm">
<Text>{t(`descriptor.settings.${key}.label`)}</Text>
{option.info?
<Tooltip.Floating label={t(`descriptor.settings.${key}.info`)} position="right-start" color={fn.darken(fn.primaryColor(), 0.5)}>
<IconAlertCircle size="1.25rem" style={{ display: 'block', opacity: 0.5 }} />
</Tooltip.Floating> : undefined
}
</Group>
<DraggableList <DraggableList
items={Array.from(value).map((v: any) => ({ items={Array.from(value).map((v: any) => ({
data: v, data: v,

View File

@@ -53,6 +53,7 @@ interface DataType {
export type IMultiSelectOptionValue = { export type IMultiSelectOptionValue = {
type: 'multi-select'; type: 'multi-select';
defaultValue: string[]; defaultValue: string[];
info?: boolean;
data: DataType[]; data: DataType[];
inputProps?: Partial<MultiSelectProps>; inputProps?: Partial<MultiSelectProps>;
}; };
@@ -61,6 +62,7 @@ export type IMultiSelectOptionValue = {
export type ISelectOptionValue = { export type ISelectOptionValue = {
type: 'select'; type: 'select';
defaultValue: string; defaultValue: string;
info?: boolean;
data: DataType[]; data: DataType[];
inputProps?: Partial<SelectProps>; inputProps?: Partial<SelectProps>;
}; };
@@ -69,6 +71,7 @@ export type ISelectOptionValue = {
export type ISwitchOptionValue = { export type ISwitchOptionValue = {
type: 'switch'; type: 'switch';
defaultValue: boolean; defaultValue: boolean;
info?: boolean;
inputProps?: Partial<SwitchProps>; inputProps?: Partial<SwitchProps>;
}; };
@@ -76,6 +79,7 @@ export type ISwitchOptionValue = {
export type ITextInputOptionValue = { export type ITextInputOptionValue = {
type: 'text'; type: 'text';
defaultValue: string; defaultValue: string;
info?: boolean;
inputProps?: Partial<TextInputProps>; inputProps?: Partial<TextInputProps>;
}; };
@@ -83,6 +87,7 @@ export type ITextInputOptionValue = {
export type INumberInputOptionValue = { export type INumberInputOptionValue = {
type: 'number'; type: 'number';
defaultValue: number; defaultValue: number;
info?: boolean;
inputProps?: Partial<NumberInputProps>; inputProps?: Partial<NumberInputProps>;
}; };
@@ -90,6 +95,7 @@ export type INumberInputOptionValue = {
export type ISliderInputOptionValue = { export type ISliderInputOptionValue = {
type: 'slider'; type: 'slider';
defaultValue: number; defaultValue: number;
info?: boolean;
min: number; min: number;
max: number; max: number;
step: number; step: number;
@@ -108,6 +114,7 @@ export type IDraggableListInputValue = {
key: string; key: string;
subValues?: Record<string, any>; subValues?: Record<string, any>;
}[]; }[];
info?: boolean;
items: Record< items: Record<
string, string,
Record<string, Omit<Exclude<IWidgetOptionValue, IDraggableListInputValue>, 'defaultValue'>> Record<string, Omit<Exclude<IWidgetOptionValue, IDraggableListInputValue>, 'defaultValue'>>
@@ -117,6 +124,7 @@ export type IDraggableListInputValue = {
export type IDraggableEditableListInputValue<TData extends { id: string }> = { export type IDraggableEditableListInputValue<TData extends { id: string }> = {
type: 'draggable-editable-list'; type: 'draggable-editable-list';
defaultValue: TData[]; defaultValue: TData[];
info?: boolean;
create: () => TData; create: () => TData;
getLabel: (data: TData) => string | JSX.Element; getLabel: (data: TData) => string | JSX.Element;
itemComponent: (props: { itemComponent: (props: {
@@ -130,6 +138,7 @@ export type IDraggableEditableListInputValue<TData extends { id: string }> = {
export type IMultipleTextInputOptionValue = { export type IMultipleTextInputOptionValue = {
type: 'multiple-text'; type: 'multiple-text';
defaultValue: string[]; defaultValue: string[];
info?: boolean;
inputProps?: Partial<TextInputProps>; inputProps?: Partial<TextInputProps>;
}; };