diff --git a/common/src/dateJump/GregorianJumper.tsx b/common/src/dateJump/GregorianJumper.tsx new file mode 100644 index 0000000..252589e --- /dev/null +++ b/common/src/dateJump/GregorianJumper.tsx @@ -0,0 +1,43 @@ +import {DateJumperProps} from './base'; +import React from 'react'; +import {gregorianJDN, jdnGregorian} from '../gregorian'; + +export default function GregorianJumper({minJDN, maxJDN, todayJDN, onJump}: DateJumperProps): JSX.Element { + const {todayYear, todayMonth, todayDay, startYear, endYear} = React.useMemo(() => { + const [todayYear, todayMonth, todayDay] = jdnGregorian(todayJDN); + const [startYear] = jdnGregorian(minJDN); + const [endYear] = jdnGregorian(maxJDN); + return {todayYear, todayMonth, todayDay, startYear, endYear}; + }, [minJDN, maxJDN, todayJDN]); + + const [year, setYear] = React.useState(todayYear.toString()); + const [month, setMonth] = React.useState(todayMonth.toString()); + const [day, setDay] = React.useState(todayDay.toString()); + + const validYear = /^-?\d+$/.test(year) && startYear <= +year && +year <= endYear; + const validMonth = /^\d+$/.test(month) && 1 <= +month && +month <= 12; + const validDay = /^\d+$/.test(day) && 1 <= +day && +day <= 31; + + function goToGregorian(event: React.FormEvent) { + event.preventDefault(); + + if (!validYear || !validMonth || !validDay) + return; + + onJump(gregorianJDN(+year, +month, +day)); + } + + return
+ Gregorian Date + setYear(e.target.value)} value={year} + min={startYear} max={endYear}/> + setMonth(e.target.value)} value={month} + min={1} max={12}/> + setDay(e.target.value)} value={day} + min={1} max={31}/> + +
; +} diff --git a/common/src/dateJump/base.ts b/common/src/dateJump/base.ts new file mode 100644 index 0000000..958516f --- /dev/null +++ b/common/src/dateJump/base.ts @@ -0,0 +1,6 @@ +export type DateJumperProps = { + minJDN: number; + maxJDN: number; + todayJDN: number; + onJump: (jdn: number) => void; +}; \ No newline at end of file diff --git a/common/src/dateJump/index.ts b/common/src/dateJump/index.ts new file mode 100644 index 0000000..feb9e73 --- /dev/null +++ b/common/src/dateJump/index.ts @@ -0,0 +1,3 @@ +import GregorianJumper from './GregorianJumper'; + +export {GregorianJumper}; diff --git a/common/src/french/index.ts b/common/src/french/index.ts index 3061f5d..023dd3b 100644 --- a/common/src/french/index.ts +++ b/common/src/french/index.ts @@ -1,6 +1,5 @@ import data from './cal.json'; import ruralName from './rural-days.json'; -import {jdnGregorian} from '../gregorian'; // Month 13 is for the complementary days export type FrenchMonth = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13; @@ -145,9 +144,6 @@ export function dateRuralName(month: FrenchMonth, day: FrenchDay): { name: strin return {name, title}; } -export const startGregorian = jdnGregorian(frStartJD); -export const endGregorian = jdnGregorian(frEndJD); - export function frDateFormat({year, month, day}: { year: number, month: FrenchMonth, day: FrenchDay }): string { return `${dateName(month, day)} ${year}`; } diff --git a/frcal/src/App.tsx b/frcal/src/App.tsx index f863885..e833e7c 100644 --- a/frcal/src/App.tsx +++ b/frcal/src/App.tsx @@ -1,16 +1,9 @@ -import React, {FormEvent} from 'react'; +import React from 'react'; import {Calendar} from './Calendar'; -import { - endGregorian, - frEndJD, - FrenchMonth, - frSupportedYear, - jdnFrench, - startGregorian, - frStartJD, -} from '@common/french'; -import {dateJDN, gregorianJDN} from '@common/gregorian'; +import {FrenchMonth, frEndJD, frStartJD, frSupportedYear, jdnFrench} from '@common/french'; +import {dateJDN} from '@common/gregorian'; import {TimeOfDay} from './TimeOfDay'; +import {GregorianJumper} from '@common/dateJump'; type YearMonth = { year: number; @@ -31,9 +24,6 @@ function parseURL(): YearMonth | null { type AppState = YearMonth & { todayJDN: number, - goYear: string, - goMonth: string, - goDay: string, }; class App extends React.Component<{}, AppState> { @@ -41,16 +31,12 @@ class App extends React.Component<{}, AppState> { constructor(props: {}) { super(props); - const today = new Date(); - const todayJDN = dateJDN(today); + const todayJDN = dateJDN(new Date()); const {year, month} = jdnFrench(todayJDN); this.state = { ...(parseURL() || {year, month}), todayJDN, - goYear: today.getFullYear().toString(), - goMonth: (today.getMonth() + 1).toString(), - goDay: today.getDate().toString(), }; this.updateStateFromURL = this.updateStateFromURL.bind(this); } @@ -75,38 +61,10 @@ class App extends React.Component<{}, AppState> { } } - changeField(field: keyof AppState, event: any) { - this.setState({[field]: event.target.value}); - } - - validYear() { - return /^-?\d+$/.test(this.state.goYear) && startGregorian[0] <= +this.state.goYear && - +this.state.goYear <= endGregorian[0]; - } - - validMonth() { - return /^\d+$/.test(this.state.goMonth) && 1 <= +this.state.goMonth && +this.state.goMonth <= 12; - } - - validDay() { - return /^\d+$/.test(this.state.goDay) && 1 <= +this.state.goDay && +this.state.goDay <= 31; - } - - goToGregorian(event: FormEvent) { - event.preventDefault(); - - if (!this.validYear() || !this.validMonth() || !this.validDay()) - return; - - const jdn = gregorianJDN(+this.state.goYear, +this.state.goMonth, +this.state.goDay); - const {year, month} = jdnFrench(Math.min(Math.max(frStartJD, jdn), frEndJD)); - this.setState({year, month}); - } - setState(state: any, callback?: () => void) { super.setState(state, () => { this.updateURL(); - callback && callback(); + callback?.(); }); } @@ -114,6 +72,11 @@ class App extends React.Component<{}, AppState> { this.setState({todayJDN}); }; + goToJDN = (jdn: number) => { + const {year, month} = jdnFrench(Math.min(Math.max(frStartJD, jdn), frEndJD)); + this.setState({year, month}); + }; + render() { return <> {

