This commit is contained in:
seb
2026-10-07 13:23:44 +02:00
parent 6c0b1503e8
commit 7045fe5e69
5 changed files with 140 additions and 202 deletions

View File

@@ -3,16 +3,13 @@ import Box from '@mui/material/Box';
import Typography from '@mui/material/Typography';
import IconButton from '@mui/material/IconButton';
import Button from '@mui/material/Button';
import Tooltip from '@mui/material/Tooltip';
import CircularProgress from '@mui/material/CircularProgress';
import Chip from '@mui/material/Chip';
import SaveRoundedIcon from '@mui/icons-material/SaveRounded';
import UndoRoundedIcon from '@mui/icons-material/UndoRounded';
import DownloadRoundedIcon from '@mui/icons-material/DownloadRounded';
import CloseRoundedIcon from '@mui/icons-material/CloseRounded';
import ArrowBackRoundedIcon from '@mui/icons-material/ArrowBackRounded';
import ChatBubbleOutlineRoundedIcon from '@mui/icons-material/ChatBubbleOutlineRounded';
import WrapTextRoundedIcon from '@mui/icons-material/WrapTextRounded';
import Alert from '@mui/material/Alert';
import VfsFileIcon from './VfsFileIcon';
@@ -69,6 +66,37 @@ export default class VfsTextEditor extends PureComponent {
}
};
handleMentionInChat = () => {
const ta = this.textareaRef.current;
let lineInfo = null;
if (ta) {
const start = ta.selectionStart;
const end = ta.selectionEnd;
if (typeof start === 'number' && typeof end === 'number' && end > start) {
const content = this.props.content || '';
const beforeStart = content.substring(0, start);
const startLine = beforeStart.split('\n').length;
let effectiveEnd = end;
if (effectiveEnd > start && content[effectiveEnd - 1] === '\n') {
effectiveEnd -= 1;
}
const beforeEnd = content.substring(0, effectiveEnd);
const endLine = Math.max(startLine, beforeEnd.split('\n').length);
lineInfo = {
startLine,
endLine,
selectedText: content.substring(start, end),
};
}
}
if (this.props.onMentionInChat) {
this.props.onMentionInChat(lineInfo);
}
};
handleKeyDown = (e) => {
// Ctrl+S or Cmd+S -> Save
if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === 's') {
@@ -159,11 +187,9 @@ export default class VfsTextEditor extends PureComponent {
>
{/* File Name & Status */}
<Box sx={{ display: 'flex', alignItems: 'center', gap: 0.75, minWidth: 0, mr: 1 }}>
<Tooltip title="Zurück zur Dateiliste">
<IconButton size="small" onClick={onClose} sx={{ p: 0.5, mr: 0.25 }}>
<ArrowBackRoundedIcon fontSize="small" />
</IconButton>
</Tooltip>
<IconButton size="small" onClick={onClose} aria-label="Zurück zur Dateiliste" sx={{ p: 0.5, mr: 0.25 }}>
<ArrowBackRoundedIcon fontSize="small" />
</IconButton>
<VfsFileIcon fileName={fileName} mime={file?.mime} fontSize="small" />
<Typography
variant="body2"
@@ -174,60 +200,29 @@ export default class VfsTextEditor extends PureComponent {
{fileName}
</Typography>
{isDirty ? (
{isDirty && (
<Chip
label="Ungespeichert"
size="small"
color="warning"
sx={{ height: 20, fontSize: '0.68rem', fontWeight: 600, borderRadius: 1 }}
/>
) : (
<Chip
label="Gespeichert"
size="small"
variant="outlined"
sx={{ height: 20, fontSize: '0.68rem', borderRadius: 1, opacity: 0.7 }}
/>
)}
</Box>
{/* Action Buttons */}
<Box sx={{ display: 'flex', alignItems: 'center', gap: 0.75, flexShrink: 0 }}>
{onMentionInChat && (
<Tooltip title="In Chat erwähnen">
<IconButton size="small" onClick={onMentionInChat} sx={{ p: 0.6 }}>
<ChatBubbleOutlineRoundedIcon fontSize="small" color="primary" />
</IconButton>
</Tooltip>
)}
<Tooltip title="Herunterladen">
<IconButton size="small" onClick={onDownload} sx={{ p: 0.6 }}>
<DownloadRoundedIcon fontSize="small" />
<IconButton size="small" onClick={this.handleMentionInChat} aria-label="In Chat erwähnen" sx={{ p: 0.6 }}>
<ChatBubbleOutlineRoundedIcon fontSize="small" color="primary" />
</IconButton>
</Tooltip>
)}
{isDirty && (
<Tooltip title="Änderungen verwerfen">
<IconButton size="small" onClick={this.handleRevert} sx={{ p: 0.6, color: 'text.secondary' }}>
<UndoRoundedIcon fontSize="small" />
</IconButton>
</Tooltip>
)}
<Tooltip title={this.state.wrapLines ? 'Zeilenumbruch ausschalten' : 'Zeilenumbruch einschalten'}>
<IconButton
size="small"
onClick={this.toggleWrap}
color={this.state.wrapLines ? 'primary' : 'default'}
sx={{
p: 0.6,
bgcolor: this.state.wrapLines ? 'action.selected' : 'transparent',
}}
>
<WrapTextRoundedIcon fontSize="small" />
<IconButton size="small" onClick={this.handleRevert} aria-label="Änderungen verwerfen" sx={{ p: 0.6, color: 'text.secondary' }}>
<UndoRoundedIcon fontSize="small" />
</IconButton>
</Tooltip>
)}
<Button
size="small"
@@ -247,11 +242,9 @@ export default class VfsTextEditor extends PureComponent {
{isSaving ? 'Speichern…' : 'Speichern (Strg+S)'}
</Button>
<Tooltip title="Editor schließen">
<IconButton size="small" onClick={onClose} sx={{ p: 0.6, ml: 0.5 }}>
<CloseRoundedIcon fontSize="small" />
</IconButton>
</Tooltip>
<IconButton size="small" onClick={onClose} aria-label="Editor schließen" sx={{ p: 0.6, ml: 0.5 }}>
<CloseRoundedIcon fontSize="small" />
</IconButton>
</Box>
</Box>