fix: make CalendarEventModal more compact for small smartphone screens

- Modal uses flexbox column layout: scrollable body + pinned action bar
- maxHeight raised to 96vh, width uses calc(100vw - 12px)
- iconRow: gap 10→8px, padding 6→3px, minHeight 28→24px
- iconCol: width 20→18px
- inlineSelect: fontSize 0.8→0.78rem, padding 2→1px
- Title: fontSize 1.1→1rem, padding 4→3px
- Date inputs: padding 4→3px, fontSize 0.8→0.78rem, smaller labels
- Notes: minHeight 50→36px, padding tightened
- Action buttons: padding and font slightly reduced
- All section paddings reduced from 16px to 14px

v1.81.2
This commit is contained in:
mARTin 2026-03-31 09:59:56 +02:00
parent 5bcf281502
commit bb34e083d5
2 changed files with 47 additions and 39 deletions

View File

@ -1,6 +1,6 @@
{ {
"name": "my-weekly-todo-list", "name": "my-weekly-todo-list",
"version": "1.81.1", "version": "1.81.2",
"description": "A web-based weekly task management application that organizes to-dos and calendar events in a single, intuitive weekly view", "description": "A web-based weekly task management application that organizes to-dos and calendar events in a single, intuitive weekly view",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {

View File

@ -337,11 +337,11 @@ export default function CalendarEventModal({
// Compact icon-row style used throughout // Compact icon-row style used throughout
const iconRow: React.CSSProperties = { const iconRow: React.CSSProperties = {
display: 'flex', alignItems: 'center', gap: '10px', display: 'flex', alignItems: 'center', gap: '8px',
padding: '6px 0', minHeight: '28px', padding: '3px 0', minHeight: '24px',
}; };
const iconCol: React.CSSProperties = { const iconCol: React.CSSProperties = {
width: '20px', display: 'flex', alignItems: 'center', justifyContent: 'center', width: '18px', display: 'flex', alignItems: 'center', justifyContent: 'center',
color: 'var(--weekly-text-light)', flexShrink: 0, opacity: 0.6, color: 'var(--weekly-text-light)', flexShrink: 0, opacity: 0.6,
}; };
const fieldCol: React.CSSProperties = { const fieldCol: React.CSSProperties = {
@ -349,8 +349,8 @@ export default function CalendarEventModal({
}; };
const inlineSelect: React.CSSProperties = { const inlineSelect: React.CSSProperties = {
background: 'transparent', border: 'none', background: 'transparent', border: 'none',
fontSize: '0.8rem', cursor: 'pointer', outline: 'none', fontSize: '0.78rem', cursor: 'pointer', outline: 'none',
color: 'var(--weekly-text)', padding: '2px 0', color: 'var(--weekly-text)', padding: '1px 0',
}; };
const chipBtn = (active: boolean): React.CSSProperties => ({ const chipBtn = (active: boolean): React.CSSProperties => ({
padding: '3px 10px', borderRadius: '14px', fontSize: '0.72rem', fontWeight: 500, padding: '3px 10px', borderRadius: '14px', fontSize: '0.72rem', fontWeight: 500,
@ -366,19 +366,23 @@ export default function CalendarEventModal({
<div className="weekly-modal-overlay" onClick={onClose}> <div className="weekly-modal-overlay" onClick={onClose}>
<div className="weekly-modal-content" onClick={e => e.stopPropagation()} style={{ <div className="weekly-modal-content" onClick={e => e.stopPropagation()} style={{
maxWidth: '380px', maxWidth: '380px',
width: 'calc(100vw - 16px)', width: 'calc(100vw - 12px)',
padding: '0', padding: '0',
borderRadius: '14px', borderRadius: '12px',
boxShadow: '0 12px 40px rgba(0,0,0,0.18)', boxShadow: '0 12px 40px rgba(0,0,0,0.18)',
border: 'none', border: 'none',
maxHeight: '90vh', maxHeight: '96vh',
overflowY: 'auto', display: 'flex',
flexDirection: 'column',
overflow: 'hidden', overflow: 'hidden',
}}> }}>
{/* Color accent bar at top */} {/* Color accent bar at top */}
<div style={{ height: '4px', background: calColor }} /> <div style={{ height: '3px', background: calColor, flexShrink: 0 }} />
<div style={{ padding: '12px 16px 8px', display: 'flex', flexDirection: 'column', gap: '2px' }}> {/* Scrollable body */}
<div style={{ flex: 1, overflowY: 'auto', minHeight: 0 }}>
<div style={{ padding: '8px 14px 6px', display: 'flex', flexDirection: 'column', gap: '2px' }}>
{error && <div style={{ color: '#ef4444', fontSize: '0.75rem', textAlign: 'center', padding: '4px', background: 'rgba(239,68,68,0.08)', borderRadius: '6px', marginBottom: '4px' }}>{error}</div>} {error && <div style={{ color: '#ef4444', fontSize: '0.75rem', textAlign: 'center', padding: '4px', background: 'rgba(239,68,68,0.08)', borderRadius: '6px', marginBottom: '4px' }}>{error}</div>}
{/* Title */} {/* Title */}
@ -389,7 +393,7 @@ export default function CalendarEventModal({
placeholder={language === 'de' ? 'Titel hinzufügen' : 'Add title'} placeholder={language === 'de' ? 'Titel hinzufügen' : 'Add title'}
autoFocus autoFocus
style={{ style={{
width: '100%', padding: '4px 0', fontSize: '1.1rem', fontWeight: 600, width: '100%', padding: '3px 0', fontSize: '1rem', fontWeight: 600,
border: 'none', borderBottom: `2px solid ${calColor}`, border: 'none', borderBottom: `2px solid ${calColor}`,
background: 'transparent', outline: 'none', background: 'transparent', outline: 'none',
color: 'var(--weekly-text)', color: 'var(--weekly-text)',
@ -397,7 +401,7 @@ export default function CalendarEventModal({
/> />
{/* Calendar selector */} {/* Calendar selector */}
<div style={{ ...iconRow, padding: '4px 0' }}> <div style={{ ...iconRow, padding: '2px 0' }}>
<div style={{ ...iconCol, gap: '4px', width: 'auto', display: 'flex', alignItems: 'center' }}> <div style={{ ...iconCol, gap: '4px', width: 'auto', display: 'flex', alignItems: 'center' }}>
<span style={{ fontSize: '0.8rem', opacity: 0.7 }}>{selectedCal ? getProviderIcon(selectedCal.provider) : null}</span> <span style={{ fontSize: '0.8rem', opacity: 0.7 }}>{selectedCal ? getProviderIcon(selectedCal.provider) : null}</span>
<div style={{ width: '10px', height: '10px', borderRadius: '50%', background: calColor, flexShrink: 0 }} /> <div style={{ width: '10px', height: '10px', borderRadius: '50%', background: calColor, flexShrink: 0 }} />
@ -458,10 +462,10 @@ export default function CalendarEventModal({
</div> </div>
{/* Divider */} {/* Divider */}
<div style={{ height: '1px', background: 'var(--weekly-border, #eee)', margin: '0 16px' }} /> <div style={{ height: '1px', background: 'var(--weekly-border, #eee)', margin: '0 14px' }} />
{/* Main fields section */} {/* Main fields section */}
<div style={{ padding: '4px 16px', display: 'flex', flexDirection: 'column', gap: '0' }}> <div style={{ padding: '2px 14px', display: 'flex', flexDirection: 'column', gap: '0' }}>
{/* All Day toggle */} {/* All Day toggle */}
<div style={iconRow}> <div style={iconRow}>
@ -491,33 +495,33 @@ export default function CalendarEventModal({
</div> </div>
{/* Start & End times - compact inline */} {/* Start & End times - compact inline */}
<div style={{ ...iconRow, padding: '2px 0' }}> <div style={{ ...iconRow, padding: '1px 0' }}>
<div style={iconCol} /> <div style={iconCol} />
<div style={{ ...fieldCol, display: 'flex', flexDirection: 'column', gap: '2px' }}> <div style={{ ...fieldCol, display: 'flex', flexDirection: 'column', gap: '2px' }}>
<div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}> <div style={{ display: 'flex', alignItems: 'center', gap: '6px' }}>
<span style={{ fontSize: '0.75rem', color: 'var(--weekly-text-light)', width: '32px', flexShrink: 0 }}>{language === 'de' ? 'Von' : 'From'}</span> <span style={{ fontSize: '0.72rem', color: 'var(--weekly-text-light)', width: '26px', flexShrink: 0 }}>{language === 'de' ? 'Von' : 'From'}</span>
<input <input
type={allDay ? "date" : "datetime-local"} type={allDay ? "date" : "datetime-local"}
value={allDay ? startDate.toISOString().split('T')[0] : toLocalISOString(startDate)} value={allDay ? startDate.toISOString().split('T')[0] : toLocalISOString(startDate)}
onChange={e => handleStartDateChange(e.target.value)} onChange={e => handleStartDateChange(e.target.value)}
style={{ style={{
flex: 1, padding: '4px 8px', border: 'none', borderRadius: '6px', flex: 1, padding: '3px 6px', border: 'none', borderRadius: '5px',
background: 'var(--weekly-bg-secondary, #f3f4f6)', background: 'var(--weekly-bg-secondary, #f3f4f6)',
fontSize: '0.8rem', outline: 'none', color: 'var(--weekly-text)', fontSize: '0.78rem', outline: 'none', color: 'var(--weekly-text)',
minWidth: 0, minWidth: 0,
}} }}
/> />
</div> </div>
<div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}> <div style={{ display: 'flex', alignItems: 'center', gap: '6px' }}>
<span style={{ fontSize: '0.75rem', color: 'var(--weekly-text-light)', width: '32px', flexShrink: 0 }}>{language === 'de' ? 'Bis' : 'To'}</span> <span style={{ fontSize: '0.72rem', color: 'var(--weekly-text-light)', width: '26px', flexShrink: 0 }}>{language === 'de' ? 'Bis' : 'To'}</span>
<input <input
type={allDay ? "date" : "datetime-local"} type={allDay ? "date" : "datetime-local"}
value={allDay ? endDate.toISOString().split('T')[0] : toLocalISOString(endDate)} value={allDay ? endDate.toISOString().split('T')[0] : toLocalISOString(endDate)}
onChange={e => setEndDate(new Date(e.target.value))} onChange={e => setEndDate(new Date(e.target.value))}
style={{ style={{
flex: 1, padding: '4px 8px', border: 'none', borderRadius: '6px', flex: 1, padding: '3px 6px', border: 'none', borderRadius: '5px',
background: 'var(--weekly-bg-secondary, #f3f4f6)', background: 'var(--weekly-bg-secondary, #f3f4f6)',
fontSize: '0.8rem', outline: 'none', color: 'var(--weekly-text)', fontSize: '0.78rem', outline: 'none', color: 'var(--weekly-text)',
minWidth: 0, minWidth: 0,
}} }}
/> />
@ -833,34 +837,38 @@ export default function CalendarEventModal({
</div> </div>
{/* Divider */} {/* Divider */}
<div style={{ height: '1px', background: 'var(--weekly-border, #eee)', margin: '0 16px' }} /> <div style={{ height: '1px', background: 'var(--weekly-border, #eee)', margin: '0 14px' }} />
{/* Notes */} {/* Notes */}
<div style={{ padding: '6px 16px 8px' }}> <div style={{ padding: '4px 14px 6px' }}>
<Suspense fallback={ <Suspense fallback={
<textarea <textarea
value={description} value={description}
onChange={e => setDescription(e.target.value)} onChange={e => setDescription(e.target.value)}
placeholder={language === 'de' ? 'Notizen' : 'Notes'} placeholder={language === 'de' ? 'Notizen' : 'Notes'}
rows={2} rows={2}
style={{ width: '100%', padding: '4px 0', border: 'none', background: 'transparent', resize: 'none', fontSize: '0.8rem', outline: 'none', color: 'var(--weekly-text)' }} style={{ width: '100%', padding: '3px 0', border: 'none', background: 'transparent', resize: 'none', fontSize: '0.78rem', outline: 'none', color: 'var(--weekly-text)' }}
/> />
}> }>
<RichTextEditor <RichTextEditor
value={description} value={description}
onChange={setDescription} onChange={setDescription}
placeholder={language === 'de' ? 'Notizen' : 'Notes'} placeholder={language === 'de' ? 'Notizen' : 'Notes'}
minHeight="50px" minHeight="36px"
/> />
</Suspense> </Suspense>
</div> </div>
{/* Actions bar */} {/* End scrollable body */}
</div>
{/* Actions bar — pinned at bottom */}
<div style={{ <div style={{
padding: '8px 16px', display: 'flex', justifyContent: 'space-between', alignItems: 'center', padding: '6px 14px', display: 'flex', justifyContent: 'space-between', alignItems: 'center',
borderTop: '1px solid var(--weekly-border)', borderTop: '1px solid var(--weekly-border)',
background: 'var(--weekly-bg-secondary, #fafafa)', background: 'var(--weekly-bg-secondary, #fafafa)',
borderRadius: '0 0 14px 14px', borderRadius: '0 0 12px 12px',
flexShrink: 0,
}}> }}>
<div style={{ display: 'flex', gap: '4px', alignItems: 'center', flexWrap: 'wrap', flex: 1, minWidth: 0 }}> <div style={{ display: 'flex', gap: '4px', alignItems: 'center', flexWrap: 'wrap', flex: 1, minWidth: 0 }}>
{event && onDelete && !showRecurringDeleteOptions && ( {event && onDelete && !showRecurringDeleteOptions && (
@ -868,8 +876,8 @@ export default function CalendarEventModal({
onClick={() => handleDelete()} onClick={() => handleDelete()}
disabled={isSaving || isDeleting} disabled={isSaving || isDeleting}
style={{ style={{
padding: '5px 10px', background: 'none', color: '#ef4444', padding: '4px 8px', background: 'none', color: '#ef4444',
border: 'none', borderRadius: '6px', fontSize: '0.8rem', border: 'none', borderRadius: '6px', fontSize: '0.78rem',
fontWeight: 500, cursor: 'pointer', fontWeight: 500, cursor: 'pointer',
opacity: isSaving || isDeleting ? 0.5 : 1 opacity: isSaving || isDeleting ? 0.5 : 1
}} }}
@ -881,8 +889,8 @@ export default function CalendarEventModal({
<button <button
onClick={() => setShowRecurringDeleteOptions(false)} onClick={() => setShowRecurringDeleteOptions(false)}
style={{ style={{
padding: '5px 10px', background: 'none', color: 'var(--weekly-text-light)', padding: '4px 8px', background: 'none', color: 'var(--weekly-text-light)',
border: 'none', fontSize: '0.8rem', cursor: 'pointer', border: 'none', fontSize: '0.78rem', cursor: 'pointer',
}} }}
> >
{language === 'de' ? 'Abbrechen' : 'Cancel'} {language === 'de' ? 'Abbrechen' : 'Cancel'}
@ -894,7 +902,7 @@ export default function CalendarEventModal({
</span> </span>
)} )}
{!event && ( {!event && (
<button onClick={onClose} style={{ padding: '5px 10px', fontSize: '0.8rem', color: 'var(--weekly-text-light)', border: 'none', background: 'none', cursor: 'pointer' }}> <button onClick={onClose} style={{ padding: '4px 8px', fontSize: '0.78rem', color: 'var(--weekly-text-light)', border: 'none', background: 'none', cursor: 'pointer' }}>
{language === 'de' ? 'Abbrechen' : 'Cancel'} {language === 'de' ? 'Abbrechen' : 'Cancel'}
</button> </button>
)} )}
@ -902,7 +910,7 @@ export default function CalendarEventModal({
<div style={{ display: 'flex', gap: '6px', flexShrink: 0 }}> <div style={{ display: 'flex', gap: '6px', flexShrink: 0 }}>
{event && ( {event && (
<button onClick={onClose} style={{ padding: '5px 10px', fontSize: '0.8rem', color: 'var(--weekly-text-light)', border: 'none', background: 'none', cursor: 'pointer' }}> <button onClick={onClose} style={{ padding: '4px 8px', fontSize: '0.78rem', color: 'var(--weekly-text-light)', border: 'none', background: 'none', cursor: 'pointer' }}>
{language === 'de' ? 'Abbrechen' : 'Cancel'} {language === 'de' ? 'Abbrechen' : 'Cancel'}
</button> </button>
)} )}
@ -911,7 +919,7 @@ export default function CalendarEventModal({
onClick={() => handleSubmit()} onClick={() => handleSubmit()}
disabled={isSaving || isDeleting} disabled={isSaving || isDeleting}
style={{ style={{
padding: '6px 18px', borderRadius: '8px', fontSize: '0.82rem', padding: '5px 14px', borderRadius: '7px', fontSize: '0.8rem',
fontWeight: 600, backgroundColor: calColor, color: 'white', fontWeight: 600, backgroundColor: calColor, color: 'white',
border: 'none', cursor: 'pointer', border: 'none', cursor: 'pointer',
opacity: isSaving || isDeleting ? 0.7 : 1, opacity: isSaving || isDeleting ? 0.7 : 1,