Dateien nach "frontend/src" hochladen
This commit is contained in:
@@ -90,7 +90,7 @@ export default function CalendarWidget() {
|
|||||||
const getFeeds = () => { try { return JSON.parse(localStorage.getItem('dd_cal_feeds') || '[]'); } catch { return []; } };
|
const getFeeds = () => { try { return JSON.parse(localStorage.getItem('dd_cal_feeds') || '[]'); } catch { return []; } };
|
||||||
const [feedCount, setFeedCount] = useState(0); // trigger re-render
|
const [feedCount, setFeedCount] = useState(0); // trigger re-render
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [selected, setSelected] = useState(null); // date object
|
const [selected, setSelected] = useState(new Date()); // default: heute
|
||||||
|
|
||||||
const [errors, setErrors] = useState([]);
|
const [errors, setErrors] = useState([]);
|
||||||
|
|
||||||
@@ -124,6 +124,15 @@ export default function CalendarWidget() {
|
|||||||
const refresh = () => { const f = getFeeds(); if (f.length > 0) loadFeeds(f); setFeedCount(f.length); };
|
const refresh = () => { const f = getFeeds(); if (f.length > 0) loadFeeds(f); setFeedCount(f.length); };
|
||||||
useEffect(() => { if (isOpen) refresh(); }, [isOpen]);
|
useEffect(() => { if (isOpen) refresh(); }, [isOpen]);
|
||||||
|
|
||||||
|
// Nächster oder aktueller Termin (für zugeklappte Ansicht)
|
||||||
|
const nextEvent = useMemo(() => {
|
||||||
|
const now = new Date();
|
||||||
|
const upcoming = events
|
||||||
|
.filter(e => e.dtend >= now)
|
||||||
|
.sort((a,b) => a.dtstart - b.dtstart);
|
||||||
|
return upcoming[0] || null;
|
||||||
|
}, [events]);
|
||||||
|
|
||||||
// Calendar grid
|
// Calendar grid
|
||||||
const days = useMemo(() => {
|
const days = useMemo(() => {
|
||||||
const first = new Date(cur.y, cur.m, 1);
|
const first = new Date(cur.y, cur.m, 1);
|
||||||
@@ -161,6 +170,24 @@ export default function CalendarWidget() {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Nächster Termin auch im zugeklappten Zustand */}
|
||||||
|
{!isOpen && nextEvent && (
|
||||||
|
<div style={{ marginTop:8, display:'flex', alignItems:'center', gap:8 }}>
|
||||||
|
<span style={{ width:6, height:6, borderRadius:'50%', background:nextEvent.color||'#4ecdc4',
|
||||||
|
flexShrink:0, display:'inline-block' }}/>
|
||||||
|
<div style={{ flex:1, minWidth:0 }}>
|
||||||
|
<div style={{ color:'rgba(255,255,255,0.75)', fontFamily:'monospace', fontSize:11,
|
||||||
|
overflow:'hidden', textOverflow:'ellipsis', whiteSpace:'nowrap' }}>{nextEvent.summary}</div>
|
||||||
|
<div style={{ color:'rgba(255,255,255,0.4)', fontFamily:'monospace', fontSize:9 }}>
|
||||||
|
{nextEvent.allDay
|
||||||
|
? nextEvent.dtstart.toLocaleDateString('de-DE',{weekday:'short',day:'numeric',month:'short'})
|
||||||
|
: `${nextEvent.dtstart.toLocaleDateString('de-DE',{weekday:'short',day:'numeric',month:'short'})} ${nextEvent.dtstart.toLocaleTimeString('de-DE',{hour:'2-digit',minute:'2-digit'})}`
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{isOpen && (
|
{isOpen && (
|
||||||
<div style={{ marginTop:12 }}>
|
<div style={{ marginTop:12 }}>
|
||||||
{/* Fehler */}
|
{/* Fehler */}
|
||||||
@@ -186,6 +213,10 @@ export default function CalendarWidget() {
|
|||||||
cursor:'pointer', fontSize:18, padding:'0 6px' }}>›</button>
|
cursor:'pointer', fontSize:18, padding:'0 6px' }}>›</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div style={{ display:'flex', gap:16, alignItems:'flex-start' }}>
|
||||||
|
{/* Kalender-Grid */}
|
||||||
|
<div style={{ flex:'0 0 auto', width: window.innerWidth>=768 ? 'min(320px,50%)' : '100%' }}>
|
||||||
|
|
||||||
{/* Wochentage */}
|
{/* Wochentage */}
|
||||||
<div style={{ display:'grid', gridTemplateColumns:'repeat(7,1fr)', gap:2, marginBottom:4 }}>
|
<div style={{ display:'grid', gridTemplateColumns:'repeat(7,1fr)', gap:2, marginBottom:4 }}>
|
||||||
{WEEKDAYS.map(d => (
|
{WEEKDAYS.map(d => (
|
||||||
@@ -226,6 +257,11 @@ export default function CalendarWidget() {
|
|||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
</div>{/* Ende Kalender-Grid */}
|
||||||
|
|
||||||
|
{/* Termine – auf PC rechts, auf Mobile darunter */}
|
||||||
|
<div style={{ flex:1, minWidth:0, ...(window.innerWidth<768 ? {width:'100%'} : {}) }}>
|
||||||
{/* Ausgewählter Tag Events */}
|
{/* Ausgewählter Tag Events */}
|
||||||
{selected && (
|
{selected && (
|
||||||
<div style={{ marginTop:10, borderTop:'1px solid rgba(255,255,255,0.07)', paddingTop:10 }}>
|
<div style={{ marginTop:10, borderTop:'1px solid rgba(255,255,255,0.07)', paddingTop:10 }}>
|
||||||
@@ -253,6 +289,9 @@ export default function CalendarWidget() {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
</div>{/* Ende Termine */}
|
||||||
|
</div>{/* Ende Flex-Layout */}
|
||||||
|
|
||||||
{getFeeds().length === 0 && (
|
{getFeeds().length === 0 && (
|
||||||
<div style={{ marginTop:10, color:'rgba(255,255,255,0.3)', fontFamily:'monospace', fontSize:11, textAlign:'center' }}>
|
<div style={{ marginTop:10, color:'rgba(255,255,255,0.3)', fontFamily:'monospace', fontSize:11, textAlign:'center' }}>
|
||||||
Noch keine Kalender abonniert. Füge Kalender in den Einstellungen hinzu.
|
Noch keine Kalender abonniert. Füge Kalender in den Einstellungen hinzu.
|
||||||
|
|||||||
Reference in New Issue
Block a user