Optimise month field

This commit is contained in:
Benji Grant 2023-06-09 03:51:20 +10:00
parent 028d63992c
commit 25d029ba57
6 changed files with 35 additions and 30 deletions

View file

@ -4,13 +4,11 @@ import Header from '/src/components/Header/Header'
const Layout = async ({ children }: { children: React.ReactNode }) => <> const Layout = async ({ children }: { children: React.ReactNode }) => <>
<Content> <Content>
{/* @ts-expect-error Async Server Component */}
<Header /> <Header />
</Content> </Content>
{children} {children}
{/* @ts-expect-error Async Server Component */}
<Footer /> <Footer />
</> </>

View file

@ -15,7 +15,6 @@ export const metadata: Metadata = {
*/ */
const Page = async () => <> const Page = async () => <>
<Content isSlim> <Content isSlim>
{/* @ts-expect-error Async Server Component */}
<Header isFull isSmall /> <Header isFull isSmall />
</Content> </Content>

View file

@ -30,7 +30,6 @@ const Page = async () => {
return <> return <>
<Content> <Content>
{/* @ts-expect-error Async Server Component */}
<Header /> <Header />
<h1>{t('help:name')}</h1> <h1>{t('help:name')}</h1>
@ -82,7 +81,6 @@ const Page = async () => {
</Content> </Content>
</Section> </Section>
{/* @ts-expect-error Async Server Component */}
<Footer /> <Footer />
</> </>
} }

View file

@ -18,7 +18,6 @@ const Page = async () => {
return <> return <>
<Content> <Content>
{/* @ts-expect-error Async Server Component */}
<Header isFull /> <Header isFull />
</Content> </Content>
@ -32,7 +31,6 @@ const Page = async () => {
<Content> <Content>
<h2>{t('about.name')}</h2> <h2>{t('about.name')}</h2>
{/* @ts-expect-error Async Server Component */}
<Stats /> <Stats />
<P><Trans i18nKey="about.content.p1" t={t} i18n={i18n}>_<br /><Link href="/how-to" rel="help">_</Link>_</Trans></P> <P><Trans i18nKey="about.content.p1" t={t} i18n={i18n}>_<br /><Link href="/how-to" rel="help">_</Link>_</Trans></P>
@ -48,7 +46,6 @@ const Page = async () => {
</Content> </Content>
</Section> </Section>
{/* @ts-expect-error Async Server Component */}
<Footer /> <Footer />
</> </>
} }

View file

@ -24,7 +24,6 @@ const Page = async () => {
return <> return <>
<Content> <Content>
{/* @ts-expect-error Async Server Component */}
<Header /> <Header />
<h1>{t('privacy:name')}</h1> <h1>{t('privacy:name')}</h1>
@ -86,7 +85,6 @@ const Page = async () => {
</Content> </Content>
</Section> </Section>
{/* @ts-expect-error Async Server Component */}
<Footer /> <Footer />
</> </>
} }

View file

@ -23,7 +23,7 @@ const Month = ({ value, onChange }: MonthProps) => {
const weekStart = useStore(useSettingsStore, state => state.weekStart) ?? 0 const weekStart = useStore(useSettingsStore, state => state.weekStart) ?? 0
const [page, setPage] = useState<Temporal.PlainYearMonth>(Temporal.Now.plainDateISO().toPlainYearMonth()) const [page, setPage] = useState<Temporal.PlainYearMonth>(Temporal.Now.plainDateISO().toPlainYearMonth())
const dates = useMemo(() => calculateMonth(page, weekStart), [page, weekStart]) const dates = useMemo(() => calculateMonth(page, weekStart, i18n.language), [page, weekStart, i18n.language])
// Ref and state required to rerender but also access static version in callbacks // Ref and state required to rerender but also access static version in callbacks
const selectingRef = useRef<string[]>([]) const selectingRef = useRef<string[]>([])
@ -46,7 +46,7 @@ const Month = ({ value, onChange }: MonthProps) => {
}, [value]) }, [value])
return <> return <>
<div className={styles.header}> {useMemo(() => <div className={styles.header}>
<Button <Button
title={t<string>('form.dates.tooltips.previous')} title={t<string>('form.dates.tooltips.previous')}
onClick={() => setPage(page.subtract({ months: 1 }))} onClick={() => setPage(page.subtract({ months: 1 }))}
@ -58,13 +58,13 @@ const Month = ({ value, onChange }: MonthProps) => {
onClick={() => setPage(page.add({ months: 1 }))} onClick={() => setPage(page.add({ months: 1 }))}
icon={<ChevronRight />} icon={<ChevronRight />}
/> />
</div> </div>, [page, i18n.language])}
<div className={styles.dayLabels}> {useMemo(() => <div className={styles.dayLabels}>
{(rotateArray(getWeekdayNames(i18n.language, 'short'), weekStart ? 0 : 1)).map(name => {(rotateArray(getWeekdayNames(i18n.language, 'short'), weekStart ? 0 : 1)).map(name =>
<label key={name}>{name}</label> <label key={name}>{name}</label>
)} )}
</div> </div>, [i18n.language, weekStart])}
<div className={styles.grid}> <div className={styles.grid}>
{dates.length > 0 && dates.map((dateRow, y) => {dates.length > 0 && dates.map((dateRow, y) =>
@ -73,27 +73,27 @@ const Month = ({ value, onChange }: MonthProps) => {
className={makeClass( className={makeClass(
styles.date, styles.date,
date.month !== page.month && styles.otherMonth, date.month !== page.month && styles.otherMonth,
date.equals(Temporal.Now.plainDateISO()) && styles.today, date.isToday && styles.today,
( (
(!(mode.current === 'remove' && selecting.includes(date.toString())) && value.includes(date.toString())) (!(mode.current === 'remove' && selecting.includes(date.string)) && value.includes(date.string))
|| (mode.current === 'add' && selecting.includes(date.toString())) || (mode.current === 'add' && selecting.includes(date.string))
) && styles.selected, ) && styles.selected,
)} )}
key={date.toString()} key={date.string}
title={`${date.toLocaleString(i18n.language, { day: 'numeric', month: 'long' })}${date.equals(Temporal.Now.plainDateISO()) ? ` (${t('form.dates.tooltips.today')})` : ''}`} title={`${date.title}${date.isToday ? ` (${t('form.dates.tooltips.today')})` : ''}`}
onKeyDown={e => { onKeyDown={e => {
if (e.key === ' ' || e.key === 'Enter') { if (e.key === ' ' || e.key === 'Enter') {
if (value.includes(date.toString())) { if (value.includes(date.string)) {
onChange(value.filter(d => d !== date.toString())) onChange(value.filter(d => d !== date.string))
} else { } else {
onChange([...value, date.toString()]) onChange([...value, date.string])
} }
} }
}} }}
onPointerDown={e => { onPointerDown={e => {
startPos.current = { x, y } startPos.current = { x, y }
mode.current = value.includes(date.toString()) ? 'remove' : 'add' mode.current = value.includes(date.string) ? 'remove' : 'add'
setSelecting([date.toString()]) setSelecting([date.string])
e.currentTarget.releasePointerCapture(e.pointerId) e.currentTarget.releasePointerCapture(e.pointerId)
document.addEventListener('pointerup', handleFinishSelection, { once: true }) document.addEventListener('pointerup', handleFinishSelection, { once: true })
@ -106,10 +106,10 @@ const Month = ({ value, onChange }: MonthProps) => {
found.push({ y: cy, x: cx }) found.push({ y: cy, x: cx })
} }
} }
setSelecting(found.map(d => dates[d.y][d.x].toString())) setSelecting(found.map(d => dates[d.y][d.x].string))
} }
}} }}
>{date.toLocaleString(i18n.language, { day: 'numeric' })}</button>) >{date.label}</button>)
)} )}
</div> </div>
</> </>
@ -117,18 +117,33 @@ const Month = ({ value, onChange }: MonthProps) => {
export default Month export default Month
interface Day {
month: number
isToday: boolean
string: string
title: string
label: string
}
/** Calculate the dates to show for the month in a 2d array */ /** Calculate the dates to show for the month in a 2d array */
const calculateMonth = (month: Temporal.PlainYearMonth, weekStart: 0 | 1) => { const calculateMonth = (month: Temporal.PlainYearMonth, weekStart: 0 | 1, locale: string) => {
const today = Temporal.Now.plainDateISO()
const daysBefore = month.toPlainDate({ day: 1 }).dayOfWeek - weekStart const daysBefore = month.toPlainDate({ day: 1 }).dayOfWeek - weekStart
const daysAfter = 6 - month.toPlainDate({ day: month.daysInMonth }).dayOfWeek + weekStart const daysAfter = 6 - month.toPlainDate({ day: month.daysInMonth }).dayOfWeek + weekStart
const dates: Temporal.PlainDate[][] = [] const dates: Day[][] = []
let curDate = month.toPlainDate({ day: 1 }).subtract({ days: daysBefore }) let curDate = month.toPlainDate({ day: 1 }).subtract({ days: daysBefore })
let y = 0 let y = 0
let x = 0 let x = 0
for (let i = 0; i < daysBefore + month.daysInMonth + daysAfter; i++) { for (let i = 0; i < daysBefore + month.daysInMonth + daysAfter; i++) {
if (x === 0) dates[y] = [] if (x === 0) dates[y] = []
dates[y][x] = curDate dates[y][x] = {
month: curDate.month,
isToday: curDate.equals(today),
string: curDate.toString(),
title: curDate.toLocaleString(locale, { day: 'numeric', month: 'long' }),
label: curDate.toLocaleString(locale, { day: 'numeric' }),
}
curDate = curDate.add({ days: 1 }) curDate = curDate.add({ days: 1 })
x++ x++
if (x > 6) { if (x > 6) {