This commit is contained in:
2026-05-14 19:55:53 +08:00
parent c764603dbd
commit 8a16b01e9e
55 changed files with 5754 additions and 5277 deletions
+10
View File
@@ -97,6 +97,12 @@ test.db1:
```bash ```bash
cd cyynote-backend cd cyynote-backend
mvn clean package mvn clean package
mvn clean package -DskipTests
mvn solon:run
java -jar demo.jar
java -jar target/cyynote.jar java -jar target/cyynote.jar
``` ```
@@ -177,7 +183,11 @@ VITE_WS_URL=ws://localhost:1234
```bash ```bash
cd cyynote-frontend cd cyynote-frontend
若网络不好
pnpm config set registry https://registry.npmmirror.com/
pnpm install pnpm install
pnpm dev pnpm dev
``` ```
Binary file not shown.
+1 -1
View File
@@ -1,3 +1,3 @@
test.db1: test.db1:
jdbcUrl: "jdbc:sqlite:D:/cyynote.db" jdbcUrl: "jdbc:sqlite:./cyynote.db"
driverClassName: "org.sqlite.JDBC" driverClassName: "org.sqlite.JDBC"
+53 -52
View File
@@ -1,53 +1,54 @@
CREATE TABLE `user` ( CREATE TABLE `user` (
id INTEGER PRIMARY KEY AUTOINCREMENT, id INTEGER PRIMARY KEY AUTOINCREMENT,
email TEXT, email TEXT,
password TEXT, password TEXT,
username TEXT, username TEXT,
role TEXT, role TEXT,
token TEXT, token TEXT,
logintime TEXT logintime TEXT
); );
CREATE TABLE `note` ( CREATE TABLE `note` (
id INTEGER PRIMARY KEY AUTOINCREMENT, id INTEGER PRIMARY KEY AUTOINCREMENT,
pid INTEGER, pid INTEGER,
title TEXT, title TEXT,
context TEXT, context TEXT,
conjson TEXT, conjson TEXT,
createtime TEXT, createtime TEXT,
updatetime TEXT, updatetime TEXT,
viewtime TEXT, viewtime TEXT,
userid INTEGER, userid INTEGER,
username TEXT, username TEXT,
flag INTEGER DEFAULT 1 flag INTEGER DEFAULT 1
); );
CREATE TABLE `history` ( CREATE TABLE `history` (
id INTEGER PRIMARY KEY AUTOINCREMENT, id INTEGER PRIMARY KEY AUTOINCREMENT,
nid INTEGER, nid INTEGER,
title TEXT, title TEXT,
context TEXT, context TEXT,
conjson TEXT, conjson TEXT,
createtime TEXT, createtime TEXT,
userid INTEGER, userid INTEGER,
username TEXT username TEXT,
); flag INTEGER DEFAULT 1
CREATE TABLE appx ( );
app_id INTEGER PRIMARY KEY AUTOINCREMENT, CREATE TABLE appx (
app_key TEXT, app_id INTEGER PRIMARY KEY AUTOINCREMENT,
akey TEXT, app_key TEXT,
ugroup_id INTEGER DEFAULT 0, akey TEXT,
agroup_id INTEGER, ugroup_id INTEGER DEFAULT 0,
name TEXT, agroup_id INTEGER,
note TEXT, name TEXT,
ar_is_setting INTEGER NOT NULL DEFAULT 0, note TEXT,
ar_is_examine INTEGER NOT NULL DEFAULT 0, ar_is_setting INTEGER NOT NULL DEFAULT 0,
ar_examine_ver INTEGER NOT NULL DEFAULT 0, ar_is_examine INTEGER NOT NULL DEFAULT 0,
log_fulltime TEXT ar_examine_ver INTEGER NOT NULL DEFAULT 0,
); log_fulltime TEXT
);
INSERT INTO `user` VALUES ('1', 'aaaaaaaaa', 'cyy123', 'admin', 'admin','','');
INSERT INTO `user` VALUES ('2', 'aaaaaaaaa', 'test', 'test', 'test','',''); INSERT INTO `user` VALUES ('1', 'aaaaaaaaa', 'cyy123', 'admin', 'admin','','');
INSERT INTO `user` VALUES ('2', 'aaaaaaaaa', 'test', 'test', 'test','','');
INSERT INTO `note` VALUES ('1', '0', 'test', 'test', 'test','','','','1','1','1'); INSERT INTO `note` VALUES ('1', '0', 'test', 'test', 'test','','','','1','1','1');
Binary file not shown.
Binary file not shown.
@@ -1,5 +1,5 @@
#Generated by Maven #Generated by Maven
#Wed Apr 29 15:30:28 CST 2026 #Thu May 14 15:10:41 CST 2026
groupId=com.cyynote groupId=com.cyynote
artifactId=cyynote artifactId=cyynote
version=1.0.0 version=1.0.0
+2 -1
View File
@@ -1,4 +1,3 @@
{ {
"name": "cyynote", "name": "cyynote",
"private": true, "private": true,
@@ -42,6 +41,7 @@
"html-react-parser": "^5.2.0", "html-react-parser": "^5.2.0",
"katex": "^0.16.21", "katex": "^0.16.21",
"lexical": "0.44.0", "lexical": "0.44.0",
"lodash-es": "^4.18.1",
"react": "^18.3.1", "react": "^18.3.1",
"react-dom": "^18.3.1", "react-dom": "^18.3.1",
"react-hook-form": "^7.55.0", "react-hook-form": "^7.55.0",
@@ -52,6 +52,7 @@
"zustand": "^5.0.3" "zustand": "^5.0.3"
}, },
"devDependencies": { "devDependencies": {
"@types/lodash-es": "^4.17.12",
"@types/react": "^18.3.20", "@types/react": "^18.3.20",
"@types/react-dom": "^18.3.5", "@types/react-dom": "^18.3.5",
"@typescript-eslint/eslint-plugin": "^8.30.0", "@typescript-eslint/eslint-plugin": "^8.30.0",
+5537
View File
File diff suppressed because it is too large Load Diff
@@ -10,9 +10,9 @@ import {AutoFocusPlugin} from '@lexical/react/LexicalAutoFocusPlugin';
import {CharacterLimitPlugin} from '@lexical/react/LexicalCharacterLimitPlugin'; import {CharacterLimitPlugin} from '@lexical/react/LexicalCharacterLimitPlugin';
import {CheckListPlugin} from '@lexical/react/LexicalCheckListPlugin'; import {CheckListPlugin} from '@lexical/react/LexicalCheckListPlugin';
import {ClearEditorPlugin} from '@lexical/react/LexicalClearEditorPlugin'; import {ClearEditorPlugin} from '@lexical/react/LexicalClearEditorPlugin';
import LexicalClickableLinkPlugin from '@lexical/react/LexicalClickableLinkPlugin'; import {ClickableLinkPlugin} from '@lexical/react/LexicalClickableLinkPlugin';
import {CollaborationPlugin} from '@lexical/react/LexicalCollaborationPlugin'; import {CollaborationPlugin} from '@lexical/react/LexicalCollaborationPlugin';
import LexicalErrorBoundary from '@lexical/react/LexicalErrorBoundary'; import {LexicalErrorBoundary} from '@lexical/react/LexicalErrorBoundary';
import {HashtagPlugin} from '@lexical/react/LexicalHashtagPlugin'; import {HashtagPlugin} from '@lexical/react/LexicalHashtagPlugin';
import {HistoryPlugin} from '@lexical/react/LexicalHistoryPlugin'; import {HistoryPlugin} from '@lexical/react/LexicalHistoryPlugin';
import {HorizontalRulePlugin} from '@lexical/react/LexicalHorizontalRulePlugin'; import {HorizontalRulePlugin} from '@lexical/react/LexicalHorizontalRulePlugin';
@@ -21,7 +21,7 @@ import {PlainTextPlugin} from '@lexical/react/LexicalPlainTextPlugin';
import {RichTextPlugin} from '@lexical/react/LexicalRichTextPlugin'; import {RichTextPlugin} from '@lexical/react/LexicalRichTextPlugin';
import {TabIndentationPlugin} from '@lexical/react/LexicalTabIndentationPlugin'; import {TabIndentationPlugin} from '@lexical/react/LexicalTabIndentationPlugin';
import {TablePlugin} from '@lexical/react/LexicalTablePlugin'; import {TablePlugin} from '@lexical/react/LexicalTablePlugin';
import useLexicalEditable from '@lexical/react/useLexicalEditable'; import {useLexicalEditable} from '@lexical/react/useLexicalEditable';
import {useEffect, useState,useLayoutEffect} from 'react'; import {useEffect, useState,useLayoutEffect} from 'react';
import {CAN_USE_DOM} from './shared/src/canUseDOM'; import {CAN_USE_DOM} from './shared/src/canUseDOM';
@@ -221,7 +221,7 @@ export default function Editor(props: { noteId: bigint; noteTitle: string; editD
<TwitterPlugin /> <TwitterPlugin />
<YouTubePlugin /> <YouTubePlugin />
<FigmaPlugin /> <FigmaPlugin />
{!isEditable && <LexicalClickableLinkPlugin />} {!isEditable && <ClickableLinkPlugin />}
<HorizontalRulePlugin /> <HorizontalRulePlugin />
<EquationsPlugin /> <EquationsPlugin />
<ExcalidrawPlugin /> <ExcalidrawPlugin />
@@ -9,6 +9,7 @@ import "./index.css";
import {$createLinkNode} from '@lexical/link'; import {$createLinkNode} from '@lexical/link';
import {$createListItemNode, $createListNode} from '@lexical/list'; import {$createListItemNode, $createListNode} from '@lexical/list';
import {LexicalComposer} from '@lexical/react/LexicalComposer'; import {LexicalComposer} from '@lexical/react/LexicalComposer';
import {LexicalCollaboration} from '@lexical/react/LexicalCollaborationContext';
import {$createHeadingNode, $createQuoteNode} from '@lexical/rich-text'; import {$createHeadingNode, $createQuoteNode} from '@lexical/rich-text';
import {$createParagraphNode, $createTextNode, $getRoot} from 'lexical'; import {$createParagraphNode, $createTextNode, $getRoot} from 'lexical';
@@ -121,13 +122,27 @@ function LexicalApp(props: { noteId: bigint; editData: object | null; noteTitle:
console.log(props.editData!==null) console.log(props.editData!==null)
console.log(prepopulatedRichText) console.log(prepopulatedRichText)
const resolveEditorState = (): string | null | undefined => {
if (props.editData === null) return undefined; // use prepopulatedRichText via function below
const raw = props.editData as unknown as string;
if (typeof raw === 'string') {
try {
JSON.parse(raw);
return raw;
} catch {
return null; // not valid Lexical JSON, start with empty editor
}
}
return undefined;
};
const editorState = resolveEditorState();
const resolvedEditorState = editorState === undefined && props.editData === null
? prepopulatedRichText
: editorState;
const initialConfig = { const initialConfig = {
// editorState: isCollab editorState: resolvedEditorState,
// ? null
// : emptyEditor
// ? undefined
// : prepopulatedRichText,
editorState: props.editData!==null?props.editData:prepopulatedRichText,
namespace: 'Playground', namespace: 'Playground',
nodes: [...PlaygroundNodes], nodes: [...PlaygroundNodes],
onError: (error: Error) => { onError: (error: Error) => {
@@ -137,6 +152,7 @@ function LexicalApp(props: { noteId: bigint; editData: object | null; noteTitle:
}; };
return ( return (
<LexicalCollaboration>
<LexicalComposer initialConfig={initialConfig}> <LexicalComposer initialConfig={initialConfig}>
<SharedHistoryContext> <SharedHistoryContext>
<TableContext> <TableContext>
@@ -159,6 +175,7 @@ function LexicalApp(props: { noteId: bigint; editData: object | null; noteTitle:
</TableContext> </TableContext>
</SharedHistoryContext> </SharedHistoryContext>
</LexicalComposer> </LexicalComposer>
</LexicalCollaboration>
); );
} }
@@ -46,9 +46,8 @@ header h1 {
} }
.editor-shell { .editor-shell {
margin: 20px auto; margin: 0;
border-radius: 2px; border-radius: 2px;
max-width: 1100px;
color: #000; color: #000;
position: relative; position: relative;
line-height: 1.7; line-height: 1.7;
@@ -61,6 +60,7 @@ header h1 {
display: block; display: block;
border-bottom-left-radius: 10px; border-bottom-left-radius: 10px;
border-bottom-right-radius: 10px; border-bottom-right-radius: 10px;
padding: 8px 15px 15px;
} }
.editor-shell .editor-container.tree-view { .editor-shell .editor-container.tree-view {
@@ -1428,7 +1428,6 @@ button.action-button:disabled {
.toolbar { .toolbar {
display: flex; display: flex;
margin-bottom: 1px;
background: #fff; background: #fff;
padding: 4px; padding: 4px;
border-top-left-radius: 10px; border-top-left-radius: 10px;
@@ -1438,7 +1437,9 @@ button.action-button:disabled {
height: 36px; height: 36px;
position: sticky; position: sticky;
top: 0; top: 0;
z-index: 2; z-index: 4;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
border-bottom: 1px solid #eee;
} }
button.toolbar-item { button.toolbar-item {
@@ -19,7 +19,7 @@ import {AutoFocusPlugin} from '@lexical/react/LexicalAutoFocusPlugin';
import {useCollaborationContext} from '@lexical/react/LexicalCollaborationContext'; import {useCollaborationContext} from '@lexical/react/LexicalCollaborationContext';
import {CollaborationPlugin} from '@lexical/react/LexicalCollaborationPlugin'; import {CollaborationPlugin} from '@lexical/react/LexicalCollaborationPlugin';
import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext'; import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext';
import LexicalErrorBoundary from '@lexical/react/LexicalErrorBoundary'; import {LexicalErrorBoundary} from '@lexical/react/LexicalErrorBoundary';
import {HashtagPlugin} from '@lexical/react/LexicalHashtagPlugin'; import {HashtagPlugin} from '@lexical/react/LexicalHashtagPlugin';
import {HistoryPlugin} from '@lexical/react/LexicalHistoryPlugin'; import {HistoryPlugin} from '@lexical/react/LexicalHistoryPlugin';
import {LexicalNestedComposer} from '@lexical/react/LexicalNestedComposer'; import {LexicalNestedComposer} from '@lexical/react/LexicalNestedComposer';
@@ -12,7 +12,7 @@ import './InlineImageNode.css';
import {AutoFocusPlugin} from '@lexical/react/LexicalAutoFocusPlugin'; import {AutoFocusPlugin} from '@lexical/react/LexicalAutoFocusPlugin';
import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext'; import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext';
import LexicalErrorBoundary from '@lexical/react/LexicalErrorBoundary'; import {LexicalErrorBoundary} from '@lexical/react/LexicalErrorBoundary';
import {LexicalNestedComposer} from '@lexical/react/LexicalNestedComposer'; import {LexicalNestedComposer} from '@lexical/react/LexicalNestedComposer';
import {RichTextPlugin} from '@lexical/react/LexicalRichTextPlugin'; import {RichTextPlugin} from '@lexical/react/LexicalRichTextPlugin';
import {useLexicalNodeSelection} from '@lexical/react/useLexicalNodeSelection'; import {useLexicalNodeSelection} from '@lexical/react/useLexicalNodeSelection';
@@ -13,7 +13,7 @@ import './StickyNode.css';
import {useCollaborationContext} from '@lexical/react/LexicalCollaborationContext'; import {useCollaborationContext} from '@lexical/react/LexicalCollaborationContext';
import {CollaborationPlugin} from '@lexical/react/LexicalCollaborationPlugin'; import {CollaborationPlugin} from '@lexical/react/LexicalCollaborationPlugin';
import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext'; import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext';
import LexicalErrorBoundary from '@lexical/react/LexicalErrorBoundary'; import {LexicalErrorBoundary} from '@lexical/react/LexicalErrorBoundary';
import {HistoryPlugin} from '@lexical/react/LexicalHistoryPlugin'; import {HistoryPlugin} from '@lexical/react/LexicalHistoryPlugin';
import {LexicalNestedComposer} from '@lexical/react/LexicalNestedComposer'; import {LexicalNestedComposer} from '@lexical/react/LexicalNestedComposer';
import {PlainTextPlugin} from '@lexical/react/LexicalPlainTextPlugin'; import {PlainTextPlugin} from '@lexical/react/LexicalPlainTextPlugin';
@@ -32,7 +32,7 @@ import {useCollaborationContext} from '@lexical/react/LexicalCollaborationContex
import {LexicalComposer} from '@lexical/react/LexicalComposer'; import {LexicalComposer} from '@lexical/react/LexicalComposer';
import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext'; import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext';
import {EditorRefPlugin} from '@lexical/react/LexicalEditorRefPlugin'; import {EditorRefPlugin} from '@lexical/react/LexicalEditorRefPlugin';
import LexicalErrorBoundary from '@lexical/react/LexicalErrorBoundary'; import {LexicalErrorBoundary} from '@lexical/react/LexicalErrorBoundary';
import {HistoryPlugin} from '@lexical/react/LexicalHistoryPlugin'; import {HistoryPlugin} from '@lexical/react/LexicalHistoryPlugin';
import {OnChangePlugin} from '@lexical/react/LexicalOnChangePlugin'; import {OnChangePlugin} from '@lexical/react/LexicalOnChangePlugin';
import {PlainTextPlugin} from '@lexical/react/LexicalPlainTextPlugin'; import {PlainTextPlugin} from '@lexical/react/LexicalPlainTextPlugin';
@@ -8,120 +8,40 @@
import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext'; import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext';
import { import {
LexicalContextMenuPlugin, NodeContextMenuPlugin,
MenuOption, NodeContextMenuOption,
} from '@lexical/react/LexicalContextMenuPlugin'; } from '@lexical/react/LexicalNodeContextMenuPlugin';
import { import {
type LexicalNode,
$getSelection, $getSelection,
$isRangeSelection, $isRangeSelection,
COPY_COMMAND, COPY_COMMAND,
CUT_COMMAND, CUT_COMMAND,
PASTE_COMMAND, PASTE_COMMAND,
} from 'lexical'; } from 'lexical';
import {useCallback, useMemo} from 'react'; import {useMemo} from 'react';
import * as React from 'react'; import * as React from 'react';
import * as ReactDOM from 'react-dom';
function ContextMenuItem({
index,
isSelected,
onClick,
onMouseEnter,
option,
}: {
index: number;
isSelected: boolean;
onClick: () => void;
onMouseEnter: () => void;
option: ContextMenuOption;
}) {
let className = 'item';
if (isSelected) {
className += ' selected';
}
return (
<li
key={option.key}
tabIndex={-1}
className={className}
ref={option.setRefElement}
role="option"
aria-selected={isSelected}
id={'typeahead-item-' + index}
onMouseEnter={onMouseEnter}
onClick={onClick}>
<span className="text">{option.title}</span>
</li>
);
}
function ContextMenu({
options,
selectedItemIndex,
onOptionClick,
onOptionMouseEnter,
}: {
selectedItemIndex: number | null;
onOptionClick: (option: ContextMenuOption, index: number) => void;
onOptionMouseEnter: (index: number) => void;
options: Array<ContextMenuOption>;
}) {
return (
<div className="typeahead-popover">
<ul>
{options.map((option: ContextMenuOption, i: number) => (
<ContextMenuItem
index={i}
isSelected={selectedItemIndex === i}
onClick={() => onOptionClick(option, i)}
onMouseEnter={() => onOptionMouseEnter(i)}
key={option.key}
option={option}
/>
))}
</ul>
</div>
);
}
export class ContextMenuOption extends MenuOption {
title: string;
onSelect: (targetNode: LexicalNode | null) => void;
constructor(
title: string,
options: {
onSelect: (targetNode: LexicalNode | null) => void;
},
) {
super(title);
this.title = title;
this.onSelect = options.onSelect.bind(this);
}
}
export default function ContextMenuPlugin(): JSX.Element { export default function ContextMenuPlugin(): JSX.Element {
const [editor] = useLexicalComposerContext(); const [editor] = useLexicalComposerContext();
const options = useMemo(() => { const items = useMemo(() => {
return [ return [
new ContextMenuOption(`Copy`, { new NodeContextMenuOption('Copy', {
onSelect: (_node) => { $onSelect: () => {
editor.dispatchCommand(COPY_COMMAND, null); editor.dispatchCommand(COPY_COMMAND, null);
}, },
}), }),
new ContextMenuOption(`Cut`, { new NodeContextMenuOption('Cut', {
onSelect: (_node) => { $onSelect: () => {
editor.dispatchCommand(CUT_COMMAND, null); editor.dispatchCommand(CUT_COMMAND, null);
}, },
}), }),
new ContextMenuOption(`Paste`, { new NodeContextMenuOption('Paste', {
onSelect: (_node) => { $onSelect: () => {
navigator.clipboard.read().then(async (...args) => { navigator.clipboard.read().then(async () => {
const data = new DataTransfer(); const data = new DataTransfer();
const clipItems = await navigator.clipboard.read();
const items = await navigator.clipboard.read(); const item = clipItems[0];
const item = items[0];
const permission = await navigator.permissions.query({ const permission = await navigator.permissions.query({
// @ts-ignore These types are incorrect. // @ts-ignore These types are incorrect.
@@ -137,108 +57,48 @@ export default function ContextMenuPlugin(): JSX.Element {
data.setData(type, dataString); data.setData(type, dataString);
} }
const event = new ClipboardEvent('paste', { const event = new ClipboardEvent('paste', {clipboardData: data});
clipboardData: data,
});
editor.dispatchCommand(PASTE_COMMAND, event); editor.dispatchCommand(PASTE_COMMAND, event);
}); });
}, },
}), }),
new ContextMenuOption(`Paste as Plain Text`, { new NodeContextMenuOption('Paste as Plain Text', {
onSelect: (_node) => { $onSelect: () => {
navigator.clipboard.read().then(async (...args) => { navigator.clipboard.read().then(async () => {
const permission = await navigator.permissions.query({ const permission = await navigator.permissions.query({
// @ts-ignore These types are incorrect. // @ts-ignore These types are incorrect.
name: 'clipboard-read', name: 'clipboard-read',
}); });
if (permission.state === 'denied') { if (permission.state === 'denied') {
alert('Not allowed to paste from clipboard.'); alert('Not allowed to paste from clipboard.');
return; return;
} }
const data = new DataTransfer(); const data = new DataTransfer();
const items = await navigator.clipboard.readText(); const text = await navigator.clipboard.readText();
data.setData('text/plain', items); data.setData('text/plain', text);
const event = new ClipboardEvent('paste', { const event = new ClipboardEvent('paste', {clipboardData: data});
clipboardData: data,
});
editor.dispatchCommand(PASTE_COMMAND, event); editor.dispatchCommand(PASTE_COMMAND, event);
}); });
}, },
}), }),
new ContextMenuOption(`Delete Node`, { new NodeContextMenuOption('Delete Node', {
onSelect: (_node) => { $onSelect: () => {
const selection = $getSelection(); editor.update(() => {
if ($isRangeSelection(selection)) { const selection = $getSelection();
const currentNode = selection.anchor.getNode(); if ($isRangeSelection(selection)) {
const ancestorNodeWithRootAsParent = currentNode const currentNode = selection.anchor.getNode();
.getParents() const ancestorNodeWithRootAsParent = currentNode
.at(-2); .getParents()
.at(-2);
ancestorNodeWithRootAsParent?.remove(); ancestorNodeWithRootAsParent?.remove();
} }
});
}, },
}), }),
]; ];
}, [editor]); }, [editor]);
const onSelectOption = useCallback( return <NodeContextMenuPlugin items={items} />;
(
selectedOption: ContextMenuOption,
targetNode: LexicalNode | null,
closeMenu: () => void,
) => {
editor.update(() => {
selectedOption.onSelect(targetNode);
closeMenu();
});
},
[editor],
);
return (
<LexicalContextMenuPlugin
options={options}
onSelectOption={onSelectOption}
menuRenderFn={(
anchorElementRef,
{
selectedIndex,
options: _options,
selectOptionAndCleanUp,
setHighlightedIndex,
},
{setMenuRef},
) =>
anchorElementRef.current
? ReactDOM.createPortal(
<div
className="typeahead-popover auto-embed-menu"
style={{
marginLeft: anchorElementRef.current.style.width,
userSelect: 'none',
width: 200,
}}
ref={setMenuRef}>
<ContextMenu
options={options}
selectedItemIndex={selectedIndex}
onOptionClick={(option: ContextMenuOption, index: number) => {
setHighlightedIndex(index);
selectOptionAndCleanUp(option);
}}
onOptionMouseEnter={(index: number) => {
setHighlightedIndex(index);
}}
/>
</div>,
anchorElementRef.current,
)
: null
}
/>
);
} }
@@ -7,16 +7,16 @@
*/ */
import type { import type {
DEPRECATED_GridCellNode,
ElementNode, ElementNode,
LexicalEditor, LexicalEditor,
} from 'lexical'; } from 'lexical';
import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext'; import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext';
import useLexicalEditable from '@lexical/react/useLexicalEditable'; import {useLexicalEditable} from '@lexical/react/useLexicalEditable';
import { import {
$deleteTableColumn__EXPERIMENTAL, $deleteTableColumn__EXPERIMENTAL,
$deleteTableRow__EXPERIMENTAL, $deleteTableRow__EXPERIMENTAL,
$getNodeTriplet,
$getTableCellNodeFromLexicalNode, $getTableCellNodeFromLexicalNode,
$getTableColumnIndexFromTableCellNode, $getTableColumnIndexFromTableCellNode,
$getTableNodeFromLexicalNodeOrThrow, $getTableNodeFromLexicalNodeOrThrow,
@@ -25,11 +25,13 @@ import {
$insertTableRow__EXPERIMENTAL, $insertTableRow__EXPERIMENTAL,
$isTableCellNode, $isTableCellNode,
$isTableRowNode, $isTableRowNode,
$isTableSelection,
$unmergeCell, $unmergeCell,
getTableSelectionFromTableElement, getTableObserverFromTableElement,
HTMLTableElementWithWithTableSelectionState, HTMLTableElementWithWithTableSelectionState,
TableCellHeaderStates, TableCellHeaderStates,
TableCellNode, TableCellNode,
TableSelection,
} from '@lexical/table'; } from '@lexical/table';
import { import {
$createParagraphNode, $createParagraphNode,
@@ -39,10 +41,6 @@ import {
$isParagraphNode, $isParagraphNode,
$isRangeSelection, $isRangeSelection,
$isTextNode, $isTextNode,
DEPRECATED_$getNodeTriplet,
DEPRECATED_$isGridCellNode,
DEPRECATED_$isGridSelection,
GridSelection,
} from 'lexical'; } from 'lexical';
import * as React from 'react'; import * as React from 'react';
import {ReactPortal, useCallback, useEffect, useRef, useState} from 'react'; import {ReactPortal, useCallback, useEffect, useRef, useState} from 'react';
@@ -52,7 +50,7 @@ import invariant from '../../shared/src/invariant';
import useModal from '../../hooks/useModal'; import useModal from '../../hooks/useModal';
import ColorPicker from '../../ui/ColorPicker'; import ColorPicker from '../../ui/ColorPicker';
function computeSelectionCount(selection: GridSelection): { function computeSelectionCount(selection: TableSelection): {
columns: number; columns: number;
rows: number; rows: number;
} { } {
@@ -65,7 +63,7 @@ function computeSelectionCount(selection: GridSelection): {
// This is important when merging cells as there is no good way to re-merge weird shapes (a result // This is important when merging cells as there is no good way to re-merge weird shapes (a result
// of selecting merged cells and non-merged) // of selecting merged cells and non-merged)
function isGridSelectionRectangular(selection: GridSelection): boolean { function isTableSelectionRectangular(selection: TableSelection): boolean {
const nodes = selection.getNodes(); const nodes = selection.getNodes();
const currentRows: Array<number> = []; const currentRows: Array<number> = [];
let currentRow = null; let currentRow = null;
@@ -109,17 +107,17 @@ function $canUnmerge(): boolean {
const selection = $getSelection(); const selection = $getSelection();
if ( if (
($isRangeSelection(selection) && !selection.isCollapsed()) || ($isRangeSelection(selection) && !selection.isCollapsed()) ||
(DEPRECATED_$isGridSelection(selection) && ($isTableSelection(selection) &&
!selection.anchor.is(selection.focus)) || !selection.anchor.is(selection.focus)) ||
(!$isRangeSelection(selection) && !DEPRECATED_$isGridSelection(selection)) (!$isRangeSelection(selection) && !$isTableSelection(selection))
) { ) {
return false; return false;
} }
const [cell] = DEPRECATED_$getNodeTriplet(selection.anchor); const [cell] = $getNodeTriplet(selection.anchor);
return cell.__colSpan > 1 || cell.__rowSpan > 1; return cell.__colSpan > 1 || cell.__rowSpan > 1;
} }
function $cellContainsEmptyParagraph(cell: DEPRECATED_GridCellNode): boolean { function $cellContainsEmptyParagraph(cell: TableCellNode): boolean {
if (cell.getChildrenSize() !== 1) { if (cell.getChildrenSize() !== 1) {
return false; return false;
} }
@@ -146,9 +144,9 @@ function currentCellBackgroundColor(editor: LexicalEditor): null | string {
const selection = $getSelection(); const selection = $getSelection();
if ( if (
$isRangeSelection(selection) || $isRangeSelection(selection) ||
DEPRECATED_$isGridSelection(selection) $isTableSelection(selection)
) { ) {
const [cell] = DEPRECATED_$getNodeTriplet(selection.anchor); const [cell] = $getNodeTriplet(selection.anchor);
if ($isTableCellNode(cell)) { if ($isTableCellNode(cell)) {
return cell.getBackgroundColor(); return cell.getBackgroundColor();
} }
@@ -208,11 +206,11 @@ function TableActionMenu({
editor.getEditorState().read(() => { editor.getEditorState().read(() => {
const selection = $getSelection(); const selection = $getSelection();
// Merge cells // Merge cells
if (DEPRECATED_$isGridSelection(selection)) { if ($isTableSelection(selection)) {
const currentSelectionCounts = computeSelectionCount(selection); const currentSelectionCounts = computeSelectionCount(selection);
updateSelectionCounts(computeSelectionCount(selection)); updateSelectionCounts(computeSelectionCount(selection));
setCanMergeCells( setCanMergeCells(
isGridSelectionRectangular(selection) && isTableSelectionRectangular(selection) &&
(currentSelectionCounts.columns > 1 || (currentSelectionCounts.columns > 1 ||
currentSelectionCounts.rows > 1), currentSelectionCounts.rows > 1),
); );
@@ -286,9 +284,9 @@ function TableActionMenu({
throw new Error('Expected to find tableElement in DOM'); throw new Error('Expected to find tableElement in DOM');
} }
const tableSelection = getTableSelectionFromTableElement(tableElement); const tableSelection = getTableObserverFromTableElement(tableElement);
if (tableSelection !== null) { if (tableSelection !== null) {
tableSelection.clearHighlight(); tableSelection.$clearHighlight();
} }
tableNode.markDirty(); tableNode.markDirty();
@@ -303,13 +301,13 @@ function TableActionMenu({
const mergeTableCellsAtSelection = () => { const mergeTableCellsAtSelection = () => {
editor.update(() => { editor.update(() => {
const selection = $getSelection(); const selection = $getSelection();
if (DEPRECATED_$isGridSelection(selection)) { if ($isTableSelection(selection)) {
const {columns, rows} = computeSelectionCount(selection); const {columns, rows} = computeSelectionCount(selection);
const nodes = selection.getNodes(); const nodes = selection.getNodes();
let firstCell: null | DEPRECATED_GridCellNode = null; let firstCell: null | TableCellNode = null;
for (let i = 0; i < nodes.length; i++) { for (let i = 0; i < nodes.length; i++) {
const node = nodes[i]; const node = nodes[i];
if (DEPRECATED_$isGridCellNode(node)) { if ($isTableCellNode(node)) {
if (firstCell === null) { if (firstCell === null) {
node.setColSpan(columns).setRowSpan(rows); node.setColSpan(columns).setRowSpan(rows);
firstCell = node; firstCell = node;
@@ -321,7 +319,7 @@ function TableActionMenu({
) { ) {
firstChild.remove(); firstChild.remove();
} }
} else if (DEPRECATED_$isGridCellNode(firstCell)) { } else if ($isTableCellNode(firstCell)) {
const isEmpty = $cellContainsEmptyParagraph(node); const isEmpty = $cellContainsEmptyParagraph(node);
if (!isEmpty) { if (!isEmpty) {
firstCell.append(...node.getChildren()); firstCell.append(...node.getChildren());
@@ -473,19 +471,19 @@ function TableActionMenu({
const selection = $getSelection(); const selection = $getSelection();
if ( if (
$isRangeSelection(selection) || $isRangeSelection(selection) ||
DEPRECATED_$isGridSelection(selection) $isTableSelection(selection)
) { ) {
const [cell] = DEPRECATED_$getNodeTriplet(selection.anchor); const [cell] = $getNodeTriplet(selection.anchor);
if ($isTableCellNode(cell)) { if ($isTableCellNode(cell)) {
cell.setBackgroundColor(value); cell.setBackgroundColor(value);
} }
if (DEPRECATED_$isGridSelection(selection)) { if ($isTableSelection(selection)) {
const nodes = selection.getNodes(); const nodes = selection.getNodes();
for (let i = 0; i < nodes.length; i++) { for (let i = 0; i < nodes.length; i++) {
const node = nodes[i]; const node = nodes[i];
if (DEPRECATED_$isGridCellNode(node)) { if ($isTableCellNode(node)) {
node.setBackgroundColor(value); node.setBackgroundColor(value);
} }
} }
@@ -5,26 +5,26 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
*/ */
import type {Cell} from '@lexical/table'; import type {TableDOMCell} from '@lexical/table';
import type {LexicalEditor} from 'lexical'; import type {LexicalEditor} from 'lexical';
import './index.css'; import './index.css';
import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext'; import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext';
import useLexicalEditable from '@lexical/react/useLexicalEditable'; import {useLexicalEditable} from '@lexical/react/useLexicalEditable';
import { import {
$getTableColumnIndexFromTableCellNode, $getTableColumnIndexFromTableCellNode,
$getTableNodeFromLexicalNodeOrThrow, $getTableNodeFromLexicalNodeOrThrow,
$getTableRowIndexFromTableCellNode, $getTableRowIndexFromTableCellNode,
$isTableCellNode, $isTableCellNode,
$isTableRowNode, $isTableRowNode,
getCellFromTarget, $isTableSelection,
getDOMCellFromTarget,
} from '@lexical/table'; } from '@lexical/table';
import { import {
$getNearestNodeFromDOMNode, $getNearestNodeFromDOMNode,
$getSelection, $getSelection,
COMMAND_PRIORITY_HIGH, COMMAND_PRIORITY_HIGH,
DEPRECATED_$isGridSelection,
SELECTION_CHANGE_COMMAND, SELECTION_CHANGE_COMMAND,
} from 'lexical'; } from 'lexical';
import * as React from 'react'; import * as React from 'react';
@@ -58,7 +58,7 @@ function TableCellResizer({editor}: {editor: LexicalEditor}): JSX.Element {
const [mouseCurrentPos, updateMouseCurrentPos] = const [mouseCurrentPos, updateMouseCurrentPos] =
useState<MousePosition | null>(null); useState<MousePosition | null>(null);
const [activeCell, updateActiveCell] = useState<Cell | null>(null); const [activeCell, updateActiveCell] = useState<TableDOMCell | null>(null);
const [isSelectingGrid, updateIsSelectingGrid] = useState<boolean>(false); const [isSelectingGrid, updateIsSelectingGrid] = useState<boolean>(false);
const [draggingDirection, updateDraggingDirection] = const [draggingDirection, updateDraggingDirection] =
useState<MouseDraggingDirection | null>(null); useState<MouseDraggingDirection | null>(null);
@@ -68,7 +68,7 @@ function TableCellResizer({editor}: {editor: LexicalEditor}): JSX.Element {
SELECTION_CHANGE_COMMAND, SELECTION_CHANGE_COMMAND,
(payload) => { (payload) => {
const selection = $getSelection(); const selection = $getSelection();
const isGridSelection = DEPRECATED_$isGridSelection(selection); const isGridSelection = $isTableSelection(selection);
if (isSelectingGrid !== isGridSelection) { if (isSelectingGrid !== isGridSelection) {
updateIsSelectingGrid(isGridSelection); updateIsSelectingGrid(isGridSelection);
@@ -107,7 +107,7 @@ function TableCellResizer({editor}: {editor: LexicalEditor}): JSX.Element {
if (targetRef.current !== target) { if (targetRef.current !== target) {
targetRef.current = target as HTMLElement; targetRef.current = target as HTMLElement;
const cell = getCellFromTarget(target as HTMLElement); const cell = getDOMCellFromTarget(target as HTMLElement);
if (cell && activeCell !== cell) { if (cell && activeCell !== cell) {
editor.update(() => { editor.update(() => {
@@ -5,14 +5,14 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
*/ */
import type {TableOfContentsEntry} from '@lexical/react/LexicalTableOfContents'; import type {TableOfContentsEntry} from '@lexical/react/LexicalTableOfContentsPlugin';
import type {HeadingTagType} from '@lexical/rich-text'; import type {HeadingTagType} from '@lexical/rich-text';
import type {NodeKey} from 'lexical'; import type {NodeKey} from 'lexical';
import './index.css'; import './index.css';
import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext'; import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext';
import LexicalTableOfContents from '@lexical/react/LexicalTableOfContents'; import {TableOfContentsPlugin} from '@lexical/react/LexicalTableOfContentsPlugin';
import {useEffect, useRef, useState} from 'react'; import {useEffect, useRef, useState} from 'react';
import { Collapsible, Button } from '@douyinfe/semi-ui'; import { Collapsible, Button } from '@douyinfe/semi-ui';
@@ -243,12 +243,12 @@ function TableOfContentsList({
); );
} }
export default function TableOfContentsPlugin() { export default function TableOfContentsPluginWrapper() {
return ( return (
<LexicalTableOfContents> <TableOfContentsPlugin>
{(tableOfContents) => { {(tableOfContents) => {
return <TableOfContentsList tableOfContents={tableOfContents} />; return <TableOfContentsList tableOfContents={tableOfContents} />;
}} }}
</LexicalTableOfContents> </TableOfContentsPlugin>
); );
} }
@@ -51,7 +51,6 @@ import {
$getNodeByKey, $getNodeByKey,
$getRoot, $getRoot,
$getSelection, $getSelection,
$INTERNAL_isPointSelection,
$isElementNode, $isElementNode,
$isRangeSelection, $isRangeSelection,
$isRootOrShadowRoot, $isRootOrShadowRoot,
@@ -213,7 +212,7 @@ function BlockFormatDropDown({
const formatParagraph = () => { const formatParagraph = () => {
editor.update(() => { editor.update(() => {
const selection = $getSelection(); const selection = $getSelection();
if ($INTERNAL_isPointSelection(selection)) { if ($isRangeSelection(selection)) {
$setBlocksType(selection, () => $createParagraphNode()); $setBlocksType(selection, () => $createParagraphNode());
} }
}); });
@@ -223,7 +222,7 @@ function BlockFormatDropDown({
if (blockType !== headingSize) { if (blockType !== headingSize) {
editor.update(() => { editor.update(() => {
const selection = $getSelection(); const selection = $getSelection();
if ($INTERNAL_isPointSelection(selection)) { if ($isRangeSelection(selection)) {
$setBlocksType(selection, () => $createHeadingNode(headingSize)); $setBlocksType(selection, () => $createHeadingNode(headingSize));
} }
}); });
@@ -258,7 +257,7 @@ function BlockFormatDropDown({
if (blockType !== 'quote') { if (blockType !== 'quote') {
editor.update(() => { editor.update(() => {
const selection = $getSelection(); const selection = $getSelection();
if ($INTERNAL_isPointSelection(selection)) { if ($isRangeSelection(selection)) {
$setBlocksType(selection, () => $createQuoteNode()); $setBlocksType(selection, () => $createQuoteNode());
} }
}); });
@@ -270,7 +269,7 @@ function BlockFormatDropDown({
editor.update(() => { editor.update(() => {
let selection = $getSelection(); let selection = $getSelection();
if ($INTERNAL_isPointSelection(selection)) { if ($isRangeSelection(selection)) {
if (selection.isCollapsed()) { if (selection.isCollapsed()) {
$setBlocksType(selection, () => $createCodeNode()); $setBlocksType(selection, () => $createCodeNode());
} else { } else {
@@ -370,7 +369,7 @@ function FontDropDown({
(option: string) => { (option: string) => {
editor.update(() => { editor.update(() => {
const selection = $getSelection(); const selection = $getSelection();
if ($INTERNAL_isPointSelection(selection)) { if ($isRangeSelection(selection)) {
$patchStyleText(selection, { $patchStyleText(selection, {
[style]: option, [style]: option,
}); });
@@ -677,7 +676,7 @@ export default function ToolbarPlugin({
activeEditor.registerUpdateListener(({editorState}) => { activeEditor.registerUpdateListener(({editorState}) => {
editorState.read(() => { editorState.read(() => {
$updateToolbar(); $updateToolbar();
}); }, {editor: activeEditor});
}), }),
activeEditor.registerCommand<boolean>( activeEditor.registerCommand<boolean>(
CAN_UNDO_COMMAND, CAN_UNDO_COMMAND,
@@ -727,7 +726,7 @@ export default function ToolbarPlugin({
(styles: Record<string, string>) => { (styles: Record<string, string>) => {
activeEditor.update(() => { activeEditor.update(() => {
const selection = $getSelection(); const selection = $getSelection();
if ($INTERNAL_isPointSelection(selection)) { if ($isRangeSelection(selection)) {
$patchStyleText(selection, styles); $patchStyleText(selection, styles);
} }
}); });
@@ -25,28 +25,27 @@ export default function NoteEditor() {
return ( return (
<> <>
<Breadcrumb <Breadcrumb
style={{ marginBottom: '24px' }} style={{ marginBottom: '16px', paddingTop: '10px' }}
routes={['CyyNote', '笔记标题', currentTitle]} routes={['CyyNote', '笔记标题', currentTitle]}
/> />
<div <Skeleton
style={{ placeholder={<Skeleton.Paragraph rows={2} />}
borderRadius: '10px', loading={isNoteLoading}
border: '1px solid var(--semi-color-border)',
padding: '15px',
}}
> >
<Skeleton <Input
placeholder={<Skeleton.Paragraph rows={2} />} placeholder="笔记标题"
loading={isNoteLoading} size="large"
value={currentTitle}
onChange={handleTitleChange}
style={{ marginBottom: '12px' }}
/>
<div
style={{
borderRadius: '10px',
border: '1px solid var(--semi-color-border)',
overflow: 'clip',
}}
> >
<Input
placeholder="笔记标题"
size="large"
value={currentTitle}
onChange={handleTitleChange}
/>
<br />
<br />
{currentNoteId !== null && currentContent !== null ? ( {currentNoteId !== null && currentContent !== null ? (
<PlaygroundApp <PlaygroundApp
noteId={currentNoteId} noteId={currentNoteId}
@@ -55,10 +54,10 @@ export default function NoteEditor() {
handleLawClick={handleRefreshTree} handleLawClick={handleRefreshTree}
/> />
) : ( ) : (
<div style={{ color: 'var(--semi-color-text-2)' }}></div> <div style={{ padding: '15px', color: 'var(--semi-color-text-2)' }}></div>
)} )}
</Skeleton> </div>
</div> </Skeleton>
</> </>
); );
} }
@@ -189,7 +189,7 @@ export default function NoteTree({ onRefreshTree, onNavItemClick, onSearch }: No
searchPlaceholder=" " searchPlaceholder=" "
showFilteredOnly showFilteredOnly
directory directory
virtualize virtualize={{ itemSize: 28 }}
value={currentNoteId === null ? undefined : String(currentNoteId)} value={currentNoteId === null ? undefined : String(currentNoteId)}
treeData={treeData as unknown as Parameters<typeof Tree>[0]['treeData']} treeData={treeData as unknown as Parameters<typeof Tree>[0]['treeData']}
renderLabel={renderLabel as Parameters<typeof Tree>[0]['renderLabel']} renderLabel={renderLabel as Parameters<typeof Tree>[0]['renderLabel']}
+3 -6
View File
@@ -1,4 +1,3 @@
import React from 'react';
import ReactDOM from 'react-dom/client'; import ReactDOM from 'react-dom/client';
import { BrowserRouter } from 'react-router'; import { BrowserRouter } from 'react-router';
@@ -6,10 +5,8 @@ import './index.css';
import App from './App'; import App from './App';
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render( ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
<React.StrictMode> <BrowserRouter>
<BrowserRouter> <App />
<App /> </BrowserRouter>,
</BrowserRouter>
</React.StrictMode>,
); );
+8 -8
View File
@@ -131,8 +131,8 @@ export default function NotePage() {
const siderWidth = siderFlag ? '265px' : '0px'; const siderWidth = siderFlag ? '265px' : '0px';
return ( return (
<Layout style={{ border: '1px solid var(--semi-color-border)' }}> <Layout style={{ border: '1px solid var(--semi-color-border)', height: '100vh', overflow: 'hidden' }}>
<Header style={{ backgroundColor: 'var(--semi-color-bg-1)' }}> <Header style={{ backgroundColor: 'var(--semi-color-bg-1)', flexShrink: 0 }}>
<Nav mode="horizontal" defaultSelectedKeys={['Home']}> <Nav mode="horizontal" defaultSelectedKeys={['Home']}>
<Nav.Header> <Nav.Header>
<IconDescriptions style={{ height: '36px', fontSize: 36 }} /> <IconDescriptions style={{ height: '36px', fontSize: 36 }} />
@@ -181,9 +181,9 @@ export default function NotePage() {
</Nav> </Nav>
</Header> </Header>
<Layout> <Layout style={{ flex: 1, minHeight: 0 }}>
<Sider <Sider
style={{ width: siderWidth, backgroundColor: 'var(--semi-color-bg-1)' }} style={{ width: siderWidth, backgroundColor: 'var(--semi-color-bg-1)', overflowY: 'auto' }}
breakpoint={['md']} breakpoint={['md']}
onBreakpoint={handleBreakpoint} onBreakpoint={handleBreakpoint}
> >
@@ -207,13 +207,13 @@ export default function NotePage() {
{/* Main content area */} {/* Main content area */}
{activeView === 'note' && ( {activeView === 'note' && (
<Content style={{ padding: '10px', backgroundColor: 'var(--semi-color-bg-0)' }}> <Content style={{ padding: '0 10px 10px', backgroundColor: 'var(--semi-color-bg-0)', overflowY: 'auto' }}>
<NoteEditor /> <NoteEditor />
</Content> </Content>
)} )}
{activeView === 'home' && ( {activeView === 'home' && (
<Content style={{ padding: '10px', backgroundColor: 'var(--semi-color-bg-0)' }}> <Content style={{ padding: '10px', backgroundColor: 'var(--semi-color-bg-0)', overflowY: 'auto' }}>
<Breadcrumb style={{ marginBottom: 24 }} routes={['首页']} /> <Breadcrumb style={{ marginBottom: 24 }} routes={['首页']} />
<div <div
style={{ style={{
@@ -228,7 +228,7 @@ export default function NotePage() {
)} )}
{activeView === 'settings' && ( {activeView === 'settings' && (
<Content style={{ padding: '10px', backgroundColor: 'var(--semi-color-bg-0)' }}> <Content style={{ padding: '10px', backgroundColor: 'var(--semi-color-bg-0)', overflowY: 'auto' }}>
<Breadcrumb style={{ marginBottom: 24 }} routes={['设置']} /> <Breadcrumb style={{ marginBottom: 24 }} routes={['设置']} />
<div <div
style={{ style={{
@@ -284,7 +284,7 @@ export default function NotePage() {
)} )}
{activeView === 'search' && ( {activeView === 'search' && (
<Content style={{ padding: 24, backgroundColor: 'var(--semi-color-bg-0)' }}> <Content style={{ padding: 24, backgroundColor: 'var(--semi-color-bg-0)', overflowY: 'auto' }}>
<Breadcrumb style={{ marginBottom: 24 }} routes={['搜索结果']} /> <Breadcrumb style={{ marginBottom: 24 }} routes={['搜索结果']} />
<div <div
style={{ style={{
+1 -1
View File
@@ -16,7 +16,7 @@
"jsx": "react-jsx", "jsx": "react-jsx",
/* Path aliases */ /* Path aliases */
"ignoreDeprecations": "6.0", "ignoreDeprecations": "5.0",
"baseUrl": ".", "baseUrl": ".",
"paths": { "paths": {
"@/*": ["./src/*"] "@/*": ["./src/*"]
+3
View File
@@ -4,6 +4,9 @@ import react from '@vitejs/plugin-react';
// https://vitejs.dev/config/ // https://vitejs.dev/config/
export default defineConfig(({ command }) => ({ export default defineConfig(({ command }) => ({
plugins: [react()], plugins: [react()],
define: {
'process.env': {},
},
resolve: { resolve: {
// new URL is pure ESM — no __dirname needed, no @types/node required // new URL is pure ESM — no __dirname needed, no @types/node required
alias: { '@': new URL('./src', import.meta.url).pathname }, alias: { '@': new URL('./src', import.meta.url).pathname },
File diff suppressed because it is too large Load Diff