From 019cd7f55e1a5c9e0db4aaf609d4e111b8c8eae0 Mon Sep 17 00:00:00 2001 From: Michael Schramm Date: Tue, 1 Mar 2022 01:20:03 +0100 Subject: [PATCH] add admin for location field type --- assets/global.scss | 1 + assets/images/marker-icon-2x.png | Bin 0 -> 2464 bytes assets/images/marker-shadow.png | Bin 0 -> 618 bytes components/form/admin/types/image.type.tsx | 0 components/form/admin/types/index.ts | 45 +++--- components/form/admin/types/location.type.tsx | 142 ++++++++++++++++++ components/form/types/image.type.tsx | 0 components/form/types/map.type.tsx | 0 components/map/draggable.marker.tsx | 36 +++++ locales/en/type.json | 11 ++ package.json | 3 + yarn.lock | 29 ++++ 12 files changed, 239 insertions(+), 28 deletions(-) create mode 100644 assets/images/marker-icon-2x.png create mode 100644 assets/images/marker-shadow.png create mode 100644 components/form/admin/types/image.type.tsx create mode 100644 components/form/admin/types/location.type.tsx create mode 100644 components/form/types/image.type.tsx create mode 100644 components/form/types/map.type.tsx create mode 100644 components/map/draggable.marker.tsx diff --git a/assets/global.scss b/assets/global.scss index 46af7f5..a975db5 100644 --- a/assets/global.scss +++ b/assets/global.scss @@ -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}; diff --git a/assets/images/marker-icon-2x.png b/assets/images/marker-icon-2x.png new file mode 100644 index 0000000000000000000000000000000000000000..88f9e501888c9c6cb29ad340d9a888627dd1b6d8 GIT binary patch literal 2464 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 e-I|>x8~*?ZhF3snGbtJX0000cOl4 literal 0 HcmV?d00001 diff --git a/assets/images/marker-shadow.png b/assets/images/marker-shadow.png new file mode 100644 index 0000000000000000000000000000000000000000..9fd2979532a19a15b824ce763c76e04a8dafadfb GIT binary patch literal 618 zcmV-w0+s!VP)ke9$Lam@{1K@O ze*LXqlKQHiv=gx+V^Cbb2?z@ISBQ*3amF;9UJ3SBg(N|710TLamQmYZ&Qjn2LuO<* zCZlB4n%@pc&7NNnY1}x+NWpHlq`OJEo|`aYN9<`RBUB+79g;>dgb6YlfN#kGL?lO_ z!6~M^7sOnbsUkKk<@Ysie&`G>ruxH&Mgy&8;i=A zB9OO!xR{AyODw>DS-q5YM{0ExFEAzt zm>RdS+ssW(-8|?xr0(?$vBVB*%(xDLtq3Hf0I5yFm<_g=W2`QWAax{1rWVH=I!VrP zs(rTFX@W#t$hXNvbgX`gK&^w_YD;CQ!B@e0QbLIWaKAXQe2-kkloo;{iF#6}z!4=W zi$giRj1{ zt;2w`VSCF#WE&*ev7jpsC=6175@(~nTE2;7M-L((0bH@yG}-TB$R~WXd?tA$s3|%y zA`9$sA(>F%J3ioz<-LJl*^o1|w84l>HBR`>3l9c8$5Xr@xCiIQ7{x$fMCzOk_-M=% z+{a_Q#;42`#KfUte@$NT77uaTz?b-fBe)1s5XE$yA79fm?KqM^VgLXD07*qoM6N<$ Ef<_J(9smFU literal 0 HcmV?d00001 diff --git a/components/form/admin/types/image.type.tsx b/components/form/admin/types/image.type.tsx new file mode 100644 index 0000000..e69de29 diff --git a/components/form/admin/types/index.ts b/components/form/admin/types/index.ts index 9b36664..842c1fd 100644 --- a/components/form/admin/types/index.ts +++ b/components/form/admin/types/index.ts @@ -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 + [key: string]: ComponentType } = { - 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(() => import('./checkbox.type').then(c => c.CheckboxType )), + date: dynamic(() => import('./date.type').then(c => c.DateType )), + dropdown: dynamic(() => import('./dropdown.type').then(c => c.DropdownType )), + email: dynamic(() => import('./email.type').then(c => c.EmailType )), + hidden: dynamic(() => import('./hidden.type').then(c => c.HiddenType )), + link: dynamic(() => import('./link.type').then(c => c.LinkType )), + location: dynamic(() => import('./location.type').then(c => c.LocationType ), { ssr: false }), + number: dynamic(() => import('./number.type').then(c => c.NumberType )), + radio: dynamic(() => import('./radio.type').then(c => c.RadioType )), + rating: dynamic(() => import('./rating.type').then(c => c.RatingType )), + slider: dynamic(() => import('./slider.type').then(c => c.SliderType )), + textarea: dynamic(() => import('./textarea.type').then(c => c.TextareaType )), + textfield: dynamic(() => import('./text.type').then(c => c.TextType )), + yes_no: dynamic(() => import('./yes_no.type').then(c => c.YesNoType )), } diff --git a/components/form/admin/types/location.type.tsx b/components/form/admin/types/location.type.tsx new file mode 100644 index 0000000..1a6e215 --- /dev/null +++ b/components/form/admin/types/location.type.tsx @@ -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 = (props) => { + const { t } = useTranslation() + + return ( +
+ + + + + + + + + + + + + + + + + + + + + + {(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 + } + + return ( +
+ + + {center.lat && center.lng && ( + { + 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, + }, + ]) + }} + /> + )} + +
+ ) + }} +
+
+ ) +} diff --git a/components/form/types/image.type.tsx b/components/form/types/image.type.tsx new file mode 100644 index 0000000..e69de29 diff --git a/components/form/types/map.type.tsx b/components/form/types/map.type.tsx new file mode 100644 index 0000000..e69de29 diff --git a/components/map/draggable.marker.tsx b/components/map/draggable.marker.tsx new file mode 100644 index 0000000..3788779 --- /dev/null +++ b/components/map/draggable.marker.tsx @@ -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) => { + const markerRef = useRef(null) + const eventHandlers = useMemo( + () => ({ + dragend() { + const marker = markerRef.current + if (marker != null) { + props.onChange(marker.getLatLng()) + } + }, + }), + [], + ) + return ( + + ) +} diff --git a/locales/en/type.json b/locales/en/type.json index 006d7b5..3db45d6 100644 --- a/locales/en/type.json +++ b/locales/en/type.json @@ -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" diff --git a/package.json b/package.json index 559d63b..2085463 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/yarn.lock b/yarn.lock index 4f65765..238219f 100644 --- a/yarn.lock +++ b/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"