Suche: Key-Gen Einträge, Einstellungs-Sektionen, Link-Ordner, Settings-Navigation

This commit is contained in:
2026-06-05 09:26:12 +02:00
parent f4e64811c1
commit a2527b8541
2 changed files with 84 additions and 24 deletions

View File

@@ -15,6 +15,15 @@ router.get('/', authenticate, (req, res) => {
ORDER BY title LIMIT 8
`).all(uid, like, like, like);
let folders = [];
try {
folders = db.prepare(`
SELECT id, name, icon FROM link_list_folders
WHERE user_id=? AND LOWER(name) LIKE ?
ORDER BY name LIMIT 5
`).all(uid, like);
} catch {}
let snippets = [];
try {
snippets = db.prepare(`
@@ -42,7 +51,7 @@ router.get('/', authenticate, (req, res) => {
`).all(uid, like);
} catch {}
res.json({ links, snippets, calculations, orders });
res.json({ links, folders, snippets, calculations, orders });
});
module.exports = router;

View File

@@ -1433,9 +1433,11 @@ function ChangelogModal({ user, toast, onClose, onRead }) {
function SearchResultItem({ item, idx, activeIdx, onNavigate, onHover }) {
const isActive = idx === activeIdx;
let icon = '❓', primary = '', secondary = '';
if (item.type==='tool') { icon=item.icon||'🛠'; primary=item.label; secondary=item.sub||'Navigation'; }
if (item.type==='devtool') { icon=item.icon||'🔧'; primary=item.label; secondary='Dev-Tools'; }
if (item.type==='link') {
if (item.type==='tool') { icon=item.icon||'🛠'; primary=item.label; secondary=item.sub||'Navigation'; }
if (item.type==='devtool') { icon=item.icon||'🔧'; primary=item.label; secondary=item.sub||'Dev-Tools'; }
if (item.type==='settings') { icon=item.icon||'⚙️'; primary=item.label; secondary=item.sub||'Einstellungen'; }
if (item.type==='folder') { icon=item.icon||'📁'; primary=item.name; secondary='Linkliste Ordner'; }
if (item.type==='link') {
const hasCustom = item.icon && item.icon !== '🔗';
icon = hasCustom ? item.icon : '🔗';
primary = item.title; secondary = item.url;
@@ -1456,15 +1458,15 @@ function SearchResultItem({ item, idx, activeIdx, onNavigate, onHover }) {
overflow:'hidden',textOverflow:'ellipsis',whiteSpace:'nowrap'}}>{secondary}</div>
</div>
{item.type==='link' && <span style={{color:'rgba(255,255,255,0.2)',fontSize:10,flexShrink:0}}></span>}
{(item.type==='tool'||item.type==='devtool') && <span style={{color:'rgba(255,255,255,0.2)',fontSize:10,flexShrink:0}}></span>}
{(item.type==='tool'||item.type==='devtool'||item.type==='settings'||item.type==='folder'||item.type==='snippet'||item.type==='calc'||item.type==='order') && <span style={{color:'rgba(255,255,255,0.2)',fontSize:10,flexShrink:0}}></span>}
</div>
);
}
// ── Globale Suche ─────────────────────────────────────────────────────────────
// Statischer Such-Index für Tools & Dev-Tools Sub-Tools
// Statischer Such-Index Tools, Dev-Tools Inhalte, Einstellungen
const SEARCH_TOOL_INDEX = [
// Haupt-Tools
// ── Haupt-Tools ──
{type:'tool',label:'Dashboard',icon:'🏠',sub:'',id:'dashboard'},
{type:'tool',label:'Bestellungen',icon:'📦',sub:'3D-Druck',id:'bestellungen'},
{type:'tool',label:'Kalkulator3D',icon:'🖨',sub:'3D-Druck',id:'kalkulator3d'},
@@ -1474,18 +1476,54 @@ const SEARCH_TOOL_INDEX = [
{type:'tool',label:'Code-Schnipsel',icon:'📄',sub:'Werkzeuge',id:'codeschnipsel'},
{type:'tool',label:'CAD-Skizzen',icon:'📐',sub:'Werkzeuge',id:'skizze'},
{type:'tool',label:'Dev-Tools',icon:'🔧',sub:'Werkzeuge',id:'devtools'},
{type:'tool',label:'Einstellungen',icon:'⚙️',sub:'',id:'admin'},
// Dev-Tools Sub-Tools
// ── Einstellungen-Sektionen ──
{type:'settings',label:'Einstellungen Profil',icon:'👤',sub:'Einstellungen',section:'profil'},
{type:'settings',label:'Einstellungen Sicherheit',icon:'🔒',sub:'Einstellungen',section:'sicherheit'},
{type:'settings',label:'Einstellungen Dashboard',icon:'🏠',sub:'Einstellungen',section:'dashboard'},
{type:'settings',label:'Einstellungen Benutzer',icon:'👥',sub:'Einstellungen (Admin)',section:'benutzer'},
{type:'settings',label:'Einstellungen Backup',icon:'💾',sub:'Einstellungen (Admin)',section:'backup'},
// ── Dev-Tools Sub-Tools ──
{type:'devtool',label:'Crontab',icon:'⏱',sub:'Dev-Tools',tool:'cron'},
{type:'devtool',label:'Elektro-Rechner',icon:'⚡',sub:'Dev-Tools',tool:'elektro'},
{type:'devtool',label:'JSON Viewer',icon:'{}',sub:'Dev-Tools',tool:'json'},
{type:'devtool',label:'Ohmsches Gesetz',icon:'',sub:'Elektro-Rechner',tool:'elektro'},
{type:'devtool',label:'JSON Viewer & Builder',icon:'{}',sub:'Dev-Tools',tool:'json'},
{type:'devtool',label:'Regex Builder',icon:'🔍',sub:'Dev-Tools',tool:'regex'},
{type:'devtool',label:'Text Diff',icon:'±',sub:'Dev-Tools',tool:'diff'},
{type:'devtool',label:'Netzwerk',icon:'🌐',sub:'Dev-Tools',tool:'netzwerk'},
{type:'devtool',label:'Datetime',icon:'📅',sub:'Dev-Tools',tool:'datetime'},
{type:'devtool',label:'Farben',icon:'🎨',sub:'Dev-Tools',tool:'farben'},
{type:'devtool',label:'Key-Generator',icon:'🔐',sub:'Dev-Tools',tool:'keygen'},
{type:'devtool',label:'Netzwerk-Rechner',icon:'🌐',sub:'Dev-Tools',tool:'netzwerk'},
{type:'devtool',label:'IP / Subnetz',icon:'🌐',sub:'Netzwerk',tool:'netzwerk'},
{type:'devtool',label:'Geschwindigkeit MB/s Mbit',icon:'🌐',sub:'Netzwerk',tool:'netzwerk'},
{type:'devtool',label:'CIDR Tabelle',icon:'🌐',sub:'Netzwerk',tool:'netzwerk'},
{type:'devtool',label:'Datetime Uhrzeitrechner',icon:'📅',sub:'Dev-Tools',tool:'datetime'},
{type:'devtool',label:'Unix Timestamp',icon:'📅',sub:'Datetime',tool:'datetime'},
{type:'devtool',label:'Moseszeit Umrechner',icon:'📅',sub:'Datetime',tool:'datetime'},
{type:'devtool',label:'Geburtstagsrechner',icon:'📅',sub:'Datetime',tool:'datetime'},
{type:'devtool',label:'Zeitdifferenz',icon:'📅',sub:'Datetime',tool:'datetime'},
{type:'devtool',label:'Farb-Rechner',icon:'🎨',sub:'Dev-Tools',tool:'farben'},
{type:'devtool',label:'HEX RGB HSL Farben',icon:'🎨',sub:'Farben',tool:'farben'},
{type:'devtool',label:'CMYK Farbkonverter',icon:'🎨',sub:'Farben',tool:'farben'},
{type:'devtool',label:'QR-Code Generator',icon:'◻',sub:'Dev-Tools',tool:'qrcode'},
// ── Key-Gen Einträge (direkt durchsuchbar) ──
{type:'devtool',label:'Key-Generator',icon:'🔐',sub:'Dev-Tools',tool:'keygen'},
{type:'devtool',label:'Laravel APP_KEY',icon:'🔐',sub:'Key-Gen',tool:'keygen'},
{type:'devtool',label:'JWT Secret HS256',icon:'🔐',sub:'Key-Gen',tool:'keygen'},
{type:'devtool',label:'JWT Secret HS512',icon:'🔐',sub:'Key-Gen',tool:'keygen'},
{type:'devtool',label:'AES-256 Key',icon:'🔐',sub:'Key-Gen',tool:'keygen'},
{type:'devtool',label:'AES-128 Key',icon:'🔐',sub:'Key-Gen',tool:'keygen'},
{type:'devtool',label:'Generic Secret',icon:'🔐',sub:'Key-Gen',tool:'keygen'},
{type:'devtool',label:'Passwort Generator',icon:'🔐',sub:'Key-Gen',tool:'keygen'},
{type:'devtool',label:'UUID v4',icon:'🔐',sub:'Key-Gen',tool:'keygen'},
{type:'devtool',label:'NanoID Generator',icon:'🔐',sub:'Key-Gen',tool:'keygen'},
{type:'devtool',label:'DB-Passwort Docker',icon:'🔐',sub:'Key-Gen',tool:'keygen'},
{type:'devtool',label:'Hex Token Generator',icon:'🔐',sub:'Key-Gen',tool:'keygen'},
{type:'devtool',label:'Base64 Token',icon:'🔐',sub:'Key-Gen',tool:'keygen'},
{type:'devtool',label:'Base64url Token',icon:'🔐',sub:'Key-Gen',tool:'keygen'},
{type:'devtool',label:'NEXTAUTH_SECRET',icon:'🔐',sub:'Key-Gen',tool:'keygen'},
{type:'devtool',label:'Webhook Secret',icon:'🔐',sub:'Key-Gen',tool:'keygen'},
{type:'devtool',label:'OAuth Secret',icon:'🔐',sub:'Key-Gen',tool:'keygen'},
{type:'devtool',label:'VAPID Key',icon:'🔐',sub:'Key-Gen',tool:'keygen'},
{type:'devtool',label:'docker-compose Passwort',icon:'🔐',sub:'Key-Gen',tool:'keygen'},
{type:'devtool',label:'MYSQL_ROOT_PASSWORD',icon:'🔐',sub:'Key-Gen',tool:'keygen'},
{type:'devtool',label:'POSTGRES_PASSWORD',icon:'🔐',sub:'Key-Gen',tool:'keygen'},
];
function GlobalSearch({ setActive, setDevToolsNav, mobile }) {
@@ -1528,6 +1566,7 @@ function GlobalSearch({ setActive, setDevToolsNav, mobile }) {
const allItems = results ? [
...results.static,
...(results.links||[]).map(l=>({...l,type:'link'})),
...(results.folders||[]).map(f=>({...f,type:'folder'})),
...(results.snippets||[]).map(s=>({...s,type:'snippet'})),
...(results.calculations||[]).map(c=>({...c,type:'calc'})),
...(results.orders||[]).map(o=>({...o,type:'order'})),
@@ -1535,12 +1574,14 @@ function GlobalSearch({ setActive, setDevToolsNav, mobile }) {
const navigate = (item) => {
close();
if (item.type === 'tool') { setActive(item.id); }
else if (item.type === 'devtool') { setActive('devtools'); setDevToolsNav({tool: item.tool, ts: Date.now()}); }
else if (item.type === 'link') { window.open(item.url, '_blank', 'noopener'); }
else if (item.type === 'snippet') { setActive('codeschnipsel'); }
else if (item.type === 'calc') { setActive('kalkulator3d'); }
else if (item.type === 'order') { setActive('bestellungen'); }
if (item.type === 'tool') { setActive(item.id); }
else if (item.type === 'devtool') { setActive('devtools'); setDevToolsNav({tool: item.tool, ts: Date.now()}); }
else if (item.type === 'settings') { setActive('admin'); setDevToolsNav({section: item.section, ts: Date.now()}); }
else if (item.type === 'link') { window.open(item.url, '_blank', 'noopener'); }
else if (item.type === 'folder') { setActive('linkliste'); }
else if (item.type === 'snippet') { setActive('codeschnipsel'); }
else if (item.type === 'calc') { setActive('kalkulator3d'); }
else if (item.type === 'order') { setActive('bestellungen'); }
};
const onKey = e => {
@@ -1604,6 +1645,15 @@ function GlobalSearch({ setActive, setDevToolsNav, mobile }) {
{results.links.map((item,i)=><SearchResultItem key={`l${i}`} item={{...item,type:'link'}} idx={results.static.length+i} activeIdx={active} onNavigate={navigate} onHover={setActiveR}/>)}
</div>
)}
{results.folders?.length>0 && (
<div>
<div style={{padding:'7px 14px 4px',color:'rgba(255,255,255,0.3)',fontFamily:'monospace',fontSize:9,letterSpacing:1}}>LINK-ORDNER</div>
{results.folders.map((item,i)=>{
const off=results.static.length+(results.links||[]).length+(results.folders||[]).length;
return <SearchResultItem key={`f${i}`} item={{...item,type:'folder'}} idx={off+i} activeIdx={active} onNavigate={navigate} onHover={setActiveR}/>;
})}
</div>
)}
{results.snippets?.length>0 && (
<div>
<div style={{padding:'7px 14px 4px',color:'rgba(255,255,255,0.3)',fontFamily:'monospace',fontSize:9,letterSpacing:1}}>CODE-SCHNIPSEL</div>
@@ -1617,7 +1667,7 @@ function GlobalSearch({ setActive, setDevToolsNav, mobile }) {
<div>
<div style={{padding:'7px 14px 4px',color:'rgba(255,255,255,0.3)',fontFamily:'monospace',fontSize:9,letterSpacing:1}}>3D-ARCHIV</div>
{results.calculations.map((item,i)=>{
const off=results.static.length+(results.links||[]).length+(results.snippets||[]).length;
const off=results.static.length+(results.links||[]).length+(results.folders||[]).length+(results.snippets||[]).length;
return <SearchResultItem key={`c${i}`} item={{...item,type:'calc'}} idx={off+i} activeIdx={active} onNavigate={navigate} onHover={setActiveR}/>;
})}
</div>
@@ -1626,7 +1676,7 @@ function GlobalSearch({ setActive, setDevToolsNav, mobile }) {
<div>
<div style={{padding:'7px 14px 4px',color:'rgba(255,255,255,0.3)',fontFamily:'monospace',fontSize:9,letterSpacing:1}}>BESTELLUNGEN</div>
{results.orders.map((item,i)=>{
const off=results.static.length+(results.links||[]).length+(results.snippets||[]).length+(results.calculations||[]).length;
const off=results.static.length+(results.links||[]).length+(results.folders||[]).length+(results.snippets||[]).length+(results.calculations||[]).length;
return <SearchResultItem key={`o${i}`} item={{...item,type:'order'}} idx={off+i} activeIdx={active} onNavigate={navigate} onHover={setActiveR}/>;
})}
</div>
@@ -2380,8 +2430,9 @@ const Field = ({ label, type='text', value, onChange, placeholder='', autoCapita
</div>
);
function AdminPanel({ toast, mobile, user }) {
function AdminPanel({ toast, mobile, user, nav }) {
const [section, setSection] = useState('profil');
useEffect(() => { if (nav?.section) setSection(nav.section); }, [nav?.ts]);
const [pw, setPw] = useState({ current:'', newPw:'', confirm:'' });
const [avatar, setAvatar] = useState(localStorage.getItem('dd_avatar') || null);
const [un, setUn] = useState({ newUsername:'', unPw:'' });
@@ -2682,7 +2733,7 @@ export default function App() {
)}
<main style={mainStyle}>
{active==='dashboard' && <Dashboard toast={toast} mobile={mobile} setActive={setActive} setDevToolsNav={setDevToolsNav} unreadMsgs={unreadMsgs} unreadBoard={unreadBoard} unreadPromoted={unreadPromoted} onBoardRead={()=>{ setUnreadBoard(0); setUnreadPromoted(0); }} unreadChangelog={unreadChangelog} onChangelogRead={()=>setUnreadChangelog(0)} user={user}/>}
{active==='admin' && <AdminPanel toast={toast} mobile={mobile} user={user}/>}
{active==='admin' && <AdminPanel toast={toast} mobile={mobile} user={user} nav={devToolsNav}/>}
{activeTool && <activeTool.component toast={toast} mobile={mobile} setActive={setActive} {...(activeTool.id==='devtools'?{nav:devToolsNav}:{})}/>}
</main>
</div>