mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-22 23:16:46 +00:00
ba70ad28b8
Arabic runs the app right to left, but margins, paddings, insets, text alignment, borders and corner radii were written for the left side, so icons sat against the wrong edge of their labels, indents and badges pointed the wrong way and amount columns aligned left. They now use the logical forms (ms-, ps-, start-, text-start, marginInlineStart, insetInlineEnd and their CSS equivalents), which are the very same sides in a left to right language. Geometry stays physical on purpose: maps, positions measured from the pointer or a bounding box, time axes, sliders, transforms and print output. Amounts drawn as several spans keep their order in a right to left row, the time picker keeps hours before minutes, and two switches whose thumb slid out of its track in Arabic now move the right way. lint:rtl counts what is still physical per file against a baseline that may only shrink (1512 uses in 370 files before, 319 in 113 now), and CI runs it, so new code reaches for the logical forms.
91 lines
5.9 KiB
TypeScript
91 lines
5.9 KiB
TypeScript
import { createPortal } from 'react-dom'
|
|
import { CalendarDays, Pencil, Trash2, ChevronDown, Check, Eye } from 'lucide-react'
|
|
import type { SidebarState } from './usePlacesSidebar'
|
|
|
|
export function MobileDayPickerSheet(S: SidebarState) {
|
|
const {
|
|
dayPickerPlace, setDayPickerPlace, setMobileShowDays, onPlaceClick, canEditPlaces, onEditPlace,
|
|
t, days, mobileShowDays, onAssignToDay, assignments, onDeletePlace,
|
|
} = S
|
|
return createPortal(
|
|
<div
|
|
role="presentation"
|
|
onClick={() => { setDayPickerPlace(null); setMobileShowDays(false) }}
|
|
style={{ position: 'fixed', inset: 0, background: 'rgba(0,0,0,0.4)', zIndex: 99999, display: 'flex', alignItems: 'flex-end', justifyContent: 'center' }}
|
|
>
|
|
<div
|
|
role="presentation"
|
|
onClick={e => e.stopPropagation()}
|
|
className="bg-surface-card"
|
|
style={{ borderRadius: '20px 20px 0 0', width: '100%', maxWidth: 500, maxHeight: '70vh', display: 'flex', flexDirection: 'column', overflow: 'hidden', paddingBottom: 'var(--bottom-nav-h)' }}
|
|
>
|
|
<div style={{ padding: '16px 20px 12px', borderBottom: '1px solid var(--border-secondary)' }}>
|
|
<div className="text-content" style={{ fontSize: 'calc(15px * var(--fs-scale-subtitle, 1))', fontWeight: 700 }}>{dayPickerPlace.name}</div>
|
|
{dayPickerPlace.address && <div className="text-content-faint" style={{ fontSize: 'calc(12px * var(--fs-scale-body, 1))', marginTop: 2 }}>{dayPickerPlace.address}</div>}
|
|
</div>
|
|
<div style={{ overflowY: 'auto', overscrollBehavior: 'contain', padding: '8px 12px' }}>
|
|
{/* View details */}
|
|
<button type="button"
|
|
onClick={() => { onPlaceClick(dayPickerPlace.id); setDayPickerPlace(null); setMobileShowDays(false) }}
|
|
className="bg-transparent text-content"
|
|
style={{ display: 'flex', alignItems: 'center', gap: 12, width: '100%', padding: '12px 14px', borderRadius: 12, border: 'none', cursor: 'pointer', fontFamily: 'inherit', textAlign: 'start', fontSize: 'calc(14px * var(--fs-scale-body, 1))' }}
|
|
>
|
|
<Eye size={18} color="var(--text-muted)" /> {t('places.viewDetails')}
|
|
</button>
|
|
{/* Edit */}
|
|
{canEditPlaces && (
|
|
<button type="button"
|
|
onClick={() => { onEditPlace(dayPickerPlace); setDayPickerPlace(null); setMobileShowDays(false) }}
|
|
className="bg-transparent text-content"
|
|
style={{ display: 'flex', alignItems: 'center', gap: 12, width: '100%', padding: '12px 14px', borderRadius: 12, border: 'none', cursor: 'pointer', fontFamily: 'inherit', textAlign: 'start', fontSize: 'calc(14px * var(--fs-scale-body, 1))' }}
|
|
>
|
|
<Pencil size={18} color="var(--text-muted)" /> {t('common.edit')}
|
|
</button>
|
|
)}
|
|
{/* Assign to day */}
|
|
{days?.length > 0 && (
|
|
<>
|
|
<button type="button"
|
|
onClick={() => setMobileShowDays(v => !v)}
|
|
className="bg-transparent text-content"
|
|
style={{ display: 'flex', alignItems: 'center', gap: 12, width: '100%', padding: '12px 14px', borderRadius: 12, border: 'none', cursor: 'pointer', fontFamily: 'inherit', textAlign: 'start', fontSize: 'calc(14px * var(--fs-scale-body, 1))' }}
|
|
>
|
|
<CalendarDays size={18} color="var(--text-muted)" /> {t('places.assignToDay')}
|
|
<ChevronDown size={14} style={{ marginInlineStart: 'auto', color: 'var(--text-faint)', transform: mobileShowDays ? 'rotate(180deg)' : 'none', transition: 'transform 0.15s' }} />
|
|
</button>
|
|
{mobileShowDays && (
|
|
<div style={{ paddingInlineStart: 20 }}>
|
|
{days.map((day, i) => (
|
|
<button type="button"
|
|
key={day.id}
|
|
onClick={() => { onAssignToDay(dayPickerPlace.id, day.id); setDayPickerPlace(null); setMobileShowDays(false) }}
|
|
style={{ display: 'flex', alignItems: 'center', gap: 10, width: '100%', padding: '10px 14px', borderRadius: 10, border: 'none', cursor: 'pointer', background: 'transparent', fontFamily: 'inherit', textAlign: 'start' }}
|
|
>
|
|
<div className="bg-surface-tertiary text-content" style={{ width: 28, height: 28, borderRadius: '50%', display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 'calc(12px * var(--fs-scale-body, 1))', fontWeight: 700, flexShrink: 0 }}>{i + 1}</div>
|
|
<div style={{ flex: 1, minWidth: 0 }}>
|
|
<div className="text-content" style={{ fontSize: 'calc(13px * var(--fs-scale-body, 1))', fontWeight: 500 }}>{day.title || t('dayplan.dayN', { n: i + 1 })}</div>
|
|
{day.date && <div className="text-content-faint" style={{ fontSize: 'calc(11px * var(--fs-scale-caption, 1))' }}>{new Date(day.date + 'T00:00:00Z').toLocaleDateString(undefined, { timeZone: 'UTC' })}</div>}
|
|
</div>
|
|
{(assignments[String(day.id)] || []).some(a => a.place?.id === dayPickerPlace.id) && <Check size={14} color="var(--text-faint)" />}
|
|
</button>
|
|
))}
|
|
</div>
|
|
)}
|
|
</>
|
|
)}
|
|
{/* Delete */}
|
|
{canEditPlaces && (
|
|
<button type="button"
|
|
onClick={() => { onDeletePlace(dayPickerPlace.id); setDayPickerPlace(null); setMobileShowDays(false) }}
|
|
style={{ display: 'flex', alignItems: 'center', gap: 12, width: '100%', padding: '12px 14px', borderRadius: 12, border: 'none', cursor: 'pointer', background: 'transparent', fontFamily: 'inherit', textAlign: 'start', fontSize: 'calc(14px * var(--fs-scale-body, 1))', color: '#ef4444' }}
|
|
>
|
|
<Trash2 size={18} /> {t('common.delete')}
|
|
</button>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>,
|
|
document.body
|
|
)
|
|
}
|