214 lines
5.0 KiB
TypeScript
214 lines
5.0 KiB
TypeScript
import React from 'react';
|
|
import type { PageRef } from '../../pdf/pdfTypes';
|
|
import DropIndicator from './DropIndicator';
|
|
|
|
interface PageCardProps {
|
|
page: PageRef;
|
|
visualIndex: number;
|
|
thumbnail?: string;
|
|
selected: boolean;
|
|
isDraggingCard: boolean;
|
|
isBusy: boolean;
|
|
isCopyDragging: boolean;
|
|
showLeftLine: boolean;
|
|
showRightLine: boolean;
|
|
dropIndicatorColor: string;
|
|
onDragStart: React.DragEventHandler<HTMLDivElement>;
|
|
onDragEnd: React.DragEventHandler<HTMLDivElement>;
|
|
onDragOver: React.DragEventHandler<HTMLDivElement>;
|
|
onOpenPreview: () => void;
|
|
onToggleSelect: React.MouseEventHandler<HTMLButtonElement>;
|
|
onRotateClockwise: () => void;
|
|
onRotateCounterclockwise: () => void;
|
|
onDelete: () => void;
|
|
}
|
|
|
|
const pageActionButtonStyle: React.CSSProperties = {
|
|
border: 'none',
|
|
borderRadius: '999px',
|
|
padding: '0.15rem 0.4rem',
|
|
fontSize: '0.75rem',
|
|
cursor: 'pointer',
|
|
};
|
|
|
|
const PageCard: React.FC<PageCardProps> = ({
|
|
page,
|
|
visualIndex,
|
|
thumbnail,
|
|
selected,
|
|
isDraggingCard,
|
|
isBusy,
|
|
isCopyDragging,
|
|
showLeftLine,
|
|
showRightLine,
|
|
dropIndicatorColor,
|
|
onDragStart,
|
|
onDragEnd,
|
|
onDragOver,
|
|
onOpenPreview,
|
|
onToggleSelect,
|
|
onRotateClockwise,
|
|
onRotateCounterclockwise,
|
|
onDelete,
|
|
}) => {
|
|
const background = isDraggingCard
|
|
? isCopyDragging
|
|
? '#dcfce7'
|
|
: '#dbeafe'
|
|
: selected
|
|
? '#eff6ff'
|
|
: '#f9fafb';
|
|
|
|
return (
|
|
<div
|
|
draggable
|
|
onDragStart={onDragStart}
|
|
onDragEnd={onDragEnd}
|
|
onDragOver={onDragOver}
|
|
onClick={onOpenPreview}
|
|
style={{
|
|
position: 'relative',
|
|
width: '162px',
|
|
padding: '0.4rem',
|
|
borderRadius: '0.5rem',
|
|
border: '1px solid #e5e7eb',
|
|
background,
|
|
display: 'flex',
|
|
flexDirection: 'column',
|
|
alignItems: 'center',
|
|
gap: '0.25rem',
|
|
cursor: isBusy ? 'default' : isCopyDragging ? 'copy' : 'grab',
|
|
opacity: isBusy ? 0.7 : 1,
|
|
}}
|
|
>
|
|
<button
|
|
type="button"
|
|
onClick={onToggleSelect}
|
|
style={{
|
|
position: 'absolute',
|
|
top: '4px',
|
|
left: '4px',
|
|
width: '20px',
|
|
height: '20px',
|
|
borderRadius: '0.4rem',
|
|
border: '1px solid #9ca3af',
|
|
background: selected ? '#2563eb' : 'rgba(255,255,255,0.9)',
|
|
color: selected ? 'white' : 'transparent',
|
|
fontSize: '0.8rem',
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
padding: 0,
|
|
cursor: 'pointer',
|
|
}}
|
|
title="Select page"
|
|
>
|
|
✓
|
|
</button>
|
|
|
|
{showLeftLine && <DropIndicator side="left" color={dropIndicatorColor} />}
|
|
{showRightLine && (
|
|
<DropIndicator side="right" color={dropIndicatorColor} />
|
|
)}
|
|
|
|
<div
|
|
style={{
|
|
width: '110px',
|
|
height: '90px',
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
}}
|
|
>
|
|
{thumbnail ? (
|
|
<img
|
|
src={thumbnail}
|
|
alt={`Page ${page.sourcePageIndex + 1}`}
|
|
style={{
|
|
maxWidth: '100%',
|
|
maxHeight: '100%',
|
|
width: 'auto',
|
|
height: 'auto',
|
|
objectFit: 'contain',
|
|
borderRadius: '0.25rem',
|
|
border: '1px solid #e5e7eb',
|
|
background: 'white',
|
|
}}
|
|
/>
|
|
) : (
|
|
<div
|
|
style={{
|
|
width: '60px',
|
|
height: '80px',
|
|
borderRadius: '0.25rem',
|
|
border: '1px dashed #d1d5db',
|
|
background: '#f3f4f6',
|
|
}}
|
|
/>
|
|
)}
|
|
</div>
|
|
|
|
<span style={{ fontSize: '0.8rem' }}>
|
|
Page {page.sourcePageIndex + 1}
|
|
</span>
|
|
<span style={{ fontSize: '0.7rem', color: '#6b7280' }}>
|
|
Pos {visualIndex + 1} · Rot {page.rotation}°
|
|
</span>
|
|
|
|
<div
|
|
style={{
|
|
display: 'flex',
|
|
gap: '0.25rem',
|
|
marginTop: '0.25rem',
|
|
}}
|
|
>
|
|
<button
|
|
type="button"
|
|
onClick={(e) => {
|
|
e.stopPropagation();
|
|
onRotateClockwise();
|
|
}}
|
|
style={{
|
|
...pageActionButtonStyle,
|
|
background: '#e5e7eb',
|
|
}}
|
|
>
|
|
↻ 90°
|
|
</button>
|
|
|
|
<button
|
|
type="button"
|
|
onClick={(e) => {
|
|
e.stopPropagation();
|
|
onRotateCounterclockwise();
|
|
}}
|
|
style={{
|
|
...pageActionButtonStyle,
|
|
background: '#e5e7eb',
|
|
}}
|
|
>
|
|
↺ 90°
|
|
</button>
|
|
|
|
<button
|
|
type="button"
|
|
onClick={(e) => {
|
|
e.stopPropagation();
|
|
onDelete();
|
|
}}
|
|
style={{
|
|
...pageActionButtonStyle,
|
|
background: '#fecaca',
|
|
color: '#b91c1c',
|
|
}}
|
|
title="Remove this page from the exported PDF"
|
|
>
|
|
✕
|
|
</button>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default PageCard;
|