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>
66 lines
1.8 KiB
React
66 lines
1.8 KiB
React
import { useState } from 'react';
|
|
import axios from '../services/api';
|
|
|
|
const resultBox = {
|
|
marginTop: '12px',
|
|
padding: '12px 14px',
|
|
background: 'var(--surface-2)',
|
|
border: '1px solid var(--border)',
|
|
borderRadius: '12px',
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
gap: '10px',
|
|
justifyContent: 'space-between',
|
|
};
|
|
|
|
function Base64Tool() {
|
|
const [input, setInput] = useState('');
|
|
const [result, setResult] = useState('');
|
|
const [error, setError] = useState('');
|
|
const [copied, setCopied] = useState(false);
|
|
|
|
const request = async (endpoint) => {
|
|
setError('');
|
|
setResult('');
|
|
try {
|
|
const res = await axios.post(endpoint, { text: input });
|
|
setResult(res.data.result);
|
|
} catch (err) {
|
|
setError(err.response?.data?.message || 'Fehler');
|
|
}
|
|
};
|
|
|
|
const copy = () => {
|
|
navigator.clipboard.writeText(result);
|
|
setCopied(true);
|
|
setTimeout(() => setCopied(false), 1500);
|
|
};
|
|
|
|
return (
|
|
<div className="main-content">
|
|
<h2>Base64 Encoder / Decoder</h2>
|
|
<input
|
|
type="text"
|
|
value={input}
|
|
onChange={(e) => { setInput(e.target.value); setResult(''); setError(''); }}
|
|
placeholder="Text eingeben"
|
|
/>
|
|
<button onClick={() => request('/api/base64/encode')}>Encode</button>
|
|
<button onClick={() => request('/api/base64/decode')}>Decode</button>
|
|
{error && <p className="error">{error}</p>}
|
|
{result && (
|
|
<div style={resultBox}>
|
|
<span style={{ wordBreak: 'break-all', color: 'var(--text)', fontFamily: 'monospace', fontSize: '0.9rem' }}>
|
|
{result}
|
|
</span>
|
|
<button className="ghost" onClick={copy} style={{ flexShrink: 0, margin: 0 }}>
|
|
{copied ? 'Kopiert!' : 'Kopieren'}
|
|
</button>
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export default Base64Tool;
|