mirror of
https://github.com/pipipi-pikachu/PPTist.git
synced 2025-04-15 02:20:00 +08:00
refactor: 使用pinia代替vuex
This commit is contained in:
parent
16f5646023
commit
54dfccd643
@ -1,6 +0,0 @@
|
||||
module.exports = {
|
||||
preset: '@vue/cli-plugin-unit-jest/presets/typescript-and-babel',
|
||||
transform: {
|
||||
'^.+\\.vue$': 'vue-jest',
|
||||
},
|
||||
}
|
@ -21,6 +21,7 @@
|
||||
"hfmath": "0.0.2",
|
||||
"lodash": "^4.17.20",
|
||||
"mitt": "^3.0.0",
|
||||
"pinia": "^2.0.4",
|
||||
"pptxgenjs": "^3.7.1",
|
||||
"prosemirror-commands": "^1.1.7",
|
||||
"prosemirror-dropcursor": "^1.3.2",
|
||||
@ -36,8 +37,7 @@
|
||||
"svg-pathdata": "^6.0.0",
|
||||
"tinycolor2": "^1.4.2",
|
||||
"vue": "^3.2.22",
|
||||
"vuedraggable": "^4.0.1",
|
||||
"vuex": "^4.0.2"
|
||||
"vuedraggable": "^4.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@commitlint/cli": "^12.0.0",
|
||||
|
14
src/App.vue
14
src/App.vue
@ -4,8 +4,9 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, onMounted } from 'vue'
|
||||
import { MutationTypes, ActionTypes, useStore } from '@/store'
|
||||
import { defineComponent, onMounted } from 'vue'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useScreenStore, useMainStore, useSnapshotStore } from '@/store'
|
||||
|
||||
import Editor from './views/Editor/index.vue'
|
||||
import Screen from './views/Screen/index.vue'
|
||||
@ -17,16 +18,17 @@ export default defineComponent({
|
||||
Screen,
|
||||
},
|
||||
setup() {
|
||||
const store = useStore()
|
||||
const screening = computed(() => store.state.screening)
|
||||
const mainStore = useMainStore()
|
||||
const snapshotStore = useSnapshotStore()
|
||||
const { screening } = storeToRefs(useScreenStore())
|
||||
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
window.onbeforeunload = () => false
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
store.commit(MutationTypes.SET_AVAILABLE_FONTS)
|
||||
store.dispatch(ActionTypes.INIT_SNAPSHOT_DATABASE)
|
||||
snapshotStore.initSnapshotDatabase()
|
||||
mainStore.setAvailableFonts()
|
||||
})
|
||||
|
||||
return {
|
||||
|
@ -1,16 +1,14 @@
|
||||
import { computed } from 'vue'
|
||||
import { MutationTypes, useStore } from '@/store'
|
||||
import { PPTElement, Slide } from '@/types/slides'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useMainStore, useSlidesStore } from '@/store'
|
||||
import { PPTElement } from '@/types/slides'
|
||||
import { ElementAlignCommand, ElementAlignCommands } from '@/types/edit'
|
||||
import { getElementListRange, getRectRotatedOffset } from '@/utils/element'
|
||||
import useHistorySnapshot from './useHistorySnapshot'
|
||||
|
||||
export default () => {
|
||||
const store = useStore()
|
||||
|
||||
const activeElementIdList = computed(() => store.state.activeElementIdList)
|
||||
const activeElementList = computed<PPTElement[]>(() => store.getters.activeElementList)
|
||||
const currentSlide = computed<Slide>(() => store.getters.currentSlide)
|
||||
const slidesStore = useSlidesStore()
|
||||
const { activeElementIdList, activeElementList } = storeToRefs(useMainStore())
|
||||
const { currentSlide } = storeToRefs(slidesStore)
|
||||
|
||||
const { addHistorySnapshot } = useHistorySnapshot()
|
||||
|
||||
@ -164,8 +162,8 @@ export default () => {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
store.commit(MutationTypes.UPDATE_SLIDE, { elements: elementList })
|
||||
|
||||
slidesStore.updateSlide({ elements: elementList })
|
||||
addHistorySnapshot()
|
||||
}
|
||||
|
||||
|
@ -1,18 +1,15 @@
|
||||
import { computed } from 'vue'
|
||||
import { MutationTypes, useStore } from '@/store'
|
||||
import { PPTElement, Slide } from '@/types/slides'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useMainStore, useSlidesStore } from '@/store'
|
||||
import { PPTElement } from '@/types/slides'
|
||||
import { ElementAlignCommand, ElementAlignCommands } from '@/types/edit'
|
||||
import { getElementListRange } from '@/utils/element'
|
||||
import { VIEWPORT_SIZE } from '@/configs/canvas'
|
||||
import useHistorySnapshot from './useHistorySnapshot'
|
||||
|
||||
export default () => {
|
||||
const store = useStore()
|
||||
|
||||
const activeElementIdList = computed(() => store.state.activeElementIdList)
|
||||
const viewportRatio = computed(() => store.state.viewportRatio)
|
||||
const activeElementList = computed<PPTElement[]>(() => store.getters.activeElementList)
|
||||
const currentSlide = computed<Slide>(() => store.getters.currentSlide)
|
||||
const slidesStore = useSlidesStore()
|
||||
const { activeElementIdList, activeElementList } = storeToRefs(useMainStore())
|
||||
const { currentSlide, viewportRatio } = storeToRefs(slidesStore)
|
||||
|
||||
const { addHistorySnapshot } = useHistorySnapshot()
|
||||
|
||||
@ -73,8 +70,8 @@ export default () => {
|
||||
element.left = element.left - offsetX
|
||||
}
|
||||
}
|
||||
|
||||
store.commit(MutationTypes.UPDATE_SLIDE, { elements: newElementList })
|
||||
|
||||
slidesStore.updateSlide({ elements: newElementList })
|
||||
addHistorySnapshot()
|
||||
}
|
||||
|
||||
|
@ -1,15 +1,15 @@
|
||||
import { computed } from 'vue'
|
||||
import { MutationTypes, useStore } from '@/store'
|
||||
import { PPTElement, Slide } from '@/types/slides'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useMainStore, useSlidesStore } from '@/store'
|
||||
import { PPTElement } from '@/types/slides'
|
||||
import { createRandomCode } from '@/utils/common'
|
||||
import useHistorySnapshot from '@/hooks/useHistorySnapshot'
|
||||
|
||||
export default () => {
|
||||
const store = useStore()
|
||||
const activeElementIdList = computed(() => store.state.activeElementIdList)
|
||||
const activeElementList = computed<PPTElement[]>(() => store.getters.activeElementList)
|
||||
const currentSlide = computed<Slide>(() => store.getters.currentSlide)
|
||||
const handleElementId = computed(() => store.state.handleElementId)
|
||||
const mainStore = useMainStore()
|
||||
const slidesStore = useSlidesStore()
|
||||
const { activeElementIdList, activeElementList, handleElementId } = storeToRefs(mainStore)
|
||||
const { currentSlide } = storeToRefs(slidesStore)
|
||||
|
||||
const { addHistorySnapshot } = useHistorySnapshot()
|
||||
|
||||
@ -57,7 +57,7 @@ export default () => {
|
||||
const insertLevel = combineElementMaxLevel - combineElementList.length + 1
|
||||
newElementList.splice(insertLevel, 0, ...combineElementList)
|
||||
|
||||
store.commit(MutationTypes.UPDATE_SLIDE, { elements: newElementList })
|
||||
slidesStore.updateSlide({ elements: newElementList })
|
||||
addHistorySnapshot()
|
||||
}
|
||||
|
||||
@ -73,12 +73,13 @@ export default () => {
|
||||
for (const element of newElementList) {
|
||||
if (activeElementIdList.value.includes(element.id) && element.groupId) delete element.groupId
|
||||
}
|
||||
store.commit(MutationTypes.UPDATE_SLIDE, { elements: newElementList })
|
||||
slidesStore.updateSlide({ elements: newElementList })
|
||||
|
||||
// 取消组合后,需要重置激活元素状态
|
||||
// 默认重置为当前正在操作的元素,如果不存在则重置为空
|
||||
const handleElementIdList = handleElementId.value ? [handleElementId.value] : []
|
||||
store.commit(MutationTypes.SET_ACTIVE_ELEMENT_ID_LIST, handleElementIdList)
|
||||
mainStore.setActiveElementIdList(handleElementIdList)
|
||||
|
||||
addHistorySnapshot()
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
import { computed } from 'vue'
|
||||
import { MutationTypes, useStore } from '@/store'
|
||||
import { PPTElement } from '@/types/slides'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useMainStore } from '@/store'
|
||||
import { copyText, readClipboard } from '@/utils/clipboard'
|
||||
import { encrypt } from '@/utils/crypto'
|
||||
import { message } from 'ant-design-vue'
|
||||
@ -8,9 +7,8 @@ import usePasteTextClipboardData from '@/hooks/usePasteTextClipboardData'
|
||||
import useDeleteElement from './useDeleteElement'
|
||||
|
||||
export default () => {
|
||||
const store = useStore()
|
||||
const activeElementIdList = computed(() => store.state.activeElementIdList)
|
||||
const activeElementList = computed<PPTElement[]>(() => store.getters.activeElementList)
|
||||
const mainStore = useMainStore()
|
||||
const { activeElementIdList, activeElementList } = storeToRefs(mainStore)
|
||||
|
||||
const { pasteTextClipboardData } = usePasteTextClipboardData()
|
||||
const { deleteElement } = useDeleteElement()
|
||||
@ -25,7 +23,7 @@ export default () => {
|
||||
}))
|
||||
|
||||
copyText(text).then(() => {
|
||||
store.commit(MutationTypes.SET_EDITORAREA_FOCUS, true)
|
||||
mainStore.setEditorareaFocus(true)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { computed } from 'vue'
|
||||
import { MutationTypes, useStore } from '@/store'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useMainStore, useSlidesStore } from '@/store'
|
||||
import { createRandomCode } from '@/utils/common'
|
||||
import { getImageSize } from '@/utils/image'
|
||||
import { VIEWPORT_SIZE } from '@/configs/canvas'
|
||||
@ -23,24 +23,23 @@ interface LineElementPosition {
|
||||
}
|
||||
|
||||
export default () => {
|
||||
const store = useStore()
|
||||
const themeColor = computed(() => store.state.theme.themeColor)
|
||||
const fontColor = computed(() => store.state.theme.fontColor)
|
||||
const fontName = computed(() => store.state.theme.fontName)
|
||||
const viewportRatio = computed(() => store.state.viewportRatio)
|
||||
const creatingElement = computed(() => store.state.creatingElement)
|
||||
const mainStore = useMainStore()
|
||||
const slidesStore = useSlidesStore()
|
||||
const { creatingElement } = storeToRefs(mainStore)
|
||||
const { theme, viewportRatio } = storeToRefs(slidesStore)
|
||||
const { themeColor, fontColor, fontName } = theme.value
|
||||
|
||||
const { addHistorySnapshot } = useHistorySnapshot()
|
||||
|
||||
// 创建(插入)一个元素并将其设置为被选中元素
|
||||
const createElement = (element: PPTElement) => {
|
||||
store.commit(MutationTypes.ADD_ELEMENT, element)
|
||||
store.commit(MutationTypes.SET_ACTIVE_ELEMENT_ID_LIST, [element.id])
|
||||
slidesStore.addElement(element)
|
||||
mainStore.setActiveElementIdList([element.id])
|
||||
|
||||
if (creatingElement.value) store.commit(MutationTypes.SET_CREATING_ELEMENT, null)
|
||||
if (creatingElement.value) mainStore.setCreatingElement(null)
|
||||
|
||||
setTimeout(() => {
|
||||
store.commit(MutationTypes.SET_EDITORAREA_FOCUS, true)
|
||||
mainStore.setEditorareaFocus(true)
|
||||
}, 0)
|
||||
|
||||
addHistorySnapshot()
|
||||
@ -91,8 +90,8 @@ export default () => {
|
||||
width: 400,
|
||||
height: 400,
|
||||
rotate: 0,
|
||||
themeColor: [themeColor.value],
|
||||
gridColor: fontColor.value,
|
||||
themeColor: [themeColor],
|
||||
gridColor: fontColor,
|
||||
data: {
|
||||
labels: ['类别1', '类别2', '类别3', '类别4', '类别5'],
|
||||
legends: ['系列1'],
|
||||
@ -110,8 +109,8 @@ export default () => {
|
||||
*/
|
||||
const createTableElement = (row: number, col: number) => {
|
||||
const style: TableCellStyle = {
|
||||
fontname: fontName.value,
|
||||
color: fontColor.value,
|
||||
fontname: fontName,
|
||||
color: fontColor,
|
||||
}
|
||||
const data: TableCell[][] = []
|
||||
for (let i = 0; i < row; i++) {
|
||||
@ -146,7 +145,7 @@ export default () => {
|
||||
color: '#eeece1',
|
||||
},
|
||||
theme: {
|
||||
color: themeColor.value,
|
||||
color: themeColor,
|
||||
rowHeader: true,
|
||||
rowFooter: false,
|
||||
colHeader: false,
|
||||
@ -171,8 +170,8 @@ export default () => {
|
||||
height,
|
||||
content,
|
||||
rotate: 0,
|
||||
defaultFontName: fontName.value,
|
||||
defaultColor: fontColor.value,
|
||||
defaultFontName: fontName,
|
||||
defaultColor: fontColor,
|
||||
})
|
||||
}
|
||||
|
||||
@ -192,7 +191,7 @@ export default () => {
|
||||
height,
|
||||
viewBox: data.viewBox,
|
||||
path: data.path,
|
||||
fill: themeColor.value,
|
||||
fill: themeColor,
|
||||
fixedRatio: false,
|
||||
rotate: 0,
|
||||
}
|
||||
@ -216,7 +215,7 @@ export default () => {
|
||||
start,
|
||||
end,
|
||||
points: data.points,
|
||||
color: themeColor.value,
|
||||
color: themeColor,
|
||||
style: data.style,
|
||||
width: 2,
|
||||
}
|
||||
@ -240,7 +239,7 @@ export default () => {
|
||||
top: (VIEWPORT_SIZE * viewportRatio.value - data.h) / 2,
|
||||
path: data.path,
|
||||
latex: data.latex,
|
||||
color: fontColor.value,
|
||||
color: fontColor,
|
||||
strokeWidth: 2,
|
||||
viewBox: [data.w, data.h],
|
||||
fixedRatio: true,
|
||||
|
@ -1,13 +1,13 @@
|
||||
import { computed } from 'vue'
|
||||
import { MutationTypes, useStore } from '@/store'
|
||||
import { PPTElement, Slide } from '@/types/slides'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useMainStore, useSlidesStore } from '@/store'
|
||||
import { PPTElement } from '@/types/slides'
|
||||
import useHistorySnapshot from '@/hooks/useHistorySnapshot'
|
||||
|
||||
export default () => {
|
||||
const store = useStore()
|
||||
const activeElementIdList = computed(() => store.state.activeElementIdList)
|
||||
const activeGroupElementId = computed(() => store.state.activeGroupElementId)
|
||||
const currentSlide = computed<Slide>(() => store.getters.currentSlide)
|
||||
const mainStore = useMainStore()
|
||||
const slidesStore = useSlidesStore()
|
||||
const { activeElementIdList, activeGroupElementId } = storeToRefs(mainStore)
|
||||
const { currentSlide } = storeToRefs(slidesStore)
|
||||
|
||||
const { addHistorySnapshot } = useHistorySnapshot()
|
||||
|
||||
@ -24,16 +24,16 @@ export default () => {
|
||||
newElementList = currentSlide.value.elements.filter(el => !activeElementIdList.value.includes(el.id))
|
||||
}
|
||||
|
||||
store.commit(MutationTypes.SET_ACTIVE_ELEMENT_ID_LIST, [])
|
||||
store.commit(MutationTypes.UPDATE_SLIDE, { elements: newElementList })
|
||||
mainStore.setActiveElementIdList([])
|
||||
slidesStore.updateSlide({ elements: newElementList })
|
||||
addHistorySnapshot()
|
||||
}
|
||||
|
||||
// 删除内面内全部元素(无论是否选中)
|
||||
const deleteAllElements = () => {
|
||||
if (!currentSlide.value.elements.length) return
|
||||
store.commit(MutationTypes.SET_ACTIVE_ELEMENT_ID_LIST, [])
|
||||
store.commit(MutationTypes.UPDATE_SLIDE, { elements: [] })
|
||||
mainStore.setActiveElementIdList([])
|
||||
slidesStore.updateSlide({ elements: [] })
|
||||
addHistorySnapshot()
|
||||
}
|
||||
|
||||
|
@ -1,18 +1,18 @@
|
||||
import { computed, ref } from 'vue'
|
||||
import { ref } from 'vue'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { trim } from 'lodash'
|
||||
import { saveAs } from 'file-saver'
|
||||
import pptxgen from 'pptxgenjs'
|
||||
import tinycolor from 'tinycolor2'
|
||||
import { useSlidesStore } from '@/store'
|
||||
import { getElementRange, getLineElementPath, getTableSubThemeColor } from '@/utils/element'
|
||||
import { AST, toAST } from '@/utils/htmlParser'
|
||||
import { SvgPoints, toPoints } from '@/utils/svgPathParser'
|
||||
import { svg2Base64 } from '@/utils/svg2Base64'
|
||||
import { useStore } from '@/store'
|
||||
import { message } from 'ant-design-vue'
|
||||
|
||||
export default () => {
|
||||
const store = useStore()
|
||||
const slides = computed(() => store.state.slides)
|
||||
const { slides } = storeToRefs(useSlidesStore())
|
||||
|
||||
const exporting = ref(false)
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { computed, onMounted, onUnmounted } from 'vue'
|
||||
import { MutationTypes, useStore } from '@/store'
|
||||
import { onMounted, onUnmounted } from 'vue'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useMainStore, useSlidesStore, useKeyboardStore } from '@/store'
|
||||
import { ElementOrderCommand, ElementOrderCommands } from '@/types/edit'
|
||||
import { PPTElement, Slide } from '@/types/slides'
|
||||
import { KEYS } from '@/configs/hotkey'
|
||||
|
||||
import useSlideHandler from './useSlideHandler'
|
||||
@ -17,17 +17,18 @@ import useScreening from './useScreening'
|
||||
import useScaleCanvas from './useScaleCanvas'
|
||||
|
||||
export default () => {
|
||||
const store = useStore()
|
||||
|
||||
const ctrlKeyActive = computed(() => store.state.ctrlKeyState)
|
||||
const shiftKeyActive = computed(() => store.state.shiftKeyState)
|
||||
const disableHotkeys = computed(() => store.state.disableHotkeys)
|
||||
const activeElementIdList = computed(() => store.state.activeElementIdList)
|
||||
const handleElement = computed<PPTElement>(() => store.getters.handleElement)
|
||||
const currentSlide = computed<Slide>(() => store.getters.currentSlide)
|
||||
|
||||
const editorAreaFocus = computed(() => store.state.editorAreaFocus)
|
||||
const thumbnailsFocus = computed(() => store.state.thumbnailsFocus)
|
||||
const mainStore = useMainStore()
|
||||
const keyboardStore = useKeyboardStore()
|
||||
const {
|
||||
activeElementIdList,
|
||||
disableHotkeys,
|
||||
handleElement,
|
||||
handleElementId,
|
||||
editorAreaFocus,
|
||||
thumbnailsFocus,
|
||||
} = storeToRefs(mainStore)
|
||||
const { currentSlide } = storeToRefs(useSlidesStore())
|
||||
const { ctrlKeyState, shiftKeyState } = storeToRefs(keyboardStore)
|
||||
|
||||
const {
|
||||
updateSlideIndex,
|
||||
@ -106,17 +107,16 @@ export default () => {
|
||||
|
||||
const tabActiveElement = () => {
|
||||
if (!currentSlide.value.elements.length) return
|
||||
if (!handleElement.value) {
|
||||
if (!handleElementId.value) {
|
||||
const firstElement = currentSlide.value.elements[0]
|
||||
store.commit(MutationTypes.SET_ACTIVE_ELEMENT_ID_LIST, [firstElement.id])
|
||||
mainStore.setActiveElementIdList([firstElement.id])
|
||||
return
|
||||
}
|
||||
|
||||
const currentIndex = currentSlide.value.elements.findIndex(el => el.id === handleElement.value.id)
|
||||
const currentIndex = currentSlide.value.elements.findIndex(el => el.id === handleElementId.value)
|
||||
const nextIndex = currentIndex >= currentSlide.value.elements.length - 1 ? 0 : currentIndex + 1
|
||||
const nextElementId = currentSlide.value.elements[nextIndex].id
|
||||
|
||||
store.commit(MutationTypes.SET_ACTIVE_ELEMENT_ID_LIST, [nextElementId])
|
||||
mainStore.setActiveElementIdList([nextElementId])
|
||||
}
|
||||
|
||||
const keydownListener = (e: KeyboardEvent) => {
|
||||
@ -125,13 +125,13 @@ export default () => {
|
||||
|
||||
const key = e.key.toUpperCase()
|
||||
|
||||
if (ctrlOrMetaKeyActive && !ctrlKeyActive.value) store.commit(MutationTypes.SET_CTRL_KEY_STATE, true)
|
||||
if (shiftKey && !shiftKeyActive.value) store.commit(MutationTypes.SET_SHIFT_KEY_STATE, true)
|
||||
if (ctrlOrMetaKeyActive && !ctrlKeyState.value) keyboardStore.setCtrlKeyState(true)
|
||||
if (shiftKey && !shiftKeyState.value) keyboardStore.setShiftKeyState(true)
|
||||
|
||||
if (ctrlOrMetaKeyActive && key === KEYS.F) {
|
||||
e.preventDefault()
|
||||
enterScreening()
|
||||
store.commit(MutationTypes.SET_CTRL_KEY_STATE, false)
|
||||
keyboardStore.setCtrlKeyState(false)
|
||||
}
|
||||
|
||||
if (!editorAreaFocus.value && !thumbnailsFocus.value) return
|
||||
@ -244,8 +244,8 @@ export default () => {
|
||||
}
|
||||
|
||||
const keyupListener = () => {
|
||||
if (ctrlKeyActive.value) store.commit(MutationTypes.SET_CTRL_KEY_STATE, false)
|
||||
if (shiftKeyActive.value) store.commit(MutationTypes.SET_SHIFT_KEY_STATE, false)
|
||||
if (ctrlKeyState.value) keyboardStore.setCtrlKeyState(false)
|
||||
if (shiftKeyState.value) keyboardStore.setShiftKeyState(false)
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
|
@ -1,22 +1,22 @@
|
||||
import { debounce, throttle} from 'lodash'
|
||||
import { ActionTypes, useStore } from '@/store'
|
||||
import { useSnapshotStore } from '@/store'
|
||||
|
||||
export default () => {
|
||||
const store = useStore()
|
||||
const snapshotStore = useSnapshotStore()
|
||||
|
||||
// 添加历史快照(历史记录)
|
||||
const addHistorySnapshot = debounce(function() {
|
||||
store.dispatch(ActionTypes.ADD_SNAPSHOT)
|
||||
snapshotStore.addSnapshot()
|
||||
}, 300, { trailing: true })
|
||||
|
||||
// 重做
|
||||
const redo = throttle(function() {
|
||||
store.dispatch(ActionTypes.RE_DO)
|
||||
snapshotStore.reDo()
|
||||
}, 100, { leading: true, trailing: false })
|
||||
|
||||
// 撤销
|
||||
const undo = throttle(function() {
|
||||
store.dispatch(ActionTypes.UN_DO)
|
||||
snapshotStore.unDo()
|
||||
}, 100, { leading: true, trailing: false })
|
||||
|
||||
return {
|
||||
|
@ -1,10 +1,10 @@
|
||||
import { MutationTypes, useStore } from '@/store'
|
||||
import { useSlidesStore } from '@/store'
|
||||
import { PPTElement } from '@/types/slides'
|
||||
import useHistorySnapshot from '@/hooks/useHistorySnapshot'
|
||||
import { message } from 'ant-design-vue'
|
||||
|
||||
export default () => {
|
||||
const store = useStore()
|
||||
const slidesStore = useSlidesStore()
|
||||
|
||||
const { addHistorySnapshot } = useHistorySnapshot()
|
||||
|
||||
@ -15,14 +15,14 @@ export default () => {
|
||||
return false
|
||||
}
|
||||
const props = { link }
|
||||
store.commit(MutationTypes.UPDATE_ELEMENT, { id: handleElement.id, props })
|
||||
slidesStore.updateElement({ id: handleElement.id, props })
|
||||
addHistorySnapshot()
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
const removeLink = (handleElement: PPTElement) => {
|
||||
store.commit(MutationTypes.REMOVE_ELEMENT_PROPS, { id: handleElement.id, propName: 'link' })
|
||||
slidesStore.removeElementProps({ id: handleElement.id, propName: 'link' })
|
||||
addHistorySnapshot()
|
||||
}
|
||||
|
||||
|
@ -1,12 +1,13 @@
|
||||
import { computed } from 'vue'
|
||||
import { MutationTypes, useStore } from '@/store'
|
||||
import { PPTElement, Slide } from '@/types/slides'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useMainStore, useSlidesStore } from '@/store'
|
||||
import { PPTElement } from '@/types/slides'
|
||||
import useHistorySnapshot from '@/hooks/useHistorySnapshot'
|
||||
|
||||
export default () => {
|
||||
const store = useStore()
|
||||
const activeElementIdList = computed(() => store.state.activeElementIdList)
|
||||
const currentSlide = computed<Slide>(() => store.getters.currentSlide)
|
||||
const mainStore = useMainStore()
|
||||
const slidesStore = useSlidesStore()
|
||||
const { activeElementIdList } = storeToRefs(mainStore)
|
||||
const { currentSlide } = storeToRefs(slidesStore)
|
||||
|
||||
const { addHistorySnapshot } = useHistorySnapshot()
|
||||
|
||||
@ -17,8 +18,8 @@ export default () => {
|
||||
for (const element of newElementList) {
|
||||
if (activeElementIdList.value.includes(element.id)) element.lock = true
|
||||
}
|
||||
store.commit(MutationTypes.UPDATE_SLIDE, { elements: newElementList })
|
||||
store.commit(MutationTypes.SET_ACTIVE_ELEMENT_ID_LIST, [])
|
||||
slidesStore.updateSlide({ elements: newElementList })
|
||||
mainStore.setActiveElementIdList([])
|
||||
addHistorySnapshot()
|
||||
}
|
||||
|
||||
@ -42,8 +43,8 @@ export default () => {
|
||||
break
|
||||
}
|
||||
}
|
||||
store.commit(MutationTypes.UPDATE_SLIDE, { elements: newElementList })
|
||||
store.commit(MutationTypes.SET_ACTIVE_ELEMENT_ID_LIST, [handleElement.id])
|
||||
slidesStore.updateSlide({ elements: newElementList })
|
||||
mainStore.setActiveElementIdList([handleElement.id])
|
||||
addHistorySnapshot()
|
||||
}
|
||||
|
||||
|
@ -1,14 +1,13 @@
|
||||
import { computed } from 'vue'
|
||||
import { MutationTypes, useStore } from '@/store'
|
||||
import { PPTElement, Slide } from '@/types/slides'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useMainStore, useSlidesStore } from '@/store'
|
||||
import { PPTElement } from '@/types/slides'
|
||||
import { KEYS } from '@/configs/hotkey'
|
||||
import useHistorySnapshot from '@/hooks/useHistorySnapshot'
|
||||
|
||||
export default () => {
|
||||
const store = useStore()
|
||||
const activeElementIdList = computed(() => store.state.activeElementIdList)
|
||||
const activeGroupElementId = computed(() => store.state.activeGroupElementId)
|
||||
const currentSlide = computed<Slide>(() => store.getters.currentSlide)
|
||||
const slidesStore = useSlidesStore()
|
||||
const { activeElementIdList, activeGroupElementId } = storeToRefs(useMainStore())
|
||||
const { currentSlide } = storeToRefs(slidesStore)
|
||||
|
||||
const { addHistorySnapshot } = useHistorySnapshot()
|
||||
|
||||
@ -52,7 +51,7 @@ export default () => {
|
||||
})
|
||||
}
|
||||
|
||||
store.commit(MutationTypes.UPDATE_SLIDE, { elements: newElementList })
|
||||
slidesStore.updateSlide({ elements: newElementList })
|
||||
addHistorySnapshot()
|
||||
}
|
||||
|
||||
|
@ -1,12 +1,12 @@
|
||||
import { computed } from 'vue'
|
||||
import { MutationTypes, useStore } from '@/store'
|
||||
import { PPTElement, Slide } from '@/types/slides'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useSlidesStore } from '@/store'
|
||||
import { PPTElement } from '@/types/slides'
|
||||
import { ElementOrderCommand, ElementOrderCommands } from '@/types/edit'
|
||||
import useHistorySnapshot from '@/hooks/useHistorySnapshot'
|
||||
|
||||
export default () => {
|
||||
const store = useStore()
|
||||
const currentSlide = computed<Slide>(() => store.getters.currentSlide)
|
||||
const slidesStore = useSlidesStore()
|
||||
const { currentSlide } = storeToRefs(slidesStore)
|
||||
|
||||
const { addHistorySnapshot } = useHistorySnapshot()
|
||||
|
||||
@ -202,7 +202,7 @@ export default () => {
|
||||
|
||||
if (!newElementList) return
|
||||
|
||||
store.commit(MutationTypes.UPDATE_SLIDE, { elements: newElementList })
|
||||
slidesStore.updateSlide({ elements: newElementList })
|
||||
addHistorySnapshot()
|
||||
}
|
||||
|
||||
|
@ -1,14 +1,12 @@
|
||||
import { computed, onMounted, onUnmounted } from 'vue'
|
||||
import { useStore } from '@/store'
|
||||
import { onMounted, onUnmounted } from 'vue'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useMainStore } from '@/store'
|
||||
import { getImageDataURL } from '@/utils/image'
|
||||
import usePasteTextClipboardData from './usePasteTextClipboardData'
|
||||
import useCreateElement from './useCreateElement'
|
||||
|
||||
export default () => {
|
||||
const store = useStore()
|
||||
const editorAreaFocus = computed(() => store.state.editorAreaFocus)
|
||||
const thumbnailsFocus = computed(() => store.state.thumbnailsFocus)
|
||||
const disableHotkeys = computed(() => store.state.disableHotkeys)
|
||||
const { editorAreaFocus, thumbnailsFocus, disableHotkeys } = storeToRefs(useMainStore())
|
||||
|
||||
const { pasteTextClipboardData } = usePasteTextClipboardData()
|
||||
const { createImageElement } = useCreateElement()
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { computed } from 'vue'
|
||||
import { MutationTypes, useStore } from '@/store'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useSlidesStore, useMainStore } from '@/store'
|
||||
import { pasteCustomClipboardString } from '@/utils/clipboard'
|
||||
import { PPTElement, Slide } from '@/types/slides'
|
||||
import { createRandomCode } from '@/utils/common'
|
||||
@ -14,8 +14,9 @@ interface PasteTextClipboardDataOptions {
|
||||
}
|
||||
|
||||
export default () => {
|
||||
const store = useStore()
|
||||
const currentSlide = computed<Slide>(() => store.getters.currentSlide)
|
||||
const mainStore = useMainStore()
|
||||
const slidesStore = useSlidesStore()
|
||||
const { currentSlide } = storeToRefs(slidesStore)
|
||||
|
||||
const { addHistorySnapshot } = useHistorySnapshot()
|
||||
const { createTextElement } = useCreateElement()
|
||||
@ -40,8 +41,8 @@ export default () => {
|
||||
|
||||
if (element.groupId) element.groupId = groupIdMap[element.groupId]
|
||||
}
|
||||
store.commit(MutationTypes.ADD_ELEMENT, elements)
|
||||
store.commit(MutationTypes.SET_ACTIVE_ELEMENT_ID_LIST, Object.values(elIdMap))
|
||||
slidesStore.addElement(elements)
|
||||
mainStore.setActiveElementIdList(Object.values(elIdMap))
|
||||
addHistorySnapshot()
|
||||
}
|
||||
|
||||
@ -67,7 +68,7 @@ export default () => {
|
||||
id: createRandomCode(8),
|
||||
}
|
||||
})
|
||||
store.commit(MutationTypes.ADD_SLIDE, newSlides)
|
||||
slidesStore.addSlide(newSlides)
|
||||
addHistorySnapshot()
|
||||
}
|
||||
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { computed } from 'vue'
|
||||
import { MutationTypes, useStore } from '@/store'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useMainStore } from '@/store'
|
||||
|
||||
export default () => {
|
||||
const store = useStore()
|
||||
const canvasPercentage = computed(() => store.state.canvasPercentage)
|
||||
const mainStore = useMainStore()
|
||||
const { canvasPercentage } = storeToRefs(mainStore)
|
||||
|
||||
/**
|
||||
* 缩放画布百分比
|
||||
@ -16,8 +16,8 @@ export default () => {
|
||||
const min = 60
|
||||
if (command === '+' && percentage <= max) percentage += step
|
||||
if (command === '-' && percentage >= min) percentage -= step
|
||||
|
||||
store.commit(MutationTypes.SET_CANVAS_PERCENTAGE, percentage)
|
||||
|
||||
mainStore.setCanvasPercentage(percentage)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -25,7 +25,7 @@ export default () => {
|
||||
* @param percentage 百分比(小数形式,如0.8)
|
||||
*/
|
||||
const setCanvasPercentage = (percentage: number) => {
|
||||
store.commit(MutationTypes.SET_CANVAS_PERCENTAGE, percentage)
|
||||
mainStore.setCanvasPercentage(percentage)
|
||||
}
|
||||
|
||||
return {
|
||||
|
@ -1,24 +1,25 @@
|
||||
import { MutationTypes, useStore } from '@/store'
|
||||
import { useScreenStore, useSlidesStore } from '@/store'
|
||||
import { enterFullscreen, exitFullscreen, isFullscreen } from '@/utils/fullscreen'
|
||||
|
||||
export default () => {
|
||||
const store = useStore()
|
||||
const screenStore = useScreenStore()
|
||||
const slidesStore = useSlidesStore()
|
||||
|
||||
// 进入放映状态(从当前页开始)
|
||||
const enterScreening = () => {
|
||||
enterFullscreen()
|
||||
store.commit(MutationTypes.SET_SCREENING, true)
|
||||
screenStore.setScreening(true)
|
||||
}
|
||||
|
||||
// 进入放映状态(从第一页开始)
|
||||
const enterScreeningFromStart = () => {
|
||||
store.commit(MutationTypes.UPDATE_SLIDE_INDEX, 0)
|
||||
slidesStore.updateSlideIndex(0)
|
||||
enterScreening()
|
||||
}
|
||||
|
||||
// 退出放映状态
|
||||
const exitScreening = () => {
|
||||
store.commit(MutationTypes.SET_SCREENING, false)
|
||||
screenStore.setScreening(false)
|
||||
if (isFullscreen()) exitFullscreen()
|
||||
}
|
||||
|
||||
|
@ -1,16 +1,15 @@
|
||||
import { computed } from 'vue'
|
||||
import { MutationTypes, useStore } from '@/store'
|
||||
import { Slide } from '@/types/slides'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useMainStore, useSlidesStore } from '@/store'
|
||||
|
||||
export default () => {
|
||||
const store = useStore()
|
||||
const currentSlide = computed<Slide>(() => store.getters.currentSlide)
|
||||
const mainStore = useMainStore()
|
||||
const { currentSlide } = storeToRefs(useSlidesStore())
|
||||
|
||||
// 将当前页面全部元素设置为被选择状态
|
||||
const selectAllElement = () => {
|
||||
const unlockedElements = currentSlide.value.elements.filter(el => !el.lock)
|
||||
const newActiveElementIdList = unlockedElements.map(el => el.id)
|
||||
store.commit(MutationTypes.SET_ACTIVE_ELEMENT_ID_LIST, newActiveElementIdList)
|
||||
mainStore.setActiveElementIdList(newActiveElementIdList)
|
||||
}
|
||||
|
||||
return {
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { computed } from 'vue'
|
||||
import { MutationTypes, useStore } from '@/store'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useMainStore, useSlidesStore } from '@/store'
|
||||
import { Slide } from '@/types/slides'
|
||||
import { createRandomCode } from '@/utils/common'
|
||||
import { copyText, readClipboard } from '@/utils/clipboard'
|
||||
@ -11,13 +12,12 @@ import usePasteTextClipboardData from '@/hooks/usePasteTextClipboardData'
|
||||
import useHistorySnapshot from '@/hooks/useHistorySnapshot'
|
||||
|
||||
export default () => {
|
||||
const store = useStore()
|
||||
const slideIndex = computed(() => store.state.slideIndex)
|
||||
const theme = computed(() => store.state.theme)
|
||||
const slides = computed(() => store.state.slides)
|
||||
const currentSlide = computed<Slide>(() => store.getters.currentSlide)
|
||||
const mainStore = useMainStore()
|
||||
const slidesStore = useSlidesStore()
|
||||
const { selectedSlidesIndex: _selectedSlidesIndex } = storeToRefs(mainStore)
|
||||
const { currentSlide, slides, theme, slideIndex } = storeToRefs(slidesStore)
|
||||
|
||||
const selectedSlidesIndex = computed(() => [...store.state.selectedSlidesIndex, slideIndex.value])
|
||||
const selectedSlidesIndex = computed(() => [..._selectedSlidesIndex.value, slideIndex.value])
|
||||
const selectedSlides = computed(() => slides.value.filter((item, index) => selectedSlidesIndex.value.includes(index)))
|
||||
const selectedSlidesId = computed(() => selectedSlides.value.map(item => item.id))
|
||||
|
||||
@ -26,7 +26,7 @@ export default () => {
|
||||
|
||||
// 重置幻灯片
|
||||
const resetSlides = () => {
|
||||
const emptySlide = {
|
||||
const emptySlide: Slide = {
|
||||
id: createRandomCode(8),
|
||||
elements: [],
|
||||
background: {
|
||||
@ -34,9 +34,9 @@ export default () => {
|
||||
color: theme.value.backgroundColor,
|
||||
},
|
||||
}
|
||||
store.commit(MutationTypes.UPDATE_SLIDE_INDEX, 0)
|
||||
store.commit(MutationTypes.SET_ACTIVE_ELEMENT_ID_LIST, [])
|
||||
store.commit(MutationTypes.SET_SLIDES, [emptySlide])
|
||||
slidesStore.updateSlideIndex(0)
|
||||
mainStore.setActiveElementIdList([])
|
||||
slidesStore.setSlides([emptySlide])
|
||||
}
|
||||
|
||||
/**
|
||||
@ -45,10 +45,10 @@ export default () => {
|
||||
*/
|
||||
const updateSlideIndex = (command: string) => {
|
||||
if (command === KEYS.UP && slideIndex.value > 0) {
|
||||
store.commit(MutationTypes.UPDATE_SLIDE_INDEX, slideIndex.value - 1)
|
||||
slidesStore.updateSlideIndex(slideIndex.value - 1)
|
||||
}
|
||||
else if (command === KEYS.DOWN && slideIndex.value < slides.value.length - 1) {
|
||||
store.commit(MutationTypes.UPDATE_SLIDE_INDEX, slideIndex.value + 1)
|
||||
slidesStore.updateSlideIndex(slideIndex.value + 1)
|
||||
}
|
||||
}
|
||||
|
||||
@ -60,7 +60,7 @@ export default () => {
|
||||
}))
|
||||
|
||||
copyText(text).then(() => {
|
||||
store.commit(MutationTypes.SET_THUMBNAILS_FOCUS, true)
|
||||
mainStore.setThumbnailsFocus(true)
|
||||
})
|
||||
}
|
||||
|
||||
@ -73,7 +73,7 @@ export default () => {
|
||||
|
||||
// 创建一页空白页并添加到下一页
|
||||
const createSlide = () => {
|
||||
const emptySlide = {
|
||||
const emptySlide: Slide = {
|
||||
id: createRandomCode(8),
|
||||
elements: [],
|
||||
background: {
|
||||
@ -81,8 +81,8 @@ export default () => {
|
||||
color: theme.value.backgroundColor,
|
||||
},
|
||||
}
|
||||
store.commit(MutationTypes.SET_ACTIVE_ELEMENT_ID_LIST, [])
|
||||
store.commit(MutationTypes.ADD_SLIDE, emptySlide)
|
||||
mainStore.setActiveElementIdList([])
|
||||
slidesStore.addSlide(emptySlide)
|
||||
addHistorySnapshot()
|
||||
}
|
||||
|
||||
@ -98,8 +98,8 @@ export default () => {
|
||||
...slide,
|
||||
id: createRandomCode(8),
|
||||
}
|
||||
store.commit(MutationTypes.SET_ACTIVE_ELEMENT_ID_LIST, [])
|
||||
store.commit(MutationTypes.ADD_SLIDE, newSlide)
|
||||
mainStore.setActiveElementIdList([])
|
||||
slidesStore.addSlide(newSlide)
|
||||
addHistorySnapshot()
|
||||
}
|
||||
|
||||
@ -112,9 +112,9 @@ export default () => {
|
||||
// 删除当前页,若将删除全部页面,则执行重置幻灯片操作
|
||||
const deleteSlide = (targetSlidesId = selectedSlidesId.value) => {
|
||||
if (slides.value.length === targetSlidesId.length) resetSlides()
|
||||
else store.commit(MutationTypes.DELETE_SLIDE, targetSlidesId)
|
||||
else slidesStore.deleteSlide(targetSlidesId)
|
||||
|
||||
store.commit(MutationTypes.UPDATE_SELECTED_SLIDES_INDEX, [])
|
||||
mainStore.updateSelectedSlidesIndex([])
|
||||
|
||||
addHistorySnapshot()
|
||||
}
|
||||
@ -130,8 +130,8 @@ export default () => {
|
||||
// 选中全部幻灯片
|
||||
const selectAllSlide = () => {
|
||||
const newSelectedSlidesIndex = Array.from(Array(slides.value.length), (item, index) => index)
|
||||
store.commit(MutationTypes.SET_ACTIVE_ELEMENT_ID_LIST, [])
|
||||
store.commit(MutationTypes.UPDATE_SELECTED_SLIDES_INDEX, newSelectedSlidesIndex)
|
||||
mainStore.setActiveElementIdList([])
|
||||
mainStore.updateSelectedSlidesIndex(newSelectedSlidesIndex)
|
||||
}
|
||||
|
||||
return {
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { computed } from 'vue'
|
||||
import { MutationTypes, useStore } from '@/store'
|
||||
import { PPTElement, Slide } from '@/types/slides'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useMainStore, useSlidesStore } from '@/store'
|
||||
import { PPTElement } from '@/types/slides'
|
||||
import { getElementRange, getElementListRange, getRectRotatedOffset } from '@/utils/element'
|
||||
import useHistorySnapshot from './useHistorySnapshot'
|
||||
|
||||
@ -34,10 +35,9 @@ interface LastPos {
|
||||
}
|
||||
|
||||
export default () => {
|
||||
const store = useStore()
|
||||
const activeElementIdList = computed(() => store.state.activeElementIdList)
|
||||
const activeElementList = computed<PPTElement[]>(() => store.getters.activeElementList)
|
||||
const currentSlide = computed<Slide>(() => store.getters.currentSlide)
|
||||
const slidesStore = useSlidesStore()
|
||||
const { activeElementIdList, activeElementList } = storeToRefs(useMainStore())
|
||||
const { currentSlide } = storeToRefs(slidesStore)
|
||||
|
||||
const { addHistorySnapshot } = useHistorySnapshot()
|
||||
|
||||
@ -154,7 +154,7 @@ export default () => {
|
||||
}
|
||||
}
|
||||
|
||||
store.commit(MutationTypes.UPDATE_SLIDE, { elements: newElementList })
|
||||
slidesStore.updateSlide({ elements: newElementList })
|
||||
addHistorySnapshot()
|
||||
}
|
||||
|
||||
@ -249,7 +249,7 @@ export default () => {
|
||||
}
|
||||
}
|
||||
|
||||
store.commit(MutationTypes.UPDATE_SLIDE, { elements: newElementList })
|
||||
slidesStore.updateSlide({ elements: newElementList })
|
||||
addHistorySnapshot()
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { createApp } from 'vue'
|
||||
import { createPinia } from 'pinia'
|
||||
import App from './App.vue'
|
||||
import { store, key } from './store'
|
||||
|
||||
import '@icon-park/vue-next/styles/index.css'
|
||||
import 'prosemirror-view/style/prosemirror.css'
|
||||
@ -65,5 +65,5 @@ app.use(Icon)
|
||||
app.use(Component)
|
||||
app.use(Directive)
|
||||
|
||||
app.use(store, key)
|
||||
app.use(createPinia())
|
||||
app.mount('#app')
|
||||
|
@ -1,99 +0,0 @@
|
||||
import { ActionTree } from 'vuex'
|
||||
import { IndexableTypeArray } from 'dexie'
|
||||
import { State } from './state'
|
||||
import { ActionTypes, MutationTypes } from './constants'
|
||||
import { snapshotDB, Snapshot } from '@/utils/database'
|
||||
|
||||
export const actions: ActionTree<State, State> = {
|
||||
async [ActionTypes.INIT_SNAPSHOT_DATABASE]({ commit, state }) {
|
||||
const snapshots: Snapshot[] = await snapshotDB.snapshots.orderBy('id').toArray()
|
||||
const lastSnapshot = snapshots.slice(-1)[0]
|
||||
|
||||
if (lastSnapshot) {
|
||||
snapshotDB.snapshots.clear()
|
||||
}
|
||||
|
||||
const newFirstSnapshot = {
|
||||
index: state.slideIndex,
|
||||
slides: state.slides,
|
||||
}
|
||||
await snapshotDB.snapshots.add(newFirstSnapshot)
|
||||
commit(MutationTypes.SET_SNAPSHOT_CURSOR, 0)
|
||||
commit(MutationTypes.SET_SNAPSHOT_LENGTH, 1)
|
||||
},
|
||||
|
||||
async [ActionTypes.ADD_SNAPSHOT]({ state, commit }) {
|
||||
|
||||
// 获取当前indexeddb中全部快照的ID
|
||||
const allKeys = await snapshotDB.snapshots.orderBy('id').keys()
|
||||
|
||||
let needDeleteKeys: IndexableTypeArray = []
|
||||
|
||||
// 记录需要删除的快照ID
|
||||
// 若当前快照指针不处在最后一位,那么再添加快照时,应该将当前指针位置后面的快照全部删除,对应的实际情况是:
|
||||
// 用户撤回多次后,再进行操作(添加快照),此时原先被撤销的快照都应该被删除
|
||||
if (state.snapshotCursor >= 0 && state.snapshotCursor < allKeys.length - 1) {
|
||||
needDeleteKeys = allKeys.slice(state.snapshotCursor + 1)
|
||||
}
|
||||
|
||||
// 添加新快照
|
||||
const snapshot = {
|
||||
index: state.slideIndex,
|
||||
slides: state.slides,
|
||||
}
|
||||
await snapshotDB.snapshots.add(snapshot)
|
||||
|
||||
// 计算当前快照长度,用于设置快照指针的位置(此时指针应该处在最后一位,即:快照长度 - 1)
|
||||
let snapshotLength = allKeys.length - needDeleteKeys.length + 1
|
||||
|
||||
// 快照数量超过长度限制时,应该将头部多余的快照删除
|
||||
const snapshotLengthLimit = 20
|
||||
if (snapshotLength > snapshotLengthLimit) {
|
||||
needDeleteKeys.push(allKeys[0])
|
||||
snapshotLength--
|
||||
}
|
||||
|
||||
// 快照数大于1时,需要保证撤回操作后维持页面焦点不变:也就是将倒数第二个快照对应的索引设置为当前页的索引
|
||||
// https://github.com/pipipi-pikachu/PPTist/issues/27
|
||||
if (snapshotLength >= 2) {
|
||||
snapshotDB.snapshots.update(allKeys[snapshotLength - 2] as number, { index: state.slideIndex })
|
||||
}
|
||||
|
||||
await snapshotDB.snapshots.bulkDelete(needDeleteKeys)
|
||||
|
||||
commit(MutationTypes.SET_SNAPSHOT_CURSOR, snapshotLength - 1)
|
||||
commit(MutationTypes.SET_SNAPSHOT_LENGTH, snapshotLength)
|
||||
},
|
||||
|
||||
async [ActionTypes.UN_DO]({ state, commit }) {
|
||||
if (state.snapshotCursor <= 0) return
|
||||
|
||||
const snapshotCursor = state.snapshotCursor - 1
|
||||
const snapshots: Snapshot[] = await snapshotDB.snapshots.orderBy('id').toArray()
|
||||
const snapshot = snapshots[snapshotCursor]
|
||||
const { index, slides } = snapshot
|
||||
|
||||
const slideIndex = index > slides.length - 1 ? slides.length - 1 : index
|
||||
|
||||
commit(MutationTypes.SET_SLIDES, slides)
|
||||
commit(MutationTypes.UPDATE_SLIDE_INDEX, slideIndex)
|
||||
commit(MutationTypes.SET_SNAPSHOT_CURSOR, snapshotCursor)
|
||||
commit(MutationTypes.SET_ACTIVE_ELEMENT_ID_LIST, [])
|
||||
},
|
||||
|
||||
async [ActionTypes.RE_DO]({ state, commit }) {
|
||||
if (state.snapshotCursor >= state.snapshotLength - 1) return
|
||||
|
||||
const snapshotCursor = state.snapshotCursor + 1
|
||||
const snapshots: Snapshot[] = await snapshotDB.snapshots.orderBy('id').toArray()
|
||||
const snapshot = snapshots[snapshotCursor]
|
||||
const { index, slides } = snapshot
|
||||
|
||||
const slideIndex = index > slides.length - 1 ? slides.length - 1 : index
|
||||
|
||||
commit(MutationTypes.SET_SLIDES, slides)
|
||||
commit(MutationTypes.UPDATE_SLIDE_INDEX, slideIndex)
|
||||
commit(MutationTypes.SET_SNAPSHOT_CURSOR, snapshotCursor)
|
||||
commit(MutationTypes.SET_ACTIVE_ELEMENT_ID_LIST, [])
|
||||
},
|
||||
}
|
@ -1,52 +0,0 @@
|
||||
export const enum MutationTypes {
|
||||
|
||||
// editor
|
||||
SET_ACTIVE_ELEMENT_ID_LIST = 'setActiveElementIdList',
|
||||
SET_HANDLE_ELEMENT_ID = 'setHandleElementId',
|
||||
SET_ACTIVE_GROUP_ELEMENT_ID = 'setActiveGroupElementId',
|
||||
SET_CANVAS_PERCENTAGE = 'setCanvasPercentage',
|
||||
SET_CANVAS_SCALE = 'setCanvasScale',
|
||||
SET_THUMBNAILS_FOCUS = 'setThumbnailsFocus',
|
||||
SET_EDITORAREA_FOCUS = 'setEditorAreaFocus',
|
||||
SET_DISABLE_HOTKEYS_STATE = 'setDisableHotkeysState',
|
||||
SET_GRID_LINES_STATE = 'setGridLinesState',
|
||||
SET_CREATING_ELEMENT = 'setCreatingElement',
|
||||
SET_AVAILABLE_FONTS = 'setAvailableFonts',
|
||||
SET_TOOLBAR_STATE = 'setToolbarState',
|
||||
SET_CLIPING_IMAGE_ELEMENT_ID = 'setClipingImageElementId',
|
||||
SET_RICHTEXT_ATTRS = 'setRichTextAttrs',
|
||||
SET_SELECTED_TABLE_CELLS = 'setSelectedTableCells',
|
||||
SET_SCALING_STATE = 'setScalingState',
|
||||
SET_EDITING_SHAPE_ELEMENT_ID = 'setEditingShapeElementId',
|
||||
|
||||
// slides
|
||||
SET_THEME = 'setTheme',
|
||||
SET_VIEWPORT_RATIO = 'setViewportRatio',
|
||||
SET_SLIDES = 'setSlides',
|
||||
ADD_SLIDE = 'addSlide',
|
||||
UPDATE_SLIDE = 'updateSlide',
|
||||
DELETE_SLIDE = 'deleteSlide',
|
||||
UPDATE_SLIDE_INDEX = 'updateSlideIndex',
|
||||
UPDATE_SELECTED_SLIDES_INDEX = 'updateSelectedSlidesIndex',
|
||||
ADD_ELEMENT = 'addElement',
|
||||
UPDATE_ELEMENT = 'updateElement',
|
||||
REMOVE_ELEMENT_PROPS = 'removeElementProps',
|
||||
|
||||
// snapshot
|
||||
SET_SNAPSHOT_CURSOR = 'setSnapshotCursor',
|
||||
SET_SNAPSHOT_LENGTH = 'setSnapshotLength',
|
||||
|
||||
// keyboard
|
||||
SET_CTRL_KEY_STATE = 'setCtrlKeyState',
|
||||
SET_SHIFT_KEY_STATE = 'setShiftKeyState',
|
||||
|
||||
// screen
|
||||
SET_SCREENING = 'setScreening',
|
||||
}
|
||||
|
||||
export const enum ActionTypes {
|
||||
INIT_SNAPSHOT_DATABASE = 'initSnapshotDatabase',
|
||||
ADD_SNAPSHOT = 'addSnapshot',
|
||||
UN_DO = 'undo',
|
||||
RE_DO = 'redo',
|
||||
}
|
@ -1,65 +0,0 @@
|
||||
import { GetterTree } from 'vuex'
|
||||
import tinycolor from 'tinycolor2'
|
||||
import { State } from './state'
|
||||
import { layouts } from '@/mocks/layout'
|
||||
|
||||
export const getters: GetterTree<State, State> = {
|
||||
currentSlide(state) {
|
||||
return state.slides[state.slideIndex] || null
|
||||
},
|
||||
|
||||
currentSlideAnimations(state) {
|
||||
const currentSlide = state.slides[state.slideIndex]
|
||||
if (!currentSlide) return null
|
||||
const animations = currentSlide.animations
|
||||
if (!animations) return null
|
||||
|
||||
const els = currentSlide.elements
|
||||
const elIds = els.map(el => el.id)
|
||||
return animations.filter(animation => elIds.includes(animation.elId))
|
||||
},
|
||||
|
||||
layouts(state) {
|
||||
const {
|
||||
themeColor,
|
||||
fontColor,
|
||||
fontName,
|
||||
backgroundColor,
|
||||
} = state.theme
|
||||
|
||||
const subColor = tinycolor(fontColor).isDark() ? 'rgba(230, 230, 230, 0.5)' : 'rgba(180, 180, 180, 0.5)'
|
||||
|
||||
const layoutsString = JSON.stringify(layouts)
|
||||
.replaceAll('{{themeColor}}', themeColor)
|
||||
.replaceAll('{{fontColor}}', fontColor)
|
||||
.replaceAll('{{fontName}}', fontName)
|
||||
.replaceAll('{{backgroundColor}}', backgroundColor)
|
||||
.replaceAll('{{subColor}}', subColor)
|
||||
|
||||
return JSON.parse(layoutsString)
|
||||
},
|
||||
|
||||
activeElementList(state) {
|
||||
const currentSlide = state.slides[state.slideIndex]
|
||||
if (!currentSlide || !currentSlide.elements) return []
|
||||
return currentSlide.elements.filter(element => state.activeElementIdList.includes(element.id))
|
||||
},
|
||||
|
||||
handleElement(state) {
|
||||
const currentSlide = state.slides[state.slideIndex]
|
||||
if (!currentSlide || !currentSlide.elements) return null
|
||||
return currentSlide.elements.find(element => state.handleElementId === element.id) || null
|
||||
},
|
||||
|
||||
canUndo(state) {
|
||||
return state.snapshotCursor > 0
|
||||
},
|
||||
|
||||
canRedo(state) {
|
||||
return state.snapshotCursor < state.snapshotLength - 1
|
||||
},
|
||||
|
||||
ctrlOrShiftKeyActive(state) {
|
||||
return state.ctrlKeyState || state.shiftKeyState
|
||||
},
|
||||
}
|
@ -1,20 +1,13 @@
|
||||
import { InjectionKey } from 'vue'
|
||||
import { createStore, Store, useStore as baseUseStore } from 'vuex'
|
||||
import { state, State } from './state'
|
||||
import { getters } from './getters'
|
||||
import { actions } from './actions'
|
||||
import { mutations } from './mutations'
|
||||
import { MutationTypes, ActionTypes } from './constants'
|
||||
import { useMainStore } from './main'
|
||||
import { useSlidesStore } from './slides'
|
||||
import { useSnapshotStore } from './snapshot'
|
||||
import { useKeyboardStore } from './keyboard'
|
||||
import { useScreenStore } from './screen'
|
||||
|
||||
export { MutationTypes, ActionTypes }
|
||||
|
||||
export const key: InjectionKey<Store<State>> = Symbol()
|
||||
|
||||
export const store = createStore<State>({
|
||||
state,
|
||||
getters,
|
||||
mutations,
|
||||
actions,
|
||||
})
|
||||
|
||||
export const useStore = () => baseUseStore(key)
|
||||
export {
|
||||
useMainStore,
|
||||
useSlidesStore,
|
||||
useSnapshotStore,
|
||||
useKeyboardStore,
|
||||
useScreenStore,
|
||||
}
|
28
src/store/keyboard.ts
Normal file
28
src/store/keyboard.ts
Normal file
@ -0,0 +1,28 @@
|
||||
import { defineStore } from 'pinia'
|
||||
|
||||
export interface KeyboardState {
|
||||
ctrlKeyState: boolean;
|
||||
shiftKeyState: boolean;
|
||||
}
|
||||
|
||||
export const useKeyboardStore = defineStore('keyboard', {
|
||||
state: (): KeyboardState => ({
|
||||
ctrlKeyState: false, // ctrl键按下状态
|
||||
shiftKeyState: false, // shift键按下状态
|
||||
}),
|
||||
|
||||
getters: {
|
||||
ctrlOrShiftKeyActive(state) {
|
||||
return state.ctrlKeyState || state.shiftKeyState
|
||||
},
|
||||
},
|
||||
|
||||
actions: {
|
||||
setCtrlKeyState(active: boolean) {
|
||||
this.ctrlKeyState = active
|
||||
},
|
||||
setShiftKeyState(active: boolean) {
|
||||
this.shiftKeyState = active
|
||||
},
|
||||
},
|
||||
})
|
145
src/store/main.ts
Normal file
145
src/store/main.ts
Normal file
@ -0,0 +1,145 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { CreatingElement } from '@/types/edit'
|
||||
import { ToolbarState } from '@/types/toolbar'
|
||||
import { SYS_FONTS } from '@/configs/font'
|
||||
import { TextAttrs, defaultRichTextAttrs } from '@/utils/prosemirror/utils'
|
||||
import { isSupportFont } from '@/utils/font'
|
||||
|
||||
import { useSlidesStore } from './slides'
|
||||
|
||||
export interface MainState {
|
||||
activeElementIdList: string[];
|
||||
handleElementId: string;
|
||||
activeGroupElementId: string;
|
||||
canvasPercentage: number;
|
||||
canvasScale: number;
|
||||
thumbnailsFocus: boolean;
|
||||
editorAreaFocus: boolean;
|
||||
disableHotkeys: boolean;
|
||||
showGridLines: boolean;
|
||||
creatingElement: CreatingElement | null;
|
||||
availableFonts: typeof SYS_FONTS;
|
||||
toolbarState: ToolbarState;
|
||||
clipingImageElementId: string;
|
||||
isScaling: boolean;
|
||||
richTextAttrs: TextAttrs;
|
||||
selectedTableCells: string[];
|
||||
editingShapeElementId: string;
|
||||
selectedSlidesIndex: number[];
|
||||
}
|
||||
|
||||
export const useMainStore = defineStore('main', {
|
||||
state: (): MainState => ({
|
||||
activeElementIdList: [], // 被选中的元素ID集合,包含 handleElementId
|
||||
handleElementId: '', // 正在操作的元素ID
|
||||
activeGroupElementId: '', // 组合元素成员中,被选中可独立操作的元素ID
|
||||
canvasPercentage: 90, // 画布可视区域百分比
|
||||
canvasScale: 1, // 画布缩放比例(基于宽度1000px)
|
||||
thumbnailsFocus: false, // 左侧导航缩略图区域聚焦
|
||||
editorAreaFocus: false, // 编辑区域聚焦
|
||||
disableHotkeys: false, // 禁用快捷键
|
||||
showGridLines: false, // 显示网格线
|
||||
creatingElement: null, // 正在插入的元素信息,需要绘制插入的元素需要(文字、形状、线条)
|
||||
availableFonts: [], // 当前环境可用字体
|
||||
toolbarState: 'slideDesign', // 右侧工具栏状态
|
||||
clipingImageElementId: '', // 当前正在裁剪的图片ID
|
||||
richTextAttrs: defaultRichTextAttrs, // 富文本状态
|
||||
selectedTableCells: [], // 选中的表格单元格
|
||||
isScaling: false, // 正在进行元素缩放
|
||||
editingShapeElementId: '', // 当前正处在编辑文字状态的形状ID
|
||||
selectedSlidesIndex: [], // 当前被选中的页面索引集合
|
||||
}),
|
||||
|
||||
getters: {
|
||||
activeElementList(state) {
|
||||
const slidesStore = useSlidesStore()
|
||||
const currentSlide = slidesStore.currentSlide
|
||||
if (!currentSlide || !currentSlide.elements) return []
|
||||
return currentSlide.elements.filter(element => state.activeElementIdList.includes(element.id))
|
||||
},
|
||||
|
||||
handleElement(state) {
|
||||
const slidesStore = useSlidesStore()
|
||||
const currentSlide = slidesStore.currentSlide
|
||||
if (!currentSlide || !currentSlide.elements) return null
|
||||
return currentSlide.elements.find(element => state.handleElementId === element.id) || null
|
||||
},
|
||||
},
|
||||
|
||||
actions: {
|
||||
setActiveElementIdList(activeElementIdList: string[]) {
|
||||
if (activeElementIdList.length === 1) this.handleElementId = activeElementIdList[0]
|
||||
else this.handleElementId = ''
|
||||
|
||||
this.activeElementIdList = activeElementIdList
|
||||
},
|
||||
|
||||
setHandleElementId(handleElementId: string) {
|
||||
this.handleElementId = handleElementId
|
||||
},
|
||||
|
||||
setActiveGroupElementId(activeGroupElementId: string) {
|
||||
this.activeGroupElementId = activeGroupElementId
|
||||
},
|
||||
|
||||
setCanvasPercentage(percentage: number) {
|
||||
this.canvasPercentage = percentage
|
||||
},
|
||||
|
||||
setCanvasScale(scale: number) {
|
||||
this.canvasScale = scale
|
||||
},
|
||||
|
||||
setThumbnailsFocus(isFocus: boolean) {
|
||||
this.thumbnailsFocus = isFocus
|
||||
},
|
||||
|
||||
setEditorareaFocus(isFocus: boolean) {
|
||||
this.editorAreaFocus = isFocus
|
||||
},
|
||||
|
||||
setDisableHotkeysState(disable: boolean) {
|
||||
this.disableHotkeys = disable
|
||||
},
|
||||
|
||||
setGridLinesState(show: boolean) {
|
||||
this.showGridLines = show
|
||||
},
|
||||
|
||||
setCreatingElement(element: CreatingElement | null) {
|
||||
this.creatingElement = element
|
||||
},
|
||||
|
||||
setAvailableFonts() {
|
||||
this.availableFonts = SYS_FONTS.filter(font => isSupportFont(font.value))
|
||||
},
|
||||
|
||||
setToolbarState(toolbarState: ToolbarState) {
|
||||
this.toolbarState = toolbarState
|
||||
},
|
||||
|
||||
setClipingImageElementId(elId: string) {
|
||||
this.clipingImageElementId = elId
|
||||
},
|
||||
|
||||
setRichtextAttrs(attrs: TextAttrs) {
|
||||
this.richTextAttrs = attrs
|
||||
},
|
||||
|
||||
setSelectedTableCells(cells: string[]) {
|
||||
this.selectedTableCells = cells
|
||||
},
|
||||
|
||||
setScalingState(isScaling: boolean) {
|
||||
this.isScaling = isScaling
|
||||
},
|
||||
|
||||
setEditingShapeElementId(ellId: string) {
|
||||
this.editingShapeElementId = ellId
|
||||
},
|
||||
|
||||
updateSelectedSlidesIndex(selectedSlidesIndex: number[]) {
|
||||
this.selectedSlidesIndex = selectedSlidesIndex
|
||||
},
|
||||
},
|
||||
})
|
@ -1,203 +0,0 @@
|
||||
import { MutationTree } from 'vuex'
|
||||
import { omit } from 'lodash'
|
||||
import { MutationTypes } from './constants'
|
||||
import { State } from './state'
|
||||
import { Slide, PPTElement, SlideTheme } from '@/types/slides'
|
||||
import { CreatingElement } from '@/types/edit'
|
||||
import { SYS_FONTS } from '@/configs/font'
|
||||
import { isSupportFont } from '@/utils/font'
|
||||
import { ToolbarState } from '@/types/toolbar'
|
||||
import { TextAttrs } from '@/utils/prosemirror/utils'
|
||||
|
||||
interface RemoveElementPropData {
|
||||
id: string;
|
||||
propName: string | string[];
|
||||
}
|
||||
|
||||
interface UpdateElementData {
|
||||
id: string | string[];
|
||||
props: Partial<PPTElement>;
|
||||
}
|
||||
|
||||
export const mutations: MutationTree<State> = {
|
||||
|
||||
// editor
|
||||
|
||||
[MutationTypes.SET_ACTIVE_ELEMENT_ID_LIST](state, activeElementIdList: string[]) {
|
||||
if (activeElementIdList.length === 1) state.handleElementId = activeElementIdList[0]
|
||||
else state.handleElementId = ''
|
||||
|
||||
state.activeElementIdList = activeElementIdList
|
||||
},
|
||||
|
||||
[MutationTypes.SET_HANDLE_ELEMENT_ID](state, handleElementId: string) {
|
||||
state.handleElementId = handleElementId
|
||||
},
|
||||
|
||||
[MutationTypes.SET_ACTIVE_GROUP_ELEMENT_ID](state, activeGroupElementId: string) {
|
||||
state.activeGroupElementId = activeGroupElementId
|
||||
},
|
||||
|
||||
[MutationTypes.SET_CANVAS_PERCENTAGE](state, percentage: number) {
|
||||
state.canvasPercentage = percentage
|
||||
},
|
||||
|
||||
[MutationTypes.SET_CANVAS_SCALE](state, scale: number) {
|
||||
state.canvasScale = scale
|
||||
},
|
||||
|
||||
[MutationTypes.SET_THUMBNAILS_FOCUS](state, isFocus: boolean) {
|
||||
state.thumbnailsFocus = isFocus
|
||||
},
|
||||
|
||||
[MutationTypes.SET_EDITORAREA_FOCUS](state, isFocus: boolean) {
|
||||
state.editorAreaFocus = isFocus
|
||||
},
|
||||
|
||||
[MutationTypes.SET_DISABLE_HOTKEYS_STATE](state, disable: boolean) {
|
||||
state.disableHotkeys = disable
|
||||
},
|
||||
|
||||
[MutationTypes.SET_GRID_LINES_STATE](state, show: boolean) {
|
||||
state.showGridLines = show
|
||||
},
|
||||
|
||||
[MutationTypes.SET_CREATING_ELEMENT](state, element: CreatingElement | null) {
|
||||
state.creatingElement = element
|
||||
},
|
||||
|
||||
[MutationTypes.SET_AVAILABLE_FONTS](state) {
|
||||
state.availableFonts = SYS_FONTS.filter(font => isSupportFont(font.value))
|
||||
},
|
||||
|
||||
[MutationTypes.SET_TOOLBAR_STATE](state, toolbarState: ToolbarState) {
|
||||
state.toolbarState = toolbarState
|
||||
},
|
||||
|
||||
[MutationTypes.SET_CLIPING_IMAGE_ELEMENT_ID](state, elId: string) {
|
||||
state.clipingImageElementId = elId
|
||||
},
|
||||
|
||||
[MutationTypes.SET_RICHTEXT_ATTRS](state, attrs: TextAttrs) {
|
||||
state.richTextAttrs = attrs
|
||||
},
|
||||
|
||||
[MutationTypes.SET_SELECTED_TABLE_CELLS](state, cells: string[]) {
|
||||
state.selectedTableCells = cells
|
||||
},
|
||||
|
||||
[MutationTypes.SET_SCALING_STATE](state, isScaling: boolean) {
|
||||
state.isScaling = isScaling
|
||||
},
|
||||
|
||||
[MutationTypes.SET_EDITING_SHAPE_ELEMENT_ID](state, ellId: string) {
|
||||
state.editingShapeElementId = ellId
|
||||
},
|
||||
|
||||
// slides
|
||||
|
||||
[MutationTypes.SET_THEME](state, themeProps: Partial<SlideTheme>) {
|
||||
state.theme = { ...state.theme, ...themeProps }
|
||||
},
|
||||
|
||||
[MutationTypes.SET_VIEWPORT_RATIO](state, viewportRatio: number) {
|
||||
state.viewportRatio = viewportRatio
|
||||
},
|
||||
|
||||
[MutationTypes.SET_SLIDES](state, slides: Slide[]) {
|
||||
state.slides = slides
|
||||
},
|
||||
|
||||
[MutationTypes.ADD_SLIDE](state, slide: Slide | Slide[]) {
|
||||
const slides = Array.isArray(slide) ? slide : [slide]
|
||||
const addIndex = state.slideIndex + 1
|
||||
state.slides.splice(addIndex, 0, ...slides)
|
||||
state.slideIndex = addIndex
|
||||
},
|
||||
|
||||
[MutationTypes.UPDATE_SLIDE](state, props: Partial<Slide>) {
|
||||
const slideIndex = state.slideIndex
|
||||
state.slides[slideIndex] = { ...state.slides[slideIndex], ...props }
|
||||
},
|
||||
|
||||
[MutationTypes.DELETE_SLIDE](state, slideId: string | string[]) {
|
||||
const slidesId = Array.isArray(slideId) ? slideId : [slideId]
|
||||
|
||||
const deleteSlidesIndex = []
|
||||
for (let i = 0; i < slidesId.length; i++) {
|
||||
const index = state.slides.findIndex(item => item.id === slidesId[i])
|
||||
deleteSlidesIndex.push(index)
|
||||
}
|
||||
let newIndex = Math.min(...deleteSlidesIndex)
|
||||
|
||||
const maxIndex = state.slides.length - slidesId.length - 1
|
||||
if (newIndex > maxIndex) newIndex = maxIndex
|
||||
|
||||
state.slideIndex = newIndex
|
||||
state.slides = state.slides.filter(item => !slidesId.includes(item.id))
|
||||
},
|
||||
|
||||
[MutationTypes.UPDATE_SLIDE_INDEX](state, index: number) {
|
||||
state.slideIndex = index
|
||||
},
|
||||
|
||||
[MutationTypes.UPDATE_SELECTED_SLIDES_INDEX](state, selectedSlidesIndex: number[]) {
|
||||
state.selectedSlidesIndex = selectedSlidesIndex
|
||||
},
|
||||
|
||||
[MutationTypes.ADD_ELEMENT](state, element: PPTElement | PPTElement[]) {
|
||||
const elements = Array.isArray(element) ? element : [element]
|
||||
const currentSlideEls = state.slides[state.slideIndex].elements
|
||||
const newEls = [...currentSlideEls, ...elements]
|
||||
state.slides[state.slideIndex].elements = newEls
|
||||
},
|
||||
|
||||
[MutationTypes.UPDATE_ELEMENT](state, data: UpdateElementData) {
|
||||
const { id, props } = data
|
||||
const elIdList = typeof id === 'string' ? [id] : id
|
||||
|
||||
const slideIndex = state.slideIndex
|
||||
const slide = state.slides[slideIndex]
|
||||
const elements = slide.elements.map(el => {
|
||||
return elIdList.includes(el.id) ? { ...el, ...props } : el
|
||||
})
|
||||
state.slides[slideIndex].elements = (elements as PPTElement[])
|
||||
},
|
||||
|
||||
[MutationTypes.REMOVE_ELEMENT_PROPS](state, data: RemoveElementPropData) {
|
||||
const { id, propName } = data
|
||||
const propsNames = typeof propName === 'string' ? [propName] : propName
|
||||
|
||||
const slideIndex = state.slideIndex
|
||||
const slide = state.slides[slideIndex]
|
||||
const elements = slide.elements.map(el => {
|
||||
return el.id === id ? omit(el, propsNames) : el
|
||||
})
|
||||
state.slides[slideIndex].elements = (elements as PPTElement[])
|
||||
},
|
||||
|
||||
// snapshot
|
||||
|
||||
[MutationTypes.SET_SNAPSHOT_CURSOR](state, cursor: number) {
|
||||
state.snapshotCursor = cursor
|
||||
},
|
||||
|
||||
[MutationTypes.SET_SNAPSHOT_LENGTH](state, length: number) {
|
||||
state.snapshotLength = length
|
||||
},
|
||||
|
||||
// keyboard
|
||||
|
||||
[MutationTypes.SET_CTRL_KEY_STATE](state, isActive: boolean) {
|
||||
state.ctrlKeyState = isActive
|
||||
},
|
||||
[MutationTypes.SET_SHIFT_KEY_STATE](state, isActive: boolean) {
|
||||
state.shiftKeyState = isActive
|
||||
},
|
||||
|
||||
// screen
|
||||
|
||||
[MutationTypes.SET_SCREENING](state, screening) {
|
||||
state.screening = screening
|
||||
},
|
||||
}
|
17
src/store/screen.ts
Normal file
17
src/store/screen.ts
Normal file
@ -0,0 +1,17 @@
|
||||
import { defineStore } from 'pinia'
|
||||
|
||||
export interface ScreenState {
|
||||
screening: boolean;
|
||||
}
|
||||
|
||||
export const useScreenStore = defineStore('screen', {
|
||||
state: (): ScreenState => ({
|
||||
screening: false, // 是否进入放映状态
|
||||
}),
|
||||
|
||||
actions: {
|
||||
setScreening(screening: boolean) {
|
||||
this.screening = screening
|
||||
},
|
||||
},
|
||||
})
|
148
src/store/slides.ts
Normal file
148
src/store/slides.ts
Normal file
@ -0,0 +1,148 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import tinycolor from 'tinycolor2'
|
||||
import { omit } from 'lodash'
|
||||
import { Slide, SlideTheme, PPTElement } from '@/types/slides'
|
||||
import { slides } from '@/mocks/slides'
|
||||
import { theme } from '@/mocks/theme'
|
||||
import { layouts } from '@/mocks/layout'
|
||||
|
||||
interface RemoveElementPropData {
|
||||
id: string;
|
||||
propName: string | string[];
|
||||
}
|
||||
|
||||
interface UpdateElementData {
|
||||
id: string | string[];
|
||||
props: Partial<PPTElement>;
|
||||
}
|
||||
|
||||
export interface SlidesState {
|
||||
theme: SlideTheme;
|
||||
slides: Slide[];
|
||||
slideIndex: number;
|
||||
viewportRatio: number;
|
||||
}
|
||||
|
||||
export const useSlidesStore = defineStore('slides', {
|
||||
state: (): SlidesState => ({
|
||||
theme: theme, // 主题样式
|
||||
slides: slides, // 幻灯片页面数据
|
||||
slideIndex: 0, // 当前页面索引
|
||||
viewportRatio: 0.5625, // 可是区域比例,默认16:9
|
||||
}),
|
||||
|
||||
getters: {
|
||||
currentSlide(state) {
|
||||
return state.slides[state.slideIndex]
|
||||
},
|
||||
|
||||
currentSlideAnimations(state) {
|
||||
const currentSlide = state.slides[state.slideIndex]
|
||||
if (!currentSlide) return null
|
||||
const animations = currentSlide.animations
|
||||
if (!animations) return null
|
||||
|
||||
const els = currentSlide.elements
|
||||
const elIds = els.map(el => el.id)
|
||||
return animations.filter(animation => elIds.includes(animation.elId))
|
||||
},
|
||||
|
||||
layouts(state) {
|
||||
const {
|
||||
themeColor,
|
||||
fontColor,
|
||||
fontName,
|
||||
backgroundColor,
|
||||
} = state.theme
|
||||
|
||||
const subColor = tinycolor(fontColor).isDark() ? 'rgba(230, 230, 230, 0.5)' : 'rgba(180, 180, 180, 0.5)'
|
||||
|
||||
const layoutsString = JSON.stringify(layouts)
|
||||
.replaceAll('{{themeColor}}', themeColor)
|
||||
.replaceAll('{{fontColor}}', fontColor)
|
||||
.replaceAll('{{fontName}}', fontName)
|
||||
.replaceAll('{{backgroundColor}}', backgroundColor)
|
||||
.replaceAll('{{subColor}}', subColor)
|
||||
|
||||
return JSON.parse(layoutsString)
|
||||
},
|
||||
},
|
||||
|
||||
actions: {
|
||||
setTheme(themeProps: Partial<SlideTheme>) {
|
||||
this.theme = { ...this.theme, ...themeProps }
|
||||
},
|
||||
|
||||
setViewportRatio(viewportRatio: number) {
|
||||
this.viewportRatio = viewportRatio
|
||||
},
|
||||
|
||||
setSlides(slides: Slide[]) {
|
||||
this.slides = slides
|
||||
},
|
||||
|
||||
addSlide(slide: Slide | Slide[]) {
|
||||
const slides = Array.isArray(slide) ? slide : [slide]
|
||||
const addIndex = this.slideIndex + 1
|
||||
this.slides.splice(addIndex, 0, ...slides)
|
||||
this.slideIndex = addIndex
|
||||
},
|
||||
|
||||
updateSlide(props: Partial<Slide>) {
|
||||
const slideIndex = this.slideIndex
|
||||
this.slides[slideIndex] = { ...this.slides[slideIndex], ...props }
|
||||
},
|
||||
|
||||
deleteSlide(slideId: string | string[]) {
|
||||
const slidesId = Array.isArray(slideId) ? slideId : [slideId]
|
||||
|
||||
const deleteSlidesIndex = []
|
||||
for (let i = 0; i < slidesId.length; i++) {
|
||||
const index = this.slides.findIndex(item => item.id === slidesId[i])
|
||||
deleteSlidesIndex.push(index)
|
||||
}
|
||||
let newIndex = Math.min(...deleteSlidesIndex)
|
||||
|
||||
const maxIndex = this.slides.length - slidesId.length - 1
|
||||
if (newIndex > maxIndex) newIndex = maxIndex
|
||||
|
||||
this.slideIndex = newIndex
|
||||
this.slides = this.slides.filter(item => !slidesId.includes(item.id))
|
||||
},
|
||||
|
||||
updateSlideIndex(index: number) {
|
||||
this.slideIndex = index
|
||||
},
|
||||
|
||||
addElement(element: PPTElement | PPTElement[]) {
|
||||
const elements = Array.isArray(element) ? element : [element]
|
||||
const currentSlideEls = this.slides[this.slideIndex].elements
|
||||
const newEls = [...currentSlideEls, ...elements]
|
||||
this.slides[this.slideIndex].elements = newEls
|
||||
},
|
||||
|
||||
updateElement(data: UpdateElementData) {
|
||||
const { id, props } = data
|
||||
const elIdList = typeof id === 'string' ? [id] : id
|
||||
|
||||
const slideIndex = this.slideIndex
|
||||
const slide = this.slides[slideIndex]
|
||||
const elements = slide.elements.map(el => {
|
||||
return elIdList.includes(el.id) ? { ...el, ...props } : el
|
||||
})
|
||||
this.slides[slideIndex].elements = (elements as PPTElement[])
|
||||
},
|
||||
|
||||
removeElementProps(data: RemoveElementPropData) {
|
||||
const { id, propName } = data
|
||||
const propsNames = typeof propName === 'string' ? [propName] : propName
|
||||
|
||||
const slideIndex = this.slideIndex
|
||||
const slide = this.slides[slideIndex]
|
||||
const elements = slide.elements.map(el => {
|
||||
return el.id === id ? omit(el, propsNames) : el
|
||||
})
|
||||
this.slides[slideIndex].elements = (elements as PPTElement[])
|
||||
},
|
||||
},
|
||||
})
|
137
src/store/snapshot.ts
Normal file
137
src/store/snapshot.ts
Normal file
@ -0,0 +1,137 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { IndexableTypeArray } from 'dexie'
|
||||
import { snapshotDB, Snapshot } from '@/utils/database'
|
||||
|
||||
import { useSlidesStore } from './slides'
|
||||
import { useMainStore } from './main'
|
||||
|
||||
export interface ScreenState {
|
||||
snapshotCursor: number;
|
||||
snapshotLength: number;
|
||||
}
|
||||
|
||||
export const useSnapshotStore = defineStore('snapshot', {
|
||||
state: (): ScreenState => ({
|
||||
snapshotCursor: -1, // 历史快照指针
|
||||
snapshotLength: 0, // 历史快照长度
|
||||
}),
|
||||
|
||||
getters: {
|
||||
canUndo(state) {
|
||||
return state.snapshotCursor > 0
|
||||
},
|
||||
canRedo(state) {
|
||||
return state.snapshotCursor < state.snapshotLength - 1
|
||||
},
|
||||
},
|
||||
|
||||
actions: {
|
||||
setSnapshotCursor(cursor: number) {
|
||||
this.snapshotCursor = cursor
|
||||
},
|
||||
setSnapshotLength(length: number) {
|
||||
this.snapshotLength = length
|
||||
},
|
||||
|
||||
async initSnapshotDatabase() {
|
||||
const slidesStore = useSlidesStore()
|
||||
|
||||
const snapshots: Snapshot[] = await snapshotDB.snapshots.orderBy('id').toArray()
|
||||
const lastSnapshot = snapshots.slice(-1)[0]
|
||||
|
||||
if (lastSnapshot) {
|
||||
snapshotDB.snapshots.clear()
|
||||
}
|
||||
|
||||
const newFirstSnapshot = {
|
||||
index: slidesStore.slideIndex,
|
||||
slides: slidesStore.slides,
|
||||
}
|
||||
await snapshotDB.snapshots.add(newFirstSnapshot)
|
||||
this.setSnapshotCursor(0)
|
||||
this.setSnapshotLength(1)
|
||||
},
|
||||
|
||||
async addSnapshot() {
|
||||
const slidesStore = useSlidesStore()
|
||||
|
||||
// 获取当前indexeddb中全部快照的ID
|
||||
const allKeys = await snapshotDB.snapshots.orderBy('id').keys()
|
||||
|
||||
let needDeleteKeys: IndexableTypeArray = []
|
||||
|
||||
// 记录需要删除的快照ID
|
||||
// 若当前快照指针不处在最后一位,那么再添加快照时,应该将当前指针位置后面的快照全部删除,对应的实际情况是:
|
||||
// 用户撤回多次后,再进行操作(添加快照),此时原先被撤销的快照都应该被删除
|
||||
if (this.snapshotCursor >= 0 && this.snapshotCursor < allKeys.length - 1) {
|
||||
needDeleteKeys = allKeys.slice(this.snapshotCursor + 1)
|
||||
}
|
||||
|
||||
// 添加新快照
|
||||
const snapshot = {
|
||||
index: slidesStore.slideIndex,
|
||||
slides: slidesStore.slides,
|
||||
}
|
||||
await snapshotDB.snapshots.add(snapshot)
|
||||
|
||||
// 计算当前快照长度,用于设置快照指针的位置(此时指针应该处在最后一位,即:快照长度 - 1)
|
||||
let snapshotLength = allKeys.length - needDeleteKeys.length + 1
|
||||
|
||||
// 快照数量超过长度限制时,应该将头部多余的快照删除
|
||||
const snapshotLengthLimit = 20
|
||||
if (snapshotLength > snapshotLengthLimit) {
|
||||
needDeleteKeys.push(allKeys[0])
|
||||
snapshotLength--
|
||||
}
|
||||
|
||||
// 快照数大于1时,需要保证撤回操作后维持页面焦点不变:也就是将倒数第二个快照对应的索引设置为当前页的索引
|
||||
// https://github.com/pipipi-pikachu/PPTist/issues/27
|
||||
if (snapshotLength >= 2) {
|
||||
snapshotDB.snapshots.update(allKeys[snapshotLength - 2] as number, { index: slidesStore.slideIndex })
|
||||
}
|
||||
|
||||
await snapshotDB.snapshots.bulkDelete(needDeleteKeys)
|
||||
|
||||
this.setSnapshotCursor(snapshotLength - 1)
|
||||
this.setSnapshotLength(snapshotLength)
|
||||
},
|
||||
|
||||
async unDo() {
|
||||
if (this.snapshotCursor <= 0) return
|
||||
|
||||
const slidesStore = useSlidesStore()
|
||||
const mainStore = useMainStore()
|
||||
|
||||
const snapshotCursor = this.snapshotCursor - 1
|
||||
const snapshots: Snapshot[] = await snapshotDB.snapshots.orderBy('id').toArray()
|
||||
const snapshot = snapshots[snapshotCursor]
|
||||
const { index, slides } = snapshot
|
||||
|
||||
const slideIndex = index > slides.length - 1 ? slides.length - 1 : index
|
||||
|
||||
slidesStore.setSlides(slides)
|
||||
slidesStore.updateSlideIndex(slideIndex)
|
||||
this.setSnapshotCursor(snapshotCursor)
|
||||
mainStore.setActiveElementIdList([])
|
||||
},
|
||||
|
||||
async reDo() {
|
||||
if (this.snapshotCursor >= this.snapshotLength - 1) return
|
||||
|
||||
const slidesStore = useSlidesStore()
|
||||
const mainStore = useMainStore()
|
||||
|
||||
const snapshotCursor = this.snapshotCursor + 1
|
||||
const snapshots: Snapshot[] = await snapshotDB.snapshots.orderBy('id').toArray()
|
||||
const snapshot = snapshots[snapshotCursor]
|
||||
const { index, slides } = snapshot
|
||||
|
||||
const slideIndex = index > slides.length - 1 ? slides.length - 1 : index
|
||||
|
||||
slidesStore.setSlides(slides)
|
||||
slidesStore.updateSlideIndex(slideIndex)
|
||||
this.setSnapshotCursor(snapshotCursor)
|
||||
mainStore.setActiveElementIdList([])
|
||||
},
|
||||
},
|
||||
})
|
@ -1,67 +0,0 @@
|
||||
import { Slide, SlideTheme } from '@/types/slides'
|
||||
import { CreatingElement } from '@/types/edit'
|
||||
import { ToolbarState } from '@/types/toolbar'
|
||||
import { slides } from '@/mocks/slides'
|
||||
import { theme } from '@/mocks/theme'
|
||||
import { SYS_FONTS } from '@/configs/font'
|
||||
import { TextAttrs, defaultRichTextAttrs } from '@/utils/prosemirror/utils'
|
||||
|
||||
export interface State {
|
||||
activeElementIdList: string[];
|
||||
handleElementId: string;
|
||||
activeGroupElementId: string;
|
||||
canvasPercentage: number;
|
||||
canvasScale: number;
|
||||
thumbnailsFocus: boolean;
|
||||
editorAreaFocus: boolean;
|
||||
disableHotkeys: boolean;
|
||||
showGridLines: boolean;
|
||||
creatingElement: CreatingElement | null;
|
||||
availableFonts: typeof SYS_FONTS;
|
||||
toolbarState: ToolbarState;
|
||||
theme: SlideTheme;
|
||||
viewportRatio: number;
|
||||
slides: Slide[];
|
||||
slideIndex: number;
|
||||
selectedSlidesIndex: number[];
|
||||
snapshotCursor: number;
|
||||
snapshotLength: number;
|
||||
ctrlKeyState: boolean;
|
||||
shiftKeyState: boolean;
|
||||
screening: boolean;
|
||||
clipingImageElementId: string;
|
||||
richTextAttrs: TextAttrs;
|
||||
selectedTableCells: string[];
|
||||
isScaling: boolean;
|
||||
editingShapeElementId: string;
|
||||
}
|
||||
|
||||
export const state: State = {
|
||||
activeElementIdList: [], // 被选中的元素ID集合,包含 handleElementId
|
||||
handleElementId: '', // 正在操作的元素ID
|
||||
activeGroupElementId: '', // 组合元素成员中,被选中可独立操作的元素ID
|
||||
canvasPercentage: 90, // 画布可视区域百分比
|
||||
canvasScale: 1, // 画布缩放比例(基于宽度1000px)
|
||||
thumbnailsFocus: false, // 左侧导航缩略图区域聚焦
|
||||
editorAreaFocus: false, // 编辑区域聚焦
|
||||
disableHotkeys: false, // 禁用快捷键
|
||||
showGridLines: false, // 显示网格线
|
||||
creatingElement: null, // 正在插入的元素信息,需要绘制插入的元素需要(文字、形状、线条)
|
||||
availableFonts: [], // 当前环境可用字体
|
||||
toolbarState: 'slideDesign', // 右侧工具栏状态
|
||||
viewportRatio: 0.5625, // 可是区域比例,默认16:9
|
||||
theme: theme, // 主题样式
|
||||
slides: slides, // 幻灯片页面数据
|
||||
slideIndex: 0, // 当前页面索引
|
||||
selectedSlidesIndex: [], // 当前被选中的页面索引集合
|
||||
snapshotCursor: -1, // 历史快照指针
|
||||
snapshotLength: 0, // 历史快照长度
|
||||
ctrlKeyState: false, // ctrl键按下状态
|
||||
shiftKeyState: false, // shift键按下状态
|
||||
screening: false, // 是否进入放映状态
|
||||
clipingImageElementId: '', // 当前正在裁剪的图片ID
|
||||
richTextAttrs: defaultRichTextAttrs, // 富文本状态
|
||||
selectedTableCells: [], // 选中的表格单元格
|
||||
isScaling: false, // 正在进行元素缩放
|
||||
editingShapeElementId: '', // 当前正处在编辑文字状态的形状ID
|
||||
}
|
@ -545,6 +545,9 @@ export interface SlideBackground {
|
||||
gradientRotate?: number;
|
||||
}
|
||||
|
||||
|
||||
export type TurningMode = 'no' | 'fade' | 'slideX' | 'slideY'
|
||||
|
||||
/**
|
||||
* 幻灯片页面
|
||||
*
|
||||
@ -566,7 +569,7 @@ export interface Slide {
|
||||
remark?: string;
|
||||
background?: SlideBackground;
|
||||
animations?: PPTAnimation[];
|
||||
turningMode?: 'no' | 'fade' | 'slideX' | 'slideY';
|
||||
turningMode?: TurningMode;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,11 +1,11 @@
|
||||
export type ToolbarState = 'symbol' | 'elAnimation' | 'elStyle' | 'elPosition' | 'slideDesign' | 'slideAnimation' | 'multiPosition'
|
||||
|
||||
export const ToolbarStates = {
|
||||
SYMBOL: 'symbol',
|
||||
EL_ANIMATION: 'elAnimation',
|
||||
EL_STYLE: 'elStyle',
|
||||
EL_POSITION: 'elPosition',
|
||||
SLIDE_DESIGN: 'slideDesign',
|
||||
SLIDE_ANIMATION: 'slideAnimation',
|
||||
MULTI_POSITION: 'multiPosition',
|
||||
export const enum ToolbarStates {
|
||||
SYMBOL = 'symbol',
|
||||
EL_ANIMATION = 'elAnimation',
|
||||
EL_STYLE = 'elStyle',
|
||||
EL_POSITION = 'elPosition',
|
||||
SLIDE_DESIGN = 'slideDesign',
|
||||
SLIDE_ANIMATION = 'slideAnimation',
|
||||
MULTI_POSITION = 'multiPosition',
|
||||
}
|
@ -6,7 +6,8 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, PropType, defineComponent } from 'vue'
|
||||
import { useStore } from '@/store'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useMainStore } from '@/store'
|
||||
import { AlignmentLineAxis } from '@/types/edit'
|
||||
|
||||
export default defineComponent({
|
||||
@ -26,8 +27,7 @@ export default defineComponent({
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const store = useStore()
|
||||
const canvasScale = computed(() => store.state.canvasScale)
|
||||
const { canvasScale } = storeToRefs(useMainStore())
|
||||
|
||||
// 吸附对齐线的位置
|
||||
const left = computed(() => props.axis.x * canvasScale.value + 'px')
|
||||
|
@ -30,15 +30,16 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, onMounted, reactive, ref } from 'vue'
|
||||
import { MutationTypes, useStore } from '@/store'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useMainStore, useKeyboardStore } from '@/store'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'element-create-selection',
|
||||
emits: ['created'],
|
||||
setup(props, { emit }) {
|
||||
const store = useStore()
|
||||
const ctrlOrShiftKeyActive = computed<boolean>(() => store.getters.ctrlOrShiftKeyActive)
|
||||
const creatingElement = computed(() => store.state.creatingElement)
|
||||
const mainStore = useMainStore()
|
||||
const { creatingElement } = storeToRefs(mainStore)
|
||||
const { ctrlOrShiftKeyActive } = storeToRefs(useKeyboardStore())
|
||||
|
||||
const start = ref<[number, number]>()
|
||||
const end = ref<[number, number]>()
|
||||
@ -107,7 +108,7 @@ export default defineComponent({
|
||||
document.onmouseup = null
|
||||
|
||||
if (e.button === 2) {
|
||||
setTimeout(() => store.commit(MutationTypes.SET_CREATING_ELEMENT, null), 0)
|
||||
setTimeout(() => mainStore.setCreatingElement(null), 0)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -16,17 +16,18 @@
|
||||
<script lang="ts">
|
||||
import { defineComponent, computed } from 'vue'
|
||||
import tinycolor from 'tinycolor2'
|
||||
import { useStore } from '@/store'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useMainStore, useSlidesStore } from '@/store'
|
||||
import { VIEWPORT_SIZE } from '@/configs/canvas'
|
||||
import { SlideBackground } from '@/types/slides'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'grid-lines',
|
||||
setup() {
|
||||
const store = useStore()
|
||||
const canvasScale = computed(() => store.state.canvasScale)
|
||||
const viewportRatio = computed(() => store.state.viewportRatio)
|
||||
const background = computed<SlideBackground | undefined>(() => store.getters.currentSlide?.background)
|
||||
const { canvasScale } = storeToRefs(useMainStore())
|
||||
const { currentSlide, viewportRatio } = storeToRefs(useSlidesStore())
|
||||
|
||||
const background = computed<SlideBackground | undefined>(() => currentSlide.value?.background)
|
||||
|
||||
// 计算网格线的颜色,避免与背景的颜色太接近
|
||||
const gridColor = computed(() => {
|
||||
|
@ -10,17 +10,16 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, onMounted, ref } from 'vue'
|
||||
import { useStore } from '@/store'
|
||||
import { PPTElement } from '@/types/slides'
|
||||
import { defineComponent, onMounted, ref } from 'vue'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useMainStore } from '@/store'
|
||||
import useLink from '@/hooks/useLink'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'link-dialog',
|
||||
emits: ['close'],
|
||||
setup(props, { emit }) {
|
||||
const store = useStore()
|
||||
const handleElement = computed<PPTElement | null>(() => store.getters.handleElement)
|
||||
const { handleElement } = storeToRefs(useMainStore())
|
||||
|
||||
const link = ref('')
|
||||
|
||||
|
@ -28,8 +28,8 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, PropType } from 'vue'
|
||||
import { useStore } from '@/store'
|
||||
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useMainStore } from '@/store'
|
||||
import { PPTShapeElement, PPTVideoElement, PPTLatexElement } from '@/types/slides'
|
||||
import { OperateResizeHandler } from '@/types/edit'
|
||||
import useCommonOperate from '../hooks/useCommonOperate'
|
||||
@ -67,8 +67,7 @@ export default defineComponent({
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const store = useStore()
|
||||
const canvasScale = computed(() => store.state.canvasScale)
|
||||
const { canvasScale } = storeToRefs(useMainStore())
|
||||
|
||||
const scaleWidth = computed(() => props.elementInfo.width * canvasScale.value)
|
||||
const scaleHeight = computed(() => props.elementInfo.height * canvasScale.value)
|
||||
|
@ -28,7 +28,8 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, PropType } from 'vue'
|
||||
import { useStore } from '@/store'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useMainStore } from '@/store'
|
||||
import { PPTImageElement } from '@/types/slides'
|
||||
import { OperateResizeHandler } from '@/types/edit'
|
||||
import useCommonOperate from '../hooks/useCommonOperate'
|
||||
@ -64,9 +65,8 @@ export default defineComponent({
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const store = useStore()
|
||||
const canvasScale = computed(() => store.state.canvasScale)
|
||||
const clipingImageElementId = computed(() => store.state.clipingImageElementId)
|
||||
const { canvasScale, clipingImageElementId } = storeToRefs(useMainStore())
|
||||
|
||||
const isCliping = computed(() => clipingImageElementId.value === props.elementInfo.id)
|
||||
|
||||
const scaleWidth = computed(() => props.elementInfo.width * canvasScale.value)
|
||||
|
@ -15,8 +15,8 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, PropType } from 'vue'
|
||||
import { useStore } from '@/store'
|
||||
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useMainStore } from '@/store'
|
||||
import { PPTLineElement } from '@/types/slides'
|
||||
import { OperateLineHandler, OperateLineHandlers } from '@/types/edit'
|
||||
|
||||
@ -43,8 +43,7 @@ export default defineComponent({
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const store = useStore()
|
||||
const canvasScale = computed(() => store.state.canvasScale)
|
||||
const { canvasScale } = storeToRefs(useMainStore())
|
||||
|
||||
const resizeHandlers = computed(() => {
|
||||
const handlers = [
|
||||
|
@ -10,8 +10,9 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, PropType } from 'vue'
|
||||
import { useStore } from '@/store'
|
||||
import { defineComponent, PropType } from 'vue'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useMainStore } from '@/store'
|
||||
import { PPTElement } from '@/types/slides'
|
||||
import useLink from '@/hooks/useLink'
|
||||
|
||||
@ -28,8 +29,7 @@ export default defineComponent({
|
||||
},
|
||||
},
|
||||
setup() {
|
||||
const store = useStore()
|
||||
const canvasScale = computed(() => store.state.canvasScale)
|
||||
const { canvasScale } = storeToRefs(useMainStore())
|
||||
|
||||
const { removeLink } = useLink()
|
||||
|
||||
|
@ -22,7 +22,8 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, reactive, PropType, watchEffect, toRefs } from 'vue'
|
||||
import { useStore } from '@/store'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useMainStore } from '@/store'
|
||||
import { PPTElement } from '@/types/slides'
|
||||
import { getElementListRange } from '@/utils/element'
|
||||
import { OperateResizeHandler, MultiSelectRange } from '@/types/edit'
|
||||
@ -48,9 +49,8 @@ export default defineComponent({
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const store = useStore()
|
||||
const activeElementIdList = computed(() => store.state.activeElementIdList)
|
||||
const canvasScale = computed(() => store.state.canvasScale)
|
||||
const { activeElementIdList, canvasScale } = storeToRefs(useMainStore())
|
||||
|
||||
const localActiveElementList = computed(() => props.elementList.filter(el => activeElementIdList.value.includes(el.id)))
|
||||
|
||||
const range = reactive({
|
||||
|
@ -28,8 +28,8 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, PropType } from 'vue'
|
||||
import { useStore } from '@/store'
|
||||
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useMainStore } from '@/store'
|
||||
import { PPTShapeElement } from '@/types/slides'
|
||||
import { OperateResizeHandler } from '@/types/edit'
|
||||
import useCommonOperate from '../hooks/useCommonOperate'
|
||||
@ -65,8 +65,7 @@ export default defineComponent({
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const store = useStore()
|
||||
const canvasScale = computed(() => store.state.canvasScale)
|
||||
const { canvasScale } = storeToRefs(useMainStore())
|
||||
|
||||
const scaleWidth = computed(() => props.elementInfo.width * canvasScale.value)
|
||||
const scaleHeight = computed(() => props.elementInfo.height * canvasScale.value)
|
||||
|
@ -28,8 +28,8 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, PropType } from 'vue'
|
||||
import { useStore } from '@/store'
|
||||
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useMainStore } from '@/store'
|
||||
import { PPTTableElement } from '@/types/slides'
|
||||
import { OperateResizeHandler } from '@/types/edit'
|
||||
import useCommonOperate from '../hooks/useCommonOperate'
|
||||
@ -65,8 +65,7 @@ export default defineComponent({
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const store = useStore()
|
||||
const canvasScale = computed(() => store.state.canvasScale)
|
||||
const { canvasScale } = storeToRefs(useMainStore())
|
||||
|
||||
const outlineWidth = computed(() => props.elementInfo.outline.width || 1)
|
||||
|
||||
|
@ -28,8 +28,8 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, PropType } from 'vue'
|
||||
import { useStore } from '@/store'
|
||||
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useMainStore } from '@/store'
|
||||
import { PPTTextElement } from '@/types/slides'
|
||||
import { OperateResizeHandler } from '@/types/edit'
|
||||
import useCommonOperate from '../hooks/useCommonOperate'
|
||||
@ -65,8 +65,7 @@ export default defineComponent({
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const store = useStore()
|
||||
const canvasScale = computed(() => store.state.canvasScale)
|
||||
const { canvasScale } = storeToRefs(useMainStore())
|
||||
|
||||
const scaleWidth = computed(() => props.elementInfo.width * canvasScale.value)
|
||||
const scaleHeight = computed(() => props.elementInfo.height * canvasScale.value)
|
||||
|
@ -37,8 +37,9 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, PropType, computed } from 'vue'
|
||||
import { useStore } from '@/store'
|
||||
import { ElementTypes, PPTElement, Slide } from '@/types/slides'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useMainStore, useSlidesStore } from '@/store'
|
||||
import { ElementTypes, PPTElement } from '@/types/slides'
|
||||
import { OperateLineHandler, OperateResizeHandler } from '@/types/edit'
|
||||
|
||||
import ImageElementOperate from './ImageElementOperate.vue'
|
||||
@ -93,10 +94,8 @@ export default defineComponent({
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const store = useStore()
|
||||
const canvasScale = computed(() => store.state.canvasScale)
|
||||
const toolbarState = computed(() => store.state.toolbarState)
|
||||
const currentSlide = computed<Slide>(() => store.getters.currentSlide)
|
||||
const { canvasScale, toolbarState } = storeToRefs(useMainStore())
|
||||
const { currentSlide } = storeToRefs(useSlidesStore())
|
||||
|
||||
const currentOperateComponent = computed(() => {
|
||||
const elementTypeMap = {
|
||||
|
@ -9,7 +9,8 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent } from 'vue'
|
||||
import { useStore } from '@/store'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useMainStore, useSlidesStore } from '@/store'
|
||||
import { SlideBackground } from '@/types/slides'
|
||||
import GridLines from './GridLines.vue'
|
||||
import useSlideBackgroundStyle from '@/hooks/useSlideBackgroundStyle'
|
||||
@ -20,9 +21,9 @@ export default defineComponent({
|
||||
GridLines,
|
||||
},
|
||||
setup() {
|
||||
const store = useStore()
|
||||
const showGridLines = computed(() => store.state.showGridLines)
|
||||
const background = computed<SlideBackground | undefined>(() => store.getters.currentSlide?.background)
|
||||
const { showGridLines } = storeToRefs(useMainStore())
|
||||
const { currentSlide } = storeToRefs(useSlidesStore())
|
||||
const background = computed<SlideBackground | undefined>(() => currentSlide.value?.background)
|
||||
|
||||
const { backgroundStyle } = useSlideBackgroundStyle(background)
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { Ref, computed } from 'vue'
|
||||
import { MutationTypes, useStore } from '@/store'
|
||||
import { Ref } from 'vue'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useMainStore, useSlidesStore } from '@/store'
|
||||
import { PPTElement } from '@/types/slides'
|
||||
import { AlignmentLineProps } from '@/types/edit'
|
||||
import { VIEWPORT_SIZE } from '@/configs/canvas'
|
||||
@ -10,11 +11,9 @@ export default (
|
||||
elementList: Ref<PPTElement[]>,
|
||||
alignmentLines: Ref<AlignmentLineProps[]>,
|
||||
) => {
|
||||
const store = useStore()
|
||||
const activeElementIdList = computed(() => store.state.activeElementIdList)
|
||||
const activeGroupElementId = computed(() => store.state.activeGroupElementId)
|
||||
const canvasScale = computed(() => store.state.canvasScale)
|
||||
const viewportRatio = computed(() => store.state.viewportRatio)
|
||||
const slidesStore = useSlidesStore()
|
||||
const { activeElementIdList, activeGroupElementId, canvasScale } = storeToRefs(useMainStore())
|
||||
const { viewportRatio } = storeToRefs(slidesStore)
|
||||
|
||||
const { addHistorySnapshot } = useHistorySnapshot()
|
||||
|
||||
@ -296,7 +295,7 @@ export default (
|
||||
|
||||
if (startPageX === currentPageX && startPageY === currentPageY) return
|
||||
|
||||
store.commit(MutationTypes.UPDATE_SLIDE, { elements: elementList.value })
|
||||
slidesStore.updateSlide({ elements: elementList.value })
|
||||
addHistorySnapshot()
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { Ref, computed } from 'vue'
|
||||
import { MutationTypes, useStore } from '@/store'
|
||||
import { Ref } from 'vue'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useMainStore, useSlidesStore } from '@/store'
|
||||
import { PPTElement, PPTLineElement } from '@/types/slides'
|
||||
import { OperateLineHandler, OperateLineHandlers } from '@/types/edit'
|
||||
import useHistorySnapshot from '@/hooks/useHistorySnapshot'
|
||||
@ -10,8 +11,8 @@ interface AdsorptionPoint {
|
||||
}
|
||||
|
||||
export default (elementList: Ref<PPTElement[]>) => {
|
||||
const store = useStore()
|
||||
const canvasScale = computed(() => store.state.canvasScale)
|
||||
const slidesStore = useSlidesStore()
|
||||
const { canvasScale } = storeToRefs(useMainStore())
|
||||
|
||||
const { addHistorySnapshot } = useHistorySnapshot()
|
||||
|
||||
@ -180,7 +181,7 @@ export default (elementList: Ref<PPTElement[]>) => {
|
||||
|
||||
if (startPageX === currentPageX && startPageY === currentPageY) return
|
||||
|
||||
store.commit(MutationTypes.UPDATE_SLIDE, { elements: elementList.value })
|
||||
slidesStore.updateSlide({ elements: elementList.value })
|
||||
addHistorySnapshot()
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,12 @@
|
||||
import { computed, onMounted, onUnmounted, Ref } from 'vue'
|
||||
import { useStore } from '@/store'
|
||||
import { onMounted, onUnmounted, Ref } from 'vue'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useMainStore } from '@/store'
|
||||
import { getImageDataURL } from '@/utils/image'
|
||||
import { parseText2Paragraphs } from '@/utils/textParser'
|
||||
import useCreateElement from '@/hooks/useCreateElement'
|
||||
|
||||
export default (elementRef: Ref<HTMLElement | undefined>) => {
|
||||
const store = useStore()
|
||||
const disableHotkeys = computed(() => store.state.disableHotkeys)
|
||||
const { disableHotkeys } = storeToRefs(useMainStore())
|
||||
|
||||
const { createImageElement, createTextElement } = useCreateElement()
|
||||
|
||||
|
@ -1,12 +1,12 @@
|
||||
import { computed, Ref } from 'vue'
|
||||
import { MutationTypes, useStore } from '@/store'
|
||||
import { Ref } from 'vue'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useMainStore } from '@/store'
|
||||
import { CreateElementSelectionData, CreatingLineElement, CreatingShapeElement } from '@/types/edit'
|
||||
import useCreateElement from '@/hooks/useCreateElement'
|
||||
|
||||
export default (viewportRef: Ref<HTMLElement | undefined>) => {
|
||||
const store = useStore()
|
||||
const canvasScale = computed(() => store.state.canvasScale)
|
||||
const creatingElement = computed(() => store.state.creatingElement)
|
||||
const mainStore = useMainStore()
|
||||
const { canvasScale, creatingElement } = storeToRefs(mainStore)
|
||||
|
||||
// 通过鼠标框选时的起点和终点,计算选区的位置大小
|
||||
const formatCreateSelection = (selectionData: CreateElementSelectionData) => {
|
||||
@ -85,7 +85,7 @@ export default (viewportRef: Ref<HTMLElement | undefined>) => {
|
||||
const position = formatCreateSelectionForLine(selectionData)
|
||||
position && createLineElement(position, (creatingElement.value as CreatingLineElement).data)
|
||||
}
|
||||
store.commit(MutationTypes.SET_CREATING_ELEMENT, null)
|
||||
mainStore.setCreatingElement(null)
|
||||
}
|
||||
|
||||
return {
|
||||
|
@ -1,11 +1,12 @@
|
||||
import { Ref, reactive, computed } from 'vue'
|
||||
import { MutationTypes, useStore } from '@/store'
|
||||
import { Ref, reactive } from 'vue'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useMainStore } from '@/store'
|
||||
import { PPTElement } from '@/types/slides'
|
||||
import { getElementRange } from '@/utils/element'
|
||||
|
||||
export default (elementList: Ref<PPTElement[]>, viewportRef: Ref<HTMLElement | undefined>) => {
|
||||
const store = useStore()
|
||||
const canvasScale = computed(() => store.state.canvasScale)
|
||||
const mainStore = useMainStore()
|
||||
const { canvasScale } = storeToRefs(mainStore)
|
||||
|
||||
const mouseSelectionState = reactive({
|
||||
isShow: false,
|
||||
@ -127,7 +128,7 @@ export default (elementList: Ref<PPTElement[]>, viewportRef: Ref<HTMLElement | u
|
||||
return true
|
||||
})
|
||||
const inRangeElementIdList = inRangeElementList.map(inRangeElement => inRangeElement.id)
|
||||
if (inRangeElementIdList.length) store.commit(MutationTypes.SET_ACTIVE_ELEMENT_ID_LIST, inRangeElementIdList)
|
||||
mainStore.setActiveElementIdList(inRangeElementIdList)
|
||||
|
||||
mouseSelectionState.isShow = false
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { Ref, computed } from 'vue'
|
||||
import { MutationTypes, useStore } from '@/store'
|
||||
import { Ref } from 'vue'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useMainStore, useSlidesStore } from '@/store'
|
||||
import { PPTElement, PPTTextElement, PPTImageElement, PPTShapeElement } from '@/types/slides'
|
||||
import useHistorySnapshot from '@/hooks/useHistorySnapshot'
|
||||
|
||||
@ -15,8 +16,8 @@ const getAngleFromCoordinate = (x: number, y: number) => {
|
||||
}
|
||||
|
||||
export default (elementList: Ref<PPTElement[]>, viewportRef: Ref<HTMLElement | undefined>) => {
|
||||
const store = useStore()
|
||||
const canvasScale = computed(() => store.state.canvasScale)
|
||||
const slidesStore = useSlidesStore()
|
||||
const { canvasScale } = storeToRefs(useMainStore())
|
||||
|
||||
const { addHistorySnapshot } = useHistorySnapshot()
|
||||
|
||||
@ -71,7 +72,7 @@ export default (elementList: Ref<PPTElement[]>, viewportRef: Ref<HTMLElement | u
|
||||
|
||||
if (elOriginRotate === angle) return
|
||||
|
||||
store.commit(MutationTypes.UPDATE_SLIDE, { elements: elementList.value })
|
||||
slidesStore.updateSlide({ elements: elementList.value })
|
||||
addHistorySnapshot()
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { computed, Ref } from 'vue'
|
||||
import { MutationTypes, useStore } from '@/store'
|
||||
import { Ref } from 'vue'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useMainStore, useSlidesStore, useKeyboardStore } from '@/store'
|
||||
import { PPTElement, PPTImageElement, PPTLineElement, PPTShapeElement } from '@/types/slides'
|
||||
import { OperateResizeHandlers, AlignmentLineProps, MultiSelectRange } from '@/types/edit'
|
||||
import { VIEWPORT_SIZE } from '@/configs/canvas'
|
||||
@ -95,19 +96,18 @@ export default (
|
||||
elementList: Ref<PPTElement[]>,
|
||||
alignmentLines: Ref<AlignmentLineProps[]>,
|
||||
) => {
|
||||
const store = useStore()
|
||||
const activeElementIdList = computed(() => store.state.activeElementIdList)
|
||||
const activeGroupElementId = computed(() => store.state.activeGroupElementId)
|
||||
const canvasScale = computed(() => store.state.canvasScale)
|
||||
const viewportRatio = computed(() => store.state.viewportRatio)
|
||||
const ctrlOrShiftKeyActive = computed<boolean>(() => store.getters.ctrlOrShiftKeyActive)
|
||||
const mainStore = useMainStore()
|
||||
const slidesStore = useSlidesStore()
|
||||
const { activeElementIdList, activeGroupElementId, canvasScale } = storeToRefs(mainStore)
|
||||
const { viewportRatio } = storeToRefs(slidesStore)
|
||||
const { ctrlOrShiftKeyActive } = storeToRefs(useKeyboardStore())
|
||||
|
||||
const { addHistorySnapshot } = useHistorySnapshot()
|
||||
|
||||
// 缩放元素
|
||||
const scaleElement = (e: MouseEvent, element: Exclude<PPTElement, PPTLineElement>, command: OperateResizeHandlers) => {
|
||||
let isMouseDown = true
|
||||
store.commit(MutationTypes.SET_SCALING_STATE, true)
|
||||
mainStore.setScalingState(true)
|
||||
|
||||
const elOriginLeft = element.left
|
||||
const elOriginTop = element.top
|
||||
@ -404,8 +404,8 @@ export default (
|
||||
|
||||
if (startPageX === e.pageX && startPageY === e.pageY) return
|
||||
|
||||
store.commit(MutationTypes.UPDATE_SLIDE, { elements: elementList.value })
|
||||
store.commit(MutationTypes.SET_SCALING_STATE, false)
|
||||
slidesStore.updateSlide({ elements: elementList.value })
|
||||
mainStore.setScalingState(false)
|
||||
|
||||
addHistorySnapshot()
|
||||
}
|
||||
@ -509,7 +509,7 @@ export default (
|
||||
|
||||
if (startPageX === e.pageX && startPageY === e.pageY) return
|
||||
|
||||
store.commit(MutationTypes.UPDATE_SLIDE, { elements: elementList.value })
|
||||
slidesStore.updateSlide({ elements: elementList.value })
|
||||
addHistorySnapshot()
|
||||
}
|
||||
}
|
||||
|
@ -1,23 +1,21 @@
|
||||
import { Ref, computed } from 'vue'
|
||||
import { Ref } from 'vue'
|
||||
import { uniq } from 'lodash'
|
||||
import { MutationTypes, useStore } from '@/store'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useMainStore, useKeyboardStore } from '@/store'
|
||||
import { PPTElement } from '@/types/slides'
|
||||
|
||||
export default (
|
||||
elementList: Ref<PPTElement[]>,
|
||||
moveElement: (e: MouseEvent, element: PPTElement) => void,
|
||||
) => {
|
||||
const store = useStore()
|
||||
const activeElementIdList = computed(() => store.state.activeElementIdList)
|
||||
const handleElementId = computed(() => store.state.handleElementId)
|
||||
const activeGroupElementId = computed(() => store.state.activeGroupElementId)
|
||||
const editorAreaFocus = computed(() => store.state.editorAreaFocus)
|
||||
const ctrlOrShiftKeyActive = computed<boolean>(() => store.getters.ctrlOrShiftKeyActive)
|
||||
const mainStore = useMainStore()
|
||||
const { activeElementIdList, activeGroupElementId, handleElementId, editorAreaFocus } = storeToRefs(mainStore)
|
||||
const { ctrlOrShiftKeyActive } = storeToRefs(useKeyboardStore())
|
||||
|
||||
// 选中元素
|
||||
// startMove 表示是否需要再选中操作后进入到开始移动的状态
|
||||
const selectElement = (e: MouseEvent, element: PPTElement, startMove = true) => {
|
||||
if (!editorAreaFocus.value) store.commit(MutationTypes.SET_EDITORAREA_FOCUS, true)
|
||||
if (!editorAreaFocus.value) mainStore.setEditorareaFocus(true)
|
||||
|
||||
// 如果目标元素当前未被选中,则将他设为选中状态
|
||||
// 此时如果按下Ctrl键或Shift键,则进入多选状态,将当前已选中的元素和目标元素一起设置为选中状态,否则仅将目标元素设置为选中状态
|
||||
@ -38,8 +36,8 @@ export default (
|
||||
newActiveIdList = [...newActiveIdList, ...groupMembersId]
|
||||
}
|
||||
|
||||
store.commit(MutationTypes.SET_ACTIVE_ELEMENT_ID_LIST, uniq(newActiveIdList))
|
||||
store.commit(MutationTypes.SET_HANDLE_ELEMENT_ID, element.id)
|
||||
mainStore.setActiveElementIdList(uniq(newActiveIdList))
|
||||
mainStore.setHandleElementId(element.id)
|
||||
}
|
||||
|
||||
// 如果目标元素已被选中,且按下了Ctrl键或Shift键,则取消其被选中状态
|
||||
@ -60,13 +58,13 @@ export default (
|
||||
}
|
||||
|
||||
if (newActiveIdList.length > 0) {
|
||||
store.commit(MutationTypes.SET_ACTIVE_ELEMENT_ID_LIST, newActiveIdList)
|
||||
mainStore.setActiveElementIdList(newActiveIdList)
|
||||
}
|
||||
}
|
||||
|
||||
// 如果目标元素已被选中,同时目标元素不是当前操作元素,则将其设置为当前操作元素
|
||||
else if (handleElementId.value !== element.id) {
|
||||
store.commit(MutationTypes.SET_HANDLE_ELEMENT_ID, element.id)
|
||||
mainStore.setHandleElementId(element.id)
|
||||
}
|
||||
|
||||
// 如果目标元素已被选中,同时也是当前操作元素,那么当目标元素在该状态下再次被点击时,将被设置为多选元素中的激活成员
|
||||
@ -79,7 +77,7 @@ export default (
|
||||
const currentPageY = e.pageY
|
||||
|
||||
if (startPageX === currentPageX && startPageY === currentPageY) {
|
||||
store.commit(MutationTypes.SET_ACTIVE_GROUP_ELEMENT_ID, element.id)
|
||||
mainStore.setActiveGroupElementId(element.id)
|
||||
;(e.target as HTMLElement).onmouseup = null
|
||||
}
|
||||
}
|
||||
@ -92,7 +90,7 @@ export default (
|
||||
const selectAllElement = () => {
|
||||
const unlockedElements = elementList.value.filter(el => !el.lock)
|
||||
const newActiveElementIdList = unlockedElements.map(el => el.id)
|
||||
store.commit(MutationTypes.SET_ACTIVE_ELEMENT_ID_LIST, newActiveElementIdList)
|
||||
mainStore.setActiveElementIdList(newActiveElementIdList)
|
||||
}
|
||||
|
||||
return {
|
||||
|
@ -1,14 +1,15 @@
|
||||
import { ref, computed, onMounted, onUnmounted, Ref, watch } from 'vue'
|
||||
import { MutationTypes, useStore } from '@/store'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useMainStore, useSlidesStore } from '@/store'
|
||||
import { VIEWPORT_SIZE } from '@/configs/canvas'
|
||||
|
||||
export default (canvasRef: Ref<HTMLElement | undefined>) => {
|
||||
const viewportLeft = ref(0)
|
||||
const viewportTop = ref(0)
|
||||
|
||||
const store = useStore()
|
||||
const canvasPercentage = computed(() => store.state.canvasPercentage)
|
||||
const viewportRatio = computed(() => store.state.viewportRatio)
|
||||
const mainStore = useMainStore()
|
||||
const { canvasPercentage } = storeToRefs(mainStore)
|
||||
const { viewportRatio } = storeToRefs(useSlidesStore())
|
||||
|
||||
// 计算画布可视区域的位置
|
||||
const setViewportPosition = () => {
|
||||
@ -18,13 +19,13 @@ export default (canvasRef: Ref<HTMLElement | undefined>) => {
|
||||
|
||||
if (canvasHeight / canvasWidth > viewportRatio.value) {
|
||||
const viewportActualWidth = canvasWidth * (canvasPercentage.value / 100)
|
||||
store.commit(MutationTypes.SET_CANVAS_SCALE, viewportActualWidth / VIEWPORT_SIZE)
|
||||
mainStore.setCanvasScale(viewportActualWidth / VIEWPORT_SIZE)
|
||||
viewportLeft.value = (canvasWidth - viewportActualWidth) / 2
|
||||
viewportTop.value = (canvasHeight - viewportActualWidth * viewportRatio.value) / 2
|
||||
}
|
||||
else {
|
||||
const viewportActualHeight = canvasHeight * (canvasPercentage.value / 100)
|
||||
store.commit(MutationTypes.SET_CANVAS_SCALE, viewportActualHeight / (VIEWPORT_SIZE * viewportRatio.value))
|
||||
mainStore.setCanvasScale(viewportActualHeight / (VIEWPORT_SIZE * viewportRatio.value))
|
||||
viewportLeft.value = (canvasWidth - viewportActualHeight / viewportRatio.value) / 2
|
||||
viewportTop.value = (canvasHeight - viewportActualHeight) / 2
|
||||
}
|
||||
|
@ -87,11 +87,12 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, provide, ref, watch, watchEffect } from 'vue'
|
||||
import { defineComponent, provide, ref, watch, watchEffect } from 'vue'
|
||||
import { throttle } from 'lodash'
|
||||
import { MutationTypes, useStore } from '@/store'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useMainStore, useSlidesStore, useKeyboardStore } from '@/store'
|
||||
import { ContextmenuItem } from '@/components/Contextmenu/types'
|
||||
import { PPTElement, Slide } from '@/types/slides'
|
||||
import { PPTElement } from '@/types/slides'
|
||||
import { AlignmentLineProps } from '@/types/edit'
|
||||
import { removeAllRanges } from '@/utils/selection'
|
||||
import { KEYS } from '@/configs/hotkey'
|
||||
@ -135,14 +136,18 @@ export default defineComponent({
|
||||
LinkDialog,
|
||||
},
|
||||
setup() {
|
||||
const store = useStore()
|
||||
|
||||
const activeElementIdList = computed(() => store.state.activeElementIdList)
|
||||
const handleElementId = computed(() => store.state.handleElementId)
|
||||
const activeGroupElementId = computed(() => store.state.activeGroupElementId)
|
||||
const editorAreaFocus = computed(() => store.state.editorAreaFocus)
|
||||
const ctrlKeyState = computed(() => store.state.ctrlKeyState)
|
||||
const ctrlOrShiftKeyActive = computed<boolean>(() => store.getters.ctrlOrShiftKeyActive)
|
||||
const mainStore = useMainStore()
|
||||
const {
|
||||
activeElementIdList,
|
||||
activeGroupElementId,
|
||||
handleElementId,
|
||||
editorAreaFocus,
|
||||
showGridLines,
|
||||
creatingElement,
|
||||
canvasScale,
|
||||
} = storeToRefs(mainStore)
|
||||
const { currentSlide } = storeToRefs(useSlidesStore())
|
||||
const { ctrlKeyState, ctrlOrShiftKeyActive } = storeToRefs(useKeyboardStore())
|
||||
|
||||
const viewportRef = ref<HTMLElement>()
|
||||
const alignmentLines = ref<AlignmentLineProps[]>([])
|
||||
@ -151,10 +156,9 @@ export default defineComponent({
|
||||
const openLinkDialog = () => linkDialogVisible.value = true
|
||||
|
||||
watch(handleElementId, () => {
|
||||
store.commit(MutationTypes.SET_ACTIVE_GROUP_ELEMENT_ID, '')
|
||||
mainStore.setActiveGroupElementId('')
|
||||
})
|
||||
|
||||
const currentSlide = computed<Slide>(() => store.getters.currentSlide)
|
||||
const elementList = ref<PPTElement[]>([])
|
||||
const setLocalElementList = () => {
|
||||
elementList.value = currentSlide.value ? JSON.parse(JSON.stringify(currentSlide.value.elements)) : []
|
||||
@ -162,7 +166,6 @@ export default defineComponent({
|
||||
watchEffect(setLocalElementList)
|
||||
|
||||
const canvasRef = ref<HTMLElement>()
|
||||
const canvasScale = computed(() => store.state.canvasScale)
|
||||
const { viewportStyles } = useViewportSize(canvasRef)
|
||||
|
||||
useDropImageOrText(canvasRef)
|
||||
@ -183,15 +186,15 @@ export default defineComponent({
|
||||
|
||||
// 点击画布的空白区域:清空焦点元素、设置画布焦点、清除文字选区
|
||||
const handleClickBlankArea = (e: MouseEvent) => {
|
||||
store.commit(MutationTypes.SET_ACTIVE_ELEMENT_ID_LIST, [])
|
||||
mainStore.setActiveElementIdList([])
|
||||
if (!ctrlOrShiftKeyActive.value) updateMouseSelection(e)
|
||||
if (!editorAreaFocus.value) store.commit(MutationTypes.SET_EDITORAREA_FOCUS, true)
|
||||
if (!editorAreaFocus.value) mainStore.setEditorareaFocus(true)
|
||||
removeAllRanges()
|
||||
}
|
||||
|
||||
// 移除画布编辑区域焦点
|
||||
const removeEditorAreaFocus = () => {
|
||||
if (editorAreaFocus.value) store.commit(MutationTypes.SET_EDITORAREA_FOCUS, false)
|
||||
if (editorAreaFocus.value) mainStore.setEditorareaFocus(false)
|
||||
}
|
||||
|
||||
// 滚动鼠标
|
||||
@ -215,13 +218,11 @@ export default defineComponent({
|
||||
}
|
||||
|
||||
// 开关网格线
|
||||
const showGridLines = computed(() => store.state.showGridLines)
|
||||
const toggleGridLines = () => {
|
||||
store.commit(MutationTypes.SET_GRID_LINES_STATE, !showGridLines.value)
|
||||
mainStore.setGridLinesState(!showGridLines.value)
|
||||
}
|
||||
|
||||
// 在鼠标绘制的范围插入元素
|
||||
const creatingElement = computed(() => store.state.creatingElement)
|
||||
const { insertElementFromCreateSelection } = useInsertFromCreateSelection(viewportRef)
|
||||
|
||||
const contextmenus = (): ContextmenuItem[] => {
|
||||
|
@ -95,7 +95,8 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, computed, ref } from 'vue'
|
||||
import { MutationTypes, useStore } from '@/store'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useMainStore, useSnapshotStore } from '@/store'
|
||||
import { getImageDataURL } from '@/utils/image'
|
||||
import { ShapePoolItem } from '@/configs/shapes'
|
||||
import { LinePoolItem } from '@/configs/lines'
|
||||
@ -121,10 +122,9 @@ export default defineComponent({
|
||||
LaTeXEditor,
|
||||
},
|
||||
setup() {
|
||||
const store = useStore()
|
||||
const canvasScale = computed(() => store.state.canvasScale)
|
||||
const canUndo = computed(() => store.getters.canUndo)
|
||||
const canRedo = computed(() => store.getters.canRedo)
|
||||
const mainStore = useMainStore()
|
||||
const { canvasScale } = storeToRefs(mainStore)
|
||||
const { canUndo, canRedo } = storeToRefs(useSnapshotStore())
|
||||
|
||||
const canvasScalePercentage = computed(() => parseInt(canvasScale.value * 100 + '') + '%')
|
||||
|
||||
@ -148,15 +148,14 @@ export default defineComponent({
|
||||
|
||||
// 绘制文字范围
|
||||
const drawText = () => {
|
||||
store.commit(MutationTypes.SET_CREATING_ELEMENT, {
|
||||
mainStore.setCreatingElement({
|
||||
type: 'text',
|
||||
data: null,
|
||||
})
|
||||
}
|
||||
|
||||
// 绘制形状范围
|
||||
const drawShape = (shape: ShapePoolItem) => {
|
||||
store.commit(MutationTypes.SET_CREATING_ELEMENT, {
|
||||
mainStore.setCreatingElement({
|
||||
type: 'shape',
|
||||
data: shape,
|
||||
})
|
||||
@ -165,7 +164,7 @@ export default defineComponent({
|
||||
|
||||
// 绘制线条路径
|
||||
const drawLine = (line: LinePoolItem) => {
|
||||
store.commit(MutationTypes.SET_CREATING_ELEMENT, {
|
||||
mainStore.setCreatingElement({
|
||||
type: 'line',
|
||||
data: line,
|
||||
})
|
||||
|
@ -68,8 +68,9 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, ref } from 'vue'
|
||||
import { MutationTypes, useStore } from '@/store'
|
||||
import { defineComponent, ref } from 'vue'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useMainStore } from '@/store'
|
||||
import useScreening from '@/hooks/useScreening'
|
||||
import useSlideHandler from '@/hooks/useSlideHandler'
|
||||
import useHistorySnapshot from '@/hooks/useHistorySnapshot'
|
||||
@ -83,16 +84,16 @@ export default defineComponent({
|
||||
HotkeyDoc,
|
||||
},
|
||||
setup() {
|
||||
const store = useStore()
|
||||
const mainStore = useMainStore()
|
||||
const { showGridLines } = storeToRefs(mainStore)
|
||||
|
||||
const { enterScreening, enterScreeningFromStart } = useScreening()
|
||||
const { createSlide, deleteSlide, resetSlides } = useSlideHandler()
|
||||
const { redo, undo } = useHistorySnapshot()
|
||||
const { exporting, exportJSON, exportPPTX } = useExport()
|
||||
|
||||
const showGridLines = computed(() => store.state.showGridLines)
|
||||
const toggleGridLines = () => {
|
||||
store.commit(MutationTypes.SET_GRID_LINES_STATE, !showGridLines.value)
|
||||
mainStore.setGridLinesState(!showGridLines.value)
|
||||
}
|
||||
|
||||
const hotkeyDrawerVisible = ref(false)
|
||||
|
@ -14,8 +14,8 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent } from 'vue'
|
||||
import { MutationTypes, useStore } from '@/store'
|
||||
import { Slide } from '@/types/slides'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useSlidesStore } from '@/store'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'remark',
|
||||
@ -27,13 +27,14 @@ export default defineComponent({
|
||||
},
|
||||
},
|
||||
setup(props, { emit }) {
|
||||
const store = useStore()
|
||||
const currentSlide = computed<Slide>(() => store.getters.currentSlide)
|
||||
const slidesStore = useSlidesStore()
|
||||
const { currentSlide } = storeToRefs(slidesStore)
|
||||
|
||||
const remark = computed(() => currentSlide.value?.remark || '')
|
||||
|
||||
const handleInput = (e: InputEvent) => {
|
||||
const value = (e.target as HTMLTextAreaElement).value
|
||||
store.commit(MutationTypes.UPDATE_SLIDE, { remark: value })
|
||||
slidesStore.updateSlide({ remark: value })
|
||||
}
|
||||
|
||||
const resize = (e: MouseEvent) => {
|
||||
|
@ -12,8 +12,9 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent } from 'vue'
|
||||
import { useStore } from '@/store'
|
||||
import { defineComponent } from 'vue'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useSlidesStore } from '@/store'
|
||||
import { Slide } from '@/types/slides'
|
||||
|
||||
import ThumbnailSlide from '@/views/components/ThumbnailSlide/index.vue'
|
||||
@ -25,8 +26,7 @@ export default defineComponent({
|
||||
ThumbnailSlide,
|
||||
},
|
||||
setup(props, { emit }) {
|
||||
const store = useStore()
|
||||
const layouts = computed<Slide[]>(() => store.getters.layouts)
|
||||
const { layouts } = storeToRefs(useSlidesStore())
|
||||
|
||||
const selectSlideTemplate = (slide: Slide) => {
|
||||
emit('select', slide)
|
||||
|
@ -45,7 +45,8 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, provide, ref } from 'vue'
|
||||
import { MutationTypes, useStore } from '@/store'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useMainStore, useSlidesStore, useKeyboardStore } from '@/store'
|
||||
import { fillDigit } from '@/utils/common'
|
||||
import { ContextmenuItem } from '@/components/Contextmenu/types'
|
||||
import { VIEWPORT_SIZE } from '@/configs/canvas'
|
||||
@ -64,12 +65,14 @@ export default defineComponent({
|
||||
LayoutPool,
|
||||
},
|
||||
setup() {
|
||||
const store = useStore()
|
||||
const slides = computed(() => store.state.slides)
|
||||
const slideIndex = computed(() => store.state.slideIndex)
|
||||
const ctrlKeyState = computed(() => store.state.ctrlKeyState)
|
||||
const shiftKeyState = computed(() => store.state.shiftKeyState)
|
||||
const selectedSlidesIndex = computed(() => [...store.state.selectedSlidesIndex, slideIndex.value])
|
||||
const mainStore = useMainStore()
|
||||
const slidesStore = useSlidesStore()
|
||||
const keyboardStore = useKeyboardStore()
|
||||
const { selectedSlidesIndex: _selectedSlidesIndex, thumbnailsFocus } = storeToRefs(mainStore)
|
||||
const { slides, slideIndex } = storeToRefs(slidesStore)
|
||||
const { ctrlKeyState, shiftKeyState } = storeToRefs(keyboardStore)
|
||||
|
||||
const selectedSlidesIndex = computed(() => [..._selectedSlidesIndex.value, slideIndex.value])
|
||||
|
||||
const presetLayoutPopoverVisible = ref(false)
|
||||
|
||||
@ -89,10 +92,10 @@ export default defineComponent({
|
||||
|
||||
// 切换页面
|
||||
const changSlideIndex = (index: number) => {
|
||||
store.commit(MutationTypes.SET_ACTIVE_ELEMENT_ID_LIST, [])
|
||||
mainStore.setActiveElementIdList([])
|
||||
|
||||
if (slideIndex.value === index) return
|
||||
store.commit(MutationTypes.UPDATE_SLIDE_INDEX, index)
|
||||
slidesStore.updateSlideIndex(index)
|
||||
}
|
||||
|
||||
// 点击缩略图
|
||||
@ -107,17 +110,17 @@ export default defineComponent({
|
||||
if (!isMultiSelected) return
|
||||
|
||||
const newSelectedSlidesIndex = selectedSlidesIndex.value.filter(item => item !== index)
|
||||
store.commit(MutationTypes.UPDATE_SELECTED_SLIDES_INDEX, newSelectedSlidesIndex)
|
||||
mainStore.updateSelectedSlidesIndex(newSelectedSlidesIndex)
|
||||
changSlideIndex(selectedSlidesIndex.value[0])
|
||||
}
|
||||
else {
|
||||
if (selectedSlidesIndex.value.includes(index)) {
|
||||
const newSelectedSlidesIndex = selectedSlidesIndex.value.filter(item => item !== index)
|
||||
store.commit(MutationTypes.UPDATE_SELECTED_SLIDES_INDEX, newSelectedSlidesIndex)
|
||||
mainStore.updateSelectedSlidesIndex(newSelectedSlidesIndex)
|
||||
}
|
||||
else {
|
||||
const newSelectedSlidesIndex = [...selectedSlidesIndex.value, index]
|
||||
store.commit(MutationTypes.UPDATE_SELECTED_SLIDES_INDEX, newSelectedSlidesIndex)
|
||||
mainStore.updateSelectedSlidesIndex(newSelectedSlidesIndex)
|
||||
changSlideIndex(index)
|
||||
}
|
||||
}
|
||||
@ -136,24 +139,22 @@ export default defineComponent({
|
||||
|
||||
const newSelectedSlidesIndex = []
|
||||
for (let i = minIndex; i <= maxIndex; i++) newSelectedSlidesIndex.push(i)
|
||||
store.commit(MutationTypes.UPDATE_SELECTED_SLIDES_INDEX, newSelectedSlidesIndex)
|
||||
mainStore.updateSelectedSlidesIndex(newSelectedSlidesIndex)
|
||||
changSlideIndex(index)
|
||||
}
|
||||
// 正常切换页面
|
||||
else {
|
||||
store.commit(MutationTypes.UPDATE_SELECTED_SLIDES_INDEX, [])
|
||||
mainStore.updateSelectedSlidesIndex([])
|
||||
changSlideIndex(index)
|
||||
}
|
||||
}
|
||||
|
||||
const thumbnailsFocus = computed(() => store.state.thumbnailsFocus)
|
||||
|
||||
// 设置缩略图工具栏聚焦状态(只有聚焦状态下,该部分的快捷键才能生效)
|
||||
const setThumbnailsFocus = (focus: boolean) => {
|
||||
if (thumbnailsFocus.value === focus) return
|
||||
store.commit(MutationTypes.SET_THUMBNAILS_FOCUS, focus)
|
||||
mainStore.setThumbnailsFocus(focus)
|
||||
|
||||
if (!focus) store.commit(MutationTypes.UPDATE_SELECTED_SLIDES_INDEX, [])
|
||||
if (!focus) mainStore.updateSelectedSlidesIndex([])
|
||||
}
|
||||
|
||||
// 拖拽调整顺序后进行数据的同步
|
||||
@ -165,8 +166,8 @@ export default defineComponent({
|
||||
const _slide = _slides[oldIndex]
|
||||
_slides.splice(oldIndex, 1)
|
||||
_slides.splice(newIndex, 0, _slide)
|
||||
store.commit(MutationTypes.SET_SLIDES, _slides)
|
||||
store.commit(MutationTypes.UPDATE_SLIDE_INDEX, newIndex)
|
||||
slidesStore.setSlides(_slides)
|
||||
slidesStore.updateSlideIndex(newIndex)
|
||||
}
|
||||
|
||||
const { enterScreening } = useScreening()
|
||||
|
@ -89,8 +89,9 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, ref } from 'vue'
|
||||
import { MutationTypes, useStore } from '@/store'
|
||||
import { PPTAnimation, PPTElement, Slide } from '@/types/slides'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useMainStore, useSlidesStore } from '@/store'
|
||||
import { PPTAnimation } from '@/types/slides'
|
||||
import { ANIMATIONS } from '@/configs/animation'
|
||||
import { ELEMENT_TYPE_ZH } from '@/configs/element'
|
||||
import useHistorySnapshot from '@/hooks/useHistorySnapshot'
|
||||
@ -112,10 +113,9 @@ export default defineComponent({
|
||||
Draggable,
|
||||
},
|
||||
setup() {
|
||||
const store = useStore()
|
||||
const handleElement = computed<PPTElement>(() => store.getters.handleElement)
|
||||
const currentSlideAnimations = computed<PPTAnimation[] | null>(() => store.getters.currentSlideAnimations)
|
||||
const currentSlide = computed<Slide>(() => store.getters.currentSlide)
|
||||
const slidesStore = useSlidesStore()
|
||||
const { handleElement, handleElementId } = storeToRefs(useMainStore())
|
||||
const { currentSlide, currentSlideAnimations } = storeToRefs(slidesStore)
|
||||
|
||||
const hoverPreviewAnimation = ref('')
|
||||
const animationPoolVisible = ref(false)
|
||||
@ -145,9 +145,8 @@ export default defineComponent({
|
||||
|
||||
// 当前选中元素的入场动画信息
|
||||
const handleElementAnimation = computed(() => {
|
||||
if (!handleElement.value) return null
|
||||
const animations = currentSlideAnimations.value || []
|
||||
const animation = animations.find(item => item.elId === handleElement.value.id)
|
||||
const animation = animations.find(item => item.elId === handleElementId.value)
|
||||
return animation || null
|
||||
})
|
||||
|
||||
@ -160,7 +159,7 @@ export default defineComponent({
|
||||
// 删除元素入场动画
|
||||
const deleteAnimation = (elId: string) => {
|
||||
const animations = (currentSlideAnimations.value as PPTAnimation[]).filter(item => item.elId !== elId)
|
||||
store.commit(MutationTypes.UPDATE_SLIDE, { animations })
|
||||
slidesStore.updateSlide({ animations })
|
||||
addHistorySnapshot()
|
||||
}
|
||||
|
||||
@ -174,7 +173,7 @@ export default defineComponent({
|
||||
animations.splice(oldIndex, 1)
|
||||
animations.splice(newIndex, 0, animation)
|
||||
|
||||
store.commit(MutationTypes.UPDATE_SLIDE, { animations })
|
||||
slidesStore.updateSlide({ animations })
|
||||
addHistorySnapshot()
|
||||
}
|
||||
|
||||
@ -200,17 +199,17 @@ export default defineComponent({
|
||||
if (!currentSlideAnimations.value) return
|
||||
|
||||
const animations = currentSlideAnimations.value.map(item => {
|
||||
if (item.elId === handleElement.value.id) return { ...item, type }
|
||||
if (item.elId === handleElementId.value) return { ...item, type }
|
||||
return item
|
||||
})
|
||||
store.commit(MutationTypes.UPDATE_SLIDE, { animations })
|
||||
slidesStore.updateSlide({ animations })
|
||||
animationPoolVisible.value = false
|
||||
addHistorySnapshot()
|
||||
|
||||
const animationItem = currentSlideAnimations.value.find(item => item.elId === handleElement.value.id)
|
||||
const animationItem = currentSlideAnimations.value.find(item => item.elId === handleElementId.value)
|
||||
const duration = animationItem?.duration || defaultDuration
|
||||
|
||||
runAnimation(handleElement.value.id, type, duration)
|
||||
runAnimation(handleElementId.value, type, duration)
|
||||
}
|
||||
|
||||
// 修改元素入场动画持续时间
|
||||
@ -219,10 +218,10 @@ export default defineComponent({
|
||||
if (duration < 100 || duration > 5000) return
|
||||
|
||||
const animations = currentSlideAnimations.value.map(item => {
|
||||
if (item.elId === handleElement.value.id) return { ...item, duration }
|
||||
if (item.elId === handleElementId.value) return { ...item, duration }
|
||||
return item
|
||||
})
|
||||
store.commit(MutationTypes.UPDATE_SLIDE, { animations })
|
||||
slidesStore.updateSlide({ animations })
|
||||
addHistorySnapshot()
|
||||
}
|
||||
|
||||
@ -234,15 +233,15 @@ export default defineComponent({
|
||||
}
|
||||
const animations: PPTAnimation[] = currentSlideAnimations.value ? JSON.parse(JSON.stringify(currentSlideAnimations.value)) : []
|
||||
animations.push({
|
||||
elId: handleElement.value.id,
|
||||
elId: handleElementId.value,
|
||||
type,
|
||||
duration: defaultDuration,
|
||||
})
|
||||
store.commit(MutationTypes.UPDATE_SLIDE, { animations })
|
||||
slidesStore.updateSlide({ animations })
|
||||
animationPoolVisible.value = false
|
||||
addHistorySnapshot()
|
||||
|
||||
runAnimation(handleElement.value.id, type, defaultDuration)
|
||||
runAnimation(handleElementId.value, type, defaultDuration)
|
||||
}
|
||||
|
||||
// 动画选择面板打开500ms后再移除遮罩层,否则打开面板后迅速滑入鼠标预览会导致抖动
|
||||
|
@ -134,8 +134,8 @@
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, ref, watch } from 'vue'
|
||||
import { round } from 'lodash'
|
||||
import { MutationTypes, useStore } from '@/store'
|
||||
import { PPTElement } from '@/types/slides'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useMainStore, useSlidesStore } from '@/store'
|
||||
import { MIN_SIZE } from '@/configs/element'
|
||||
import useOrderElement from '@/hooks/useOrderElement'
|
||||
import useAlignElementToCanvas from '@/hooks/useAlignElementToCanvas'
|
||||
@ -144,8 +144,8 @@ import useHistorySnapshot from '@/hooks/useHistorySnapshot'
|
||||
export default defineComponent({
|
||||
name: 'element-positopn-panel',
|
||||
setup() {
|
||||
const store = useStore()
|
||||
const handleElement = computed<PPTElement>(() => store.getters.handleElement)
|
||||
const slidesStore = useSlidesStore()
|
||||
const { handleElement, handleElementId } = storeToRefs(useMainStore())
|
||||
|
||||
const left = ref(0)
|
||||
const top = ref(0)
|
||||
@ -182,36 +182,36 @@ export default defineComponent({
|
||||
// 设置元素位置
|
||||
const updateLeft = (value: number) => {
|
||||
const props = { left: value }
|
||||
store.commit(MutationTypes.UPDATE_ELEMENT, { id: handleElement.value.id, props })
|
||||
slidesStore.updateElement({ id: handleElementId.value, props })
|
||||
addHistorySnapshot()
|
||||
}
|
||||
const updateTop = (value: number) => {
|
||||
const props = { top: value }
|
||||
store.commit(MutationTypes.UPDATE_ELEMENT, { id: handleElement.value.id, props })
|
||||
slidesStore.updateElement({ id: handleElementId.value, props })
|
||||
addHistorySnapshot()
|
||||
}
|
||||
|
||||
// 设置元素宽度、高度、旋转角度
|
||||
const updateWidth = (value: number) => {
|
||||
const props = { width: value }
|
||||
store.commit(MutationTypes.UPDATE_ELEMENT, { id: handleElement.value.id, props })
|
||||
slidesStore.updateElement({ id: handleElementId.value, props })
|
||||
addHistorySnapshot()
|
||||
}
|
||||
const updateHeight = (value: number) => {
|
||||
const props = { height: value }
|
||||
store.commit(MutationTypes.UPDATE_ELEMENT, { id: handleElement.value.id, props })
|
||||
slidesStore.updateElement({ id: handleElementId.value, props })
|
||||
addHistorySnapshot()
|
||||
}
|
||||
const updateRotate = (value: number) => {
|
||||
const props = { rotate: value }
|
||||
store.commit(MutationTypes.UPDATE_ELEMENT, { id: handleElement.value.id, props })
|
||||
slidesStore.updateElement({ id: handleElementId.value, props })
|
||||
addHistorySnapshot()
|
||||
}
|
||||
|
||||
// 固定元素的宽高比
|
||||
const updateFixedRatio = (value: boolean) => {
|
||||
const props = { fixedRatio: value }
|
||||
store.commit(MutationTypes.UPDATE_ELEMENT, { id: handleElement.value.id, props })
|
||||
slidesStore.updateElement({ id: handleElementId.value, props })
|
||||
addHistorySnapshot()
|
||||
}
|
||||
|
||||
@ -225,7 +225,7 @@ export default defineComponent({
|
||||
if (_rotate > 180) _rotate = 180
|
||||
|
||||
const props = { rotate: _rotate }
|
||||
store.commit(MutationTypes.UPDATE_ELEMENT, { id: handleElement.value.id, props })
|
||||
slidesStore.updateElement({ id: handleElementId.value, props })
|
||||
addHistorySnapshot()
|
||||
}
|
||||
|
||||
|
@ -125,9 +125,10 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, onUnmounted, ref, watch } from 'vue'
|
||||
import { defineComponent, onUnmounted, ref, watch } from 'vue'
|
||||
import { IBarChartOptions, ILineChartOptions, IPieChartOptions } from 'chartist'
|
||||
import { MutationTypes, useStore } from '@/store'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useMainStore, useSlidesStore } from '@/store'
|
||||
import { ChartData, PPTChartElement } from '@/types/slides'
|
||||
import emitter, { EmitterEvents } from '@/utils/emitter'
|
||||
import useHistorySnapshot from '@/hooks/useHistorySnapshot'
|
||||
@ -144,9 +145,10 @@ export default defineComponent({
|
||||
ColorButton,
|
||||
},
|
||||
setup() {
|
||||
const store = useStore()
|
||||
const handleElement = computed<PPTChartElement>(() => store.getters.handleElement)
|
||||
const theme = computed(() => store.state.theme)
|
||||
const mainStore = useMainStore()
|
||||
const slidesStore = useSlidesStore()
|
||||
const { handleElement, handleElementId } = storeToRefs(mainStore)
|
||||
const { theme } = storeToRefs(slidesStore)
|
||||
|
||||
const chartDataEditorVisible = ref(false)
|
||||
|
||||
@ -189,28 +191,28 @@ export default defineComponent({
|
||||
legend.value = handleElement.value.legend || ''
|
||||
}, { deep: true, immediate: true })
|
||||
|
||||
const updateElement = (props: Partial<PPTChartElement>) => {
|
||||
slidesStore.updateElement({ id: handleElementId.value, props })
|
||||
addHistorySnapshot()
|
||||
}
|
||||
|
||||
// 设置图表数据
|
||||
const updateData = (data: ChartData) => {
|
||||
chartDataEditorVisible.value = false
|
||||
const props = { data }
|
||||
store.commit(MutationTypes.UPDATE_ELEMENT, { id: handleElement.value.id, props })
|
||||
addHistorySnapshot()
|
||||
updateElement({ data })
|
||||
}
|
||||
|
||||
// 设置填充色
|
||||
const updateFill = (value: string) => {
|
||||
const props = { fill: value }
|
||||
store.commit(MutationTypes.UPDATE_ELEMENT, { id: handleElement.value.id, props })
|
||||
addHistorySnapshot()
|
||||
updateElement({ fill: value })
|
||||
}
|
||||
|
||||
// 设置其他选项:柱状图转条形图、折线图转面积图、折线图转散点图、饼图转环形图、折线图开关平滑曲线
|
||||
const updateOptions = (optionProps: ILineChartOptions & IBarChartOptions & IPieChartOptions) => {
|
||||
const options = handleElement.value.options || {}
|
||||
const newOptions = { ...options, ...optionProps }
|
||||
const props = { options: newOptions }
|
||||
store.commit(MutationTypes.UPDATE_ELEMENT, { id: handleElement.value.id, props })
|
||||
addHistorySnapshot()
|
||||
const _handleElement = handleElement.value as PPTChartElement
|
||||
|
||||
const newOptions = { ..._handleElement.options, ...optionProps }
|
||||
updateElement({ options: newOptions })
|
||||
}
|
||||
|
||||
// 设置主题色
|
||||
@ -218,8 +220,7 @@ export default defineComponent({
|
||||
const props = {
|
||||
themeColor: themeColor.value.map((c, i) => i === index ? color : c),
|
||||
}
|
||||
store.commit(MutationTypes.UPDATE_ELEMENT, { id: handleElement.value.id, props })
|
||||
addHistorySnapshot()
|
||||
updateElement(props)
|
||||
}
|
||||
|
||||
// 添加主题色
|
||||
@ -227,8 +228,7 @@ export default defineComponent({
|
||||
const props = {
|
||||
themeColor: [...themeColor.value, theme.value.themeColor],
|
||||
}
|
||||
store.commit(MutationTypes.UPDATE_ELEMENT, { id: handleElement.value.id, props })
|
||||
addHistorySnapshot()
|
||||
updateElement(props)
|
||||
}
|
||||
|
||||
// 删除主题色
|
||||
@ -236,22 +236,17 @@ export default defineComponent({
|
||||
const props = {
|
||||
themeColor: themeColor.value.filter((c, i) => i !== index),
|
||||
}
|
||||
store.commit(MutationTypes.UPDATE_ELEMENT, { id: handleElement.value.id, props })
|
||||
addHistorySnapshot()
|
||||
updateElement(props)
|
||||
}
|
||||
|
||||
// 设置网格颜色
|
||||
const updateGridColor = (gridColor: string) => {
|
||||
const props = { gridColor }
|
||||
store.commit(MutationTypes.UPDATE_ELEMENT, { id: handleElement.value.id, props })
|
||||
addHistorySnapshot()
|
||||
updateElement({ gridColor })
|
||||
}
|
||||
|
||||
// 设置图例位置/不显示
|
||||
const updateLegend = (legend: '' | 'top' | 'bottom') => {
|
||||
const props = { legend }
|
||||
store.commit(MutationTypes.UPDATE_ELEMENT, { id: handleElement.value.id, props })
|
||||
addHistorySnapshot()
|
||||
updateElement({ legend })
|
||||
}
|
||||
|
||||
const openDataEditor = () => chartDataEditorVisible.value = true
|
||||
|
@ -75,9 +75,10 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, ref, watch } from 'vue'
|
||||
import { MutationTypes, useStore } from '@/store'
|
||||
import { PPTImageElement, Slide } from '@/types/slides'
|
||||
import { defineComponent, ref, watch } from 'vue'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useMainStore, useSlidesStore } from '@/store'
|
||||
import { PPTImageElement, SlideBackground } from '@/types/slides'
|
||||
import { CLIPPATHS } from '@/configs/imageClip'
|
||||
import { getImageDataURL } from '@/utils/image'
|
||||
import useHistorySnapshot from '@/hooks/useHistorySnapshot'
|
||||
@ -148,9 +149,10 @@ export default defineComponent({
|
||||
ElementFlip,
|
||||
},
|
||||
setup() {
|
||||
const store = useStore()
|
||||
const handleElement = computed<PPTImageElement>(() => store.getters.handleElement)
|
||||
const currentSlide = computed<Slide>(() => store.getters.currentSlide)
|
||||
const mainStore = useMainStore()
|
||||
const slidesStore = useSlidesStore()
|
||||
const { handleElement, handleElementId } = storeToRefs(mainStore)
|
||||
const { currentSlide } = storeToRefs(slidesStore)
|
||||
|
||||
const clipPanelVisible = ref(false)
|
||||
|
||||
@ -173,28 +175,30 @@ export default defineComponent({
|
||||
|
||||
// 设置滤镜
|
||||
const updateFilter = (filter: FilterOption, value: number) => {
|
||||
const originFilters = handleElement.value.filters || {}
|
||||
const _handleElement = handleElement.value as PPTImageElement
|
||||
|
||||
const originFilters = _handleElement.filters || {}
|
||||
const filters = { ...originFilters, [filter.key]: `${value}${filter.unit}` }
|
||||
const props = { filters }
|
||||
store.commit(MutationTypes.UPDATE_ELEMENT, { id: handleElement.value.id, props })
|
||||
slidesStore.updateElement({ id: handleElementId.value, props: { filters } })
|
||||
addHistorySnapshot()
|
||||
}
|
||||
|
||||
// 打开自由裁剪
|
||||
const clipImage = () => {
|
||||
store.commit(MutationTypes.SET_CLIPING_IMAGE_ELEMENT_ID, handleElement.value.id)
|
||||
mainStore.setClipingImageElementId(handleElementId.value)
|
||||
clipPanelVisible.value = false
|
||||
}
|
||||
|
||||
// 获取原始图片的位置大小
|
||||
const getImageElementDataBeforeClip = () => {
|
||||
const _handleElement = handleElement.value as PPTImageElement
|
||||
|
||||
// 图片当前的位置大小和裁剪范围
|
||||
const imgWidth = handleElement.value.width
|
||||
const imgHeight = handleElement.value.height
|
||||
const imgLeft = handleElement.value.left
|
||||
const imgTop = handleElement.value.top
|
||||
const originClipRange = handleElement.value.clip ? handleElement.value.clip.range : [[0, 0], [100, 100]]
|
||||
const imgWidth = _handleElement.width
|
||||
const imgHeight = _handleElement.height
|
||||
const imgLeft = _handleElement.left
|
||||
const imgTop = _handleElement.top
|
||||
const originClipRange: [[number, number], [number, number]] = _handleElement.clip ? _handleElement.clip.range : [[0, 0], [100, 100]]
|
||||
|
||||
const originWidth = imgWidth / ((originClipRange[1][0] - originClipRange[0][0]) / 100)
|
||||
const originHeight = imgHeight / ((originClipRange[1][1] - originClipRange[0][1]) / 100)
|
||||
@ -212,6 +216,8 @@ export default defineComponent({
|
||||
|
||||
// 预设裁剪
|
||||
const presetImageClip = (shape: string, ratio = 0) => {
|
||||
const _handleElement = handleElement.value as PPTImageElement
|
||||
|
||||
const {
|
||||
originClipRange,
|
||||
originWidth,
|
||||
@ -226,7 +232,7 @@ export default defineComponent({
|
||||
|
||||
const min = 0
|
||||
const max = 100
|
||||
let range
|
||||
let range: [[number, number], [number, number]]
|
||||
|
||||
if (imageRatio > ratio) {
|
||||
const distance = ((1 - ratio / imageRatio) / 2) * 100
|
||||
@ -236,10 +242,10 @@ export default defineComponent({
|
||||
const distance = ((1 - imageRatio / ratio) / 2) * 100
|
||||
range = [[distance, min], [max - distance, max]]
|
||||
}
|
||||
store.commit(MutationTypes.UPDATE_ELEMENT, {
|
||||
id: handleElement.value.id,
|
||||
slidesStore.updateElement({
|
||||
id: handleElementId.value,
|
||||
props: {
|
||||
clip: { ...handleElement.value.clip, shape, range },
|
||||
clip: { ..._handleElement.clip, shape, range },
|
||||
left: originLeft + originWidth * (range[0][0] / 100),
|
||||
top: originTop + originHeight * (range[0][1] / 100),
|
||||
width: originWidth * (range[1][0] - range[0][0]) / 100,
|
||||
@ -249,10 +255,10 @@ export default defineComponent({
|
||||
}
|
||||
// 形状裁剪(保持当前裁剪范围)
|
||||
else {
|
||||
store.commit(MutationTypes.UPDATE_ELEMENT, {
|
||||
id: handleElement.value.id,
|
||||
slidesStore.updateElement({
|
||||
id: handleElementId.value,
|
||||
props: {
|
||||
clip: { ...handleElement.value.clip, shape, range: originClipRange }
|
||||
clip: { ..._handleElement.clip, shape, range: originClipRange }
|
||||
},
|
||||
})
|
||||
}
|
||||
@ -266,14 +272,16 @@ export default defineComponent({
|
||||
if (!imageFile) return
|
||||
getImageDataURL(imageFile).then(dataURL => {
|
||||
const props = { src: dataURL }
|
||||
store.commit(MutationTypes.UPDATE_ELEMENT, { id: handleElement.value.id, props })
|
||||
slidesStore.updateElement({ id: handleElementId.value, props })
|
||||
})
|
||||
addHistorySnapshot()
|
||||
}
|
||||
|
||||
// 重置图片:清除全部样式
|
||||
const resetImage = () => {
|
||||
if (handleElement.value.clip) {
|
||||
const _handleElement = handleElement.value as PPTImageElement
|
||||
|
||||
if (_handleElement.clip) {
|
||||
const {
|
||||
originWidth,
|
||||
originHeight,
|
||||
@ -281,8 +289,8 @@ export default defineComponent({
|
||||
originTop,
|
||||
} = getImageElementDataBeforeClip()
|
||||
|
||||
store.commit(MutationTypes.UPDATE_ELEMENT, {
|
||||
id: handleElement.value.id,
|
||||
slidesStore.updateElement({
|
||||
id: handleElementId.value,
|
||||
props: {
|
||||
left: originLeft,
|
||||
top: originTop,
|
||||
@ -292,8 +300,8 @@ export default defineComponent({
|
||||
})
|
||||
}
|
||||
|
||||
store.commit(MutationTypes.REMOVE_ELEMENT_PROPS, {
|
||||
id: handleElement.value.id,
|
||||
slidesStore.removeElementProps({
|
||||
id: handleElementId.value,
|
||||
propName: ['clip', 'outline', 'flip', 'shadow', 'filters'],
|
||||
})
|
||||
addHistorySnapshot()
|
||||
@ -301,13 +309,15 @@ export default defineComponent({
|
||||
|
||||
// 将图片设置为背景
|
||||
const setBackgroundImage = () => {
|
||||
const background = {
|
||||
const _handleElement = handleElement.value as PPTImageElement
|
||||
|
||||
const background: SlideBackground = {
|
||||
...currentSlide.value.background,
|
||||
type: 'image',
|
||||
image: handleElement.value.src,
|
||||
image: _handleElement.src,
|
||||
imageSize: 'cover',
|
||||
}
|
||||
store.commit(MutationTypes.UPDATE_SLIDE, { background })
|
||||
slidesStore.updateSlide({ background })
|
||||
addHistorySnapshot()
|
||||
}
|
||||
|
||||
|
@ -44,8 +44,9 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, onUnmounted, ref } from 'vue'
|
||||
import { MutationTypes, useStore } from '@/store'
|
||||
import { defineComponent, onUnmounted, ref } from 'vue'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useMainStore, useSlidesStore } from '@/store'
|
||||
import { PPTLatexElement } from '@/types/slides'
|
||||
import emitter, { EmitterEvents } from '@/utils/emitter'
|
||||
import useHistorySnapshot from '@/hooks/useHistorySnapshot'
|
||||
@ -60,15 +61,16 @@ export default defineComponent({
|
||||
LaTeXEditor,
|
||||
},
|
||||
setup() {
|
||||
const store = useStore()
|
||||
const handleElement = computed<PPTLatexElement>(() => store.getters.handleElement)
|
||||
const slidesStore = useSlidesStore()
|
||||
const { handleElement } = storeToRefs(useMainStore())
|
||||
|
||||
const latexEditorVisible = ref(false)
|
||||
|
||||
const { addHistorySnapshot } = useHistorySnapshot()
|
||||
|
||||
const updateLatex = (props: Partial<PPTLatexElement>) => {
|
||||
store.commit(MutationTypes.UPDATE_ELEMENT, { id: handleElement.value.id, props })
|
||||
if (!handleElement.value) return
|
||||
slidesStore.updateElement({ id: handleElement.value.id, props })
|
||||
addHistorySnapshot()
|
||||
}
|
||||
|
||||
|
@ -63,8 +63,9 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent } from 'vue'
|
||||
import { MutationTypes, useStore } from '@/store'
|
||||
import { defineComponent } from 'vue'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useMainStore, useSlidesStore } from '@/store'
|
||||
import { PPTLineElement } from '@/types/slides'
|
||||
import useHistorySnapshot from '@/hooks/useHistorySnapshot'
|
||||
|
||||
@ -78,13 +79,14 @@ export default defineComponent({
|
||||
ColorButton,
|
||||
},
|
||||
setup() {
|
||||
const store = useStore()
|
||||
const handleElement = computed<PPTLineElement>(() => store.getters.handleElement)
|
||||
const slidesStore = useSlidesStore()
|
||||
const { handleElement } = storeToRefs(useMainStore())
|
||||
|
||||
const { addHistorySnapshot } = useHistorySnapshot()
|
||||
|
||||
const updateLine = (props: Partial<PPTLineElement>) => {
|
||||
store.commit(MutationTypes.UPDATE_ELEMENT, { id: handleElement.value.id, props })
|
||||
if (!handleElement.value) return
|
||||
slidesStore.updateElement({ id: handleElement.value.id, props })
|
||||
addHistorySnapshot()
|
||||
}
|
||||
|
||||
|
@ -196,7 +196,8 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, ref, watch } from 'vue'
|
||||
import { MutationTypes, useStore } from '@/store'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useMainStore, useSlidesStore } from '@/store'
|
||||
import { PPTShapeElement, ShapeGradient, ShapeText } from '@/types/slides'
|
||||
import { WEB_FONTS } from '@/configs/font'
|
||||
import emitter, { EmitterEvents } from '@/utils/emitter'
|
||||
@ -220,13 +221,11 @@ export default defineComponent({
|
||||
ColorButton,
|
||||
},
|
||||
setup() {
|
||||
const store = useStore()
|
||||
const handleElement = computed<PPTShapeElement>(() => store.getters.handleElement)
|
||||
const editingShapeElementId = computed(() => store.state.editingShapeElementId)
|
||||
const mainStore = useMainStore()
|
||||
const slidesStore = useSlidesStore()
|
||||
const { handleElement, handleElementId, editingShapeElementId, richTextAttrs, availableFonts } = storeToRefs(mainStore)
|
||||
|
||||
const showTextTools = computed(() => {
|
||||
return editingShapeElementId.value === handleElement.value.id
|
||||
})
|
||||
const showTextTools = computed(() => editingShapeElementId.value === handleElementId.value)
|
||||
|
||||
const fill = ref<string>()
|
||||
const gradient = ref<ShapeGradient>()
|
||||
@ -235,61 +234,54 @@ export default defineComponent({
|
||||
|
||||
watch(handleElement, () => {
|
||||
if (!handleElement.value || handleElement.value.type !== 'shape') return
|
||||
|
||||
fill.value = handleElement.value.fill || '#000'
|
||||
|
||||
gradient.value = handleElement.value.gradient || { type: 'linear', rotate: 0, color: [fill.value, '#fff'] }
|
||||
|
||||
fillType.value = handleElement.value.gradient ? 'gradient' : 'fill'
|
||||
|
||||
textAlign.value = handleElement.value?.text?.align || 'middle'
|
||||
}, { deep: true, immediate: true })
|
||||
|
||||
const { addHistorySnapshot } = useHistorySnapshot()
|
||||
|
||||
const updateElement = (props: Partial<PPTShapeElement>) => {
|
||||
slidesStore.updateElement({ id: handleElementId.value, props })
|
||||
addHistorySnapshot()
|
||||
}
|
||||
|
||||
// 设置填充类型:渐变、纯色
|
||||
const updateFillType = (type: 'gradient' | 'fill') => {
|
||||
if (type === 'fill') {
|
||||
store.commit(MutationTypes.REMOVE_ELEMENT_PROPS, {
|
||||
id: handleElement.value.id,
|
||||
propName: 'gradient',
|
||||
})
|
||||
slidesStore.removeElementProps({ id: handleElementId.value, propName: 'gradient' })
|
||||
addHistorySnapshot()
|
||||
}
|
||||
else {
|
||||
const props = { gradient: gradient.value }
|
||||
store.commit(MutationTypes.UPDATE_ELEMENT, { id: handleElement.value.id, props })
|
||||
}
|
||||
addHistorySnapshot()
|
||||
else updateElement({ gradient: gradient.value })
|
||||
}
|
||||
|
||||
// 设置渐变填充
|
||||
const updateGradient = (gradientProps: Partial<ShapeGradient>) => {
|
||||
const props = { gradient: { ...gradient.value, ...gradientProps } }
|
||||
store.commit(MutationTypes.UPDATE_ELEMENT, { id: handleElement.value.id, props })
|
||||
addHistorySnapshot()
|
||||
if (!gradient.value) return
|
||||
const _gradient: ShapeGradient = { ...gradient.value, ...gradientProps }
|
||||
updateElement({ gradient: _gradient })
|
||||
}
|
||||
|
||||
// 设置填充色
|
||||
const updateFill = (value: string) => {
|
||||
const props = { fill: value }
|
||||
store.commit(MutationTypes.UPDATE_ELEMENT, { id: handleElement.value.id, props })
|
||||
addHistorySnapshot()
|
||||
updateElement({ fill: value })
|
||||
}
|
||||
|
||||
const updateTextAlign = (align: 'top' | 'middle' | 'bottom') => {
|
||||
const _handleElement = handleElement.value as PPTShapeElement
|
||||
|
||||
const defaultText: ShapeText = {
|
||||
content: '',
|
||||
defaultFontName: '微软雅黑',
|
||||
defaultColor: '#000',
|
||||
align: 'middle',
|
||||
}
|
||||
const _text = handleElement.value.text || defaultText
|
||||
const props = { text: { ..._text, align } }
|
||||
store.commit(MutationTypes.UPDATE_ELEMENT, { id: handleElement.value.id, props })
|
||||
addHistorySnapshot()
|
||||
const _text = _handleElement.text || defaultText
|
||||
updateElement({ text: { ..._text, align } })
|
||||
}
|
||||
|
||||
const richTextAttrs = computed(() => store.state.richTextAttrs)
|
||||
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', '76px',
|
||||
|
@ -122,7 +122,6 @@
|
||||
:max="20"
|
||||
v-model:value="rowCount"
|
||||
@pressEnter="e => setTableRow(e)"
|
||||
@blur="e => setTableRow(e)"
|
||||
style="flex: 3;"
|
||||
/>
|
||||
</div>
|
||||
@ -133,7 +132,6 @@
|
||||
:max="20"
|
||||
v-model:value="colCount"
|
||||
@pressEnter="e => setTableCol(e)"
|
||||
@blur="e => setTableCol(e)"
|
||||
style="flex: 3;"
|
||||
/>
|
||||
</div>
|
||||
@ -193,7 +191,8 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, onMounted, ref, watch } from 'vue'
|
||||
import { MutationTypes, useStore } from '@/store'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useMainStore, useSlidesStore } from '@/store'
|
||||
import { PPTTableElement, TableCell, TableCellStyle, TableTheme } from '@/types/slides'
|
||||
import { createRandomCode } from '@/utils/common'
|
||||
import { WEB_FONTS } from '@/configs/font'
|
||||
@ -213,12 +212,10 @@ export default defineComponent({
|
||||
ColorButton,
|
||||
},
|
||||
setup() {
|
||||
const store = useStore()
|
||||
const handleElement = computed<PPTTableElement>(() => store.getters.handleElement)
|
||||
const selectedCells = computed(() => store.state.selectedTableCells)
|
||||
const themeColor = computed(() => store.state.theme.themeColor)
|
||||
const slidesStore = useSlidesStore()
|
||||
const { handleElement, handleElementId, selectedTableCells: selectedCells, availableFonts } = storeToRefs(useMainStore())
|
||||
const themeColor = computed(() => slidesStore.theme.themeColor)
|
||||
|
||||
const availableFonts = computed(() => store.state.availableFonts)
|
||||
const fontSizeOptions = [
|
||||
'12px', '14px', '16px', '18px', '20px', '22px', '24px', '28px', '32px',
|
||||
]
|
||||
@ -304,9 +301,16 @@ export default defineComponent({
|
||||
|
||||
watch(selectedCells, updateTextAttrState)
|
||||
|
||||
const updateElement = (props: Partial<PPTTableElement>) => {
|
||||
slidesStore.updateElement({ id: handleElementId.value, props })
|
||||
addHistorySnapshot()
|
||||
}
|
||||
|
||||
// 设置单元格内容文本样式
|
||||
const updateTextAttrs = (textAttrProp: Partial<TableCellStyle>) => {
|
||||
const data: TableCell[][] = JSON.parse(JSON.stringify(handleElement.value.data))
|
||||
const _handleElement = handleElement.value as PPTTableElement
|
||||
|
||||
const data: TableCell[][] = JSON.parse(JSON.stringify(_handleElement.data))
|
||||
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
for (let j = 0; j < data[i].length; j++) {
|
||||
@ -316,19 +320,15 @@ export default defineComponent({
|
||||
}
|
||||
}
|
||||
}
|
||||
const props = { data }
|
||||
store.commit(MutationTypes.UPDATE_ELEMENT, { id: handleElement.value.id, props })
|
||||
|
||||
addHistorySnapshot()
|
||||
updateElement({ data })
|
||||
updateTextAttrState()
|
||||
}
|
||||
|
||||
// 更新表格主题:主题色、标题行、汇总行、第一列、最后一列
|
||||
const updateTheme = (themeProp: Partial<TableTheme>) => {
|
||||
const currentTheme = theme.value || {}
|
||||
const props = { theme: { ...currentTheme, ...themeProp } }
|
||||
store.commit(MutationTypes.UPDATE_ELEMENT, { id: handleElement.value.id, props })
|
||||
addHistorySnapshot()
|
||||
if (!theme.value) return
|
||||
const _theme = { ...theme.value, ...themeProp }
|
||||
updateElement({ theme: _theme })
|
||||
}
|
||||
|
||||
// 开启/关闭表格主题
|
||||
@ -343,18 +343,20 @@ export default defineComponent({
|
||||
colFooter: false,
|
||||
}
|
||||
}
|
||||
store.commit(MutationTypes.UPDATE_ELEMENT, { id: handleElement.value.id, props })
|
||||
updateElement(props)
|
||||
}
|
||||
else {
|
||||
store.commit(MutationTypes.REMOVE_ELEMENT_PROPS, { id: handleElement.value.id, propName: 'theme' })
|
||||
slidesStore.removeElementProps({ id: handleElementId.value, propName: 'theme' })
|
||||
addHistorySnapshot()
|
||||
}
|
||||
addHistorySnapshot()
|
||||
}
|
||||
|
||||
// 设置表格行数(只能增加)
|
||||
const setTableRow = (e: KeyboardEvent) => {
|
||||
const _handleElement = handleElement.value as PPTTableElement
|
||||
|
||||
const value = +(e.target as HTMLInputElement).value
|
||||
const rowCount = handleElement.value.data.length
|
||||
const rowCount = _handleElement.data.length
|
||||
|
||||
if (value === rowCount) return
|
||||
if (value < rowCount) return message.warning('设置行数不能少于当前值')
|
||||
@ -362,34 +364,34 @@ export default defineComponent({
|
||||
const rowCells: TableCell[] = new Array(colCount.value).fill({ id: createRandomCode(), colspan: 1, rowspan: 1, text: '' })
|
||||
const newTableCells: TableCell[][] = new Array(value - rowCount).fill(rowCells)
|
||||
|
||||
const tableCells: TableCell[][] = JSON.parse(JSON.stringify(handleElement.value.data))
|
||||
const tableCells: TableCell[][] = JSON.parse(JSON.stringify(_handleElement.data))
|
||||
tableCells.push(...newTableCells)
|
||||
|
||||
const props = { data: tableCells }
|
||||
store.commit(MutationTypes.UPDATE_ELEMENT, { id: handleElement.value.id, props })
|
||||
addHistorySnapshot()
|
||||
updateElement({ data: tableCells })
|
||||
}
|
||||
|
||||
|
||||
// 设置表格列数(只能增加)
|
||||
const setTableCol = (e: KeyboardEvent) => {
|
||||
const _handleElement = handleElement.value as PPTTableElement
|
||||
|
||||
const value = +(e.target as HTMLInputElement).value
|
||||
const colCount = handleElement.value.data[0].length
|
||||
const colCount = _handleElement.data[0].length
|
||||
|
||||
if (value === colCount) return
|
||||
if (value < colCount) return message.warning('设置列数不能少于当前值')
|
||||
|
||||
const tableCells = handleElement.value.data.map(item => {
|
||||
const tableCells = _handleElement.data.map(item => {
|
||||
const cells: TableCell[] = new Array(value - colCount).fill({ id: createRandomCode(), colspan: 1, rowspan: 1, text: '' })
|
||||
item.push(...cells)
|
||||
return item
|
||||
})
|
||||
|
||||
const colSizeList = handleElement.value.colWidths.map(item => item * handleElement.value.width)
|
||||
const colSizeList = _handleElement.colWidths.map(item => item * _handleElement.width)
|
||||
const newColSizeList = new Array(value - colCount).fill(100)
|
||||
colSizeList.push(...newColSizeList)
|
||||
|
||||
const width = handleElement.value.width + 100 * (value - colCount)
|
||||
const width = _handleElement.width + 100 * (value - colCount)
|
||||
const colWidths = colSizeList.map(item => item / width)
|
||||
|
||||
const props = {
|
||||
@ -397,9 +399,7 @@ export default defineComponent({
|
||||
data: tableCells,
|
||||
colWidths,
|
||||
}
|
||||
store.commit(MutationTypes.UPDATE_ELEMENT, { id: handleElement.value.id, props })
|
||||
|
||||
addHistorySnapshot()
|
||||
updateElement(props)
|
||||
}
|
||||
|
||||
return {
|
||||
|
@ -218,9 +218,9 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, ref, watch } from 'vue'
|
||||
import { MutationTypes, useStore } from '@/store'
|
||||
import { PPTTextElement } from '@/types/slides'
|
||||
import { defineComponent, ref, watch } from 'vue'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useMainStore, useSlidesStore } from '@/store'
|
||||
import emitter, { EmitterEvents, RichTextCommand } from '@/utils/emitter'
|
||||
import { WEB_FONTS } from '@/configs/font'
|
||||
import useHistorySnapshot from '@/hooks/useHistorySnapshot'
|
||||
@ -228,6 +228,7 @@ import useHistorySnapshot from '@/hooks/useHistorySnapshot'
|
||||
import ElementOpacity from '../common/ElementOpacity.vue'
|
||||
import ElementOutline from '../common/ElementOutline.vue'
|
||||
import ElementShadow from '../common/ElementShadow.vue'
|
||||
import { PPTTextElement } from '@/types/slides'
|
||||
|
||||
const presetStyles = [
|
||||
{
|
||||
@ -312,9 +313,8 @@ export default defineComponent({
|
||||
ElementShadow,
|
||||
},
|
||||
setup() {
|
||||
const store = useStore()
|
||||
const handleElement = computed<PPTTextElement>(() => store.getters.handleElement)
|
||||
const richTextAttrs = computed(() => store.state.richTextAttrs)
|
||||
const slidesStore = useSlidesStore()
|
||||
const { handleElement, handleElementId, richTextAttrs, availableFonts } = storeToRefs(useMainStore())
|
||||
|
||||
const fill = ref<string>()
|
||||
const lineHeight = ref<number>()
|
||||
@ -328,7 +328,6 @@ export default defineComponent({
|
||||
wordSpace.value = handleElement.value.wordSpace || 0
|
||||
}, { deep: true, immediate: true })
|
||||
|
||||
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', '76px',
|
||||
@ -349,25 +348,24 @@ export default defineComponent({
|
||||
|
||||
const { addHistorySnapshot } = useHistorySnapshot()
|
||||
|
||||
const updateElement = (props: Partial<PPTTextElement>) => {
|
||||
slidesStore.updateElement({ id: handleElementId.value, props })
|
||||
addHistorySnapshot()
|
||||
}
|
||||
|
||||
// 设置行高
|
||||
const updateLineHeight = (value: number) => {
|
||||
const props = { lineHeight: value }
|
||||
store.commit(MutationTypes.UPDATE_ELEMENT, { id: handleElement.value.id, props })
|
||||
addHistorySnapshot()
|
||||
updateElement({ lineHeight: value })
|
||||
}
|
||||
|
||||
// 设置字间距
|
||||
const updateWordSpace = (value: number) => {
|
||||
const props = { wordSpace: value }
|
||||
store.commit(MutationTypes.UPDATE_ELEMENT, { id: handleElement.value.id, props })
|
||||
addHistorySnapshot()
|
||||
updateElement({ wordSpace: value })
|
||||
}
|
||||
|
||||
// 设置文本框填充
|
||||
const updateFill = (value: string) => {
|
||||
const props = { fill: value }
|
||||
store.commit(MutationTypes.UPDATE_ELEMENT, { id: handleElement.value.id, props })
|
||||
addHistorySnapshot()
|
||||
updateElement({ fill: value })
|
||||
}
|
||||
|
||||
return {
|
||||
|
@ -15,8 +15,9 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent } from 'vue'
|
||||
import { MutationTypes, useStore } from '@/store'
|
||||
import { defineComponent } from 'vue'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useMainStore, useSlidesStore } from '@/store'
|
||||
import { PPTVideoElement } from '@/types/slides'
|
||||
import { getImageDataURL } from '@/utils/image'
|
||||
import useHistorySnapshot from '@/hooks/useHistorySnapshot'
|
||||
@ -24,13 +25,14 @@ import useHistorySnapshot from '@/hooks/useHistorySnapshot'
|
||||
export default defineComponent({
|
||||
name: 'video-style-panel',
|
||||
setup() {
|
||||
const store = useStore()
|
||||
const handleElement = computed<PPTVideoElement>(() => store.getters.handleElement)
|
||||
const slidesStore = useSlidesStore()
|
||||
const { handleElement } = storeToRefs(useMainStore())
|
||||
|
||||
const { addHistorySnapshot } = useHistorySnapshot()
|
||||
|
||||
const updateVideo = (props: Partial<PPTVideoElement>) => {
|
||||
store.commit(MutationTypes.UPDATE_ELEMENT, { id: handleElement.value.id, props })
|
||||
if (!handleElement.value) return
|
||||
slidesStore.updateElement({ id: handleElement.value.id, props })
|
||||
addHistorySnapshot()
|
||||
}
|
||||
|
||||
|
@ -9,8 +9,9 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent } from 'vue'
|
||||
import { useStore } from '@/store'
|
||||
import { ElementTypes, PPTElement } from '@/types/slides'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useMainStore } from '@/store'
|
||||
import { ElementTypes } from '@/types/slides'
|
||||
|
||||
import TextStylePanel from './TextStylePanel.vue'
|
||||
import ImageStylePanel from './ImageStylePanel.vue'
|
||||
@ -24,8 +25,7 @@ import VideoStylePanel from './VideoStylePanel.vue'
|
||||
export default defineComponent({
|
||||
name: 'element-style-panel',
|
||||
setup() {
|
||||
const store = useStore()
|
||||
const handleElement = computed<PPTElement>(() => store.getters.handleElement)
|
||||
const { handleElement } = storeToRefs(useMainStore())
|
||||
|
||||
const currentPanelComponent = computed(() => {
|
||||
if (!handleElement.value) return null
|
||||
|
@ -18,20 +18,25 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent } from 'vue'
|
||||
import { MutationTypes, useStore } from '@/store'
|
||||
import { Slide } from '@/types/slides'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useSlidesStore } from '@/store'
|
||||
import { TurningMode } from '@/types/slides'
|
||||
import useHistorySnapshot from '@/hooks/useHistorySnapshot'
|
||||
|
||||
interface Animations {
|
||||
label: string;
|
||||
value: TurningMode;
|
||||
}
|
||||
|
||||
export default defineComponent({
|
||||
name: 'slide-animation-panel',
|
||||
setup() {
|
||||
const store = useStore()
|
||||
const slides = computed(() => store.state.slides)
|
||||
const currentSlide = computed<Slide>(() => store.getters.currentSlide)
|
||||
const slidesStore = useSlidesStore()
|
||||
const { slides, currentSlide } = storeToRefs(slidesStore)
|
||||
|
||||
const currentTurningMode = computed(() => currentSlide.value.turningMode || 'slideY')
|
||||
|
||||
const animations = [
|
||||
const animations: Animations[] = [
|
||||
{ label: '无', value: 'no' },
|
||||
{ label: '淡入淡出', value: 'fade' },
|
||||
{ label: '左右推移', value: 'slideX' },
|
||||
@ -41,9 +46,9 @@ export default defineComponent({
|
||||
const { addHistorySnapshot } = useHistorySnapshot()
|
||||
|
||||
// 修改播放时的切换页面方式
|
||||
const updateTurningMode = (mode: string) => {
|
||||
const updateTurningMode = (mode: TurningMode) => {
|
||||
if (mode === currentTurningMode.value) return
|
||||
store.commit(MutationTypes.UPDATE_SLIDE, { turningMode: mode })
|
||||
slidesStore.updateSlide({ turningMode: mode })
|
||||
addHistorySnapshot()
|
||||
}
|
||||
|
||||
@ -55,7 +60,7 @@ export default defineComponent({
|
||||
turningMode: currentSlide.value.turningMode,
|
||||
}
|
||||
})
|
||||
store.commit(MutationTypes.SET_SLIDES, newSlides)
|
||||
slidesStore.setSlides(newSlides)
|
||||
addHistorySnapshot()
|
||||
}
|
||||
|
||||
|
@ -193,7 +193,8 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, ref } from 'vue'
|
||||
import { MutationTypes, useStore } from '@/store'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useMainStore, useSlidesStore } from '@/store'
|
||||
import { Slide, SlideBackground, SlideTheme } from '@/types/slides'
|
||||
import { PRESET_THEMES } from '@/configs/theme'
|
||||
import { WEB_FONTS } from '@/configs/font'
|
||||
@ -211,12 +212,9 @@ export default defineComponent({
|
||||
ColorButton,
|
||||
},
|
||||
setup() {
|
||||
const store = useStore()
|
||||
const slides = computed(() => store.state.slides)
|
||||
const theme = computed(() => store.state.theme)
|
||||
const availableFonts = computed(() => store.state.availableFonts)
|
||||
const viewportRatio = computed(() => store.state.viewportRatio)
|
||||
const currentSlide = computed<Slide>(() => store.getters.currentSlide)
|
||||
const slidesStore = useSlidesStore()
|
||||
const { availableFonts } = storeToRefs(useMainStore())
|
||||
const { slides, currentSlide, viewportRatio, theme } = storeToRefs(slidesStore)
|
||||
|
||||
const background = computed(() => {
|
||||
if (!currentSlide.value.background) {
|
||||
@ -238,7 +236,7 @@ export default defineComponent({
|
||||
type: 'solid',
|
||||
color: background.value.color || '#fff',
|
||||
}
|
||||
store.commit(MutationTypes.UPDATE_SLIDE, { background: newBackground })
|
||||
slidesStore.updateSlide({ background: newBackground })
|
||||
}
|
||||
else if (type === 'image') {
|
||||
const newBackground: SlideBackground = {
|
||||
@ -247,7 +245,7 @@ export default defineComponent({
|
||||
image: background.value.image || '',
|
||||
imageSize: background.value.imageSize || 'cover',
|
||||
}
|
||||
store.commit(MutationTypes.UPDATE_SLIDE, { background: newBackground })
|
||||
slidesStore.updateSlide({ background: newBackground })
|
||||
}
|
||||
else {
|
||||
const newBackground: SlideBackground = {
|
||||
@ -257,14 +255,14 @@ export default defineComponent({
|
||||
gradientColor: background.value.gradientColor || ['#fff', '#fff'],
|
||||
gradientRotate: background.value.gradientRotate || 0,
|
||||
}
|
||||
store.commit(MutationTypes.UPDATE_SLIDE, { background: newBackground })
|
||||
slidesStore.updateSlide({ background: newBackground })
|
||||
}
|
||||
addHistorySnapshot()
|
||||
}
|
||||
|
||||
// 设置背景图片
|
||||
const updateBackground = (props: Partial<SlideBackground>) => {
|
||||
store.commit(MutationTypes.UPDATE_SLIDE, { background: { ...background.value, ...props } })
|
||||
slidesStore.updateSlide({ background: { ...background.value, ...props } })
|
||||
addHistorySnapshot()
|
||||
}
|
||||
|
||||
@ -283,13 +281,13 @@ export default defineComponent({
|
||||
background: currentSlide.value.background,
|
||||
}
|
||||
})
|
||||
store.commit(MutationTypes.SET_SLIDES, newSlides)
|
||||
slidesStore.setSlides(newSlides)
|
||||
addHistorySnapshot()
|
||||
}
|
||||
|
||||
// 设置主题
|
||||
const updateTheme = (themeProps: Partial<SlideTheme>) => {
|
||||
store.commit(MutationTypes.SET_THEME, themeProps)
|
||||
slidesStore.setTheme(themeProps)
|
||||
}
|
||||
|
||||
// 将当前主题应用到全部页面
|
||||
@ -333,7 +331,7 @@ export default defineComponent({
|
||||
else if (el.type === 'latex') el.color = fontColor
|
||||
}
|
||||
}
|
||||
store.commit(MutationTypes.SET_SLIDES, newSlides)
|
||||
slidesStore.setSlides(newSlides)
|
||||
addHistorySnapshot()
|
||||
}
|
||||
|
||||
@ -345,7 +343,7 @@ export default defineComponent({
|
||||
|
||||
// 设置画布尺寸(宽高比例)
|
||||
const updateViewportRatio = (value: number) => {
|
||||
store.commit(MutationTypes.SET_VIEWPORT_RATIO, value)
|
||||
slidesStore.setViewportRatio(value)
|
||||
}
|
||||
|
||||
return {
|
||||
|
@ -16,31 +16,33 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, ref, watch } from 'vue'
|
||||
import { MutationTypes, useStore } from '@/store'
|
||||
import { PPTImageElement, PPTShapeElement, ImageOrShapeFlip } from '@/types/slides'
|
||||
import { defineComponent, ref, watch } from 'vue'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useMainStore, useSlidesStore } from '@/store'
|
||||
import { ImageOrShapeFlip } from '@/types/slides'
|
||||
import useHistorySnapshot from '@/hooks/useHistorySnapshot'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'element-flip',
|
||||
setup() {
|
||||
const store = useStore()
|
||||
const handleElement = computed<PPTImageElement | PPTShapeElement>(() => store.getters.handleElement)
|
||||
const slidesStore = useSlidesStore()
|
||||
const { handleElement } = storeToRefs(useMainStore())
|
||||
|
||||
const flipH = ref(false)
|
||||
const flipV = ref(false)
|
||||
|
||||
watch(handleElement, () => {
|
||||
if (!handleElement.value || !['image', 'shape'].includes(handleElement.value.type)) return
|
||||
|
||||
flipH.value = !!handleElement.value.flipH
|
||||
flipV.value = !!handleElement.value.flipV
|
||||
if (handleElement.value && (handleElement.value.type === 'image' || handleElement.value.type === 'shape')) {
|
||||
flipH.value = !!handleElement.value.flipH
|
||||
flipV.value = !!handleElement.value.flipV
|
||||
}
|
||||
}, { deep: true, immediate: true })
|
||||
|
||||
const { addHistorySnapshot } = useHistorySnapshot()
|
||||
|
||||
const updateFlip = (flipProps: ImageOrShapeFlip) => {
|
||||
store.commit(MutationTypes.UPDATE_ELEMENT, { id: handleElement.value.id, props: flipProps })
|
||||
if (!handleElement.value) return
|
||||
slidesStore.updateElement({ id: handleElement.value.id, props: flipProps })
|
||||
addHistorySnapshot()
|
||||
}
|
||||
|
||||
|
@ -3,11 +3,11 @@
|
||||
<div class="row">
|
||||
<div style="flex: 2;">不透明度:</div>
|
||||
<Slider
|
||||
class="slider"
|
||||
:min="0"
|
||||
:max="1"
|
||||
:step="0.1"
|
||||
:value="opacity"
|
||||
style="flex: 3;"
|
||||
@change="value => updateOpacity(value)"
|
||||
/>
|
||||
</div>
|
||||
@ -15,18 +15,18 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, ref, watch } from 'vue'
|
||||
import { MutationTypes, useStore } from '@/store'
|
||||
import { PPTElement } from '@/types/slides'
|
||||
import { defineComponent, ref, watch } from 'vue'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useMainStore, useSlidesStore } from '@/store'
|
||||
import useHistorySnapshot from '@/hooks/useHistorySnapshot'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'element-opacity',
|
||||
setup() {
|
||||
const store = useStore()
|
||||
const handleElement = computed<PPTElement>(() => store.getters.handleElement)
|
||||
const slidesStore = useSlidesStore()
|
||||
const { handleElement } = storeToRefs(useMainStore())
|
||||
|
||||
const opacity = ref<number>()
|
||||
const opacity = ref<number>(1)
|
||||
|
||||
watch(handleElement, () => {
|
||||
if (!handleElement.value) return
|
||||
@ -36,8 +36,9 @@ export default defineComponent({
|
||||
const { addHistorySnapshot } = useHistorySnapshot()
|
||||
|
||||
const updateOpacity = (value: number) => {
|
||||
if (!handleElement.value) return
|
||||
const props = { opacity: value }
|
||||
store.commit(MutationTypes.UPDATE_ELEMENT, { id: handleElement.value.id, props })
|
||||
slidesStore.updateElement({ id: handleElement.value.id, props })
|
||||
addHistorySnapshot()
|
||||
}
|
||||
|
||||
@ -56,4 +57,7 @@ export default defineComponent({
|
||||
align-items: center;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.slider {
|
||||
flex: 3;
|
||||
}
|
||||
</style>
|
@ -46,9 +46,10 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, ref, watch } from 'vue'
|
||||
import { MutationTypes, useStore } from '@/store'
|
||||
import { PPTElement, PPTElementOutline } from '@/types/slides'
|
||||
import { defineComponent, ref, watch } from 'vue'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useMainStore, useSlidesStore } from '@/store'
|
||||
import { PPTElementOutline } from '@/types/slides'
|
||||
import useHistorySnapshot from '@/hooks/useHistorySnapshot'
|
||||
|
||||
import ColorButton from './ColorButton.vue'
|
||||
@ -65,8 +66,8 @@ export default defineComponent({
|
||||
},
|
||||
},
|
||||
setup() {
|
||||
const store = useStore()
|
||||
const handleElement = computed<PPTElement>(() => store.getters.handleElement)
|
||||
const slidesStore = useSlidesStore()
|
||||
const { handleElement } = storeToRefs(useMainStore())
|
||||
|
||||
const outline = ref<PPTElementOutline>()
|
||||
const hasOutline = ref(false)
|
||||
@ -80,18 +81,20 @@ export default defineComponent({
|
||||
const { addHistorySnapshot } = useHistorySnapshot()
|
||||
|
||||
const updateOutline = (outlineProps: Partial<PPTElementOutline>) => {
|
||||
if (!handleElement.value) return
|
||||
const props = { outline: { ...outline.value, ...outlineProps } }
|
||||
store.commit(MutationTypes.UPDATE_ELEMENT, { id: handleElement.value.id, props })
|
||||
slidesStore.updateElement({ id: handleElement.value.id, props })
|
||||
addHistorySnapshot()
|
||||
}
|
||||
|
||||
const toggleOutline = (checked: boolean) => {
|
||||
if (!handleElement.value) return
|
||||
if (checked) {
|
||||
const props = { outline: { width: 2, color: '#000', style: 'solid' } }
|
||||
store.commit(MutationTypes.UPDATE_ELEMENT, { id: handleElement.value.id, props })
|
||||
const _outline: PPTElementOutline = { width: 2, color: '#000', style: 'solid' }
|
||||
slidesStore.updateElement({ id: handleElement.value.id, props: { outline: _outline } })
|
||||
}
|
||||
else {
|
||||
store.commit(MutationTypes.REMOVE_ELEMENT_PROPS, { id: handleElement.value.id, propName: 'outline' })
|
||||
slidesStore.removeElementProps({ id: handleElement.value.id, propName: 'outline' })
|
||||
}
|
||||
addHistorySnapshot()
|
||||
}
|
||||
|
@ -57,9 +57,10 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, ref, watch } from 'vue'
|
||||
import { MutationTypes, useStore } from '@/store'
|
||||
import { PPTElement, PPTElementShadow } from '@/types/slides'
|
||||
import { defineComponent, ref, watch } from 'vue'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useMainStore, useSlidesStore } from '@/store'
|
||||
import { PPTElementShadow } from '@/types/slides'
|
||||
import useHistorySnapshot from '@/hooks/useHistorySnapshot'
|
||||
|
||||
import ColorButton from './ColorButton.vue'
|
||||
@ -70,8 +71,8 @@ export default defineComponent({
|
||||
ColorButton,
|
||||
},
|
||||
setup() {
|
||||
const store = useStore()
|
||||
const handleElement = computed<PPTElement>(() => store.getters.handleElement)
|
||||
const slidesStore = useSlidesStore()
|
||||
const { handleElement } = storeToRefs(useMainStore())
|
||||
|
||||
const shadow = ref<PPTElementShadow>()
|
||||
const hasShadow = ref(false)
|
||||
@ -85,18 +86,20 @@ export default defineComponent({
|
||||
const { addHistorySnapshot } = useHistorySnapshot()
|
||||
|
||||
const updateShadow = (shadowProps: Partial<PPTElementShadow>) => {
|
||||
const props = { shadow: { ...shadow.value, ...shadowProps } }
|
||||
store.commit(MutationTypes.UPDATE_ELEMENT, { id: handleElement.value.id, props })
|
||||
if (!handleElement.value || !shadow.value) return
|
||||
const _shadow = { ...shadow.value, ...shadowProps }
|
||||
slidesStore.updateElement({ id: handleElement.value.id, props: { shadow: _shadow } })
|
||||
addHistorySnapshot()
|
||||
}
|
||||
|
||||
const toggleShadow = (checked: boolean) => {
|
||||
if (!handleElement.value) return
|
||||
if (checked) {
|
||||
const props = { shadow: { h: 1, v: 1, blur: 2, color: '#000' } }
|
||||
store.commit(MutationTypes.UPDATE_ELEMENT, { id: handleElement.value.id, props })
|
||||
const _shadow: PPTElementShadow = { h: 1, v: 1, blur: 2, color: '#000' }
|
||||
slidesStore.updateElement({ id: handleElement.value.id, props: { shadow: _shadow } })
|
||||
}
|
||||
else {
|
||||
store.commit(MutationTypes.REMOVE_ELEMENT_PROPS, { id: handleElement.value.id, propName: 'shadow' })
|
||||
slidesStore.removeElementProps({ id: handleElement.value.id, propName: 'shadow' })
|
||||
}
|
||||
addHistorySnapshot()
|
||||
}
|
||||
|
@ -17,8 +17,8 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, watch } from 'vue'
|
||||
import { MutationTypes, useStore } from '@/store'
|
||||
import { PPTElement } from '@/types/slides'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useMainStore } from '@/store'
|
||||
import { ToolbarState, ToolbarStates } from '@/types/toolbar'
|
||||
|
||||
import ElementStylePanel from './ElementStylePanel/index.vue'
|
||||
@ -29,14 +29,18 @@ import SlideAnimationPanel from './SlideAnimationPanel.vue'
|
||||
import MultiPositionPanel from './MultiPositionPanel.vue'
|
||||
import SymbolPanel from './SymbolPanel.vue'
|
||||
|
||||
interface ElementTabs {
|
||||
label: string;
|
||||
value: ToolbarState;
|
||||
}
|
||||
|
||||
export default defineComponent({
|
||||
name: 'toolbar',
|
||||
setup() {
|
||||
const store = useStore()
|
||||
const toolbarState = computed(() => store.state.toolbarState)
|
||||
const handleElement = computed<PPTElement>(() => store.getters.handleElement)
|
||||
const mainStore = useMainStore()
|
||||
const { activeElementIdList, handleElement, toolbarState } = storeToRefs(mainStore)
|
||||
|
||||
const elementTabs = computed(() => {
|
||||
const elementTabs = computed<ElementTabs[]>(() => {
|
||||
if (handleElement.value?.type === 'text') {
|
||||
return [
|
||||
{ label: '样式', value: ToolbarStates.EL_STYLE },
|
||||
@ -62,10 +66,9 @@ export default defineComponent({
|
||||
]
|
||||
|
||||
const setToolbarState = (value: ToolbarState) => {
|
||||
store.commit(MutationTypes.SET_TOOLBAR_STATE, value)
|
||||
mainStore.setToolbarState(value)
|
||||
}
|
||||
|
||||
const activeElementIdList = computed(() => store.state.activeElementIdList)
|
||||
const currentTabs = computed(() => {
|
||||
if (!activeElementIdList.value.length) return slideTabs
|
||||
else if (activeElementIdList.value.length > 1) return multiSelectTabs
|
||||
@ -73,9 +76,9 @@ export default defineComponent({
|
||||
})
|
||||
|
||||
watch(currentTabs, () => {
|
||||
const currentTabsValue = currentTabs.value.map(tab => tab.value)
|
||||
const currentTabsValue: ToolbarState[] = currentTabs.value.map(tab => tab.value)
|
||||
if (!currentTabsValue.includes(toolbarState.value)) {
|
||||
store.commit(MutationTypes.SET_TOOLBAR_STATE, currentTabsValue[0])
|
||||
mainStore.setToolbarState(currentTabsValue[0])
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -21,8 +21,9 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, PropType } from 'vue'
|
||||
import { useStore } from '@/store'
|
||||
import { ElementTypes, PPTElement, Slide } from '@/types/slides'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useSlidesStore } from '@/store'
|
||||
import { ElementTypes, PPTElement } from '@/types/slides'
|
||||
|
||||
import BaseImageElement from '@/views/components/element/ImageElement/BaseImageElement.vue'
|
||||
import BaseTextElement from '@/views/components/element/TextElement/BaseTextElement.vue'
|
||||
@ -64,9 +65,7 @@ export default defineComponent({
|
||||
return elementTypeMap[props.elementInfo.type] || null
|
||||
})
|
||||
|
||||
const store = useStore()
|
||||
const theme = computed(() => store.state.theme)
|
||||
const currentSlide = computed<Slide>(() => store.getters.currentSlide)
|
||||
const { currentSlide, theme } = storeToRefs(useSlidesStore())
|
||||
|
||||
// 判断元素是否需要等待执行入场动画:等待执行的元素需要先隐藏
|
||||
const needWaitAnimation = computed(() => {
|
||||
|
@ -20,7 +20,8 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, PropType, defineComponent } from 'vue'
|
||||
import { useStore } from '@/store'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useSlidesStore } from '@/store'
|
||||
import { Slide } from '@/types/slides'
|
||||
import { VIEWPORT_SIZE } from '@/configs/canvas'
|
||||
import useSlideBackgroundStyle from '@/hooks/useSlideBackgroundStyle'
|
||||
@ -47,8 +48,7 @@ export default defineComponent({
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const store = useStore()
|
||||
const viewportRatio = computed(() => store.state.viewportRatio)
|
||||
const { viewportRatio } = storeToRefs(useSlidesStore())
|
||||
|
||||
const background = computed(() => props.slide.background)
|
||||
const { backgroundStyle } = useSlideBackgroundStyle(background)
|
||||
|
@ -18,8 +18,9 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, PropType } from 'vue'
|
||||
import { useStore } from '@/store'
|
||||
import { defineComponent, PropType } from 'vue'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useSlidesStore } from '@/store'
|
||||
|
||||
import ThumbnailSlide from '@/views/components/ThumbnailSlide/index.vue'
|
||||
|
||||
@ -35,9 +36,7 @@ export default defineComponent({
|
||||
},
|
||||
},
|
||||
setup(props, { emit }) {
|
||||
const store = useStore()
|
||||
const slides = computed(() => store.state.slides)
|
||||
const slideIndex = computed(() => store.state.slideIndex)
|
||||
const { slides, slideIndex } = storeToRefs(useSlidesStore())
|
||||
|
||||
const close = () => emit('close')
|
||||
|
||||
|
@ -60,8 +60,8 @@
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, onMounted, onUnmounted, provide, ref } from 'vue'
|
||||
import { throttle } from 'lodash'
|
||||
import { MutationTypes, useStore } from '@/store'
|
||||
import { Slide } from '@/types/slides'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useSlidesStore } from '@/store'
|
||||
import { VIEWPORT_SIZE } from '@/configs/canvas'
|
||||
import { KEYS } from '@/configs/hotkey'
|
||||
import { ContextmenuItem } from '@/components/Contextmenu/types'
|
||||
@ -82,11 +82,8 @@ export default defineComponent({
|
||||
WritingBoardTool,
|
||||
},
|
||||
setup() {
|
||||
const store = useStore()
|
||||
const slides = computed(() => store.state.slides)
|
||||
const slideIndex = computed(() => store.state.slideIndex)
|
||||
const viewportRatio = computed(() => store.state.viewportRatio)
|
||||
const currentSlide = computed<Slide>(() => store.getters.currentSlide)
|
||||
const slidesStore = useSlidesStore()
|
||||
const { slides, slideIndex, currentSlide, viewportRatio } = storeToRefs(slidesStore)
|
||||
|
||||
const slideWidth = ref(0)
|
||||
const slideHeight = ref(0)
|
||||
@ -184,7 +181,7 @@ export default defineComponent({
|
||||
animationIndex.value -= 1
|
||||
}
|
||||
else if (slideIndex.value > 0) {
|
||||
store.commit(MutationTypes.UPDATE_SLIDE_INDEX, slideIndex.value - 1)
|
||||
slidesStore.updateSlideIndex(slideIndex.value - 1)
|
||||
const lastIndex = animations.value ? animations.value.length : 0
|
||||
animationIndex.value = lastIndex
|
||||
}
|
||||
@ -197,7 +194,7 @@ export default defineComponent({
|
||||
runAnimation()
|
||||
}
|
||||
else if (slideIndex.value < slides.value.length - 1) {
|
||||
store.commit(MutationTypes.UPDATE_SLIDE_INDEX, slideIndex.value + 1)
|
||||
slidesStore.updateSlideIndex(slideIndex.value + 1)
|
||||
animationIndex.value = 0
|
||||
}
|
||||
else {
|
||||
@ -263,18 +260,18 @@ export default defineComponent({
|
||||
|
||||
// 切换到上一张/上一张幻灯片(无视元素的入场动画)
|
||||
const turnPrevSlide = () => {
|
||||
store.commit(MutationTypes.UPDATE_SLIDE_INDEX, slideIndex.value - 1)
|
||||
slidesStore.updateSlideIndex(slideIndex.value - 1)
|
||||
animationIndex.value = 0
|
||||
}
|
||||
const turnNextSlide = () => {
|
||||
store.commit(MutationTypes.UPDATE_SLIDE_INDEX, slideIndex.value + 1)
|
||||
slidesStore.updateSlideIndex(slideIndex.value + 1)
|
||||
animationIndex.value = 0
|
||||
}
|
||||
|
||||
// 切换幻灯片到指定的页面
|
||||
const turnSlideToIndex = (index: number) => {
|
||||
slideThumbnailModelVisible.value = false
|
||||
store.commit(MutationTypes.UPDATE_SLIDE_INDEX, index)
|
||||
slidesStore.updateSlideIndex(index)
|
||||
animationIndex.value = 0
|
||||
}
|
||||
|
||||
|
@ -26,7 +26,8 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, PropType, defineComponent } from 'vue'
|
||||
import { useStore } from '@/store'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useSlidesStore } from '@/store'
|
||||
import { Slide } from '@/types/slides'
|
||||
import { VIEWPORT_SIZE } from '@/configs/canvas'
|
||||
import useSlideBackgroundStyle from '@/hooks/useSlideBackgroundStyle'
|
||||
@ -49,8 +50,7 @@ export default defineComponent({
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const store = useStore()
|
||||
const viewportRatio = computed(() => store.state.viewportRatio)
|
||||
const { viewportRatio } = storeToRefs(useSlidesStore())
|
||||
|
||||
const background = computed(() => props.slide.background)
|
||||
const { backgroundStyle } = useSlideBackgroundStyle(background)
|
||||
|
@ -67,7 +67,8 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, onMounted, onUnmounted, PropType, reactive, ref } from 'vue'
|
||||
import { useStore } from '@/store'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useMainStore, useKeyboardStore } from '@/store'
|
||||
import { KEYS } from '@/configs/hotkey'
|
||||
import { ImageClipData, ImageClipDataRange, ImageClipedEmitData } from '@/types/edit'
|
||||
|
||||
@ -106,9 +107,8 @@ export default defineComponent({
|
||||
},
|
||||
},
|
||||
setup(props, { emit }) {
|
||||
const store = useStore()
|
||||
const canvasScale = computed(() => store.state.canvasScale)
|
||||
const ctrlOrShiftKeyActive = computed<boolean>(() => store.getters.ctrlOrShiftKeyActive)
|
||||
const { canvasScale } = storeToRefs(useMainStore())
|
||||
const { ctrlOrShiftKeyActive } = storeToRefs(useKeyboardStore())
|
||||
|
||||
const clipWrapperPositionStyle = reactive({
|
||||
top: '0',
|
||||
|
@ -58,7 +58,8 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, PropType } from 'vue'
|
||||
import { MutationTypes, useStore } from '@/store'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useMainStore, useSlidesStore } from '@/store'
|
||||
import { ImageElementClip, PPTImageElement } from '@/types/slides'
|
||||
import { ImageClipedEmitData } from '@/types/edit'
|
||||
import { ContextmenuItem } from '@/components/Contextmenu/types'
|
||||
@ -91,8 +92,10 @@ export default defineComponent({
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const store = useStore()
|
||||
const clipingImageElementId = computed(() => store.state.clipingImageElementId)
|
||||
const mainStore = useMainStore()
|
||||
const slidesStore = useSlidesStore()
|
||||
const { clipingImageElementId } = storeToRefs(mainStore)
|
||||
|
||||
const isCliping = computed(() => clipingImageElementId.value === props.elementInfo.id)
|
||||
|
||||
const { addHistorySnapshot } = useHistorySnapshot()
|
||||
@ -117,7 +120,7 @@ export default defineComponent({
|
||||
}
|
||||
|
||||
const handleClip = (data: ImageClipedEmitData) => {
|
||||
store.commit(MutationTypes.SET_CLIPING_IMAGE_ELEMENT_ID, '')
|
||||
mainStore.setClipingImageElementId('')
|
||||
|
||||
if (!data) return
|
||||
|
||||
@ -131,7 +134,7 @@ export default defineComponent({
|
||||
width: props.elementInfo.width + position.width,
|
||||
height: props.elementInfo.height + position.height,
|
||||
}
|
||||
store.commit(MutationTypes.UPDATE_ELEMENT, { id: props.elementInfo.id, props: _props })
|
||||
slidesStore.updateElement({ id: props.elementInfo.id, props: _props })
|
||||
|
||||
addHistorySnapshot()
|
||||
}
|
||||
|
@ -8,7 +8,8 @@
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, onMounted, onUnmounted, ref, watch } from 'vue'
|
||||
import { debounce } from 'lodash'
|
||||
import { MutationTypes, useStore } from '@/store'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useMainStore } from '@/store'
|
||||
import { EditorView } from 'prosemirror-view'
|
||||
import { toggleMark, wrapIn, selectAll } from 'prosemirror-commands'
|
||||
import { initProsemirrorEditor, createDocument } from '@/utils/prosemirror'
|
||||
@ -47,8 +48,8 @@ export default defineComponent({
|
||||
},
|
||||
},
|
||||
setup(props, { emit }) {
|
||||
const store = useStore()
|
||||
const handleElementId = computed(() => store.state.handleElementId)
|
||||
const mainStore = useMainStore()
|
||||
const { handleElementId } = storeToRefs(mainStore)
|
||||
|
||||
const editorViewRef = ref<HTMLElement>()
|
||||
let editorView: EditorView
|
||||
@ -67,12 +68,12 @@ export default defineComponent({
|
||||
selectAll(editorView.state, editorView.dispatch)
|
||||
}, 0)
|
||||
}
|
||||
store.commit(MutationTypes.SET_DISABLE_HOTKEYS_STATE, true)
|
||||
mainStore.setDisableHotkeysState(true)
|
||||
emit('focus')
|
||||
}
|
||||
|
||||
const handleBlur = () => {
|
||||
store.commit(MutationTypes.SET_DISABLE_HOTKEYS_STATE, false)
|
||||
mainStore.setDisableHotkeysState(false)
|
||||
emit('blur')
|
||||
}
|
||||
|
||||
@ -81,7 +82,7 @@ export default defineComponent({
|
||||
color: props.defaultColor,
|
||||
fontname: props.defaultFontName,
|
||||
})
|
||||
store.commit(MutationTypes.SET_RICHTEXT_ATTRS, attrs)
|
||||
mainStore.setRichtextAttrs(attrs)
|
||||
}, 30, { trailing: true })
|
||||
|
||||
const handleKeydown = () => {
|
||||
|
@ -82,7 +82,8 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, PropType, ref, watch } from 'vue'
|
||||
import { MutationTypes, useStore } from '@/store'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useMainStore, useSlidesStore } from '@/store'
|
||||
import { PPTShapeElement, ShapeText } from '@/types/slides'
|
||||
import { ContextmenuItem } from '@/components/Contextmenu/types'
|
||||
import useElementOutline from '@/views/components/element/hooks/useElementOutline'
|
||||
@ -113,7 +114,9 @@ export default defineComponent({
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const store = useStore()
|
||||
const mainStore = useMainStore()
|
||||
const slidesStore = useSlidesStore()
|
||||
const { handleElementId } = storeToRefs(mainStore)
|
||||
|
||||
const { addHistorySnapshot } = useHistorySnapshot()
|
||||
|
||||
@ -138,15 +141,14 @@ export default defineComponent({
|
||||
|
||||
const enterEditing = () => {
|
||||
editable.value = true
|
||||
store.commit(MutationTypes.SET_EDITING_SHAPE_ELEMENT_ID, props.elementInfo.id)
|
||||
mainStore.setEditingShapeElementId(props.elementInfo.id)
|
||||
}
|
||||
|
||||
const exitEditing = () => {
|
||||
editable.value = false
|
||||
store.commit(MutationTypes.SET_EDITING_SHAPE_ELEMENT_ID, '')
|
||||
mainStore.setEditingShapeElementId('')
|
||||
}
|
||||
|
||||
const handleElementId = computed(() => store.state.handleElementId)
|
||||
watch(handleElementId, () => {
|
||||
if (handleElementId.value !== props.elementInfo.id) {
|
||||
if (editable.value) exitEditing()
|
||||
@ -167,7 +169,7 @@ export default defineComponent({
|
||||
|
||||
const updateText = (content: string) => {
|
||||
const _text = { ...text.value, content }
|
||||
store.commit(MutationTypes.UPDATE_ELEMENT, {
|
||||
slidesStore.updateElement({
|
||||
id: props.elementInfo.id,
|
||||
props: { text: _text },
|
||||
})
|
||||
|
@ -69,7 +69,8 @@
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, nextTick, onMounted, onUnmounted, PropType, ref, watch } from 'vue'
|
||||
import { debounce, isEqual } from 'lodash'
|
||||
import { useStore } from '@/store'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useMainStore } from '@/store'
|
||||
import { PPTElementOutline, TableCell, TableTheme } from '@/types/slides'
|
||||
import { ContextmenuItem } from '@/components/Contextmenu/types'
|
||||
import { KEYS } from '@/configs/hotkey'
|
||||
@ -112,8 +113,7 @@ export default defineComponent({
|
||||
},
|
||||
},
|
||||
setup(props, { emit }) {
|
||||
const store = useStore()
|
||||
const canvasScale = computed(() => store.state.canvasScale)
|
||||
const { canvasScale } = storeToRefs(useMainStore())
|
||||
|
||||
const isStartSelect = ref(false)
|
||||
const startCell = ref<number[]>([])
|
||||
|
@ -44,8 +44,9 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, nextTick, onMounted, onUnmounted, PropType, ref, watch } from 'vue'
|
||||
import { MutationTypes, useStore } from '@/store'
|
||||
import { defineComponent, nextTick, onMounted, onUnmounted, PropType, ref, watch } from 'vue'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useMainStore, useSlidesStore } from '@/store'
|
||||
import { PPTTableElement, TableCell } from '@/types/slides'
|
||||
import { ContextmenuItem } from '@/components/Contextmenu/types'
|
||||
import useHistorySnapshot from '@/hooks/useHistorySnapshot'
|
||||
@ -71,9 +72,9 @@ export default defineComponent({
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const store = useStore()
|
||||
const canvasScale = computed(() => store.state.canvasScale)
|
||||
const handleElementId = computed(() => store.state.handleElementId)
|
||||
const mainStore = useMainStore()
|
||||
const slidesStore = useSlidesStore()
|
||||
const { canvasScale, handleElementId, isScaling } = storeToRefs(mainStore)
|
||||
|
||||
const elementRef = ref<HTMLElement>()
|
||||
|
||||
@ -94,7 +95,7 @@ export default defineComponent({
|
||||
})
|
||||
|
||||
watch(editable, () => {
|
||||
store.commit(MutationTypes.SET_DISABLE_HOTKEYS_STATE, editable.value)
|
||||
mainStore.setDisableHotkeysState(editable.value)
|
||||
})
|
||||
|
||||
const startEdit = () => {
|
||||
@ -105,15 +106,13 @@ export default defineComponent({
|
||||
// 如果高度变化时正处在缩放操作中,则等待缩放操作结束后再更新
|
||||
const realHeightCache = ref(-1)
|
||||
|
||||
const isScaling = computed(() => store.state.isScaling)
|
||||
|
||||
watch(isScaling, () => {
|
||||
if (handleElementId.value !== props.elementInfo.id) return
|
||||
|
||||
if (isScaling.value) editable.value = false
|
||||
|
||||
if (!isScaling.value && realHeightCache.value !== -1) {
|
||||
store.commit(MutationTypes.UPDATE_ELEMENT, {
|
||||
slidesStore.updateElement({
|
||||
id: props.elementInfo.id,
|
||||
props: { height: realHeightCache.value },
|
||||
})
|
||||
@ -129,7 +128,7 @@ export default defineComponent({
|
||||
|
||||
if (props.elementInfo.height !== realHeight) {
|
||||
if (!isScaling.value) {
|
||||
store.commit(MutationTypes.UPDATE_ELEMENT, {
|
||||
slidesStore.updateElement({
|
||||
id: props.elementInfo.id,
|
||||
props: { height: realHeight },
|
||||
})
|
||||
@ -149,7 +148,7 @@ export default defineComponent({
|
||||
|
||||
// 更新表格内容数据
|
||||
const updateTableCells = (data: TableCell[][]) => {
|
||||
store.commit(MutationTypes.UPDATE_ELEMENT, {
|
||||
slidesStore.updateElement({
|
||||
id: props.elementInfo.id,
|
||||
props: { data },
|
||||
})
|
||||
@ -161,7 +160,7 @@ export default defineComponent({
|
||||
const width = widths.reduce((a, b) => a + b)
|
||||
const colWidths = widths.map(item => item / width)
|
||||
|
||||
store.commit(MutationTypes.UPDATE_ELEMENT, {
|
||||
slidesStore.updateElement({
|
||||
id: props.elementInfo.id,
|
||||
props: { width, colWidths },
|
||||
})
|
||||
@ -170,7 +169,7 @@ export default defineComponent({
|
||||
|
||||
// 更新表格当前选中的单元格
|
||||
const updateSelectedCells = (cells: string[]) => {
|
||||
nextTick(() => store.commit(MutationTypes.SET_SELECTED_TABLE_CELLS, cells))
|
||||
nextTick(() => mainStore.setSelectedTableCells(cells))
|
||||
}
|
||||
|
||||
return {
|
||||
|
@ -49,7 +49,8 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, onMounted, onUnmounted, PropType, ref, watch } from 'vue'
|
||||
import { MutationTypes, useStore } from '@/store'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useMainStore, useSlidesStore } from '@/store'
|
||||
import { PPTTextElement } from '@/types/slides'
|
||||
import { ContextmenuItem } from '@/components/Contextmenu/types'
|
||||
import useElementShadow from '@/views/components/element/hooks/useElementShadow'
|
||||
@ -78,7 +79,10 @@ export default defineComponent({
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const store = useStore()
|
||||
const mainStore = useMainStore()
|
||||
const slidesStore = useSlidesStore()
|
||||
const { handleElementId, isScaling } = storeToRefs(mainStore)
|
||||
|
||||
const { addHistorySnapshot } = useHistorySnapshot()
|
||||
|
||||
const elementRef = ref<HTMLElement>()
|
||||
@ -86,8 +90,6 @@ export default defineComponent({
|
||||
const shadow = computed(() => props.elementInfo.shadow)
|
||||
const { shadowStyle } = useElementShadow(shadow)
|
||||
|
||||
const handleElementId = computed(() => store.state.handleElementId)
|
||||
|
||||
const handleSelectElement = (e: MouseEvent, canMove = true) => {
|
||||
if (props.elementInfo.lock) return
|
||||
e.stopPropagation()
|
||||
@ -99,13 +101,11 @@ export default defineComponent({
|
||||
// 如果高度变化时正处在缩放操作中,则等待缩放操作结束后再更新
|
||||
const realHeightCache = ref(-1)
|
||||
|
||||
const isScaling = computed(() => store.state.isScaling)
|
||||
|
||||
watch(isScaling, () => {
|
||||
if (handleElementId.value !== props.elementInfo.id) return
|
||||
|
||||
if (!isScaling.value && realHeightCache.value !== -1) {
|
||||
store.commit(MutationTypes.UPDATE_ELEMENT, {
|
||||
slidesStore.updateElement({
|
||||
id: props.elementInfo.id,
|
||||
props: { height: realHeightCache.value },
|
||||
})
|
||||
@ -121,7 +121,7 @@ export default defineComponent({
|
||||
|
||||
if (props.elementInfo.height !== realHeight) {
|
||||
if (!isScaling.value) {
|
||||
store.commit(MutationTypes.UPDATE_ELEMENT, {
|
||||
slidesStore.updateElement({
|
||||
id: props.elementInfo.id,
|
||||
props: { height: realHeight },
|
||||
})
|
||||
@ -139,8 +139,8 @@ export default defineComponent({
|
||||
})
|
||||
|
||||
const updateContent = (content: string) => {
|
||||
store.commit(MutationTypes.UPDATE_ELEMENT, {
|
||||
id: props.elementInfo.id,
|
||||
slidesStore.updateElement({
|
||||
id: props.elementInfo.id,
|
||||
props: { content },
|
||||
})
|
||||
|
||||
|
@ -22,7 +22,7 @@
|
||||
:height="elementInfo.height"
|
||||
:src="elementInfo.src"
|
||||
:poster="elementInfo.poster"
|
||||
:scale="scale"
|
||||
:scale="canvasScale"
|
||||
/>
|
||||
<div
|
||||
:class="['handler-border', item]"
|
||||
@ -36,8 +36,9 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, PropType } from 'vue'
|
||||
import { useStore } from '@/store'
|
||||
import { defineComponent, PropType } from 'vue'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useMainStore } from '@/store'
|
||||
import { PPTVideoElement } from '@/types/slides'
|
||||
import { ContextmenuItem } from '@/components/Contextmenu/types'
|
||||
|
||||
@ -62,8 +63,7 @@ export default defineComponent({
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const store = useStore()
|
||||
const scale = computed(() => store.state.canvasScale)
|
||||
const { canvasScale } = storeToRefs(useMainStore())
|
||||
|
||||
const handleSelectElement = (e: MouseEvent, canMove = true) => {
|
||||
if (props.elementInfo.lock) return
|
||||
@ -73,7 +73,7 @@ export default defineComponent({
|
||||
}
|
||||
|
||||
return {
|
||||
scale,
|
||||
canvasScale,
|
||||
handleSelectElement,
|
||||
}
|
||||
},
|
||||
|
@ -23,13 +23,6 @@ module.exports = {
|
||||
},
|
||||
},
|
||||
},
|
||||
chainWebpack: config => {
|
||||
config.module
|
||||
.rule('images')
|
||||
.use('url-loader')
|
||||
.loader('url-loader')
|
||||
.tap(options => Object.assign(options, { limit: 5120 }))
|
||||
},
|
||||
configureWebpack: {
|
||||
plugins: [
|
||||
new StyleLintPlugin({
|
||||
|
Loading…
x
Reference in New Issue
Block a user