diff --git a/plans/PROJECT_PLAN.md b/plans/PROJECT_PLAN.md index 89211fc..6473e6c 100644 --- a/plans/PROJECT_PLAN.md +++ b/plans/PROJECT_PLAN.md @@ -99,11 +99,19 @@ - Tailwind CSS (опционально для стилей) ### Основные компоненты + +#### UI компоненты (максимум 5) +- AppHeader - заголовок приложения с кнопкой загрузки изображения +- ImageManager - управление загрузкой и обрезкой изображений +- TextSection - управление текстами и настройками +- BackgroundPreview - превью фонового изображения +- PanelsList - список превью всех созданных панелей + +#### Вспомогательные компоненты - ImageUpload - загрузка изображений - ImageCropper - обрезка изображений -- TextManager - добавление, редактирование и удаление текстов, настройки текста +- TextManager - добавление, редактирование и удаление текстов - PanelPreview - превью отдельной панели (только для просмотра) -- PanelList - список превью всех созданных панелей ### Хранилище данных - panelStore - хранение состояния панелей и функций для их создания diff --git a/src/components/AppHeader.svelte b/src/components/AppHeader.svelte new file mode 100644 index 0000000..b2a4e44 --- /dev/null +++ b/src/components/AppHeader.svelte @@ -0,0 +1,35 @@ + + +
+

Twitch Panels Creator

+ {#if onUploadNewImage} + + {/if} +
+ + diff --git a/src/components/BackgroundPreview.svelte b/src/components/BackgroundPreview.svelte new file mode 100644 index 0000000..aaab258 --- /dev/null +++ b/src/components/BackgroundPreview.svelte @@ -0,0 +1,54 @@ + + +{#if backgroundImage} +
+
+

Фоновое изображение

+ +
+ Фон +
+{/if} + + diff --git a/src/components/ImageManager.svelte b/src/components/ImageManager.svelte new file mode 100644 index 0000000..084c8f6 --- /dev/null +++ b/src/components/ImageManager.svelte @@ -0,0 +1,24 @@ + + +{#if currentStep === "upload"} + +{:else if currentStep === "crop" && uploadedImage} + +{/if} diff --git a/src/components/PanelsList.svelte b/src/components/PanelsList.svelte new file mode 100644 index 0000000..848dfac --- /dev/null +++ b/src/components/PanelsList.svelte @@ -0,0 +1,71 @@ + + +{#if panels.length > 0} +
+
+

Созданные панели ({panels.length})

+ +
+
+ {#each panels as panel (panel.id)} +
+ onDownload(panel)} + /> +
+ {/each} +
+
+{/if} + + diff --git a/src/components/TextSection.svelte b/src/components/TextSection.svelte new file mode 100644 index 0000000..a83849e --- /dev/null +++ b/src/components/TextSection.svelte @@ -0,0 +1,40 @@ + + +
+

Добавьте тексты для панелей

+ +
+ + diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index 0d5e0af..c2f7cfe 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -6,11 +6,11 @@ import { exportService } from "../lib/services/exportService"; import type { Panel } from "../lib/types/panel"; - import ImageUpload from "../components/ImageUpload.svelte"; - import ImageCropper from "../components/ImageCropper.svelte"; - import TextManager from "../components/TextManager.svelte"; - import PanelPreview from "../components/PanelPreview.svelte"; - import { Button } from "../lib/components/ui"; + import AppHeader from "../components/AppHeader.svelte"; + import ImageManager from "../components/ImageManager.svelte"; + import TextSection from "../components/TextSection.svelte"; + import BackgroundPreview from "../components/BackgroundPreview.svelte"; + import PanelsList from "../components/PanelsList.svelte"; let uploadedImage = $state(null); let panels = $state([]); @@ -84,12 +84,10 @@ if (existingPanel) { return updatePanelText(existingPanel, textItem.text); } - return createPanelFromText(backgroundImage, textItem.text); + return createPanelFromText(backgroundImage!, textItem.text); }); } - - async function handleDownload(panel: Panel) { try { setLoading(true); @@ -117,14 +115,10 @@ setLoading(false); } } - -
-
-

Twitch Panels Creator

-
+ {#if errorMessage}
@@ -134,50 +128,34 @@
- {#if $uiStore.currentStep === "upload"} - - {:else if $uiStore.currentStep === "crop" && uploadedImage} - - {:else if $uiStore.currentStep === "text"} -
-

Добавьте тексты для панелей

- -
+ + {#if $uiStore.currentStep === "text"} + {/if}
@@ -193,23 +171,6 @@ padding: 2rem; } - .app-header { - display: flex; - justify-content: space-between; - align-items: center; - padding: 1.5rem; - background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); - border-radius: 12px; - color: white; - box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); - } - - .app-header h1 { - margin: 0; - font-size: 2rem; - font-weight: 600; - } - .app-content { display: grid; grid-template-columns: 1fr 1fr; @@ -222,91 +183,12 @@ gap: 1.5rem; } - .text-section { - display: flex; - flex-direction: column; - gap: 1rem; - } - - .text-section h2 { - margin: 0; - color: #333; - font-size: 1.5rem; - font-weight: 600; - } - .sidebar { display: flex; flex-direction: column; gap: 1.5rem; } - .background-preview { - display: flex; - flex-direction: column; - gap: 0.5rem; - padding: 1rem; - background: white; - border-radius: 8px; - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); - } - - .background-header { - display: flex; - justify-content: space-between; - align-items: center; - gap: 0.5rem; - } - - .background-preview h3 { - margin: 0; - color: #333; - font-size: 1rem; - font-weight: 600; - } - - .background-preview img { - width: 100%; - max-width: 320px; - height: auto; - border-radius: 4px; - } - - .panels-container { - display: flex; - flex-direction: column; - gap: 1rem; - } - - .panels-header { - display: flex; - justify-content: space-between; - align-items: center; - padding: 1rem; - background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); - border-radius: 8px; - color: white; - } - - .panels-header h2 { - margin: 0; - font-size: 1.25rem; - font-weight: 600; - } - - .panels-list { - display: flex; - flex-direction: column; - gap: 1rem; - } - - .panel-item { - border: 2px solid #e9ecef; - border-radius: 8px; - overflow: hidden; - background: white; - } - .error-message { background: #ffebee; color: #c62828; @@ -316,36 +198,6 @@ font-weight: 500; } - .loading { - text-align: center; - padding: 2rem; - color: #666; - background: #f9f9f9; - border-radius: 8px; - border: 2px solid #e9ecef; - } - - .btn { - padding: 0.75rem 1.5rem; - border: none; - border-radius: 8px; - font-size: 1rem; - cursor: pointer; - transition: all 0.3s ease; - font-weight: 500; - } - - .btn-primary { - background: white; - color: #667eea; - } - - .btn-primary:hover { - background: #f0f0f0; - transform: translateY(-2px); - box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); - } - @media (max-width: 1024px) { .app-content { grid-template-columns: 1fr;