feat: editor in popover

This commit is contained in:
2026-04-05 00:31:47 +02:00
parent 3eec7f316e
commit 914945279f
17 changed files with 755 additions and 266 deletions

View File

@@ -1,5 +1,4 @@
import { useEffect, useState } from "react";
import { useNavigate } from "react-router-dom";
import { toast } from "sonner";
import { MoreVertical, Plus, RotateCcw } from "lucide-react";
import { usePagesStore } from "@/stores/pagesStore";
@@ -29,13 +28,20 @@ import {
AlertDialogHeader,
AlertDialogTitle,
} from "@/components/ui/alert-dialog";
import { useWindowManager } from "@/hooks/useWindowManager";
import EditorWindow, { type EditorWinData } from "@/components/editor/EditorWindow";
export default function ComposeView() {
const { pages, isLoading, fetchPages, deletePage, publishPage, unpublishPage } =
usePagesStore();
const navigate = useNavigate();
const [pageToDelete, setPageToDelete] = useState<string | null>(null);
const [restarting, setRestarting] = useState(false);
const { windows, focusedId, open, update, close, focus } = useWindowManager<EditorWinData>({ w: 720, h: 520 });
const openEditor = (name: string, isNew: boolean) => {
const id = isNew ? `new-${Date.now()}` : name;
open(id, { pageName: isNew ? "" : name, isNew });
};
useEffect(() => {
fetchPages();
@@ -89,15 +95,15 @@ export default function ComposeView() {
<div>
<div>
{/* Header row */}
<div className="flex items-center px-4 py-2 border-b-2 border-border">
<h1 className="text-sm font-semibold flex-1">Compose</h1>
<div className="flex items-center px-2 py-1.5 border-b-2 border-border">
<h1 className="text-xs font-semibold flex-1">Compose</h1>
<div className="flex gap-2">
<Button variant="outline" onClick={handleRestart} disabled={restarting}>
<RotateCcw className="w-4 h-4 mr-2" />
<Button variant="outline" size="sm" onClick={handleRestart} disabled={restarting}>
<RotateCcw className="w-3 h-3 mr-1.5" />
Restart
</Button>
<Button onClick={() => navigate("/editor/new")}>
<Plus className="w-4 h-4 mr-2" />
<Button size="sm" onClick={() => openEditor("", true)}>
<Plus className="w-3 h-3 mr-1.5" />
New Page
</Button>
</div>
@@ -119,7 +125,7 @@ export default function ComposeView() {
<TableRow
key={p.name}
className="cursor-pointer"
onClick={() => navigate(`/editor/${p.name}`)}
onClick={() => openEditor(p.name, false)}
>
<TableCell className="font-mono">
{p.name}
@@ -138,8 +144,8 @@ export default function ComposeView() {
</TableCell>
<TableCell className="text-right w-8">
<PageActions
name={p.name}
published={p.published}
onEdit={() => openEditor(p.name, false)}
onPublish={() => handlePublish(p.name)}
onUnpublish={() => handleUnpublish(p.name)}
onDelete={() => setPageToDelete(p.name)}
@@ -184,6 +190,18 @@ export default function ComposeView() {
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
{/* Floating editor windows */}
{windows.map((win) => (
<EditorWindow
key={win.id}
win={win}
focused={focusedId === win.id}
onUpdate={update}
onClose={close}
onFocus={focus}
/>
))}
</div>
);
}
@@ -191,20 +209,18 @@ export default function ComposeView() {
/** Per-row action menu for a page. */
function PageActions({
name,
published,
onEdit,
onPublish,
onUnpublish,
onDelete,
}: {
name: string;
published: boolean;
onEdit: () => void;
onPublish: () => void;
onUnpublish: () => void;
onDelete: () => void;
}) {
const navigate = useNavigate();
return (
<Popover>
<PopoverTrigger
@@ -219,7 +235,7 @@ function PageActions({
/>
<PopoverContent side="bottom" align="end" sideOffset={4} className="w-36 p-1">
<button
onClick={(e) => { e.stopPropagation(); navigate(`/editor/${name}`); }}
onClick={(e) => { e.stopPropagation(); onEdit(); }}
className="w-full text-left px-3 py-1.5 text-xs hover:bg-accent transition-colors cursor-pointer"
>Edit</button>
{published ? (