Go to a date

-
- Gregorian Date - - - - -
+
; } diff --git a/jcal/src/App.tsx b/jcal/src/App.tsx index 4515f49..9af34d5 100644 --- a/jcal/src/App.tsx +++ b/jcal/src/App.tsx @@ -1,13 +1,13 @@ -import React, {FormEvent} from 'react'; +import React from 'react'; import {Calendar} from './Calendar'; -import {frEndJD, frStartJD} from '@common/french'; import {dateJDN, gregorianJDN, JulianMonth} from '@common/gregorian'; import {DayChanger} from '@common/DayChanger'; import {jdnJulian} from '@common/julian'; +import {GregorianJumper} from '@common/dateJump'; // Not real limitations other than JS number precision. -const START_YEAR = -10_000_000_000_000; -const END_YEAR = 10_000_000_000_000; +const START_JDN = gregorianJDN(-10_000_000_000_000, 1, 1); +const END_JDN = gregorianJDN(10_000_000_000_000, 12, 31); type YearMonth = { year: number; @@ -28,9 +28,6 @@ function parseURL(): YearMonth | null { type AppState = YearMonth & { todayJDN: number, - goYear: string, - goMonth: string, - goDay: string, }; class App extends React.Component<{}, AppState> { @@ -38,16 +35,12 @@ class App extends React.Component<{}, AppState> { constructor(props: {}) { super(props); - const today = new Date(); - const todayJDN = dateJDN(today); + const todayJDN = dateJDN(new Date()); const [year, month] = jdnJulian(todayJDN); this.state = { ...(parseURL() || {year, month}), todayJDN, - goYear: today.getFullYear().toString(), - goMonth: (today.getMonth() + 1).toString(), - goDay: today.getDate().toString(), }; this.updateStateFromURL = this.updateStateFromURL.bind(this); } @@ -72,33 +65,6 @@ class App extends React.Component<{}, AppState> { } } - changeField(field: keyof AppState, event: any) { - this.setState({[field]: event.target.value}); - } - - validYear() { - return /^-?\d+$/.test(this.state.goYear) && START_YEAR <= +this.state.goYear && +this.state.goYear <= END_YEAR; - } - - validMonth() { - return /^\d+$/.test(this.state.goMonth) && 1 <= +this.state.goMonth && +this.state.goMonth <= 12; - } - - validDay() { - return /^\d+$/.test(this.state.goDay) && 1 <= +this.state.goDay && +this.state.goDay <= 31; - } - - goToGregorian(event: FormEvent) { - event.preventDefault(); - - if (!this.validYear() || !this.validMonth() || !this.validDay()) - return; - - const jdn = gregorianJDN(+this.state.goYear, +this.state.goMonth, +this.state.goDay); - const [year, month] = jdnJulian(Math.min(Math.max(frStartJD, jdn), frEndJD)); - this.setState({year, month}); - } - setState(state: any, callback?: () => void) { super.setState(state, () => { this.updateURL(); @@ -110,6 +76,11 @@ class App extends React.Component<{}, AppState> { this.setState({todayJDN}); }; + goToJDN = (jdn: number) => { + const [year, month] = jdnJulian(jdn); + this.setState({year, month}); + }; + render() { return <> {

Go to a date

-
- Gregorian Date - - - - -
+
; }