diff --git a/packages/word/src/editor/core/range/RangeManager.ts b/packages/word/src/editor/core/range/RangeManager.ts
index 1568166..5bb18fd 100644
--- a/packages/word/src/editor/core/range/RangeManager.ts
+++ b/packages/word/src/editor/core/range/RangeManager.ts
@@ -433,6 +433,7 @@ export class RangeManager {
el => !el.underline && !el.control?.underline
)
const strikeout = !~curElementList.findIndex(el => !el.strikeout)
+ const aiEdit = !~curElementList.findIndex(el => !el.aiEdit)
const color = curElement.color || null
const highlight = curElement.highlight || null
const rowFlex = curElement.rowFlex || null
@@ -461,6 +462,7 @@ export class RangeManager {
italic,
underline,
strikeout,
+ aiEdit,
color,
highlight,
rowFlex,
@@ -503,6 +505,7 @@ export class RangeManager {
italic: false,
underline: false,
strikeout: false,
+ aiEdit: false,
color: null,
highlight: null,
rowFlex: null,
diff --git a/packages/word/src/editor/interface/Element.ts b/packages/word/src/editor/interface/Element.ts
index 734f7b1..b758b0b 100644
--- a/packages/word/src/editor/interface/Element.ts
+++ b/packages/word/src/editor/interface/Element.ts
@@ -33,6 +33,7 @@ export interface IElementStyle {
italic?: boolean
underline?: boolean
strikeout?: boolean
+ aiEdit?: boolean
rowFlex?: RowFlex
rowMargin?: number
letterSpacing?: number
diff --git a/packages/word/src/editor/interface/Listener.ts b/packages/word/src/editor/interface/Listener.ts
index b31d435..18e4276 100644
--- a/packages/word/src/editor/interface/Listener.ts
+++ b/packages/word/src/editor/interface/Listener.ts
@@ -23,6 +23,7 @@ export interface IRangeStyle {
italic: boolean
underline: boolean
strikeout: boolean
+ aiEdit: boolean
color: string | null
highlight: string | null
rowFlex: RowFlex | null
diff --git a/packages/word/src/plugins/floatingToolbar/enum/index.ts b/packages/word/src/plugins/floatingToolbar/enum/index.ts
index 8205921..c6ae04e 100644
--- a/packages/word/src/plugins/floatingToolbar/enum/index.ts
+++ b/packages/word/src/plugins/floatingToolbar/enum/index.ts
@@ -6,5 +6,6 @@ export enum ToolbarType {
UNDERLINE = 'underline',
STRIKEOUT = 'strikeout',
COLOR = 'color',
- HIGHLIGHT = 'highlight'
+ HIGHLIGHT = 'highlight',
+ AI_EDIT = 'ai-edit'
}
diff --git a/packages/word/src/plugins/floatingToolbar/icons/Svgs.ts b/packages/word/src/plugins/floatingToolbar/icons/Svgs.ts
new file mode 100644
index 0000000..ba209c5
--- /dev/null
+++ b/packages/word/src/plugins/floatingToolbar/icons/Svgs.ts
@@ -0,0 +1,15 @@
+export const Svgs = {
+ tips: ``,
+ check: ``,
+ refresh: ``,
+ aiPanelStart: ``,
+ addContent: ``,
+ replace: ` `,
+ cancle: ``,
+ optimize: ``,
+ checkGrammar: ``,
+ simplification: ``,
+ richContent: ``,
+ translation: ``,
+ summary: ``
+}
\ No newline at end of file
diff --git a/packages/word/src/plugins/floatingToolbar/icons/ai-edit.svg b/packages/word/src/plugins/floatingToolbar/icons/ai-edit.svg
new file mode 100644
index 0000000..d3e202b
--- /dev/null
+++ b/packages/word/src/plugins/floatingToolbar/icons/ai-edit.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/packages/word/src/plugins/floatingToolbar/index.ts b/packages/word/src/plugins/floatingToolbar/index.ts
index 9b3f429..06d1d6f 100644
--- a/packages/word/src/plugins/floatingToolbar/index.ts
+++ b/packages/word/src/plugins/floatingToolbar/index.ts
@@ -5,6 +5,7 @@ import './style/index.scss'
import { ToolbarType } from './enum'
import { IToolbarRegister } from './interface'
import { PLUGIN_PREFIX } from './constant'
+import { Svgs } from './icons/Svgs'
function createPickerToolbar(
container: HTMLDivElement,
@@ -60,9 +61,110 @@ function createPickerToolbar(
changed(color)
})
}
+export const defaultAiPanelMenus = [
+ {
+ prompt: `{content}\n请帮我优化一下这段内容,并直接返回优化后的结果。\n注意:你应该先判断一下这句话是中文还是英文,如果是中文,请给我返回中文的内容,如果是英文,请给我返回英文内容,只需要返回内容即可,不需要告知我是中文还是英文。`,
+ icon: Svgs.optimize,
+ title: '改进写作'
+ },
+ {
+ prompt: `{content}\n请帮我检查一下这段内容,是否有拼写错误或者语法上的错误。\n注意:你应该先判断一下这句话是中文还是英文,如果是中文,请给我返回中文的内容,如果是英文,请给我返回英文内容,只需要返回内容即可,不需要告知我是中文还是英文。`,
+ icon: Svgs.checkGrammar,
+ title: '检查拼写和语法'
+ },
+ {
+ prompt: `{content}\n这句话的内容较长,帮我简化一下这个内容,并直接返回简化后的内容结果。\n注意:你应该先判断一下这句话是中文还是英文,如果是中文,请给我返回中文的内容,如果是英文,请给我返回英文内容,只需要返回内容即可,不需要告知我是中文还是英文。`,
+ icon: Svgs.simplification,
+ title: '简化内容'
+ },
+ {
+ prompt: `{content}\n这句话的内容较简短,帮我简单的优化和丰富一下内容,并直接返回优化后的结果。注意:优化的内容不能超过原来内容的 2 倍。\n注意:你应该先判断一下这句话是中文还是英文,如果是中文,请给我返回中文的内容,如果是英文,请给我返回英文内容,只需要返回内容即可,不需要告知我是中文还是英文。`,
+ icon: Svgs.richContent,
+ title: '丰富内容'
+ },
+ '
',
+ {
+ prompt: `{content}\n请帮我翻译以上内容,在翻译之前,想先判断一下这个内容是不是中文,如果是中文,则翻译问英文,如果是其他语言,则需要翻译为中文,注意,你只需要返回翻译的结果,不需要对此进行任何解释,不需要除了翻译结果以外的其他任何内容。`,
+ icon: Svgs.translation,
+ title: '翻译'
+ },
+ {
+ prompt: `{content}\n请帮我总结以上内容,并直接返回总结的结果\n注意:你应该先判断一下这句话是中文还是英文,如果是中文,请给我返回中文的内容,如果是英文,请给我返回英文内容,只需要返回内容即可,不需要告知我是中文还是英文。`,
+ icon: Svgs.summary,
+ title: '总结'
+ }
+]
+// 创建ai选择栏
+function createAIToolbar(
+ container: HTMLDivElement,
+ toolbarType: ToolbarType,
+ changed: (color: string) => void
+) {
+ const toolbarItem = document.createElement('div')
+ toolbarItem.classList.add(`${PLUGIN_PREFIX}-picker-ai`)
+ toolbarItem.classList.add(`${PLUGIN_PREFIX}-${toolbarType}`)
+ const chooseBox = document.createElement('div')
+ chooseBox.classList.add('ce-picker-container')
+ toolbarItem.append(chooseBox)
+ const aiBubbleMenuItems = defaultAiPanelMenus
+ toolbarItem.innerHTML = `
+
+
+
+
+
+
+
+ ${Svgs.tips}
+ 提示:您可以在上面输入文字或者选择下方的操作
+
+
+
+
+
+
+
+ `
+ container.append(toolbarItem)
+}
// 工具栏列表
const toolbarRegisterList: IToolbarRegister[] = [
+ {
+ // key: ToolbarType.AI_EDIT,
+ // callback(editor) {
+ // console.log('editor:', editor)
+ // }
+ render(container, editor) {
+ createAIToolbar(container, ToolbarType.AI_EDIT, color => {
+ editor.command.executeColor(color)
+ })
+ }
+ },
+ {
+ isDivider: true
+ },
{
key: ToolbarType.SIZE_ADD,
callback(editor) {
@@ -178,6 +280,12 @@ export default function floatingToolbarPlugin(editor: Editor) {
toolbarContainer.style.left = `${position.x}px`
toolbarContainer.style.top = `${position.y + position.height}px`
// 样式回显
+ const aiDom = toolbarContainer.querySelector(
+ `.${PLUGIN_PREFIX}-ai-edit`
+ )
+ if (aiDom) {
+ toggleToolbarItemActive(aiDom, rangeStyle.aiEdit)
+ }
const boldDom = toolbarContainer.querySelector(
`.${PLUGIN_PREFIX}-bold`
)
diff --git a/packages/word/src/plugins/floatingToolbar/style/index.scss b/packages/word/src/plugins/floatingToolbar/style/index.scss
index 5c1184f..b1c524b 100644
--- a/packages/word/src/plugins/floatingToolbar/style/index.scss
+++ b/packages/word/src/plugins/floatingToolbar/style/index.scss
@@ -44,6 +44,10 @@
background-color: #cfd2d8;
}
+ &.ce-ai-edit i {
+ background: url(../icons/ai-edit.svg);
+ }
+
&.ce-size-add i {
background: url(../icons/size-add.svg);
}
@@ -97,4 +101,200 @@
background: url(../icons/highlight.svg);
}
}
+}
+.aie-container {
+ position: absolute;
+ top: 40px;
+ left: 0;
+ height: 100%;
+
+ *, ::before, ::after {
+ box-sizing: content-box;
+ }
+ .aie-ai-panel-body {
+ width: 350px;
+ border: solid 1px;
+ background: #ffffff;
+ border-radius: 5px;
+ border-color: #eee;
+ box-shadow: 0 0 7px 0 rgba(0, 0, 0, .15);
+ display: flex;
+ flex-direction: column;
+ overflow: hidden;
+
+ &-tips {
+ width: 100%;
+ padding: 10px;
+ color: #999;
+ font-size: 12px;
+ background-color: #fafafa;
+ box-sizing: border-box;
+ display: flex;
+ align-items: center;
+
+ svg {
+ width: 15px;
+ height: 15px;
+ margin-right: 5px;
+ }
+ }
+
+ &-content {
+ width: 100%;
+ // height: 160px;
+ position: relative;
+
+ .loader {
+ position: absolute;
+ top: 10px;
+ right: 10px;
+ display: none;
+
+ svg {
+ width: 16px;
+ color: #999;
+ animation: rotate 2s linear infinite;
+ @keyframes rotate {
+ from {
+ transform: rotate(0deg);
+ }
+ to {
+ transform: rotate(360deg);
+ }
+ }
+ }
+ }
+
+ textarea {
+ width: 100%;
+ height: 100%;
+ max-height: 300px;
+ padding: 15px;
+ box-sizing: border-box;
+ font-size: 12px;
+ line-height: 1.6em;
+ font-family: Arial, 'Helvetica Neue', Helvetica, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', sans-serif;
+ border: none;
+ resize: none;
+ }
+
+ textarea:focus-visible {
+ outline: none;
+ }
+
+ }
+
+ &-input {
+ display: flex;
+ justify-content: space-between;
+ box-sizing: border-box;
+ border-bottom: 1px solid;
+ border-bottom-color: #eee;
+ align-items: center;
+ padding: 5px 10px 5px 5px;
+
+ input {
+ width: 92%;
+ height: 90%;
+ border: none;
+ margin: 0;
+ background: #ffffff;
+ font-size: 12px;
+ font-family: Arial, 'Helvetica Neue', Helvetica, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', sans-serif;
+ background-color: #edf0f5;
+ padding: 10px;
+ box-sizing: border-box;
+ border-radius: 4px;
+
+ &::-webkit-input-placeholder {
+ color: #ccc;
+ font-size: 12px;
+ }
+ }
+
+ input:focus-visible {
+ outline: none;
+ }
+
+ button {
+ border: none;
+ border-radius: 50%;
+ width: 25px !important;
+ height: 25px !important;
+ padding: 0;
+ margin-left: 5px;
+ background: #609eec;
+
+ svg {
+ fill: #fff;
+ width: 14px;
+ margin-top: 2px;
+ }
+ }
+
+ button:hover {
+ background: #ccc;
+ cursor: pointer;
+ }
+ }
+ }
+
+ .aie-ai-panel-footer {
+ width: fit-content;
+ border: solid 1px;
+ border-color: #eee;
+ background: #ffffff;
+ border-radius: 5px;
+ box-shadow: 0 0 7px 0 rgba(0, 0, 0, .15);
+ display: flex;
+ padding: 10px 0;
+ flex-direction: column;
+ margin-top: 5px;
+
+ &-tips {
+ padding: 5px 10px;
+ color: #999;
+ font-size: 12px;
+ margin-bottom: 5px;
+ }
+
+ hr {
+ height: 1px;
+ width: 100%;
+ margin: 5px 0;
+ background-color: #eaeaea;
+ border: none;
+ }
+
+ p {
+ width: 100%;
+ margin: 0;
+ }
+
+ p {
+ cursor: pointer;
+ display: flex;
+ align-items: center;
+ width: 100%;
+ box-sizing: border-box;
+ height: 25px;
+ line-height: 25px;
+ font-weight: 600;
+ font-size: 12px;
+ padding: 0 20px;
+ color: #666;
+ text-decoration: none;
+ font-family: Arial, 'Helvetica Neue', Helvetica, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', sans-serif;
+ }
+
+ p:hover {
+ background: #e3e2e2;
+ }
+
+ svg {
+ width: 16px;
+ height: 16px;
+ margin-right: 10px;
+ }
+ }
}
\ No newline at end of file