diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index 3e08aa6..1bddfb5 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -1,9 +1,9 @@
- {#if errorMessage} + {#if exportService.getErrorMessage()}
- {errorMessage} + {exportService.getErrorMessage()}
{/if} diff --git a/src/routes/+page.svelte.old b/src/routes/+page.svelte.old new file mode 100644 index 0000000..a98267b --- /dev/null +++ b/src/routes/+page.svelte.old @@ -0,0 +1,203 @@ + + +
+ + + {#if errorMessage} +
+ {errorMessage} +
+ {/if} + +
+
+ + {#if $uiStore.currentStep === "text"} + + {/if} +
+ + +
+
+ + diff --git a/src/services/exportService.ts b/src/services/exportService.ts new file mode 100644 index 0000000..62f8fb8 --- /dev/null +++ b/src/services/exportService.ts @@ -0,0 +1,55 @@ +import type { Panel } from "../lib/types/panel"; +import { exportService as exportPanelService } from "../lib/services/exportService"; +import { setLoading } from "../stores/uiStore"; + +export class ExportService { + private static instance: ExportService; + private errorMessage: string | null = null; + + private constructor() {} + + static getInstance(): ExportService { + if (!ExportService.instance) { + ExportService.instance = new ExportService(); + } + return ExportService.instance; + } + + getErrorMessage(): string | null { + return this.errorMessage; + } + + setErrorMessage(message: string | null): void { + this.errorMessage = message; + } + + async handleDownload(panel: Panel): Promise { + try { + setLoading(true); + const result = await exportPanelService.exportPanel(panel); + + if (!result.success) { + this.errorMessage = result.error || "Ошибка экспорта панели"; + } + } catch (error) { + this.errorMessage = error instanceof Error ? error.message : "Ошибка экспорта панели"; + } finally { + setLoading(false); + } + } + + async handleDownloadAll(panels: Panel[]): Promise { + try { + setLoading(true); + for (const panel of panels) { + await exportPanelService.exportPanel(panel); + } + } catch (error) { + this.errorMessage = error instanceof Error ? error.message : "Ошибка экспорта панелей"; + } finally { + setLoading(false); + } + } +} + +export const exportService = ExportService.getInstance(); diff --git a/src/services/imageService.ts b/src/services/imageService.ts new file mode 100644 index 0000000..e042f0d --- /dev/null +++ b/src/services/imageService.ts @@ -0,0 +1,45 @@ +import { setCurrentStep } from "../stores/uiStore"; + +export class ImageService { + private static instance: ImageService; + + private constructor() {} + + static getInstance(): ImageService { + if (!ImageService.instance) { + ImageService.instance = new ImageService(); + } + return ImageService.instance; + } + + async loadDefaultBackground(): Promise { + const defaultBackground = "/backgrounds/b1.jpg"; + const response = await fetch(defaultBackground); + if (!response.ok) throw new Error("Не удалось загрузить фоновое изображение"); + const blob = await response.blob(); + return new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.onload = () => resolve(reader.result as string); + reader.onerror = reject; + reader.readAsDataURL(blob); + }); + } + + handleImageUpload(image: string): void { + setCurrentStep("crop"); + } + + handleUploadNewImage(): void { + setCurrentStep("upload"); + } + + handleCropComplete(croppedImage: string): void { + setCurrentStep("text"); + } + + handleCropCancel(): void { + setCurrentStep("text"); + } +} + +export const imageService = ImageService.getInstance(); diff --git a/src/services/panelService.ts b/src/services/panelService.ts new file mode 100644 index 0000000..6442cb7 --- /dev/null +++ b/src/services/panelService.ts @@ -0,0 +1,61 @@ +import type { Panel } from "../lib/types/panel"; +import { createPanelFromText, updatePanelText } from "../stores/panelStore"; + +export class PanelService { + private static instance: PanelService; + + private constructor() {} + + static getInstance(): PanelService { + if (!PanelService.instance) { + PanelService.instance = new PanelService(); + } + return PanelService.instance; + } + + validateText(text: string): boolean { + return text.trim().length > 0; + } + + isDuplicateText(texts: Array<{ id: string; text: string }>, text: string, excludeId?: string): boolean { + return texts.some(t => t.id !== excludeId && t.text === text); + } + + addText(texts: Array<{ id: string; text: string }>, text: string): Array<{ id: string; text: string }> { + if (!this.validateText(text)) return texts; + if (this.isDuplicateText(texts, text)) return texts; + + return [...texts, { id: crypto.randomUUID(), text }]; + } + + updateText(texts: Array<{ id: string; text: string }>, id: string, newText: string): Array<{ id: string; text: string }> { + if (!this.validateText(newText)) return texts; + if (this.isDuplicateText(texts, newText, id)) return texts; + + return texts.map(t => t.id === id ? { ...t, text: newText } : t); + } + + deleteText(texts: Array<{ id: string; text: string }>, id: string): Array<{ id: string; text: string }> { + return texts.filter(t => t.id !== id); + } + + updatePanelsFromTexts(texts: Array<{ id: string; text: string }>, panels: Panel[], backgroundImage: string): Panel[] { + return texts.map(textItem => { + const existingPanel = panels.find(p => p.texts[0]?.text === textItem.text); + if (existingPanel) { + return updatePanelText(existingPanel, textItem.text); + } + return createPanelFromText(backgroundImage, textItem.text); + }); + } + + updatePanelsBackground(panels: Panel[], newBackground: string): Panel[] { + return panels.map(panel => ({ + ...panel, + backgroundImage: newBackground, + updatedAt: new Date(), + })); + } +} + +export const panelService = PanelService.getInstance();