mirror of
https://github.com/pipipi-pikachu/PPTist.git
synced 2025-04-15 02:20:00 +08:00
update
This commit is contained in:
parent
5bf32419bb
commit
942488f47c
@ -19,4 +19,13 @@
|
|||||||
}
|
}
|
||||||
.ant-radio-button-wrapper {
|
.ant-radio-button-wrapper {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
}
|
||||||
|
.ant-slider-track {
|
||||||
|
background-color: $themeColor;
|
||||||
|
}
|
||||||
|
.ant-slider-handle {
|
||||||
|
border-color: $themeColor;
|
||||||
|
}
|
||||||
|
.ant-select {
|
||||||
|
user-select: none;
|
||||||
}
|
}
|
@ -44,7 +44,7 @@ export const setTextAlign = (tr: Transaction, schema: Schema, alignment: string)
|
|||||||
let { attrs } = node
|
let { attrs } = node
|
||||||
if(alignment) attrs = { ...attrs, align: alignment }
|
if(alignment) attrs = { ...attrs, align: alignment }
|
||||||
else attrs = { ...attrs, align: null }
|
else attrs = { ...attrs, align: null }
|
||||||
tr = tr.setNodeMarkup(pos, nodeType, attrs, node.marks);
|
tr = tr.setNodeMarkup(pos, nodeType, attrs, node.marks)
|
||||||
})
|
})
|
||||||
|
|
||||||
return tr
|
return tr
|
||||||
|
@ -2,6 +2,7 @@ import mitt, { Emitter } from 'mitt'
|
|||||||
|
|
||||||
export enum EmitterEvents {
|
export enum EmitterEvents {
|
||||||
UPDATE_TEXT_STATE = 'UPDATE_TEXT_STATE',
|
UPDATE_TEXT_STATE = 'UPDATE_TEXT_STATE',
|
||||||
|
EXEC_TEXT_COMMAND = 'EXEC_TEXT_COMMAND',
|
||||||
}
|
}
|
||||||
|
|
||||||
const emitter: Emitter = mitt()
|
const emitter: Emitter = mitt()
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
<Select
|
<Select
|
||||||
style="flex: 3;"
|
style="flex: 3;"
|
||||||
:value="richTextAttrs.fontname"
|
:value="richTextAttrs.fontname"
|
||||||
|
@change="value => emitRichTextCommand('fontname', value)"
|
||||||
>
|
>
|
||||||
<SelectOption v-for="font in availableFonts" :key="font.en" :value="font.en">
|
<SelectOption v-for="font in availableFonts" :key="font.en" :value="font.en">
|
||||||
<span :style="{ fontFamily: font.en }">{{font.zh}}</span>
|
<span :style="{ fontFamily: font.en }">{{font.zh}}</span>
|
||||||
@ -12,6 +13,7 @@
|
|||||||
<Select
|
<Select
|
||||||
style="flex: 2;"
|
style="flex: 2;"
|
||||||
:value="richTextAttrs.fontsize"
|
:value="richTextAttrs.fontsize"
|
||||||
|
@change="value => emitRichTextCommand('fontsize', value)"
|
||||||
>
|
>
|
||||||
<SelectOption v-for="fontsize in fontSizeOptions" :key="fontsize" :value="fontsize">
|
<SelectOption v-for="fontsize in fontSizeOptions" :key="fontsize" :value="fontsize">
|
||||||
{{fontsize}}
|
{{fontsize}}
|
||||||
@ -22,7 +24,10 @@
|
|||||||
<ButtonGroup class="row">
|
<ButtonGroup class="row">
|
||||||
<Popover trigger="click">
|
<Popover trigger="click">
|
||||||
<template #content>
|
<template #content>
|
||||||
<ColorPicker v-model="richTextAttrs.color" />
|
<ColorPicker
|
||||||
|
:modelValue="richTextAttrs.color"
|
||||||
|
@update:modelValue="value => emitRichTextCommand('color', value)"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
<Button class="text-color-btn" style="flex: 1;">
|
<Button class="text-color-btn" style="flex: 1;">
|
||||||
<FontColorsOutlined />
|
<FontColorsOutlined />
|
||||||
@ -31,7 +36,10 @@
|
|||||||
</Popover>
|
</Popover>
|
||||||
<Popover trigger="click">
|
<Popover trigger="click">
|
||||||
<template #content>
|
<template #content>
|
||||||
<ColorPicker v-model="richTextAttrs.backcolor" />
|
<ColorPicker
|
||||||
|
:modelValue="richTextAttrs.backcolor"
|
||||||
|
@update:modelValue="value => emitRichTextCommand('backcolor', value)"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
<Button class="text-color-btn" style="flex: 1;">
|
<Button class="text-color-btn" style="flex: 1;">
|
||||||
<HighlightOutlined />
|
<HighlightOutlined />
|
||||||
@ -40,7 +48,10 @@
|
|||||||
</Popover>
|
</Popover>
|
||||||
<Popover trigger="click">
|
<Popover trigger="click">
|
||||||
<template #content>
|
<template #content>
|
||||||
<ColorPicker v-model="fill" />
|
<ColorPicker
|
||||||
|
:modelValue="fill"
|
||||||
|
@update:modelValue="value => updateFill(value)"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
<Button class="text-color-btn" style="flex: 1;">
|
<Button class="text-color-btn" style="flex: 1;">
|
||||||
<BgColorsOutlined />
|
<BgColorsOutlined />
|
||||||
@ -50,31 +61,79 @@
|
|||||||
</ButtonGroup>
|
</ButtonGroup>
|
||||||
|
|
||||||
<CheckboxButtonGroup class="row">
|
<CheckboxButtonGroup class="row">
|
||||||
<CheckboxButton style="flex: 1;" :checked="richTextAttrs.bold"><BoldOutlined /></CheckboxButton>
|
<CheckboxButton
|
||||||
<CheckboxButton style="flex: 1;" :checked="richTextAttrs.em"><ItalicOutlined /></CheckboxButton>
|
style="flex: 1;"
|
||||||
<CheckboxButton style="flex: 1;" :checked="richTextAttrs.underline"><UnderlineOutlined /></CheckboxButton>
|
:checked="richTextAttrs.bold"
|
||||||
<CheckboxButton style="flex: 1;" :checked="richTextAttrs.strikethrough"><StrikethroughOutlined /></CheckboxButton>
|
@click="emitRichTextCommand('bold')"
|
||||||
|
><BoldOutlined /></CheckboxButton>
|
||||||
|
<CheckboxButton
|
||||||
|
style="flex: 1;"
|
||||||
|
:checked="richTextAttrs.em"
|
||||||
|
@click="emitRichTextCommand('em')"
|
||||||
|
><ItalicOutlined /></CheckboxButton>
|
||||||
|
<CheckboxButton
|
||||||
|
style="flex: 1;"
|
||||||
|
:checked="richTextAttrs.underline"
|
||||||
|
@click="emitRichTextCommand('underline')"
|
||||||
|
><UnderlineOutlined /></CheckboxButton>
|
||||||
|
<CheckboxButton
|
||||||
|
style="flex: 1;"
|
||||||
|
:checked="richTextAttrs.strikethrough"
|
||||||
|
@click="emitRichTextCommand('strikethrough')"
|
||||||
|
><StrikethroughOutlined /></CheckboxButton>
|
||||||
</CheckboxButtonGroup>
|
</CheckboxButtonGroup>
|
||||||
|
|
||||||
<CheckboxButtonGroup class="row">
|
<CheckboxButtonGroup class="row">
|
||||||
<CheckboxButton style="flex: 1;" :checked="richTextAttrs.superscript">上</CheckboxButton>
|
<CheckboxButton
|
||||||
<CheckboxButton style="flex: 1;" :checked="richTextAttrs.subscript">下</CheckboxButton>
|
style="flex: 1;"
|
||||||
<CheckboxButton style="flex: 1;" :checked="richTextAttrs.code">码</CheckboxButton>
|
:checked="richTextAttrs.superscript"
|
||||||
<CheckboxButton style="flex: 1;" :checked="richTextAttrs.blockquote">引</CheckboxButton>
|
@click="emitRichTextCommand('superscript')"
|
||||||
<CheckboxButton style="flex: 1;">清</CheckboxButton>
|
>上</CheckboxButton>
|
||||||
|
<CheckboxButton
|
||||||
|
style="flex: 1;"
|
||||||
|
:checked="richTextAttrs.subscript"
|
||||||
|
@click="emitRichTextCommand('subscript')"
|
||||||
|
>下</CheckboxButton>
|
||||||
|
<CheckboxButton
|
||||||
|
style="flex: 1;"
|
||||||
|
:checked="richTextAttrs.code"
|
||||||
|
@click="emitRichTextCommand('code')"
|
||||||
|
>码</CheckboxButton>
|
||||||
|
<CheckboxButton
|
||||||
|
style="flex: 1;"
|
||||||
|
:checked="richTextAttrs.blockquote"
|
||||||
|
@click="emitRichTextCommand('blockquote')"
|
||||||
|
>引</CheckboxButton>
|
||||||
|
<CheckboxButton
|
||||||
|
style="flex: 1;"
|
||||||
|
@click="emitRichTextCommand('clear')"
|
||||||
|
>清</CheckboxButton>
|
||||||
</CheckboxButtonGroup>
|
</CheckboxButtonGroup>
|
||||||
|
|
||||||
<Divider />
|
<Divider />
|
||||||
|
|
||||||
<RadioGroup class="row" button-style="solid" :value="richTextAttrs.align">
|
<RadioGroup
|
||||||
|
class="row"
|
||||||
|
button-style="solid"
|
||||||
|
:value="richTextAttrs.align"
|
||||||
|
@change="e => emitRichTextCommand('align', e.target.value)"
|
||||||
|
>
|
||||||
<RadioButton value="left" style="flex: 1;"><AlignLeftOutlined /></RadioButton>
|
<RadioButton value="left" style="flex: 1;"><AlignLeftOutlined /></RadioButton>
|
||||||
<RadioButton value="center" style="flex: 1;"><AlignCenterOutlined /></RadioButton>
|
<RadioButton value="center" style="flex: 1;"><AlignCenterOutlined /></RadioButton>
|
||||||
<RadioButton value="right" style="flex: 1;"><AlignRightOutlined /></RadioButton>
|
<RadioButton value="right" style="flex: 1;"><AlignRightOutlined /></RadioButton>
|
||||||
</RadioGroup>
|
</RadioGroup>
|
||||||
|
|
||||||
<CheckboxButtonGroup class="row">
|
<CheckboxButtonGroup class="row">
|
||||||
<CheckboxButton style="flex: 1;" :checked="richTextAttrs.bulletList"><UnorderedListOutlined /></CheckboxButton>
|
<CheckboxButton
|
||||||
<CheckboxButton style="flex: 1;" :checked="richTextAttrs.orderedList"><OrderedListOutlined /></CheckboxButton>
|
style="flex: 1;"
|
||||||
|
:checked="richTextAttrs.bulletList"
|
||||||
|
@click="emitRichTextCommand('bulletList')"
|
||||||
|
><UnorderedListOutlined /></CheckboxButton>
|
||||||
|
<CheckboxButton
|
||||||
|
style="flex: 1;"
|
||||||
|
:checked="richTextAttrs.orderedList"
|
||||||
|
@click="emitRichTextCommand('orderedList')"
|
||||||
|
><OrderedListOutlined /></CheckboxButton>
|
||||||
</CheckboxButtonGroup>
|
</CheckboxButtonGroup>
|
||||||
|
|
||||||
<Divider />
|
<Divider />
|
||||||
@ -95,15 +154,10 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Divider />
|
<Divider />
|
||||||
|
|
||||||
<ElementOutline />
|
<ElementOutline />
|
||||||
|
|
||||||
<Divider />
|
<Divider />
|
||||||
|
|
||||||
<ElementShadow />
|
<ElementShadow />
|
||||||
|
|
||||||
<Divider />
|
<Divider />
|
||||||
|
|
||||||
<ElementOpacity />
|
<ElementOpacity />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -222,6 +276,10 @@ export default defineComponent({
|
|||||||
emitter.off(EmitterEvents.UPDATE_TEXT_STATE, attr => updateRichTextAttrs(attr))
|
emitter.off(EmitterEvents.UPDATE_TEXT_STATE, attr => updateRichTextAttrs(attr))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const emitRichTextCommand = (command: string, value?: string) => {
|
||||||
|
emitter.emit(EmitterEvents.EXEC_TEXT_COMMAND, { command, value })
|
||||||
|
}
|
||||||
|
|
||||||
const { addHistorySnapshot } = useHistorySnapshot()
|
const { addHistorySnapshot } = useHistorySnapshot()
|
||||||
|
|
||||||
const updateLineHeight = (value: number) => {
|
const updateLineHeight = (value: number) => {
|
||||||
@ -236,6 +294,12 @@ export default defineComponent({
|
|||||||
addHistorySnapshot()
|
addHistorySnapshot()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const updateFill = (value: string) => {
|
||||||
|
const props = { fill: value }
|
||||||
|
store.commit(MutationTypes.UPDATE_ELEMENT, { id: handleElement.value.id, props })
|
||||||
|
addHistorySnapshot()
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
fill,
|
fill,
|
||||||
lineHeight,
|
lineHeight,
|
||||||
@ -247,12 +311,17 @@ export default defineComponent({
|
|||||||
wordSpaceOptions,
|
wordSpaceOptions,
|
||||||
updateLineHeight,
|
updateLineHeight,
|
||||||
updateWordSpace,
|
updateWordSpace,
|
||||||
|
updateFill,
|
||||||
|
emitRichTextCommand,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
.text-style-panel {
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
.row {
|
.row {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -66,6 +66,8 @@ export default defineComponent({
|
|||||||
position: relative;
|
position: relative;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
|
word-break: break-word;
|
||||||
|
font-family: '微软雅黑';
|
||||||
|
|
||||||
.text {
|
.text {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
@ -51,6 +51,14 @@ import useElementShadow from '@/views/components/element/hooks/useElementShadow'
|
|||||||
import useHistorySnapshot from '@/hooks/useHistorySnapshot'
|
import useHistorySnapshot from '@/hooks/useHistorySnapshot'
|
||||||
|
|
||||||
import ElementOutline from '@/views/components/element/ElementOutline.vue'
|
import ElementOutline from '@/views/components/element/ElementOutline.vue'
|
||||||
|
import { toggleMark, wrapIn } from 'prosemirror-commands'
|
||||||
|
import { alignmentCommand } from '@/prosemirror/commands/setTextAlign'
|
||||||
|
import { toggleList } from '@/prosemirror/commands/toggleList'
|
||||||
|
|
||||||
|
interface CommandPayload {
|
||||||
|
command: string;
|
||||||
|
value?: string;
|
||||||
|
}
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'editable-element-text',
|
name: 'editable-element-text',
|
||||||
@ -81,7 +89,7 @@ export default defineComponent({
|
|||||||
id: props.elementInfo.id,
|
id: props.elementInfo.id,
|
||||||
props: { height: realHeight },
|
props: { height: realHeight },
|
||||||
})
|
})
|
||||||
}, 500, { trailing: true })
|
}, 300, { trailing: true })
|
||||||
|
|
||||||
const updateTextElementHeight = () => {
|
const updateTextElementHeight = () => {
|
||||||
if(!elementRef.value) return
|
if(!elementRef.value) return
|
||||||
@ -115,12 +123,12 @@ export default defineComponent({
|
|||||||
props: { content: editorView.dom.innerHTML },
|
props: { content: editorView.dom.innerHTML },
|
||||||
})
|
})
|
||||||
addHistorySnapshot()
|
addHistorySnapshot()
|
||||||
}, 500, { trailing: true })
|
}, 300, { trailing: true })
|
||||||
|
|
||||||
const handleClick = debounce(function() {
|
const handleClick = debounce(function() {
|
||||||
const attr = getTextAttrs(editorView)
|
const attr = getTextAttrs(editorView)
|
||||||
emitter.emit(EmitterEvents.UPDATE_TEXT_STATE, attr)
|
emitter.emit(EmitterEvents.UPDATE_TEXT_STATE, attr)
|
||||||
}, 50, { trailing: true })
|
}, 30, { trailing: true })
|
||||||
|
|
||||||
const handleKeydown = () => {
|
const handleKeydown = () => {
|
||||||
handleInput()
|
handleInput()
|
||||||
@ -164,6 +172,81 @@ export default defineComponent({
|
|||||||
const shadow = computed(() => props.elementInfo.shadow)
|
const shadow = computed(() => props.elementInfo.shadow)
|
||||||
const { shadowStyle } = useElementShadow(shadow)
|
const { shadowStyle } = useElementShadow(shadow)
|
||||||
|
|
||||||
|
const handleElementId = computed(() => store.state.handleElementId)
|
||||||
|
|
||||||
|
const execCommand = (payload: CommandPayload) => {
|
||||||
|
if(handleElementId.value !== props.elementInfo.id) return
|
||||||
|
|
||||||
|
if(payload.command === 'fontname' && payload.value) {
|
||||||
|
const mark = editorView.state.schema.marks.fontname.create({ fontname: payload.value })
|
||||||
|
const { $from, $to } = editorView.state.selection
|
||||||
|
editorView.dispatch(editorView.state.tr.addMark($from.pos, $to.pos, mark))
|
||||||
|
}
|
||||||
|
else if(payload.command === 'fontsize' && payload.value) {
|
||||||
|
const mark = editorView.state.schema.marks.fontsize.create({ fontsize: payload.value })
|
||||||
|
const { $from, $to } = editorView.state.selection
|
||||||
|
editorView.dispatch(editorView.state.tr.addMark($from.pos, $to.pos, mark))
|
||||||
|
}
|
||||||
|
else if(payload.command === 'color' && payload.value) {
|
||||||
|
const mark = editorView.state.schema.marks.forecolor.create({ color: payload.value })
|
||||||
|
const { $from, $to } = editorView.state.selection
|
||||||
|
editorView.dispatch(editorView.state.tr.addMark($from.pos, $to.pos, mark))
|
||||||
|
}
|
||||||
|
else if(payload.command === 'backcolor' && payload.value) {
|
||||||
|
const mark = editorView.state.schema.marks.backcolor.create({ backcolor: payload.value })
|
||||||
|
const { $from, $to } = editorView.state.selection
|
||||||
|
editorView.dispatch(editorView.state.tr.addMark($from.pos, $to.pos, mark))
|
||||||
|
}
|
||||||
|
else if(payload.command === 'bold') {
|
||||||
|
toggleMark(editorView.state.schema.marks.strong)(editorView.state, editorView.dispatch)
|
||||||
|
}
|
||||||
|
else if(payload.command === 'em') {
|
||||||
|
toggleMark(editorView.state.schema.marks.em)(editorView.state, editorView.dispatch)
|
||||||
|
}
|
||||||
|
else if(payload.command === 'underline') {
|
||||||
|
toggleMark(editorView.state.schema.marks.underline)(editorView.state, editorView.dispatch)
|
||||||
|
}
|
||||||
|
else if(payload.command === 'strikethrough') {
|
||||||
|
toggleMark(editorView.state.schema.marks.strikethrough)(editorView.state, editorView.dispatch)
|
||||||
|
}
|
||||||
|
else if(payload.command === 'subscript') {
|
||||||
|
toggleMark(editorView.state.schema.marks.subscript)(editorView.state, editorView.dispatch)
|
||||||
|
}
|
||||||
|
else if(payload.command === 'superscript') {
|
||||||
|
toggleMark(editorView.state.schema.marks.superscript)(editorView.state, editorView.dispatch)
|
||||||
|
}
|
||||||
|
else if(payload.command === 'blockquote') {
|
||||||
|
wrapIn(editorView.state.schema.nodes.blockquote)(editorView.state, editorView.dispatch)
|
||||||
|
}
|
||||||
|
else if(payload.command === 'code') {
|
||||||
|
toggleMark(editorView.state.schema.marks.code)(editorView.state, editorView.dispatch)
|
||||||
|
}
|
||||||
|
else if(payload.command === 'align' && payload.value) {
|
||||||
|
alignmentCommand(editorView, payload.value)
|
||||||
|
}
|
||||||
|
else if(payload.command === 'bulletList') {
|
||||||
|
const { bullet_list: bulletList, list_item: listItem } = editorView.state.schema.nodes
|
||||||
|
toggleList(bulletList, listItem)(editorView.state, editorView.dispatch)
|
||||||
|
}
|
||||||
|
else if(payload.command === 'orderedList') {
|
||||||
|
const { ordered_list: orderedList, list_item: listItem } = editorView.state.schema.nodes
|
||||||
|
toggleList(orderedList, listItem)(editorView.state, editorView.dispatch)
|
||||||
|
}
|
||||||
|
else if(payload.command === 'clear') {
|
||||||
|
if(editorView.state.selection.empty) return false
|
||||||
|
const { $from, $to } = editorView.state.selection
|
||||||
|
editorView.dispatch(editorView.state.tr.removeMark($from.pos, $to.pos))
|
||||||
|
}
|
||||||
|
editorView.focus()
|
||||||
|
handleInput()
|
||||||
|
handleClick()
|
||||||
|
}
|
||||||
|
|
||||||
|
emitter.on(EmitterEvents.EXEC_TEXT_COMMAND, payload => execCommand(payload))
|
||||||
|
onUnmounted(() => {
|
||||||
|
emitter.off(EmitterEvents.EXEC_TEXT_COMMAND, payload => execCommand(payload))
|
||||||
|
})
|
||||||
|
|
||||||
return {
|
return {
|
||||||
elementRef,
|
elementRef,
|
||||||
editorViewRef,
|
editorViewRef,
|
||||||
@ -188,6 +271,8 @@ export default defineComponent({
|
|||||||
position: relative;
|
position: relative;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
|
word-break: break-word;
|
||||||
|
font-family: '微软雅黑';
|
||||||
|
|
||||||
.text {
|
.text {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user