first commit
This commit is contained in:
125
src/components/ActionsPanel.tsx
Normal file
125
src/components/ActionsPanel.tsx
Normal file
@@ -0,0 +1,125 @@
|
||||
import React, { useState } from 'react';
|
||||
import type { SplitResult } from '../pdf/pdfTypes';
|
||||
|
||||
interface ActionsPanelProps {
|
||||
hasPdf: boolean;
|
||||
onSplit: () => void;
|
||||
onExtractRange: (from: number, to: number) => void;
|
||||
isBusy: boolean;
|
||||
splitResults: SplitResult[];
|
||||
rangeDownloadUrl: string | null;
|
||||
rangeFilename: string | null;
|
||||
}
|
||||
|
||||
const ActionsPanel: React.FC<ActionsPanelProps> = ({
|
||||
hasPdf,
|
||||
onSplit,
|
||||
onExtractRange,
|
||||
isBusy,
|
||||
splitResults,
|
||||
rangeDownloadUrl,
|
||||
rangeFilename,
|
||||
}) => {
|
||||
const [fromPage, setFromPage] = useState<string>('');
|
||||
const [toPage, setToPage] = useState<string>('');
|
||||
|
||||
const handleExtractClick = () => {
|
||||
const from = parseInt(fromPage, 10);
|
||||
const to = parseInt(toPage, 10);
|
||||
if (!Number.isFinite(from) || !Number.isFinite(to)) return;
|
||||
onExtractRange(from, to);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="card">
|
||||
<h2>3. Actions</h2>
|
||||
<p>Split into single pages or extract a continuous range.</p>
|
||||
|
||||
<div className="button-row">
|
||||
<button
|
||||
className="primary"
|
||||
disabled={!hasPdf || isBusy}
|
||||
onClick={onSplit}
|
||||
>
|
||||
{isBusy ? 'Splitting…' : 'Split into single pages'}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<hr style={{ margin: '0.75rem 0', borderColor: '#e5e7eb' }} />
|
||||
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: '0.4rem' }}>
|
||||
<div>
|
||||
<strong>Extract range:</strong>
|
||||
</div>
|
||||
<div style={{ display: 'flex', gap: '0.5rem', alignItems: 'center' }}>
|
||||
<label>
|
||||
From
|
||||
<input
|
||||
type="number"
|
||||
min={1}
|
||||
value={fromPage}
|
||||
onChange={(e) => setFromPage(e.target.value)}
|
||||
style={{ marginLeft: '0.3rem', width: '4rem' }}
|
||||
/>
|
||||
</label>
|
||||
<label>
|
||||
To
|
||||
<input
|
||||
type="number"
|
||||
min={1}
|
||||
value={toPage}
|
||||
onChange={(e) => setToPage(e.target.value)}
|
||||
style={{ marginLeft: '0.3rem', width: '4rem' }}
|
||||
/>
|
||||
</label>
|
||||
<button
|
||||
className="secondary"
|
||||
disabled={!hasPdf || isBusy}
|
||||
onClick={handleExtractClick}
|
||||
>
|
||||
{isBusy ? 'Working…' : 'Extract'}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{rangeDownloadUrl && rangeFilename && (
|
||||
<div style={{ marginTop: '0.5rem', fontSize: '0.9rem' }}>
|
||||
<strong>Range result:</strong>{' '}
|
||||
<a
|
||||
className="download-link"
|
||||
href={rangeDownloadUrl}
|
||||
download={rangeFilename}
|
||||
>
|
||||
Download {rangeFilename}
|
||||
</a>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{splitResults.length > 0 && (
|
||||
<div style={{ marginTop: '0.75rem', fontSize: '0.9rem' }}>
|
||||
<strong>Split result:</strong>
|
||||
<div>
|
||||
{splitResults.map((r) => {
|
||||
const url = URL.createObjectURL(r.blob);
|
||||
return (
|
||||
<a
|
||||
key={r.pageIndex}
|
||||
className="download-link"
|
||||
href={url}
|
||||
download={r.filename}
|
||||
onClick={() => {
|
||||
setTimeout(() => URL.revokeObjectURL(url), 5000);
|
||||
}}
|
||||
>
|
||||
Download {r.filename}
|
||||
</a>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ActionsPanel;
|
||||
Reference in New Issue
Block a user