refactor: change null to undefined
This commit is contained in:
@@ -40,6 +40,7 @@ interface ImageUploadProps {
|
|||||||
- **Error Handling**: Invalid crop areas ✅
|
- **Error Handling**: Invalid crop areas ✅
|
||||||
|
|
||||||
**Implementation Details:**
|
**Implementation Details:**
|
||||||
|
|
||||||
- Integrated cropperjs v2.1.0 with Web Components
|
- Integrated cropperjs v2.1.0 with Web Components
|
||||||
- Used `$toCanvas()` method to get HTMLCanvasElement
|
- Used `$toCanvas()` method to get HTMLCanvasElement
|
||||||
- Implemented proper error handling with user-friendly messages
|
- Implemented proper error handling with user-friendly messages
|
||||||
@@ -147,7 +148,7 @@ interface Panel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface PanelManagerProps {
|
interface PanelManagerProps {
|
||||||
currentPanel: Panel | null;
|
currentPanel: Panel | undefined;
|
||||||
onPanelUpdate: (panel: Panel) => void;
|
onPanelUpdate: (panel: Panel) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -255,11 +256,11 @@ interface ImageUploadResult {
|
|||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
// Core stores
|
// Core stores
|
||||||
export const panelStore = writable<Panel | null>(null);
|
export const panelStore = writable<Panel | undefined>(undefined);
|
||||||
export const uiStore = writable({
|
export const uiStore = writable({
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
error: null as string | null,
|
error: string | undefined,
|
||||||
currentStep: "upload" as "upload" | "crop" | "text" | "preview",
|
currentStep: "upload" | "crop" | "text" | "preview",
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -359,11 +360,13 @@ _Estimated Duration: 5 weeks_
|
|||||||
**Challenge:** cropperjs v2.x uses Web Components API which differs significantly from v1.x
|
**Challenge:** cropperjs v2.x uses Web Components API which differs significantly from v1.x
|
||||||
|
|
||||||
**Solution:**
|
**Solution:**
|
||||||
|
|
||||||
1. Used `getCropperCanvas()` to get `<cropper-canvas>` Web Component
|
1. Used `getCropperCanvas()` to get `<cropper-canvas>` Web Component
|
||||||
2. Called `$toCanvas()` method to convert to HTMLCanvasElement
|
2. Called `$toCanvas()` method to convert to HTMLCanvasElement
|
||||||
3. Applied `toDataURL()` on the resulting canvas to get base64 image
|
3. Applied `toDataURL()` on the resulting canvas to get base64 image
|
||||||
|
|
||||||
**Code Example:**
|
**Code Example:**
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
const cropperCanvasElement = cropper.getCropperCanvas();
|
const cropperCanvasElement = cropper.getCropperCanvas();
|
||||||
const canvas = await cropperCanvasElement.$toCanvas({
|
const canvas = await cropperCanvasElement.$toCanvas({
|
||||||
@@ -375,6 +378,7 @@ const croppedImage = canvas.toDataURL("image/png");
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Key Points:**
|
**Key Points:**
|
||||||
|
|
||||||
- cropperjs v2.x methods return Web Components, not standard DOM elements
|
- cropperjs v2.x methods return Web Components, not standard DOM elements
|
||||||
- `$toCanvas()` is an async method that returns HTMLCanvasElement
|
- `$toCanvas()` is an async method that returns HTMLCanvasElement
|
||||||
- Proper error handling is essential for user experience
|
- Proper error handling is essential for user experience
|
||||||
|
|||||||
@@ -4,10 +4,10 @@
|
|||||||
import AppContent from "./AppContent.svelte";
|
import AppContent from "./AppContent.svelte";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
errorMessage: string | null;
|
errorMessage: string | undefined;
|
||||||
uploadedImage: string | null;
|
uploadedImage: string | undefined;
|
||||||
texts: Array<{ id: string; text: string }>;
|
texts: Array<{ id: string; text: string }>;
|
||||||
backgroundImage: string | null;
|
backgroundImage: string | undefined;
|
||||||
panels: any[];
|
panels: any[];
|
||||||
onUploadNewImage: () => void;
|
onUploadNewImage: () => void;
|
||||||
onImageUpload: (image: string) => void;
|
onImageUpload: (image: string) => void;
|
||||||
@@ -34,12 +34,12 @@
|
|||||||
onTextUpdate,
|
onTextUpdate,
|
||||||
onTextDelete,
|
onTextDelete,
|
||||||
onDownload,
|
onDownload,
|
||||||
onDownloadAll
|
onDownloadAll,
|
||||||
}: Props = $props();
|
}: Props = $props();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="app-container">
|
<div class="app-container">
|
||||||
<AppHeader onUploadNewImage={onUploadNewImage} />
|
<AppHeader {onUploadNewImage} />
|
||||||
|
|
||||||
<ErrorMessage {errorMessage} />
|
<ErrorMessage {errorMessage} />
|
||||||
|
|
||||||
@@ -48,15 +48,15 @@
|
|||||||
{texts}
|
{texts}
|
||||||
{backgroundImage}
|
{backgroundImage}
|
||||||
{panels}
|
{panels}
|
||||||
onImageUpload={onImageUpload}
|
{onImageUpload}
|
||||||
onCropComplete={onCropComplete}
|
{onCropComplete}
|
||||||
onCropCancel={onCropCancel}
|
{onCropCancel}
|
||||||
onTextAdd={onTextAdd}
|
{onTextAdd}
|
||||||
onTextUpdate={onTextUpdate}
|
{onTextUpdate}
|
||||||
onTextDelete={onTextDelete}
|
{onTextDelete}
|
||||||
onUploadNewImage={onUploadNewImage}
|
{onUploadNewImage}
|
||||||
onDownload={onDownload}
|
{onDownload}
|
||||||
onDownloadAll={onDownloadAll}
|
{onDownloadAll}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -3,9 +3,9 @@
|
|||||||
import Sidebar from "./Sidebar.svelte";
|
import Sidebar from "./Sidebar.svelte";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
uploadedImage: string | null;
|
uploadedImage: string | undefined;
|
||||||
texts: Array<{ id: string; text: string }>;
|
texts: Array<{ id: string; text: string }>;
|
||||||
backgroundImage: string | null;
|
backgroundImage: string | undefined;
|
||||||
panels: any[];
|
panels: any[];
|
||||||
onImageUpload: (image: string) => void;
|
onImageUpload: (image: string) => void;
|
||||||
onCropComplete: (croppedImage: string) => void;
|
onCropComplete: (croppedImage: string) => void;
|
||||||
@@ -31,7 +31,7 @@
|
|||||||
onTextDelete,
|
onTextDelete,
|
||||||
onUploadNewImage,
|
onUploadNewImage,
|
||||||
onDownload,
|
onDownload,
|
||||||
onDownloadAll
|
onDownloadAll,
|
||||||
}: Props = $props();
|
}: Props = $props();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -39,20 +39,14 @@
|
|||||||
<MainSection
|
<MainSection
|
||||||
{uploadedImage}
|
{uploadedImage}
|
||||||
{texts}
|
{texts}
|
||||||
onImageUpload={onImageUpload}
|
{onImageUpload}
|
||||||
onCropComplete={onCropComplete}
|
{onCropComplete}
|
||||||
onCropCancel={onCropCancel}
|
{onCropCancel}
|
||||||
onTextAdd={onTextAdd}
|
{onTextAdd}
|
||||||
onTextUpdate={onTextUpdate}
|
{onTextUpdate}
|
||||||
onTextDelete={onTextDelete}
|
{onTextDelete}
|
||||||
/>
|
|
||||||
<Sidebar
|
|
||||||
{backgroundImage}
|
|
||||||
{panels}
|
|
||||||
onUploadNewImage={onUploadNewImage}
|
|
||||||
onDownload={onDownload}
|
|
||||||
onDownloadAll={onDownloadAll}
|
|
||||||
/>
|
/>
|
||||||
|
<Sidebar {backgroundImage} {panels} {onUploadNewImage} {onDownload} {onDownloadAll} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
import { Button } from "../lib/components/ui";
|
import { Button } from "../lib/components/ui";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
backgroundImage?: string | null;
|
backgroundImage?: string | undefined;
|
||||||
onUploadNewImage: () => void;
|
onUploadNewImage: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
interface Props {
|
interface Props {
|
||||||
message: string | null;
|
errorMessage: string | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
let { message }: Props = $props();
|
let { errorMessage }: Props = $props();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if message}
|
{#if errorMessage}
|
||||||
<div class="error-message">
|
<div class="error-message">
|
||||||
{message}
|
{errorMessage}
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
|||||||
@@ -15,9 +15,9 @@
|
|||||||
let { imageSrc, onCropComplete, onCancel }: Props = $props();
|
let { imageSrc, onCropComplete, onCancel }: Props = $props();
|
||||||
|
|
||||||
let imageElement: HTMLImageElement;
|
let imageElement: HTMLImageElement;
|
||||||
let cropper: CropperJS | null = null;
|
let cropper: CropperJS | undefined = undefined;
|
||||||
let isProcessing = $state(false);
|
let isProcessing = $state(false);
|
||||||
let errorMessage = $state<string | null>(null);
|
let errorMessage = $state<string | undefined>(undefined);
|
||||||
|
|
||||||
let imageService = new ImageService();
|
let imageService = new ImageService();
|
||||||
|
|
||||||
@@ -46,7 +46,7 @@
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
isProcessing = true;
|
isProcessing = true;
|
||||||
errorMessage = null;
|
errorMessage = undefined;
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
|
|
||||||
console.log("Calling getCropperCanvas");
|
console.log("Calling getCropperCanvas");
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
currentStep: string;
|
currentStep: string;
|
||||||
uploadedImage: string | null;
|
uploadedImage: string | undefined;
|
||||||
onImageUpload: (image: string) => void;
|
onImageUpload: (image: string) => void;
|
||||||
onCropComplete: (croppedImage: string) => void;
|
onCropComplete: (croppedImage: string) => void;
|
||||||
onCropCancel: () => void;
|
onCropCancel: () => void;
|
||||||
|
|||||||
@@ -15,15 +15,15 @@
|
|||||||
|
|
||||||
let { onImageSelect }: Props = $props();
|
let { onImageSelect }: Props = $props();
|
||||||
|
|
||||||
let dropZone = $state<HTMLElement | null>(null);
|
let dropZone = $state<HTMLElement | undefined>(undefined);
|
||||||
let fileInput = $state<HTMLInputElement | null>(null);
|
let fileInput = $state<HTMLInputElement | undefined>(undefined);
|
||||||
let urlInput = $state<HTMLInputElement | null>(null);
|
let urlInput = $state<HTMLInputElement | undefined>(undefined);
|
||||||
let urlForm = $state<HTMLFormElement | null>(null);
|
let urlForm = $state<HTMLFormElement | undefined>(undefined);
|
||||||
|
|
||||||
let isDragOver = $state(false);
|
let isDragOver = $state(false);
|
||||||
let showUrlInput = $state(false);
|
let showUrlInput = $state(false);
|
||||||
let uploadedImage = $state<string | null>(null);
|
let uploadedImage = $state<string | undefined>(undefined);
|
||||||
let errorMessage = $state<string | null>(null);
|
let errorMessage = $state<string | undefined>(undefined);
|
||||||
|
|
||||||
const uiError = $derived($uiStore.error?.error);
|
const uiError = $derived($uiStore.error?.error);
|
||||||
|
|
||||||
@@ -148,8 +148,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function resetUpload() {
|
function resetUpload() {
|
||||||
uploadedImage = null;
|
uploadedImage = undefined;
|
||||||
errorMessage = null;
|
errorMessage = undefined;
|
||||||
showUrlInput = false;
|
showUrlInput = false;
|
||||||
setCurrentStep("upload");
|
setCurrentStep("upload");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
import TextSection from "./TextSection.svelte";
|
import TextSection from "./TextSection.svelte";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
uploadedImage: string | null;
|
uploadedImage: string | undefined;
|
||||||
texts: Array<{ id: string; text: string }>;
|
texts: Array<{ id: string; text: string }>;
|
||||||
onImageUpload: (image: string) => void;
|
onImageUpload: (image: string) => void;
|
||||||
onCropComplete: (croppedImage: string) => void;
|
onCropComplete: (croppedImage: string) => void;
|
||||||
@@ -22,25 +22,14 @@
|
|||||||
onCropCancel,
|
onCropCancel,
|
||||||
onTextAdd,
|
onTextAdd,
|
||||||
onTextUpdate,
|
onTextUpdate,
|
||||||
onTextDelete
|
onTextDelete,
|
||||||
}: Props = $props();
|
}: Props = $props();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="main-section">
|
<div class="main-section">
|
||||||
<ImageManager
|
<ImageManager currentStep={$uiStore.currentStep} {uploadedImage} {onImageUpload} {onCropComplete} {onCropCancel} />
|
||||||
currentStep={$uiStore.currentStep}
|
|
||||||
{uploadedImage}
|
|
||||||
onImageUpload={onImageUpload}
|
|
||||||
onCropComplete={onCropComplete}
|
|
||||||
onCropCancel={onCropCancel}
|
|
||||||
/>
|
|
||||||
{#if $uiStore.currentStep === "text"}
|
{#if $uiStore.currentStep === "text"}
|
||||||
<TextSection
|
<TextSection {texts} {onTextAdd} {onTextUpdate} {onTextDelete} />
|
||||||
{texts}
|
|
||||||
onTextAdd={onTextAdd}
|
|
||||||
onTextUpdate={onTextUpdate}
|
|
||||||
onTextDelete={onTextDelete}
|
|
||||||
/>
|
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -12,8 +12,8 @@
|
|||||||
let { onPanelSelect, onPanelDelete }: Props = $props();
|
let { onPanelSelect, onPanelDelete }: Props = $props();
|
||||||
|
|
||||||
let panels = $state<Panel[]>([]);
|
let panels = $state<Panel[]>([]);
|
||||||
let selectedPanelId = $state<string | null>(null);
|
let selectedPanelId = $state<string | undefined>(undefined);
|
||||||
let errorMessage = $state<string | null>(null);
|
let errorMessage = $state<string | undefined>(undefined);
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
loadPanels();
|
loadPanels();
|
||||||
@@ -21,7 +21,7 @@
|
|||||||
|
|
||||||
function loadPanels() {
|
function loadPanels() {
|
||||||
try {
|
try {
|
||||||
errorMessage = null;
|
errorMessage = undefined;
|
||||||
panels = panelStorage.getAllPanels();
|
panels = panelStorage.getAllPanels();
|
||||||
|
|
||||||
// Если есть текущая панель в store, отмечаем её как выбранную
|
// Если есть текущая панель в store, отмечаем её как выбранную
|
||||||
@@ -41,7 +41,7 @@
|
|||||||
|
|
||||||
function handlePanelDelete(panelId: string) {
|
function handlePanelDelete(panelId: string) {
|
||||||
try {
|
try {
|
||||||
errorMessage = null;
|
errorMessage = undefined;
|
||||||
const result = panelStorage.deletePanel(panelId);
|
const result = panelStorage.deletePanel(panelId);
|
||||||
|
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
@@ -49,7 +49,7 @@
|
|||||||
|
|
||||||
// Если удалили выбранную панель, сбрасываем выбор
|
// Если удалили выбранную панель, сбрасываем выбор
|
||||||
if (selectedPanelId === panelId) {
|
if (selectedPanelId === panelId) {
|
||||||
selectedPanelId = null;
|
selectedPanelId = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Уведомляем родительский компонент
|
// Уведомляем родительский компонент
|
||||||
|
|||||||
@@ -4,33 +4,20 @@
|
|||||||
import PanelsList from "./PanelsList.svelte";
|
import PanelsList from "./PanelsList.svelte";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
backgroundImage: string | null;
|
backgroundImage: string | undefined;
|
||||||
panels: any[];
|
panels: any[];
|
||||||
onUploadNewImage: () => void;
|
onUploadNewImage: () => void;
|
||||||
onDownload: (panel: any) => Promise<void>;
|
onDownload: (panel: any) => Promise<void>;
|
||||||
onDownloadAll: () => Promise<void>;
|
onDownloadAll: () => Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
let {
|
let { backgroundImage, panels, onUploadNewImage, onDownload, onDownloadAll }: Props = $props();
|
||||||
backgroundImage,
|
|
||||||
panels,
|
|
||||||
onUploadNewImage,
|
|
||||||
onDownload,
|
|
||||||
onDownloadAll
|
|
||||||
}: Props = $props();
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="sidebar">
|
<div class="sidebar">
|
||||||
{#if $uiStore.currentStep === "text"}
|
{#if $uiStore.currentStep === "text"}
|
||||||
<BackgroundPreview
|
<BackgroundPreview {backgroundImage} {onUploadNewImage} />
|
||||||
{backgroundImage}
|
<PanelsList {panels} {onDownload} {onDownloadAll} />
|
||||||
onUploadNewImage={onUploadNewImage}
|
|
||||||
/>
|
|
||||||
<PanelsList
|
|
||||||
{panels}
|
|
||||||
onDownload={onDownload}
|
|
||||||
onDownloadAll={onDownloadAll}
|
|
||||||
/>
|
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -11,14 +11,14 @@
|
|||||||
let { onTextAdd, onTextUpdate, onTextDelete, texts }: Props = $props();
|
let { onTextAdd, onTextUpdate, onTextDelete, texts }: Props = $props();
|
||||||
|
|
||||||
let newText = $state("");
|
let newText = $state("");
|
||||||
let errorMessage = $state<string | null>(null);
|
let errorMessage = $state<string | undefined>(undefined);
|
||||||
|
|
||||||
// Общие настройки текста для всех панелей
|
// Общие настройки текста для всех панелей
|
||||||
let commonTextSettings = $state({
|
let commonTextSettings = $state({
|
||||||
fontSize: 18,
|
fontSize: 18,
|
||||||
fontFamily: "Arial",
|
fontFamily: "Arial",
|
||||||
color: "#ffffff",
|
color: "#ffffff",
|
||||||
textAlign: "center" as "left" | "center" | "right",
|
textAlign: "left" | "center" | "right",
|
||||||
paddingX: 10,
|
paddingX: 10,
|
||||||
verticalOffset: 0,
|
verticalOffset: 0,
|
||||||
});
|
});
|
||||||
@@ -47,7 +47,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
errorMessage = null;
|
errorMessage = undefined;
|
||||||
onTextAdd(newText.trim());
|
onTextAdd(newText.trim());
|
||||||
newText = "";
|
newText = "";
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ export class ImageService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Find image item
|
// Find image item
|
||||||
let imageItem: DataTransferItem | null = null;
|
let imageItem: DataTransferItem | undefined = undefined;
|
||||||
for (let i = 0; i < items.length; i++) {
|
for (let i = 0; i < items.length; i++) {
|
||||||
if (items[i].type.indexOf("image") !== -1) {
|
if (items[i].type.indexOf("image") !== -1) {
|
||||||
imageItem = items[i];
|
imageItem = items[i];
|
||||||
@@ -184,6 +184,7 @@ export class ImageService {
|
|||||||
private fileToBase64(file: File): Promise<string> {
|
private fileToBase64(file: File): Promise<string> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const reader = new FileReader();
|
const reader = new FileReader();
|
||||||
|
// TODO: look for a better way to handle errors non strings
|
||||||
reader.onload = () => resolve(reader.result as string);
|
reader.onload = () => resolve(reader.result as string);
|
||||||
reader.onerror = () => reject(new ImageError("Ошибка чтения файла"));
|
reader.onerror = () => reject(new ImageError("Ошибка чтения файла"));
|
||||||
reader.readAsDataURL(file);
|
reader.readAsDataURL(file);
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ export interface ImageCropResult {
|
|||||||
|
|
||||||
export interface UIState {
|
export interface UIState {
|
||||||
isLoading: boolean;
|
isLoading: boolean;
|
||||||
error: string | null;
|
error: string | undefined;
|
||||||
currentStep: "upload" | "crop" | "text" | "preview";
|
currentStep: "upload" | "crop" | "text" | "preview";
|
||||||
showCropModal: boolean;
|
showCropModal: boolean;
|
||||||
showTextManager: boolean;
|
showTextManager: boolean;
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
import type { Panel } from "../types/panel";
|
import type { Panel } from "../types/panel";
|
||||||
import { ImageError } from "../types/errors";
|
import { ImageError } from "../types/errors";
|
||||||
import { handleError, logError } from "./errorHandler";
|
import { handleError, logError } from "./errorHandler";
|
||||||
@@ -72,13 +71,13 @@ export class PanelStorage {
|
|||||||
/**
|
/**
|
||||||
* Загружает панель по ID
|
* Загружает панель по ID
|
||||||
*/
|
*/
|
||||||
getPanelById(id: string): Panel | null {
|
getPanelById(id: string): Panel | undefined {
|
||||||
try {
|
try {
|
||||||
const panels = this.getAllPanels();
|
const panels = this.getAllPanels();
|
||||||
return panels.find((p) => p.id === id) || null;
|
return panels.find((p) => p.id === id) || undefined;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logError(error, "Failed to get panel by id");
|
logError(error, "Failed to get panel by id");
|
||||||
return null;
|
return undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,10 +8,10 @@
|
|||||||
|
|
||||||
import AppContainer from "../components/AppContainer.svelte";
|
import AppContainer from "../components/AppContainer.svelte";
|
||||||
|
|
||||||
let uploadedImage = $state<string | null>(null);
|
let uploadedImage = $state<string | undefined>(undefined);
|
||||||
let panels = $state<Panel[]>([]);
|
let panels = $state<Panel[]>([]);
|
||||||
let texts = $state<Array<{ id: string; text: string }>>([]);
|
let texts = $state<Array<{ id: string; text: string }>>([]);
|
||||||
let backgroundImage = $state<string | null>(null);
|
let backgroundImage = $state<string | undefined>(undefined);
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
try {
|
try {
|
||||||
@@ -32,14 +32,14 @@
|
|||||||
|
|
||||||
function handleCropComplete(croppedImage: string) {
|
function handleCropComplete(croppedImage: string) {
|
||||||
backgroundImage = croppedImage;
|
backgroundImage = croppedImage;
|
||||||
uploadedImage = null;
|
uploadedImage = undefined;
|
||||||
imageService.handleCropComplete(croppedImage);
|
imageService.handleCropComplete(croppedImage);
|
||||||
panels = panelService.updatePanelsBackground(panels, croppedImage);
|
panels = panelService.updatePanelsBackground(panels, croppedImage);
|
||||||
panels = panelService.updatePanelsFromTexts(texts, panels, croppedImage);
|
panels = panelService.updatePanelsFromTexts(texts, panels, croppedImage);
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleCropCancel() {
|
function handleCropCancel() {
|
||||||
uploadedImage = null;
|
uploadedImage = undefined;
|
||||||
imageService.handleCropCancel();
|
imageService.handleCropCancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { setLoading } from "../stores/uiStore";
|
|||||||
|
|
||||||
export class ExportService {
|
export class ExportService {
|
||||||
private static instance: ExportService;
|
private static instance: ExportService;
|
||||||
private errorMessage: string | null = null;
|
private errorMessage: string | undefined = undefined;
|
||||||
|
|
||||||
private constructor() {}
|
private constructor() {}
|
||||||
|
|
||||||
@@ -15,11 +15,11 @@ export class ExportService {
|
|||||||
return ExportService.instance;
|
return ExportService.instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
getErrorMessage(): string | null {
|
getErrorMessage(): string | undefined {
|
||||||
return this.errorMessage;
|
return this.errorMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
setErrorMessage(message: string | null): void {
|
setErrorMessage(message: string | undefined): void {
|
||||||
this.errorMessage = message;
|
this.errorMessage = message;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ export class ImageService {
|
|||||||
const blob = await response.blob();
|
const blob = await response.blob();
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const reader = new FileReader();
|
const reader = new FileReader();
|
||||||
|
// TODO: look for a better handle non string
|
||||||
reader.onload = () => resolve(reader.result as string);
|
reader.onload = () => resolve(reader.result as string);
|
||||||
reader.onerror = reject;
|
reader.onerror = reject;
|
||||||
reader.readAsDataURL(blob);
|
reader.readAsDataURL(blob);
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { writable, type Writable } from "svelte/store";
|
|||||||
import { type Panel } from "../lib/types/panel";
|
import { type Panel } from "../lib/types/panel";
|
||||||
import { v4 as uuidv4 } from "uuid";
|
import { v4 as uuidv4 } from "uuid";
|
||||||
|
|
||||||
export const panelStore: Writable<Panel | null> = writable(null);
|
export const panelStore: Writable<Panel | undefined> = writable(undefined);
|
||||||
|
|
||||||
export const createEmptyPanel = (height: number = 100): Panel => {
|
export const createEmptyPanel = (height: number = 100): Panel => {
|
||||||
return {
|
return {
|
||||||
@@ -30,7 +30,7 @@ export const addTextToPanel = (panel: Panel, text: string): Panel => {
|
|||||||
fontSize: 18,
|
fontSize: 18,
|
||||||
fontFamily: "Arial",
|
fontFamily: "Arial",
|
||||||
color: "#ffffff",
|
color: "#ffffff",
|
||||||
textAlign: "center" as const,
|
textAlign: "center",
|
||||||
paddingX: 10,
|
paddingX: 10,
|
||||||
verticalOffset: 0,
|
verticalOffset: 0,
|
||||||
};
|
};
|
||||||
@@ -58,7 +58,7 @@ export const createPanelFromText = (backgroundImage: string, text: string, heigh
|
|||||||
fontSize: 18,
|
fontSize: 18,
|
||||||
fontFamily: "Arial",
|
fontFamily: "Arial",
|
||||||
color: "#ffffff",
|
color: "#ffffff",
|
||||||
textAlign: "center" as const,
|
textAlign: "center",
|
||||||
paddingX: 10,
|
paddingX: 10,
|
||||||
verticalOffset: 0,
|
verticalOffset: 0,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { type UIState } from "../lib/types/panel";
|
|||||||
|
|
||||||
export const uiStore: Writable<UIState> = writable({
|
export const uiStore: Writable<UIState> = writable({
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
error: null,
|
error: undefined,
|
||||||
currentStep: "text",
|
currentStep: "text",
|
||||||
showCropModal: false,
|
showCropModal: false,
|
||||||
showTextManager: false,
|
showTextManager: false,
|
||||||
@@ -13,12 +13,12 @@ export const setLoading = (loading: boolean): void => {
|
|||||||
uiStore.update((state) => ({ ...state, isLoading: loading }));
|
uiStore.update((state) => ({ ...state, isLoading: loading }));
|
||||||
};
|
};
|
||||||
|
|
||||||
export const setError = (error: string | null): void => {
|
export const setError = (error: string | undefined): void => {
|
||||||
uiStore.update((state) => ({ ...state, error }));
|
uiStore.update((state) => ({ ...state, error }));
|
||||||
};
|
};
|
||||||
|
|
||||||
export const clearError = (): void => {
|
export const clearError = (): void => {
|
||||||
setError(null);
|
setError(undefined);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const setCurrentStep = (step: UIState["currentStep"]): void => {
|
export const setCurrentStep = (step: UIState["currentStep"]): void => {
|
||||||
@@ -36,7 +36,7 @@ export const showTextManager = (show: boolean): void => {
|
|||||||
export const resetUI = (): void => {
|
export const resetUI = (): void => {
|
||||||
uiStore.set({
|
uiStore.set({
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
error: null,
|
error: undefined,
|
||||||
currentStep: "text",
|
currentStep: "text",
|
||||||
showCropModal: false,
|
showCropModal: false,
|
||||||
showTextManager: false,
|
showTextManager: false,
|
||||||
|
|||||||
+3
-1
@@ -10,6 +10,8 @@
|
|||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
"strict": true,
|
"strict": true,
|
||||||
|
"strictNullChecks": true,
|
||||||
|
"exactOptionalPropertyTypes": true,
|
||||||
"moduleResolution": "bundler"
|
"moduleResolution": "bundler"
|
||||||
}
|
}
|
||||||
// Path aliases are handled by https://svelte.dev/docs/kit/configuration#alias
|
// Path aliases are handled by https://svelte.dev/docs/kit/configuration#alias
|
||||||
@@ -17,4 +19,4 @@
|
|||||||
//
|
//
|
||||||
// To make changes to top-level options such as include and exclude, we recommend extending
|
// To make changes to top-level options such as include and exclude, we recommend extending
|
||||||
// the generated config; see https://svelte.dev/docs/kit/configuration#typescript
|
// the generated config; see https://svelte.dev/docs/kit/configuration#typescript
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user