fix: resolve text settings not applied
This commit is contained in:
@@ -1,8 +1,10 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Button from "$components/ui/Button.svelte";
|
import Button from "$components/ui/Button.svelte";
|
||||||
|
import type { TextAlign, TextItem } from "$lib/types/panel";
|
||||||
|
import { textSettingsStore, updateAllTextSettings } from "$stores/panelStore";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
onTextAdd: (text: string) => void;
|
onTextAdd: (text: string, settings?: Partial<TextItem>) => void;
|
||||||
onTextUpdate: (id: string, text: string) => void;
|
onTextUpdate: (id: string, text: string) => void;
|
||||||
onTextDelete: (id: string) => void;
|
onTextDelete: (id: string) => void;
|
||||||
texts: Array<{ id: string; text: string }>;
|
texts: Array<{ id: string; text: string }>;
|
||||||
@@ -13,15 +15,8 @@
|
|||||||
let newText = $state("");
|
let newText = $state("");
|
||||||
let errorMessage = $state<string | undefined>(undefined);
|
let errorMessage = $state<string | undefined>(undefined);
|
||||||
|
|
||||||
// Общие настройки текста для всех панелей
|
// Use reactive store for text settings
|
||||||
let commonTextSettings = $state({
|
let commonTextSettings = $derived($textSettingsStore);
|
||||||
fontSize: 18,
|
|
||||||
fontFamily: "Arial",
|
|
||||||
color: "#ffffff",
|
|
||||||
textAlign: "left",
|
|
||||||
paddingX: 10,
|
|
||||||
verticalOffset: 0,
|
|
||||||
});
|
|
||||||
|
|
||||||
// Список доступных шрифтов
|
// Список доступных шрифтов
|
||||||
const availableFonts = [
|
const availableFonts = [
|
||||||
@@ -48,7 +43,7 @@
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
errorMessage = undefined;
|
errorMessage = undefined;
|
||||||
onTextAdd(newText.trim());
|
onTextAdd(newText.trim(), commonTextSettings);
|
||||||
newText = "";
|
newText = "";
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
errorMessage = error instanceof Error ? error.message : "Ошибка добавления текста";
|
errorMessage = error instanceof Error ? error.message : "Ошибка добавления текста";
|
||||||
@@ -133,7 +128,7 @@
|
|||||||
step="1"
|
step="1"
|
||||||
value={commonTextSettings.fontSize}
|
value={commonTextSettings.fontSize}
|
||||||
oninput={(e: Event) => {
|
oninput={(e: Event) => {
|
||||||
commonTextSettings.fontSize = parseInt((e.target as HTMLInputElement).value);
|
updateAllTextSettings({ fontSize: parseInt((e.target as HTMLInputElement).value) });
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<span class="value-display">{commonTextSettings.fontSize}px</span>
|
<span class="value-display">{commonTextSettings.fontSize}px</span>
|
||||||
@@ -146,7 +141,7 @@
|
|||||||
<select
|
<select
|
||||||
value={commonTextSettings.fontFamily}
|
value={commonTextSettings.fontFamily}
|
||||||
onchange={(e) => {
|
onchange={(e) => {
|
||||||
commonTextSettings.fontFamily = (e.target as HTMLSelectElement).value;
|
updateAllTextSettings({ fontFamily: (e.target as HTMLSelectElement).value });
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{#each availableFonts as font}
|
{#each availableFonts as font}
|
||||||
@@ -163,7 +158,7 @@
|
|||||||
type="color"
|
type="color"
|
||||||
value={commonTextSettings.color}
|
value={commonTextSettings.color}
|
||||||
oninput={(e) => {
|
oninput={(e) => {
|
||||||
commonTextSettings.color = (e.target as HTMLInputElement).value;
|
updateAllTextSettings({ color: (e.target as HTMLInputElement).value });
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
@@ -176,7 +171,7 @@
|
|||||||
<button
|
<button
|
||||||
class="align-btn {commonTextSettings.textAlign === 'left' ? 'active' : ''}"
|
class="align-btn {commonTextSettings.textAlign === 'left' ? 'active' : ''}"
|
||||||
onclick={() => {
|
onclick={() => {
|
||||||
commonTextSettings.textAlign = "left";
|
updateAllTextSettings({ textAlign: "left" as TextAlign });
|
||||||
}}
|
}}
|
||||||
aria-label="Выровнять по левому краю"
|
aria-label="Выровнять по левому краю"
|
||||||
>
|
>
|
||||||
@@ -185,7 +180,7 @@
|
|||||||
<button
|
<button
|
||||||
class="align-btn {commonTextSettings.textAlign === 'center' ? 'active' : ''}"
|
class="align-btn {commonTextSettings.textAlign === 'center' ? 'active' : ''}"
|
||||||
onclick={() => {
|
onclick={() => {
|
||||||
commonTextSettings.textAlign = "center";
|
updateAllTextSettings({ textAlign: "center" as TextAlign });
|
||||||
}}
|
}}
|
||||||
aria-label="Выровнять по центру"
|
aria-label="Выровнять по центру"
|
||||||
>
|
>
|
||||||
@@ -194,7 +189,7 @@
|
|||||||
<button
|
<button
|
||||||
class="align-btn {commonTextSettings.textAlign === 'right' ? 'active' : ''}"
|
class="align-btn {commonTextSettings.textAlign === 'right' ? 'active' : ''}"
|
||||||
onclick={() => {
|
onclick={() => {
|
||||||
commonTextSettings.textAlign = "right";
|
updateAllTextSettings({ textAlign: "right" as TextAlign });
|
||||||
}}
|
}}
|
||||||
aria-label="Выровнять по правому краю"
|
aria-label="Выровнять по правому краю"
|
||||||
>
|
>
|
||||||
@@ -214,7 +209,7 @@
|
|||||||
step="1"
|
step="1"
|
||||||
value={commonTextSettings.paddingX}
|
value={commonTextSettings.paddingX}
|
||||||
oninput={(e) => {
|
oninput={(e) => {
|
||||||
commonTextSettings.paddingX = parseInt((e.target as HTMLInputElement).value);
|
updateAllTextSettings({ paddingX: parseInt((e.target as HTMLInputElement).value) });
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<span class="value-display">{commonTextSettings.paddingX}px</span>
|
<span class="value-display">{commonTextSettings.paddingX}px</span>
|
||||||
@@ -231,11 +226,11 @@
|
|||||||
step="1"
|
step="1"
|
||||||
value={commonTextSettings.verticalOffset}
|
value={commonTextSettings.verticalOffset}
|
||||||
oninput={(e) => {
|
oninput={(e) => {
|
||||||
commonTextSettings.verticalOffset = parseInt((e.target as HTMLInputElement).value);
|
updateAllTextSettings({ verticalOffset: parseInt((e.target as HTMLInputElement).value) });
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<span class="value-display"
|
<span class="value-display"
|
||||||
>{commonTextSettings.verticalOffset > 0 ? "+" : ""}{commonTextSettings.verticalOffset}px</span
|
>{(commonTextSettings.verticalOffset ?? 0) > 0 ? "+" : ""}{commonTextSettings.verticalOffset ?? 0}px</span
|
||||||
>
|
>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import type { TextItem } from "$lib/types/panel";
|
||||||
import TextManager from "./TextManager.svelte";
|
import TextManager from "./TextManager.svelte";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
texts: Array<{ id: string; text: string }>;
|
texts: Array<{ id: string; text: string }>;
|
||||||
onTextAdd: (text: string) => void;
|
onTextAdd: (text: string, settings?: Partial<TextItem>) => void;
|
||||||
onTextUpdate: (id: string, text: string) => void;
|
onTextUpdate: (id: string, text: string) => void;
|
||||||
onTextDelete: (id: string) => void;
|
onTextDelete: (id: string) => void;
|
||||||
}
|
}
|
||||||
|
|||||||
+36
-3
@@ -1,9 +1,10 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { Panel } from "$lib/types/panel";
|
import type { Panel, TextItem } from "$lib/types/panel";
|
||||||
import { onMount } from "svelte";
|
import { onMount } from "svelte";
|
||||||
import { exportService } from "../services/exportService";
|
import { exportService } from "../services/exportService";
|
||||||
import { imageService } from "../services/imageService";
|
import { imageService } from "../services/imageService";
|
||||||
import { panelService } from "../services/panelService";
|
import { panelService } from "../services/panelService";
|
||||||
|
import { textSettingsStore } from "../stores/panelStore";
|
||||||
|
|
||||||
import AppContainer from "../components/layout/AppContainer.svelte";
|
import AppContainer from "../components/layout/AppContainer.svelte";
|
||||||
|
|
||||||
@@ -12,6 +13,38 @@
|
|||||||
let texts = $state<Array<{ id: string; text: string }>>([]);
|
let texts = $state<Array<{ id: string; text: string }>>([]);
|
||||||
let backgroundImage = $state<string | undefined>(undefined);
|
let backgroundImage = $state<string | undefined>(undefined);
|
||||||
|
|
||||||
|
// Create a derived store for text settings to avoid cyclic dependencies
|
||||||
|
let textSettings = $derived($textSettingsStore);
|
||||||
|
|
||||||
|
// Listen for text settings changes and update all panels
|
||||||
|
let previousSettings = $state<string>("");
|
||||||
|
|
||||||
|
$effect(() => {
|
||||||
|
// Only depend on the derived settings value
|
||||||
|
const currentSettings = textSettings;
|
||||||
|
const settingsString = JSON.stringify(currentSettings);
|
||||||
|
|
||||||
|
// Only update if settings actually changed
|
||||||
|
if (settingsString !== previousSettings) {
|
||||||
|
console.log("[SETTINGS] Applying text settings to all panels:", currentSettings);
|
||||||
|
|
||||||
|
// Update panels with new settings
|
||||||
|
const updatedPanels = panels.map((panel) => ({
|
||||||
|
...panel,
|
||||||
|
text: { ...panel.text, ...currentSettings },
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Use a microtask to avoid synchronous update issues
|
||||||
|
Promise.resolve().then(() => {
|
||||||
|
if (panels.length > 0) {
|
||||||
|
panels = updatedPanels;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
previousSettings = settingsString;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
// Initialize with default texts for common Twitch panels
|
// Initialize with default texts for common Twitch panels
|
||||||
console.log("[INIT] Creating default texts...");
|
console.log("[INIT] Creating default texts...");
|
||||||
@@ -62,9 +95,9 @@
|
|||||||
imageService.handleCropCancel();
|
imageService.handleCropCancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleAddText(text: string) {
|
function handleAddText(text: string, settings?: Partial<TextItem>) {
|
||||||
texts = panelService.addText(texts, text);
|
texts = panelService.addText(texts, text);
|
||||||
panels = panelService.updatePanelsFromTexts(texts, panels, backgroundImage!);
|
panels = panelService.updatePanelsFromTexts(texts, panels, backgroundImage!, settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleUpdateText(id: string, newText: string) {
|
function handleUpdateText(id: string, newText: string) {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { Panel } from "../lib/types/panel";
|
import type { Panel, TextItem } from "../lib/types/panel";
|
||||||
import { createPanelFromText, updatePanelText } from "../stores/panelStore";
|
import { createPanelFromText, updatePanelText } from "../stores/panelStore";
|
||||||
|
|
||||||
export class PanelService {
|
export class PanelService {
|
||||||
@@ -43,13 +43,18 @@ export class PanelService {
|
|||||||
return texts.filter((t) => t.id !== id);
|
return texts.filter((t) => t.id !== id);
|
||||||
}
|
}
|
||||||
|
|
||||||
updatePanelsFromTexts(texts: Array<{ id: string; text: string }>, panels: Panel[], backgroundImage: string): Panel[] {
|
updatePanelsFromTexts(
|
||||||
|
texts: Array<{ id: string; text: string }>,
|
||||||
|
panels: Panel[],
|
||||||
|
backgroundImage: string,
|
||||||
|
textSettings?: Partial<TextItem>,
|
||||||
|
): Panel[] {
|
||||||
return texts.map((textItem) => {
|
return texts.map((textItem) => {
|
||||||
const existingPanel = panels.find((p) => p.text.text === textItem.text);
|
const existingPanel = panels.find((p) => p.text.text === textItem.text);
|
||||||
if (existingPanel) {
|
if (existingPanel) {
|
||||||
return updatePanelText(existingPanel, textItem.text);
|
return updatePanelText(existingPanel, textItem.text);
|
||||||
}
|
}
|
||||||
return createPanelFromText(backgroundImage, textItem.text);
|
return createPanelFromText(backgroundImage, textItem.text, 100, textSettings);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,20 @@ import { type Panel, type TextItem } from "../lib/types/panel";
|
|||||||
|
|
||||||
export const panelStore: Writable<Panel | undefined> = writable(undefined);
|
export const panelStore: Writable<Panel | undefined> = writable(undefined);
|
||||||
|
|
||||||
|
// Store for common text settings that should apply to all texts
|
||||||
|
export const textSettingsStore = writable<Partial<TextItem>>({
|
||||||
|
fontSize: 18,
|
||||||
|
fontFamily: "Arial",
|
||||||
|
color: "#ffffff",
|
||||||
|
textAlign: "left",
|
||||||
|
paddingX: 10,
|
||||||
|
verticalOffset: 0,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const updateAllTextSettings = (settings: Partial<TextItem>) => {
|
||||||
|
textSettingsStore.update((current) => ({ ...current, ...settings }));
|
||||||
|
};
|
||||||
|
|
||||||
// Panel creation should go through panelService.updatePanelsFromTexts()
|
// Panel creation should go through panelService.updatePanelsFromTexts()
|
||||||
// These functions are kept for backward compatibility but should be avoided
|
// These functions are kept for backward compatibility but should be avoided
|
||||||
export const createEmptyPanel = (height: number = 100): Panel => {
|
export const createEmptyPanel = (height: number = 100): Panel => {
|
||||||
@@ -48,16 +62,21 @@ export const updateTextProperties = (panel: Panel, updates: Partial<TextItem>):
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const createPanelFromText = (backgroundImage: string, text: string, height: number = 100): Panel => {
|
export const createPanelFromText = (
|
||||||
|
backgroundImage: string,
|
||||||
|
text: string,
|
||||||
|
height: number = 100,
|
||||||
|
textSettings?: Partial<TextItem>,
|
||||||
|
): Panel => {
|
||||||
const newText: TextItem = {
|
const newText: TextItem = {
|
||||||
id: uuidv4(),
|
id: uuidv4(),
|
||||||
text,
|
text,
|
||||||
fontSize: 18,
|
fontSize: textSettings?.fontSize ?? 18,
|
||||||
fontFamily: "Arial",
|
fontFamily: textSettings?.fontFamily ?? "Arial",
|
||||||
color: "#ffffff",
|
color: textSettings?.color ?? "#ffffff",
|
||||||
textAlign: "center",
|
textAlign: textSettings?.textAlign ?? "center",
|
||||||
paddingX: 10,
|
paddingX: textSettings?.paddingX ?? 10,
|
||||||
verticalOffset: 0,
|
verticalOffset: textSettings?.verticalOffset ?? 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
Reference in New Issue
Block a user