414c1f7d68
Includes changes from prior sessions: Epilogue + Space Mono fonts, OverlayScrollbars integration, markdown editor fixes, settings dialog, import/export buttons, and various UI refinements.
75 lines
2.2 KiB
TypeScript
75 lines
2.2 KiB
TypeScript
import { useRef } from "react";
|
|
import { Upload } from "lucide-react";
|
|
import { Button } from "@/components/ui/button";
|
|
import { useAppStore } from "@/stores/app-store";
|
|
import { useBoardStore } from "@/stores/board-store";
|
|
import { useToastStore } from "@/stores/toast-store";
|
|
import { saveBoard } from "@/lib/storage";
|
|
import {
|
|
importBoardFromJson,
|
|
importFromTrelloJson,
|
|
} from "@/lib/import-export";
|
|
|
|
export function ImportButton() {
|
|
const fileInputRef = useRef<HTMLInputElement>(null);
|
|
const addToast = useToastStore((s) => s.addToast);
|
|
const refreshBoards = useAppStore((s) => s.refreshBoards);
|
|
const setView = useAppStore((s) => s.setView);
|
|
const addRecentBoard = useAppStore((s) => s.addRecentBoard);
|
|
const openBoard = useBoardStore((s) => s.openBoard);
|
|
|
|
function handleImportClick() {
|
|
fileInputRef.current?.click();
|
|
}
|
|
|
|
async function handleFileSelected(e: React.ChangeEvent<HTMLInputElement>) {
|
|
const file = e.target.files?.[0];
|
|
if (!file) return;
|
|
|
|
try {
|
|
const text = await file.text();
|
|
let imported;
|
|
|
|
// Try to detect if it's a Trello export
|
|
const parsed = JSON.parse(text);
|
|
if (parsed.lists && parsed.cards && !parsed.columns) {
|
|
// Looks like Trello format
|
|
imported = importFromTrelloJson(text);
|
|
} else {
|
|
imported = importBoardFromJson(text);
|
|
}
|
|
|
|
await saveBoard(imported);
|
|
await refreshBoards();
|
|
await openBoard(imported.id);
|
|
setView({ type: "board", boardId: imported.id });
|
|
addRecentBoard(imported.id);
|
|
addToast("Board imported successfully", "success");
|
|
} catch (err) {
|
|
console.error("Import failed:", err);
|
|
addToast("Import failed — check file format", "error");
|
|
}
|
|
|
|
// Reset the input so the same file can be re-imported
|
|
if (fileInputRef.current) {
|
|
fileInputRef.current.value = "";
|
|
}
|
|
}
|
|
|
|
return (
|
|
<>
|
|
<Button variant="outline" size="sm" onClick={handleImportClick}>
|
|
<Upload className="size-4" />
|
|
Import
|
|
</Button>
|
|
<input
|
|
ref={fileInputRef}
|
|
type="file"
|
|
accept=".json"
|
|
onChange={handleFileSelected}
|
|
className="hidden"
|
|
/>
|
|
</>
|
|
);
|
|
}
|