113 lines
4.3 KiB
TypeScript
113 lines
4.3 KiB
TypeScript
"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>
|
||
);
|
||
}
|