freeze v0.2.0

This commit is contained in:
2026-05-16 20:07:52 +02:00
parent afeb46a210
commit bdbb6c0a1c
9 changed files with 857 additions and 161 deletions

View File

@@ -0,0 +1,166 @@
import React, { useEffect } from 'react';
interface HelpDialogProps {
open: boolean;
onClose: () => void;
}
const shortcuts = [
{ keys: 'F1 / ?', description: 'Open this help and tutorial dialog' },
{ keys: 'Ctrl/⌘ + A', description: 'Select all pages in the current workspace' },
{ keys: 'Delete / Backspace', description: 'Delete the selected pages after confirmation' },
{ keys: 'Esc', description: 'Clear the page selection or close an open dialog' },
{ keys: 'Ctrl/⌘ + Z', description: 'Undo the latest workspace command' },
{ keys: 'Ctrl/⌘ + Shift + Z', description: 'Redo the next workspace command' },
{ keys: 'Ctrl/⌘ + Y', description: 'Redo the next workspace command' },
{ keys: '← / → in preview', description: 'Move to the previous or next page in the preview overlay' },
];
const tutorialSteps = [
{
title: '1. Open a PDF or load a workspace',
body: 'Start by selecting a local PDF file. If you saved workspaces before, you can restore one from browser storage instead.',
},
{
title: '2. Arrange pages visually',
body: 'Drag page cards to reorder them. Rotate single pages, open the large preview with a click, or remove pages you do not want in the export.',
},
{
title: '3. Select, copy, and delete pages',
body: 'Use the checkbox on a page card to select it. Shift-click extends a range. Dragging a selected page moves the whole selection; the copy controls duplicate selected pages into a chosen slot.',
},
{
title: '4. Save your workspace or export a PDF',
body: 'Saving a workspace keeps the current working state in this browser. Exporting creates a new PDF file for download.',
},
{
title: '5. Use history deliberately',
body: 'Each workspace operation is stored as a command with label and timestamp. Undo and redo walk through that command history.',
},
];
const HelpDialog: React.FC<HelpDialogProps> = ({ open, onClose }) => {
useEffect(() => {
if (!open) return;
const handleKeyDown = (e: KeyboardEvent) => {
if (e.key !== 'Escape') return;
e.preventDefault();
e.stopPropagation();
e.stopImmediatePropagation();
onClose();
};
window.addEventListener('keydown', handleKeyDown, { capture: true });
return () => {
window.removeEventListener('keydown', handleKeyDown, { capture: true });
};
}, [open, onClose]);
if (!open) return null;
return (
<div
className="help-dialog-backdrop"
role="dialog"
aria-modal="true"
aria-labelledby="help-dialog-title"
onPointerDown={(e) => {
if (e.target === e.currentTarget) {
onClose();
}
}}
>
<div className="help-dialog-panel">
<div className="help-dialog-header">
<div>
<h2 id="help-dialog-title">Help & tutorial</h2>
<p>
PDF Workbench is a browser-only page workspace. Use it to quickly
rearrange, split, merge, rotate, duplicate, and export PDFs without
uploading documents to a server.
</p>
</div>
<button
type="button"
className="help-close-button"
onClick={onClose}
aria-label="Close help"
title="Close help (Esc)"
>
×
</button>
</div>
<div className="help-dialog-content">
<section className="help-section">
<h3>Quick tutorial</h3>
<div className="help-step-list">
{tutorialSteps.map((step) => (
<article key={step.title} className="help-step">
<h4>{step.title}</h4>
<p>{step.body}</p>
</article>
))}
</div>
</section>
<section className="help-section">
<h3>Keyboard shortcuts</h3>
<div className="shortcut-grid">
{shortcuts.map((shortcut) => (
<React.Fragment key={shortcut.keys}>
<kbd>{shortcut.keys}</kbd>
<span>{shortcut.description}</span>
</React.Fragment>
))}
</div>
<p className="help-note">
Shortcuts are ignored while typing in text fields or other editable
controls.
</p>
</section>
<section className="help-section help-concepts">
<h3>Important concepts</h3>
<dl>
<div>
<dt>Browser-only processing</dt>
<dd>
PDF operations run in your browser. A self-hosted server only
delivers the static app files.
</dd>
</div>
<div>
<dt>Workspace</dt>
<dd>
A named local editing state, including the PDF binary, page
order, rotations, selection, and command history.
</dd>
</div>
<div>
<dt>Export</dt>
<dd>
A generated PDF download. Exported files are separate from
saved workspaces.
</dd>
</div>
<div>
<dt>History</dt>
<dd>
Undoable commands show what changed, when it changed, and
where the current point in history is.
</dd>
</div>
</dl>
</section>
</div>
</div>
</div>
);
};
export default HelpDialog;