+
Markdown Editor
+
+
+
+
Vorschau
+
Vorschau erscheint hier...' }}
+ style={{
+ minHeight: '460px',
+ padding: '16px',
+ background: '#ffffff',
+ color: '#0f172a',
+ border: '1px solid var(--border)',
+ borderRadius: '12px',
+ overflowY: 'auto',
+ lineHeight: 1.7,
+ }}
+ />
+
+
+
+ );
+}
+
+export default MarkdownTool;
diff --git a/frontend/src/components/QrCodeTool.jsx b/frontend/src/components/QrCodeTool.jsx
new file mode 100644
index 0000000..d41a931
--- /dev/null
+++ b/frontend/src/components/QrCodeTool.jsx
@@ -0,0 +1,47 @@
+import { useState } from 'react';
+import axios from '../services/api';
+
+function QrCodeTool() {
+ const [input, setInput] = useState('');
+ const [image, setImage] = useState('');
+ const [error, setError] = useState('');
+
+ const generate = async () => {
+ setError('');
+ try {
+ const res = await axios.post('/api/qrcode/generate', { text: input });
+ setImage(res.data.image);
+ } catch (err) {
+ setError(err.response?.data?.message || 'Fehler beim Generieren');
+ }
+ };
+
+ const download = () => {
+ const a = document.createElement('a');
+ a.href = image;
+ a.download = 'qrcode.png';
+ a.click();
+ };
+
+ return (
+
+
QR-Code Generator
+
{ setInput(e.target.value); setImage(''); setError(''); }}
+ placeholder="Text oder URL eingeben"
+ />
+
+ {error &&
{error}
}
+ {image && (
+
+

+
+
+ )}
+
+ );
+}
+
+export default QrCodeTool;
diff --git a/frontend/src/components/RegexTesterTool.jsx b/frontend/src/components/RegexTesterTool.jsx
new file mode 100644
index 0000000..8188a01
--- /dev/null
+++ b/frontend/src/components/RegexTesterTool.jsx
@@ -0,0 +1,116 @@
+import { useState, useEffect, useRef } from 'react';
+import axios from '../services/api';
+
+function highlightText(text, matches) {
+ const parts = [];
+ let last = 0;
+ for (const m of matches) {
+ if (m.start > last) parts.push({ text: text.slice(last, m.start), highlight: false });
+ parts.push({ text: text.slice(m.start, m.end), highlight: true });
+ last = m.end;
+ }
+ if (last < text.length) parts.push({ text: text.slice(last), highlight: false });
+ return parts;
+}
+
+function RegexTesterTool() {
+ const [pattern, setPattern] = useState('');
+ const [flags, setFlags] = useState({ i: false, m: false, s: false });
+ const [text, setText] = useState('');
+ const [result, setResult] = useState(null);
+ const [patternError, setPatternError] = useState('');
+ const timer = useRef(null);
+
+ useEffect(() => {
+ clearTimeout(timer.current);
+ if (!pattern || !text) { setResult(null); setPatternError(''); return; }
+ timer.current = setTimeout(async () => {
+ try {
+ const activeFlags = Object.entries(flags).filter(([, v]) => v).map(([k]) => k);
+ const res = await axios.post('/api/regex/test', { pattern, text, flags: activeFlags });
+ if (res.data.error) {
+ setPatternError(res.data.error);
+ setResult(null);
+ } else {
+ setPatternError('');
+ setResult(res.data);
+ }
+ } catch {
+ setPatternError('Fehler beim Testen');
+ }
+ }, 400);
+ return () => clearTimeout(timer.current);
+ }, [pattern, text, flags]);
+
+ const parts = result?.matches?.length && text ? highlightText(text, result.matches) : null;
+
+ return (
+
+
Regex Tester
+
setPattern(e.target.value)}
+ placeholder={String.raw`Regex Pattern, z.B. \d+`}
+ style={{ fontFamily: 'monospace' }}
+ />
+ {patternError &&
{patternError}
}
+
+
+ {[
+ { key: 'i', label: 'Case Insensitive (i)' },
+ { key: 'm', label: 'Multiline (m)' },
+ { key: 's', label: 'Dotall (s)' },
+ ].map(({ key, label }) => (
+
+ ))}
+
+
+
+ );
+}
+
+export default RegexTesterTool;
diff --git a/frontend/src/components/ToolOverview.jsx b/frontend/src/components/ToolOverview.jsx
index 17f2ad2..518f451 100644
--- a/frontend/src/components/ToolOverview.jsx
+++ b/frontend/src/components/ToolOverview.jsx
@@ -10,6 +10,11 @@ const TOOLS = [
{ icon: '🔐', path: '/tools/password', title: 'Passwort-Generator', desc: 'Sichere Passwörter generieren' },
{ icon: '🕐', path: '/tools/timestamp', title: 'Timestamp Converter', desc: 'Unix Timestamp in Datum umrechnen' },
{ icon: '📝', path: '/tools/textdiff', title: 'Text Diff', desc: 'Zwei Texte vergleichen' },
+ { icon: '📷', path: '/tools/qrcode', title: 'QR-Code Generator', desc: 'Text oder URL als QR-Code generieren' },
+ { icon: '📄', path: '/tools/markdown', title: 'Markdown Editor', desc: 'Markdown live rendern und vorschauen' },
+ { icon: '🎨', path: '/tools/color', title: 'Farb-Konverter', desc: 'HEX, RGB und HSL konvertieren' },
+ { icon: '{ }', path: '/tools/json', title: 'JSON Formatter', desc: 'JSON formatieren und validieren' },
+ { icon: '🔍', path: '/tools/regex', title: 'Regex Tester', desc: 'Reguläre Ausdrücke live testen' },
];
function ToolOverview() {