Speicherplatz in Dateien, Smilies in Nachrichten

This commit is contained in:
2026-05-28 11:49:53 +02:00
parent d932f1edb5
commit 970872111b
3 changed files with 56 additions and 8 deletions

View File

@@ -172,6 +172,7 @@ export default function Dateien({ toast, mobile }) {
const [dragOver, setDragOver] = useState(false);
const [newFolder, setNewFolder] = useState(false);
const [folderName, setFolderName] = useState('');
const [storage, setStorage] = useState(null);
const fileRef = useRef(null);
const { confirm, ConfirmDialog } = useConfirm();
@@ -186,6 +187,7 @@ export default function Dateien({ toast, mobile }) {
})
.catch(e=>toast(e.message,'error'))
.finally(()=>setLoading(false));
api('/tools/dateien/storage').then(setStorage).catch(()=>{});
}, [currentFolderId]);
useEffect(()=>{load();},[load]);
@@ -276,7 +278,28 @@ export default function Dateien({ toast, mobile }) {
return (
<div style={{padding:mobile?'14px 14px 90px':'36px 44px',maxWidth:960}}>
<ConfirmDialog/>
{shareItem && <ShareModal item={shareItem.item} type={shareItem.type} onClose={()=>{setShareItem(null);load();}} toast={toast}/>}
{/* ── Speicherplatz ─────────────────────────────────────────────────── */}
{storage && (
<div style={{marginBottom:14}}>
<div style={{display:'flex',justifyContent:'space-between',
color:'rgba(255,255,255,0.35)',fontFamily:'monospace',fontSize:9,marginBottom:4}}>
<span>{fmtSize(storage.used)} belegt</span>
<span>{storage.diskFree!=null ? `${fmtSize(storage.diskFree)} frei auf Disk` : ''}</span>
</div>
<div style={{height:4,borderRadius:4,background:'rgba(255,255,255,0.06)',overflow:'hidden'}}>
<div style={{
height:'100%', borderRadius:4,
width:`${Math.min(100,(storage.used/storage.max)*100)}%`,
background: storage.used/storage.max > 0.85 ? '#ff6b9d' :
storage.used/storage.max > 0.6 ? '#ffe66d' : '#4ecdc4',
transition:'width 0.4s',
}}/>
</div>
<div style={{color:'rgba(255,255,255,0.2)',fontFamily:'monospace',fontSize:8,marginTop:3,textAlign:'right'}}>
Limit: {fmtSize(storage.max)}
</div>
</div>
)} item={shareItem.item} type={shareItem.type} onClose={()=>{setShareItem(null);load();}} toast={toast}/>}
{pwPrompt && <PasswordPromptModal
filename={pwPrompt.originalname}
onSubmit={pw=>{ setPwPrompt(null); download(pwPrompt, pw); }}

View File

@@ -25,12 +25,10 @@ const EMOJI_MAP = {
// Ersetze Kürzel am Ende des Textes (nach Leerzeichen oder Satzanfang)
function convertEmojis(text) {
let result = text;
for (const [code, emoji] of Object.entries(EMOJI_MAP)) {
const escaped = code.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
result = result.replace(new RegExp(`(^|\\s)${escaped}(?=\\s|$)`, 'g'), `$1${emoji}`);
}
return result;
// Letztes "Wort" vor dem Leerzeichen/Newline prüfen
return text.replace(/(\S+)(\s)$/, (_, word, space) => {
return (EMOJI_MAP[word] ?? word) + space;
});
}
// ── Emoji-Picker Daten ────────────────────────────────────────────────────────
@@ -86,6 +84,17 @@ export default function Nachrichten({ toast, mobile }) {
const [showPicker, setShowPicker] = useState(false);
const bottomRef = useRef(null);
const pollRef = useRef(null);
const pickerRef = useRef(null);
useEffect(() => {
if (!showPicker) return;
const handler = e => {
if (pickerRef.current && !pickerRef.current.contains(e.target)) setShowPicker(false);
};
document.addEventListener('mousedown', handler);
document.addEventListener('touchstart', handler);
return () => { document.removeEventListener('mousedown', handler); document.removeEventListener('touchstart', handler); };
}, [showPicker]);
// ── Initialisierung ──────────────────────────────────────────────────────────
useEffect(() => {
@@ -430,7 +439,7 @@ export default function Nachrichten({ toast, mobile }) {
Senden nicht möglich
</div>
) : (
<div style={{ display:'flex', gap:8, alignItems:'flex-end', position:'relative' }}>
<div style={{ display:'flex', gap:8, alignItems:'flex-end', position:'relative' }} ref={pickerRef}>
{showPicker && (
<EmojiPicker
onSelect={em => { setText(t => t + em); setShowPicker(false); }}