From f1642e0f14cb30a4cb9f58396a0b0c69d3245780 Mon Sep 17 00:00:00 2001 From: godo Date: Fri, 29 Nov 2024 08:46:02 +0800 Subject: [PATCH] change markdown ai --- frontend/components.d.ts | 1 - frontend/public/markdown/index.html | 3 +- frontend/public/markdown/katex/dialog.css | 101 --------- frontend/public/markdown/scripts/dialog.css | 233 ++++++++++++++++++++ frontend/public/markdown/scripts/index.js | 67 ++++-- frontend/public/markdown/scripts/modal.js | 160 ++++++++++++++ 6 files changed, 439 insertions(+), 126 deletions(-) delete mode 100644 frontend/public/markdown/katex/dialog.css create mode 100644 frontend/public/markdown/scripts/dialog.css create mode 100644 frontend/public/markdown/scripts/modal.js diff --git a/frontend/components.d.ts b/frontend/components.d.ts index e1c32f9..6dff287 100644 --- a/frontend/components.d.ts +++ b/frontend/components.d.ts @@ -69,7 +69,6 @@ declare module 'vue' { ElCarousel: typeof import('element-plus/es')['ElCarousel'] ElCarouselItem: typeof import('element-plus/es')['ElCarouselItem'] ElCol: typeof import('element-plus/es')['ElCol'] - ElColorPicker: typeof import('element-plus/es')['ElColorPicker'] ElContainer: typeof import('element-plus/es')['ElContainer'] ElDialog: typeof import('element-plus/es')['ElDialog'] ElDrawer: typeof import('element-plus/es')['ElDrawer'] diff --git a/frontend/public/markdown/index.html b/frontend/public/markdown/index.html index e6bfea6..2a967ee 100644 --- a/frontend/public/markdown/index.html +++ b/frontend/public/markdown/index.html @@ -33,7 +33,7 @@ - + @@ -44,6 +44,7 @@ + diff --git a/frontend/public/markdown/katex/dialog.css b/frontend/public/markdown/katex/dialog.css deleted file mode 100644 index cc2b356..0000000 --- a/frontend/public/markdown/katex/dialog.css +++ /dev/null @@ -1,101 +0,0 @@ -.hide { - display: none !important; -} -#aiDialog { - position: absolute; - top: 0%; - left: 0%; - width: 100%; - height: 100%; - z-index: 3; -} -.ai-markdown-dialog { - width: 40%; - min-width: 150px; - height: 300px; - float: right; - margin: 50px; - padding: 10px; - border-radius: 5px; - background-color: #ebf9fb; - box-shadow: 0px 5px 5px #e3dfdf; - text-align: center; -} -.ai-dialog-title { - width: 100%; - height: 40px; - line-height: 40px; -} -.ai-content-box { - position: relative; -} -.ai-dialog-content { - width: 100%; - height: 200px; - resize: none; - outline: none; - border-radius: 5px; - border-color: rgb(203, 203, 203); - box-sizing: border-box; -} -.ai-outline-choose { - width: 100%; - height: 200px; - padding: 20px; - margin: 10px 0; - background-color: #fff; - border: 1px solid #e0dfdf; - border-radius: 5px; - box-sizing: border-box; -} -.ai-outline-choose select, -.ai-outline-choose input { - display: inline-block; - width: 80%; - height: 30px; - padding: 0 10px; - margin: 10px 0; - appearance: none; - background-color: #fff; - background-image: none; - border-radius: 4px; - border: 1px solid #ebebeb; - box-sizing: border-box; - color: #606266; - line-height: 27px; - outline: none; -} -.ai-mask { - position: absolute; - top: 0; - left: 0; - display: flex; - justify-content: center; - align-items: center; - width: 100%; - height: 200px; - background-color: rgba(0, 0, 0, .1); -} -#aiLoader { - width: 32px; - height: 32px; - background-image: url('./loader.svg'); - animation: rotate 2s linear infinite; -} -@keyframes rotate { - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); - } -} -.ai-dialog-button { - min-width: 50px; - border-color: rgb(181, 181, 247); - border-radius: 3px; - background-color: #fff; -} -.ai-dialog-button:hover { - background-color: #ceecfb; -} diff --git a/frontend/public/markdown/scripts/dialog.css b/frontend/public/markdown/scripts/dialog.css new file mode 100644 index 0000000..b50f1e8 --- /dev/null +++ b/frontend/public/markdown/scripts/dialog.css @@ -0,0 +1,233 @@ +.hide { + display: none !important; +} +#aiDialog { + position: absolute; + top: 0%; + left: 0%; + width: 100%; + height: 100%; + z-index: 3; +} +.ai-markdown-dialog { + width: 40%; + min-width: 150px; + height: 300px; + float: right; + margin: 50px; + padding: 10px; + border-radius: 5px; + background-color: #ffffff; /* 更改为白色 */ + box-shadow: 0px 5px 5px #e3dfdf; + text-align: center; +} +.ai-dialog-title { + width: 100%; + height: 40px; + line-height: 40px; + color: #333333; /* 文字颜色调整为深色 */ +} +.ai-content-box { + position: relative; +} +.ai-dialog-content { + width: 100%; + height: 200px; + resize: none; + outline: none; + border-radius: 5px; + border-color: #dcdcdc; /* 边框颜色调整为浅灰色 */ + box-sizing: border-box; +} +.ai-outline-choose { + width: 100%; + height: 200px; + padding: 20px; + margin: 10px 0; + background-color: #ffffff; /* 背景颜色调整为白色 */ + border: 1px solid #dcdcdc; /* 边框颜色调整为浅灰色 */ + border-radius: 5px; + box-sizing: border-box; +} +.ai-outline-choose select, +.ai-outline-choose input { + display: inline-block; + width: 80%; + height: 30px; + padding: 0 10px; + margin: 10px 0; + appearance: none; + background-color: #ffffff; /* 背景颜色调整为白色 */ + background-image: none; + border-radius: 4px; + border: 1px solid #dcdcdc; /* 边框颜色调整为浅灰色 */ + box-sizing: border-box; + color: #333333; /* 文字颜色调整为深色 */ + line-height: 27px; + outline: none; +} +.ai-mask { + position: absolute; + top: 0; + left: 0; + display: flex; + justify-content: center; + align-items: center; + width: 100%; + height: 200px; + background-color: rgba(255, 255, 255, 0.8); /* 背景颜色调整为半透明白色 */ +} +#aiLoader { + width: 32px; + height: 32px; + background-image: url('./loader.svg'); + animation: rotate 2s linear infinite; +} +@keyframes rotate { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } +} +.ai-dialog-button { + min-width: 55px; /* 减小最小宽度 */ + padding: 5px 8px; /* 减少内边距 */ + margin:0 5px; + border: 1px solid #0078d4; /* 边框颜色调整为蓝色 */ + border-radius: 4px; /* 边角稍微圆润一些 */ + background: linear-gradient(145deg, #ffffff, #f0f8ff); /* 更亮的渐变背景 */ + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); /* 更柔和的阴影 */ + font-size: 14px; /* 调整字体大小 */ + color: #333333; /* 文字颜色调整为深色 */ + cursor: pointer; + transition: background 0.3s, box-shadow 0.2s, transform 0.2s; /* 平滑过渡效果 */ +} + +.ai-dialog-button:hover { + background: linear-gradient(145deg, #f0f8ff, #e6f3ff); /* 悬停时的更亮渐变背景 */ + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); /* 略微加深阴影 */ + transform: scale(1.02); /* 微微放大 */ +} + +.ai-dialog-button:active { + background: linear-gradient(145deg, #e6f3ff, #f0f8ff); /* 按下时的更亮渐变背景 */ + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); /* 减轻阴影 */ + transform: scale(0.98); /* 微微缩小 */ +} + +/* 模态对话框的基本样式 */ +.modal { + position: fixed; + z-index: 9999; + left: 0; + top: 0; + width: 100%; + height: 100%; + overflow: auto; + background-color: rgba(255, 255, 255, 0.8); /* 背景颜色调整为半透明白色 */ +} + +/* 模态对话框的内容区域 */ +.modal-content { + background-color: #ffffff; /* 背景颜色调整为白色 */ + margin: 15% auto; + padding: 20px; + border-radius: 5px; + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); + width: 60%; + max-width: 500px; + border: none; +} + +/* 关闭按钮 */ +.modal-close { + color: #333333; /* 文字颜色调整为深色 */ + float: right; + font-size: 28px; + font-weight: bold; + cursor: pointer; + transition: color 0.3s; + margin-top: -10px; + margin-right: -10px; +} + +.modal-close:hover, +.modal-close:focus { + color: #000000; /* 鼠标悬停时文字颜色调整为黑色 */ + text-decoration: none; +} + +/* 按钮通用样式 */ +.modal-button-group { + display: flex; + justify-content: flex-end; + gap: 10px; + margin-top: 20px; + /* 添加一定的顶部间距 */ +} + +.modal-button { + padding: 10px 30px; + margin: 0; + /* 移除外边距 */ + cursor: pointer; + border: none; + border-radius: 8px; + /* 较大的圆角 */ + font-size: 16px; + transition: background-color 0.3s, transform 0.2s, box-shadow 0.2s; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); + /* 添加轻微的阴影 */ +} + + +/* 确定按钮 */ +.modal-button-ok { + border: 1px solid #0078d4; /* 边框颜色调整为蓝色 */ + border-radius: 4px; /* 边角稍微圆润一些 */ + background: linear-gradient(145deg, #ffffff, #f0f8ff); /* 更亮的渐变背景 */ + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); /* 更柔和的阴影 */ + font-size: 14px; /* 调整字体大小 */ + color: #333333; /* 文字颜色调整为深色 */ + cursor: pointer; + transition: background 0.3s, box-shadow 0.2s, transform 0.2s; /* 平滑过渡效果 */ +} + +.modal-button-ok:hover { + background: linear-gradient(145deg, #f0f8ff, #e6f3ff); /* 悬停时的更亮渐变背景 */ + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); /* 略微加深阴影 */ + transform: scale(1.02); /* 微微放大 */ +} + +/* 取消按钮 */ +.modal-button-cancel { + background-color: #e53935; /* 背景颜色保持不变 */ + color: #ffffff; /* 文字颜色调整为白色 */ +} + +.modal-button-cancel:hover { + background-color: #c62828; /* 鼠标悬停时背景颜色调整为深红色 */ + transform: scale(1.05); + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); + /* 加深阴影 */ +} + +/* 标题样式 */ +#modal-title { + font-size: 18px; + color: #333333; /* 文字颜色调整为深色 */ + margin-bottom: 10px; +} + +/* 内容样式 */ +#modal-content { + font-size: 16px; + color: #333333; /* 文字颜色调整为深色 */ + text-align: center; + justify-content: center; + align-items: center; + margin-bottom: 20px; + line-height: 1.5; +} \ No newline at end of file diff --git a/frontend/public/markdown/scripts/index.js b/frontend/public/markdown/scripts/index.js index d580a97..72f87e8 100644 --- a/frontend/public/markdown/scripts/index.js +++ b/frontend/public/markdown/scripts/index.js @@ -1,4 +1,5 @@ var markdownTitle = "" +let aiSelected = "" var CustomHookA = Cherry.createSyntaxHook('codeBlock', Cherry.constants.HOOKS_TYPE_LIST.PAR, { makeHtml(str) { console.warn('custom hook', 'hello'); @@ -78,7 +79,7 @@ var exportDataHook = Cherry.createMenuHook('导出', { // noIcon: true, // name: 'PPTX', // onclick: () => { - + // } // }, { @@ -137,7 +138,7 @@ class AiDialogClass { creation_proofreading: { title: '纠错', btn: ['aiAdd', 'aiReplace', 'aiCancle'] - }, + }, creation_summarize: { title: '总结', btn: ['aiAdd', 'aiReplace', 'aiCancle'] @@ -179,7 +180,7 @@ class AiDialogClass { method: this.cheakAiContent } ] - outline = { + outline = { title: '', content: '', category: '' @@ -229,7 +230,7 @@ class AiDialogClass { ` this.container.appendChild(dialog) - // 绑定事件 + // 绑定事件 const aiOptions = Array.from(this.container.querySelectorAll('.ai-dialog-button')) aiOptions.forEach(item => { item.addEventListener('click', () => { @@ -240,11 +241,11 @@ class AiDialogClass { } }) }) - } + } // 打开弹窗 openDialog(action) { this.container.classList.remove('hide') - const title = 'AI - ' + this.actionArr[action].title + const title = 'AI - ' + this.actionArr[action].title this.container.querySelector('.ai-dialog-title').innerText = title this.addButton(action) } @@ -257,7 +258,7 @@ class AiDialogClass { this.container.querySelector('.ai-outline-choose').classList.add('hide') this.container.querySelector('.ai-content-box').classList.remove('hide') this.container.querySelector('.ai-mask').classList.remove('hide') - } + } const buttonArr = Array.from(this.container.querySelectorAll('.ai-dialog-button')) buttonArr.forEach(item => { const actionType = item.getAttribute('data-type') @@ -298,7 +299,7 @@ class AiDialogClass { // 追加 addAiContent(dialog, that) { const content = dialog.querySelector('textarea').value - cherry.insert(content,false) + cherry.insert(content, false) that.closeDialog(dialog) } // 替换 @@ -316,13 +317,19 @@ class AiDialogClass { } that.outline.title = content.title that.outline.category = content.category - if (content.title !== '' ) { + if (content.title !== '') { window.parent.postMessage({ type: 'aiCreater', data: content, action: 'creation_leader' }, '*') that.openDialog('creation_builder') + }else{ + showModal({ + titleText: '提示', + contentText: "请输入标题", + showOk: true + }); } } // 生成文章 @@ -347,49 +354,60 @@ class AiDialogClass { } } const aiDialog = new AiDialogClass() +const aiTips = (action) => { + if (aiSelected == "") { + showModal({ + titleText: '提示', + contentText: "请选择内容", + showOk: true + }); + return; + } + aiDialog.sendRequest(action, aiSelected) +} var aiEditMenu = Cherry.createMenuHook('AI', { subMenuConfig: [ { noIcon: true, name: '优化', onclick: () => { - aiDialog.sendRequest('creation_optimization', cherry.getMarkdown()) + aiTips("creation_optimization") } }, { noIcon: true, name: '纠错', onclick: () => { - aiDialog.sendRequest('creation_proofreading', cherry.getMarkdown()) + aiTips("creation_proofreading") } }, { noIcon: true, name: '续写', onclick: () => { - aiDialog.sendRequest('creation_continuation', cherry.getMarkdown()) + aiTips("creation_continuation") } }, { noIcon: true, name: '翻译', onclick: () => { - aiDialog.sendRequest('creation_translation', cherry.getMarkdown()) + aiTips("creation_translation") } }, { noIcon: true, name: '总结', onclick: () => { - aiDialog.sendRequest('creation_summarize', cherry.getMarkdown()) + aiTips("creation_summarize") } }, { noIcon: true, name: '大纲', onclick: () => { - // aiDialog.showDialog() - aiDialog.sendRequest('creation_leader', cherry.getMarkdown()) + aiDialog.openDialog('creation_leader') + //aiDialog.sendRequest('creation_leader', cherry.getMarkdown()) } } ] @@ -594,6 +612,12 @@ var basicConfig = { console.log("onClickPreview", event); }, }, + event: { + selectionChange: ({ selections, lastSelections, info }) => { + aiSelected = lastSelections[0] + //console.log(aiSelected) + }, + }, editor: { id: 'cherry-text', name: 'cherry-text', @@ -612,10 +636,7 @@ var basicConfig = { }; var config = Object.assign({}, basicConfig, { value: "" }); window.cherry = new Cherry(config); -// fetch('./markdown/basic.md').then((response) => response.text()).then((value) => { -// var config = Object.assign({}, basicConfig, { value: value }); -// window.cherry = new Cherry(config); -// }); + const debouncedHandleKeyDown = (event) => { // 确保仅在我们的按钮获得焦点时处理快捷键 @@ -649,7 +670,7 @@ function decodeBase64(base64String) { // 将二进制字符串转换为TypedArray const bytes = new Uint8Array(binaryString.length); for (let i = 0; i < binaryString.length; i++) { - bytes[i] = binaryString.charCodeAt(i); + bytes[i] = binaryString.charCodeAt(i); } // 将TypedArray转换为字符串 @@ -669,13 +690,13 @@ const eventHandler = (e) => { return; } let content = data.content; - + if (isBase64(content)) { content = decodeBase64(content); } else if (content instanceof ArrayBuffer) { content = new TextDecoder('utf-8').decode(content); } - + cherry.setMarkdown(content); } if (eventData.type == 'aiReciver') { diff --git a/frontend/public/markdown/scripts/modal.js b/frontend/public/markdown/scripts/modal.js new file mode 100644 index 0000000..9dde421 --- /dev/null +++ b/frontend/public/markdown/scripts/modal.js @@ -0,0 +1,160 @@ +let currentZIndex = 1000; // 初始 z-index 值 + +// 动态生成模态对话框的 HTML 结构 +function createModal() { + const modal = document.createElement('div'); + modal.className = 'modal'; + modal.id = `modal-${currentZIndex}`; // 添加唯一 ID + + const modalContent = document.createElement('div'); + modalContent.className = 'modal-content'; + + const closeBtn = document.createElement('span'); + closeBtn.className = 'modal-close'; + closeBtn.innerHTML = '×'; + + const title = document.createElement('h2'); + title.id = 'modal-title'; + + const contentContainer = document.createElement('div'); + contentContainer.id = 'modal-content-container'; + + const btnGroup = document.createElement('div'); + btnGroup.className = 'modal-button-group'; + const okButton = document.createElement('button'); + okButton.id = 'ok-button'; + okButton.className = 'modal-button modal-button-ok'; + okButton.textContent = '确定'; + + const cancelButton = document.createElement('button'); + cancelButton.id = 'cancel-button'; + cancelButton.className = 'modal-button modal-button-cancel'; + cancelButton.textContent = '取消'; + + modalContent.appendChild(closeBtn); + modalContent.appendChild(title); + modalContent.appendChild(contentContainer); + btnGroup.appendChild(okButton); + btnGroup.appendChild(cancelButton); + modalContent.appendChild(btnGroup); + modal.appendChild(modalContent); + + // 设置初始 z-index + modal.style.zIndex = currentZIndex; + + return modal; +} + +// 显示模态对话框 +function showModal(options) { + const modal = createModal(); + document.body.appendChild(modal); + + const title = modal.querySelector('#modal-title'); + const contentContainer = modal.querySelector('#modal-content-container'); + const okButton = modal.querySelector('#ok-button'); + const cancelButton = modal.querySelector('#cancel-button'); + + title.textContent = options.titleText || '标题'; + + // 清空旧的内容 + while (contentContainer.firstChild) { + contentContainer.removeChild(contentContainer.firstChild); + } + + // 插入内容或自定义 HTML + if (options.contentText) { + const content = document.createElement('p'); + content.textContent = options.contentText; + contentContainer.appendChild(content); + } else if (options.contentHtml) { + contentContainer.innerHTML = options.contentHtml; + } + + if (!options.showOk) { + okButton.style.display = "none"; + } else { + okButton.style.display = "block"; + } + + if (!options.showCancel) { + cancelButton.style.display = "none"; + } else { + cancelButton.style.display = "block"; + } + + // 关闭模态对话框 + function closeModal() { + modal.remove(); + } + + // 当用户点击关闭按钮时 + const closeBtn = modal.querySelector('.modal-close'); + closeBtn.onclick = function() { + closeModal(); + } + + // 当用户点击确定按钮时 + okButton.onclick = function() { + if (typeof options.onOkClick === 'function') { + const shouldClose = options.onOkClick(); + if (shouldClose !== false) { + closeModal(); + } + } else { + closeModal(); + } + } + + // 当用户点击取消按钮时 + cancelButton.onclick = function() { + if (typeof options.onCancelClick === 'function') { + options.onCancelClick(); + } + closeModal(); + } + + // 当用户点击模态对话框外部时 + modal.onclick = function(event) { + if (event.target === modal) { + closeModal(); + } + } + + // 更新当前最高的 z-index + currentZIndex++; +} + +// 示例: 调用 showModal 函数并传递确定和取消按钮的回调函数 +// showModal({ +// titleText: '提示', +// content: '你确定要继续吗?', +// showOk: true, +// showCancel: true, +// onOkClick: function() { +// alert('您点击了确定按钮'); +// }, +// onCancelClick: function() { +// alert('您点击了取消按钮'); +// } +// }); + +// 创建第二个模态框 +// setTimeout(function() { +// showModal({ +// titleText: '回复', +// contentHtml: '', +// showOk: true, +// onOkClick: function() { +// var reply = document.getElementById('reply').value; +// if (reply == '') { +// showModal({ +// titleText: '提示', +// content: '回复内容不能为空', +// showOk: true +// }) +// return false; // 阻止关闭模态框 +// } +// } +// }); +// }, 2000); \ No newline at end of file