1
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import Link from "next/link";
|
||||
import ReactMarkdown from "react-markdown";
|
||||
import remarkGfm from "remark-gfm";
|
||||
import { api, DocumentItem } from "@/lib/api";
|
||||
import { Shell } from "@/components/Shell";
|
||||
import { Button, Card } from "@/components/ui";
|
||||
|
||||
export default function DocumentPage({ params }: { params: { documentId: string } }) {
|
||||
const documentId = Number(params.documentId);
|
||||
const [document, setDocument] = useState<DocumentItem | null>(null);
|
||||
const [content, setContent] = useState("");
|
||||
const [savedContent, setSavedContent] = useState("");
|
||||
const [status, setStatus] = useState("");
|
||||
const dirty = content !== savedContent;
|
||||
|
||||
useEffect(() => {
|
||||
Promise.all([api.document(documentId), api.markdown(documentId)]).then(([doc, markdown]) => {
|
||||
setDocument(doc); setContent(markdown); setSavedContent(markdown);
|
||||
}).catch((err) => setStatus(err.message));
|
||||
}, [documentId]);
|
||||
|
||||
async function save() {
|
||||
setStatus("Guardando...");
|
||||
await api.saveMarkdown(documentId, content);
|
||||
setSavedContent(content);
|
||||
setStatus("Guardado");
|
||||
}
|
||||
|
||||
async function copy() {
|
||||
await navigator.clipboard.writeText(content);
|
||||
setStatus("Copiado al portapapeles");
|
||||
}
|
||||
|
||||
return (
|
||||
<Shell>
|
||||
<Link href="/" className="text-sm text-blue-300">Volver al dashboard</Link>
|
||||
<div className="mt-4 flex flex-wrap items-center justify-between gap-4">
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold">{document?.title || "Documento"}</h1>
|
||||
<p className="mt-1 text-sm text-slate-400">{dirty ? "Cambios sin guardar" : "Sin cambios pendientes"} {status && `- ${status}`}</p>
|
||||
</div>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
<Button onClick={save} disabled={!dirty}>Guardar</Button>
|
||||
<Button className="bg-slate-700 hover:bg-slate-600" onClick={copy}>Copiar</Button>
|
||||
<a className="rounded-xl border border-white/10 px-4 py-2 hover:bg-white/10" href={api.downloadDocumentUrl(documentId)}>Descargar .md</a>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-6 grid gap-6 xl:grid-cols-2">
|
||||
<Card className="p-0">
|
||||
<div className="border-b border-white/10 px-4 py-3 font-medium">Editor Markdown</div>
|
||||
<textarea value={content} onChange={(event) => setContent(event.target.value)} className="h-[72vh] w-full resize-none rounded-b-2xl bg-slate-950 p-4 font-mono text-sm leading-6 outline-none" />
|
||||
</Card>
|
||||
<Card className="overflow-auto">
|
||||
<div className="mb-4 font-medium">Vista previa</div>
|
||||
<article className="prose prose-invert prose-slate">
|
||||
<ReactMarkdown remarkPlugins={[remarkGfm]}>{content}</ReactMarkdown>
|
||||
</article>
|
||||
</Card>
|
||||
</div>
|
||||
</Shell>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user