Skip to content

Commit

Permalink
Merge pull request #1490 from merico-dev/1469-add-gradient-color-feat…
Browse files Browse the repository at this point in the history
…ure-to-rich-text

1469 add color-mapping feature to rich text
  • Loading branch information
GerilLeto authored Aug 2, 2024
2 parents 50f0dec + 2b3e350 commit 2a877f7
Show file tree
Hide file tree
Showing 22 changed files with 792 additions and 23 deletions.
2 changes: 1 addition & 1 deletion api/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@devtable/api",
"version": "13.27.15",
"version": "13.28.1",
"description": "",
"main": "index.js",
"scripts": {
Expand Down
4 changes: 3 additions & 1 deletion dashboard/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@devtable/dashboard",
"version": "13.27.15",
"version": "13.28.1",
"license": "Apache-2.0",
"publishConfig": {
"access": "public",
Expand Down Expand Up @@ -92,6 +92,7 @@
"@tiptap/starter-kit": "2.0.3",
"@types/crypto-js": "v4.1.1",
"@types/d3-array": "3.0.4",
"@types/d3-scale": "4.0.8",
"@types/file-saver": "2.0.5",
"@types/lodash": "^4.14.182",
"@types/react": "^18.0.0",
Expand Down Expand Up @@ -160,6 +161,7 @@
"crypto-js": "^4.1.1",
"d3-array": "3.2.3",
"d3-regression": "1.3.10",
"d3-scale": "4.0.2",
"dayjs": "1.11.9",
"echarts": "5.4.1",
"echarts-for-react": "3.0.2",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './variable-selector';
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { Box, Group, Text } from '@mantine/core';
import { useHover } from '@mantine/hooks';
import { forwardRef } from 'react';

interface ItemProps extends React.ComponentPropsWithoutRef<'div'> {
label: string;
value: string;
aggValue: string;
formattedValue: string;
preview: 'aggregated' | 'formatted';
}

export const VariableSelectorItem = forwardRef<HTMLDivElement, ItemProps>(
({ aggValue, formattedValue, label, preview, ...others }: ItemProps, ref) => {
const { hovered, ref: hoverRef } = useHover();

const defaultPreview = preview === 'aggregated' ? aggValue : formattedValue;
const hoveredPreview = preview === 'aggregated' ? formattedValue : aggValue;
return (
<Box ref={hoverRef} {...others}>
<Group noWrap position="apart" ref={ref}>
<Text size="sm" sx={{ flexGrow: 1 }}>
{label}
</Text>
<Text size="xs" opacity={hovered ? 1 : 0.65} sx={{ flexShrink: 0 }}>
{hovered ? hoveredPreview : defaultPreview}
</Text>
</Group>
</Box>
);
},
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { Box, Group, HoverCard, Select, Sx, Text, TextInput } from '@mantine/core';
import { observer } from 'mobx-react-lite';
import React from 'react';
import { forwardRef } from 'react';
import { useTranslation } from 'react-i18next';
import { useEditPanelContext } from '~/contexts';
import { VariableSelectorItem } from './variable-selector-item';

type Props = {
label: string;
value: string;
onChange: (v: string) => void;
description?: string;
required?: boolean;
clearable?: boolean;
sx?: Sx;
preview?: 'aggregated' | 'formatted';
zIndex?: number;
};

export const VariableSelector = observer(
forwardRef<HTMLInputElement, Props>((props, ref) => {
const {
label,
value,
onChange,
description,
required,
clearable = true,
sx,
preview = 'formatted',
zIndex = 340,
} = props;
const { t } = useTranslation();
const { panel } = useEditPanelContext();
const options = React.useMemo(() => {
return panel.variableOptions(value, clearable);
}, [value, clearable]);

if (options.length === 0) {
return <TextInput ref={ref} label={label} placeholder={value} readOnly disabled />;
}

return (
<Select
ref={ref}
label={label}
description={description}
itemComponent={(props) => <VariableSelectorItem preview={preview} {...props} />}
data={options}
value={value}
onChange={onChange}
required={required}
sx={sx}
maxDropdownHeight={500}
withinPortal
zIndex={zIndex}
/>
);
}),
);
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,10 @@ const ColorRow = ({ color, index, handleChange, handleRemove }: ColorRowProps) =
type Props = {
value: string[];
onChange: (v: string[]) => void;
zIndex?: number;
};

export const GradientEditor = forwardRef(({ value, onChange }: Props, ref: Ref<HTMLDivElement>) => {
export const GradientEditor = forwardRef(({ value, onChange, zIndex = 340 }: Props, ref: Ref<HTMLDivElement>) => {
const { t } = useTranslation();
const colors = useMemo(() => {
return value.map((value) => ({
Expand Down Expand Up @@ -114,7 +115,7 @@ export const GradientEditor = forwardRef(({ value, onChange }: Props, ref: Ref<H

return (
<Stack ref={ref}>
<PreviewGradientAndApplyPalette colors={value} applyPalette={replace} />
<PreviewGradientAndApplyPalette colors={value} applyPalette={replace} zIndex={zIndex} />
<DragDropProvider onDragEnd={onDragEnd}>
{colors.map((c, index) => (
<ColorRow
Expand All @@ -131,7 +132,7 @@ export const GradientEditor = forwardRef(({ value, onChange }: Props, ref: Ref<H
<div style={{ flex: 1 }}>
<ColorInput
withinPortal
dropdownZIndex={340}
dropdownZIndex={zIndex}
placeholder={t('chart.color.click_to_add_a_color')}
value={newColor}
onChange={setNewColor}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@ const palettes = getVisualMapPalettes();
type Props = {
colors: string[];
applyPalette: (colors: string[]) => void;
zIndex?: number;
};
export const PreviewGradientAndApplyPalette = ({ colors, applyPalette }: Props) => {
export const PreviewGradientAndApplyPalette = ({ colors, applyPalette, zIndex = 340 }: Props) => {
const { t } = useTranslation();
const backgroundImage = `linear-gradient(to right, ${colors.join(', ')})`;
return (
<Menu shadow="md" width={300}>
<Menu shadow="md" width={300} withinPortal zIndex={zIndex}>
<Menu.Target>
<UnstyledButton>
<Text
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
import { ActionIcon, Box, Modal, Tooltip, useMantineTheme } from '@mantine/core';
import { RichTextEditor } from '@mantine/tiptap';
import '@tiptap/extension-text-style';
import { Editor } from '@tiptap/react';
import { useBoolean } from 'ahooks';
import { useCallback, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { ChartTheme } from '~/styles/register-themes';
import { ColorMappingForm, ColorMappingFormValues } from './color-mapping-form';
import { ColorMappingName } from './color-mapping-mark';
import { parseColorMappingAttrs } from './utils';

const IconColorMapping = () => {
const theme = useMantineTheme();
return (
<div
style={{
width: '20px',
height: '13px',
borderRadius: '2px',
background: theme.fn.linearGradient(90, ...Object.values(ChartTheme.graphics.depth)),
}}
/>
);
};
const IconColorMappingOff = ({ disabled }: { disabled: boolean }) => {
const theme = useMantineTheme();
return (
<Box
sx={{
width: '16px',
height: '10px',
borderRadius: '2px',
background: theme.fn.linearGradient(90, ...Object.values(ChartTheme.graphics.depth)),
opacity: disabled ? '0.5' : 1,
position: 'relative',
'&:after': {
position: 'absolute',
content: "''",
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)',
width: '15px',
height: '15px',
background: `
linear-gradient(to top right,
rgba(0,0,0,0) 0%,
rgba(0,0,0,0) calc(50% - 1.4px),
rgba(255,255,255,1) calc(50% - 1.4px),
rgba(0,0,0,0) calc(50% - 0.8px),
rgba(0,0,0,1) 50%,
rgba(0,0,0,0) calc(50% + 0.8px),
rgba(255,255,255,1) calc(50% + 1.4px),
rgba(0,0,0,0) calc(50% + 1.4px),
rgba(0,0,0,0) 100%)`,
},
}}
/>
);
};

export const ColorMappingControl = ({ editor }: { editor: Editor }) => {
const { t } = useTranslation();
const [opened, { set: setOpened, setTrue: open, setFalse: close, toggle }] = useBoolean();
const attrs = editor.getAttributes(ColorMappingName);
const { empty, ...defaultValues } = useMemo(() => {
return parseColorMappingAttrs(attrs);
}, [attrs]);

const saveChanges = useCallback(
(values: ColorMappingFormValues) => {
editor.chain().focus().setColorMapping(values).run();
close();
},
[editor],
);
const unset = useCallback(() => {
editor.chain().focus().unsetColorMapping().run();
}, [editor]);

return (
<>
<Modal
size={500}
opened={opened}
onClose={close}
shadow="md"
withinPortal
zIndex={330}
closeOnClickOutside={false}
closeOnEscape={false}
title={t('rich_text.color_mapping.edit')}
styles={{
header: {
paddingBottom: 0,
},
body: {
padding: 0,
},
}}
>
<ColorMappingForm defaultValues={defaultValues} unset={unset} onSubmit={saveChanges} />
</Modal>
<RichTextEditor.ControlsGroup>
<Tooltip label={t('rich_text.color_mapping.label')}>
<ActionIcon
variant="default"
data-rich-text-editor-control="true"
sx={{
height: '26px',
minHeight: '26px',
lineHeight: '26px',
borderColor: '#ced4da !important',
color: '#000',
}}
onClick={open}
>
<IconColorMapping />
</ActionIcon>
</Tooltip>
<Tooltip label={t('rich_text.color_mapping.clear')}>
<ActionIcon
variant="default"
data-rich-text-editor-control="true"
sx={{
height: '26px',
minHeight: '26px',
lineHeight: '26px',
borderColor: '#ced4da !important',
}}
disabled={empty}
onClick={unset}
>
<IconColorMappingOff disabled={empty} />
</ActionIcon>
</Tooltip>
</RichTextEditor.ControlsGroup>
</>
);
};
Loading

0 comments on commit 2a877f7

Please sign in to comment.