diff --git a/package.json b/package.json index fd58052..c0dca8f 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "ionicons": "^6.0.4", "isomorphic-xml2js": "^0.1.3", "jotai": "^1.10.0", + "jotai-location": "^0.2.0", "lodash": "^4.17.21", "pouchdb": "^7.3.1", "pouchdb-browser": "^7.3.1", diff --git a/src/App.tsx b/src/App.tsx index a6f5749..1c14002 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -32,7 +32,7 @@ import dispatch from './workers/dispatcher-main'; import LiveMap from './components/map/LiveMap'; import { atom, useAtom } from 'jotai'; -import { atomWithHash } from 'jotai/utils'; +import { atomWithHash } from 'jotai-location'; import { MapScope } from './components/map/types'; import { debounce } from 'lodash'; import GetLocation from './components/buttons/GetLocation'; @@ -42,6 +42,7 @@ import Forward from './components/buttons/Forward'; import CurrentLocation from './components/map/CurrentLocation'; import GpxImport from './components/dialogs/GpxImport'; import Gpxes from './components/map/Gpxes'; +import MapChooser from './components/dialogs/MapChooser'; // import { initDb } from './db'; // import PouchDB from 'pouchdb'; // import PouchDBFind from 'pouchdb-find'; @@ -93,6 +94,18 @@ export const setCenterAtom = atom(null, (get, set, center: geoPoint) => { set(scopeAtom, newScope); }); +export const tileProviderAtom = atom( + (get) => get(scopeAtom).tileProvider, + (get, set, tileProvider: string) => { + const previousScope = get(scopeAtom); + const newScope: MapScope = { + ...previousScope, + tileProvider, + }; + set(scopeAtom, newScope); + } +); + // const db = new PouchDB('dyomedea', { auto_compaction: true, revs_limit: 10 }); // initDb(db); @@ -129,6 +142,7 @@ const App: React.FC = () => { + diff --git a/src/components/dialogs/MapChooser.tsx b/src/components/dialogs/MapChooser.tsx new file mode 100644 index 0000000..3fae7d6 --- /dev/null +++ b/src/components/dialogs/MapChooser.tsx @@ -0,0 +1,78 @@ +import react, { useRef } from 'react'; + +import { + IonButton, + IonButtons, + IonContent, + IonIcon, + IonItem, + IonLabel, + IonList, + IonModal, + IonRadio, + IonRadioGroup, + IonTitle, + IonToolbar, +} from '@ionic/react'; +import { layersOutline } from 'ionicons/icons'; +import { nonFakeTileProviders } from '../map/tile-providers'; +import { tileProviderAtom } from '../../App'; +import i18n from '../../i18n/index'; +import { useAtom } from 'jotai'; + +import cssDialog from './dialogs.module.css'; + +export interface MapChooserProperties {} + +export const MapChooser: react.FC = ( + props: MapChooserProperties +) => { + const modal = useRef(null); + + const dismiss = () => { + modal.current?.dismiss(); + }; + + const [tileProvider, setTileProvider] = useAtom(tileProviderAtom); + + const changeHandler = (event: any) => { + setTileProvider(event.detail.value); + dismiss(); + }; + + return ( + <> + + + + + + {i18n.mapChooser.chooseYourMap} + + dismiss()}>{i18n.common.close} + + + + + + {Object.keys(nonFakeTileProviders).map((provider) => { + return ( + + {nonFakeTileProviders[provider].name} + + + ); + })} + + + + + + ); +}; + +export default MapChooser; diff --git a/src/components/dialogs/dialogs.module.css b/src/components/dialogs/dialogs.module.css new file mode 100644 index 0000000..a5d5493 --- /dev/null +++ b/src/components/dialogs/dialogs.module.css @@ -0,0 +1,15 @@ +.modal { + --height: 100%; + --border-radius: 16px; + --box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), + 0 4px 6px -4px rgb(0 0 0 / 0.1); +} + +.modal ion-toolbar { + --background: rgba(14, 116, 144, 0.7); + --color: white; +} + +.modal ion-content { + background-color: rgba(255, 255, 255, 0.7); +} diff --git a/src/components/map/tile-providers.tsx b/src/components/map/tile-providers.tsx index 7fc499c..8fb86de 100644 --- a/src/components/map/tile-providers.tsx +++ b/src/components/map/tile-providers.tsx @@ -133,6 +133,8 @@ export const tileProviders: TileProviders = { }, }; +export const { fake, ...nonFakeTileProviders } = tileProviders; + const mod = (n: number, m: number) => { const jsMod = n % m; return jsMod >= 0 ? jsMod : jsMod + m; diff --git a/src/i18n/index.tsx b/src/i18n/index.tsx new file mode 100644 index 0000000..d9a1f63 --- /dev/null +++ b/src/i18n/index.tsx @@ -0,0 +1,36 @@ +import LocalizedStrings from 'react-localization'; + +const strings = new LocalizedStrings({ + en: { + colonize: (input: string): any => strings.formatString('{0}:', input), + + common: { save: 'Save', cancel: 'Cancel', close: 'Close' }, + + mapChooser: { + chooseYourMap: 'Choose your map', + }, + }, + fr: { + colonize: (input: string): any => strings.formatString('{0} :', input), + + common: { + save: 'Sauvegarder', + cancel: 'Annuler', + close: 'Fermer', + }, + + mapChooser: { + chooseYourMap: 'Choisissez votre carte', + }, + }, +}); + +export default strings; + +export const setI18nLanguage = (language: string) => { + if (language === undefined || language === 'auto') { + strings.setLanguage(strings.getInterfaceLanguage()); + } else { + strings.setLanguage(language); + } +};