website-01/components/admin/MarkdownImport.tsx

83 lines
2.0 KiB
TypeScript
Raw Permalink Normal View History

2026-06-22 14:43:46 +08:00
'use client';
import { useRef, useState } from 'react';
import { FileUp, Loader2 } from 'lucide-react';
import { Button } from '@/components/ui/button';
interface MarkdownImportProps {
/** 上传成功后回调,传入 MD 原文和文件名 */
onImport: (markdown: string, filename: string) => void;
/** 错误回调 */
onError?: (msg: string) => void;
/** 单文件大小上限(字节),默认 2MB */
maxSize?: number;
}
/**
* Markdown
* - .md / .markdown
* - onImport
*/
export function MarkdownImport({
onImport,
onError,
maxSize = 2 * 1024 * 1024,
}: MarkdownImportProps) {
const inputRef = useRef<HTMLInputElement>(null);
const [loading, setLoading] = useState(false);
const handleFile = async (file: File) => {
const isMd =
/\.md$/i.test(file.name) ||
/\.markdown$/i.test(file.name) ||
file.type === 'text/markdown';
if (!isMd) {
onError?.('请选择 .md 或 .markdown 文件');
return;
}
if (file.size > maxSize) {
onError?.('文件不能超过 2M');
return;
}
setLoading(true);
try {
const text = await file.text();
onImport(text, file.name);
} catch (e) {
onError?.((e as Error).message);
} finally {
setLoading(false);
}
};
return (
<>
<input
ref={inputRef}
type="file"
accept=".md,.markdown,text/markdown"
className="hidden"
onChange={(e) => {
const f = e.target.files?.[0];
if (f) void handleFile(f);
e.target.value = '';
}}
/>
<Button
type="button"
variant="outline"
size="sm"
onClick={() => inputRef.current?.click()}
disabled={loading}
>
{loading ? (
<Loader2 className="h-4 w-4 animate-spin" />
) : (
<FileUp className="h-4 w-4" />
)}
Markdown
</Button>
</>
);
}