w-funnel/src/components/admin/builder/templates/InfoScreenConfig.tsx
dev.daminik00 b57e99e472 merge
2025-09-28 04:41:13 +02:00

113 lines
4.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use client";
import { TextInput } from "@/components/ui/TextInput/TextInput";
import { MarkupPreview } from "@/components/ui/MarkupText/MarkupText";
import type { InfoScreenDefinition } from "@/lib/funnel/types";
import type { BuilderScreen } from "@/lib/admin/builder/types";
interface InfoScreenConfigProps {
screen: BuilderScreen & { template: "info" };
onUpdate: (updates: Partial<InfoScreenDefinition>) => void;
}
export function InfoScreenConfig({ screen, onUpdate }: InfoScreenConfigProps) {
const infoScreen = screen as InfoScreenDefinition & { position: { x: number; y: number } };
const handleDescriptionChange = (text: string) => {
onUpdate({
description: text
? {
...(infoScreen.description ?? {}),
text,
}
: undefined,
});
};
const handleIconChange = <T extends keyof NonNullable<InfoScreenDefinition["icon"]>>(
field: T,
value: NonNullable<InfoScreenDefinition["icon"]>[T] | undefined
) => {
const baseIcon = infoScreen.icon ?? { type: "emoji", value: "✨", size: "lg" };
if (field === "value") {
if (!value) {
onUpdate({ icon: undefined });
} else {
onUpdate({ icon: { ...baseIcon, value } });
}
return;
}
onUpdate({ icon: { ...baseIcon, [field]: value } });
};
return (
<div className="space-y-6 rounded-2xl border border-border/70 bg-background/80 p-5 shadow-sm">
<div className="space-y-3">
<h3 className="text-sm font-semibold uppercase tracking-wide text-muted-foreground">
Информационный контент
</h3>
<div className="space-y-3">
<label className="flex flex-col gap-2 text-sm">
<span className="text-xs font-medium text-muted-foreground">Описание (необязательно)</span>
<TextInput
placeholder="Введите пояснение для пользователя. Используйте **текст** для выделения жирным."
value={infoScreen.description?.text ?? ""}
onChange={(event) => handleDescriptionChange(event.target.value)}
/>
</label>
{/* 🎨 ПРЕВЬЮ РАЗМЕТКИ */}
{infoScreen.description?.text && (
<MarkupPreview text={infoScreen.description.text} />
)}
</div>
</div>
<div className="space-y-3">
<h4 className="text-sm font-semibold text-foreground">Иконка</h4>
<div className="grid grid-cols-2 gap-2 text-xs">
<label className="flex flex-col gap-1 text-muted-foreground">
Тип иконки
<select
className="rounded-lg border border-border bg-background px-2 py-1"
value={infoScreen.icon?.type ?? "emoji"}
onChange={(event) => handleIconChange("type", event.target.value as "emoji" | "image")}
>
<option value="emoji">Emoji</option>
<option value="image">Изображение</option>
</select>
</label>
<label className="flex flex-col gap-1 text-muted-foreground">
Размер
<select
className="rounded-lg border border-border bg-background px-2 py-1"
value={infoScreen.icon?.size ?? "lg"}
onChange={(event) =>
handleIconChange("size", event.target.value as "sm" | "md" | "lg" | "xl")
}
>
<option value="sm">Маленький</option>
<option value="md">Средний</option>
<option value="lg">Большой</option>
<option value="xl">Огромный</option>
</select>
</label>
</div>
<label className="flex flex-col gap-2 text-sm">
<span className="text-xs font-medium text-muted-foreground">
{infoScreen.icon?.type === "image" ? "Ссылка на изображение" : "Emoji символ"}
</span>
<TextInput
placeholder={infoScreen.icon?.type === "image" ? "https://..." : "Например, ✨"}
value={infoScreen.icon?.value ?? ""}
onChange={(event) => handleIconChange("value", event.target.value || undefined)}
/>
</label>
</div>
</div>
);
}