feat: 保存文集
This commit is contained in:
parent
b7ac57f6a8
commit
1982910745
20
main.js
20
main.js
|
@ -2,6 +2,8 @@
|
||||||
const { app,Menu, BrowserWindow } = require('electron')
|
const { app,Menu, BrowserWindow } = require('electron')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const {menuRebuild} = require('./src/comment/TopMenu.js')
|
const {menuRebuild} = require('./src/comment/TopMenu.js')
|
||||||
|
// const {SAVE} = require("./src/utils/HotkeyConst");
|
||||||
|
// const {PUSH_HOTKEY} = require("./src/utils/MainContentsChannel");
|
||||||
const createWindow = () => {
|
const createWindow = () => {
|
||||||
// Create the browser window.
|
// Create the browser window.
|
||||||
const win = new BrowserWindow({
|
const win = new BrowserWindow({
|
||||||
|
@ -20,15 +22,23 @@ const createWindow = () => {
|
||||||
// 打开开发工具
|
// 打开开发工具
|
||||||
win.webContents.openDevTools()
|
win.webContents.openDevTools()
|
||||||
win.webContents.on('before-input-event', (event, input) => {
|
win.webContents.on('before-input-event', (event, input) => {
|
||||||
// if (input.control && input.key.toLowerCase() === 's') {
|
if (input.control && input.key.toLowerCase() === 's') {
|
||||||
// console.log('Pressed Control+s')
|
console.log("win.webContents.send(\"pushHotkeys\",\"CTRL+S\")")
|
||||||
|
win.webContents.send("pushHotkeys","CTRL+S")
|
||||||
// event.preventDefault()
|
// event.preventDefault()
|
||||||
// }
|
}
|
||||||
console.log('Pressed ',input.key)
|
console.log('Pressed ',input.key)
|
||||||
if (input.key==='f5'){
|
if (input.key.toUpperCase()==='F5'){
|
||||||
console.log('Pressed f5')
|
|
||||||
win.reload()
|
win.reload()
|
||||||
}
|
}
|
||||||
|
if (input.key.toUpperCase()==='F12'){
|
||||||
|
if (win.webContents.isDevToolsOpened()){
|
||||||
|
win.webContents.closeDevTools()
|
||||||
|
}else {
|
||||||
|
win.webContents.openDevTools()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
})
|
})
|
||||||
Menu.setApplicationMenu(Menu.buildFromTemplate(menuRebuild(win)))
|
Menu.setApplicationMenu(Menu.buildFromTemplate(menuRebuild(win)))
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"electron-squirrel-startup": "^1.0.0",
|
"electron-squirrel-startup": "^1.0.0",
|
||||||
"electron-store": "^8.1.0",
|
"electron-store": "^8.1.0",
|
||||||
|
"md5": "^2.3.0",
|
||||||
"mousetrap": "^1.6.5",
|
"mousetrap": "^1.6.5",
|
||||||
"node-sass": "^7.0.3"
|
"node-sass": "^7.0.3"
|
||||||
},
|
},
|
||||||
|
@ -8490,6 +8491,14 @@
|
||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/charenc": {
|
||||||
|
"version": "0.0.2",
|
||||||
|
"resolved": "https://registry.npmmirror.com/charenc/-/charenc-0.0.2.tgz",
|
||||||
|
"integrity": "sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==",
|
||||||
|
"engines": {
|
||||||
|
"node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/check-types": {
|
"node_modules/check-types": {
|
||||||
"version": "11.2.3",
|
"version": "11.2.3",
|
||||||
"resolved": "https://registry.npmmirror.com/check-types/-/check-types-11.2.3.tgz",
|
"resolved": "https://registry.npmmirror.com/check-types/-/check-types-11.2.3.tgz",
|
||||||
|
@ -9667,6 +9676,14 @@
|
||||||
"node": ">=12.10"
|
"node": ">=12.10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/crypt": {
|
||||||
|
"version": "0.0.2",
|
||||||
|
"resolved": "https://registry.npmmirror.com/crypt/-/crypt-0.0.2.tgz",
|
||||||
|
"integrity": "sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==",
|
||||||
|
"engines": {
|
||||||
|
"node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/crypto-random-string": {
|
"node_modules/crypto-random-string": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmmirror.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz",
|
"resolved": "https://registry.npmmirror.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz",
|
||||||
|
@ -14346,6 +14363,11 @@
|
||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/is-buffer": {
|
||||||
|
"version": "1.1.6",
|
||||||
|
"resolved": "https://registry.npmmirror.com/is-buffer/-/is-buffer-1.1.6.tgz",
|
||||||
|
"integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w=="
|
||||||
|
},
|
||||||
"node_modules/is-callable": {
|
"node_modules/is-callable": {
|
||||||
"version": "1.2.7",
|
"version": "1.2.7",
|
||||||
"resolved": "https://registry.npmmirror.com/is-callable/-/is-callable-1.2.7.tgz",
|
"resolved": "https://registry.npmmirror.com/is-callable/-/is-callable-1.2.7.tgz",
|
||||||
|
@ -17928,6 +17950,16 @@
|
||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/md5": {
|
||||||
|
"version": "2.3.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/md5/-/md5-2.3.0.tgz",
|
||||||
|
"integrity": "sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==",
|
||||||
|
"dependencies": {
|
||||||
|
"charenc": "0.0.2",
|
||||||
|
"crypt": "0.0.2",
|
||||||
|
"is-buffer": "~1.1.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/mdn-data": {
|
"node_modules/mdn-data": {
|
||||||
"version": "2.0.4",
|
"version": "2.0.4",
|
||||||
"resolved": "https://registry.npmmirror.com/mdn-data/-/mdn-data-2.0.4.tgz",
|
"resolved": "https://registry.npmmirror.com/mdn-data/-/mdn-data-2.0.4.tgz",
|
||||||
|
|
|
@ -51,6 +51,7 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"electron-squirrel-startup": "^1.0.0",
|
"electron-squirrel-startup": "^1.0.0",
|
||||||
"electron-store": "^8.1.0",
|
"electron-store": "^8.1.0",
|
||||||
|
"md5": "^2.3.0",
|
||||||
"mousetrap": "^1.6.5",
|
"mousetrap": "^1.6.5",
|
||||||
"node-sass": "^7.0.3"
|
"node-sass": "^7.0.3"
|
||||||
},
|
},
|
||||||
|
|
|
@ -3,7 +3,7 @@ import routes from './routes'
|
||||||
import {Outlet, useNavigate, useRoutes} from 'react-router-dom'
|
import {Outlet, useNavigate, useRoutes} from 'react-router-dom'
|
||||||
import useIpcRenderer from '../src/utils/useIpcRenderer'
|
import useIpcRenderer from '../src/utils/useIpcRenderer'
|
||||||
import {dirAdd} from "./redux/dirMessage_reducer";
|
import {dirAdd} from "./redux/dirMessage_reducer";
|
||||||
import {openFile} from "./redux/clickFile_reducer"
|
import {pushHotkeys} from "./redux/pushHotkeys_reducer";
|
||||||
import {store} from "./redux/store";
|
import {store} from "./redux/store";
|
||||||
function App() {
|
function App() {
|
||||||
|
|
||||||
|
@ -17,11 +17,16 @@ function App() {
|
||||||
const addNewDir =(event,args)=> {
|
const addNewDir =(event,args)=> {
|
||||||
store.dispatch(dirAdd(args))
|
store.dispatch(dirAdd(args))
|
||||||
}
|
}
|
||||||
|
const pushHotkeysAction =(event,args)=> {
|
||||||
|
console.log("store.dispatch(pushHotkeys(args))",args)
|
||||||
|
store.dispatch(pushHotkeys(args))
|
||||||
|
}
|
||||||
|
|
||||||
console.log("routes",routes)
|
console.log("routes",routes)
|
||||||
const element = useRoutes(routes)
|
const element = useRoutes(routes)
|
||||||
useIpcRenderer({'redirectUrl':redirectUrl})
|
useIpcRenderer({'redirectUrl':redirectUrl})
|
||||||
useIpcRenderer({'openDirectory':addNewDir})
|
useIpcRenderer({'openDirectory':addNewDir})
|
||||||
|
useIpcRenderer({'pushHotkeys':pushHotkeysAction})
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{/* 注册路由 */}
|
{/* 注册路由 */}
|
||||||
|
|
|
@ -23,11 +23,14 @@ import CodeHighlightPlugin from "./plugins/CodeHighlightPlugin";
|
||||||
import AutoLinkPlugin from "./plugins/AutoLinkPlugin";
|
import AutoLinkPlugin from "./plugins/AutoLinkPlugin";
|
||||||
import {useEffect, useState} from 'react';
|
import {useEffect, useState} from 'react';
|
||||||
import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext';
|
import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext';
|
||||||
import {importFile} from "../../../utils/File"
|
import {importFile, overWriteFile} from "../../../utils/File"
|
||||||
import {CLEAR_HISTORY_COMMAND} from "lexical";
|
import {CLEAR_HISTORY_COMMAND} from "lexical";
|
||||||
import ActionPlugin from "../../../components/ActionPlug"
|
import ActionPlugin from "../../../components/ActionPlug"
|
||||||
import {func} from "prop-types";
|
import {func} from "prop-types";
|
||||||
|
import store from "../../../redux/store";
|
||||||
|
import {useSelector} from 'react-redux'
|
||||||
|
import {SAVE} from "../../../utils/HotkeyConst";
|
||||||
|
import md5 from "md5"
|
||||||
|
|
||||||
function Placeholder() {
|
function Placeholder() {
|
||||||
return <div className="editor-placeholder">Enter some rich text...</div>;
|
return <div className="editor-placeholder">Enter some rich text...</div>;
|
||||||
|
@ -65,11 +68,11 @@ function OnChangePlugin({ onChange }) {
|
||||||
});
|
});
|
||||||
}, [editor, onChange]);
|
}, [editor, onChange]);
|
||||||
}
|
}
|
||||||
|
|
||||||
function ImportFilePlugin(props) {
|
function ImportFilePlugin(props) {
|
||||||
const [editor] = useLexicalComposerContext();
|
const [editor] = useLexicalComposerContext();
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
importFile(props.filePath).then(value => {
|
importFile(props.filePath).then(value => {
|
||||||
console.log('value.toString()',value.toString())
|
|
||||||
const editorState = editor.parseEditorState(
|
const editorState = editor.parseEditorState(
|
||||||
JSON.stringify(JSON.parse(value.toString()).editorState)
|
JSON.stringify(JSON.parse(value.toString()).editorState)
|
||||||
);
|
);
|
||||||
|
@ -81,6 +84,28 @@ function ImportFilePlugin(props) {
|
||||||
}, [])
|
}, [])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function SaveFilePlugin(props) {
|
||||||
|
const [editor] = useLexicalComposerContext();
|
||||||
|
useEffect(() => {
|
||||||
|
store.subscribe(() => {
|
||||||
|
let data = store.getState().pushHotkeys.data;
|
||||||
|
const editorState = {"editorState":editor.getEditorState()};
|
||||||
|
let resultSave = JSON.stringify(editorState);
|
||||||
|
if (data === SAVE) {
|
||||||
|
importFile(props.filePath).then(value => {
|
||||||
|
if (md5(resultSave)!==md5(JSON.stringify(JSON.parse(value.toString())))){
|
||||||
|
console.log("保存重写")
|
||||||
|
overWriteFile(props.filePath, resultSave)
|
||||||
|
}
|
||||||
|
}).catch(error =>
|
||||||
|
console.error(error)
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}, editor)
|
||||||
|
}
|
||||||
|
|
||||||
// 从字符串化 JSON 设置编辑器状态
|
// 从字符串化 JSON 设置编辑器状态
|
||||||
// const editorState = editor.parseEditorState(editorStateJSONString);
|
// const editorState = editor.parseEditorState(editorStateJSONString);
|
||||||
// editor.setEditorState(editorState);
|
// editor.setEditorState(editorState);
|
||||||
|
@ -88,6 +113,7 @@ function ImportFilePlugin(props) {
|
||||||
export default function Hlexical(props) {
|
export default function Hlexical(props) {
|
||||||
console.log("this.props.filePath:", props.filePath)
|
console.log("this.props.filePath:", props.filePath)
|
||||||
const [editorState, setEditorState] = useState();
|
const [editorState, setEditorState] = useState();
|
||||||
|
|
||||||
function onChange(editorState) {
|
function onChange(editorState) {
|
||||||
// Call toJSON on the EditorState object, which produces a serialization safe string
|
// Call toJSON on the EditorState object, which produces a serialization safe string
|
||||||
const editorStateJSON = editorState.toJSON();
|
const editorStateJSON = editorState.toJSON();
|
||||||
|
@ -95,6 +121,7 @@ export default function Hlexical(props) {
|
||||||
// However, we still have a JavaScript object, so we need to convert it to an actual string with JSON.stringify
|
// However, we still have a JavaScript object, so we need to convert it to an actual string with JSON.stringify
|
||||||
setEditorState(JSON.stringify(editorStateJSON));
|
setEditorState(JSON.stringify(editorStateJSON));
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<LexicalComposer initialConfig={editorConfig}>
|
<LexicalComposer initialConfig={editorConfig}>
|
||||||
<div className="editor-container">
|
<div className="editor-container">
|
||||||
|
@ -118,6 +145,7 @@ export default function Hlexical(props) {
|
||||||
<MarkdownShortcutPlugin transformers={TRANSFORMERS}/>
|
<MarkdownShortcutPlugin transformers={TRANSFORMERS}/>
|
||||||
<OnChangePlugin onChange={onChange}/>
|
<OnChangePlugin onChange={onChange}/>
|
||||||
<ImportFilePlugin filePath={props.filePath}/>
|
<ImportFilePlugin filePath={props.filePath}/>
|
||||||
|
<SaveFilePlugin filePath={props.filePath}/>
|
||||||
{/*<ActionPlugin/>*/}
|
{/*<ActionPlugin/>*/}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
import { createSlice } from '@reduxjs/toolkit'
|
||||||
|
|
||||||
|
export const pushHotkeysSlice = createSlice({
|
||||||
|
name: 'pushHotkeys',
|
||||||
|
initialState: {
|
||||||
|
data: ""
|
||||||
|
},
|
||||||
|
reducers: {
|
||||||
|
pushHotkeys: (state, action) => {
|
||||||
|
console.log("pushHotkeys:pushHotkeys", state, action)
|
||||||
|
if(action.payload){
|
||||||
|
state.data = action.payload;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
export const { pushHotkeys } = pushHotkeysSlice.actions
|
||||||
|
|
||||||
|
export default pushHotkeysSlice.reducer
|
|
@ -3,12 +3,14 @@ import historyReducer from './historyRecord_reducer'
|
||||||
import redirectReducer from './redirectUrl_reducer'
|
import redirectReducer from './redirectUrl_reducer'
|
||||||
import dirMessageReducer from './dirMessage_reducer'
|
import dirMessageReducer from './dirMessage_reducer'
|
||||||
import clickFileReducer from './clickFile_reducer'
|
import clickFileReducer from './clickFile_reducer'
|
||||||
|
import pushHotkeysReducer from "./pushHotkeys_reducer";
|
||||||
// 用于支持异步函数
|
// 用于支持异步函数
|
||||||
export const store = configureStore({
|
export const store = configureStore({
|
||||||
reducer: {
|
reducer: {
|
||||||
historyRecord:historyReducer,
|
historyRecord:historyReducer,
|
||||||
redirectUrl:redirectReducer,
|
redirectUrl:redirectReducer,
|
||||||
dirMessage:dirMessageReducer,
|
dirMessage:dirMessageReducer,
|
||||||
|
pushHotkeys:pushHotkeysReducer,
|
||||||
clickFileMessage:clickFileReducer
|
clickFileMessage:clickFileReducer
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -7,6 +7,6 @@ export async function importFile(pathName) {
|
||||||
return await fs.readFile(pathName)
|
return await fs.readFile(pathName)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function overWriteFile(filePath) {
|
export async function overWriteFile(filePath,jsonText) {
|
||||||
fs.writeFile(filePath,)
|
await fs.writeFile(filePath,jsonText,{"encoding":"utf-8"})
|
||||||
}
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
export const SAVE = 'CTRL+S'
|
|
@ -0,0 +1 @@
|
||||||
|
export const PUSH_HOTKEY = 'pushHotkeys'
|
|
@ -5,6 +5,7 @@ const { ipcRenderer } = window.require('electron')
|
||||||
const useIpcRenderer = (keyCallbackMap) => {
|
const useIpcRenderer = (keyCallbackMap) => {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
Object.keys(keyCallbackMap).forEach(key => {
|
Object.keys(keyCallbackMap).forEach(key => {
|
||||||
|
console.log("ipcRenderer.on(key, keyCallbackMap[key])",key)
|
||||||
ipcRenderer.on(key, keyCallbackMap[key])
|
ipcRenderer.on(key, keyCallbackMap[key])
|
||||||
})
|
})
|
||||||
return () => {
|
return () => {
|
||||||
|
|
Loading…
Reference in New Issue