refactoring, linting, formatting

This commit is contained in:
2026-05-17 02:05:27 +02:00
parent bdbb6c0a1c
commit 07f4361573
38 changed files with 6121 additions and 2647 deletions

View File

@@ -1,327 +1,327 @@
import React from 'react';
import type { WorkspaceSummary } from '../workspace/workspaceTypes';
import type { WorkspaceCommandRecord } from '../workspace/workspaceCommands';
import React from "react";
import type { WorkspaceSummary } from "../workspace/workspaceTypes";
import type { WorkspaceCommandRecord } from "../workspace/workspaceCommands";
interface WorkspacePanelProps {
hasPdf: boolean;
isBusy: boolean;
hasPdf: boolean;
isBusy: boolean;
activeWorkspaceId: string | null;
workspaceName: string;
workspaceDirty: boolean;
workspaceMessage: string | null;
activeWorkspaceId: string | null;
workspaceName: string;
workspaceDirty: boolean;
workspaceMessage: string | null;
workspaces: WorkspaceSummary[];
history: WorkspaceCommandRecord[];
redoHistory: WorkspaceCommandRecord[];
workspaces: WorkspaceSummary[];
history: WorkspaceCommandRecord[];
redoHistory: WorkspaceCommandRecord[];
onWorkspaceNameChange: (value: string) => void;
onSaveWorkspace: () => void;
onLoadWorkspace: (workspaceId: string) => void;
onDeleteWorkspace: (workspaceId: string) => void;
onRefreshWorkspaces: () => void;
onResetWorkspace: () => void;
onUndo: () => void;
onRedo: () => void;
onWorkspaceNameChange: (value: string) => void;
onSaveWorkspace: () => void;
onLoadWorkspace: (workspaceId: string) => void;
onDeleteWorkspace: (workspaceId: string) => void;
onRefreshWorkspaces: () => void;
onResetWorkspace: () => void;
onUndo: () => void;
onRedo: () => void;
}
const WorkspacePanel: React.FC<WorkspacePanelProps> = ({
hasPdf,
isBusy,
activeWorkspaceId,
workspaceName,
workspaceDirty,
workspaceMessage,
workspaces,
history,
redoHistory,
onWorkspaceNameChange,
onSaveWorkspace,
onLoadWorkspace,
onDeleteWorkspace,
onRefreshWorkspaces,
onResetWorkspace,
onUndo,
onRedo,
hasPdf,
isBusy,
activeWorkspaceId,
workspaceName,
workspaceDirty,
workspaceMessage,
workspaces,
history,
redoHistory,
onWorkspaceNameChange,
onSaveWorkspace,
onLoadWorkspace,
onDeleteWorkspace,
onRefreshWorkspaces,
onResetWorkspace,
onUndo,
onRedo,
}) => {
const canUndo = history.length > 0;
const canRedo = redoHistory.length > 0;
const canUndo = history.length > 0;
const canRedo = redoHistory.length > 0;
const latestUndo = history[history.length - 1];
const latestRedo = redoHistory[redoHistory.length - 1];
const latestUndo = history[history.length - 1];
const latestRedo = redoHistory[redoHistory.length - 1];
return (
<div className="card">
<h2>Workspace</h2>
return (
<div className="card">
<h2>Workspace</h2>
<p style={{ fontSize: '0.85rem', color: '#6b7280' }}>
Save named workspaces in this browser. PDF binaries are stored in
IndexedDB; nothing is uploaded.
</p>
<p style={{ fontSize: "0.85rem", color: "#6b7280" }}>
Save named workspaces in this browser. PDF binaries are stored in
IndexedDB; nothing is uploaded.
</p>
<div
style={{
display: "flex",
gap: "0.5rem",
flexWrap: "wrap",
alignItems: "center",
}}
>
<input
type="text"
value={workspaceName}
onChange={(e) => onWorkspaceNameChange(e.target.value)}
placeholder="Workspace name"
disabled={!hasPdf || isBusy}
style={{
flex: "1 1 220px",
minWidth: 0,
padding: "0.45rem 0.55rem",
borderRadius: "0.5rem",
border: "1px solid #d1d5db",
fontSize: "0.9rem",
}}
/>
<button
type="button"
className="secondary"
onClick={onUndo}
disabled={!hasPdf || isBusy || !canUndo}
title={latestUndo ? `Undo: ${latestUndo.label}` : "Nothing to undo"}
>
Undo
</button>
<button
type="button"
className="secondary"
onClick={onRedo}
disabled={!hasPdf || isBusy || !canRedo}
title={latestRedo ? `Redo: ${latestRedo.label}` : "Nothing to redo"}
>
Redo
</button>
<button
type="button"
className="secondary"
onClick={onSaveWorkspace}
disabled={!hasPdf || isBusy}
title={!hasPdf ? "Open a PDF first" : "Save workspace"}
>
💾 {activeWorkspaceId ? "Save" : "Save as"}
</button>
<button
type="button"
className="secondary"
onClick={onResetWorkspace}
disabled={!hasPdf || isBusy}
title={
!hasPdf ? "No active workspace" : "Close the current workspace"
}
>
Reset workspace
</button>
<button
type="button"
className="secondary"
onClick={onRefreshWorkspaces}
disabled={isBusy}
>
Refresh
</button>
</div>
{workspaceDirty && hasPdf && (
<div
style={{
marginTop: "0.5rem",
fontSize: "0.8rem",
color: "#92400e",
}}
>
Unsaved workspace changes.
</div>
)}
{workspaceMessage && (
<div
style={{
marginTop: "0.5rem",
fontSize: "0.85rem",
color: "#166534",
}}
>
{workspaceMessage}
</div>
)}
{workspaces.length > 0 && (
<div style={{ marginTop: "0.75rem" }}>
<strong style={{ fontSize: "0.9rem" }}>Saved workspaces</strong>
<div
style={{
display: "flex",
flexDirection: "column",
gap: "0.4rem",
marginTop: "0.4rem",
}}
>
{workspaces.map((workspace) => {
const active = workspace.id === activeWorkspaceId;
return (
<div
key={workspace.id}
style={{
border: "1px solid #e5e7eb",
borderRadius: "0.5rem",
padding: "0.5rem",
background: active ? "#eff6ff" : "#f9fafb",
display: "flex",
justifyContent: "space-between",
gap: "0.75rem",
alignItems: "center",
flexWrap: "wrap",
}}
>
<div style={{ minWidth: 0 }}>
<div style={{ fontSize: "0.9rem" }}>
<strong>{workspace.name}</strong>
{active && (
<span style={{ color: "#2563eb" }}> · active</span>
)}
</div>
<div style={{ fontSize: "0.75rem", color: "#6b7280" }}>
{workspace.pdfName} · source pages:{" "}
{workspace.sourcePageCount} · workspace pages:{" "}
{workspace.workspacePageCount} · undo:{" "}
{workspace.historyCount} · redo: {workspace.redoCount} ·
updated {new Date(workspace.updatedAt).toLocaleString()}
</div>
</div>
<div
style={{
display: "flex",
gap: "0.35rem",
flexWrap: "wrap",
}}
>
<button
type="button"
className="secondary"
disabled={isBusy}
onClick={() => onLoadWorkspace(workspace.id)}
>
Load
</button>
<button
type="button"
className="secondary"
disabled={isBusy}
onClick={() => onDeleteWorkspace(workspace.id)}
style={{
background: "#fee2e2",
color: "#991b1b",
}}
>
Delete
</button>
</div>
</div>
);
})}
</div>
</div>
)}
{(history.length > 0 || redoHistory.length > 0) && (
<details style={{ marginTop: "0.75rem" }} open>
<summary style={{ cursor: "pointer", fontSize: "0.9rem" }}>
Command history ({history.length} undo / {redoHistory.length} redo)
</summary>
<div
style={{
marginTop: "0.5rem",
display: "flex",
flexDirection: "column",
gap: "0.25rem",
}}
>
{history.map((entry, index) => (
<div
key={entry.id}
style={{
fontSize: "0.8rem",
color: "#374151",
borderLeft: "3px solid #2563eb",
paddingLeft: "0.45rem",
paddingTop: "0.2rem",
paddingBottom: "0.2rem",
}}
>
<strong>
Undo {history.length - index}. {entry.label}
</strong>
<br />
<span style={{ color: "#6b7280" }}>
{new Date(entry.timestamp).toLocaleString()}
</span>
</div>
))}
<div
style={{
display: 'flex',
gap: '0.5rem',
flexWrap: 'wrap',
alignItems: 'center',
}}
>
<input
type="text"
value={workspaceName}
onChange={(e) => onWorkspaceNameChange(e.target.value)}
placeholder="Workspace name"
disabled={!hasPdf || isBusy}
style={{
flex: '1 1 220px',
minWidth: 0,
padding: '0.45rem 0.55rem',
borderRadius: '0.5rem',
border: '1px solid #d1d5db',
fontSize: '0.9rem',
}}
/>
style={{
margin: "0.25rem 0",
borderRadius: "999px",
background: "#ecfdf5",
color: "#166534",
fontSize: "0.8rem",
fontWeight: 600,
alignSelf: "flex-start",
border: "2px solid #166534",
width: "100%",
}}
></div>
<button
type="button"
className="secondary"
onClick={onUndo}
disabled={!hasPdf || isBusy || !canUndo}
title={latestUndo ? `Undo: ${latestUndo.label}` : 'Nothing to undo'}
>
Undo
</button>
<button
type="button"
className="secondary"
onClick={onRedo}
disabled={!hasPdf || isBusy || !canRedo}
title={latestRedo ? `Redo: ${latestRedo.label}` : 'Nothing to redo'}
>
Redo
</button>
<button
type="button"
className="secondary"
onClick={onSaveWorkspace}
disabled={!hasPdf || isBusy}
title={!hasPdf ? 'Open a PDF first' : 'Save workspace'}
>
💾 {activeWorkspaceId ? 'Save' : 'Save as'}
</button>
<button
type="button"
className="secondary"
onClick={onResetWorkspace}
disabled={!hasPdf || isBusy}
title={!hasPdf ? 'No active workspace' : 'Close the current workspace'}
>
Reset workspace
</button>
<button
type="button"
className="secondary"
onClick={onRefreshWorkspaces}
disabled={isBusy}
>
Refresh
</button>
</div>
{workspaceDirty && hasPdf && (
{redoHistory
.slice()
.reverse()
.map((entry, index) => (
<div
style={{
marginTop: '0.5rem',
fontSize: '0.8rem',
color: '#92400e',
}}
key={entry.id}
style={{
fontSize: "0.8rem",
color: "#9ca3af",
borderLeft: "3px solid #d1d5db",
paddingLeft: "0.45rem",
paddingTop: "0.2rem",
paddingBottom: "0.2rem",
opacity: 0.75,
}}
>
Unsaved workspace changes.
<strong>
Redo {index + 1}. {entry.label}
</strong>
<br />
<span style={{ color: "#9ca3af" }}>
{new Date(entry.timestamp).toLocaleString()}
</span>
</div>
)}
{workspaceMessage && (
<div
style={{
marginTop: '0.5rem',
fontSize: '0.85rem',
color: '#166534',
}}
>
{workspaceMessage}
</div>
)}
{workspaces.length > 0 && (
<div style={{ marginTop: '0.75rem' }}>
<strong style={{ fontSize: '0.9rem' }}>Saved workspaces</strong>
<div
style={{
display: 'flex',
flexDirection: 'column',
gap: '0.4rem',
marginTop: '0.4rem',
}}
>
{workspaces.map((workspace) => {
const active = workspace.id === activeWorkspaceId;
return (
<div
key={workspace.id}
style={{
border: '1px solid #e5e7eb',
borderRadius: '0.5rem',
padding: '0.5rem',
background: active ? '#eff6ff' : '#f9fafb',
display: 'flex',
justifyContent: 'space-between',
gap: '0.75rem',
alignItems: 'center',
flexWrap: 'wrap',
}}
>
<div style={{ minWidth: 0 }}>
<div style={{ fontSize: '0.9rem' }}>
<strong>{workspace.name}</strong>
{active && (
<span style={{ color: '#2563eb' }}> · active</span>
)}
</div>
<div style={{ fontSize: '0.75rem', color: '#6b7280' }}>
{workspace.pdfName} · source pages:{' '}
{workspace.sourcePageCount} · workspace pages:{' '}
{workspace.workspacePageCount} · undo:{' '}
{workspace.historyCount} · redo: {workspace.redoCount} · updated{' '}
{new Date(workspace.updatedAt).toLocaleString()}
</div>
</div>
<div
style={{
display: 'flex',
gap: '0.35rem',
flexWrap: 'wrap',
}}
>
<button
type="button"
className="secondary"
disabled={isBusy}
onClick={() => onLoadWorkspace(workspace.id)}
>
Load
</button>
<button
type="button"
className="secondary"
disabled={isBusy}
onClick={() => onDeleteWorkspace(workspace.id)}
style={{
background: '#fee2e2',
color: '#991b1b',
}}
>
Delete
</button>
</div>
</div>
);
})}
</div>
</div>
)}
{(history.length > 0 || redoHistory.length > 0) && (
<details style={{ marginTop: '0.75rem' }} open>
<summary style={{ cursor: 'pointer', fontSize: '0.9rem' }}>
Command history ({history.length} undo / {redoHistory.length} redo)
</summary>
<div
style={{
marginTop: '0.5rem',
display: 'flex',
flexDirection: 'column',
gap: '0.25rem',
}}
>
{history.map((entry, index) => (
<div
key={entry.id}
style={{
fontSize: '0.8rem',
color: '#374151',
borderLeft: '3px solid #2563eb',
paddingLeft: '0.45rem',
paddingTop: '0.2rem',
paddingBottom: '0.2rem',
}}
>
<strong>
Undo {history.length - index}. {entry.label}
</strong>
<br />
<span style={{ color: '#6b7280' }}>
{new Date(entry.timestamp).toLocaleString()}
</span>
</div>
))}
<div
style={{
margin: '0.25rem 0',
borderRadius: '999px',
background: '#ecfdf5',
color: '#166534',
fontSize: '0.8rem',
fontWeight: 600,
alignSelf: 'flex-start',
border: '2px solid #166534',
width: '100%',
}}
>
</div>
{redoHistory
.slice()
.reverse()
.map((entry, index) => (
<div
key={entry.id}
style={{
fontSize: '0.8rem',
color: '#9ca3af',
borderLeft: '3px solid #d1d5db',
paddingLeft: '0.45rem',
paddingTop: '0.2rem',
paddingBottom: '0.2rem',
opacity: 0.75,
}}
>
<strong>
Redo {index + 1}. {entry.label}
</strong>
<br />
<span style={{ color: '#9ca3af' }}>
{new Date(entry.timestamp).toLocaleString()}
</span>
</div>
))}
</div>
</details>
)}
</div>
);
))}
</div>
</details>
)}
</div>
);
};
export default WorkspacePanel;
export default WorkspacePanel;