fix:标题,图片设置。
This commit is contained in:
parent
3f97149a73
commit
72310d3278
|
@ -58,9 +58,7 @@
|
|||
"electron-store": "^8.1.0",
|
||||
"md5": "^2.3.0",
|
||||
"mousetrap": "^1.6.5",
|
||||
"node-sass": "^7.0.3",
|
||||
"redux-persist": "^6.0.0",
|
||||
"redux-persist-electron-storage": "^2.1.0"
|
||||
"redux-persist": "^6.0.0"
|
||||
},
|
||||
"browser": {
|
||||
"fs": false
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import {useEffect, useLayoutEffect} from 'react';
|
||||
import {CAN_USE_DOM} from './canUseDOM';
|
||||
import {CAN_USE_DOM} from '@/pages/Note/Hlexical/context/shared/canUseDOM';
|
||||
|
||||
const useLayoutEffectImpl = CAN_USE_DOM
|
||||
? useLayoutEffect
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import {useCallback, useMemo, useState} from 'react';
|
||||
import * as React from 'react';
|
||||
|
||||
import Modal from '../plugins/Input/Modal';
|
||||
import Modal from '@/pages/Note/Hlexical/plugins/Input/Modal';
|
||||
|
||||
export default function useModal(){
|
||||
const [modalContent, setModalContent] = useState(null);
|
||||
|
|
|
@ -34,6 +34,7 @@ import ContextMenuPlugin from "@/pages/Note/Hlexical/plugins/ContextMenuPlugin"
|
|||
import {Spin} from "antd";
|
||||
import {useState} from "react";
|
||||
import DragDropPaste from "@/pages/Note/Hlexical/plugins/DragDropPastePlugin";
|
||||
import TreeViewPlugin from "@/pages/Note/Hlexical/plugins/TreeViewPlugin";
|
||||
function Placeholder() {
|
||||
return <div className="editor-placeholder">记录一些灵感吧</div>;
|
||||
}
|
||||
|
@ -94,7 +95,7 @@ export default function Hlexical(props) {
|
|||
{/*markdown 快捷键*/}
|
||||
<MarkdownShortcutPlugin transformers={TRANSFORMERS}/>
|
||||
{/*图片加载*/}
|
||||
<ImagesPlugin/>
|
||||
<ImagesPlugin captionsEnabled={true}/>
|
||||
<InlineImagePlugin/>
|
||||
|
||||
{/*分割线 */}
|
||||
|
|
|
@ -225,22 +225,60 @@ h1 {
|
|||
}
|
||||
|
||||
.editor-heading-h1 {
|
||||
font-size: 24px;
|
||||
font-size: 50px;
|
||||
color: rgb(5, 5, 5);
|
||||
font-weight: 400;
|
||||
margin: 0;
|
||||
margin-bottom: 12px;
|
||||
margin-bottom: 25px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.editor-heading-h2 {
|
||||
font-size: 15px;
|
||||
color: rgb(101, 103, 107);
|
||||
font-weight: 700;
|
||||
font-size: 45px;
|
||||
//color: rgb(101, 103, 107);
|
||||
//font-weight: 400;
|
||||
color: rgb(5, 5, 5);
|
||||
font-weight: 400;
|
||||
margin: 0;
|
||||
margin-top: 10px;
|
||||
margin-top: 25px;
|
||||
padding: 0;
|
||||
text-transform: uppercase;
|
||||
//text-transform: uppercase;
|
||||
}
|
||||
.editor-heading-h3 {
|
||||
font-size: 40px;
|
||||
color: rgb(5, 5, 5);
|
||||
font-weight: 400;
|
||||
margin: 0;
|
||||
margin-top: 20px;
|
||||
padding: 0;
|
||||
//text-transform: uppercase;
|
||||
}
|
||||
.editor-heading-h4 {
|
||||
font-size: 35px;
|
||||
color: rgb(5, 5, 5);
|
||||
font-weight: 400;
|
||||
margin: 0;
|
||||
margin-top: 20px;
|
||||
padding: 0;
|
||||
//text-transform: uppercase;
|
||||
}
|
||||
.editor-heading-h5 {
|
||||
font-size: 30px;
|
||||
color: rgb(5, 5, 5);
|
||||
font-weight: 400;
|
||||
margin: 0;
|
||||
margin-top: 15px;
|
||||
padding: 0;
|
||||
//text-transform: uppercase;
|
||||
}
|
||||
.editor-heading-h6 {
|
||||
font-size: 25px;
|
||||
color: rgb(5, 5, 5);
|
||||
font-weight: 400;
|
||||
margin: 0;
|
||||
margin-top: 15px;
|
||||
padding: 0;
|
||||
//text-transform: uppercase;
|
||||
}
|
||||
|
||||
.editor-quote {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import '../index.less';
|
||||
import '@/pages/Note/Hlexical/nodes/ImageNode/index.less';
|
||||
import {AutoFocusPlugin} from '@lexical/react/LexicalAutoFocusPlugin';
|
||||
import {useCollaborationContext} from '@lexical/react/LexicalCollaborationContext';
|
||||
import {CollaborationPlugin} from '@lexical/react/LexicalCollaborationPlugin';
|
||||
|
@ -30,20 +30,25 @@ import {Suspense, useCallback, useEffect, useRef, useState} from 'react';
|
|||
// import {createWebsocketProvider} from '../../../createWebsocketProvider';
|
||||
|
||||
import {useSharedHistoryContext} from '../../../context/SharedHistoryContext';
|
||||
import EmojisPlugin from '../../../plugins/EmojisPlugin';
|
||||
import KeywordsPlugin from '../../../plugins/KeywordsPlugin';
|
||||
import LinkPlugin from '../../../plugins/LinkPlugin';
|
||||
import EmojisPlugin from '@/pages/Note/Hlexical/plugins/EmojisPlugin';
|
||||
import KeywordsPlugin from '@/pages/Note/Hlexical/plugins/KeywordsPlugin';
|
||||
import LinkPlugin from '@/pages/Note/Hlexical/plugins/LinkPlugin';
|
||||
|
||||
// import MentionsPlugin from '../../../plugins/MentionsPlugin';
|
||||
import TreeViewPlugin from '../../../plugins/TreeViewPlugin';
|
||||
import ContentEditable from '../../../plugins/Input/ContentEditable';
|
||||
import ImageResizer from '../../../plugins/Input/ImageResizer';
|
||||
import Placeholder from '../../../plugins/Input/Placeholder';
|
||||
|
||||
import {$isImageNode} from '../index';
|
||||
import TreeViewPlugin from '@/pages/Note/Hlexical/plugins/TreeViewPlugin';
|
||||
import ContentEditable from '@/pages/Note/Hlexical/plugins/Input/ContentEditable';
|
||||
import ImageResizer from '@/pages/Note/Hlexical/plugins/Input/ImageResizer';
|
||||
import Placeholder from '@/pages/Note/Hlexical/plugins/Input/Placeholder';
|
||||
|
||||
import {$isImageNode} from '@/pages/Note/Hlexical/nodes/ImageNode';
|
||||
import {Image as AntImage} from "antd";
|
||||
/*
|
||||
* 缓存图片,后期使用预览所有图片。
|
||||
*/
|
||||
const imageCache = new Set();
|
||||
|
||||
/*
|
||||
* 添加图片到缓存列表
|
||||
*/
|
||||
function useSuspenseImage(src) {
|
||||
if (!imageCache.has(src)) {
|
||||
throw new Promise((resolve) => {
|
||||
|
@ -59,16 +64,23 @@ function useSuspenseImage(src) {
|
|||
|
||||
function LazyImage({altText, className, imageRef, src, width, height, maxWidth,}) {
|
||||
useSuspenseImage(src);
|
||||
return (<img
|
||||
className={className || undefined}
|
||||
const [editor] = useLexicalComposerContext();
|
||||
return editor.isEditable()?(<img
|
||||
className={className || undefined}
|
||||
src={src}
|
||||
alt={altText}
|
||||
ref={imageRef}
|
||||
style={{
|
||||
height, maxWidth, width,
|
||||
}}
|
||||
draggable="false"
|
||||
/>):(<AntImage
|
||||
src={src}
|
||||
alt={altText}
|
||||
height={height}
|
||||
width={width}
|
||||
ref={imageRef}
|
||||
style={{
|
||||
height, maxWidth, width,
|
||||
}}
|
||||
draggable="false"
|
||||
/>);
|
||||
/>)
|
||||
}
|
||||
|
||||
export default function ImageComponent({
|
||||
|
@ -87,6 +99,7 @@ export default function ImageComponent({
|
|||
const buttonRef = useRef(null);
|
||||
const [isSelected, setSelected, clearSelection] = useLexicalNodeSelection(nodeKey);
|
||||
const [isResizing, setIsResizing] = useState(false);
|
||||
// 协作
|
||||
const {isCollabActive} = useCollaborationContext();
|
||||
const [editor] = useLexicalComposerContext();
|
||||
const [selection, setSelection] = useState(null);
|
||||
|
@ -139,6 +152,7 @@ export default function ImageComponent({
|
|||
}, [caption, editor, setSelected],);
|
||||
|
||||
useEffect(() => {
|
||||
// 增强
|
||||
let isMounted = true;
|
||||
const unregister = mergeRegister(
|
||||
editor.registerUpdateListener(({editorState}) => {
|
||||
|
@ -152,12 +166,15 @@ export default function ImageComponent({
|
|||
}, COMMAND_PRIORITY_LOW,),
|
||||
editor.registerCommand(CLICK_COMMAND, (payload) => {
|
||||
const event = payload;
|
||||
|
||||
console.log("点击图片:",event,isResizing)
|
||||
if (isResizing) {
|
||||
return true;
|
||||
}
|
||||
if (event.target === imageRef.current) {
|
||||
if (event.shiftKey) {
|
||||
if (event.ctrlKey){
|
||||
// ctrl 预览图片
|
||||
}else if (event.shiftKey) {
|
||||
// shift反选
|
||||
setSelected(!isSelected);
|
||||
} else {
|
||||
clearSelection();
|
||||
|
@ -168,6 +185,7 @@ export default function ImageComponent({
|
|||
|
||||
return false;
|
||||
}, COMMAND_PRIORITY_LOW,),
|
||||
// 拖拽
|
||||
editor.registerCommand(DRAGSTART_COMMAND, (event) => {
|
||||
if (event.target === imageRef.current) {
|
||||
// TODO This is just a temporary workaround for FF to behave like other browsers.
|
||||
|
@ -191,6 +209,7 @@ export default function ImageComponent({
|
|||
editor.update(() => {
|
||||
const node = $getNodeByKey(nodeKey);
|
||||
if ($isImageNode(node)) {
|
||||
// 展示说明文字
|
||||
node.setShowCaption(true);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -3,7 +3,7 @@ import * as React from 'react';
|
|||
import {Suspense} from 'react';
|
||||
|
||||
const ImageComponent = React.lazy(
|
||||
() => import('./ImageComponent'),
|
||||
() => import('@/pages/Note/Hlexical/nodes/ImageNode/ImageComponent'),
|
||||
);
|
||||
|
||||
function convertImageElement(domNode) {
|
||||
|
@ -15,17 +15,18 @@ function convertImageElement(domNode) {
|
|||
return null;
|
||||
}
|
||||
|
||||
|
||||
export class ImageNode extends DecoratorNode {
|
||||
// 路径
|
||||
__src;
|
||||
__altText;
|
||||
// 大小
|
||||
__width;
|
||||
__height;
|
||||
__maxWidth;
|
||||
// 图片文字说明
|
||||
__showCaption;
|
||||
__caption;
|
||||
__captionsEnabled;
|
||||
|
||||
static getType() {
|
||||
return 'image';
|
||||
}
|
||||
|
@ -154,6 +155,7 @@ export class ImageNode extends DecoratorNode {
|
|||
}
|
||||
|
||||
decorate() {
|
||||
console.log('ImageNode.decorate()')
|
||||
return (
|
||||
<Suspense fallback={null}>
|
||||
<ImageComponent
|
||||
|
@ -176,7 +178,7 @@ export class ImageNode extends DecoratorNode {
|
|||
export function $createImageNode({
|
||||
altText,
|
||||
height,
|
||||
maxWidth = 500,
|
||||
maxWidth = 600,
|
||||
captionsEnabled,
|
||||
src,
|
||||
width,
|
||||
|
|
|
@ -41,3 +41,236 @@
|
|||
.image-control-wrapper--resizing {
|
||||
touch-action: none;
|
||||
}
|
||||
|
||||
.editor-container span.editor-image {
|
||||
cursor: default;
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.editor-container .editor-image img {
|
||||
max-width: 200%;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.editor-container .editor-image img.focused {
|
||||
outline: 2px solid rgb(60, 132, 244);
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.editor-container .editor-image img.focused.draggable {
|
||||
cursor: grab;
|
||||
}
|
||||
|
||||
.editor-container .editor-image img.focused.draggable:active {
|
||||
cursor: grabbing;
|
||||
}
|
||||
|
||||
.editor-container .editor-image .image-caption-container .tree-view-output {
|
||||
margin: 0;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.editor-container .editor-image .image-caption-container {
|
||||
display: block;
|
||||
position: absolute;
|
||||
bottom: 4px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border-top: 1px solid #fff;
|
||||
background-color: rgba(255, 255, 255, 0.9);
|
||||
min-width: 100px;
|
||||
color: #000;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.editor-container .editor-image .image-caption-button {
|
||||
display: block;
|
||||
position: absolute;
|
||||
bottom: 20px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
width: 30%;
|
||||
padding: 10px;
|
||||
margin: 0 auto;
|
||||
border: 1px solid rgba(255, 255, 255, 0.3);
|
||||
border-radius: 5px;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
min-width: 100px;
|
||||
color: #fff;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.editor-container .editor-image .image-caption-button:hover {
|
||||
background-color: rgba(60, 132, 244, 0.5);
|
||||
}
|
||||
|
||||
.editor-container .editor-image .image-edit-button {
|
||||
border: 1px solid rgba(0, 0, 0, 0.3);
|
||||
border-radius: 5px;
|
||||
background-image: url(../../images/icons/pencil-fill.svg);
|
||||
background-size: 16px;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
width: 35px;
|
||||
height: 35px;
|
||||
vertical-align: -0.25em;
|
||||
position: absolute;
|
||||
right: 4px;
|
||||
top: 4px;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.editor-container .editor-image .image-edit-button:hover {
|
||||
background-color: rgba(60, 132, 244, 0.1);
|
||||
}
|
||||
|
||||
.editor-container .editor-image .image-resizer {
|
||||
display: block;
|
||||
width: 7px;
|
||||
height: 7px;
|
||||
position: absolute;
|
||||
background-color: rgb(60, 132, 244);
|
||||
border: 1px solid #fff;
|
||||
}
|
||||
|
||||
.editor-container .editor-image .image-resizer.image-resizer-n {
|
||||
top: -6px;
|
||||
left: 48%;
|
||||
cursor: n-resize;
|
||||
}
|
||||
|
||||
.editor-container .editor-image .image-resizer.image-resizer-ne {
|
||||
top: -6px;
|
||||
right: -6px;
|
||||
cursor: ne-resize;
|
||||
}
|
||||
|
||||
.editor-container .editor-image .image-resizer.image-resizer-e {
|
||||
bottom: 48%;
|
||||
right: -6px;
|
||||
cursor: e-resize;
|
||||
}
|
||||
|
||||
.editor-container .editor-image .image-resizer.image-resizer-se {
|
||||
bottom: -2px;
|
||||
right: -6px;
|
||||
cursor: nwse-resize;
|
||||
}
|
||||
|
||||
.editor-container .editor-image .image-resizer.image-resizer-s {
|
||||
bottom: -2px;
|
||||
left: 48%;
|
||||
cursor: s-resize;
|
||||
}
|
||||
|
||||
.editor-container .editor-image .image-resizer.image-resizer-sw {
|
||||
bottom: -2px;
|
||||
left: -6px;
|
||||
cursor: sw-resize;
|
||||
}
|
||||
|
||||
.editor-container .editor-image .image-resizer.image-resizer-w {
|
||||
bottom: 48%;
|
||||
left: -6px;
|
||||
cursor: w-resize;
|
||||
}
|
||||
|
||||
.editor-container .editor-image .image-resizer.image-resizer-nw {
|
||||
top: -6px;
|
||||
left: -6px;
|
||||
cursor: nw-resize;
|
||||
}
|
||||
|
||||
.editor-container span.inline-editor-image {
|
||||
cursor: default;
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.editor-container .inline-editor-image img {
|
||||
max-width: 200%;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.editor-container .inline-editor-image img.focused {
|
||||
outline: 2px solid rgb(60, 132, 244);
|
||||
}
|
||||
|
||||
.editor-container .inline-editor-image img.focused.draggable {
|
||||
cursor: grab;
|
||||
}
|
||||
|
||||
.editor-container .inline-editor-image img.focused.draggable:active {
|
||||
cursor: grabbing;
|
||||
}
|
||||
|
||||
.editor-container .inline-editor-image .image-caption-container .tree-view-output {
|
||||
margin: 0;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.editor-container .inline-editor-image.position-full {
|
||||
margin: 1em 0 1em 0;
|
||||
}
|
||||
|
||||
.editor-container .inline-editor-image.position-left {
|
||||
float: left;
|
||||
width: 50%;
|
||||
margin: 1em 1em 0 0;
|
||||
}
|
||||
|
||||
.editor-container .inline-editor-image.position-right {
|
||||
float: right;
|
||||
width: 50%;
|
||||
margin: 1em 0 0 1em;
|
||||
}
|
||||
|
||||
.editor-container .inline-editor-image .image-edit-button {
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 12px;
|
||||
right: 12px;
|
||||
padding: 6px 8px;
|
||||
margin: 0 auto;
|
||||
border: 1px solid rgba(255, 255, 255, 0.3);
|
||||
border-radius: 5px;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
min-width: 60px;
|
||||
color: #fff;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.editor-container .inline-editor-image .image-edit-button:hover {
|
||||
background-color: rgba(60, 132, 244, 0.5);
|
||||
}
|
||||
|
||||
.editor-container .inline-editor-image .image-caption-container {
|
||||
display: block;
|
||||
background-color: #f4f4f4;
|
||||
min-width: 100%;
|
||||
color: #000;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.editor-container .editor-image img.focused.draggable {
|
||||
cursor: grab;
|
||||
}
|
||||
|
||||
.editor-container .editor-image img.focused.draggable:active {
|
||||
cursor: grabbing;
|
||||
}
|
||||
.editor-container .inline-editor-image img.focused.draggable {
|
||||
cursor: grab;
|
||||
}
|
||||
|
||||
.editor-container .inline-editor-image img.focused.draggable:active {
|
||||
cursor: grabbing;
|
||||
}
|
||||
|
|
|
@ -30,33 +30,34 @@ import {DialogActions, DialogButtonsList} from '../Input/Dialog';
|
|||
import FileInput from '../Input/FileInput';
|
||||
import TextInput from '../Input/TextInput';
|
||||
import {Button} from "antd";
|
||||
|
||||
|
||||
|
||||
|
||||
export const INSERT_IMAGE_COMMAND =
|
||||
createCommand('INSERT_IMAGE_COMMAND');
|
||||
|
||||
/**
|
||||
* 插入路径图片对话框
|
||||
* @param onClick
|
||||
* @returns {Element}
|
||||
* @constructor
|
||||
*/
|
||||
export function InsertImageUriDialogBody({
|
||||
onClick,
|
||||
}) {
|
||||
const [src, setSrc] = useState('');
|
||||
const [altText, setAltText] = useState('');
|
||||
|
||||
const [resizable,setResizable] = useState(true);
|
||||
const isDisabled = src === '';
|
||||
|
||||
return (
|
||||
<>
|
||||
<TextInput
|
||||
label="Image URL"
|
||||
placeholder="i.e. https://source.unsplash.com/random"
|
||||
label="文件url"
|
||||
placeholder="例如:https://tenfei03.cfp.cn/creative/vcg/800/new/VCG41175510742.jpg"
|
||||
onChange={setSrc}
|
||||
value={src}
|
||||
data-test-id="image-modal-url-input"
|
||||
/>
|
||||
<TextInput
|
||||
label="Alt Text"
|
||||
placeholder="Random unsplash image"
|
||||
label="图片描述"
|
||||
placeholder="例如:风景"
|
||||
onChange={setAltText}
|
||||
value={altText}
|
||||
data-test-id="image-modal-alt-text-input"
|
||||
|
@ -65,7 +66,7 @@ export function InsertImageUriDialogBody({
|
|||
<Button
|
||||
data-test-id="image-modal-confirm-btn"
|
||||
disabled={isDisabled}
|
||||
onClick={() => onClick({altText, src})}>
|
||||
onClick={() => onClick({altText, src,resizable})}>
|
||||
确认
|
||||
</Button>
|
||||
</DialogActions>
|
||||
|
@ -73,14 +74,18 @@ export function InsertImageUriDialogBody({
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 插入上传文件对话框
|
||||
* @param onClick
|
||||
* @returns {Element}
|
||||
* @constructor
|
||||
*/
|
||||
export function InsertImageUploadedDialogBody({
|
||||
onClick,
|
||||
}) {
|
||||
const [src, setSrc] = useState('');
|
||||
const [altText, setAltText] = useState('');
|
||||
|
||||
const isDisabled = src === '';
|
||||
|
||||
const loadImage = (files) => {
|
||||
const reader = new FileReader();
|
||||
reader.onload = function () {
|
||||
|
@ -121,6 +126,13 @@ export function InsertImageUploadedDialogBody({
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 插入文件对话框
|
||||
* @param activeEditor
|
||||
* @param onClose
|
||||
* @returns {Element}
|
||||
* @constructor
|
||||
*/
|
||||
export function InsertImageDialog({
|
||||
activeEditor,
|
||||
onClose,
|
||||
|
@ -166,6 +178,12 @@ export function InsertImageDialog({
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 图片插件
|
||||
* @param captionsEnabled
|
||||
* @returns {null}
|
||||
* @constructor
|
||||
*/
|
||||
export default function ImagesPlugin({captionsEnabled,}){
|
||||
const [editor] = useLexicalComposerContext();
|
||||
|
||||
|
@ -214,7 +232,10 @@ export default function ImagesPlugin({captionsEnabled,}){
|
|||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 拖拽图标
|
||||
* @type {string}
|
||||
*/
|
||||
const TRANSPARENT_IMAGE =
|
||||
'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';
|
||||
const img = document.createElement('img');
|
||||
|
|
|
@ -39,49 +39,41 @@ import {
|
|||
getDefaultCodeLanguage,
|
||||
getCodeLanguages
|
||||
} from "@lexical/code";
|
||||
import DropDown, {DropDownItem} from "./Input/DropDown";
|
||||
import DropDown, {DropDownItem} from "@/pages/Note/Hlexical/plugins/Input/DropDown";
|
||||
|
||||
import {InsertImageDialog} from "./ImagesPlugin";
|
||||
import useModal from "../hook/userModal";
|
||||
import {InsertTableDialog} from "./TablePlugin";
|
||||
import {InsertImageDialog} from "@/pages/Note/Hlexical/plugins/ImagesPlugin";
|
||||
import useModal from "@/pages/Note/Hlexical/hook/userModal";
|
||||
import {InsertTableDialog} from "@/pages/Note/Hlexical/plugins/TablePlugin";
|
||||
import {INSERT_HORIZONTAL_RULE_COMMAND} from "@lexical/react/LexicalHorizontalRuleNode";
|
||||
import {InsertInlineImageDialog} from "./InlineImagePlugin";
|
||||
import {INSERT_EXCALIDRAW_COMMAND} from "./ExcalidrawPlugin";
|
||||
import {InsertInlineImageDialog} from "@/pages/Note/Hlexical/plugins/InlineImagePlugin";
|
||||
import {INSERT_EXCALIDRAW_COMMAND} from "@/pages/Note/Hlexical/plugins/ExcalidrawPlugin";
|
||||
|
||||
const LowPriority = 1;
|
||||
|
||||
const supportedBlockTypes = new Set([
|
||||
"paragraph",
|
||||
"quote",
|
||||
"code",
|
||||
"h1",
|
||||
"h2",
|
||||
"h3",
|
||||
"h4",
|
||||
"h5",
|
||||
"h6",
|
||||
"ul",
|
||||
"ol"
|
||||
// 支持的块类型
|
||||
const supportedBlockTypes = new Set(["paragraph", "quote", "code", "h1", "h2", "h3", "h4", "h5", "h6", "ul", "ol"
|
||||
]);
|
||||
|
||||
const blockTypeToBlockName = {
|
||||
code: "代码块",
|
||||
h1: "一级标题",
|
||||
h2: "二级标题",
|
||||
h3: "三级标题",
|
||||
h4: "四级标题",
|
||||
h5: "五级标题",
|
||||
h6: "六级标题",
|
||||
ol: "有序序列",
|
||||
// 块类型对应的名称
|
||||
const blockTypeToBlockName = {code: "代码块",
|
||||
h1: "一级标题", h2: "二级标题", h3: "三级标题", h4: "四级标题", h5: "五级标题", h6: "六级标题",
|
||||
ol: "有序序列", ul: "无序序列",
|
||||
paragraph: "普通文本",
|
||||
quote: "引用",
|
||||
ul: "无序序列"
|
||||
};
|
||||
|
||||
/**
|
||||
* 工具栏分割符
|
||||
* @returns {JSX.Element}
|
||||
* @constructor
|
||||
*/
|
||||
function Divider() {
|
||||
return <div className="divider"/>;
|
||||
}
|
||||
|
||||
/**
|
||||
* 位置计算
|
||||
* @param editor
|
||||
* @param rect
|
||||
*/
|
||||
function positionEditorElement(editor, rect) {
|
||||
if (rect === null) {
|
||||
editor.style.opacity = "0";
|
||||
|
@ -96,6 +88,12 @@ function positionEditorElement(editor, rect) {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 浮动连接设置
|
||||
* @param editor
|
||||
* @returns {JSX.Element}
|
||||
* @constructor
|
||||
*/
|
||||
function FloatingLinkEditor({editor}) {
|
||||
const editorRef = useRef(null);
|
||||
const inputRef = useRef(null);
|
||||
|
@ -236,6 +234,15 @@ function FloatingLinkEditor({editor}) {
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 下拉选择
|
||||
* @param onChange
|
||||
* @param className
|
||||
* @param options
|
||||
* @param value
|
||||
* @returns {JSX.Element}
|
||||
* @constructor
|
||||
*/
|
||||
function Select({onChange, className, options, value}) {
|
||||
return (
|
||||
<select className={className} onChange={onChange} value={value}>
|
||||
|
@ -252,6 +259,7 @@ function Select({onChange, className, options, value}) {
|
|||
function getSelectedNode(selection) {
|
||||
const anchor = selection.anchor;
|
||||
const focus = selection.focus;
|
||||
console.log('selection',anchor,focus)
|
||||
const anchorNode = selection.anchor.getNode();
|
||||
const focusNode = selection.focus.getNode();
|
||||
if (anchorNode === focusNode) {
|
||||
|
@ -449,6 +457,7 @@ export default function ToolbarPlugin() {
|
|||
const [isUnderline, setIsUnderline] = useState(false);
|
||||
const [isStrikethrough, setIsStrikethrough] = useState(false);
|
||||
const [isCode, setIsCode] = useState(false);
|
||||
const [isEditable, setIsEditable] = useState(() => editor.isEditable());
|
||||
|
||||
const updateToolbar = useCallback(() => {
|
||||
const selection = $getSelection();
|
||||
|
@ -555,7 +564,18 @@ export default function ToolbarPlugin() {
|
|||
return (
|
||||
<div className="toolbar" ref={toolbarRef}>
|
||||
<button
|
||||
disabled={!canUndo}
|
||||
onClick={() => {
|
||||
editor.setEditable(!isEditable)
|
||||
setIsEditable(!isEditable)
|
||||
}}
|
||||
className={"toolbar-item spaced " + (isBold ? "active" : "")}
|
||||
aria-label="Format Bold"
|
||||
>
|
||||
{isEditable?'阅读':'编辑'}
|
||||
</button>
|
||||
<Divider/>
|
||||
<button
|
||||
disabled={!canUndo||!isEditable}
|
||||
onClick={() => {
|
||||
editor.dispatchCommand(UNDO_COMMAND);
|
||||
}}
|
||||
|
@ -565,7 +585,7 @@ export default function ToolbarPlugin() {
|
|||
<i className="format undo"/>
|
||||
</button>
|
||||
<button
|
||||
disabled={!canRedo}
|
||||
disabled={!canRedo||!isEditable}
|
||||
onClick={() => {
|
||||
editor.dispatchCommand(REDO_COMMAND);
|
||||
}}
|
||||
|
@ -578,6 +598,7 @@ export default function ToolbarPlugin() {
|
|||
{supportedBlockTypes.has(blockType) && (
|
||||
<>
|
||||
<button
|
||||
disabled={!isEditable}
|
||||
className="toolbar-item block-controls"
|
||||
onClick={() =>
|
||||
setShowBlockOptionsDropDown(!showBlockOptionsDropDown)
|
||||
|
|
|
@ -9,7 +9,8 @@ const firstTheme = {
|
|||
h2: "editor-heading-h2",
|
||||
h3: "editor-heading-h3",
|
||||
h4: "editor-heading-h4",
|
||||
h5: "editor-heading-h5"
|
||||
h5: "editor-heading-h5",
|
||||
h6: "editor-heading-h6"
|
||||
},
|
||||
list: {
|
||||
nested: {
|
||||
|
|
Loading…
Reference in New Issue