diff --git a/src/router/index.ts b/src/router/index.ts index 86775c3..ad185de 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -19,4 +19,10 @@ const router = createRouter({ routes, }) +router.beforeEach((to, from) => { + if(to.name === 'Player' && from.name !== 'Editor') { + return router.push({ path: '/' }) + } +}) + export default router diff --git a/src/store/constants.ts b/src/store/constants.ts index 1d155cc..c7d9d15 100644 --- a/src/store/constants.ts +++ b/src/store/constants.ts @@ -5,9 +5,9 @@ export enum MutationTypes { SET_HANDLE_ELEMENT_ID = 'setHandleElementId', SET_EDITOR_AREA_SHOW_SCALE = 'setEditorAreaShowScale', SET_CANVAS_SCALE = 'setCanvasScale', - TOGGLE_SHOW_GRID_LINES = 'toggleShowGridLines', SET_THUMBNAILS_FOCUS = 'setThumbnailsFocus', SET_EDITORAREA_FOCUS = 'setEditorAreaFocus', + SET_DISABLE_HOTKEYS_STATE = 'setDisableHotkeysState', SET_AVAILABLE_FONTS = 'setAvailableFonts', SET_SAVE_STATE = 'setSaveState', diff --git a/src/store/getters.ts b/src/store/getters.ts index 6454657..34f4510 100644 --- a/src/store/getters.ts +++ b/src/store/getters.ts @@ -1,7 +1,9 @@ -import { PPTElement } from '@/types/slides' +import { PPTElement, Slide, PPTAnimation } from '@/types/slides' import { State } from './state' export type Getters = { + currentSlide(state: State): Slide | null; + currentSlideAnimations(state: State): PPTAnimation[] | null; activeElementList(state: State): PPTElement[]; handleElement(state: State): PPTElement | null; canUndo(state: State): boolean; @@ -9,6 +11,21 @@ export type Getters = { } export const getters: Getters = { + 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.elId) + return animations.filter(animation => elIds.includes(animation.elId)) + }, + activeElementList(state) { const currentSlide = state.slides[state.slideIndex] if(!currentSlide || !currentSlide.elements) return [] diff --git a/src/store/mutations.ts b/src/store/mutations.ts index a9c9154..2290fe0 100644 --- a/src/store/mutations.ts +++ b/src/store/mutations.ts @@ -32,9 +32,9 @@ export type Mutations = { [MutationTypes.SET_HANDLE_ELEMENT_ID](state: State, handleElementId: string): void; [MutationTypes.SET_EDITOR_AREA_SHOW_SCALE](state: State, scale: number): void; [MutationTypes.SET_CANVAS_SCALE](state: State, scale: number): void; - [MutationTypes.TOGGLE_SHOW_GRID_LINES](state: State): void; [MutationTypes.SET_THUMBNAILS_FOCUS](state: State, isFocus: boolean): void; [MutationTypes.SET_EDITORAREA_FOCUS](state: State, isFocus: boolean): void; + [MutationTypes.SET_DISABLE_HOTKEYS_STATE](state: State, disable: boolean): void; [MutationTypes.SET_AVAILABLE_FONTS](state: State): void; [MutationTypes.SET_SAVE_STATE](state: State, saveState: SaveState ): void; [MutationTypes.SET_SLIDES](state: State, slides: Slide[]): void; @@ -75,10 +75,6 @@ export const mutations: Mutations = { state.canvasScale = scale }, - [MutationTypes.TOGGLE_SHOW_GRID_LINES](state) { - state.isShowGridLines = !state.isShowGridLines - }, - [MutationTypes.SET_THUMBNAILS_FOCUS](state, isFocus) { state.thumbnailsFocus = isFocus }, @@ -87,6 +83,10 @@ export const mutations: Mutations = { state.editorAreaFocus = isFocus }, + [MutationTypes.SET_DISABLE_HOTKEYS_STATE](state, disable) { + state.disableHotkeys = disable + }, + [MutationTypes.SET_AVAILABLE_FONTS](state) { state.availableFonts = FONT_NAMES.filter(font => isSupportFontFamily(font.en)) }, diff --git a/src/store/state.ts b/src/store/state.ts index 0d68f61..1f7c5b4 100644 --- a/src/store/state.ts +++ b/src/store/state.ts @@ -7,11 +7,11 @@ export type SaveState = 'complete' | 'pending' export type State = { activeElementIdList: string[]; handleElementId: string; - isShowGridLines: boolean; editorAreaShowScale: number; canvasScale: number; thumbnailsFocus: boolean; editorAreaFocus: boolean; + disableHotkeys: boolean; availableFonts: FontName[]; saveState: SaveState; slides: Slide[]; @@ -23,11 +23,11 @@ export type State = { export const state: State = { activeElementIdList: [], handleElementId: '', - isShowGridLines: false, editorAreaShowScale: 85, canvasScale: 1, thumbnailsFocus: false, editorAreaFocus: false, + disableHotkeys: false, availableFonts: [], saveState: 'complete', slides: slides, diff --git a/src/views/Editor/Canvas/AlignmentLine.vue b/src/views/Editor/Canvas/AlignmentLine.vue index 000f92a..c173850 100644 --- a/src/views/Editor/Canvas/AlignmentLine.vue +++ b/src/views/Editor/Canvas/AlignmentLine.vue @@ -23,6 +23,12 @@ interface Axis { y: number; } +export interface AlignmentLineProps { + type: AlignmentLineType; + axis: Axis; + length: number; +} + export default { name: 'alignment-line', props: { diff --git a/src/views/Editor/Canvas/index.vue b/src/views/Editor/Canvas/index.vue index 10d29a9..0fcc796 100644 --- a/src/views/Editor/Canvas/index.vue +++ b/src/views/Editor/Canvas/index.vue @@ -25,6 +25,16 @@ :height="mouseSelectionState.height" :quadrant="mouseSelectionState.quadrant" /> + + + + @@ -38,13 +48,20 @@ import { ContextmenuItem } from '@/components/Contextmenu/types' import { VIEWPORT_SIZE, VIEWPORT_ASPECT_RATIO } from '@/configs/canvas' import MouseSelection from './MouseSelection.vue' +import SlideBackground from './SlideBackground.vue' +import AlignmentLine, { AlignmentLineProps } from './AlignmentLine.vue' export default defineComponent({ name: 'v-canvas', components: { MouseSelection, + SlideBackground, + AlignmentLine, }, setup() { + const isShowGridLines = ref(false) + const alignmentLines = ref([]) + const viewportStyles = reactive({ width: VIEWPORT_SIZE, height: VIEWPORT_SIZE * VIEWPORT_ASPECT_RATIO, @@ -57,6 +74,8 @@ export default defineComponent({ const canvasScale = ref(1) const store = useStore() + const currentSlide = computed(() => store.getters.currentSlide) + const editorAreaShowScale = computed(() => store.state.editorAreaShowScale) const setViewportSize = () => { if(!canvasRef.value) return @@ -179,9 +198,17 @@ export default defineComponent({ children: [ { text: '打开', + disable: isShowGridLines.value, + icon: isShowGridLines.value ? 'icon-check' : '', + iconPlacehoder: true, + action: () => isShowGridLines.value = true, }, { text: '关闭', + disable: !isShowGridLines.value, + icon: !isShowGridLines.value ? 'icon-check' : '', + iconPlacehoder: true, + action: () => isShowGridLines.value = false, }, ], }, @@ -202,6 +229,9 @@ export default defineComponent({ mouseSelectionState, handleClickBlankArea, removeEditorAreaFocus, + currentSlide, + isShowGridLines, + alignmentLines, contextmenus, } }, diff --git a/src/views/Editor/index.vue b/src/views/Editor/index.vue index c2c4079..83b33c8 100644 --- a/src/views/Editor/index.vue +++ b/src/views/Editor/index.vue @@ -42,6 +42,7 @@ export default defineComponent({ const store = useStore() const editorAreaFocus = computed(() => store.state.editorAreaFocus) const thumbnailsFocus = computed(() => store.state.thumbnailsFocus) + const disableHotkeys = computed(() => store.state.disableHotkeys) const save = () => { message.success('save') @@ -112,15 +113,49 @@ export default defineComponent({ if(shiftKeyDown.value) shiftKeyDown.value = false } + const pasteImageFile = (imageFile: File) => { + console.log(imageFile) + } + + const pasteText = (text: string) => { + console.log(text) + } + + const pasteListener = (e: ClipboardEvent) => { + if(!editorAreaFocus.value && !thumbnailsFocus.value) return + if(disableHotkeys.value) return + + if(!e.clipboardData) return + + const clipboardDataItems = e.clipboardData.items + const clipboardDataFirstItem = clipboardDataItems[0] + + if(!clipboardDataFirstItem) return + + for(const item of clipboardDataItems) { + if(item.kind === 'file' && item.type.indexOf('image') !== -1) { + const imageFile = item.getAsFile() + if(imageFile) pasteImageFile(imageFile) + return + } + } + + if( clipboardDataFirstItem.kind === 'string' && clipboardDataFirstItem.type === 'text/plain' ) { + clipboardDataFirstItem.getAsString(text => pasteText(text)) + } + } + onMounted(() => { document.addEventListener('keydown', keydownListener) document.addEventListener('keyup', keyupListener) window.addEventListener('blur', keyupListener) + document.addEventListener('paste', pasteListener) }) onUnmounted(() => { document.removeEventListener('keydown', keydownListener) document.removeEventListener('keyup', keyupListener) window.removeEventListener('blur', keyupListener) + document.removeEventListener('paste', pasteListener) }) }, })