Spaces:
Running
Running
| "use client"; | |
| import { useState } from "react"; | |
| import { Button } from "@/components/ui/button"; | |
| import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from "@/components/ui/dialog"; | |
| import { HERO_TEMPLATES } from "@/lib/hero-templates"; | |
| import { useEditor } from "@/hooks/useEditor"; | |
| function insertIntoBody(html: string, snippet: string): string { | |
| if (!html) return snippet; | |
| const bodyOpen = html.toLowerCase().indexOf("<body"); | |
| if (bodyOpen === -1) return snippet + "\n" + html; | |
| const afterBodyTag = html.indexOf(">", bodyOpen); | |
| if (afterBodyTag === -1) return snippet + "\n" + html; | |
| const head = html.slice(0, afterBodyTag + 1); | |
| const tail = html.slice(afterBodyTag + 1); | |
| return head + "\n" + snippet + "\n" + tail; | |
| } | |
| export function HeroPresets() { | |
| const { currentPageData, setPages } = useEditor(); | |
| const [open, setOpen] = useState(false); | |
| const [selected, setSelected] = useState<string | null>(null); | |
| const apply = () => { | |
| if (!selected) return; | |
| const t = HERO_TEMPLATES.find(x => x.id === selected); | |
| if (!t) return; | |
| const newHtml = insertIntoBody(currentPageData.html, t.html); | |
| setPages(prev => prev.map(p => p.path === currentPageData.path ? { ...p, html: newHtml } : p)); | |
| setOpen(false); | |
| }; | |
| return ( | |
| <> | |
| <Button size="xs" variant="outline" className="!rounded-md" onClick={() => setOpen(true)}>Hero Presets</Button> | |
| <Dialog open={open} onOpenChange={setOpen}> | |
| <DialogContent className="sm:max-w-3xl !bg-neutral-900 !border-neutral-800"> | |
| <DialogHeader> | |
| <DialogTitle className="text-neutral-100">Insert Hero Template</DialogTitle> | |
| </DialogHeader> | |
| <div className="grid grid-cols-1 md:grid-cols-2 gap-3 max-h-[60vh] overflow-y-auto"> | |
| {HERO_TEMPLATES.map(t => ( | |
| <div key={t.id} className={`p-3 rounded-lg border cursor-pointer ${selected===t.id ? 'border-sky-500 bg-neutral-800/50' : 'border-neutral-800 bg-neutral-900/40'}`} onClick={() => setSelected(t.id)}> | |
| <p className="font-medium text-neutral-200">{t.name}</p> | |
| <p className="text-xs text-neutral-400">{t.id}</p> | |
| <div className="mt-2 text-xs text-neutral-500 line-clamp-3">{t.html.slice(0, 200)}...</div> | |
| </div> | |
| ))} | |
| </div> | |
| <DialogFooter> | |
| <Button size="sm" variant="bordered" onClick={() => setOpen(false)}>Close</Button> | |
| <Button size="sm" onClick={apply} disabled={!selected}>Insert</Button> | |
| </DialogFooter> | |
| </DialogContent> | |
| </Dialog> | |
| </> | |
| ); | |
| } | |