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
f2661b58d4
commit
6b67e87699
@ -75,3 +75,41 @@ export const getAttrValueInSelection = (view: EditorView, attr: string) => {
|
||||
})
|
||||
return value
|
||||
}
|
||||
|
||||
export const getTextAttrs = (view: EditorView) => {
|
||||
const isBold = isActiveMark(view, 'strong')
|
||||
const isEm = isActiveMark(view, 'em')
|
||||
const isUnderline = isActiveMark(view, 'underline')
|
||||
const isStrikethrough = isActiveMark(view, 'strikethrough')
|
||||
const isSuperscript = isActiveMark(view, 'superscript')
|
||||
const isSubscript = isActiveMark(view, 'subscript')
|
||||
const isCode = isActiveMark(view, 'code')
|
||||
const color = getAttrValue(view, 'forecolor', 'color') || '#000'
|
||||
const backcolor = getAttrValue(view, 'backcolor', 'backcolor') || '#000'
|
||||
const fontsize = getAttrValue(view, 'fontsize', 'fontsize') || '12px'
|
||||
const fontname = getAttrValue(view, 'fontname', 'fontname') || '微软雅黑'
|
||||
const align = getAttrValueInSelection(view, 'align')
|
||||
const isBulletList = isActiveOfParentNodeType('bullet_list', view.state)
|
||||
const isOrderedList = isActiveOfParentNodeType('ordered_list', view.state)
|
||||
const isBlockquote = isActiveOfParentNodeType('blockquote', view.state)
|
||||
|
||||
return {
|
||||
bold: isBold,
|
||||
em: isEm,
|
||||
underline: isUnderline,
|
||||
strikethrough: isStrikethrough,
|
||||
superscript: isSuperscript,
|
||||
subscript: isSubscript,
|
||||
code: isCode,
|
||||
color: color,
|
||||
backcolor: backcolor,
|
||||
fontsize: fontsize,
|
||||
fontname: fontname,
|
||||
align: align,
|
||||
bulletList: isBulletList,
|
||||
orderedList: isOrderedList,
|
||||
blockquote: isBlockquote,
|
||||
}
|
||||
}
|
||||
|
||||
export type TextAttrs = ReturnType<typeof getTextAttrs>
|
@ -1,6 +1,8 @@
|
||||
import mitt, { Emitter } from 'mitt'
|
||||
|
||||
export enum EMITTER_EVENTS {}
|
||||
export enum EmitterEvents {
|
||||
UPDATE_TEXT_STATE = 'UPDATE_TEXT_STATE',
|
||||
}
|
||||
|
||||
const emitter: Emitter = mitt()
|
||||
|
||||
|
@ -6,16 +6,18 @@
|
||||
<div class="animation-pool">
|
||||
<div class="pool-type" v-for="type in animations" :key="type.name">
|
||||
<div class="type-title">{{type.name}}:</div>
|
||||
<div class="pool-item" v-for="item in type.children" :key="item.name">
|
||||
<div class="pool-item-wrapper">
|
||||
<div
|
||||
class="pool-item"
|
||||
v-for="item in type.children" :key="item.name"
|
||||
:class="[
|
||||
'box',
|
||||
'animate__animated',
|
||||
hoverPreviewAnimation === item.value && `animate__${item.value}`,
|
||||
]"
|
||||
@mouseover="hoverPreviewAnimation = item.value"
|
||||
></div>
|
||||
<div class="label">{{item.name}}</div>
|
||||
>
|
||||
{{item.name}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -130,9 +132,6 @@ export default defineComponent({
|
||||
margin-right: -12px;
|
||||
padding-right: 12px;
|
||||
}
|
||||
.pool-type {
|
||||
@include grid-layout-wrapper();
|
||||
}
|
||||
.type-title {
|
||||
width: 100%;
|
||||
font-size: 13px;
|
||||
@ -141,25 +140,18 @@ export default defineComponent({
|
||||
background-color: #eee;
|
||||
padding-left: 10px;
|
||||
}
|
||||
.pool-item-wrapper {
|
||||
@include grid-layout-wrapper();
|
||||
}
|
||||
.pool-item {
|
||||
@include grid-layout-item(4, 24%);
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-bottom: 10px;
|
||||
cursor: pointer;
|
||||
|
||||
.box {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
background-color: #eee;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
.label {
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
text-align: center;
|
||||
}
|
||||
background-color: #f5f5f5;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.sequence-item {
|
||||
|
@ -3,88 +3,171 @@
|
||||
<InputGroup compact class="row">
|
||||
<Select
|
||||
style="flex: 3;"
|
||||
:value="richTextAttrs.fontname"
|
||||
>
|
||||
<SelectOption value="jack">Jack</SelectOption>
|
||||
<SelectOption value="lucy">Lucy</SelectOption>
|
||||
<SelectOption value="disabled">Disabled</SelectOption>
|
||||
<SelectOption value="Yiminghe">yiminghe</SelectOption>
|
||||
<SelectOption v-for="font in availableFonts" :key="font.en" :value="font.en">
|
||||
<span :style="{ fontFamily: font.en }">{{font.zh}}</span>
|
||||
</SelectOption>
|
||||
</Select>
|
||||
<Select
|
||||
style="flex: 2;"
|
||||
:value="richTextAttrs.fontsize"
|
||||
>
|
||||
<SelectOption value="jack">Jack</SelectOption>
|
||||
<SelectOption value="lucy">Lucy</SelectOption>
|
||||
<SelectOption value="disabled">Disabled</SelectOption>
|
||||
<SelectOption value="Yiminghe">yiminghe</SelectOption>
|
||||
<SelectOption v-for="fontsize in fontSizeOptions" :key="fontsize" :value="fontsize">
|
||||
{{fontsize}}
|
||||
</SelectOption>
|
||||
</Select>
|
||||
</InputGroup>
|
||||
|
||||
<ButtonGroup class="row">
|
||||
<Button style="flex: 1;"><FontColorsOutlined /></Button>
|
||||
<Button style="flex: 1;"><HighlightOutlined /></Button>
|
||||
<Button style="flex: 1;"><BgColorsOutlined /></Button>
|
||||
<Popover trigger="click">
|
||||
<template #content>
|
||||
<ColorPicker v-model="richTextAttrs.color" />
|
||||
</template>
|
||||
<Button class="color-btn" style="flex: 1;">
|
||||
<FontColorsOutlined />
|
||||
<div class="color-block" :style="{ backgroundColor: richTextAttrs.color }"></div>
|
||||
</Button>
|
||||
</Popover>
|
||||
<Popover trigger="click">
|
||||
<template #content>
|
||||
<ColorPicker v-model="richTextAttrs.backcolor" />
|
||||
</template>
|
||||
<Button class="color-btn" style="flex: 1;">
|
||||
<HighlightOutlined />
|
||||
<div class="color-block" :style="{ backgroundColor: richTextAttrs.backcolor }"></div>
|
||||
</Button>
|
||||
</Popover>
|
||||
<Popover trigger="click">
|
||||
<template #content>
|
||||
<ColorPicker v-model="fill" />
|
||||
</template>
|
||||
<Button class="color-btn" style="flex: 1;">
|
||||
<BgColorsOutlined />
|
||||
<div class="color-block" :style="{ backgroundColor: fill }"></div>
|
||||
</Button>
|
||||
</Popover>
|
||||
</ButtonGroup>
|
||||
|
||||
<ButtonGroup class="row">
|
||||
<Button style="flex: 1;"><BoldOutlined /></Button>
|
||||
<Button style="flex: 1;"><ItalicOutlined /></Button>
|
||||
<Button style="flex: 1;"><UnderlineOutlined /></Button>
|
||||
<Button style="flex: 1;"><StrikethroughOutlined /></Button>
|
||||
<Button style="flex: 1;" :type="richTextAttrs.bold ? 'primary' : 'default'"><BoldOutlined /></Button>
|
||||
<Button style="flex: 1;" :type="richTextAttrs.em ? 'primary' : 'default'"><ItalicOutlined /></Button>
|
||||
<Button style="flex: 1;" :type="richTextAttrs.underline ? 'primary' : 'default'"><UnderlineOutlined /></Button>
|
||||
<Button style="flex: 1;" :type="richTextAttrs.strikethrough ? 'primary' : 'default'"><StrikethroughOutlined /></Button>
|
||||
</ButtonGroup>
|
||||
|
||||
<ButtonGroup class="row">
|
||||
<Button style="flex: 1;" :type="richTextAttrs.superscript ? 'primary' : 'default'">上</Button>
|
||||
<Button style="flex: 1;" :type="richTextAttrs.subscript ? 'primary' : 'default'">下</Button>
|
||||
<Button style="flex: 1;" :type="richTextAttrs.code ? 'primary' : 'default'">码</Button>
|
||||
<Button style="flex: 1;" :type="richTextAttrs.blockquote ? 'primary' : 'default'">引</Button>
|
||||
<Button style="flex: 1;">清</Button>
|
||||
</ButtonGroup>
|
||||
|
||||
<Divider />
|
||||
|
||||
<ButtonGroup class="row">
|
||||
<Button style="flex: 1;"><AlignLeftOutlined /></Button>
|
||||
<Button style="flex: 1;"><AlignCenterOutlined /></Button>
|
||||
<Button style="flex: 1;"><AlignRightOutlined /></Button>
|
||||
<Button style="flex: 1;" :type="richTextAttrs.align === 'left' || '' ? 'primary' : 'default'"><AlignLeftOutlined /></Button>
|
||||
<Button style="flex: 1;" :type="richTextAttrs.align === 'center' ? 'primary' : 'default'"><AlignCenterOutlined /></Button>
|
||||
<Button style="flex: 1;" :type="richTextAttrs.align === 'right' ? 'primary' : 'default'"><AlignRightOutlined /></Button>
|
||||
</ButtonGroup>
|
||||
|
||||
<ButtonGroup class="row">
|
||||
<Button style="flex: 1;"><OrderedListOutlined /></Button>
|
||||
<Button style="flex: 1;"><UnorderedListOutlined /></Button>
|
||||
<Button style="flex: 1;" :type="richTextAttrs.bulletList ? 'primary' : 'default'"><UnorderedListOutlined /></Button>
|
||||
<Button style="flex: 1;" :type="richTextAttrs.orderedList ? 'primary' : 'default'"><OrderedListOutlined /></Button>
|
||||
</ButtonGroup>
|
||||
|
||||
<Divider />
|
||||
|
||||
<div class="row">
|
||||
<div style="flex: 2;">行间距:</div>
|
||||
<Select style="flex: 3;">
|
||||
<Select style="flex: 3;" :value="lineHeight">
|
||||
<template #suffixIcon><ColumnHeightOutlined /></template>
|
||||
<SelectOption value="jack">Jack</SelectOption>
|
||||
<SelectOption value="lucy">Lucy</SelectOption>
|
||||
<SelectOption value="disabled">Disabled</SelectOption>
|
||||
<SelectOption value="Yiminghe">yiminghe</SelectOption>
|
||||
<SelectOption v-for="item in lineHeightOptions" :key="item" :value="item">{{item}}</SelectOption>
|
||||
</Select>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div style="flex: 2;">字间距:</div>
|
||||
<Select style="flex: 3;">
|
||||
<Select style="flex: 3;" :value="wordSpace">
|
||||
<template #suffixIcon><ColumnWidthOutlined /></template>
|
||||
<SelectOption value="jack">Jack</SelectOption>
|
||||
<SelectOption value="lucy">Lucy</SelectOption>
|
||||
<SelectOption value="disabled">Disabled</SelectOption>
|
||||
<SelectOption value="Yiminghe">yiminghe</SelectOption>
|
||||
<SelectOption v-for="item in wordSpaceOptions" :key="item" :value="item">{{item}}</SelectOption>
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
<Divider />
|
||||
|
||||
<ButtonGroup class="row">
|
||||
<Button style="flex: 1;">边框</Button>
|
||||
<Button style="flex: 1;">阴影</Button>
|
||||
</ButtonGroup>
|
||||
<div class="row">
|
||||
<div style="flex: 2;">描边样式:</div>
|
||||
<Select style="flex: 3;" :value="wordSpace">
|
||||
<template #suffixIcon><ColumnWidthOutlined /></template>
|
||||
<SelectOption v-for="item in wordSpaceOptions" :key="item" :value="item">{{item}}</SelectOption>
|
||||
</Select>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div style="flex: 2;">描边颜色:</div>
|
||||
<Select style="flex: 3;" :value="wordSpace">
|
||||
<template #suffixIcon><ColumnWidthOutlined /></template>
|
||||
<SelectOption v-for="item in wordSpaceOptions" :key="item" :value="item">{{item}}</SelectOption>
|
||||
</Select>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div style="flex: 2;">描边粗细:</div>
|
||||
<Select style="flex: 3;" :value="wordSpace">
|
||||
<template #suffixIcon><ColumnWidthOutlined /></template>
|
||||
<SelectOption v-for="item in wordSpaceOptions" :key="item" :value="item">{{item}}</SelectOption>
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
<Divider />
|
||||
|
||||
<div class="row">
|
||||
<div style="flex: 2;">水平阴影:</div>
|
||||
<Select style="flex: 3;" :value="wordSpace">
|
||||
<template #suffixIcon><ColumnWidthOutlined /></template>
|
||||
<SelectOption v-for="item in wordSpaceOptions" :key="item" :value="item">{{item}}</SelectOption>
|
||||
</Select>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div style="flex: 2;">垂直阴影:</div>
|
||||
<Select style="flex: 3;" :value="wordSpace">
|
||||
<template #suffixIcon><ColumnWidthOutlined /></template>
|
||||
<SelectOption v-for="item in wordSpaceOptions" :key="item" :value="item">{{item}}</SelectOption>
|
||||
</Select>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div style="flex: 2;">模糊距离:</div>
|
||||
<Select style="flex: 3;" :value="wordSpace">
|
||||
<template #suffixIcon><ColumnWidthOutlined /></template>
|
||||
<SelectOption v-for="item in wordSpaceOptions" :key="item" :value="item">{{item}}</SelectOption>
|
||||
</Select>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div style="flex: 2;">阴影颜色:</div>
|
||||
<Select style="flex: 3;" :value="wordSpace">
|
||||
<template #suffixIcon><ColumnWidthOutlined /></template>
|
||||
<SelectOption v-for="item in wordSpaceOptions" :key="item" :value="item">{{item}}</SelectOption>
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
<Divider />
|
||||
|
||||
<div class="row">
|
||||
<div style="flex: 2;">透明度:</div>
|
||||
<Slider style="flex: 3;" />
|
||||
<Slider :min="0" :max="1" :step="0.1" :value="opacity" style="flex: 3;" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue'
|
||||
import { Select, Input, Button, Divider, Slider } from 'ant-design-vue'
|
||||
import { computed, defineComponent, onUnmounted, ref } from 'vue'
|
||||
import { useStore } from 'vuex'
|
||||
import { State } from '@/store'
|
||||
import { PPTElementOutline, PPTElementShadow } from '@/types/slides'
|
||||
import emitter, { EmitterEvents } from '@/utils/emitter'
|
||||
import { TextAttrs } from '@/prosemirror/utils'
|
||||
|
||||
import ColorPicker from '@/components/ColorPicker/index.vue'
|
||||
import { Select, Input, Button, Divider, Slider, Popover } from 'ant-design-vue'
|
||||
import {
|
||||
FontColorsOutlined,
|
||||
HighlightOutlined,
|
||||
@ -105,6 +188,7 @@ import {
|
||||
export default defineComponent({
|
||||
name: 'text-style-panel',
|
||||
components: {
|
||||
ColorPicker,
|
||||
Select,
|
||||
SelectOption: Select.Option,
|
||||
InputGroup: Input.Group,
|
||||
@ -112,6 +196,7 @@ export default defineComponent({
|
||||
ButtonGroup: Button.Group,
|
||||
Divider,
|
||||
Slider,
|
||||
Popover,
|
||||
FontColorsOutlined,
|
||||
HighlightOutlined,
|
||||
BgColorsOutlined,
|
||||
@ -127,6 +212,63 @@ export default defineComponent({
|
||||
ColumnHeightOutlined,
|
||||
ColumnWidthOutlined,
|
||||
},
|
||||
setup() {
|
||||
const store = useStore<State>()
|
||||
|
||||
const fill = ref('#000')
|
||||
const lineHeight = ref(1.5)
|
||||
const wordSpace = ref(0)
|
||||
const opacity = ref(1)
|
||||
const shadow = ref<PPTElementShadow>()
|
||||
const outline = ref<PPTElementOutline>()
|
||||
|
||||
const richTextAttrs = ref<TextAttrs>({
|
||||
bold: false,
|
||||
em: false,
|
||||
underline: false,
|
||||
strikethrough: false,
|
||||
superscript: false,
|
||||
subscript: false,
|
||||
code: false,
|
||||
color: '#000',
|
||||
backcolor: '#000',
|
||||
fontsize: '12px',
|
||||
fontname: '微软雅黑',
|
||||
align: 'left',
|
||||
bulletList: false,
|
||||
orderedList: false,
|
||||
blockquote: false,
|
||||
})
|
||||
|
||||
const availableFonts = computed(() => store.state.availableFonts)
|
||||
const fontSizeOptions = [
|
||||
'12px', '14px', '16px', '18px', '20px', '22px', '24px', '28px', '32px',
|
||||
'36px', '40px', '44px', '48px', '54px', '60px', '66px', '72px', '80px',
|
||||
]
|
||||
const lineHeightOptions = [0.5, 1.0, 1.2, 1.5, 1.8, 2.0, 3.0]
|
||||
const wordSpaceOptions = [0, 1, 2, 3, 4, 5, 8]
|
||||
|
||||
const updateRichTextAttrs = (attr: TextAttrs) => richTextAttrs.value = attr
|
||||
|
||||
emitter.on(EmitterEvents.UPDATE_TEXT_STATE, attr => updateRichTextAttrs(attr))
|
||||
onUnmounted(() => {
|
||||
emitter.off(EmitterEvents.UPDATE_TEXT_STATE, attr => updateRichTextAttrs(attr))
|
||||
})
|
||||
|
||||
return {
|
||||
fill,
|
||||
lineHeight,
|
||||
wordSpace,
|
||||
opacity,
|
||||
shadow,
|
||||
outline,
|
||||
richTextAttrs,
|
||||
availableFonts,
|
||||
fontSizeOptions,
|
||||
lineHeightOptions,
|
||||
wordSpaceOptions,
|
||||
}
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
@ -137,4 +279,15 @@ export default defineComponent({
|
||||
align-items: center;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.color-btn {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
.color-block {
|
||||
width: 16px;
|
||||
height: 3px;
|
||||
margin-top: 1px;
|
||||
}
|
||||
</style>
|
@ -1,32 +1,13 @@
|
||||
<template>
|
||||
<div class="slide-style-panel">
|
||||
<Popover trigger="click">
|
||||
<template #content>
|
||||
<ColorPicker v-model="color" />
|
||||
</template>
|
||||
<button>Hover me</button>
|
||||
</Popover>
|
||||
slide-style-panel
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref } from 'vue'
|
||||
|
||||
import ColorPicker from '@/components/ColorPicker/index.vue'
|
||||
import { Popover } from 'ant-design-vue'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'slide-style-panel',
|
||||
components: {
|
||||
ColorPicker,
|
||||
Popover,
|
||||
},
|
||||
setup() {
|
||||
const color = ref('#888')
|
||||
|
||||
return {
|
||||
color,
|
||||
}
|
||||
},
|
||||
})
|
||||
</script>
|
@ -14,6 +14,8 @@
|
||||
backgroundColor: elementInfo.fill,
|
||||
opacity: elementInfo.opacity,
|
||||
textShadow: shadowStyle,
|
||||
lineHeight: elementInfo.lineHeight,
|
||||
letterSpacing: (elementInfo.wordSpace || 0) + 'px',
|
||||
}"
|
||||
>
|
||||
<ElementOutline
|
||||
|
@ -17,6 +17,8 @@
|
||||
backgroundColor: elementInfo.fill,
|
||||
opacity: elementInfo.opacity,
|
||||
textShadow: shadowStyle,
|
||||
lineHeight: elementInfo.lineHeight,
|
||||
letterSpacing: (elementInfo.wordSpace || 0) + 'px',
|
||||
}"
|
||||
v-contextmenu="contextmenus"
|
||||
>
|
||||
@ -43,6 +45,8 @@ import { EditorView } from 'prosemirror-view'
|
||||
import { PPTTextElement } from '@/types/slides'
|
||||
import { ContextmenuItem } from '@/components/Contextmenu/types'
|
||||
import { initProsemirrorEditor } from '@/prosemirror/'
|
||||
import { getTextAttrs } from '@/prosemirror/utils'
|
||||
import emitter, { EmitterEvents } from '@/utils/emitter'
|
||||
import useElementShadow from '@/views/components/element/hooks/useElementShadow'
|
||||
import useHistorySnapshot from '@/hooks/useHistorySnapshot'
|
||||
|
||||
@ -113,6 +117,16 @@ export default defineComponent({
|
||||
addHistorySnapshot()
|
||||
}, 500, { trailing: true })
|
||||
|
||||
const handleClick = debounce(function() {
|
||||
const attr = getTextAttrs(editorView)
|
||||
emitter.emit(EmitterEvents.UPDATE_TEXT_STATE, attr)
|
||||
}, 50, { trailing: true })
|
||||
|
||||
const handleKeydown = () => {
|
||||
handleInput()
|
||||
handleClick()
|
||||
}
|
||||
|
||||
const textContent = computed(() => props.elementInfo.content)
|
||||
watch(textContent, () => {
|
||||
if(!editorView) return
|
||||
@ -130,7 +144,8 @@ export default defineComponent({
|
||||
handleDOMEvents: {
|
||||
focus: handleFocus,
|
||||
blur: handleBlur,
|
||||
keydown: handleInput,
|
||||
keydown: handleKeydown,
|
||||
click: handleClick,
|
||||
},
|
||||
editable: () => editable.value,
|
||||
})
|
||||
|
Loading…
x
Reference in New Issue
Block a user