mirror of
https://github.com/IT4Change/ohmyform-ui.git
synced 2025-12-12 17:25:51 +00:00
add admin for location field type
This commit is contained in:
parent
2e2d1b9a21
commit
019cd7f55e
@ -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};
|
||||
|
||||
BIN
assets/images/marker-icon-2x.png
Normal file
BIN
assets/images/marker-icon-2x.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.4 KiB |
BIN
assets/images/marker-shadow.png
Normal file
BIN
assets/images/marker-shadow.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 618 B |
0
components/form/admin/types/image.type.tsx
Normal file
0
components/form/admin/types/image.type.tsx
Normal 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 )),
|
||||
}
|
||||
|
||||
142
components/form/admin/types/location.type.tsx
Normal file
142
components/form/admin/types/location.type.tsx
Normal 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='© <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>
|
||||
)
|
||||
}
|
||||
0
components/form/types/image.type.tsx
Normal file
0
components/form/types/image.type.tsx
Normal file
0
components/form/types/map.type.tsx
Normal file
0
components/form/types/map.type.tsx
Normal file
36
components/map/draggable.marker.tsx
Normal file
36
components/map/draggable.marker.tsx
Normal 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],
|
||||
})}
|
||||
/>
|
||||
)
|
||||
}
|
||||
@ -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"
|
||||
|
||||
@ -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",
|
||||
|
||||
29
yarn.lock
29
yarn.lock
@ -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"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user