Schnellzugriff Mobile: max 2 Zeilen, horizontal wischbar mit Snap

This commit is contained in:
2026-05-29 10:45:32 +02:00
parent 2e033d8ad4
commit 4f2c06f817

View File

@@ -485,20 +485,65 @@ function QuickLinks({ toast, mobile }) {
{/* Link-Grid */}
{links.length === 0 && !editMode
? <div style={{ color:'rgba(255,255,255,0.5)', fontSize:11, fontFamily:'monospace', padding:'6px 0' }}>Links können unter Einstellungen Dashboard hinzugefügt werden.</div>
: mobile ? (() => {
// Mobile: max 2 Zeilen, dann horizontal scrollbar
// Berechne Icons pro Zeile anhand der Viewport-Breite
const iconW = 58 + 6; // minWidth + gap
const containerW = window.innerWidth - 28 - 28; // padding links+rechts (S.card=14px*2)
const perRow = Math.max(3, Math.floor(containerW / iconW));
const maxVisible = perRow * 2;
const needsScroll = links.length > maxVisible;
const pages = needsScroll
? Math.ceil(links.length / maxVisible)
: 1;
// Gruppen zu je maxVisible Icons
const groups = [];
for (let i = 0; i < links.length; i += maxVisible) groups.push(links.slice(i, i + maxVisible));
return (
<div style={{ overflowX:'auto', scrollSnapType:'x mandatory',
display:'flex', gap:0, marginInline:-14, paddingInline:14,
scrollbarWidth:'none', WebkitOverflowScrolling:'touch' }}>
{groups.map((group, gi) => (
<div key={gi} style={{
display:'grid',
gridTemplateColumns:`repeat(${perRow}, ${iconW-6}px)`,
gridTemplateRows:'repeat(2, auto)',
gap:6,
flexShrink:0,
scrollSnapAlign:'start',
paddingRight: gi < groups.length-1 ? 14 : 0,
}}>
{group.map(l => (
<div key={l.id}>
<a href={l.url} target="_blank" rel="noopener noreferrer"
style={{ display:'flex', flexDirection:'column', alignItems:'center', justifyContent:'center', gap:3,
padding:'4px 2px', background:'rgba(255,255,255,0.04)',
border:'1px solid rgba(255,255,255,0.08)', borderRadius:10,
textDecoration:'none', height:48, cursor:'pointer', width:'100%' }}>
{l.icon && l.icon.startsWith('http')
? <img src={l.icon} alt="" style={{width:16,height:16,objectFit:'contain'}} onError={e=>e.target.style.display='none'}/>
: <span style={{ fontSize:16 }}>{l.icon}</span>}
<span style={{ color:'rgba(255,255,255,0.65)', fontSize:8, fontFamily:'monospace',
maxWidth:52, overflow:'hidden', textOverflow:'ellipsis', whiteSpace:'nowrap' }}>{l.title}</span>
</a>
</div>
))}
</div>
))}
</div>
);
})()
: <div style={{ display:'grid', gridTemplateColumns:'repeat(auto-fill,minmax(58px,1fr))', gap:6 }}>
{links.map(l => (
<div key={l.id} style={{ position:'relative' }}>
<a href={l.url} target="_blank" rel="noopener noreferrer"
style={{ display:'flex', flexDirection:'column', alignItems:'center', justifyContent:'center', gap:3,
padding: mobile?'4px 2px':'6px 4px',
background:'rgba(255,255,255,0.04)',
padding:'6px 4px', background:'rgba(255,255,255,0.04)',
border:'1px solid rgba(255,255,255,0.08)', borderRadius:10,
textDecoration:'none', height: mobile?48:58, cursor:'pointer' }}>
textDecoration:'none', height:58, cursor:'pointer' }}>
{l.icon && l.icon.startsWith('http')
? <img src={l.icon} alt="" style={{width:mobile?16:20,height:mobile?16:20,objectFit:'contain'}} onError={e=>e.target.style.display='none'}/>
: <span style={{ fontSize:mobile?16:18 }}>{l.icon}</span>}
? <img src={l.icon} alt="" style={{width:20,height:20,objectFit:'contain'}} onError={e=>e.target.style.display='none'}/>
: <span style={{ fontSize:18 }}>{l.icon}</span>}
<span style={{ color:'rgba(255,255,255,0.65)', fontSize:8, fontFamily:'monospace',
maxWidth:52, overflow:'hidden', textOverflow:'ellipsis', whiteSpace:'nowrap' }}>{l.title}</span>
</a>