feat: update PDF tool pages with interactive options, promote split/compress to phase 1
- pdf-split: page range input (1-3,5,7-9) with example - pdf-compress: upload zone with description - tool-grid: split/compress jadi phase 1 (backend udah implement) - merge/images-to-pdf tetap phase 2 (butuh multi-file upload) Co-Authored-By: Kilo <kilo@kilo.ai>
This commit is contained in:
@@ -16,10 +16,7 @@ export default function PdfCompressPage() {
|
|||||||
const [jobId, setJobId] = useState<string | null>(null);
|
const [jobId, setJobId] = useState<string | null>(null);
|
||||||
const [errorMsg, setErrorMsg] = useState<string | null>(null);
|
const [errorMsg, setErrorMsg] = useState<string | null>(null);
|
||||||
|
|
||||||
const { upload } = useUpload({
|
const { upload } = useUpload({ tool: "pdf-compress" });
|
||||||
tool: "pdf-compress",
|
|
||||||
options: { quality: 80 },
|
|
||||||
});
|
|
||||||
|
|
||||||
const handleComplete = useCallback(() => setPageState("result"), []);
|
const handleComplete = useCallback(() => setPageState("result"), []);
|
||||||
const handleError = useCallback(
|
const handleError = useCallback(
|
||||||
@@ -58,44 +55,28 @@ export default function PdfCompressPage() {
|
|||||||
title="Compress PDF"
|
title="Compress PDF"
|
||||||
description="Kecilin ukuran PDF"
|
description="Kecilin ukuran PDF"
|
||||||
icon={FileImage}
|
icon={FileImage}
|
||||||
phase={2}
|
phase={1}
|
||||||
>
|
>
|
||||||
{pageState === "upload" && (
|
{pageState === "upload" && (
|
||||||
<UploadZone
|
<UploadZone
|
||||||
accept="application/pdf"
|
accept=".pdf,application/pdf"
|
||||||
tool="pdf-compress"
|
tool="pdf-compress"
|
||||||
onUpload={handleUpload}
|
onUpload={handleUpload}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{pageState === "processing" && jobId && (
|
{pageState === "processing" && jobId && (
|
||||||
<ProgressBar
|
<ProgressBar progress={progress} stage={stage} message={message} status={status} onRetry={handleRetry} />
|
||||||
progress={progress}
|
|
||||||
stage={stage}
|
|
||||||
message={message}
|
|
||||||
status={status}
|
|
||||||
onRetry={handleRetry}
|
|
||||||
/>
|
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{pageState === "result" && result && (
|
{pageState === "result" && result && (
|
||||||
<ResultPreview
|
<ResultPreview result={result} onProcessAnother={handleRetry} />
|
||||||
result={result}
|
|
||||||
onProcessAnother={handleRetry}
|
|
||||||
/>
|
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{pageState === "error" && (
|
{pageState === "error" && (
|
||||||
<div className="p-6 rounded-xl border border-destructive/20 bg-destructive/5 text-center">
|
<div className="p-6 rounded-xl border border-destructive/20 bg-destructive/5 text-center">
|
||||||
<p className="text-destructive font-medium mb-4">
|
<p className="text-destructive font-medium mb-4">{errorMsg || "Terjadi kesalahan"}</p>
|
||||||
{errorMsg || "Terjadi kesalahan"}
|
<button onClick={handleRetry} className="px-4 py-2 bg-primary text-primary-foreground rounded-lg hover:opacity-90">Coba Lagi</button>
|
||||||
</p>
|
|
||||||
<button
|
|
||||||
onClick={handleRetry}
|
|
||||||
className="px-4 py-2 bg-primary text-primary-foreground rounded-lg hover:opacity-90"
|
|
||||||
>
|
|
||||||
Coba Lagi
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</ToolLayout>
|
</ToolLayout>
|
||||||
|
|||||||
@@ -15,10 +15,11 @@ export default function PdfSplitPage() {
|
|||||||
const [pageState, setPageState] = useState<PageState>("upload");
|
const [pageState, setPageState] = useState<PageState>("upload");
|
||||||
const [jobId, setJobId] = useState<string | null>(null);
|
const [jobId, setJobId] = useState<string | null>(null);
|
||||||
const [errorMsg, setErrorMsg] = useState<string | null>(null);
|
const [errorMsg, setErrorMsg] = useState<string | null>(null);
|
||||||
|
const [pages, setPages] = useState("1,3-5");
|
||||||
|
|
||||||
const { upload } = useUpload({
|
const { upload } = useUpload({
|
||||||
tool: "pdf-split",
|
tool: "pdf-split",
|
||||||
options: { quality: 80 },
|
options: { pages },
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleComplete = useCallback(() => setPageState("result"), []);
|
const handleComplete = useCallback(() => setPageState("result"), []);
|
||||||
@@ -56,46 +57,46 @@ export default function PdfSplitPage() {
|
|||||||
return (
|
return (
|
||||||
<ToolLayout
|
<ToolLayout
|
||||||
title="Split PDF"
|
title="Split PDF"
|
||||||
description="Ekstrak halaman tertentu"
|
description="Ekstrak halaman tertentu dari PDF"
|
||||||
icon={Split}
|
icon={Split}
|
||||||
phase={2}
|
phase={1}
|
||||||
>
|
>
|
||||||
{pageState === "upload" && (
|
{pageState === "upload" && (
|
||||||
<UploadZone
|
<div className="space-y-6">
|
||||||
accept="application/pdf"
|
<div className="p-6 rounded-xl border glass space-y-3">
|
||||||
tool="pdf-split"
|
<h3 className="font-semibold">Page Range</h3>
|
||||||
onUpload={handleUpload}
|
<p className="text-xs text-muted-foreground">
|
||||||
/>
|
Contoh: <code className="bg-muted px-1 rounded">1-3,5,7-9</code> ambil halaman 1-3, 5, dan 7-9
|
||||||
|
</p>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value={pages}
|
||||||
|
onChange={(e) => setPages(e.target.value)}
|
||||||
|
className="w-full bg-muted border rounded px-3 py-2 text-sm font-mono"
|
||||||
|
placeholder="1-3,5,7-9"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<UploadZone
|
||||||
|
accept=".pdf,application/pdf"
|
||||||
|
tool="pdf-split"
|
||||||
|
onUpload={handleUpload}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{pageState === "processing" && jobId && (
|
{pageState === "processing" && jobId && (
|
||||||
<ProgressBar
|
<ProgressBar progress={progress} stage={stage} message={message} status={status} onRetry={handleRetry} />
|
||||||
progress={progress}
|
|
||||||
stage={stage}
|
|
||||||
message={message}
|
|
||||||
status={status}
|
|
||||||
onRetry={handleRetry}
|
|
||||||
/>
|
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{pageState === "result" && result && (
|
{pageState === "result" && result && (
|
||||||
<ResultPreview
|
<ResultPreview result={result} onProcessAnother={handleRetry} />
|
||||||
result={result}
|
|
||||||
onProcessAnother={handleRetry}
|
|
||||||
/>
|
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{pageState === "error" && (
|
{pageState === "error" && (
|
||||||
<div className="p-6 rounded-xl border border-destructive/20 bg-destructive/5 text-center">
|
<div className="p-6 rounded-xl border border-destructive/20 bg-destructive/5 text-center">
|
||||||
<p className="text-destructive font-medium mb-4">
|
<p className="text-destructive font-medium mb-4">{errorMsg || "Terjadi kesalahan"}</p>
|
||||||
{errorMsg || "Terjadi kesalahan"}
|
<button onClick={handleRetry} className="px-4 py-2 bg-primary text-primary-foreground rounded-lg hover:opacity-90">Coba Lagi</button>
|
||||||
</p>
|
|
||||||
<button
|
|
||||||
onClick={handleRetry}
|
|
||||||
className="px-4 py-2 bg-primary text-primary-foreground rounded-lg hover:opacity-90"
|
|
||||||
>
|
|
||||||
Coba Lagi
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</ToolLayout>
|
</ToolLayout>
|
||||||
|
|||||||
@@ -82,10 +82,10 @@ const tools: ToolDefinition[] = [
|
|||||||
{
|
{
|
||||||
id: "pdf-split",
|
id: "pdf-split",
|
||||||
title: "Split PDF",
|
title: "Split PDF",
|
||||||
description: "Ekstrak halaman tertentu dari PDF. Pilih via thumbnail atau range.",
|
description: "Ekstrak halaman tertentu dari PDF. Pilih page range seperti 1-3,5,7-9.",
|
||||||
icon: Split,
|
icon: Split,
|
||||||
href: "/pdf/split",
|
href: "/pdf/split",
|
||||||
phase: 2,
|
phase: 1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "images-to-pdf",
|
id: "images-to-pdf",
|
||||||
@@ -98,10 +98,10 @@ const tools: ToolDefinition[] = [
|
|||||||
{
|
{
|
||||||
id: "pdf-compress",
|
id: "pdf-compress",
|
||||||
title: "Compress PDF",
|
title: "Compress PDF",
|
||||||
description: "Kecilin ukuran PDF dengan kompresi embedded images.",
|
description: "Kecilin ukuran PDF dengan kompresi ulang.",
|
||||||
icon: FileImage,
|
icon: FileImage,
|
||||||
href: "/pdf/compress",
|
href: "/pdf/compress",
|
||||||
phase: 2,
|
phase: 1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "video-compress",
|
id: "video-compress",
|
||||||
|
|||||||
Reference in New Issue
Block a user