Dashboard: Kalender naechster Eintrag mit TT.MM. HH:MM, Schnellzugriff 4 pro Reihe zentriert

This commit is contained in:
2026-06-02 21:02:18 +02:00
parent b0b4c27f00
commit fe899f5287
2 changed files with 9 additions and 14 deletions

View File

@@ -437,19 +437,17 @@ function BottomNav({ active, setActive, user, onLogout, updateInfo, onUpdateClic
// ── Dashboard Widgets ───────────────────────────────────────────────────────── // ── Dashboard Widgets ─────────────────────────────────────────────────────────
// ── QuickLinks Carousel (Mobile) ───────────────────────────────────────────── // ── QuickLinks Carousel (Mobile) ─────────────────────────────────────────────
function QuickLinksCarousel({ links }) { function QuickLinksCarousel({ links }) {
const iconW = 58; const gap = 6; const perRow = 4;
const containerW = window.innerWidth - 28; const gap = 6;
const perRow = Math.max(3, Math.floor((containerW + gap) / (iconW + gap)));
const pageSize = perRow * 2; const pageSize = perRow * 2;
const pageCount = Math.ceil(links.length / pageSize); const pageCount = Math.ceil(links.length / pageSize);
const [page, setPage] = useState(0); const [page, setPage] = useState(0);
const scrollRef = useRef(null); const scrollRef = useRef(null);
// Sync scroll position → page indicator
const onScroll = () => { const onScroll = () => {
if (!scrollRef.current) return; if (!scrollRef.current) return;
const p = Math.round(scrollRef.current.scrollLeft / containerW); const p = Math.round(scrollRef.current.scrollLeft / scrollRef.current.offsetWidth);
setPage(p); setPage(p);
}; };
@@ -457,18 +455,17 @@ function QuickLinksCarousel({ links }) {
const canRight = page < pageCount - 1; const canRight = page < pageCount - 1;
const scrollTo = (p) => { const scrollTo = (p) => {
scrollRef.current?.scrollTo({ left: p * containerW, behavior:'smooth' }); scrollRef.current?.scrollTo({ left: p * scrollRef.current.offsetWidth, behavior:'smooth' });
}; };
if (pageCount <= 1) return ( if (pageCount <= 1) return (
<div style={{ display:'grid', gridTemplateColumns:`repeat(${perRow}, 1fr)`, gap }}> <div style={{ display:'grid', gridTemplateColumns:`repeat(${perRow}, 1fr)`, gap, justifyItems:'center' }}>
{links.map(l => <QuickLinkIcon key={l.id} l={l}/>)} {links.map(l => <QuickLinkIcon key={l.id} l={l}/>)}
</div> </div>
); );
return ( return (
<div style={{ position:'relative' }}> <div style={{ position:'relative' }}>
{/* Scroll container overflow hidden so nothing peeks */}
<div ref={scrollRef} onScroll={onScroll} style={{ <div ref={scrollRef} onScroll={onScroll} style={{
display:'flex', overflowX:'auto', scrollSnapType:'x mandatory', display:'flex', overflowX:'auto', scrollSnapType:'x mandatory',
scrollbarWidth:'none', WebkitOverflowScrolling:'touch', scrollbarWidth:'none', WebkitOverflowScrolling:'touch',
@@ -479,8 +476,9 @@ function QuickLinksCarousel({ links }) {
display:'grid', display:'grid',
gridTemplateColumns:`repeat(${perRow}, 1fr)`, gridTemplateColumns:`repeat(${perRow}, 1fr)`,
gridTemplateRows:'repeat(2, auto)', gridTemplateRows:'repeat(2, auto)',
justifyItems:'center',
gap, flexShrink:0, scrollSnapAlign:'start', gap, flexShrink:0, scrollSnapAlign:'start',
width: containerW, width:'100%', minWidth:'100%',
}}> }}>
{links.slice(pi*pageSize, (pi+1)*pageSize).map(l => <QuickLinkIcon key={l.id} l={l}/>)} {links.slice(pi*pageSize, (pi+1)*pageSize).map(l => <QuickLinkIcon key={l.id} l={l}/>)}
</div> </div>
@@ -2383,10 +2381,7 @@ export default function App() {
const [user,setUser]=useState(null); const [user,setUser]=useState(null);
const [active,setActiveRaw]=useState('dashboard'); const [active,setActiveRaw]=useState('dashboard');
const setActive = (page) => { const setActive = (page) => {
if (window.__newBuildAvailable) { import('./main.jsx').then(m => m.reloadIfNewBuild?.()).catch(()=>{});
window.location.reload();
return; // kein Rendern mehr, Reload läuft
}
setActiveRaw(page); setActiveRaw(page);
}; };
const [toastMsg,setToastMsg]=useState({msg:'',type:'success'}); const [toastMsg,setToastMsg]=useState({msg:'',type:'success'});

View File

@@ -172,7 +172,7 @@ export default function CalendarWidget() {
<span style={{ color:'rgba(255,255,255,0.35)', fontFamily:'monospace', fontSize:9, flexShrink:0 }}> <span style={{ color:'rgba(255,255,255,0.35)', fontFamily:'monospace', fontSize:9, flexShrink:0 }}>
{nextEvent.allDay {nextEvent.allDay
? nextEvent.dtstart.toLocaleDateString('de-DE',{day:'numeric',month:'short'}) ? nextEvent.dtstart.toLocaleDateString('de-DE',{day:'numeric',month:'short'})
: nextEvent.dtstart.toLocaleTimeString('de-DE',{hour:'2-digit',minute:'2-digit'}) : nextEvent.dtstart.toLocaleString('de-DE',{day:'2-digit',month:'2-digit',hour:'2-digit',minute:'2-digit'})
} }
</span> </span>
</div> </div>