78 lines
3.2 KiB
TypeScript
78 lines
3.2 KiB
TypeScript
|
|
/**
|
|||
|
|
* HistoryPanel – Zeigt die Undo/Redo-Historie an.
|
|||
|
|
* F-CAD-09: Historie einsehbar
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
import React from 'react';
|
|||
|
|
import type { HistoryEntry } from '../history';
|
|||
|
|
|
|||
|
|
interface HistoryPanelProps {
|
|||
|
|
entries: HistoryEntry[];
|
|||
|
|
onJumpTo: (entryId: string) => void;
|
|||
|
|
onClose: () => void;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const formatTime = (ts: number): string => {
|
|||
|
|
const d = new Date(ts);
|
|||
|
|
return d.toLocaleTimeString('de-DE', { hour: '2-digit', minute: '2-digit', second: '2-digit' });
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
const HistoryPanel: React.FC<HistoryPanelProps> = ({ entries, onJumpTo, onClose }) => {
|
|||
|
|
if (entries.length === 0) {
|
|||
|
|
return (
|
|||
|
|
<div style={{
|
|||
|
|
position: 'fixed', top: '50%', right: '320px', transform: 'translateY(-50%)',
|
|||
|
|
background: 'var(--color-bg-primary, #1e1e2e)', borderRadius: '8px',
|
|||
|
|
padding: '16px', width: '280px', maxHeight: '60vh', overflow: 'auto',
|
|||
|
|
border: '1px solid var(--color-border, #333)', zIndex: 900,
|
|||
|
|
color: 'var(--color-text, #e0e0e0)',
|
|||
|
|
}}>
|
|||
|
|
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '12px' }}>
|
|||
|
|
<h3 style={{ margin: 0, fontSize: '15px' }}>Historie</h3>
|
|||
|
|
<button onClick={onClose} style={{ background: 'none', border: 'none', color: 'inherit', cursor: 'pointer', fontSize: '18px' }}>×</button>
|
|||
|
|
</div>
|
|||
|
|
<p style={{ fontSize: '13px', color: '#888' }}>Keine Historie vorhanden.</p>
|
|||
|
|
</div>
|
|||
|
|
);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return (
|
|||
|
|
<div style={{
|
|||
|
|
position: 'fixed', top: '50%', right: '320px', transform: 'translateY(-50%)',
|
|||
|
|
background: 'var(--color-bg-primary, #1e1e2e)', borderRadius: '8px',
|
|||
|
|
padding: '16px', width: '280px', maxHeight: '60vh', overflow: 'auto',
|
|||
|
|
border: '1px solid var(--color-border, #333)', zIndex: 900,
|
|||
|
|
color: 'var(--color-text, #e0e0e0)',
|
|||
|
|
}}>
|
|||
|
|
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '12px' }}>
|
|||
|
|
<h3 style={{ margin: 0, fontSize: '15px' }}>Historie ({entries.length})</h3>
|
|||
|
|
<button onClick={onClose} style={{ background: 'none', border: 'none', color: 'inherit', cursor: 'pointer', fontSize: '18px' }}>×</button>
|
|||
|
|
</div>
|
|||
|
|
<div style={{ display: 'flex', flexDirection: 'column', gap: '2px' }}>
|
|||
|
|
{entries.map((entry, idx) => (
|
|||
|
|
<button
|
|||
|
|
key={entry.id}
|
|||
|
|
onClick={() => onJumpTo(entry.id)}
|
|||
|
|
style={{
|
|||
|
|
display: 'flex', alignItems: 'center', gap: '8px',
|
|||
|
|
padding: '6px 8px', borderRadius: '4px', cursor: 'pointer',
|
|||
|
|
border: 'none', textAlign: 'left', width: '100%',
|
|||
|
|
background: entry.isCurrent ? 'rgba(80, 250, 123, 0.15)' : 'transparent',
|
|||
|
|
color: entry.isCurrent ? '#50fa7b' : 'var(--color-text, #e0e0e0)',
|
|||
|
|
fontWeight: entry.isCurrent ? 600 : 400,
|
|||
|
|
fontSize: '13px',
|
|||
|
|
opacity: entry.id.startsWith('redo-') ? 0.5 : 1,
|
|||
|
|
}}
|
|||
|
|
>
|
|||
|
|
<span style={{ fontSize: '11px', color: '#666', minWidth: '28px' }}>{formatTime(entry.timestamp)}</span>
|
|||
|
|
<span style={{ flex: 1 }}>{entry.label}</span>
|
|||
|
|
{entry.isCurrent && <span style={{ fontSize: '10px' }}>●</span>}
|
|||
|
|
</button>
|
|||
|
|
))}
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
);
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
export default HistoryPanel;
|