diff --git a/features/About/AboutProjectModal.tsx b/features/About/AboutProjectModal.tsx index ee3364f7..2da53d60 100644 --- a/features/About/AboutProjectModal.tsx +++ b/features/About/AboutProjectModal.tsx @@ -1,8 +1,8 @@ import React, { useEffect } from 'react'; -import { SheetModal } from 'sloy-ui'; -import { useIsDesktop } from 'sloy-map/helpers/isDesktop'; +import { IconType, SheetModal } from 'sloy-ui'; +import { Icon } from 'sloy-ui'; import { AboutProjectContent } from 'features/About/AboutProjectContent'; -import { Close } from 'sloy-map/components/Close'; +import { useIsDesktop } from 'helpers/isDesktop'; import styles from './AboutProjectModal.module.css'; export function AboutProjectModal({ close, isOpened }: { close: VoidFunction; isOpened: boolean }) { @@ -33,7 +33,9 @@ export function AboutProjectModal({ close, isOpened }: { close: VoidFunction; is return ( <>
- +
+ +
diff --git a/features/About/MobileAboutProject.tsx b/features/About/MobileAboutProject.tsx deleted file mode 100644 index e36f25b4..00000000 --- a/features/About/MobileAboutProject.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import { useContext } from 'react'; -import { SheetModal } from 'sloy-ui'; -import { AboutProjectContent } from 'features/About/AboutProjectContent'; -import { AboutProjectContext } from 'features/About/AboutProjectProvider'; - -export function MobileAboutProject() { - const { isOpened, close } = useContext(AboutProjectContext); - - return ( - - - - ); -} diff --git a/features/App.tsx b/features/App.tsx index ed547e69..66d5c5d4 100644 --- a/features/App.tsx +++ b/features/App.tsx @@ -2,12 +2,10 @@ import React, { useCallback, useEffect } from 'react'; import { Provider, useDispatch } from 'react-redux'; +import { SloyMap, setConfig, ILayer, OverrideLayersFn } from 'sloy-map'; import { store } from 'state/redux'; import { AboutProjectIcons } from 'features/About/AboutProjectIcons/AboutProjectIcons'; import { Footer } from 'features/Footer/Footer'; -import { SloyMap } from 'sloy-map/SloyMap'; -import { setConfig } from 'sloy-map/state/slice'; -import { ILayer, OverrideLayersFn } from 'sloy-map/types'; import { state } from 'state/config'; import facades from 'public/ekb-facades.json'; import { CENTER_COORDS, MAX_ZOOM, MIN_ZOOM } from 'constants/map'; @@ -15,6 +13,7 @@ import { overrideCard } from './CustomCardContent/overrideCard'; import { QuarterFilter } from './CustomFilterContent/QuarterFilter'; import { FacadeFilter } from './CustomFilterContent/FacadeFilter'; import { getHouseMeta } from './Buildings/houseBase'; +import 'sloy-map/style.css'; function AppMap() { const dispatch = useDispatch(); diff --git a/features/CustomCardContent/Participants/Participant/Participant.tsx b/features/CustomCardContent/Participants/Participant/Participant.tsx index 7e440122..796c4e84 100644 --- a/features/CustomCardContent/Participants/Participant/Participant.tsx +++ b/features/CustomCardContent/Participants/Participant/Participant.tsx @@ -1,7 +1,7 @@ import React, { useMemo } from 'react'; import { Tag } from 'sloy-ui'; +import { getYearNameByValue } from 'sloy-map'; import { Info } from 'features/CustomCardContent/Info/Info'; -import { getYearNameByValue } from 'sloy-map/helpers/getYearNameByValue'; import { DTPParticipant, HealthStatusType } from '../Participants.types'; import styles from './Participant.module.css'; diff --git a/features/CustomCardContent/overrideCard.tsx b/features/CustomCardContent/overrideCard.tsx index ee84807f..908db094 100644 --- a/features/CustomCardContent/overrideCard.tsx +++ b/features/CustomCardContent/overrideCard.tsx @@ -1,7 +1,7 @@ import { Tag } from 'sloy-ui'; +import { OverrideCardFn } from 'sloy-map'; import HealthProgress from 'features/CustomCardContent/HealthProgress/HealthProgress'; import { DownloadButton } from 'features/CustomCardContent/DownloadButton/DownloadButton'; -import { OverrideCardFn } from 'sloy-map/types'; import { FeedbackButton } from 'features/CustomCardContent/FeedbackButton/FeedbackButton'; import facades from 'public/ekb-facades.json'; import styles from 'features/CustomCardContent/CardContent.module.css'; diff --git a/helpers/isDesktop.tsx b/helpers/isDesktop.tsx new file mode 100644 index 00000000..db6db9ee --- /dev/null +++ b/helpers/isDesktop.tsx @@ -0,0 +1,5 @@ +import { useMediaQuery } from '@uidotdev/usehooks'; + +export const useIsDesktop = () => { + return useMediaQuery('only screen and (min-width : 1024px)'); +}; diff --git a/package.json b/package.json index 8c09dcd0..45f547ca 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ }, "dependencies": { "@reduxjs/toolkit": "^2.0.1", + "@uidotdev/usehooks": "^2.4.1", "classnames": "^2.4.0", "ekb": "1.2.0-rc.2", "geojson": "^0.5.0", @@ -28,7 +29,8 @@ "react-map-gl": "7.1.3", "react-redux": "^9.0.4", "redux": "^5.0.1", - "sloy-ui": "0.0.1-rc.1", + "sloy-map": "0.0.1-rc.1", + "sloy-ui": "0.0.1-rc.2", "styled-components": "^6.1.6", "swr": "^2.2.4", "typescript": "^5.3.3" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4a0c0f89..0184c298 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,6 +8,9 @@ dependencies: '@reduxjs/toolkit': specifier: ^2.0.1 version: 2.0.1(react-redux@9.0.4)(react@18.2.0) + '@uidotdev/usehooks': + specifier: ^2.4.1 + version: 2.4.1(react-dom@18.2.0)(react@18.2.0) classnames: specifier: ^2.4.0 version: 2.4.0 @@ -47,9 +50,12 @@ dependencies: redux: specifier: ^5.0.1 version: 5.0.1 - sloy-ui: + sloy-map: specifier: 0.0.1-rc.1 version: 0.0.1-rc.1(@types/react@18.2.45)(react-dom@18.2.0)(react@18.2.0)(styled-components@6.1.6) + sloy-ui: + specifier: 0.0.1-rc.2 + version: 0.0.1-rc.2(@types/react@18.2.45)(react-dom@18.2.0)(react@18.2.0)(styled-components@6.1.6) styled-components: specifier: ^6.1.6 version: 6.1.6(react-dom@18.2.0)(react@18.2.0) @@ -2313,6 +2319,17 @@ packages: eslint-visitor-keys: 3.4.3 dev: true + /@uidotdev/usehooks@2.4.1(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-1I+RwWyS+kdv3Mv0Vmc+p0dPYH0DTRAo04HLyXReYBL9AeseDWUJyi4THuksBJcu9F0Pih69Ak150VDnqbVnXg==} + engines: {node: '>=16'} + peerDependencies: + react: '>=18.0.0' + react-dom: '>=18.0.0' + dependencies: + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + /@ungap/structured-clone@1.2.0: resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} dev: true @@ -2807,6 +2824,13 @@ packages: esutils: 2.0.3 dev: true + /dot-prop@8.0.2: + resolution: {integrity: sha512-xaBe6ZT4DHPkg0k4Ytbvn5xoxgpG0jOS1dYxSOwAHPuNLjP3/OzN0gH55SrLqpx8cBfSaVt91lXYkApjb+nYdQ==} + engines: {node: '>=16'} + dependencies: + type-fest: 3.13.1 + dev: false + /earcut@2.2.4: resolution: {integrity: sha512-/pjZsA1b4RPHbeWZQn66SWS8nZZWLQQ23oE3Eam7aroEFGEvwKAsJfZ9ytiEMycfzXWpca4FA9QIOehf7PocBQ==} dev: false @@ -4786,6 +4810,13 @@ packages: hasBin: true dev: true + /proj4@2.10.0: + resolution: {integrity: sha512-0eyB8h1PDoWxucnq88/EZqt7UZlvjhcfbXCcINpE7hqRN0iRPWE/4mXINGulNa/FAvK+Ie7F+l2OxH/0uKV36A==} + dependencies: + mgrs: 1.0.0 + wkt-parser: 1.3.3 + dev: false + /proj4@2.9.2: resolution: {integrity: sha512-bdyfNmtlWjQN/rHEHEiqFvpTUHhuzDaeQ6Uu1G4sPGqk+Xkxae6ahh865fClJokSGPBmlDOQWWaO6465TCfv5Q==} dependencies: @@ -5235,6 +5266,37 @@ packages: is-fullwidth-code-point: 5.0.0 dev: true + /sloy-map@0.0.1-rc.1(@types/react@18.2.45)(react-dom@18.2.0)(react@18.2.0)(styled-components@6.1.6): + resolution: {integrity: sha512-NgqKq7ohRSx7BlzntaZthGT78yOswM9q0DFDrTqBNktKVm7e1HDAeyMC5jhOqdnN5w4o9wdSMPIZueJHgg8JEA==} + peerDependencies: + react: ^18.2.0 + react-dom: ^18.2.0 + styled-components: ^6.1.6 + dependencies: + '@reduxjs/toolkit': 2.0.1(react-redux@9.0.4)(react@18.2.0) + '@types/geojson': 7946.0.13 + '@uidotdev/usehooks': 2.4.1(react-dom@18.2.0)(react@18.2.0) + classnames: 2.4.0 + dot-prop: 8.0.2 + geojson: 0.5.0 + lodash: 4.17.21 + mapbox-gl: /empty-npm-package@1.0.0 + maplibre-gl: 3.6.2 + polished: 4.2.2 + proj4: 2.10.0 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + react-map-gl: 7.1.3(empty-npm-package@1.0.0)(maplibre-gl@3.6.2)(react-dom@18.2.0)(react@18.2.0) + react-redux: 9.0.4(@types/react@18.2.45)(react@18.2.0)(redux@5.0.1) + redux: 5.0.1 + sloy-ui: 0.0.1-rc.1(@types/react@18.2.45)(react-dom@18.2.0)(react@18.2.0)(styled-components@6.1.6) + styled-components: 6.1.6(react-dom@18.2.0)(react@18.2.0) + typescript: 5.3.3 + transitivePeerDependencies: + - '@types/react' + - react-native + dev: false + /sloy-ui@0.0.1-rc.1(@types/react@18.2.45)(react-dom@18.2.0)(react@18.2.0)(styled-components@6.1.6): resolution: {integrity: sha512-lj0o+e2vneVYZHAro8ab+zB1e1w40RqxWSGp4PYhMzlLVOhdH00SWqslLsMEmHr5iP9rccWC7BhJ4bWVPzDOyw==} peerDependencies: @@ -5257,6 +5319,28 @@ packages: - '@types/react' dev: false + /sloy-ui@0.0.1-rc.2(@types/react@18.2.45)(react-dom@18.2.0)(react@18.2.0)(styled-components@6.1.6): + resolution: {integrity: sha512-2vugODmkIDh3AxXw//UP3AFz9PEqiFkBAUheIkwE1mOxbKzqJ8awy5hcnhdb5AeiRlh6yFCZ5nV9NZbkvkRseQ==} + peerDependencies: + react: ^18.2.0 + react-dom: ^18.2.0 + styled-components: ^6.1.6 + dependencies: + classnames: 2.4.0 + framer-motion: 10.16.16(react-dom@18.2.0)(react@18.2.0) + polished: 4.2.2 + react: 18.2.0 + react-aria: 3.31.0(react-dom@18.2.0)(react@18.2.0) + react-dom: 18.2.0(react@18.2.0) + react-focus-lock: 2.9.6(@types/react@18.2.45)(react@18.2.0) + react-hotkeys-hook: 4.4.1(react-dom@18.2.0)(react@18.2.0) + react-modal-sheet: 2.2.0(framer-motion@10.16.16)(react@18.2.0) + react-stately: 3.29.0(react@18.2.0) + styled-components: 6.1.6(react-dom@18.2.0)(react@18.2.0) + transitivePeerDependencies: + - '@types/react' + dev: false + /sort-asc@0.2.0: resolution: {integrity: sha512-umMGhjPeHAI6YjABoSTrFp2zaBtXBej1a0yKkuMUyjjqu6FJsTF+JYwCswWDg+zJfk/5npWUUbd33HH/WLzpaA==} engines: {node: '>=0.10.0'} @@ -5523,7 +5607,6 @@ packages: /type-fest@3.13.1: resolution: {integrity: sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==} engines: {node: '>=14.16'} - dev: true /typed-array-buffer@1.0.0: resolution: {integrity: sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==} diff --git a/sloy-map/SloyMap.tsx b/sloy-map/SloyMap.tsx deleted file mode 100644 index 9f02d388..00000000 --- a/sloy-map/SloyMap.tsx +++ /dev/null @@ -1,91 +0,0 @@ -import { ReactNode, useEffect } from 'react'; -import { useDispatch, useSelector } from 'react-redux'; -import maplibregl from 'maplibre-gl'; -import MapGl, { MapProvider } from 'react-map-gl'; -import 'maplibre-gl/dist/maplibre-gl.css'; -import { activeLayerSelector, isAppLoadedSelector, layersSelector } from 'sloy-map/state/selectors'; -import { MapContextProvider } from './state/MapProvider'; -import { VisualisationLayer } from './visualLayers/VisualisationLayer'; -import { Copyright } from './components/Copyright/Copyright'; -import { Sidebars } from './components/Sidebars'; -import { OverrideCardFn, OverrideLayersFn } from './types/uiTypes'; -import { setAppLoaded } from './state/slice'; - -function MapLayers() { - const layers = useSelector(layersSelector); - const activeLayer = useSelector(activeLayerSelector); - - return ( - <> - {layers[activeLayer]?.visualisationLayers.map((vId) => ( - - ))} - - ); -} -interface SloyMapProps { - mapStyle: string; - minZoom?: number; - maxZoom?: number; - locale?: string; - initialViewState: { - latitude: number; - longitude: number; - zoom: number; - pitch: number; - }; - overrideCard?: OverrideCardFn; - overrideLayers?: OverrideLayersFn; - children?: ReactNode; -} - -export function SloyMap({ - locale, - minZoom = 11, - maxZoom = 20, - initialViewState, - children, - overrideCard, - overrideLayers, - ...mapProps -}: SloyMapProps) { - const dispatch = useDispatch(); - const isAppLoaded = useSelector(isAppLoadedSelector); - - return ( - - - {isAppLoaded && } - - dispatch(setAppLoaded())} - // Disable RTL plugin - RTLTextPlugin={null} - style={{ width: '100vw', height: '100vh', color: 'black' }} - {...mapProps} - > - {isAppLoaded && } - {children} - - - - ); -} diff --git a/sloy-map/components/Close/Close.module.css b/sloy-map/components/Close/Close.module.css deleted file mode 100644 index e7ff633e..00000000 --- a/sloy-map/components/Close/Close.module.css +++ /dev/null @@ -1,37 +0,0 @@ -.close { - position: absolute; - top: 8px; - right: 0; - z-index: 1; - float: right; - width: 32px; - height: 32px; - margin: 0; - padding: 0; - border: none; - border-radius: 50%; - background: none; - color: #fff; - line-height: 1; - cursor: pointer; - transition: 0.15s ease; - appearance: none; -} - -@media (hover) { - .close:hover { - background-color: #111725; - } -} - -.close:active { - background-color: #06080d; -} - -@media screen and (width >= 1200px) { - .close { - top: 2px; - width: 48px; - height: 48px; - } -} diff --git a/sloy-map/components/Close/Close.tsx b/sloy-map/components/Close/Close.tsx deleted file mode 100644 index 501a01e6..00000000 --- a/sloy-map/components/Close/Close.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import React from 'react'; -import styles from './Close.module.css'; - -interface Props { - close: VoidFunction; -} - -export function Close({ close }: Props) { - return ( - - ); -} diff --git a/sloy-map/components/Close/index.ts b/sloy-map/components/Close/index.ts deleted file mode 100644 index f447f8ee..00000000 --- a/sloy-map/components/Close/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { Close } from './Close'; diff --git a/sloy-map/components/Copyright/Copyright.module.css b/sloy-map/components/Copyright/Copyright.module.css deleted file mode 100644 index cf7cd61a..00000000 --- a/sloy-map/components/Copyright/Copyright.module.css +++ /dev/null @@ -1,38 +0,0 @@ -.copyright { - position: fixed; - top: 56px; - right: 0; - z-index: 1000; - padding: 4px 0; - border-radius: 0 4px 4px 0px; - background: black; - color: rgba(255, 255, 255, 0.5); - font-size: 10px; - line-height: 1.5; - opacity: 1; - transform: scale(-1); - writing-mode: vertical-lr; -} - -.copyright[hidden] { - display: block; - opacity: 0; - visibility: hidden; -} - -.copyright a:not(:first-child):before { - content: ' · '; -} - -@media screen and (width >= 1150px) { - .copyright { - top: auto; - left: 50%; - bottom: 0; - right: auto; - border-radius: 2px 2px 0 0; - padding: 0 4px; - transform: translateX(-50%); - writing-mode: lr; - } -} diff --git a/sloy-map/components/Copyright/Copyright.tsx b/sloy-map/components/Copyright/Copyright.tsx deleted file mode 100644 index e61df661..00000000 --- a/sloy-map/components/Copyright/Copyright.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import { useSelector } from 'react-redux'; -import { isAppLoadedSelector } from 'sloy-map/state/selectors'; -import styles from './Copyright.module.css'; - -export function Copyright() { - const isAppLoaded = useSelector(isAppLoadedSelector); - - return ( - - ); -} diff --git a/sloy-map/components/DesktopCard/DesktopCard.module.css b/sloy-map/components/DesktopCard/DesktopCard.module.css deleted file mode 100644 index 54723f98..00000000 --- a/sloy-map/components/DesktopCard/DesktopCard.module.css +++ /dev/null @@ -1,16 +0,0 @@ -.DesktopCard { - position: relative; - background: #1e2841 !important; - border-radius: 10px !important; - max-height: calc(90vh - 2vw) !important; - overflow-y: auto; - overflow-x: hidden; - - @mixin scroll; -} - -.DesktopCard__header { - position: absolute; - right: 0; - top: 0; -} diff --git a/sloy-map/components/DesktopCard/index.tsx b/sloy-map/components/DesktopCard/index.tsx deleted file mode 100644 index b215557e..00000000 --- a/sloy-map/components/DesktopCard/index.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import React, { ReactNode } from 'react'; -import { Close } from 'sloy-map/components/Close'; -import styles from './DesktopCard.module.css'; - -interface Props { - children: ReactNode; - closePopup: () => void; -} - -export function DesktopCard({ children, closePopup }: Props) { - return ( -
-
- -
- {children} -
- ); -} diff --git a/sloy-map/components/Layers.tsx b/sloy-map/components/Layers.tsx deleted file mode 100644 index f69c5eef..00000000 --- a/sloy-map/components/Layers.tsx +++ /dev/null @@ -1,70 +0,0 @@ -import React, { useContext } from 'react'; -import styled from 'styled-components'; -import { useSelector } from 'react-redux'; -import { Accordion, AccordionItem, Divider } from 'sloy-ui'; -import { MapFilter } from 'sloy-map/filters/MapFilter'; -import { ILayer } from 'sloy-map/types/types'; -import { filtersSelector, layersSelector } from 'sloy-map/state/selectors'; -import { MapContext } from 'sloy-map/state/MapProvider'; - -interface Props { - activeLayer: string; - onToggleClick: (type: string) => void; -} - -const FilterTitle = styled.div` - font-size: 18px; - line-height: 24px; - margin: 12px 0; - font-weight: bold; -`; - -export function Layers({ activeLayer, onToggleClick }: Props) { - const { overrideLayers } = useContext(MapContext); - const filters = useSelector(filtersSelector); - const layers = useSelector(layersSelector); - - return ( - - {Object.values(layers).map((layer: ILayer) => { - const isActive = layer.id === activeLayer; - const toggle = () => onToggleClick(layer.id); - - return ( - - {isActive ? ( - <> - {overrideLayers?.(layer)} - {layer.filters.map((filterId, i) => { - const filter = filters[filterId]; - return ( -
- {filter.type !== 'boolean' && filter.title && ( - - {filter.title} - - )} - - {layer.filters.length - 1 !== i && } -
- ); - })} - - ) : null} -
- ); - })} -
- ); -} diff --git a/sloy-map/components/LeftSidebar.tsx b/sloy-map/components/LeftSidebar.tsx deleted file mode 100644 index 0ed0f9b9..00000000 --- a/sloy-map/components/LeftSidebar.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import styled from 'styled-components'; - -export const LeftSidebar = styled.div` - width: 29%; - min-width: 340px; - max-width: 435px; - position: fixed; - top: 8px; - left: 8px; - z-index: 401; - display: flex; - flex-direction: column; - gap: 8px; - max-height: calc(100vh - 120px); -`; diff --git a/sloy-map/components/MapLoader.tsx b/sloy-map/components/MapLoader.tsx deleted file mode 100644 index eda72ab4..00000000 --- a/sloy-map/components/MapLoader.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import React from 'react'; -import styled from 'styled-components'; -import { AnimatedLogo } from 'sloy-ui'; - -const FilterLoaderContainer = styled.div` - position: relative; - height: 128px; -`; - -export function MapLoader() { - return ( - - - - ); -} diff --git a/sloy-map/components/RightSidebar.tsx b/sloy-map/components/RightSidebar.tsx deleted file mode 100644 index 82e559bf..00000000 --- a/sloy-map/components/RightSidebar.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import styled from 'styled-components'; - -export const RightSidebar = styled.div` - width: 50%; - max-width: 400px; - position: fixed; - top: 8px; - right: 8px; - z-index: 401; - display: flex; - flex-direction: column; - gap: 8px; - max-height: calc(100vh - 120px); -`; diff --git a/sloy-map/components/Sidebars.tsx b/sloy-map/components/Sidebars.tsx deleted file mode 100644 index 4350935d..00000000 --- a/sloy-map/components/Sidebars.tsx +++ /dev/null @@ -1,69 +0,0 @@ -import { useCallback, useContext } from 'react'; -import { useDispatch, useSelector } from 'react-redux'; -import { SheetModal } from 'sloy-ui'; -import { toggleData } from 'sloy-map/state/slice'; -import { activeLayerSelector } from 'sloy-map/state/selectors'; -import { useIsDesktop } from 'sloy-map/helpers/isDesktop'; -import { RenderCard } from 'sloy-map/sources/Card'; -import { DesktopCard } from 'sloy-map/components/DesktopCard'; -import { LeftSidebar } from 'sloy-map/components/LeftSidebar'; -import { RightSidebar } from 'sloy-map/components/RightSidebar'; -import { MapContext } from 'sloy-map/state/MapProvider'; -import { Layers } from 'sloy-map/components/Layers'; - -function SidebarCard() { - const isDesktop = useIsDesktop(); - const popupProps = useContext(MapContext); - const card = ; - - if (isDesktop) { - return ( - - {card} - - ); - } - - return ( - - {card} - - ); -} - -function SidebarFilter() { - const isDesktop = useIsDesktop(); - const dispatch = useDispatch(); - const activeLayer = useSelector(activeLayerSelector); - const onToggleClick = useCallback( - (type: string) => { - dispatch(toggleData({ type })); - }, - [dispatch], - ); - - const filter = ; - - if (isDesktop) { - return {filter}; - } - - return ( - - {filter} - - ); -} - -export function Sidebars() { - return ( - <> - - - - ); -} diff --git a/sloy-map/constants.ts b/sloy-map/constants.ts deleted file mode 100644 index 787e8f89..00000000 --- a/sloy-map/constants.ts +++ /dev/null @@ -1,2 +0,0 @@ -export const BUILDING_LAYER_ID = 'building'; -export const DEFAULT_BULDING_COLOR_NORMAL = '#0c1021'; diff --git a/sloy-map/filters/FilterBuildingRange.tsx b/sloy-map/filters/FilterBuildingRange.tsx deleted file mode 100644 index 37995e99..00000000 --- a/sloy-map/filters/FilterBuildingRange.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import React, { useCallback } from 'react'; -import { HistogramDatum, MinMax } from 'sloy-ui'; -import { useSelector } from 'react-redux'; -import { RangeBaseFilter } from 'sloy-map/filters/RangeBaseFilter'; -import { IFilter } from 'sloy-map/types/types'; -import { sourcesSelector } from 'sloy-map/state/selectors'; - -interface Props { - filter: IFilter; - onChange: (range: MinMax) => void; -} - -export function FilterRange({ filter, onChange }: Props) { - const sources = useSelector(sourcesSelector); - const rangeData = sources?.[filter.source]?.properties?.[filter?.property] - ?.values as HistogramDatum[]; - - const getHistogramData = useCallback(async () => { - if (!rangeData) return; - - return rangeData; - }, [rangeData]); - - const defaultMin = Math.min.apply(null, rangeData?.map((item) => item.from)); - const defaultMax = Math.max.apply(null, rangeData?.map((item) => item.to)); - - if (typeof defaultMin !== 'number' || typeof defaultMax !== 'number' || !rangeData) { - return null; - } - - return ( - - ); -} diff --git a/sloy-map/filters/FilterGrid.tsx b/sloy-map/filters/FilterGrid.tsx deleted file mode 100644 index 7d9f5cf8..00000000 --- a/sloy-map/filters/FilterGrid.tsx +++ /dev/null @@ -1,53 +0,0 @@ -import React, { ComponentProps, useCallback, useEffect, useState } from 'react'; -import { Checkbox, ListGrid, ListGridItem } from 'sloy-ui'; - -export type IFilterGridItem = Partial> & { - type: string; - color?: string; -}; - -interface Props { - selectedByDefault?: string[]; - items?: IFilterGridItem[]; - onChange?: (state: string[]) => void; -} - -export function FilterGrid({ items, onChange, selectedByDefault = [] }: Props) { - const [selected, setSelected] = useState(selectedByDefault); - - const toggle = useCallback( - (type: string) => { - if (selected.includes(type)) { - setSelected(selected.filter((s) => s !== type)); - } else { - setSelected(selected.concat(type)); - } - }, - [selected], - ); - - useEffect(() => { - onChange?.(selected); - }, [onChange, selected]); - - return ( - - {items.map(({ type, subTitle, description, color }) => ( - toggle(type)} - /> - } - > - {type} - - ))} - - ); -} diff --git a/sloy-map/filters/FilterLoader.tsx b/sloy-map/filters/FilterLoader.tsx deleted file mode 100644 index c603edb6..00000000 --- a/sloy-map/filters/FilterLoader.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import React from 'react'; -import styled from 'styled-components'; -import { AnimatedLogo } from 'sloy-ui'; - -const FilterLoaderContainer = styled.div` - position: relative; - height: 128px; -`; - -export function FilterLoader() { - return ( - - - - ); -} diff --git a/sloy-map/filters/MapFilter.tsx b/sloy-map/filters/MapFilter.tsx deleted file mode 100644 index fd759778..00000000 --- a/sloy-map/filters/MapFilter.tsx +++ /dev/null @@ -1,88 +0,0 @@ -import React, { useCallback } from 'react'; -import { useDispatch, useSelector } from 'react-redux'; -import { filtersSelector, sourcesSelector } from 'sloy-map/state/selectors'; -import { groupByProperty } from 'sloy-map/helpers/groupByProperty'; -import { FilterRange } from 'sloy-map/filters/FilterBuildingRange'; -import { useLoadGeoJSON } from 'sloy-map/helpers/useLoadGeoJSON'; -import { FilterGrid } from 'sloy-map/filters/FilterGrid'; -import { updateFilterParams } from 'sloy-map/state/slice'; -import { MapLoader } from 'sloy-map/components/MapLoader'; - -export function MapFilter({ layerId, filterId }: { layerId: string; filterId: string }) { - const dispatch = useDispatch(); - const filters = useSelector(filtersSelector); - const sources = useSelector(sourcesSelector); - - const filter = filters[filterId]; - const source = sources[filter?.source]; - const { data, loading } = useLoadGeoJSON(source); - - const onChange = useCallback( - (params) => { - dispatch( - updateFilterParams({ - activeLayer: layerId, - activeFilterParams: { - [filterId]: params, - }, - }), - ); - }, - [dispatch, filterId, layerId], - ); - - if (!filter || !source) { - return null; - } - - if (loading || !data) { - return ; - } - - switch (filter.type) { - case 'range': - return ; - case 'string[]': - case 'string': { - const items = groupByProperty( - data, - filter.property, - source.properties[filter.property]?.type, - ).map((item) => ({ - type: item.type, - subTitle: item.count, - color: source.properties[filter.property]?.values?.[item.type]?.color, - description: source.properties[filter.property]?.values?.[item.type]?.description, - })); - - const selectedByDefault = items.map((item) => item.type); - - return ( - - ); - } - - case 'boolean': { - return ( - - ); - } - - default: - return null; - } -} diff --git a/sloy-map/filters/RangeBaseFilter.tsx b/sloy-map/filters/RangeBaseFilter.tsx deleted file mode 100644 index 2f37a20f..00000000 --- a/sloy-map/filters/RangeBaseFilter.tsx +++ /dev/null @@ -1,51 +0,0 @@ -import React, { useEffect, useState } from 'react'; -import { RangeHistogram, HistogramData, MinMax } from 'sloy-ui'; -import { FilterLoader } from 'sloy-map/filters/FilterLoader'; - -export interface RangeBaseFilterProps { - defaultMin: number; - defaultMax: number; - units?: string; - onChangeCallback: (range: MinMax) => Promise | void; - getHistogramData: () => Promise; - noLoader?: boolean; -} - -export function RangeBaseFilter({ - defaultMin, - defaultMax, - units, - onChangeCallback, - getHistogramData, - noLoader, -}: RangeBaseFilterProps) { - const [rangeData, setRangeData] = useState(null); - const [loading, setLoading] = useState(true); - - useEffect(() => { - getHistogramData().then((data: HistogramData) => { - setRangeData(data); - setLoading(false); - }); - }, [getHistogramData]); - - if (loading) { - if (noLoader) { - return null; - } - - return ; - } - - return ( - - ); -} diff --git a/sloy-map/helpers/colorLuminance.ts b/sloy-map/helpers/colorLuminance.ts deleted file mode 100644 index dfb234e4..00000000 --- a/sloy-map/helpers/colorLuminance.ts +++ /dev/null @@ -1,13 +0,0 @@ -export function colorLuminance(hexColor: string, luminance: number) { - const hex = hexColor.replace(/[^0-9a-f]/gi, ''); - let color = '#'; - - for (let i = 0; i < 3; i++) { - let component = parseInt(hex.substr(i * 2, 2), 16); - component = Math.round(Math.min(Math.max(0, component + component * luminance), 255)); - const hexComponent = component.toString(16).padStart(2, '0'); - color += hexComponent; - } - - return color; -} diff --git a/sloy-map/helpers/fetchApi.ts b/sloy-map/helpers/fetchApi.ts deleted file mode 100644 index dbcbdac6..00000000 --- a/sloy-map/helpers/fetchApi.ts +++ /dev/null @@ -1,4 +0,0 @@ -export async function fetchAPI(url: string) { - const response = await fetch(url); - return response.json(); -} diff --git a/sloy-map/helpers/getFeatureState.ts b/sloy-map/helpers/getFeatureState.ts deleted file mode 100644 index 9b871e87..00000000 --- a/sloy-map/helpers/getFeatureState.ts +++ /dev/null @@ -1,24 +0,0 @@ -import type { - DataDrivenPropertyValueSpecification, - ExpressionInputType, - ExpressionSpecification, -} from 'maplibre-gl'; - -export function getLayerStyle({ - initial, - active, - hover, -}: { - initial: T; - active?: T; - hover: T; -}): DataDrivenPropertyValueSpecification { - return [ - 'case', - ['boolean', ['feature-state', 'active'], false], - active, - ['boolean', ['feature-state', 'hover'], false], - hover, - initial, - ]; -} diff --git a/sloy-map/helpers/getLayerProps.ts b/sloy-map/helpers/getLayerProps.ts deleted file mode 100644 index c28db448..00000000 --- a/sloy-map/helpers/getLayerProps.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { ISource, IVisualisationLayer } from 'sloy-map/types/types'; - -export function getLayerProps(visualisationLayer: IVisualisationLayer, source: ISource): any { - const property = source?.properties?.[visualisationLayer.property]; - const values = Object.entries(property?.values || {}) || []; - - const props = { - id: visualisationLayer.id, - type: visualisationLayer.type, - source: visualisationLayer.source, - }; - - switch (visualisationLayer.type) { - case 'circle': { - const colors = values.map(([value, { color }]) => [ - ['==', ['get', visualisationLayer.property], value], - color, - ]); - - return { - ...props, - paint: { - // @ts-ignore - 'circle-color': ['case'].concat(...colors).concat(['rgba(0, 0, 0, 0)']), - 'circle-stroke-color': '#000', - ...visualisationLayer.paint, - }, - }; - } - case 'line': { - const colors = values.map(([value, { color }]) => [ - ['==', ['get', visualisationLayer.property], value], - color, - ]); - - return { - ...props, - paint: { - // @ts-ignore - 'line-color': ['case'].concat(...colors).concat(['rgba(0, 0, 0, 0)']), - ...visualisationLayer.paint, - }, - }; - } - - case 'heatmap': - case 'fill': - return { - ...props, - // @ts-ignore - paint: visualisationLayer.paint, - }; - } - - return null; -} diff --git a/sloy-map/helpers/getStringFromStringOrArray.ts b/sloy-map/helpers/getStringFromStringOrArray.ts deleted file mode 100644 index db38b7f6..00000000 --- a/sloy-map/helpers/getStringFromStringOrArray.ts +++ /dev/null @@ -1,13 +0,0 @@ -export const getStringFromStringOrArray = ( - values: Record, - value?: string | string[], -) => { - if (!value) return undefined; - - return Array.isArray(value) - ? value - .map((t) => values[t]) - .filter(Boolean) - .join('. ') - : values[value]; -}; diff --git a/sloy-map/helpers/getYearNameByValue.ts b/sloy-map/helpers/getYearNameByValue.ts deleted file mode 100644 index f2abb40c..00000000 --- a/sloy-map/helpers/getYearNameByValue.ts +++ /dev/null @@ -1,31 +0,0 @@ -export function getYearNameByValue(year: number) { - const lastDigit = year % 10; - const lastTwoDigits = year % 100; - - switch (lastTwoDigits) { - case 11: - case 12: - case 13: - case 14: - return 'лет'; - default: - break; - } - - switch (lastDigit) { - case 1: - return 'год'; - case 2: - case 3: - case 4: - return 'года'; - default: - return 'лет'; - } -} - -export function getYearStringByValue(year: string | number) { - const age = new Date().getFullYear() - Number(String(year)?.match(/\d{4}/)?.[0]); - - return `${String(age)} ${getYearNameByValue(age)}`; -} diff --git a/sloy-map/helpers/groupByProperty.tsx b/sloy-map/helpers/groupByProperty.tsx deleted file mode 100644 index a31c3cb6..00000000 --- a/sloy-map/helpers/groupByProperty.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import { FeatureCollection } from 'geojson'; -import groupBy from 'lodash/groupBy'; - -export function groupByProperty( - geojson: FeatureCollection, - property: string = 'type', - valueType: string, -) { - let result; - - if (valueType === 'string[]') { - result = Array.from( - new Set(geojson.features.map((item) => item.properties[property]).flat(2)), - ).map((category) => [ - category, - geojson.features.filter((item) => item.properties[property]?.includes(category)), - ]); - } else { - result = Object.entries(groupBy(geojson.features, (item) => item.properties[property])); - } - - return result - .map(([type, items]) => ({ type, count: items.length })) - .sort((a, b) => b.count - a.count); -} diff --git a/sloy-map/helpers/hash.ts b/sloy-map/helpers/hash.ts deleted file mode 100644 index a9066aa4..00000000 --- a/sloy-map/helpers/hash.ts +++ /dev/null @@ -1,8 +0,0 @@ -export const getLatLngFromHash = (): string[] => - window.location.hash.split('/')[0].split('-')[1].split('_'); - -export const getFilterTypeFromHash = () => window.location.hash.split('/')[1]; - -export const setHash = (type: string, id: string, activeLayer: string): void => { - window.location.hash = `${type}-${id}/${activeLayer}`; -}; diff --git a/sloy-map/helpers/isDesktop.ts b/sloy-map/helpers/isDesktop.ts deleted file mode 100644 index 9a70c201..00000000 --- a/sloy-map/helpers/isDesktop.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { useMatchMedia } from './useMatchMedia'; - -const DESKTOP_WIDTH_MIN = 1024; - -export const useIsDesktop = () => useMatchMedia(`(min-width: ${DESKTOP_WIDTH_MIN}px)`); diff --git a/sloy-map/helpers/setBuildingStyle.ts b/sloy-map/helpers/setBuildingStyle.ts deleted file mode 100644 index d20f9054..00000000 --- a/sloy-map/helpers/setBuildingStyle.ts +++ /dev/null @@ -1,123 +0,0 @@ -import { - ColorSpecification, - DataDrivenPropertyValueSpecification, - ExpressionSpecification, -} from 'maplibre-gl'; -import { BUILDING_LAYER_ID, DEFAULT_BULDING_COLOR_NORMAL } from 'sloy-map/constants'; -import { getLayerStyle } from './getFeatureState'; -import { colorLuminance } from './colorLuminance'; - -interface SetBuildingStyleProps { - map: mapboxgl.Map; - color: DataDrivenPropertyValueSpecification; - caseCondition?: (string | string[])[]; - layerProps?: Record; -} - -export function setBuildingColor({ - map, - color, - caseCondition = ['has', '_unknown_'], - layerProps, -}: SetBuildingStyleProps) { - map?.setStyle({ - ...map?.getStyle(), - layers: map?.getStyle().layers.map((layer: any) => { - if (layer.id === BUILDING_LAYER_ID) { - return { - ...layer, - ...layerProps, - paint: { - ...layer.paint, - 'fill-extrusion-color': [ - 'case', - caseCondition, - color, - DEFAULT_BULDING_COLOR_NORMAL, - ], - ...layerProps?.paint, - }, - }; - } - return layer; - }), - }); -} - -export function setBuildingDefaultColor(map: mapboxgl.Map) { - setBuildingColor({ map, color: DEFAULT_BULDING_COLOR_NORMAL }); -} - -export function setBuildingStyleByPropertyValues({ map, property, values, color }) { - if (!values.length || !property || !map) { - return; - } - - map.setStyle({ - ...map?.getStyle(), - layers: map?.getStyle().layers.map((layer) => { - if (layer.id === BUILDING_LAYER_ID) { - return { - ...layer, - paint: { - // @ts-ignore - ...layer.paint, - 'fill-extrusion-color': [ - 'match', - ['get', property], - ['literal'].concat(values), - color, - DEFAULT_BULDING_COLOR_NORMAL, - ], - }, - }; - } - return layer; - }), - }); -} - -export function setBuildingRangeStyle({ map, range, field, rangeData }) { - if ( - !( - typeof range?.min === 'number' && - typeof range?.max === 'number' && - field && - rangeData && - map?.setStyle && - map?.getStyle - ) - ) { - setBuildingDefaultColor(map); - return; - } - - const colorsInitial = rangeData - .map((item) => { - if (item.from >= range.min && item.to <= range.max) { - return item; - } - return { ...item, color: DEFAULT_BULDING_COLOR_NORMAL }; - }) - .map((item) => [item.from, item.color]); - - const colorsHover = colorsInitial.map(([from, color]) => [from, colorLuminance(color, 0.4)]); - const colorsActive = colorsInitial.map(([from, color]) => [from, colorLuminance(color, 0.55)]); - - const getColor = (style: [number, number][]): ExpressionSpecification => [ - 'interpolate', - ['linear'], - ['to-number', ['get', field]], - ...style.flat(2), - ]; - - setBuildingColor({ - map, - color: getLayerStyle({ - initial: getColor(colorsInitial), - hover: getColor(colorsHover), - active: getColor(colorsActive), - }), - caseCondition: ['has', field], - }); -} diff --git a/sloy-map/helpers/useClickableBuilding.tsx b/sloy-map/helpers/useClickableBuilding.tsx deleted file mode 100644 index 9781ae01..00000000 --- a/sloy-map/helpers/useClickableBuilding.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import { useEffect } from 'react'; -import { useMap } from 'react-map-gl'; -import useMapObjectState from 'sloy-map/helpers/useMapObjectState'; -import { usePopup } from 'sloy-map/state/usePopup'; -import { BUILDING_LAYER_ID } from 'sloy-map/constants'; - -interface Props { - sourceId: string; -} - -export function useClickableBuilding({ sourceId }: Props) { - const sloyMapGl = useMap(); - const { openPopup } = usePopup(); - - useMapObjectState(BUILDING_LAYER_ID); - - useEffect(() => { - const map = sloyMapGl?.current?.getMap?.(); - - if (!map) return; - - map.on('click', BUILDING_LAYER_ID, (e) => { - openPopup(`${e.lngLat.lat}_${e.lngLat.lng}`, sourceId); - }); - }, [sloyMapGl, openPopup, sourceId]); - - return null; -} - -export function ClickableBuilding(props: Props) { - useClickableBuilding(props); - - return null; -} diff --git a/sloy-map/helpers/useCopyHref.ts b/sloy-map/helpers/useCopyHref.ts deleted file mode 100644 index f302eb69..00000000 --- a/sloy-map/helpers/useCopyHref.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { useEffect, useState } from 'react'; - -export function copy(text: string) { - const dummy = document.createElement('input'); - document.body.appendChild(dummy); - dummy.value = text; - dummy.select(); - document.execCommand('copy'); - document.body.removeChild(dummy); -} - -export function useCopyHref(memo: string, resetTimeout?: number) { - const [isCopied, setCopied] = useState(false); - - // reset on chamge "memo" - useEffect(() => setCopied(false), [memo]); - - return { - isCopied, - onCopy: () => { - copy(memo); - setCopied(true); - - if (!resetTimeout) { - return; - } - - setTimeout(() => { - setCopied(false); - }, resetTimeout); - }, - }; -} diff --git a/sloy-map/helpers/useLoadGeoJSON.ts b/sloy-map/helpers/useLoadGeoJSON.ts deleted file mode 100644 index 20657323..00000000 --- a/sloy-map/helpers/useLoadGeoJSON.ts +++ /dev/null @@ -1,90 +0,0 @@ -import { useEffect, useState } from 'react'; -import GeoJSON, { FeatureCollection } from 'geojson'; -import proj4 from 'proj4'; -import { fetchAPI } from 'sloy-map/helpers/fetchApi'; -import { ISource } from 'sloy-map/types/types'; - -export function useLoadGeoJSON(source: ISource): { - loading: boolean; - data: FeatureCollection; -} { - // TODO: useSWR for cache - const path = source?.path; - const [data, setData] = useState(null); - const [loading, setLoading] = useState(false); - - useEffect(() => { - if (path) { - setLoading(true); - fetchAPI(path).then((data) => { - setLoading(false); - - let fetchedData: FeatureCollection = data; - - try { - if (source.type === 'json') { - // @ts-expect-error - fetchedData = GeoJSON.parse(data, { - Point: [source?.latProperty || 'lat', source.lngProperty || 'lng'], - }); - } - - if (source.projection) { - fetchedData.features = fetchedData.features.map((feature) => { - if (feature.geometry.coordinates) { - return { - ...feature, - geometry: { - ...feature.geometry, - coordinates: proj4( - source.projection, - 'EPSG:4326', - feature.geometry.coordinates, - ), - }, - }; - } - return feature; - }); - } - - fetchedData.features = fetchedData.features.map((feature, i) => { - return { - ...feature, - properties: { - ...feature.properties, - id: feature.properties.id || feature.id || i, - }, - }; - }); - } catch (e) { - console.log('Error with parsing', source.path, e); - } - - setData(fetchedData); - }); - } - }, [ - path, - source?.latProperty, - source.lngProperty, - source.path, - source.projection, - source.type, - ]); - - if (!path) { - return { - loading: false, - data: { - type: 'FeatureCollection', - features: [], - }, - }; - } - - return { - loading, - data, - }; -} diff --git a/sloy-map/helpers/useMapObjectState.ts b/sloy-map/helpers/useMapObjectState.ts deleted file mode 100644 index 6d2177d0..00000000 --- a/sloy-map/helpers/useMapObjectState.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { FeatureIdentifier } from 'maplibre-gl'; -import { MapRef, useMap } from 'react-map-gl'; -import { useEffect, useRef } from 'react'; - -function setObjectState( - map: MapRef, - mapObject: FeatureIdentifier, - settings: { [key: string]: boolean }, - cursorPointer = true, -) { - map.getCanvas().style.cursor = cursorPointer ? 'pointer' : 'default'; - map.setFeatureState(mapObject, settings); -} - -function useMapObjectState(layerId: string) { - const map = useMap().current; - const activeObject = useRef(null); - const hoverObject = useRef(null); - - const getItem = (point: mapboxgl.Point) => - map.queryRenderedFeatures(point, { layers: [layerId] })[0]; - - useEffect(() => { - const handleClick = (e: mapboxgl.MapMouseEvent) => { - const item = getItem(e.point); - if (activeObject.current && item.id !== activeObject.current.id) { - setObjectState(map, activeObject.current, { active: false }); - activeObject.current = null; - } - - if (item) { - activeObject.current = item; - setObjectState(map, activeObject.current, { active: true }); - } - }; - - const handleMouseMove = (e: mapboxgl.MapMouseEvent) => { - const item = getItem(e.point); - if (item) { - if (hoverObject.current && item.id !== hoverObject.current.id) { - setObjectState(map, hoverObject.current, { hover: false }, false); - } - hoverObject.current = item; - setObjectState(map, item, { hover: true }); - } - }; - - const handleMouseLeave = () => { - if (hoverObject?.current?.id) { - setObjectState(map, hoverObject.current, { hover: false }, false); - } - hoverObject.current = null; - }; - - map.on('click', layerId, handleClick); - map.on('mousemove', layerId, handleMouseMove); - map.on('mouseleave', layerId, handleMouseLeave); - - return () => { - map.off('click', layerId, handleClick); - map.off('mousemove', layerId, handleMouseMove); - map.off('mouseleave', layerId, handleMouseLeave); - }; - }); - - return hoverObject.current; -} - -export default useMapObjectState; diff --git a/sloy-map/helpers/useMatchMedia.ts b/sloy-map/helpers/useMatchMedia.ts deleted file mode 100644 index a01bd164..00000000 --- a/sloy-map/helpers/useMatchMedia.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { useEffect, useState, useRef } from 'react'; - -export const useMatchMedia = (matchMediaQuery): boolean => { - const [toggleChange, setToggleChange] = useState(false); - const matchMediaRef = useRef(null); - - useEffect(() => { - matchMediaRef.current = window.matchMedia(matchMediaQuery); - const initialMatch = matchMediaRef.current.matches; - - if (initialMatch) { - setToggleChange(true); - } else { - setToggleChange(false); - } - - const test = (event: MediaQueryListEvent) => { - if (event.matches) { - setToggleChange(true); - } else { - setToggleChange(false); - } - }; - - matchMediaRef.current.addListener(test); - - return () => { - matchMediaRef.current.removeListener(test); - }; - }, [matchMediaQuery]); - - return toggleChange; -}; diff --git a/sloy-map/helpers/useOpenMapItem.tsx b/sloy-map/helpers/useOpenMapItem.tsx deleted file mode 100644 index 0a74aca8..00000000 --- a/sloy-map/helpers/useOpenMapItem.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import { useEffect } from 'react'; -import { useMap } from 'react-map-gl'; -import { usePopup } from '../state/usePopup'; - -export function useOpenMapItem(layerId: string, mapItemType: string) { - const sloyMapGl = useMap(); - const { openPopup } = usePopup(); - - useEffect(() => { - const map = sloyMapGl?.current; - - if (!map) return; - - function open(e: any) { - const item = e.target.queryRenderedFeatures(e.point)[0]; - - openPopup(item.properties?.id || item.id, mapItemType); - } - - map.on?.('click', layerId, open); - - return () => { - map.off?.('click', layerId, open); - }; - }, [sloyMapGl, layerId, mapItemType, openPopup]); -} diff --git a/sloy-map/layers/ClickableLayer.tsx b/sloy-map/layers/ClickableLayer.tsx deleted file mode 100644 index 48ab64d8..00000000 --- a/sloy-map/layers/ClickableLayer.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import { Layer } from 'react-map-gl'; -import { useSelector } from 'react-redux'; -import { ActiveFilters, IVisualisationLayer } from 'sloy-map/types/types'; -import { sourcesSelector } from 'sloy-map/state/selectors'; -import { getLayerProps } from 'sloy-map/helpers/getLayerProps'; -import useMapObjectState from 'sloy-map/helpers/useMapObjectState'; -import { useOpenMapItem } from 'sloy-map/helpers/useOpenMapItem'; -import { MarkersLayer } from './MarkersLayer'; - -function ClickableLayer({ visualisationLayer }: { visualisationLayer: IVisualisationLayer }) { - useMapObjectState(visualisationLayer.id); - useOpenMapItem(visualisationLayer.id, visualisationLayer.source); - - return null; -} - -interface Props { - visualisationLayer: IVisualisationLayer; - activeFilters: ActiveFilters; -} - -export function MapLayer({ visualisationLayer, activeFilters }: Props) { - const sources = useSelector(sourcesSelector); - const source = sources[visualisationLayer.source]; - - return ( - <> - {visualisationLayer.openable && ( - - )} - {visualisationLayer.type === 'marker-image' ? ( - - ) : ( - - )} - - ); -} diff --git a/sloy-map/layers/MarkersLayer.module.css b/sloy-map/layers/MarkersLayer.module.css deleted file mode 100644 index e12a202d..00000000 --- a/sloy-map/layers/MarkersLayer.module.css +++ /dev/null @@ -1,27 +0,0 @@ -.marker { - object-fit: cover; - box-shadow: 0 0 0 3px currentColor; - border: 1px solid #000; - border-radius: 100%; - min-width: 100%; - min-height: 100%; - cursor: pointer; - transition: all 0.15s; - background-color: black; - position: relative; - transform-origin: center; -} - -.marker:hover, -.marker.marker_open { - box-shadow: 0 0 0 4px currentColor; - z-index: 9999 !important; -} - -.marker:hover { - transform: scale(1.2); -} - -.marker.marker_open { - transform: scale(1.3); -} diff --git a/sloy-map/layers/MarkersLayer.tsx b/sloy-map/layers/MarkersLayer.tsx deleted file mode 100644 index 28b49bf4..00000000 --- a/sloy-map/layers/MarkersLayer.tsx +++ /dev/null @@ -1,84 +0,0 @@ -import React, { useMemo } from 'react'; -import { Layer, Marker, CircleLayer } from 'react-map-gl'; -import { useSelector } from 'react-redux'; -import classNames from 'classnames'; -import { useLoadGeoJSON } from 'sloy-map/helpers/useLoadGeoJSON'; -import { getLayerStyle } from 'sloy-map/helpers/getFeatureState'; -import { FilterLoader } from 'sloy-map/filters/FilterLoader'; -import { ActiveFilters, IVisualisationLayer } from 'sloy-map/types/types'; -import { sourcesSelector } from 'sloy-map/state/selectors'; -import { usePopup } from '../state/usePopup'; -import styles from './MarkersLayer.module.css'; - -interface Props { - visualisationLayer: IVisualisationLayer; - activeFilters: ActiveFilters; -} - -export function MarkersLayer({ visualisationLayer, activeFilters = [] }: Props) { - const { popupHash } = usePopup(); - const sources = useSelector(sourcesSelector); - const source = sources[visualisationLayer?.source]; - - const { loading, data } = useLoadGeoJSON(source); - - const markers = useMemo(() => { - return data?.features.filter((feature) => { - return activeFilters.find( - ({ filter, values }) => values?.includes(feature.properties?.[filter?.property]), - )?.values; - }); - }, [activeFilters, data?.features]); - - if (loading) { - return ; - } - - if (!visualisationLayer?.type || !data || !source) { - return null; - } - - const fakeClickableMarkersLayerStyle: CircleLayer = { - id: visualisationLayer.id, - source: visualisationLayer.source, - type: 'circle', - paint: { - 'circle-opacity': 0, - 'circle-radius': getLayerStyle({ - initial: 22, - hover: 22 * 1.2, - active: 22 * 1.3, - }), - }, - }; - - return ( - <> - - {markers.map((feature) => ( - - {feature.properties.description} - - ))} - - ); -} diff --git a/sloy-map/sources/Card/BaseCard.tsx b/sloy-map/sources/Card/BaseCard.tsx deleted file mode 100644 index efc70ae0..00000000 --- a/sloy-map/sources/Card/BaseCard.tsx +++ /dev/null @@ -1,163 +0,0 @@ -import React, { useContext, useMemo } from 'react'; -import { useSelector } from 'react-redux'; -import { Button, ButtonSize, ButtonType, Card, CardBlock, Link, LinkSize, Tag } from 'sloy-ui'; -import { copyrightSelector } from 'sloy-map/state/selectors'; -import { ISource, ICard } from 'sloy-map/types/types'; -import { MapContext } from 'sloy-map/state/MapProvider'; -import { getStringFromStringOrArray } from 'sloy-map/helpers/getStringFromStringOrArray'; -import { getYearStringByValue } from 'sloy-map/helpers/getYearNameByValue'; -import { OverrideCardFn } from 'sloy-map/types/uiTypes'; -import { CardActions } from './components/CardActions'; -import { Sources } from './components/Sources/Sources'; - -interface Props { - coordinates: [number, number] | number[]; - values: { [name: string]: any }; - card?: ICard; - source?: ISource; - overrideCard?: OverrideCardFn; -} - -export function BaseCard({ - values = {}, - coordinates = [], - card, - source, - overrideCard = (props) => props.cardProps, -}: Props) { - const copyright = useSelector(copyrightSelector); - const { locale } = useContext(MapContext); - const uiCardProps = useMemo(() => { - if (!card) return null; - - const defaultBlocks = (card?.blocks || []) - ?.map((block) => ({ - ...block, - title: source?.properties[block.id]?.title || block.id, - value: values[block.id], - })) - .filter((block) => block.type !== 'value' || block.value); - - const overrided = overrideCard({ - cardProps: { - title: getStringFromStringOrArray(values, card.title), - cover: getStringFromStringOrArray(values, card.cover), - description: getStringFromStringOrArray(values, card.description), - additionalInfo: card.additionalInfo?.map((i) => - getStringFromStringOrArray(values, i), - ), - actions: coordinates ? : undefined, - blocks: defaultBlocks, - }, - source, - values, - }); - - overrided.blocks = overrided.blocks - .map((block) => { - if (block.type === 'tag') { - const value = values[block.id]; - return { - ...block, - type: 'value', - value: value ? ( - - {value} - - ) : undefined, - }; - } - - if (block.type === 'age' && values[block?.deps]) { - return { - ...block, - type: 'value', - value: getYearStringByValue(values[block.deps]), - }; - } - - if (block.type === 'string[]' && values[block?.id]) { - const value = values[block?.id]; - return { - ...block, - type: 'value', - value: Array.isArray(value) ? value.join('. ') : value, - }; - } - - if (block.type === 'datetime' && values[block?.id]) { - const value = values[block?.id]; - const parsedDate = new Date(value); - if (parsedDate) { - return { - ...block, - type: 'value', - value: parsedDate.toLocaleString(locale, { - day: 'numeric', - month: 'long', - year: 'numeric', - hour: 'numeric', - minute: 'numeric', - }), - }; - } - - return { - ...block, - type: 'value', - value, - }; - } - - if (block.type === 'action-link' && block.content) { - const value = values[block.id]; - return { - ...block, - type: 'value', - title: '', - value: value ? ( - - ) : undefined, - }; - } - - if (typeof block.value === 'string' && block.value?.startsWith('http')) { - return { - ...block, - value: ( - - {block.value} - - ), - }; - } - - return block; - }) - .filter((block) => block.type !== 'value' || block.value); - - if (source.copyright.length) { - overrided.blocks.push({ type: 'divider' }); - overrided.blocks.push({ - type: 'section', - title: 'Источники', - value: copyright[item])} />, - }); - } - - return overrided; - }, [card, overrideCard, values, coordinates, source, locale, copyright]); - - if (!values || !card) { - return null; - } - - return ; -} diff --git a/sloy-map/sources/Card/BuildingCard.tsx b/sloy-map/sources/Card/BuildingCard.tsx deleted file mode 100644 index 8abdbc43..00000000 --- a/sloy-map/sources/Card/BuildingCard.tsx +++ /dev/null @@ -1,81 +0,0 @@ -import { useContext, useEffect, useState } from 'react'; -import { useMap } from 'react-map-gl'; -import { useSelector } from 'react-redux'; -import { cardsSelector, isAppLoadedSelector, sourcesSelector } from 'sloy-map/state/selectors'; -import { MapContext } from 'sloy-map/state/MapProvider'; -import { usePopup } from 'sloy-map/state/usePopup'; -import { getLatLngFromHash } from 'sloy-map/helpers/hash'; -import { BUILDING_LAYER_ID } from 'sloy-map/constants'; -import { BaseCard } from './BaseCard'; - -interface HouseObject { - id: string; - coordinates: [number, number][]; - attributes: Record; -} - -export function BuildingCard() { - const { popupHash, sourceIdValue } = usePopup(); - const { sloyMapGl } = useMap(); - const { overrideCard } = useContext(MapContext); - const isAppLoaded = useSelector(isAppLoadedSelector); - const sources = useSelector(sourcesSelector); - const cards = useSelector(cardsSelector); - const [lat, lng] = (popupHash || '').split('_'); - const [placemark, setPlacemark] = useState(null); - - useEffect(() => { - const map = sloyMapGl?.getMap?.(); - - if (!map || !popupHash || !isAppLoaded) { - return; - } - - try { - const [lat, lng] = getLatLngFromHash(); - - const house = map.queryRenderedFeatures(map.project({ lat: +lat, lng: +lng }), { - layers: [BUILDING_LAYER_ID], - })?.[0]?.properties; - - if (!house) return; - - setPlacemark({ - id: popupHash, - coordinates: [[+lat, +lng]], - attributes: house, - }); - } catch (error) { - console.error(error); - } - }, [sloyMapGl, popupHash, isAppLoaded]); - - useEffect(() => { - const map = sloyMapGl?.getMap?.(); - - if (!map || !popupHash) { - return; - } - - // center map only on loading step - if (!isAppLoaded) { - try { - map.flyTo({ center: { lat: +lat, lng: +lng } }); - } catch (error) { - console.error(error); - } - } - }, [sloyMapGl, popupHash, lat, lng, isAppLoaded]); - - const source = sources[sourceIdValue]; - - return ( - - ); -} diff --git a/sloy-map/sources/Card/FeatureCard.tsx b/sloy-map/sources/Card/FeatureCard.tsx deleted file mode 100644 index 1dc94fcf..00000000 --- a/sloy-map/sources/Card/FeatureCard.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import React from 'react'; -import { FeatureCollection } from 'geojson'; -import { ICard, ISource } from 'sloy-map/types/types'; -import { BaseCard } from './BaseCard'; - -export function FeatureCard({ - data, - featureId, - card, - source, -}: { - data: FeatureCollection; - featureId: string; - card?: ICard; - source: ISource; -}) { - const feature = data?.features?.find((f, i) => { - const byPid = String(f.properties?.id) === featureId; - const byFid = String(f.id) === featureId; - const byI = String(i) === featureId; - - return byPid || byFid || byI; - }); - - const properties = feature?.properties; - - return ( - - ); -} diff --git a/sloy-map/sources/Card/components/CardActions.tsx b/sloy-map/sources/Card/components/CardActions.tsx deleted file mode 100644 index 501b45e3..00000000 --- a/sloy-map/sources/Card/components/CardActions.tsx +++ /dev/null @@ -1,54 +0,0 @@ -import React, { useMemo } from 'react'; -import { Button, ButtonSize, ButtonType, Icon, IconType } from 'sloy-ui'; -import { useCopyHref } from 'sloy-map/helpers/useCopyHref'; - -type Props = { - coordinates?: [number, number] | number[]; -}; - -const COPY_RESET_TIMEOUT = 2000; - -export function CardActions({ coordinates }: Props) { - const { isCopied: isLinkCopied, onCopy: onCopyLink } = useCopyHref( - window.location.href, - COPY_RESET_TIMEOUT, - ); - - const coordsString = useMemo(() => { - if (!coordinates) { - return null; - } - - const coords = Array.isArray(coordinates[0]) ? coordinates[0].flat(2) : coordinates; - - return `${coords[0]?.toFixed(6)}, ${coords[1]?.toFixed(6)}`; - }, [coordinates]); - - const { isCopied: isCoordsCopied, onCopy: onCopyCoords } = useCopyHref( - coordsString, - COPY_RESET_TIMEOUT, - ); - - return ( - <> - {coordsString && ( - - )} - - - ); -} diff --git a/sloy-map/sources/Card/components/Sources/Sources.module.css b/sloy-map/sources/Card/components/Sources/Sources.module.css deleted file mode 100644 index 0b0938b7..00000000 --- a/sloy-map/sources/Card/components/Sources/Sources.module.css +++ /dev/null @@ -1,30 +0,0 @@ -.sources { - display: flex; - gap: 4px; - flex-direction: column; -} - -.sources__title { - font-size: 16px; - line-height: 1.3; - font-weight: 400; - margin: 0; -} - -.sources__list { - margin: 0; - padding: 0; - display: flex; - flex-direction: column; - gap: 8px; -} - -.sources__listItem { - list-style: none; -} - -@media screen and (width >= 1440px) { - .sources__title { - font-size: 16px; - } -} diff --git a/sloy-map/sources/Card/components/Sources/Sources.tsx b/sloy-map/sources/Card/components/Sources/Sources.tsx deleted file mode 100644 index d72c941b..00000000 --- a/sloy-map/sources/Card/components/Sources/Sources.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import React from 'react'; -import { Link, LinkSize } from 'sloy-ui'; -import styles from './Sources.module.css'; - -export function Sources({ sources }: { sources: { name: string; link: string }[] }) { - return ( -
-
    - {sources.map(({ link, name }) => { - return ( -
  • - - {name} - -
  • - ); - })} -
-
- ); -} diff --git a/sloy-map/sources/Card/index.tsx b/sloy-map/sources/Card/index.tsx deleted file mode 100644 index dd06b031..00000000 --- a/sloy-map/sources/Card/index.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import React from 'react'; -import { useSelector } from 'react-redux'; -import { useLoadGeoJSON } from 'sloy-map/helpers/useLoadGeoJSON'; -import { cardsSelector, sourcesSelector } from 'sloy-map/state/selectors'; -import { BuildingCard } from 'sloy-map/sources/Card/BuildingCard'; -import { MapLoader } from 'sloy-map/components/MapLoader'; -import { FeatureCard } from './FeatureCard'; - -interface Props { - popupHash?: string; - sourceIdValue: string | null; -} - -export function RenderCard({ popupHash, sourceIdValue }: Props) { - const sources = useSelector(sourcesSelector); - const cards = useSelector(cardsSelector); - - const source = sources[sourceIdValue]; - const card = cards[source?.card]; - - const { loading, data } = useLoadGeoJSON({ - ...source, - path: source?.dataByIdPath?.replace('{DATA_BY_ID}', popupHash) || source?.path, - }); - - if (loading) { - return ; - } - - if (!source) { - return null; - } - - if (source.id === 'buildingTile') { - return ; - } - - if (!data) { - return null; - } - - return ; -} diff --git a/sloy-map/state/MapProvider.tsx b/sloy-map/state/MapProvider.tsx deleted file mode 100644 index 1b84aa0c..00000000 --- a/sloy-map/state/MapProvider.tsx +++ /dev/null @@ -1,54 +0,0 @@ -import React, { ReactNode, useMemo } from 'react'; -import { OverrideCardFn, OverrideLayersFn } from 'sloy-map/types/uiTypes'; -import { usePopup } from './usePopup'; - -export interface IMapContext { - popupHash: string | null; - sourceIdValue: string | null; - openPopup: (p: string, t: string) => void; - closePopup: VoidFunction; - locale: string; - overrideCard: OverrideCardFn; - overrideLayers: OverrideLayersFn; -} - -export const MapContext = React.createContext({ - popupHash: null, - sourceIdValue: null, - openPopup: () => {}, - closePopup: () => {}, - locale: 'en-EN', - overrideCard: (props) => props?.cardProps, - overrideLayers: () => null, -}); - -interface Props { - children: ReactNode; - locale?: string; - overrideCard?: OverrideCardFn; - overrideLayers: OverrideLayersFn; -} - -export function MapContextProvider({ - children, - overrideCard, - overrideLayers, - locale = 'en-EN', -}: Props) { - const { popupHash, sourceIdValue, openPopup, closePopup } = usePopup(); - - const value = useMemo( - () => ({ - popupHash, - sourceIdValue, - openPopup, - closePopup, - locale, - overrideCard, - overrideLayers, - }), - [popupHash, sourceIdValue, openPopup, closePopup, locale, overrideCard, overrideLayers], - ); - - return {children}; -} diff --git a/sloy-map/state/selectors.ts b/sloy-map/state/selectors.ts deleted file mode 100644 index a8d0f5dc..00000000 --- a/sloy-map/state/selectors.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { State } from 'sloy-map/state/state'; - -export const isAppLoadedSelector = (state: State) => state.sloy.appLoaded; - -export const activeLayerSelector = (state: State) => state.sloy.activeLayer; - -export const activeFilterParamsSelector = (state: State) => state.sloy.activeFilterParams; - -export const cardsSelector = (state: State) => state.sloy.config?.cards || []; -export const copyrightSelector = (state: State) => state.sloy.config?.copyright || []; -export const filtersSelector = (state: State) => state.sloy.config?.filters || []; -export const layersSelector = (state: State) => state.sloy.config?.layers || []; -export const sourcesSelector = (state: State) => state.sloy.config?.sources || []; -export const visualisationLayersSelector = (state: State) => - state.sloy.config?.visualisationLayers || []; diff --git a/sloy-map/state/slice.ts b/sloy-map/state/slice.ts deleted file mode 100644 index 476b2b8e..00000000 --- a/sloy-map/state/slice.ts +++ /dev/null @@ -1,77 +0,0 @@ -import { createSlice, PayloadAction } from '@reduxjs/toolkit'; -import { getFilterTypeFromHash } from 'sloy-map/helpers/hash'; -import { State } from 'sloy-map/state/state'; -import { IApp } from 'sloy-map/types/types'; - -export interface SetFilterPayload { - activeLayer: string; - activeFilterParams: any; -} - -export interface SetFilterParamsPayload { - activeFilterParams: any; -} - -export interface ToggleDataPayload { - type: string; -} - -export const initialState: State['sloy'] = { - activeLayer: (getFilterTypeFromHash() as string) || 'ekbHouseAge', - activeFilterParams: null, - config: null, - appLoaded: false, -}; - -const sloySlice = createSlice({ - name: 'sloy', - initialState, - reducers: { - setAppLoaded(state) { - state.appLoaded = true; - }, - setConfig(state, action: PayloadAction) { - state.config = action.payload; - }, - setFilter(state, action: PayloadAction) { - const { activeLayer, activeFilterParams } = action.payload; - state.activeLayer = activeLayer; - state.activeFilterParams = activeFilterParams; - }, - setFilterParams(state, action: PayloadAction) { - const { activeFilterParams } = action.payload; - state.activeFilterParams = activeFilterParams; - }, - updateFilterParams( - state, - action: PayloadAction<{ - activeLayer: string; - activeFilterParams: any; - }>, - ) { - const { activeFilterParams, activeLayer } = action.payload; - state.activeLayer = activeLayer; - state.activeFilterParams = { - ...state.activeFilterParams, - ...activeFilterParams, - }; - }, - toggleData(state, action: PayloadAction) { - const { type } = action.payload; - - state.activeLayer = type === state.activeLayer ? null : type; - state.activeFilterParams = null; - }, - }, -}); - -export const { - setAppLoaded, - setConfig, - toggleData, - setFilter, - setFilterParams, - updateFilterParams, -} = sloySlice.actions; - -export const sloyReducer = sloySlice.reducer; diff --git a/sloy-map/state/state.ts b/sloy-map/state/state.ts deleted file mode 100644 index 9de90393..00000000 --- a/sloy-map/state/state.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { IApp } from 'sloy-map/types/types'; - -export interface State { - sloy: { - activeLayer: string; - activeFilterParams: any; - config: IApp; - appLoaded: boolean; - }; -} diff --git a/sloy-map/state/usePopup.ts b/sloy-map/state/usePopup.ts deleted file mode 100644 index 083f9eb3..00000000 --- a/sloy-map/state/usePopup.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { useCallback, useEffect, useState } from 'react'; -import { useSelector } from 'react-redux'; -import { setHash } from 'sloy-map/helpers/hash'; -import { activeLayerSelector } from 'sloy-map/state/selectors'; - -type PopupId = string; - -export function usePopup() { - const [popupHash, setOpenedPopup] = useState(null); - const [sourceIdValue, setSourceIdValue] = useState(null); - - const activeLayer: string = useSelector(activeLayerSelector); - - const openPopup = useCallback( - (id: PopupId, source: string) => { - setHash(source, id, activeLayer); - }, - [activeLayer], - ); - - const closePopup = useCallback(() => { - setSourceIdValue(null); - setOpenedPopup(null); - - window.location.hash = ''; - }, []); - - const handleOpenPopup = useCallback(() => { - const [source, ...id] = window.location.hash.slice(1).split('/')[0].split('-'); - - setOpenedPopup(id.join('-')); - setSourceIdValue(source); - }, []); - - useEffect(() => { - window.addEventListener('hashchange', handleOpenPopup, false); - - return () => { - window.removeEventListener('hashchange', handleOpenPopup, false); - }; - }, [handleOpenPopup]); - - useEffect(() => { - if (!window.location.hash) { - return; - } - - handleOpenPopup(); - }, [handleOpenPopup]); - - return { - popupHash, - sourceIdValue, - openPopup, - closePopup, - }; -} diff --git a/sloy-map/types/index.ts b/sloy-map/types/index.ts deleted file mode 100644 index bfcd5e1f..00000000 --- a/sloy-map/types/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './types'; -export * from './uiTypes'; diff --git a/sloy-map/types/types.ts b/sloy-map/types/types.ts deleted file mode 100644 index 92d83fff..00000000 --- a/sloy-map/types/types.ts +++ /dev/null @@ -1,99 +0,0 @@ -import { ReactNode } from 'react'; - -export type SourcePropertyValues = - | Record< - string, - { - color: string; - description?: string; - } - > - | Array<{ from: number; to: number; value?: number; color: string }>; - -export interface SourceProperty { - id: string; - type?: string; - title?: string; - values?: SourcePropertyValues; - deps?: string; -} - -export interface ICardBlock { - type: string; - id?: string; - deps?: string; - content?: string; - timeFormat?: string; - title?: string; - value?: ReactNode; -} - -export interface ICard { - id: string; - title?: string | string[]; - description?: string | string[]; - additionalInfo?: string[]; - blocks: ICardBlock[]; - cover?: string; -} - -export interface ISource { - id: string; - path?: string; - dataByIdPath?: string; - properties?: Record; - card?: ICard['id']; - copyright: Copyright['id'][]; - type: string; - latProperty?: string; - lngProperty?: string; - projection?: string; -} - -export interface IVisualisationLayer { - id: string; - type: string; - source: ISource['id']; - paint: any; - property?: string; - ids?: string[]; - openable?: boolean; -} - -export interface IFilter { - id: string; - type: string; - title?: string; - description?: string; - color?: string; - property: string; - source: ISource['id']; - filterVisualisationLayers: IVisualisationLayer['id'][]; -} - -export interface Copyright { - id: string; - name: string; - link: string; -} - -export interface ILayer { - id: string; - title: string; - filters: IFilter['id'][]; - visualisationLayers: IVisualisationLayer['id'][]; -} - -export interface IApp { - copyright: Record; - cards: Record; - sources: Record; - layers: Record; - filters: Record; - visualisationLayers: Record; -} - -export type ActiveFilters = { - filter: IFilter; - values: any; -}[]; diff --git a/sloy-map/types/uiTypes.ts b/sloy-map/types/uiTypes.ts deleted file mode 100644 index eb2e222b..00000000 --- a/sloy-map/types/uiTypes.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { ReactNode } from 'react'; -import { ICardBlock, ILayer, ISource } from './types'; - -export interface UiCardProps { - cover?: string; - actions?: ReactNode; - title?: ReactNode; - description?: ReactNode; - additionalInfo?: string[]; - blocks?: ICardBlock[]; - footerActions?: ReactNode; - loading?: boolean; -} - -export type OverrideCardFn = (props: { - cardProps: UiCardProps; - source: ISource; - values: Record; -}) => UiCardProps; - -export type OverrideLayersFn = (layer: ILayer) => ReactNode; diff --git a/sloy-map/visualLayers/BuildingRangeVisualLayer.tsx b/sloy-map/visualLayers/BuildingRangeVisualLayer.tsx deleted file mode 100644 index 2f2728fd..00000000 --- a/sloy-map/visualLayers/BuildingRangeVisualLayer.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import { useEffect } from 'react'; -import { MinMax } from 'sloy-ui'; -import { useMap } from 'react-map-gl'; -import { useSelector } from 'react-redux'; -import { setBuildingRangeStyle } from 'sloy-map/helpers/setBuildingStyle'; -import { IVisualisationLayer } from 'sloy-map/types/types'; -import { ClickableBuilding } from 'sloy-map/helpers/useClickableBuilding'; -import { sourcesSelector } from 'sloy-map/state/selectors'; - -interface Props { - visualisationLayer: IVisualisationLayer; - range?: MinMax; -} - -export function BuildingRangeVisualLayer({ visualisationLayer, range }: Props) { - const sloyMapGl = useMap(); - const sources = useSelector(sourcesSelector); - - useEffect(() => { - const map = sloyMapGl?.current?.getMap?.(); - const property = visualisationLayer.property; - - if (!property) return; - - const rangeData = sources[visualisationLayer.source]?.properties[property]?.values; - - if (!rangeData) return; - - setBuildingRangeStyle({ - map, - field: property, - rangeData, - range, - }); - }, [sloyMapGl, range, sources, visualisationLayer.property, visualisationLayer.source]); - - if (visualisationLayer.openable) { - return ; - } - - return null; -} diff --git a/sloy-map/visualLayers/BuldingsIdsVisualLayer.tsx b/sloy-map/visualLayers/BuldingsIdsVisualLayer.tsx deleted file mode 100644 index 0b52b91e..00000000 --- a/sloy-map/visualLayers/BuldingsIdsVisualLayer.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import { useEffect } from 'react'; -import { useMap } from 'react-map-gl'; -import { setBuildingStyleByPropertyValues } from 'sloy-map/helpers/setBuildingStyle'; -import { IVisualisationLayer } from 'sloy-map/types/types'; -import { ClickableBuilding } from 'sloy-map/helpers/useClickableBuilding'; - -interface Props { - visualisationLayer: IVisualisationLayer; -} - -export function BuldingsIdsVisualLayer({ visualisationLayer }: Props) { - const sloyMapGl = useMap(); - - useEffect(() => { - const map = sloyMapGl?.current?.getMap?.(); - - setBuildingStyleByPropertyValues({ - map, - property: 'osm:id', - values: visualisationLayer.ids, - color: visualisationLayer.paint['fill-extrusion-color'], - }); - }, [sloyMapGl, visualisationLayer.ids, visualisationLayer.paint]); - - if (visualisationLayer.openable) { - return ; - } - - return null; -} diff --git a/sloy-map/visualLayers/VisualisationLayer.tsx b/sloy-map/visualLayers/VisualisationLayer.tsx deleted file mode 100644 index bb582bf4..00000000 --- a/sloy-map/visualLayers/VisualisationLayer.tsx +++ /dev/null @@ -1,105 +0,0 @@ -import React, { useEffect } from 'react'; -import { Source, useMap } from 'react-map-gl'; -import { useSelector } from 'react-redux'; -import { - activeFilterParamsSelector, - filtersSelector, - sourcesSelector, - visualisationLayersSelector, -} from 'sloy-map/state/selectors'; -import { MapLayer } from 'sloy-map/layers/ClickableLayer'; -import { BuildingRangeVisualLayer } from 'sloy-map/visualLayers/BuildingRangeVisualLayer'; -import { ActiveFilters, IVisualisationLayer } from 'sloy-map/types/types'; -import { setBuildingDefaultColor } from '../helpers/setBuildingStyle'; -import { BuldingsIdsVisualLayer } from './BuldingsIdsVisualLayer'; - -export function VisualisationLayer({ id: vId }: { id: IVisualisationLayer['id'] }) { - const { sloyMapGl } = useMap(); - const filters = useSelector(filtersSelector); - const visualisationLayers = useSelector(visualisationLayersSelector); - const sources = useSelector(sourcesSelector); - - const visualisationLayer = visualisationLayers[vId]; - const source = sources[visualisationLayer?.source]; - - const activeFilterParams = useSelector(activeFilterParamsSelector); - - const activeFilters: ActiveFilters = Object.values(filters) - .filter( - (f) => - f.filterVisualisationLayers.includes(vId) && - activeFilterParams?.[f.id] !== undefined, - ) - .map((f) => ({ - filter: f, - values: activeFilterParams?.[f.id], - })); - - useEffect(() => { - const map = sloyMapGl?.getMap?.(); - - if ( - map && - visualisationLayer?.type !== 'building-range' && - visualisationLayer.id !== 'ekbFacadesLayer' - ) { - setBuildingDefaultColor(map); - } - }); - - useEffect(() => { - const map = sloyMapGl?.getMap?.(); - - if (!map) return; - - const filters: any = ['all']; - activeFilters.forEach(({ filter, values }) => { - if (filter.source !== 'buildingTile') { - if (filter.type === 'boolean' && map.getLayer(vId)) { - map.setLayoutProperty( - vId, - 'visibility', - values.length > 0 ? 'visible' : 'none', - ); - } else if (filter.type === 'range') { - filters.push([ - 'all', - ['>=', ['get', filter.property], values?.min], - ['<=', ['get', filter.property], values?.max], - ]); - } else if (filter.type === 'string[]') { - filters.push( - ['any'].concat(values.map((v) => ['in', v, ['get', filter.property]])), - ); - } else { - filters.push(['in', ['get', filter.property], ['literal', values]]); - } - } - }); - - if (map.getLayer(vId)) { - map.setFilter(vId, filters); - } - }, [activeFilters, sloyMapGl, vId]); - - if (!visualisationLayer) { - return null; - } - - if (visualisationLayer.type === 'building-ids') { - return ; - } - - if (visualisationLayer.type === 'building-range') { - const range = activeFilters.find((f) => f.filter.property === visualisationLayer.property) - ?.values; - - return ; - } - - return ( - - - - ); -} diff --git a/state/config.ts b/state/config.ts index 6c231524..9f1b87c0 100644 --- a/state/config.ts +++ b/state/config.ts @@ -1,7 +1,5 @@ -import { getLayerStyle } from 'sloy-map/helpers/getFeatureState'; -import { colorLuminance } from 'sloy-map/helpers/colorLuminance'; +import { IApp, getLayerStyle, colorLuminance } from 'sloy-map'; import { MAX_ZOOM, MIN_ZOOM } from 'constants/map'; -import { IApp } from 'sloy-map/types'; export const state: IApp = { copyright: { diff --git a/state/redux.ts b/state/redux.ts index 7c2293a2..45db2004 100644 --- a/state/redux.ts +++ b/state/redux.ts @@ -1,5 +1,5 @@ import { configureStore } from '@reduxjs/toolkit'; -import { sloyReducer } from 'sloy-map/state/slice'; +import { sloyReducer } from 'sloy-map'; export const store = configureStore({ reducer: {