7f9c5c874a
- backend/tools/hasher.py: POST /api/hash/sha256 and /api/hash/bcrypt (bcrypt added to requirements) - backend/tools/base64tool.py: POST /api/base64/encode and /api/base64/decode - backend/tools/jwtdecoder.py: POST /api/jwt/decode (signature verification disabled) - backend/tools/passwordgen.py: POST /api/password/generate with charset and length options - backend/tools/timestamp.py: POST /api/timestamp/convert (unix<->date, ISO 8601 + German format) - backend/tools/textdiff.py: POST /api/text/diff returning structured added/removed/unchanged lines - All blueprints registered in app.py and tools/__init__.py - React components with copy button, dark/light mode support via CSS variables - ToolOverview rebuilt as card grid; App.jsx routes added for all tools Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
85 lines
2.8 KiB
React
85 lines
2.8 KiB
React
import { useState } from 'react';
|
|
import axios from '../services/api';
|
|
|
|
const diffColors = {
|
|
added: { bg: 'rgba(34, 197, 94, 0.12)', text: '#22c55e', prefix: '+ ' },
|
|
removed: { bg: 'rgba(239, 68, 68, 0.12)', text: '#ef4444', prefix: '- ' },
|
|
unchanged: { bg: 'transparent', text: 'var(--muted)', prefix: ' ' },
|
|
};
|
|
|
|
function TextDiffTool() {
|
|
const [text1, setText1] = useState('');
|
|
const [text2, setText2] = useState('');
|
|
const [diff, setDiff] = useState(null);
|
|
|
|
const compare = async () => {
|
|
try {
|
|
const res = await axios.post('/api/text/diff', { text1, text2 });
|
|
setDiff(res.data.diff);
|
|
} catch {
|
|
alert('Fehler beim Vergleich');
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div className="main-content">
|
|
<h2>Text Diff</h2>
|
|
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '12px' }}>
|
|
<div>
|
|
<p className="muted" style={{ marginBottom: '6px', fontWeight: 600 }}>Text A</p>
|
|
<textarea
|
|
rows={10}
|
|
value={text1}
|
|
onChange={(e) => { setText1(e.target.value); setDiff(null); }}
|
|
placeholder="Originaltext eingeben..."
|
|
style={{ resize: 'vertical', fontFamily: 'monospace', fontSize: '0.875rem' }}
|
|
/>
|
|
</div>
|
|
<div>
|
|
<p className="muted" style={{ marginBottom: '6px', fontWeight: 600 }}>Text B</p>
|
|
<textarea
|
|
rows={10}
|
|
value={text2}
|
|
onChange={(e) => { setText2(e.target.value); setDiff(null); }}
|
|
placeholder="Geänderter Text eingeben..."
|
|
style={{ resize: 'vertical', fontFamily: 'monospace', fontSize: '0.875rem' }}
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<button onClick={compare}>Vergleichen</button>
|
|
|
|
{diff !== null && (
|
|
<div style={{ marginTop: '16px', border: '1px solid var(--border)', borderRadius: '12px', overflow: 'hidden' }}>
|
|
{diff.length === 0 ? (
|
|
<p style={{ padding: '12px 14px', color: 'var(--muted)', margin: 0 }}>Keine Unterschiede gefunden.</p>
|
|
) : (
|
|
diff.map((line, i) => {
|
|
const c = diffColors[line.type] || diffColors.unchanged;
|
|
return (
|
|
<div
|
|
key={i}
|
|
style={{
|
|
padding: '2px 14px',
|
|
background: c.bg,
|
|
color: c.text,
|
|
fontFamily: 'monospace',
|
|
fontSize: '0.875rem',
|
|
whiteSpace: 'pre-wrap',
|
|
wordBreak: 'break-all',
|
|
borderLeft: `3px solid ${line.type !== 'unchanged' ? c.text : 'transparent'}`,
|
|
}}
|
|
>
|
|
{c.prefix}{line.text}
|
|
</div>
|
|
);
|
|
})
|
|
)}
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export default TextDiffTool;
|