mirror of
https://github.com/ceratic/project_vollidioten_website.git
synced 2026-05-14 00:16:47 +02:00
- Created DatabaseManager component for managing database access via phpMyAdmin. - Developed LinkPlayer component to link Discord accounts with game characters, including user authentication and error handling. - Added mock data files for players, organizations, and projects to handle backend unavailability. - Implemented AuthService for managing user authentication and session checks. - Created DatabaseService to fetch and manage player, organization, and project data with fallback to mock data. - Added HTML page for handling authentication unavailability. - Developed a test script for validating Docker setup and required files.
117 lines
3.6 KiB
TypeScript
117 lines
3.6 KiB
TypeScript
import React, { useState, useRef } from 'react';
|
|
import { Icons } from './IconSet';
|
|
|
|
interface MarkdownEditorProps {
|
|
value: string;
|
|
onChange: (value: string) => void;
|
|
className?: string;
|
|
}
|
|
|
|
const MarkdownEditor: React.FC<MarkdownEditorProps> = ({ value, onChange, className = '' }) => {
|
|
const textareaRef = useRef<HTMLTextAreaElement>(null);
|
|
|
|
const insertText = (before: string, after: string = '', placeholder: string = 'text') => {
|
|
const textarea = textareaRef.current;
|
|
if (!textarea) return;
|
|
|
|
const start = textarea.selectionStart;
|
|
const end = textarea.selectionEnd;
|
|
const selectedText = value.substring(start, end);
|
|
const textToInsert = selectedText || placeholder;
|
|
|
|
const newText = value.substring(0, start) + before + textToInsert + after + value.substring(end);
|
|
onChange(newText);
|
|
|
|
// Set cursor position after the inserted text
|
|
setTimeout(() => {
|
|
const newCursorPos = start + before.length + textToInsert.length + after.length;
|
|
textarea.setSelectionRange(newCursorPos, newCursorPos);
|
|
textarea.focus();
|
|
}, 0);
|
|
};
|
|
|
|
const formatButtons = [
|
|
{
|
|
icon: 'H',
|
|
label: 'Überschrift',
|
|
action: () => insertText('# ', ''),
|
|
className: 'text-lg font-bold'
|
|
},
|
|
{
|
|
icon: <Icons.Hammer className="w-3 h-3" />,
|
|
label: 'Fett',
|
|
action: () => insertText('**', '**', 'fetter Text'),
|
|
},
|
|
{
|
|
icon: <Icons.Tag className="w-3 h-3" />,
|
|
label: 'Kursiv',
|
|
action: () => insertText('*', '*', 'kursiver Text'),
|
|
},
|
|
{
|
|
icon: <Icons.Scroll className="w-3 h-3" />,
|
|
label: 'Liste',
|
|
action: () => insertText('- ', ''),
|
|
},
|
|
{
|
|
icon: <Icons.Crown className="w-3 h-3" />,
|
|
label: 'Nummerierte Liste',
|
|
action: () => insertText('1. ', ''),
|
|
},
|
|
{
|
|
icon: <Icons.Shield className="w-3 h-3" />,
|
|
label: 'Zitat',
|
|
action: () => insertText('> ', ''),
|
|
},
|
|
{
|
|
icon: '🔗',
|
|
label: 'Link',
|
|
action: () => insertText('[', '](url)', 'Link-Text'),
|
|
},
|
|
{
|
|
icon: '📷',
|
|
label: 'Bild',
|
|
action: () => insertText('', 'Alt-Text'),
|
|
},
|
|
];
|
|
|
|
return (
|
|
<div className={`border border-border rounded-lg overflow-hidden ${className}`}>
|
|
{/* Toolbar */}
|
|
<div className="bg-surfaceHighlight border-b border-border p-2 flex flex-wrap gap-1">
|
|
{formatButtons.map((button, index) => (
|
|
<button
|
|
key={index}
|
|
type="button"
|
|
onClick={button.action}
|
|
className="p-1.5 hover:bg-white/10 rounded text-textMuted hover:text-textMain transition-colors text-sm flex items-center justify-center min-w-[32px] h-8"
|
|
title={button.label}
|
|
>
|
|
{typeof button.icon === 'string' ? (
|
|
<span className={button.className}>{button.icon}</span>
|
|
) : (
|
|
button.icon
|
|
)}
|
|
</button>
|
|
))}
|
|
</div>
|
|
|
|
{/* Textarea */}
|
|
<textarea
|
|
ref={textareaRef}
|
|
value={value}
|
|
onChange={(e) => onChange(e.target.value)}
|
|
className="w-full h-64 md:h-96 bg-[#0b0b0d] border-0 p-4 text-sm font-mono text-gray-300 focus:outline-none resize-none"
|
|
placeholder="Schreibe dein Journal hier... Verwende die Toolbar für Formatierung."
|
|
spellCheck={false}
|
|
/>
|
|
|
|
{/* Footer */}
|
|
<div className="bg-surfaceHighlight border-t border-border px-4 py-2 text-xs text-textMuted">
|
|
Markdown-Formatierung unterstützt. Verwende die Toolbar für schnelle Formatierung.
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default MarkdownEditor;
|