Files
pdf/frontend/src/components/Toolbar.tsx
T

169 lines
5.3 KiB
TypeScript

import React from 'react';
interface ToolbarProps {
zoom: number;
onZoomChange: (zoom: number) => void;
rotation: number;
onRotationChange: (rot: number) => void;
activeTool: string;
onActiveToolChange: (tool: string) => void;
currentPage: number;
totalPages: number;
onUploadStart?: (file: File) => void;
backendHealthy: boolean | null;
wasmEngineInfo?: string;
wasmHasSkia?: boolean;
}
export const Toolbar: React.FC<ToolbarProps> = ({
zoom,
onZoomChange,
rotation,
onRotationChange,
activeTool,
onActiveToolChange,
currentPage,
totalPages,
onUploadStart,
backendHealthy,
wasmEngineInfo,
wasmHasSkia,
}) => {
const handleZoomPercentSelect = (e: React.ChangeEvent<HTMLSelectElement>) => {
const val = parseFloat(e.target.value);
onZoomChange(val);
};
const handleFileUpload = (e: React.ChangeEvent<HTMLInputElement>) => {
const file = e.target.files?.[0];
if (file && onUploadStart) {
onUploadStart(file);
}
};
return (
<div className="toolbar">
{/* Logo & Health */}
<div className="toolbar-section">
<div className="logo-container">
<div className="logo-badge">DQ</div>
<span className="logo-text">
DocQube<span className="logo-sub">PDF</span>
</span>
</div>
<div className={`health-badge status-${backendHealthy === null ? 'checking' : backendHealthy ? 'healthy' : 'unhealthy'}`}>
<span className="health-dot" />
{backendHealthy === null
? 'Checking Gateway...'
: backendHealthy
? 'Gateway Connected'
: 'Gateway Offline'}
</div>
</div>
{/* Center Tools (Zoom, Rotate, Navigate) */}
<div className="toolbar-center">
<div className="page-indicator">
<span>Page</span>
<span className="page-current">{currentPage + 1}</span>
<span className="page-separator">/</span>
<span>{totalPages}</span>
</div>
<div className="divider-vertical" />
<div className="zoom-controls">
<button
onClick={() => onZoomChange(Math.max(0.5, zoom - 0.25))}
className="btn-icon"
title="Zoom Out"
>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2.5}>
<path strokeLinecap="round" strokeLinejoin="round" d="M20 12H4" />
</svg>
</button>
<select
value={zoom}
onChange={handleZoomPercentSelect}
className="zoom-select"
>
<option value="0.5">50%</option>
<option value="0.75">75%</option>
<option value="1.0">100%</option>
<option value="1.25">125%</option>
<option value="1.5">150%</option>
<option value="2.0">200%</option>
</select>
<button
onClick={() => onZoomChange(Math.min(3.0, zoom + 0.25))}
className="btn-icon"
title="Zoom In"
>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2.5}>
<path strokeLinecap="round" strokeLinejoin="round" d="M12 4v16m8-8H4" />
</svg>
</button>
</div>
<div className="divider-vertical" />
<button
onClick={() => onRotationChange((rotation + 90) % 360)}
className="btn-icon"
title="Rotate Clockwise"
>
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
<path strokeLinecap="round" strokeLinejoin="round" d="M4 4v5h.582m15.356 2A8.001 8.001 0 1121.21 7.89M9 11l3-3 3 3m-3-3v12" />
</svg>
</button>
</div>
{/* Right Tools (Active tool highlights, Upload) */}
<div className="toolbar-section gap-3">
<div className="tool-selector">
<button
onClick={() => onActiveToolChange('select')}
className={`tool-btn ${activeTool === 'select' ? 'active' : ''}`}
title="Select Text"
>
Select
</button>
<button
onClick={() => onActiveToolChange('highlight')}
className={`tool-btn highlight ${activeTool === 'highlight' ? 'active' : ''}`}
title="Highlight Ink"
>
Highlight
</button>
<button
onClick={() => onActiveToolChange('signature')}
className={`tool-btn signature ${activeTool === 'signature' ? 'active' : ''}`}
title="Place Digital Signature"
>
Signature
</button>
</div>
<label className="upload-btn">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2.5}>
<path strokeLinecap="round" strokeLinejoin="round" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-8l-4-4m0 0L8 8m4-4v12" />
</svg>
Upload PDF
<input
type="file"
accept=".pdf"
onChange={handleFileUpload}
className="hidden-file-input"
/>
</label>
</div>
</div>
);
};