From 763b947e09e55b1b674d668c7cba107dc8c47145 Mon Sep 17 00:00:00 2001 From: zxc <1171051090@qq.com> Date: Sat, 17 May 2025 20:18:10 +0800 Subject: [PATCH 1/3] =?UTF-8?q?feat:=20=E5=AE=9E=E7=8E=B0=E7=BB=84?= =?UTF-8?q?=E5=90=88=E5=8E=9F=E4=BB=B6=E4=BF=9D=E5=AD=98=E8=87=B3=E6=94=B6?= =?UTF-8?q?=E8=97=8F=E5=A4=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/FavoriteComponentsModal.vue | 147 ++++++++++++++++++++ src/hooks/useAIPPT.ts | 2 +- src/hooks/useFavoriteComponents.ts | 26 ++++ src/views/Editor/Canvas/EditableElement.vue | 17 +++ src/views/Editor/Canvas/index.vue | 74 +++++++++- 5 files changed, 264 insertions(+), 2 deletions(-) create mode 100644 src/components/FavoriteComponentsModal.vue create mode 100644 src/hooks/useFavoriteComponents.ts diff --git a/src/components/FavoriteComponentsModal.vue b/src/components/FavoriteComponentsModal.vue new file mode 100644 index 000000000..83a823d48 --- /dev/null +++ b/src/components/FavoriteComponentsModal.vue @@ -0,0 +1,147 @@ + + + + + diff --git a/src/hooks/useAIPPT.ts b/src/hooks/useAIPPT.ts index 9b3400286..b22265595 100644 --- a/src/hooks/useAIPPT.ts +++ b/src/hooks/useAIPPT.ts @@ -102,7 +102,7 @@ export default () => { } const getFontInfo = (htmlString: string) => { - const fontSizeRegex = /font-size:\s*(\d+)\s*px/i + const fontSizeRegex = /font-size:\s*(\d+(?:\.\d+)?)\s*px/i const fontFamilyRegex = /font-family:\s*['"]?([^'";]+)['"]?\s*(?=;|>|$)/i const defaultInfo = { diff --git a/src/hooks/useFavoriteComponents.ts b/src/hooks/useFavoriteComponents.ts new file mode 100644 index 000000000..ba1ff1827 --- /dev/null +++ b/src/hooks/useFavoriteComponents.ts @@ -0,0 +1,26 @@ +import type { PPTElement } from '@/types/slides'; + +const STORAGE_KEY = 'pptist-favorite-components'; + +export default () => { + + const getFavorites = (): PPTElement[][] => { + const favoritesJson = localStorage.getItem(STORAGE_KEY); + return favoritesJson ? JSON.parse(favoritesJson) : []; + }; + + const addFavorite = (elements: PPTElement[]) => { + if (!elements || elements.length === 0) return; + + const favorites = getFavorites(); + favorites.push(elements); + localStorage.setItem(STORAGE_KEY, JSON.stringify(favorites)); + }; + + // TODO: Implement getFavorites and other necessary functions later + + return { + addFavorite, + getFavorites, + }; +}; \ No newline at end of file diff --git a/src/views/Editor/Canvas/EditableElement.vue b/src/views/Editor/Canvas/EditableElement.vue index b191bf0ab..379c480be 100644 --- a/src/views/Editor/Canvas/EditableElement.vue +++ b/src/views/Editor/Canvas/EditableElement.vue @@ -28,6 +28,7 @@ import useOrderElement from '@/hooks/useOrderElement' import useAlignElementToCanvas from '@/hooks/useAlignElementToCanvas' import useCopyAndPasteElement from '@/hooks/useCopyAndPasteElement' import useSelectElement from '@/hooks/useSelectElement' +import useFavoriteComponents from '@/hooks/useFavoriteComponents' import { ElementOrderCommands, ElementAlignCommands } from '@/types/edit' @@ -41,6 +42,9 @@ import LatexElement from '@/views/components/element/LatexElement/index.vue' import VideoElement from '@/views/components/element/VideoElement/index.vue' import AudioElement from '@/views/components/element/AudioElement/index.vue' +import { storeToRefs } from 'pinia' +import { useMainStore } from '@/store' + const props = defineProps<{ elementInfo: PPTElement elementIndex: number @@ -72,6 +76,15 @@ const { lockElement, unlockElement } = useLockElement() const { copyElement, pasteElement, cutElement } = useCopyAndPasteElement() const { selectAllElements } = useSelectElement() +const mainStore = useMainStore() +const { activeElementList } = storeToRefs(mainStore) +const { addFavorite } = useFavoriteComponents() + +const addToFavoritesHandler = () => { + addFavorite(activeElementList.value) + // console.log('Selected elements added to favorites.') +} + const contextmenus = (): ContextmenuItem[] => { if (props.elementInfo.lock) { return [{ @@ -96,6 +109,10 @@ const contextmenus = (): ContextmenuItem[] => { subText: 'Ctrl + V', handler: pasteElement, }, + { + text: '添加到收藏夹', + handler: addToFavoritesHandler, + }, { divider: true }, { text: '水平居中', diff --git a/src/views/Editor/Canvas/index.vue b/src/views/Editor/Canvas/index.vue index 05b06faa4..57913f7fd 100644 --- a/src/views/Editor/Canvas/index.vue +++ b/src/views/Editor/Canvas/index.vue @@ -93,6 +93,13 @@ > + + @@ -126,6 +133,7 @@ import useScaleCanvas from '@/hooks/useScaleCanvas' import useScreening from '@/hooks/useScreening' import useSlideHandler from '@/hooks/useSlideHandler' import useCreateElement from '@/hooks/useCreateElement' +import useFavoriteComponents from '@/hooks/useFavoriteComponents' import EditableElement from './EditableElement.vue' import MouseSelection from './MouseSelection.vue' @@ -138,8 +146,10 @@ import MultiSelectOperate from './Operate/MultiSelectOperate.vue' import Operate from './Operate/index.vue' import LinkDialog from './LinkDialog.vue' import Modal from '@/components/Modal.vue' +import FavoriteComponentsModal from '@/components/FavoriteComponentsModal.vue' const mainStore = useMainStore() +const slidesStore = useSlidesStore() const { activeElementIdList, activeGroupElementId, @@ -153,7 +163,7 @@ const { canvasScale, textFormatPainter, } = storeToRefs(mainStore) -const { currentSlide } = storeToRefs(useSlidesStore()) +const { currentSlide } = storeToRefs(slidesStore) const { ctrlKeyState, spaceKeyState } = storeToRefs(useKeyboardStore()) const viewportRef = ref() @@ -162,6 +172,13 @@ const alignmentLines = ref([]) const linkDialogVisible = ref(false) const openLinkDialog = () => linkDialogVisible.value = true +const favoriteComponentsModalVisible = ref(false) +const favoriteComponents = ref([]) + +watch(favoriteComponentsModalVisible, (newValue) => { + console.log('favoriteComponentsModalVisible changed:', newValue) +}) + watch(handleElementId, () => { mainStore.setActiveGroupElementId('') }) @@ -193,6 +210,8 @@ const { enterScreeningFromStart } = useScreening() const { updateSlideIndex } = useSlideHandler() const { createTextElement, createShapeElement } = useCreateElement() +const { getFavorites } = useFavoriteComponents() + // 组件渲染时,如果存在元素焦点,需要清除 // 这种情况存在于:有焦点元素的情况下进入了放映模式,再退出时,需要清除原先的焦点(因为可能已经切换了页面) onMounted(() => { @@ -299,6 +318,19 @@ const contextmenus = (): ContextmenuItem[] => { subText: 'Ctrl + A', handler: selectAllElements, }, + { + text: '从收藏夹选择', + handler: () => { + const favorites = getFavorites() + if (favorites.length === 0) { + alert('收藏夹中还没有组件。') // Show an alert for now + } + else { + favoriteComponents.value = favorites + favoriteComponentsModalVisible.value = true + } + }, + }, { text: '标尺', subText: showRuler.value ? '√' : '', @@ -343,6 +375,46 @@ const contextmenus = (): ContextmenuItem[] => { ] } +// TODO: Implement function to add selected favorite components to canvas +const addFavoriteComponentsToCanvas = (elements: PPTElement[]) => { + if (!elements || elements.length === 0) return + + const currentElements = JSON.parse(JSON.stringify(currentSlide.value.elements)) + + const newElements: PPTElement[] = [] + const groupIdMap = new Map() // Map original group IDs to new group IDs + + elements.forEach(element => { + const newElement = { ...element } + // Generate a simple unique ID + newElement.id = Date.now().toString() + Math.random().toString(36).substring(2) + + // Handle grouped elements + if (element.groupId) { + if (!groupIdMap.has(element.groupId)) { + // Generate a new group ID for this original group + groupIdMap.set(element.groupId, Date.now().toString() + Math.random().toString(36).substring(2)) + } + newElement.groupId = groupIdMap.get(element.groupId) + } + + // Adjust position (can refine later) + newElement.left = (element.left || 0) + 50 + newElement.top = (element.top || 0) + 50 + + newElements.push(newElement) + }) + + const updatedElements = [...currentElements, ...newElements] + currentSlide.value.elements = updatedElements + + // Select the newly added elements + const newElementIds = newElements.map(el => el.id) + mainStore.setActiveElementIdList(newElementIds) + + favoriteComponentsModalVisible.value = false +} + provide(injectKeySlideScale, canvasScale) From d14de0aba34b9b9c3728584a223552c125e4d93d Mon Sep 17 00:00:00 2001 From: HelloFiona6 <1870341385@qq.com> Date: Thu, 22 May 2025 03:49:36 +0800 Subject: [PATCH 2/3] =?UTF-8?q?feat:=20=E4=BF=9D=E5=AD=98=E5=88=B0?= =?UTF-8?q?=E6=94=B6=E8=97=8F=E5=A4=B9=E7=9A=84=E7=BB=84=E4=BB=B6=E5=8F=AF?= =?UTF-8?q?=E4=BB=A5=E8=87=AA=E8=A1=8C=E5=91=BD=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/FavoriteComponentsModal.vue | 23 ++++----- src/hooks/useFavoriteComponents.ts | 52 +++++++++++++++------ src/views/Editor/Canvas/EditableElement.vue | 9 ++-- 3 files changed, 52 insertions(+), 32 deletions(-) diff --git a/src/components/FavoriteComponentsModal.vue b/src/components/FavoriteComponentsModal.vue index 83a823d48..71b63872a 100644 --- a/src/components/FavoriteComponentsModal.vue +++ b/src/components/FavoriteComponentsModal.vue @@ -12,17 +12,8 @@ :key="index" @click="selectFavorite(favorite)" > - -
- 文本: {{ favorite[0].content.replace(/<[^>]+>/g, '').substring(0, 50) + '...' }} - 图片 - 形状 - 单个元素 ({{ favorite[0].type }}) -
-
- 组合 {{ index + 1 }} ({{ favorite.length }} 个元素) -
- + +
{{ favorite.name }}
@@ -39,9 +30,12 @@ import { ref, watch } from 'vue' import type { PPTElement } from '@/types/slides' +// Assuming FavoriteItem is defined in useFavoriteComponents and includes 'name' +import type { FavoriteItem } from '@/hooks/useFavoriteComponents' + const props = defineProps<{ visible: boolean; - favorites: PPTElement[][]; + favorites: FavoriteItem[]; // Use FavoriteItem type }>() const emit = defineEmits<{ @@ -56,8 +50,9 @@ const closeModal = () => { } // Function to handle favorite selection -const selectFavorite = (favorite: PPTElement[]) => { - emit('select-favorite', favorite) +const selectFavorite = (favorite: FavoriteItem) => { + // Emit the elements array part of the FavoriteItem + emit('select-favorite', favorite.elements) closeModal() } diff --git a/src/hooks/useFavoriteComponents.ts b/src/hooks/useFavoriteComponents.ts index ba1ff1827..349c70cac 100644 --- a/src/hooks/useFavoriteComponents.ts +++ b/src/hooks/useFavoriteComponents.ts @@ -1,26 +1,48 @@ -import type { PPTElement } from '@/types/slides'; +import type { PPTElement } from '@/types/slides' -const STORAGE_KEY = 'pptist-favorite-components'; +const STORAGE_KEY = 'pptist-favorite-components' + +// TODO: Implement this function +const generateSvgPreview = async (elements: PPTElement[]): Promise => { + console.log('Generating SVG preview for:', elements) + // Placeholder implementation + await Promise.resolve() // Add this line + return '' +} + +export interface FavoriteItem { + elements: PPTElement[]; + name: string; + previewSvg?: string; +} export default () => { - const getFavorites = (): PPTElement[][] => { - const favoritesJson = localStorage.getItem(STORAGE_KEY); - return favoritesJson ? JSON.parse(favoritesJson) : []; - }; + const getFavorites = (): FavoriteItem[] => { + const favoritesJson = localStorage.getItem(STORAGE_KEY) + return favoritesJson ? JSON.parse(favoritesJson) : [] + } + + const addFavorite = (elements: PPTElement[], name: string) => { // Remove 'async' here + if (!elements || elements.length === 0 || !name) return + + const favorites = getFavorites() + + const newFavorite: FavoriteItem = { + elements: elements, + name: name, + previewSvg: '', + } - const addFavorite = (elements: PPTElement[]) => { - if (!elements || elements.length === 0) return; + favorites.push(newFavorite) // Remove semicolon here + localStorage.setItem(STORAGE_KEY, JSON.stringify(favorites)) // Remove semicolon here + } - const favorites = getFavorites(); - favorites.push(elements); - localStorage.setItem(STORAGE_KEY, JSON.stringify(favorites)); - }; - // TODO: Implement getFavorites and other necessary functions later + // TODO: Implement other necessary functions later (like removing favorites) return { addFavorite, getFavorites, - }; -}; \ No newline at end of file + } +} \ No newline at end of file diff --git a/src/views/Editor/Canvas/EditableElement.vue b/src/views/Editor/Canvas/EditableElement.vue index 379c480be..92a96a06f 100644 --- a/src/views/Editor/Canvas/EditableElement.vue +++ b/src/views/Editor/Canvas/EditableElement.vue @@ -17,7 +17,7 @@ @@ -114,12 +132,31 @@ const selectFavorite = (favorite: FavoriteItem) => { padding: 10px 0; border-bottom: 1px solid #eee; cursor: pointer; + display: flex; + justify-content: space-between; + align-items: center; } .modal-body li:last-child { border-bottom: none; } +.favorite-name { + flex-grow: 1; +} + +.delete-button { + background: none; + border: none; + color: red; + cursor: pointer; + margin-left: 10px; +} + +.delete-button:hover { + text-decoration: underline; +} + .modal-footer { display: flex; justify-content: flex-end; diff --git a/src/hooks/useFavoriteComponents.ts b/src/hooks/useFavoriteComponents.ts index 349c70cac..be394b63a 100644 --- a/src/hooks/useFavoriteComponents.ts +++ b/src/hooks/useFavoriteComponents.ts @@ -6,7 +6,7 @@ const STORAGE_KEY = 'pptist-favorite-components' const generateSvgPreview = async (elements: PPTElement[]): Promise => { console.log('Generating SVG preview for:', elements) // Placeholder implementation - await Promise.resolve() // Add this line + await Promise.resolve() return '' } @@ -23,26 +23,32 @@ export default () => { return favoritesJson ? JSON.parse(favoritesJson) : [] } - const addFavorite = (elements: PPTElement[], name: string) => { // Remove 'async' here + const addFavorite = (elements: PPTElement[], name: string) => { if (!elements || elements.length === 0 || !name) return const favorites = getFavorites() - + const newFavorite: FavoriteItem = { elements: elements, name: name, previewSvg: '', } - favorites.push(newFavorite) // Remove semicolon here - localStorage.setItem(STORAGE_KEY, JSON.stringify(favorites)) // Remove semicolon here + favorites.push(newFavorite) + localStorage.setItem(STORAGE_KEY, JSON.stringify(favorites)) } + const removeFavorite = (name: string) => { + const favorites = getFavorites() + const updatedFavorites = favorites.filter(favorite => favorite.name !== name) + localStorage.setItem(STORAGE_KEY, JSON.stringify(updatedFavorites)) + } - // TODO: Implement other necessary functions later (like removing favorites) + // TODO: Implement other necessary functions later return { addFavorite, getFavorites, + removeFavorite, } } \ No newline at end of file diff --git a/src/views/Editor/Canvas/EditableElement.vue b/src/views/Editor/Canvas/EditableElement.vue index 92a96a06f..2a9dcdccc 100644 --- a/src/views/Editor/Canvas/EditableElement.vue +++ b/src/views/Editor/Canvas/EditableElement.vue @@ -78,7 +78,7 @@ const { selectAllElements } = useSelectElement() const mainStore = useMainStore() const { activeElementList } = storeToRefs(mainStore) -const { addFavorite } = useFavoriteComponents() +const { addFavorite } = useFavoriteComponents() const addToFavoritesHandler = () => { const favoriteName = prompt('请输入收藏组件的名称:')