mirror of https://github.com/buster-so/buster.git
tooltip rip and replace
This commit is contained in:
parent
37a456d665
commit
098028ea63
|
@ -64,7 +64,7 @@ export const BigQueryForm: React.FC<{
|
|||
<AppSelectTagInput className="w-full" tokenSeparators={[',']} suffixIcon={null} />
|
||||
</Form.Item>
|
||||
<Form.Item name="credentials_json" label="Credentials">
|
||||
<AppTooltip title={isValidJson ? '' : 'Invalid JSON'} forceShow>
|
||||
<AppTooltip title={isValidJson ? '' : 'Invalid JSON'}>
|
||||
<div
|
||||
className="h-[180px] w-full"
|
||||
style={{
|
||||
|
|
|
@ -47,7 +47,7 @@ export const ShareMenu: React.FC<
|
|||
/>
|
||||
) : null
|
||||
}>
|
||||
<AppTooltip performant={false} title={!isOpen ? 'Share item' : ''}>
|
||||
<AppTooltip title={!isOpen ? 'Share item' : ''}>
|
||||
<div className="flex">{children}</div>
|
||||
</AppTooltip>
|
||||
</AppPopover>
|
||||
|
|
|
@ -63,7 +63,7 @@ export const FavoriteStar: React.FC<{
|
|||
const tooltipText = isFavorited ? 'Remove from favorites' : 'Add to favorites';
|
||||
|
||||
return (
|
||||
<AppTooltip title={tooltipText} performant key={tooltipText}>
|
||||
<AppTooltip title={tooltipText} key={tooltipText}>
|
||||
<Button
|
||||
classNames={{
|
||||
icon: 'text-inherit! mt-[-2px]!'
|
||||
|
|
|
@ -162,7 +162,7 @@ export const StatusBadgeIndicator: React.FC<{
|
|||
: {};
|
||||
|
||||
return (
|
||||
<AppTooltip title={showTooltip && isHovering ? tooltipText : ''} mouseEnterDelay={0.25}>
|
||||
<AppTooltip title={showTooltip && isHovering ? tooltipText : ''}>
|
||||
<div
|
||||
{...mouseEvents}
|
||||
className={`rounded-full ${className} ${sharedClass} ${isNotVerified ? '' : ''}`}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { ErrorCard } from '@/components/ui/error/ErrorCard';
|
||||
import { ReactNode } from 'react';
|
||||
import { ErrorBoundary } from '../error/ErrorBoundary';
|
||||
import React from 'react';
|
||||
|
||||
interface Props {
|
||||
children: ReactNode;
|
||||
|
|
|
@ -1,127 +0,0 @@
|
|||
import * as antColors from '@ant-design/colors';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { Button, ColorPicker, Modal } from 'antd';
|
||||
import { useMemoizedFn } from 'ahooks';
|
||||
import pick from 'lodash/pick';
|
||||
import shuffle from 'lodash/shuffle';
|
||||
import { AppTooltip } from '../tooltip';
|
||||
import { AppMaterialIcons } from '../icons';
|
||||
import { Text } from '@/components/ui';
|
||||
|
||||
export const NewColorThemeModal: React.FC<{
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
modalTheme: string[] | null;
|
||||
onEditTheme: (theme: string[]) => Promise<void>;
|
||||
onCreateNewTheme: (theme: string[]) => Promise<void>;
|
||||
}> = ({ open, onCreateNewTheme, modalTheme, onEditTheme, onClose }) => {
|
||||
const onRandomize = useMemoizedFn((): string[] => {
|
||||
const selectedPallets = pick(antColors, [
|
||||
'blue',
|
||||
'red',
|
||||
'green',
|
||||
'purple',
|
||||
'gold',
|
||||
'orange',
|
||||
'volcano',
|
||||
'magenta'
|
||||
]);
|
||||
|
||||
const randomColors = Object.values(selectedPallets).reduce((acc, curr) => {
|
||||
const middleColors = curr.slice(2, 8);
|
||||
const randomColor = middleColors[Math.floor(Math.random() * middleColors.length)]!;
|
||||
return [...acc, randomColor];
|
||||
}, [] as string[]);
|
||||
|
||||
const allColors = Object.values(selectedPallets).flatMap((p) => p.slice(1, 8));
|
||||
const numberOfColors = 10;
|
||||
const numberOfColorsShort = numberOfColors - randomColors.length;
|
||||
for (let i = 0; i < numberOfColorsShort; i++) {
|
||||
const randomColor = allColors[Math.floor(Math.random() * allColors.length)]!;
|
||||
randomColors.push(randomColor);
|
||||
}
|
||||
|
||||
const shuffleColors = shuffle(randomColors);
|
||||
|
||||
return shuffleColors;
|
||||
});
|
||||
|
||||
const [theme, setTheme] = useState<string[]>([]);
|
||||
const [submitting, setSubmitting] = useState(false);
|
||||
|
||||
const onSubmitPreflight = async () => {
|
||||
setSubmitting(true);
|
||||
|
||||
if (modalTheme) {
|
||||
await onEditTheme(theme);
|
||||
} else {
|
||||
await onCreateNewTheme(theme);
|
||||
}
|
||||
setSubmitting(false);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (open && modalTheme && modalTheme.length > 0) {
|
||||
setTheme(modalTheme);
|
||||
} else if (open) {
|
||||
setTheme(onRandomize());
|
||||
}
|
||||
}, [open]);
|
||||
|
||||
return (
|
||||
<Modal
|
||||
destroyOnClose
|
||||
open={open}
|
||||
footer={[
|
||||
<div key="footer" className="flex w-full justify-between">
|
||||
<AppTooltip title={'Generate Palette'} trigger={['hover']}>
|
||||
<Button
|
||||
onClick={() => {
|
||||
setTheme(onRandomize());
|
||||
}}
|
||||
icon={<AppMaterialIcons icon="science" />}></Button>
|
||||
</AppTooltip>
|
||||
|
||||
<Button
|
||||
loading={submitting}
|
||||
onClick={async () => {
|
||||
onSubmitPreflight();
|
||||
}}>
|
||||
{modalTheme ? 'Save theme' : 'Create theme'}
|
||||
</Button>
|
||||
</div>
|
||||
]}
|
||||
onCancel={onClose}
|
||||
width={730}
|
||||
title="Create theme">
|
||||
<Text className="">
|
||||
It is recommended to choose a color pallete with a wide range of colors as it will be used
|
||||
for charts.
|
||||
</Text>
|
||||
|
||||
<div className="mt-5 flex">
|
||||
{theme?.map((color, index) => {
|
||||
return (
|
||||
<ColorPicker
|
||||
key={index}
|
||||
value={color}
|
||||
disabledAlpha
|
||||
destroyTooltipOnHide
|
||||
onChange={(v) => {
|
||||
const newTheme = [...theme];
|
||||
newTheme[index] = v.toHexString();
|
||||
setTheme(newTheme);
|
||||
}}>
|
||||
<div
|
||||
onClick={() => {}}
|
||||
className="h-full min-h-[118px] w-full cursor-pointer transition first:rounded-l last:rounded-r hover:z-10 hover:scale-105 hover:shadow-lg"
|
||||
style={{ backgroundColor: color }}></div>
|
||||
</ColorPicker>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
export default NewColorThemeModal;
|
|
@ -68,13 +68,7 @@ const TextWrapper: React.FC<
|
|||
|
||||
const title = tooltip ? (typeof tooltip === 'string' ? tooltip : (children as string)) : '';
|
||||
|
||||
return tooltip ? (
|
||||
<AppTooltip performant title={title}>
|
||||
{children}
|
||||
</AppTooltip>
|
||||
) : (
|
||||
<>{children}</>
|
||||
);
|
||||
return tooltip ? <AppTooltip title={title}>{children}</AppTooltip> : <>{children}</>;
|
||||
});
|
||||
TextWrapper.displayName = 'TextWrapper';
|
||||
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { AppPopover } from './AppPopover';
|
||||
import { useClickAway, useMemoizedFn } from 'ahooks';
|
||||
import { useMemoizedFn } from 'ahooks';
|
||||
import isString from 'lodash/isString';
|
||||
import { AppMaterialIcons } from '../icons';
|
||||
import { Button, PopoverProps } from 'antd';
|
||||
import { ButtonProps } from 'antd/lib';
|
||||
import { PopoverProps } from 'antd';
|
||||
import { createStyles } from 'antd-style';
|
||||
import { useAntToken } from '@/styles/useAntToken';
|
||||
|
||||
|
@ -109,7 +108,7 @@ export const AppPopoverOptions: React.FC<{
|
|||
styles.item,
|
||||
rowClass,
|
||||
`${option.selected ? selectedClass : ''}`,
|
||||
`flex select-none items-center justify-between space-x-2 rounded-sm p-1`
|
||||
`flex items-center justify-between space-x-2 rounded-sm p-1 select-none`
|
||||
)}
|
||||
onClick={() => {
|
||||
option.onClick();
|
||||
|
@ -126,9 +125,9 @@ export const AppPopoverOptions: React.FC<{
|
|||
</div>
|
||||
<div
|
||||
className={`flex flex-col space-y-0.5 ${option.description ? 'justify-start' : 'justify-center'}`}>
|
||||
<div className="select-none text-base">{option.label}</div>
|
||||
<div className="text-base select-none">{option.label}</div>
|
||||
{option.description && (
|
||||
<div className="select-none text-sm">{option.description}</div>
|
||||
<div className="text-sm select-none">{option.description}</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -142,7 +141,7 @@ export const AppPopoverOptions: React.FC<{
|
|||
))}
|
||||
</div>
|
||||
|
||||
{footer && <div className={cx('pb-2 pt-2', styles.footer)}>{footer}</div>}
|
||||
{footer && <div className={cx('pt-2 pb-2', styles.footer)}>{footer}</div>}
|
||||
</div>
|
||||
}>
|
||||
<div
|
||||
|
|
|
@ -1,88 +0,0 @@
|
|||
'use client';
|
||||
|
||||
import React, { PropsWithChildren, useMemo, useState } from 'react';
|
||||
import { Tooltip } from 'antd';
|
||||
import type { TooltipProps } from 'antd';
|
||||
import { KeyboardShortcutPill } from '../pills/KeyboardShortcutPills';
|
||||
|
||||
export type AppTooltipProps = TooltipProps & {
|
||||
shortcuts?: string[];
|
||||
title?: string;
|
||||
forceShow?: boolean;
|
||||
performant?: boolean;
|
||||
};
|
||||
|
||||
export const AppTooltip = React.memo<PropsWithChildren<AppTooltipProps>>(
|
||||
({ children, ...props }) => {
|
||||
const [isHovering, setIsHovering] = useState(false);
|
||||
const { title, shortcuts = [], forceShow, performant } = props;
|
||||
|
||||
if (!title && !shortcuts.length && !forceShow) {
|
||||
return <>{children}</>;
|
||||
}
|
||||
|
||||
if (performant && !isHovering) {
|
||||
return <PerformanceTooltip setIsHovering={setIsHovering}>{children}</PerformanceTooltip>;
|
||||
}
|
||||
|
||||
return <BusterTooltip {...props}>{children}</BusterTooltip>;
|
||||
}
|
||||
);
|
||||
AppTooltip.displayName = 'AppTooltip';
|
||||
|
||||
const PerformanceTooltip: React.FC<
|
||||
PropsWithChildren<{
|
||||
setIsHovering: (v: boolean) => void;
|
||||
}>
|
||||
> = React.memo(({ children, setIsHovering }) => {
|
||||
return (
|
||||
<div
|
||||
className="performance-tooltip flex"
|
||||
onMouseEnter={() => {
|
||||
setIsHovering(true);
|
||||
}}>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
});
|
||||
PerformanceTooltip.displayName = 'PerformanceTooltip';
|
||||
|
||||
const BusterTooltip: React.FC<PropsWithChildren<AppTooltipProps>> = ({
|
||||
children,
|
||||
mouseEnterDelay = 0.75,
|
||||
mouseLeaveDelay = 0.15,
|
||||
destroyTooltipOnHide = true,
|
||||
trigger = 'hover',
|
||||
arrow = false,
|
||||
title = '',
|
||||
forceShow = false,
|
||||
performant = false,
|
||||
shortcuts = [], //⌘
|
||||
align,
|
||||
...props
|
||||
}) => {
|
||||
const memoizedTitle = useMemo(() => {
|
||||
if (title) {
|
||||
return (
|
||||
<div className="flex items-center space-x-1">
|
||||
<span className="text-sm">{title}</span>
|
||||
<KeyboardShortcutPill shortcut={shortcuts} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}, [title, shortcuts]);
|
||||
|
||||
return (
|
||||
<Tooltip
|
||||
{...props}
|
||||
title={memoizedTitle}
|
||||
mouseEnterDelay={mouseEnterDelay}
|
||||
trigger={trigger}
|
||||
arrow={arrow}
|
||||
mouseLeaveDelay={mouseLeaveDelay}>
|
||||
{children}
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
BusterTooltip.displayName = 'BusterTooltip';
|
|
@ -25,9 +25,9 @@ const meta = {
|
|||
control: 'text',
|
||||
description: 'The text content of the tooltip'
|
||||
},
|
||||
shortcut: {
|
||||
shortcuts: {
|
||||
control: 'object',
|
||||
description: 'Array of keyboard shortcuts to display'
|
||||
description: 'Array of keyboard shortcutss to display'
|
||||
},
|
||||
children: {
|
||||
control: 'object',
|
||||
|
@ -68,20 +68,20 @@ export const Basic: Story = {
|
|||
}
|
||||
};
|
||||
|
||||
// With keyboard shortcuts
|
||||
// With keyboard shortcutss
|
||||
export const WithShortcut: Story = {
|
||||
args: {
|
||||
title: 'Save file',
|
||||
shortcut: ['S'],
|
||||
shortcuts: ['S'],
|
||||
children: <Button>Save</Button>
|
||||
}
|
||||
};
|
||||
|
||||
// Multiple shortcuts
|
||||
// Multiple shortcutss
|
||||
export const MultipleShortcuts: Story = {
|
||||
args: {
|
||||
title: 'Undo action',
|
||||
shortcut: ['⌘', 'Z'],
|
||||
shortcuts: ['⌘', 'Z'],
|
||||
children: <Button>Undo</Button>
|
||||
}
|
||||
};
|
||||
|
|
|
@ -12,8 +12,8 @@ export interface TooltipProps
|
|||
extends Pick<React.ComponentProps<typeof TooltipContentBase>, 'align' | 'side' | 'sideOffset'>,
|
||||
Pick<React.ComponentProps<typeof TooltipProvider>, 'delayDuration' | 'skipDelayDuration'> {
|
||||
children: React.ReactNode;
|
||||
title: string;
|
||||
shortcut?: string[];
|
||||
title: string | undefined;
|
||||
shortcuts?: string[];
|
||||
open?: boolean;
|
||||
}
|
||||
|
||||
|
@ -22,21 +22,21 @@ export const Tooltip = React.memo<TooltipProps>(
|
|||
children,
|
||||
title,
|
||||
sideOffset,
|
||||
shortcut,
|
||||
shortcuts,
|
||||
delayDuration = 0,
|
||||
skipDelayDuration,
|
||||
align,
|
||||
side,
|
||||
open
|
||||
}) => {
|
||||
if (!title && !shortcut?.length) return children;
|
||||
if (!title || (!title && !shortcuts?.length)) return children;
|
||||
|
||||
return (
|
||||
<TooltipProvider delayDuration={delayDuration} skipDelayDuration={skipDelayDuration}>
|
||||
<TooltipBase open={open}>
|
||||
<TooltipTrigger asChild>{children}</TooltipTrigger>
|
||||
<TooltipContentBase align={align} side={side} sideOffset={sideOffset}>
|
||||
<TooltipContent title={title} shortcut={shortcut} />
|
||||
<TooltipContent title={title} shortcut={shortcuts} />
|
||||
</TooltipContentBase>
|
||||
</TooltipBase>
|
||||
</TooltipProvider>
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
export * from './AppTooltip';
|
||||
export * from './AppPopover';
|
||||
export * from './AppPopoverMenu';
|
||||
export * from './Tooltip';
|
||||
|
||||
import { Tooltip } from './Tooltip';
|
||||
|
||||
export { Tooltip as AppTooltip };
|
||||
|
|
|
@ -15,12 +15,10 @@ export const EditPieShowInnerLabel = React.memo(
|
|||
return (
|
||||
<LabelAndInput label="Show inner label">
|
||||
<div className="flex w-full items-center justify-end space-x-2.5">
|
||||
<AppTooltip mouseEnterDelay={0.25}>
|
||||
<Switch
|
||||
defaultChecked={pieShowInnerLabel}
|
||||
onChange={(value) => onUpdateChartConfig({ pieShowInnerLabel: value })}
|
||||
/>
|
||||
</AppTooltip>
|
||||
<Switch
|
||||
defaultChecked={pieShowInnerLabel}
|
||||
onChange={(value) => onUpdateChartConfig({ pieShowInnerLabel: value })}
|
||||
/>
|
||||
</div>
|
||||
</LabelAndInput>
|
||||
);
|
||||
|
|
|
@ -147,7 +147,7 @@ const ChartButton: React.FC<{
|
|||
const { styles, cx } = useStyles();
|
||||
|
||||
return (
|
||||
<AppTooltip title={tooltipText} performant mouseEnterDelay={0.75}>
|
||||
<AppTooltip title={tooltipText} delayDuration={0.65}>
|
||||
<div
|
||||
key={id}
|
||||
onClick={() => !disabled && onSelectChartType(id)}
|
||||
|
|
|
@ -50,7 +50,7 @@ export const DatasetList: React.FC<{
|
|||
))}
|
||||
|
||||
<DropdownSelect datasets={selectedDatasets} onChange={onChange}>
|
||||
<AppTooltip className="flex! items-center justify-center" title={'Add a dataset'}>
|
||||
<AppTooltip title={'Add a dataset'}>
|
||||
{selectedDatasets.length === 0 ? (
|
||||
<DropdownEmptyButton />
|
||||
) : (
|
||||
|
|
|
@ -1,18 +1,16 @@
|
|||
import React from 'react';
|
||||
|
||||
import { AppMaterialIcons, AppTooltip, AppTooltipProps } from '@/components/ui';
|
||||
import { Text } from '@/components/ui';
|
||||
|
||||
const memoizedTrigger: AppTooltipProps['trigger'] = ['click'];
|
||||
import { AppTooltip } from '@/components/ui/tooltip';
|
||||
import { CircleQuestion } from '@/components/ui/icons';
|
||||
import { Text } from '@/components/ui/typography';
|
||||
|
||||
export const TermIndividualHeaderSider: React.FC = () => {
|
||||
return (
|
||||
<div className="flex h-full w-full items-center justify-between">
|
||||
<Text>Details</Text>
|
||||
<div className="flex h-full items-center">
|
||||
<AppTooltip trigger={memoizedTrigger} title="Edit">
|
||||
<Text className="flex h-full! cursor-pointer items-center">
|
||||
<AppMaterialIcons size={18} icon="help" />
|
||||
<AppTooltip title="Edit">
|
||||
<Text className="flex h-full! cursor-pointer items-center text-lg">
|
||||
<CircleQuestion />
|
||||
</Text>
|
||||
</AppTooltip>
|
||||
</div>
|
||||
|
|
|
@ -34,8 +34,8 @@ export const SubmitButton: React.FC<SubmitButtonProps> = React.memo(
|
|||
<AppTooltip
|
||||
title={tooltipText}
|
||||
shortcuts={tooltipShortcuts}
|
||||
mouseEnterDelay={1.75}
|
||||
mouseLeaveDelay={0}>
|
||||
delayDuration={1.5}
|
||||
skipDelayDuration={0}>
|
||||
<motion.button
|
||||
onClick={onSubmitPreflight}
|
||||
disabled={disableSendButton}
|
||||
|
|
Loading…
Reference in New Issue