diff --git a/apps/web/src/components/TemplatesPane.tsx b/apps/web/src/components/TemplatesPane.tsx index 9285f0be..f3822c16 100644 --- a/apps/web/src/components/TemplatesPane.tsx +++ b/apps/web/src/components/TemplatesPane.tsx @@ -1,12 +1,50 @@ import { useMemo, useState } from "react"; -import { Check, ChevronLeft, File as FileIcon, LayoutList, Pencil, Plus, Trash2, X } from "lucide-react"; +import { + BookOpen, + Calendar, + Check, + CheckSquare, + ChevronLeft, + Eye, + FileText, + LayoutList, + Pencil, + Plus, + Sparkles, + Sun, + Trash2, + X, + Zap, + Tag, + ArrowRight, + FilePlus +} from "lucide-react"; import { useTranslation } from "react-i18next"; +import { marked } from "marked"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; +import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "@/components/ui/dialog"; import { getMemoTemplates, type MemoTemplate } from "@/lib/app-helpers"; import { WORKSPACE_PAGE_TITLE_CLASSNAME } from "@/lib/workspace-ui"; import type { MemoTemplate as SavedMemoTemplate } from "@edgeever/shared"; +const renderTemplateIcon = (iconName?: string) => { + switch (iconName) { + case "zap": + return ; + case "calendar": + return ; + case "checklist": + return ; + case "book": + return ; + case "sun": + return ; + default: + return ; + } +}; + export const TemplatesPane = ({ canCreateMemo, isCreating, @@ -33,26 +71,53 @@ export const TemplatesPane = ({ const [editingTemplate, setEditingTemplate] = useState(null); const [creatingTemplate, setCreatingTemplate] = useState(false); const [draft, setDraft] = useState({ name: "", description: "", title: "", contentMarkdown: "", tags: "" }); + const [editorTab, setEditorTab] = useState<"raw" | "preview">("raw"); + + const [previewTemplate, setPreviewTemplate] = useState<{ + title: string; + description: string | null; + noteTitle?: string | null; + tags: string[]; + contentMarkdown: string; + badge: string; + onUse: () => void; + } | null>(null); + + const [deleteConfirmTemplate, setDeleteConfirmTemplate] = useState(null); const startEditing = (template: SavedMemoTemplate) => { setCreatingTemplate(false); setEditingTemplate(template); - setDraft({ name: template.name, description: template.description ?? "", title: template.title ?? "", contentMarkdown: template.contentMarkdown, tags: template.tags.join(", ") }); + setEditorTab("raw"); + setDraft({ + name: template.name, + description: template.description ?? "", + title: template.title ?? "", + contentMarkdown: template.contentMarkdown, + tags: template.tags.join(", "), + }); }; + const startCreating = () => { setEditingTemplate(null); setCreatingTemplate(true); + setEditorTab("raw"); setDraft({ name: "", description: "", title: "", contentMarkdown: "", tags: "" }); }; + const cancelEditing = () => { setEditingTemplate(null); setCreatingTemplate(false); }; + const saveEditing = async () => { if (!draft.name.trim()) return; const payload = { - name: draft.name.trim(), description: draft.description.trim() || null, title: draft.title.trim() || null, - contentMarkdown: draft.contentMarkdown, tags: draft.tags.split(",").map((tag) => tag.trim()).filter(Boolean), + name: draft.name.trim(), + description: draft.description.trim() || null, + title: draft.title.trim() || null, + contentMarkdown: draft.contentMarkdown, + tags: draft.tags.split(",").map((tag) => tag.trim()).filter(Boolean), }; if (creatingTemplate) { await onCreateSavedTemplate(payload); @@ -60,80 +125,459 @@ export const TemplatesPane = ({ return; } if (!editingTemplate) return; - await onUpdateSavedTemplate(editingTemplate.id, { - ...payload, - }); + await onUpdateSavedTemplate(editingTemplate.id, payload); cancelEditing(); }; + const draftHtmlPreview = useMemo( + () => (draft.contentMarkdown ? (marked.parse(draft.contentMarkdown) as string) : ""), + [draft.contentMarkdown] + ); + + const previewHtmlContent = useMemo( + () => (previewTemplate?.contentMarkdown ? (marked.parse(previewTemplate.contentMarkdown) as string) : ""), + [previewTemplate?.contentMarkdown] + ); + return ( -
-
+
+ {/* Header */} +
-

{t("templates.title")}

+

+ + {t("templates.title")} +

{t("templates.description")}

-
-
-
-
-

{t("templates.myTemplates")}

- + {/* Main Content Area */} +
+
+ + {/* Section 1: My Custom Templates */} +
+
+
+

+ {t("templates.myTemplates")} + + {savedTemplates.length} + +

+

{t("templates.myTemplatesSubtitle")}

+
+ {!creatingTemplate && !editingTemplate && ( + + )}
- {(editingTemplate || creatingTemplate) && ( -
+ + {/* Form for Creating / Editing Template */} + {(editingTemplate || creatingTemplate) && ( +
+
+

+ + {creatingTemplate ? t("templates.createTemplateTitle") : t("templates.editTemplateTitle")} +

+ +
+ +
- setDraft((current) => ({ ...current, name: event.target.value }))} placeholder={t("templates.name")} /> - setDraft((current) => ({ ...current, description: event.target.value }))} placeholder={t("templates.descriptionField")} /> - setDraft((current) => ({ ...current, title: event.target.value }))} placeholder={t("templates.noteTitle")} /> - setDraft((current) => ({ ...current, tags: event.target.value }))} placeholder={t("templates.tags")} /> +
+ + setDraft((c) => ({ ...c, name: e.target.value }))} + placeholder={t("templates.namePlaceholder")} + /> +
+
+ + setDraft((c) => ({ ...c, title: e.target.value }))} + placeholder={t("templates.noteTitlePlaceholder")} + /> +
-