add admin for location field type

This commit is contained in:
Michael Schramm 2022-03-01 01:20:03 +01:00
parent 2e2d1b9a21
commit 019cd7f55e
12 changed files with 239 additions and 28 deletions

View File

@ -1,6 +1,7 @@
@import "variables";
@import "node_modules/swiper/swiper.scss";
@import "../node_modules/react-github-button/assets/style.css";
@import "../node_modules/leaflet/dist/leaflet.css";
:root {
--backgroundColor: #{$background-color};

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 618 B

View File

@ -1,33 +1,22 @@
import React from 'react'
import { CheckboxType } from './checkbox.type'
import { DateType } from './date.type'
import { DropdownType } from './dropdown.type'
import { EmailType } from './email.type'
import { HiddenType } from './hidden.type'
import { LinkType } from './link.type'
import { NumberType } from './number.type'
import { RadioType } from './radio.type'
import { RatingType } from './rating.type'
import { SliderType } from './slider.type'
import { TextType } from './text.type'
import { TextareaType } from './textarea.type'
import dynamic from 'next/dynamic'
import { ComponentType } from 'react'
import { AdminFieldTypeProps } from './type.props'
import { YesNoType } from './yes_no.type'
export const adminTypes: {
[key: string]: React.FC<AdminFieldTypeProps>
[key: string]: ComponentType<AdminFieldTypeProps>
} = {
date: DateType,
dropdown: DropdownType,
checkbox: CheckboxType,
email: EmailType,
hidden: HiddenType,
link: LinkType,
number: NumberType,
radio: RadioType,
rating: RatingType,
slider: SliderType,
textarea: TextareaType,
textfield: TextType,
yes_no: YesNoType,
checkbox: dynamic<AdminFieldTypeProps>(() => import('./checkbox.type').then(c => c.CheckboxType )),
date: dynamic<AdminFieldTypeProps>(() => import('./date.type').then(c => c.DateType )),
dropdown: dynamic<AdminFieldTypeProps>(() => import('./dropdown.type').then(c => c.DropdownType )),
email: dynamic<AdminFieldTypeProps>(() => import('./email.type').then(c => c.EmailType )),
hidden: dynamic<AdminFieldTypeProps>(() => import('./hidden.type').then(c => c.HiddenType )),
link: dynamic<AdminFieldTypeProps>(() => import('./link.type').then(c => c.LinkType )),
location: dynamic<AdminFieldTypeProps>(() => import('./location.type').then(c => c.LocationType ), { ssr: false }),
number: dynamic<AdminFieldTypeProps>(() => import('./number.type').then(c => c.NumberType )),
radio: dynamic<AdminFieldTypeProps>(() => import('./radio.type').then(c => c.RadioType )),
rating: dynamic<AdminFieldTypeProps>(() => import('./rating.type').then(c => c.RatingType )),
slider: dynamic<AdminFieldTypeProps>(() => import('./slider.type').then(c => c.SliderType )),
textarea: dynamic<AdminFieldTypeProps>(() => import('./textarea.type').then(c => c.TextareaType )),
textfield: dynamic<AdminFieldTypeProps>(() => import('./text.type').then(c => c.TextType )),
yes_no: dynamic<AdminFieldTypeProps>(() => import('./yes_no.type').then(c => c.YesNoType )),
}

View File

@ -0,0 +1,142 @@
import { Alert, Form, Input, InputNumber, Space } from 'antd'
import React from 'react'
import { useTranslation } from 'react-i18next'
import { MapContainer, TileLayer } from 'react-leaflet'
import { DraggableMarker } from '../../../map/draggable.marker'
import { AdminFieldTypeProps } from './type.props'
export const LocationType: React.FC<AdminFieldTypeProps> = (props) => {
const { t } = useTranslation()
return (
<div>
<Form.Item
label={t('type:location:default')}
labelCol={{ span: 6 }}
>
<Space>
<Form.Item
name={[
props.field.name as string,
'defaultValue',
'lat',
]}
noStyle
>
<InputNumber addonAfter={'LAT'} precision={7} step={0.00001} max={90} min={-90} />
</Form.Item>
<Form.Item
name={[
props.field.name as string,
'defaultValue',
'lng',
]}
noStyle
>
<InputNumber addonAfter={'LNG'} precision={7} step={0.00001} max={180} min={-180} />
</Form.Item>
</Space>
</Form.Item>
<Form.Item
label={t('type:location.initialZoom')}
name={[
props.field.name as string,
'optionKeys',
'initialZoom',
]}
labelCol={{ span: 6 }}
initialValue={1}
>
<InputNumber precision={0} min={1} max={18} />
</Form.Item>
<Form.Item
label={t('type:location.tiles')}
name={[
props.field.name as string,
'optionKeys',
'tiles',
]}
labelCol={{ span: 6 }}
initialValue={'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png'}
>
<Input placeholder={'https://tile.openstreetmap.org/{z}/{x}/{y}.png'} />
</Form.Item>
<Form.Item shouldUpdate>
{(form) => {
//const prefix = React.useContext(FormItemContext).prefixName
const prefix = (form as any).prefixName
const zoom = form.getFieldValue([
...prefix,
props.field.name as string,
'optionKeys',
'initialZoom',
])
const center = form.getFieldValue([
...prefix,
props.field.name as string,
'defaultValue',
])
const tiles = form.getFieldValue([
...prefix,
props.field.name as string,
'optionKeys',
'tiles',
])
if (!tiles) {
return <Alert message={'Tiles missing!'} />
}
return (
<div>
<MapContainer
center={center}
zoom={zoom}
style={{ height: 300, width: '100%' }}
>
<TileLayer
attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
url={tiles}
/>
{center.lat && center.lng && (
<DraggableMarker
value={center}
onChange={next => {
form.setFields([
{
name: [
...prefix,
props.field.name as string,
'defaultValue',
'lng',
],
value: next.lng,
},
{
name: [
...prefix,
props.field.name as string,
'defaultValue',
'lat',
],
value: next.lat,
},
])
}}
/>
)}
</MapContainer>
</div>
)
}}
</Form.Item>
</div>
)
}

View File

View File

View File

@ -0,0 +1,36 @@
import L from 'leaflet'
import React, { FC, useMemo, useRef } from 'react'
import { Marker } from 'react-leaflet'
interface Props {
value: { lat: number, lng: number }
onChange: (value: { lat: number, lng: number }) => void
}
export const DraggableMarker: FC<Props> = (props) => {
const markerRef = useRef<L.Marker>(null)
const eventHandlers = useMemo(
() => ({
dragend() {
const marker = markerRef.current
if (marker != null) {
props.onChange(marker.getLatLng())
}
},
}),
[],
)
return (
<Marker
draggable={true}
eventHandlers={eventHandlers}
position={props.value}
ref={markerRef}
icon={L.icon({
iconUrl: require('assets/images/marker-icon-2x.png'),
iconSize: [50/2, 82/2],
iconAnchor: [50 / 4, 82/2],
})}
/>
)
}

View File

@ -1,6 +1,13 @@
{
"add": "Add Field",
"confirmDelete": "Really remove this field? Check that it is not referenced anywhere!",
"checkbox": {
"addOption": "Add Checkbox",
"default": "Default Value",
"name": "Checkbox",
"options": "Checkboxes",
"removeOption": "Remove"
},
"date": {
"default": "Default Date",
"max": "Max Date",
@ -31,6 +38,10 @@
"default": "Default Link",
"name": "URL"
},
"location": {
"name": "Map Location",
"default": "Default Location"
},
"number": {
"default": "Default Number",
"name": "Number"

View File

@ -27,6 +27,7 @@
"imagemin-optipng": "^8.0.0",
"isomorphic-fetch": "^3.0.0",
"jimp": "^0.16.1",
"leaflet": "^1.7.1",
"next": "^12.1.0",
"next-compose-plugins": "^2.2.1",
"next-optimized-images": "^2.6.2",
@ -39,6 +40,7 @@
"react-i18next": "^11.15.5",
"react-icons": "^4.3.1",
"react-id-swiper": "^4.0.0",
"react-leaflet": "^3.2.5",
"react-markdown": "^8.0.0",
"react-redux": "^7.2.6",
"redux": "^4.1.2",
@ -50,6 +52,7 @@
"swiper": "^8.0.6"
},
"devDependencies": {
"@types/leaflet": "^1.7.9",
"@types/mathjs": "^9.4.2",
"@types/node": "^16.11.17",
"@types/node-fetch": "^3.0.3",

View File

@ -682,6 +682,11 @@
"@nodelib/fs.scandir" "2.1.5"
fastq "^1.6.0"
"@react-leaflet/core@^1.1.1":
version "1.1.1"
resolved "https://registry.yarnpkg.com/@react-leaflet/core/-/core-1.1.1.tgz#827fd05bb542cf874116176d8ef48d5b12163f81"
integrity sha512-7PGLWa9MZ5x/cWy8EH2VzI4T8q5WpuHbixzCDXqixP/WyqwIrg5NDUPgYuFnB4IEIZF+6nA265mYzswFo/h1Pw==
"@sindresorhus/is@^0.7.0":
version "0.7.0"
resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.7.0.tgz#9a06f4f137ee84d7df0460c1fdb1135ffa6c50fd"
@ -714,6 +719,11 @@
dependencies:
"@types/ms" "*"
"@types/geojson@*":
version "7946.0.8"
resolved "https://registry.yarnpkg.com/@types/geojson/-/geojson-7946.0.8.tgz#30744afdb385e2945e22f3b033f897f76b1f12ca"
integrity sha512-1rkryxURpr6aWP7R786/UQOkJ3PcpQiWkAXBmdWc7ryFWqN6a4xfK7BtjXvFBKO9LjQ+MWQSWxYeZX1OApnArA==
"@types/hast@^2.0.0":
version "2.3.4"
resolved "https://registry.yarnpkg.com/@types/hast/-/hast-2.3.4.tgz#8aa5ef92c117d20d974a82bdfb6a648b08c0bafc"
@ -734,6 +744,13 @@
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d"
integrity sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==
"@types/leaflet@^1.7.9":
version "1.7.9"
resolved "https://registry.yarnpkg.com/@types/leaflet/-/leaflet-1.7.9.tgz#7993d34f14cfa88c45b3d490daba39a3a1be9a2b"
integrity sha512-H8vPgD49HKzqM41ArHGZM70g/tfhp8W+JcPxfnF+5H/Xvp+xiP+KQOUNWU8U89fqS1Jj3cpRY/+nbnaHFzwnFA==
dependencies:
"@types/geojson" "*"
"@types/mathjs@^9.4.2":
version "9.4.2"
resolved "https://registry.yarnpkg.com/@types/mathjs/-/mathjs-9.4.2.tgz#beec20340d768171fed8331b08fb321d218ec6e1"
@ -3515,6 +3532,11 @@ lazystream@^1.0.0:
dependencies:
readable-stream "^2.0.5"
leaflet@^1.7.1:
version "1.7.1"
resolved "https://registry.yarnpkg.com/leaflet/-/leaflet-1.7.1.tgz#10d684916edfe1bf41d688a3b97127c0322a2a19"
integrity sha512-/xwPEBidtg69Q3HlqPdU3DnrXQOvQU/CCHA1tcDQVzOwm91YMYaILjNp7L4Eaw5Z4sOYdbBz6koWyibppd8Zqw==
levn@^0.4.1:
version "0.4.1"
resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade"
@ -5131,6 +5153,13 @@ react-is@^17.0.0, react-is@^17.0.2:
resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0"
integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==
react-leaflet@^3.2.5:
version "3.2.5"
resolved "https://registry.yarnpkg.com/react-leaflet/-/react-leaflet-3.2.5.tgz#bec0bfab9dd8c2b030ea630f7a0687a60322ca7d"
integrity sha512-Z3KZ+4SijsRbbrt2I1a3ZDY6+V6Pm91eYTdxTN18G6IOkFRsJo1BuSPLFnyFrlF3WDjQFPEcTPkEgD1VEeAoBg==
dependencies:
"@react-leaflet/core" "^1.1.1"
react-markdown@^8.0.0:
version "8.0.0"
resolved "https://registry.yarnpkg.com/react-markdown/-/react-markdown-8.0.0.tgz#3243296a59ddb0f451d262cc2e11123674b416c2"