Dateien nach "frontend/src" hochladen

This commit is contained in:
2026-05-25 23:29:25 +02:00
parent cccf4f4bb3
commit 91bd239587
3 changed files with 177 additions and 39 deletions

View File

@@ -1,6 +1,7 @@
import { useState, useEffect, useRef, useCallback } from 'react';
import { api, S } from './lib.js';
import { TOOLS, getGroupedTools } from './toolRegistry.js';
import { HomeIcon, AppsIcon, AdminIcon, MoreIcon, UserIcon, LogOutIcon, ChevronIcon, UpdateIcon } from './icons.jsx';
const ICONS = ['🔗','🌐','📊','📁','🛠','📧','🗓','💾','🖥','📡','🔒','📖','🎯','⚡','🏠','🔧','📱','🎮','🚀','💡'];
@@ -136,22 +137,25 @@ function UpdateModal({ data, onClose }) {
function Sidebar({ active, setActive, user, onLogout, updateInfo, onUpdateClick }) {
const [appsOpen, setAppsOpen] = useState(true);
const NavBtn = ({ item, sub=false }) => (
<button onClick={()=>setActive(item.id)} style={{
width:'100%', display:'flex', alignItems:'center', gap:9,
padding: '8px 12px 8px 12px',
borderRadius:7, border:'none',
background: active===item.id ? 'linear-gradient(90deg,rgba(78,205,196,0.14),rgba(78,205,196,0.02))' : 'transparent',
color: active===item.id ? '#4ecdc4' : 'rgba(255,255,255,0.6)',
cursor:'pointer', fontSize:12,
fontFamily:"'Space Mono',monospace", textAlign:'left', marginBottom:1,
borderLeft: active===item.id ? '2px solid #4ecdc4' : '2px solid transparent',
}}>
{sub && <span style={{ width:1, alignSelf:'stretch', background:'rgba(255,255,255,0.08)', marginRight:4, flexShrink:0 }}/>}
<span style={{ fontSize:13 }}>{item.icon}</span>
<span style={{ flex:1 }}>{item.label}</span>
</button>
);
const NavBtn = ({ item, sub=false }) => {
const ic = active===item.id ? '#4ecdc4' : 'rgba(255,255,255,0.55)';
return (
<button onClick={()=>setActive(item.id)} style={{
width:'100%', display:'flex', alignItems:'center', gap:9,
padding:'8px 12px', borderRadius:7, border:'none',
background: active===item.id ? 'linear-gradient(90deg,rgba(78,205,196,0.14),rgba(78,205,196,0.02))' : 'transparent',
cursor:'pointer', fontSize:12,
fontFamily:"'Space Mono',monospace", textAlign:'left', marginBottom:1,
borderLeft: active===item.id ? '2px solid #4ecdc4' : '2px solid transparent',
}}>
{sub && <span style={{ width:1, alignSelf:'stretch', background:'rgba(255,255,255,0.08)', marginRight:3, flexShrink:0 }}/>}
<span style={{ display:'flex', alignItems:'center', width:18, justifyContent:'center', flexShrink:0 }}>
{item.Icon ? <item.Icon size={15} color={ic}/> : <span style={{color:ic,fontSize:13}}>{item.icon}</span>}
</span>
<span style={{ flex:1, color:ic }}>{item.label}</span>
</button>
);
};
return (
<aside style={{ width:210, minHeight:'100vh', background:'#0d0d0f',
@@ -169,7 +173,7 @@ function Sidebar({ active, setActive, user, onLogout, updateInfo, onUpdateClick
</div>
</div>
<nav style={{ flex:1, padding:'0 8px' }}>
<NavBtn item={{ id:'dashboard', icon:'⬡', label:'Dashboard' }} />
<NavBtn item={{ id:'dashboard', Icon:HomeIcon, label:'Dashboard' }} />
{/* Apps Sektion mit Gruppenüberschriften */}
<button onClick={()=>setAppsOpen(v=>!v)} style={{
@@ -191,7 +195,7 @@ function Sidebar({ active, setActive, user, onLogout, updateInfo, onUpdateClick
</div>
))}
{user?.role==='admin' && <NavBtn item={{ id:'admin', icon:'⚙', label:'Admin' }} />}
{user?.role==='admin' && <NavBtn item={{ id:'admin', icon:'⚙', label:'Admin' }} />}
</nav>
{updateInfo?.hasUpdate && (
<button onClick={onUpdateClick} style={{
@@ -207,7 +211,7 @@ function Sidebar({ active, setActive, user, onLogout, updateInfo, onUpdateClick
<div style={{ padding:'10px 12px 16px', borderTop:'1px solid rgba(255,255,255,0.06)' }}>
<div style={{ display:'flex', alignItems:'center', gap:8, marginBottom:8 }}>
<div style={{ width:24, height:24, borderRadius:'50%', background:'linear-gradient(135deg,#ff6b9d,#4ecdc4)',
display:'flex', alignItems:'center', justifyContent:'center', fontSize:10 }}>👤</div>
display:'flex', alignItems:'center', justifyContent:'center' }}><UserIcon size={14} color="#0d0d0f"/></div>
<div style={{ color:'#fff', fontSize:11, fontFamily:'monospace' }}>{user?.username}</div>
</div>
<button onClick={onLogout} style={{ ...S.btn('#ff6b9d',true), width:'100%', textAlign:'center' }}>Ausloggen</button>
@@ -225,7 +229,7 @@ function BottomNav({ active, setActive, user, onLogout, updateInfo, onUpdateClic
const MI = ({icon, label, onClick, color='#fff'}) => (
<button onClick={onClick} style={{ width:'100%', padding:'11px 20px', background:'transparent',
border:'none', display:'flex', alignItems:'center', gap:10, cursor:'pointer' }}>
<span style={{fontSize:17, flexShrink:0, width:22, textAlign:'center', display:'inline-block', color:'rgba(255,255,255,0.85)'}}>{icon}</span>
<span style={{fontSize:17, flexShrink:0, width:22, textAlign:'center', display:'inline-block', }}>{icon}</span>
<span style={{color, fontFamily:'monospace', fontSize:13}}>{label}</span>
</button>
);
@@ -246,10 +250,10 @@ function BottomNav({ active, setActive, user, onLogout, updateInfo, onUpdateClic
);
const mainNav = [
{ id:'dashboard', icon:'⬡', label:'Home' },
{ id:'_apps', icon:'◫', label:'Apps' },
...(user?.role==='admin' ? [{ id:'admin', icon:'⚙', label:'Admin' }] : []),
{ id:'_mehr', icon:'⋯', label:'Mehr' },
{ id:'dashboard', Icon:HomeIcon, label:'Home' },
{ id:'_apps', Icon:AppsIcon, label:'Apps' },
...(user?.role==='admin' ? [{ id:'admin', Icon:AdminIcon, label:'Admin' }] : []),
{ id:'_mehr', Icon:MoreIcon, label:'Mehr' },
];
return (
@@ -262,7 +266,7 @@ function BottomNav({ active, setActive, user, onLogout, updateInfo, onUpdateClic
<div style={{ color:'rgba(255,255,255,0.28)', fontSize:9, fontFamily:'monospace',
letterSpacing:2, padding:'12px 20px 5px' }}>{group.toUpperCase()}</div>
{tools.map(t => (
<MI key={t.id} icon={t.icon} label={t.label}
<MI key={t.id} Icon={t.Icon} label={t.label}
onClick={() => { setActive(t.id); setAppsOpen(false); }} />
))}
</div>
@@ -272,10 +276,10 @@ function BottomNav({ active, setActive, user, onLogout, updateInfo, onUpdateClic
{/* Mehr Sheet */}
<Sheet open={menuOpen} onClose={()=>setMenuOpen(false)}>
{updateInfo?.hasUpdate && <MI icon="📦" label={`Update: ${updateInfo.latestVersion}`} onClick={()=>{setMenuOpen(false);onUpdateClick();}} color="#ffe66d"/>}
{updateInfo?.hasUpdate && <MI Icon={UpdateIcon} label={`Update: ${updateInfo.latestVersion}`} onClick={()=>{setMenuOpen(false);onUpdateClick();}} color="#ffe66d"/>}
<div style={{height:1, background:'rgba(255,255,255,0.08)', margin:'4px 0'}}/>
<MI icon="👤" label={user?.username||''} onClick={()=>{}} color="rgba(255,255,255,0.35)"/>
<MI icon="🚪" label="Ausloggen" onClick={()=>{onLogout();setMenuOpen(false);}} color="#ff6b9d"/>
<MI Icon={UserIcon} label={user?.username||''} onClick={()=>{}} color="rgba(255,255,255,0.35)"/>
<MI Icon={LogOutIcon} label="Ausloggen" onClick={()=>{onLogout();setMenuOpen(false);}} color="#ff6b9d"/>
</Sheet>
{/* Bottom Bar */}
@@ -301,7 +305,7 @@ function BottomNav({ active, setActive, user, onLogout, updateInfo, onUpdateClic
width:8, height:8, borderRadius:'50%', background:'#ffe66d',
boxShadow:'0 0 6px #ffe66d', display:'inline-block' }} />
)}
<span style={{ fontSize:20, lineHeight:1 }}>{item.icon}</span>
<item.Icon size={20} color={isActive ? '#4ecdc4' : 'rgba(255,255,255,0.45)'}/>
<span style={{ fontSize:9, fontFamily:'monospace', letterSpacing:0.3,
color: isActive ? '#4ecdc4' : 'rgba(255,255,255,0.4)' }}>{item.label}</span>
{isActive && !isApps && !isMehr && (