mirror of https://github.com/fantasticit/think.git
tiptap: improve mind toolbar
This commit is contained in:
parent
2f97380e63
commit
3b68238249
|
@ -82,7 +82,7 @@ define(function (require, exports, module) {
|
||||||
mask.fill(color[0]);
|
mask.fill(color[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
number.setContent(value);
|
number.setContent('P' + value);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,36 @@
|
||||||
|
const getProgressTitle = (index) => {
|
||||||
|
switch (index) {
|
||||||
|
case 0:
|
||||||
|
return '移除进度';
|
||||||
|
case 1:
|
||||||
|
return '未开始';
|
||||||
|
case 9:
|
||||||
|
return '全部完成';
|
||||||
|
default:
|
||||||
|
return '完成' + (index - 1) + '/8';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const PROGRESSES = Array.from({ length: 10 }, (_, i) => {
|
||||||
|
return {
|
||||||
|
text: getProgressTitle(i),
|
||||||
|
value: i,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
export const PRIORITIES = [
|
||||||
|
{
|
||||||
|
text: '移除优先级',
|
||||||
|
value: 0,
|
||||||
|
},
|
||||||
|
...Array.from({ length: 9 }, (_, i) => {
|
||||||
|
return {
|
||||||
|
text: `P${i + 1}`,
|
||||||
|
value: i + 1,
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
|
||||||
export const TEMPLATES = [
|
export const TEMPLATES = [
|
||||||
{
|
{
|
||||||
label: '经典',
|
label: '经典',
|
||||||
|
|
|
@ -65,6 +65,12 @@ export const MindSettingModal: React.FC<IProps> = ({ editor }) => {
|
||||||
};
|
};
|
||||||
}, [editor, toggleVisible]);
|
}, [editor, toggleVisible]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!visible && mind) {
|
||||||
|
mind.destroy();
|
||||||
|
}
|
||||||
|
}, [visible, mind]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
centered
|
centered
|
||||||
|
@ -75,6 +81,7 @@ export const MindSettingModal: React.FC<IProps> = ({ editor }) => {
|
||||||
onOk={save}
|
onOk={save}
|
||||||
okText="保存"
|
okText="保存"
|
||||||
cancelText="退出"
|
cancelText="退出"
|
||||||
|
motion={false}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
import { IconMark } from '@douyinfe/semi-icons';
|
||||||
|
import { Button, Tooltip } from '@douyinfe/semi-ui';
|
||||||
|
import { ColorPicker } from 'components/color-picker';
|
||||||
|
|
||||||
|
export const BgColor = ({ bgColor, selectedNode, setBackgroundColor }) => {
|
||||||
|
return (
|
||||||
|
<ColorPicker
|
||||||
|
onSetColor={(color) => {
|
||||||
|
setBackgroundColor(color);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Tooltip content="背景色" zIndex={10000}>
|
||||||
|
<Button
|
||||||
|
disabled={!selectedNode}
|
||||||
|
type="tertiary"
|
||||||
|
theme={bgColor ? 'light' : 'borderless'}
|
||||||
|
icon={
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
alignItems: 'center',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<IconMark />
|
||||||
|
<span
|
||||||
|
style={{
|
||||||
|
width: 12,
|
||||||
|
height: 2,
|
||||||
|
backgroundColor: bgColor,
|
||||||
|
}}
|
||||||
|
></span>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
</ColorPicker>
|
||||||
|
);
|
||||||
|
};
|
|
@ -0,0 +1,39 @@
|
||||||
|
import { IconFont } from '@douyinfe/semi-icons';
|
||||||
|
import { Button, Tooltip } from '@douyinfe/semi-ui';
|
||||||
|
import { ColorPicker } from 'components/color-picker';
|
||||||
|
|
||||||
|
export const FontColor = ({ selectedNode, setFontColor, textColor }) => {
|
||||||
|
return (
|
||||||
|
<ColorPicker
|
||||||
|
onSetColor={(color) => {
|
||||||
|
setFontColor(color);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Tooltip content="文本色" zIndex={10000}>
|
||||||
|
<Button
|
||||||
|
disabled={!selectedNode}
|
||||||
|
type="tertiary"
|
||||||
|
theme={textColor ? 'light' : 'borderless'}
|
||||||
|
icon={
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
alignItems: 'center',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<IconFont />
|
||||||
|
<span
|
||||||
|
style={{
|
||||||
|
width: 12,
|
||||||
|
height: 2,
|
||||||
|
backgroundColor: textColor,
|
||||||
|
}}
|
||||||
|
></span>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
</ColorPicker>
|
||||||
|
);
|
||||||
|
};
|
|
@ -0,0 +1,33 @@
|
||||||
|
import { IconHelpCircle } from '@douyinfe/semi-icons';
|
||||||
|
import { Button, Descriptions, Popover } from '@douyinfe/semi-ui';
|
||||||
|
|
||||||
|
import styles from './index.module.scss';
|
||||||
|
|
||||||
|
const HELP_MESSAGE = [
|
||||||
|
{ key: '新增同级节点', value: 'Enter 键' },
|
||||||
|
{ key: '新增子节点', value: 'Tab 键' },
|
||||||
|
{ key: '编辑节点文字', value: '双击节点' },
|
||||||
|
{ key: '编辑节点菜单', value: '在节点右键' },
|
||||||
|
];
|
||||||
|
|
||||||
|
const HELP_MESSAGE_STYLE = {
|
||||||
|
width: '200px',
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Help = () => {
|
||||||
|
return (
|
||||||
|
<Popover
|
||||||
|
zIndex={10000}
|
||||||
|
spacing={10}
|
||||||
|
style={{ padding: 12, overflow: 'hidden' }}
|
||||||
|
position="bottomLeft"
|
||||||
|
content={
|
||||||
|
<section className={styles.sectionWrap}>
|
||||||
|
<Descriptions data={HELP_MESSAGE} style={HELP_MESSAGE_STYLE} />
|
||||||
|
</section>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Button size="small" theme="borderless" type="tertiary" icon={<IconHelpCircle />} />
|
||||||
|
</Popover>
|
||||||
|
);
|
||||||
|
};
|
|
@ -1,4 +1,4 @@
|
||||||
import { IconFile } from '@douyinfe/semi-icons';
|
import { IconImage } from '@douyinfe/semi-icons';
|
||||||
import { Button, Dropdown, Form, Tooltip } from '@douyinfe/semi-ui';
|
import { Button, Dropdown, Form, Tooltip } from '@douyinfe/semi-ui';
|
||||||
import { FormApi } from '@douyinfe/semi-ui/lib/es/form';
|
import { FormApi } from '@douyinfe/semi-ui/lib/es/form';
|
||||||
import { Upload } from 'components/upload';
|
import { Upload } from 'components/upload';
|
||||||
|
@ -48,7 +48,7 @@ export const Image = ({ disabled, image, setImage }) => {
|
||||||
>
|
>
|
||||||
<span style={{ display: 'inline-block' }}>
|
<span style={{ display: 'inline-block' }}>
|
||||||
<Tooltip content="设置图片" zIndex={10000}>
|
<Tooltip content="设置图片" zIndex={10000}>
|
||||||
<Button disabled={disabled} type="tertiary" theme={image ? 'light' : 'borderless'} icon={<IconFile />} />
|
<Button disabled={disabled} type="tertiary" theme={image ? 'light' : 'borderless'} icon={<IconImage />} />
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</span>
|
</span>
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
|
|
|
@ -1,108 +1,188 @@
|
||||||
import { IconBold, IconFont, IconHelpCircle, IconMark } from '@douyinfe/semi-icons';
|
import { IconBold, IconRedo, IconUndo } from '@douyinfe/semi-icons';
|
||||||
import { Button, Descriptions, Popover, Space, Tooltip, Typography } from '@douyinfe/semi-ui';
|
import { Button, Space, Tooltip } from '@douyinfe/semi-ui';
|
||||||
import cls from 'classnames';
|
import { Divider } from 'components/divider';
|
||||||
import { ColorPicker } from 'components/color-picker';
|
import { IconMindCenter } from 'components/icons';
|
||||||
import { IconDrawBoard, IconMindCenter, IconStructure } from 'components/icons';
|
|
||||||
import { IconZoomIn, IconZoomOut } from 'components/icons';
|
import { IconZoomIn, IconZoomOut } from 'components/icons';
|
||||||
import { useToggle } from 'hooks/use-toggle';
|
import { useToggle } from 'hooks/use-toggle';
|
||||||
import { useCallback, useEffect, useState } from 'react';
|
import { useCallback, useEffect, useState } from 'react';
|
||||||
import { clamp } from 'tiptap/prose-utils';
|
|
||||||
|
|
||||||
import { MAX_ZOOM, MIN_ZOOM, TEMPLATES, THEMES, ZOOM_STEP } from '../constant';
|
import { BgColor } from './bgcolor';
|
||||||
|
import { FontColor } from './font-color';
|
||||||
|
import { Help } from './help';
|
||||||
import { Image } from './image';
|
import { Image } from './image';
|
||||||
import styles from './index.module.scss';
|
|
||||||
import { Link } from './link';
|
import { Link } from './link';
|
||||||
|
import { Priority } from './priority';
|
||||||
const { Text } = Typography;
|
import { Progress } from './progress';
|
||||||
|
import { Template } from './template';
|
||||||
const HELP_MESSAGE = [
|
import { Theme } from './theme';
|
||||||
{ key: '新增同级节点', value: 'Enter 键' },
|
|
||||||
{ key: '新增子节点', value: 'Tab 键' },
|
|
||||||
{ key: '编辑节点文字', value: '双击节点' },
|
|
||||||
{ key: '编辑节点菜单', value: '在节点右键' },
|
|
||||||
];
|
|
||||||
|
|
||||||
const HELP_MESSAGE_STYLE = {
|
|
||||||
width: '200px',
|
|
||||||
};
|
|
||||||
|
|
||||||
export const Toolbar = ({ mind }) => {
|
export const Toolbar = ({ mind }) => {
|
||||||
const [template, setTemplateState] = useState('');
|
const [node, setNode] = useState(null); // 当前选择节点
|
||||||
const [theme, setThemeState] = useState('');
|
|
||||||
const [node, setNode] = useState(null);
|
const [hasUndo, toggleHasUndo] = useToggle(false);
|
||||||
|
const [hasRedo, toggleHasRedo] = useToggle(false);
|
||||||
|
|
||||||
const [isBold, toggleIsBold] = useToggle(false);
|
const [isBold, toggleIsBold] = useToggle(false);
|
||||||
const [textColor, setTextColor] = useState('');
|
const [textColor, setTextColor] = useState('');
|
||||||
const [bgColor, setBgColor] = useState('');
|
const [bgColor, setBgColor] = useState('');
|
||||||
const [link, setLink] = useState('');
|
const [link, setLink] = useState('');
|
||||||
const [image, setImage] = useState('');
|
const [image, setImage] = useState('');
|
||||||
|
|
||||||
const setTemplate = useCallback(
|
const [template, setTemplateState] = useState('');
|
||||||
(template) => {
|
const [theme, setThemeState] = useState('');
|
||||||
mind.execCommand('template', template);
|
|
||||||
},
|
|
||||||
[mind]
|
|
||||||
);
|
|
||||||
|
|
||||||
const setTheme = useCallback(
|
/**
|
||||||
(theme) => {
|
* 撤销
|
||||||
mind.execCommand('theme', theme);
|
*/
|
||||||
},
|
const undo = useCallback(() => {
|
||||||
[mind]
|
|
||||||
);
|
|
||||||
|
|
||||||
const setZoom = useCallback(
|
|
||||||
(type: 'minus' | 'plus') => {
|
|
||||||
return () => {
|
|
||||||
if (!mind) return;
|
if (!mind) return;
|
||||||
const currentZoom = mind.getZoomValue();
|
if (mind.editor.history.hasUndo()) {
|
||||||
const nextZoom = clamp(
|
mind.editor.history.undo();
|
||||||
type === 'minus' ? currentZoom - ZOOM_STEP : currentZoom + ZOOM_STEP,
|
}
|
||||||
MIN_ZOOM,
|
|
||||||
MAX_ZOOM
|
|
||||||
);
|
|
||||||
mind.zoom(nextZoom);
|
|
||||||
};
|
|
||||||
},
|
|
||||||
[mind]
|
|
||||||
);
|
|
||||||
|
|
||||||
const setCenter = useCallback(() => {
|
|
||||||
if (!mind) return;
|
|
||||||
mind.execCommand('camera');
|
|
||||||
}, [mind]);
|
}, [mind]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重做
|
||||||
|
*/
|
||||||
|
const redo = useCallback(() => {
|
||||||
|
if (!mind) return;
|
||||||
|
if (mind.editor.history.hasRedo()) {
|
||||||
|
mind.editor.history.redo();
|
||||||
|
}
|
||||||
|
}, [mind]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加粗
|
||||||
|
*/
|
||||||
const toggleBold = useCallback(() => {
|
const toggleBold = useCallback(() => {
|
||||||
|
if (!mind) return;
|
||||||
|
|
||||||
mind.execCommand('Bold');
|
mind.execCommand('Bold');
|
||||||
}, [mind]);
|
}, [mind]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置文字颜色
|
||||||
|
*/
|
||||||
const setFontColor = useCallback(
|
const setFontColor = useCallback(
|
||||||
(color) => {
|
(color) => {
|
||||||
|
if (!mind) return;
|
||||||
|
|
||||||
mind.execCommand('ForeColor', color);
|
mind.execCommand('ForeColor', color);
|
||||||
},
|
},
|
||||||
[mind]
|
[mind]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置背景色
|
||||||
|
*/
|
||||||
const setBackgroundColor = useCallback(
|
const setBackgroundColor = useCallback(
|
||||||
(color) => {
|
(color) => {
|
||||||
|
if (!mind) return;
|
||||||
|
|
||||||
mind.execCommand('Background', color);
|
mind.execCommand('Background', color);
|
||||||
},
|
},
|
||||||
[mind]
|
[mind]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置链接
|
||||||
|
*/
|
||||||
const setHyperLink = useCallback(
|
const setHyperLink = useCallback(
|
||||||
(url) => {
|
(url) => {
|
||||||
|
if (!mind) return;
|
||||||
|
|
||||||
mind.execCommand('HyperLink', url);
|
mind.execCommand('HyperLink', url);
|
||||||
},
|
},
|
||||||
[mind]
|
[mind]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 插入图片
|
||||||
|
*/
|
||||||
const insertImage = useCallback(
|
const insertImage = useCallback(
|
||||||
(url) => {
|
(url) => {
|
||||||
|
if (!mind) return;
|
||||||
|
|
||||||
mind.execCommand('Image', url);
|
mind.execCommand('Image', url);
|
||||||
},
|
},
|
||||||
[mind]
|
[mind]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置进度
|
||||||
|
*/
|
||||||
|
const setProgress = useCallback(
|
||||||
|
(value) => () => {
|
||||||
|
if (!mind) return;
|
||||||
|
|
||||||
|
const node = mind.getSelectedNode();
|
||||||
|
if (!node) return;
|
||||||
|
|
||||||
|
mind.execCommand('progress', value);
|
||||||
|
},
|
||||||
|
[mind]
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置优先级
|
||||||
|
*/
|
||||||
|
const setPriority = useCallback(
|
||||||
|
(value) => () => {
|
||||||
|
if (!mind) return;
|
||||||
|
|
||||||
|
const node = mind.getSelectedNode();
|
||||||
|
if (!node) return;
|
||||||
|
|
||||||
|
mind.execCommand('priority', value);
|
||||||
|
},
|
||||||
|
[mind]
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 模板
|
||||||
|
*/
|
||||||
|
const setTemplate = useCallback(
|
||||||
|
(template) => {
|
||||||
|
if (!mind) return;
|
||||||
|
|
||||||
|
mind.execCommand('template', template);
|
||||||
|
},
|
||||||
|
[mind]
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 主题
|
||||||
|
*/
|
||||||
|
const setTheme = useCallback(
|
||||||
|
(theme) => {
|
||||||
|
if (!mind) return;
|
||||||
|
|
||||||
|
mind.execCommand('theme', theme);
|
||||||
|
},
|
||||||
|
[mind]
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 缩放
|
||||||
|
*/
|
||||||
|
const setZoom = useCallback(
|
||||||
|
(type: 'minus' | 'plus') => {
|
||||||
|
return () => {
|
||||||
|
if (!mind) return;
|
||||||
|
mind.execCommand(type === 'minus' ? 'zoomOut' : 'zoomIn');
|
||||||
|
};
|
||||||
|
},
|
||||||
|
[mind]
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 定位到根节点
|
||||||
|
*/
|
||||||
|
const setCenter = useCallback(() => {
|
||||||
|
if (!mind) return;
|
||||||
|
mind.execCommand('camera', mind.getRoot(), 600);
|
||||||
|
}, [mind]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!mind) return;
|
if (!mind) return;
|
||||||
|
|
||||||
|
@ -126,6 +206,9 @@ export const Toolbar = ({ mind }) => {
|
||||||
setNode(null);
|
setNode(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
toggleHasUndo(mind.editor.history.hasUndo());
|
||||||
|
toggleHasRedo(mind.editor.history.hasRedo());
|
||||||
|
|
||||||
setTemplateState(mind.queryCommandValue('Template'));
|
setTemplateState(mind.queryCommandValue('Template'));
|
||||||
setThemeState(mind.queryCommandValue('Theme'));
|
setThemeState(mind.queryCommandValue('Theme'));
|
||||||
toggleIsBold(isBold);
|
toggleIsBold(isBold);
|
||||||
|
@ -140,68 +223,53 @@ export const Toolbar = ({ mind }) => {
|
||||||
return () => {
|
return () => {
|
||||||
mind.off('interactchange', handler);
|
mind.off('interactchange', handler);
|
||||||
};
|
};
|
||||||
}, [mind, toggleIsBold, setBackgroundColor]);
|
}, [mind, toggleHasUndo, toggleHasRedo, toggleIsBold, setBackgroundColor]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Space>
|
<Space>
|
||||||
<Popover
|
<Tooltip content="撤销">
|
||||||
zIndex={10000}
|
<Button
|
||||||
spacing={10}
|
onClick={undo}
|
||||||
style={{ padding: '0 12px 12px', overflow: 'hidden' }}
|
icon={<IconUndo />}
|
||||||
position="bottomLeft"
|
disabled={!hasUndo}
|
||||||
content={
|
theme={hasUndo ? 'light' : 'borderless'}
|
||||||
<section className={styles.sectionWrap}>
|
type="tertiary"
|
||||||
<Text type="secondary">布局</Text>
|
/>
|
||||||
<div>
|
</Tooltip>
|
||||||
<ul>
|
|
||||||
{TEMPLATES.map((item) => {
|
|
||||||
return (
|
|
||||||
<li
|
|
||||||
key={item.label}
|
|
||||||
className={cls(template === item.value && styles.active)}
|
|
||||||
onClick={() => setTemplate(item.value)}
|
|
||||||
>
|
|
||||||
<Text>{item.label}</Text>
|
|
||||||
</li>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<Button icon={<IconStructure />} type="tertiary" theme="borderless" size="small" />
|
|
||||||
</Popover>
|
|
||||||
|
|
||||||
<Popover
|
<Tooltip content="重做">
|
||||||
zIndex={10000}
|
<Button
|
||||||
spacing={10}
|
onClick={redo}
|
||||||
style={{ padding: '0 12px 12px', overflow: 'hidden' }}
|
icon={<IconRedo />}
|
||||||
position="bottomLeft"
|
disabled={!hasRedo}
|
||||||
content={
|
theme={hasRedo ? 'light' : 'borderless'}
|
||||||
<section className={styles.sectionWrap}>
|
type="tertiary"
|
||||||
<Text type="secondary">主题</Text>
|
/>
|
||||||
<div>
|
</Tooltip>
|
||||||
<ul>
|
|
||||||
{THEMES.map((item) => {
|
<Divider />
|
||||||
return (
|
|
||||||
<li
|
<Tooltip content="加粗" zIndex={10000}>
|
||||||
key={item.label}
|
<Button
|
||||||
className={cls(theme === item.value && styles.active)}
|
disabled={!node}
|
||||||
style={item.style || {}}
|
theme={isBold ? 'light' : 'borderless'}
|
||||||
onClick={() => setTheme(item.value)}
|
type="tertiary"
|
||||||
>
|
onClick={toggleBold}
|
||||||
{item.label}
|
icon={<IconBold />}
|
||||||
</li>
|
/>
|
||||||
);
|
</Tooltip>
|
||||||
})}
|
|
||||||
</ul>
|
<FontColor selectedNode={node} textColor={textColor} setFontColor={setFontColor} />
|
||||||
</div>
|
<BgColor selectedNode={node} bgColor={bgColor} setBackgroundColor={setBackgroundColor} />
|
||||||
</section>
|
<Link disabled={!node} link={link} setLink={setHyperLink} />
|
||||||
}
|
<Image disabled={!node} image={image} setImage={insertImage} />
|
||||||
>
|
|
||||||
<Button icon={<IconDrawBoard />} type="tertiary" theme="borderless" size="small" />
|
<Divider />
|
||||||
</Popover>
|
|
||||||
|
<Progress selectedNode={node} setProgress={setProgress} />
|
||||||
|
<Priority selectedNode={node} setPriority={setPriority} />
|
||||||
|
|
||||||
|
<Divider />
|
||||||
|
|
||||||
<Tooltip content="居中">
|
<Tooltip content="居中">
|
||||||
<Button
|
<Button
|
||||||
|
@ -233,97 +301,14 @@ export const Toolbar = ({ mind }) => {
|
||||||
/>
|
/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
|
||||||
<Tooltip content="加粗" zIndex={10000}>
|
<Divider />
|
||||||
<Button
|
|
||||||
disabled={!node}
|
|
||||||
type="tertiary"
|
|
||||||
theme={isBold ? 'light' : 'borderless'}
|
|
||||||
onClick={toggleBold}
|
|
||||||
icon={<IconBold />}
|
|
||||||
/>
|
|
||||||
</Tooltip>
|
|
||||||
|
|
||||||
<ColorPicker
|
<Template template={template} setTemplate={setTemplate} />
|
||||||
onSetColor={(color) => {
|
<Theme theme={theme} setTheme={setTheme} />
|
||||||
setFontColor(color);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Tooltip content="文本色" zIndex={10000}>
|
|
||||||
<Button
|
|
||||||
disabled={!node}
|
|
||||||
type="tertiary"
|
|
||||||
theme={textColor ? 'light' : 'borderless'}
|
|
||||||
icon={
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
display: 'flex',
|
|
||||||
flexDirection: 'column',
|
|
||||||
alignItems: 'center',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<IconFont />
|
|
||||||
<span
|
|
||||||
style={{
|
|
||||||
width: 12,
|
|
||||||
height: 2,
|
|
||||||
backgroundColor: textColor,
|
|
||||||
}}
|
|
||||||
></span>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</Tooltip>
|
|
||||||
</ColorPicker>
|
|
||||||
|
|
||||||
<ColorPicker
|
<Divider />
|
||||||
onSetColor={(color) => {
|
|
||||||
setBackgroundColor(color);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Tooltip content="背景色" zIndex={10000}>
|
|
||||||
<Button
|
|
||||||
disabled={!node}
|
|
||||||
type="tertiary"
|
|
||||||
theme={bgColor ? 'light' : 'borderless'}
|
|
||||||
icon={
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
display: 'flex',
|
|
||||||
flexDirection: 'column',
|
|
||||||
alignItems: 'center',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<IconMark />
|
|
||||||
<span
|
|
||||||
style={{
|
|
||||||
width: 12,
|
|
||||||
height: 2,
|
|
||||||
backgroundColor: bgColor,
|
|
||||||
}}
|
|
||||||
></span>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</Tooltip>
|
|
||||||
</ColorPicker>
|
|
||||||
|
|
||||||
<Link disabled={!node} link={link} setLink={setHyperLink} />
|
<Help />
|
||||||
|
|
||||||
<Image disabled={!node} image={image} setImage={insertImage} />
|
|
||||||
|
|
||||||
<Popover
|
|
||||||
zIndex={10000}
|
|
||||||
spacing={10}
|
|
||||||
style={{ padding: 12, overflow: 'hidden' }}
|
|
||||||
position="bottomLeft"
|
|
||||||
content={
|
|
||||||
<section className={styles.sectionWrap}>
|
|
||||||
<Descriptions data={HELP_MESSAGE} style={HELP_MESSAGE_STYLE} />
|
|
||||||
</section>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<Button size="small" theme="borderless" type="tertiary" icon={<IconHelpCircle />} />
|
|
||||||
</Popover>
|
|
||||||
</Space>
|
</Space>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
import { IconClock } from '@douyinfe/semi-icons';
|
||||||
|
import { Button, Dropdown, Tooltip } from '@douyinfe/semi-ui';
|
||||||
|
|
||||||
|
import { PRIORITIES } from '../constant';
|
||||||
|
|
||||||
|
export const Priority = ({ selectedNode, setPriority }) => {
|
||||||
|
return (
|
||||||
|
<Dropdown
|
||||||
|
trigger="click"
|
||||||
|
render={
|
||||||
|
<Dropdown.Menu>
|
||||||
|
{PRIORITIES.map((item) => {
|
||||||
|
return (
|
||||||
|
<Dropdown.Item key={item.value} onClick={setPriority(item.value)}>
|
||||||
|
{item.text}
|
||||||
|
</Dropdown.Item>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Dropdown.Menu>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
<Tooltip content="优先级" zIndex={10000}>
|
||||||
|
<Button size="small" theme="borderless" type="tertiary" disabled={!selectedNode} icon={<IconClock />} />
|
||||||
|
</Tooltip>
|
||||||
|
</span>
|
||||||
|
</Dropdown>
|
||||||
|
);
|
||||||
|
};
|
|
@ -0,0 +1,29 @@
|
||||||
|
import { IconDuration } from '@douyinfe/semi-icons';
|
||||||
|
import { Button, Dropdown, Tooltip } from '@douyinfe/semi-ui';
|
||||||
|
|
||||||
|
import { PROGRESSES } from '../constant';
|
||||||
|
|
||||||
|
export const Progress = ({ selectedNode, setProgress }) => {
|
||||||
|
return (
|
||||||
|
<Dropdown
|
||||||
|
trigger="click"
|
||||||
|
render={
|
||||||
|
<Dropdown.Menu>
|
||||||
|
{PROGRESSES.map((progress) => {
|
||||||
|
return (
|
||||||
|
<Dropdown.Item key={progress.value} onClick={setProgress(progress.value)}>
|
||||||
|
{progress.text}
|
||||||
|
</Dropdown.Item>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Dropdown.Menu>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
<Tooltip content="进度" zIndex={10000}>
|
||||||
|
<Button size="small" theme="borderless" type="tertiary" disabled={!selectedNode} icon={<IconDuration />} />
|
||||||
|
</Tooltip>
|
||||||
|
</span>
|
||||||
|
</Dropdown>
|
||||||
|
);
|
||||||
|
};
|
|
@ -0,0 +1,41 @@
|
||||||
|
import { Button, Popover, Typography } from '@douyinfe/semi-ui';
|
||||||
|
import cls from 'classnames';
|
||||||
|
import { IconStructure } from 'components/icons';
|
||||||
|
|
||||||
|
import { TEMPLATES } from '../constant';
|
||||||
|
import styles from './index.module.scss';
|
||||||
|
|
||||||
|
const { Text } = Typography;
|
||||||
|
|
||||||
|
export const Template = ({ template, setTemplate }) => {
|
||||||
|
return (
|
||||||
|
<Popover
|
||||||
|
zIndex={10000}
|
||||||
|
spacing={10}
|
||||||
|
style={{ padding: '0 12px 12px', overflow: 'hidden' }}
|
||||||
|
position="bottomLeft"
|
||||||
|
content={
|
||||||
|
<section className={styles.sectionWrap}>
|
||||||
|
<Text type="secondary">布局</Text>
|
||||||
|
<div>
|
||||||
|
<ul>
|
||||||
|
{TEMPLATES.map((item) => {
|
||||||
|
return (
|
||||||
|
<li
|
||||||
|
key={item.label}
|
||||||
|
className={cls(template === item.value && styles.active)}
|
||||||
|
onClick={() => setTemplate(item.value)}
|
||||||
|
>
|
||||||
|
<Text>{item.label}</Text>
|
||||||
|
</li>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Button icon={<IconStructure />} type="tertiary" theme="borderless" size="small" />
|
||||||
|
</Popover>
|
||||||
|
);
|
||||||
|
};
|
|
@ -0,0 +1,42 @@
|
||||||
|
import { Button, Popover, Typography } from '@douyinfe/semi-ui';
|
||||||
|
import cls from 'classnames';
|
||||||
|
import { IconDrawBoard } from 'components/icons';
|
||||||
|
|
||||||
|
import { THEMES } from '../constant';
|
||||||
|
import styles from './index.module.scss';
|
||||||
|
|
||||||
|
const { Text } = Typography;
|
||||||
|
|
||||||
|
export const Theme = ({ theme, setTheme }) => {
|
||||||
|
return (
|
||||||
|
<Popover
|
||||||
|
zIndex={10000}
|
||||||
|
spacing={10}
|
||||||
|
style={{ padding: '0 12px 12px', overflow: 'hidden' }}
|
||||||
|
position="bottomLeft"
|
||||||
|
content={
|
||||||
|
<section className={styles.sectionWrap}>
|
||||||
|
<Text type="secondary">主题</Text>
|
||||||
|
<div>
|
||||||
|
<ul>
|
||||||
|
{THEMES.map((item) => {
|
||||||
|
return (
|
||||||
|
<li
|
||||||
|
key={item.label}
|
||||||
|
className={cls(theme === item.value && styles.active)}
|
||||||
|
style={item.style || {}}
|
||||||
|
onClick={() => setTheme(item.value)}
|
||||||
|
>
|
||||||
|
{item.label}
|
||||||
|
</li>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Button icon={<IconDrawBoard />} type="tertiary" theme="borderless" size="small" />
|
||||||
|
</Popover>
|
||||||
|
);
|
||||||
|
};
|
Loading…
Reference in New Issue