"use client"; import { useEffect, useRef, useState } from "react"; import { Check, Loader2 } from "lucide-react"; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from "@/components/ui/dialog"; import { Button } from "@/components/ui/button"; import { AVATAR_PALETTES } from "@/components/ui/user-avatar"; import { BANNER_FILLS, BANNER_HEIGHT, BANNER_WIDTH, drawBannerFill, type BannerFill } from "@/lib/banner-pattern"; import { toast } from "@/components/providers"; import { cn } from "@/lib/utils"; function FillThumb({ colors, fill, seed, label, active, onClick, }: { colors: string[]; fill: BannerFill; seed: string; label: string; active: boolean; onClick: () => void; }) { const ref = useRef(null); useEffect(() => { const canvas = ref.current; const ctx = canvas?.getContext("2d"); if (!canvas || !ctx) return; drawBannerFill(ctx, canvas.width, canvas.height, colors, fill, seed); }, [colors, fill, seed]); return ( ); } function PatternCanvas({ canvasRef, colors, seed, fill, onReady, }: { canvasRef: React.RefObject; colors: string[]; seed: string; fill: BannerFill; onReady: (ready: boolean) => void; }) { useEffect(() => { const canvas = canvasRef.current; const ctx = canvas?.getContext("2d"); if (!canvas || !ctx) { onReady(false); return; } drawBannerFill(ctx, BANNER_WIDTH, BANNER_HEIGHT, colors, fill, seed); onReady(true); }, [canvasRef, colors, seed, fill, onReady]); return ; } function HeaderPreview({ children }: { children: React.ReactNode }) { return (
{children}
); } export function BannerEditor({ open, busy, onOpenChange, onSave, onRemove, }: { open: boolean; busy?: boolean; onOpenChange: (open: boolean) => void; onSave: (blob: Blob) => Promise; onRemove?: () => void; }) { const canvasRef = useRef(null); const [paletteIndex, setPaletteIndex] = useState(0); const [fill, setFill] = useState("gradient"); const [ready, setReady] = useState(false); const palette = AVATAR_PALETTES[paletteIndex] ?? AVATAR_PALETTES[0]; const save = async () => { try { const canvas = canvasRef.current; if (!canvas || !ready) return; const blob = await new Promise((resolve) => canvas.toBlob(resolve, "image/png")); if (!blob) { toast.error("ساخت تصویر بنر ممکن نشد"); return; } await onSave(blob); } catch { toast.error("ذخیره بنر ممکن نشد"); } }; return ( !busy && onOpenChange(next)}> ویرایش بنر تصویر عریض پشت نام و آواتار در هدر پروفایل. نسبت حدود ۳ به ۱.

پیش‌نمایش هدر — سایه و جای آواتار فقط برای دیدن نتیجه‌اند و داخل تصویر ذخیره نمی‌شوند.

رنگ‌ها

{AVATAR_PALETTES.map((p, i) => { const active = i === paletteIndex; return ( ); })}

پس‌زمینه

{BANNER_FILLS.map((item) => ( setFill(item.id)} /> ))}
{onRemove && ( )}
); }