Entity export and stuff

This commit is contained in:
2026-02-27 23:23:43 +01:00
parent bcb9fdb027
commit e9c0bf5c52
6 changed files with 726 additions and 9 deletions
+7 -1
View File
@@ -87,6 +87,7 @@ export default function Router({
statuses={entity.config.statuses}
setTags={setTags}
setStatuses={setStatuses}
entityName={entity.name}
/>
);
}
@@ -101,7 +102,12 @@ export default function Router({
return (
<div className="h-full w-3xl mx-auto bg-card rounded-2xl p-6 border">
<DocView key={entity.id} doc={entity.content} setDoc={setDoc} />
<DocView
key={entity.id}
doc={entity.content}
setDoc={setDoc}
docName={entity.name}
/>
</div>
);
}
+80 -2
View File
@@ -1,6 +1,6 @@
"use client";
import { useEffect, useRef } from "react";
import { useEffect, useRef, useState } from "react";
import Header from "@editorjs/header";
import List from "@editorjs/list";
@@ -11,6 +11,21 @@ import Delimiter from "@editorjs/delimiter";
import Warning from "@editorjs/warning";
import InlineCode from "@editorjs/inline-code";
import { OutputData } from "@editorjs/editorjs";
import {
downloadFile,
exportDocAsJson,
exportDocAsMarkdown,
exportDocAsHtml,
} from "@/lib/export";
import { Button } from "@/components/ui/button";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
DropdownMenuSeparator,
} from "@/components/ui/dropdown-menu";
import { FileDown } from "lucide-react";
function toMarkdown(data: OutputData): string {
return data.blocks
@@ -55,11 +70,48 @@ function toMarkdown(data: OutputData): string {
export default function DocView({
doc,
setDoc,
docName = "Document",
}: {
doc: OutputData;
setDoc: (data: OutputData) => void;
docName?: string;
}) {
const holderRef = useRef<HTMLDivElement | null>(null);
const [isExporting, setIsExporting] = useState(false);
const handleExport = (format: "json" | "markdown" | "html") => {
const docEntity = {
id: "",
type: "doc" as const,
name: docName,
content: doc,
createdAt: Date.now(),
updatedAt: Date.now(),
};
let content = "";
let filename = `${docName.replace(/\s+/g, "_")}_${Date.now()}`;
switch (format) {
case "json":
content = exportDocAsJson(docEntity);
filename += ".json";
break;
case "markdown":
content = exportDocAsMarkdown(docEntity);
filename += ".md";
break;
case "html":
content = exportDocAsHtml(docEntity);
filename += ".html";
break;
}
downloadFile(
content,
filename,
format === "html" ? "text/html" : "text/plain",
);
};
useEffect(() => {
let editor: any;
@@ -135,5 +187,31 @@ export default function DocView({
};
}, []);
return <div ref={holderRef} className="docs-view h-max w-full" />;
return (
<div className="flex flex-col gap-4">
<div className="flex items-center justify-end gap-2">
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="outline" size="sm" disabled={isExporting}>
<FileDown className="h-4 w-4 mr-2" />
Export
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuItem onClick={() => handleExport("markdown")}>
Export as Markdown
</DropdownMenuItem>
<DropdownMenuItem onClick={() => handleExport("html")}>
Export as HTML
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem onClick={() => handleExport("json")}>
Export as JSON
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</div>
<div ref={holderRef} className="docs-view h-max w-full" />
</div>
);
}
+77 -1
View File
@@ -6,6 +6,22 @@ import BoardView from "./board/BoardView";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "../ui/tabs";
import { TableView } from "./table/TableView";
import EditView from "./edit/EditView";
import { Button } from "@/components/ui/button";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
DropdownMenuSeparator,
} from "@/components/ui/dropdown-menu";
import { FileDown } from "lucide-react";
import {
downloadFile,
exportTodoAsJson,
exportTodoAsCsv,
exportTodoAsMarkdown,
} from "@/lib/export";
import { useEffect, useState } from "react";
export type TaskViewProps = {
tags: Record<TagId, Tag>;
@@ -25,6 +41,9 @@ export type TaskViewProps = {
/** Create a new task with a status */
createTask: (statusId: string) => void;
/** Entity name for export */
entityName?: string;
};
export default function TaskView({
@@ -35,9 +54,66 @@ export default function TaskView({
setTags,
setStatuses,
createTask,
entityName = "Tasks",
}: TaskViewProps) {
const [isExporting, setIsExporting] = useState(false);
const handleExport = (format: "json" | "csv" | "markdown") => {
const todoEntity = {
id: "",
type: "todo" as const,
name: entityName,
config: { statuses },
tags,
tasks,
createdAt: Date.now(),
updatedAt: Date.now(),
};
let content = "";
let filename = `${entityName.replace(/\s+/g, "_")}_${Date.now()}`;
switch (format) {
case "json":
content = exportTodoAsJson(todoEntity);
filename += ".json";
break;
case "csv":
content = exportTodoAsCsv(todoEntity);
filename += ".csv";
break;
case "markdown":
content = exportTodoAsMarkdown(todoEntity);
filename += ".md";
break;
}
downloadFile(content, filename, "text/plain");
};
return (
<div className="px-6 pt-4">
<div className="px-6 pt-4 flex flex-col gap-4">
<div className="flex items-center justify-end">
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="outline" size="sm" disabled={isExporting}>
<FileDown className="h-4 w-4 mr-2" />
Export
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuItem onClick={() => handleExport("csv")}>
Export as CSV
</DropdownMenuItem>
<DropdownMenuItem onClick={() => handleExport("markdown")}>
Export as Markdown
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem onClick={() => handleExport("json")}>
Export as JSON
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</div>
<Tabs defaultValue="board" className="w-full">
<TabsList className="mb-4">
<TabsTrigger value="board">Board</TabsTrigger>