Skip to content
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .claude/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"permissions": {
"allow": [
"Bash(npx tsc *)"
]
}
}
Binary file modified .yarn/install-state.gz
Binary file not shown.
652 changes: 326 additions & 326 deletions .yarn/releases/yarn-4.16.0.cjs → .yarn/releases/yarn-4.17.0.cjs

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion .yarnrc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@ npmScopes:
npmAuthToken: "${NPM_TOKEN}"
npmRegistryServer: "https://npm.pkg.github.com"

yarnPath: .yarn/releases/yarn-4.16.0.cjs
yarnPath: .yarn/releases/yarn-4.17.0.cjs
10 changes: 10 additions & 0 deletions core/i18n/resources/en/dataView.js
Original file line number Diff line number Diff line change
Expand Up @@ -142,4 +142,14 @@ Merge cannot be performed.`,
'Please make your selection using the left side panel or select an existing query from "Manage queries"',
},
viewSelectedRecord: 'View selected record',
mapView: {
layersPanel: {
hidePanel: 'Hide panel',
showPanel: 'Show panel',
sortAsc: 'Sort ascending',
sortDesc: 'Sort descending',
sort: 'Sort',
sortNone: 'Remove sort',
},
},
}
10 changes: 10 additions & 0 deletions core/i18n/resources/es/dataView.js
Original file line number Diff line number Diff line change
Expand Up @@ -130,4 +130,14 @@ export default {
'Por favor, haga su selección usando el panel lateral izquierdo o seleccione una consulta existente de "Administrar consultas"',
},
viewSelectedRecord: 'Ver registro seleccionado',
mapView: {
layersPanel: {
hidePanel: 'Ocultar panel',
showPanel: 'Mostrar panel',
sortAsc: 'Ordenar ascendente',
sortDesc: 'Ordenar descendente',
sort: 'Ordenar',
sortNone: 'Quitar orden',
},
},
}
10 changes: 10 additions & 0 deletions core/i18n/resources/fr/dataView.js
Original file line number Diff line number Diff line change
Expand Up @@ -142,4 +142,14 @@ La fusion ne peut pas être effectuée.`,
'Veuillez faire votre sélection dans le panneau de gauche ou sélectionner une requête existante depuis "Gérer les requêtes"',
},
viewSelectedRecord: "Voir l'enregistrement sélectionné",
mapView: {
layersPanel: {
hidePanel: 'Masquer le panneau',
showPanel: 'Afficher le panneau',
sortAsc: 'Trier croissant',
sortDesc: 'Trier décroissant',
sort: 'Trier',
sortNone: 'Supprimer le tri',
},
},
}
10 changes: 10 additions & 0 deletions core/i18n/resources/mn/dataView.js
Original file line number Diff line number Diff line change
Expand Up @@ -142,4 +142,14 @@ export default {
'Зүүн талын самбараас сонголт хийнэ үү эсвэл "Хүсэлтүүдийг удирдах"-аас одоо байгаа хүсэлтийг сонгоно уу',
},
viewSelectedRecord: 'Сонгогдсон бичлэгийг харах',
mapView: {
layersPanel: {
hidePanel: 'Самбарыг нуух',
showPanel: 'Самбарыг харуулах',
sortAsc: 'Өсөх эрэмбэ',
sortDesc: 'Буурах эрэмбэ',
sort: 'Эрэмбэлэх',
sortNone: 'Эрэмбэ арилгах',
},
},
}
10 changes: 10 additions & 0 deletions core/i18n/resources/pt/dataView.js
Original file line number Diff line number Diff line change
Expand Up @@ -141,4 +141,14 @@ A mesclagem não pode ser realizada.`,
'Faça sua seleção usando o painel esquerdo ou selecione uma consulta existente em "Gerenciar consultas"',
},
viewSelectedRecord: 'Visualizar registro selecionado',
mapView: {
layersPanel: {
hidePanel: 'Ocultar painel',
showPanel: 'Mostrar painel',
sort: 'Ordenar',
sortAsc: 'Ordenar ascendente',
sortDesc: 'Ordenar descendente',
sortNone: 'Remover ordem',
},
},
}
10 changes: 10 additions & 0 deletions core/i18n/resources/ru/dataView.js
Original file line number Diff line number Diff line change
Expand Up @@ -142,4 +142,14 @@ export default {
'Пожалуйста, сделайте выбор, используя левую панель, или выберите существующий запрос из "Управление запросами"',
},
viewSelectedRecord: 'Просмотреть выбранную запись',
mapView: {
layersPanel: {
hidePanel: 'Скрыть панель',
showPanel: 'Показать панель',
sortAsc: 'Сортировать по возрастанию',
sortDesc: 'Сортировать по убыванию',
sort: 'Сортировка',
sortNone: 'Убрать сортировку',
},
},
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -235,5 +235,5 @@
"lint-staged": {
"{common,core,server,test,webapp}/**/*.{js,jsx,ts,tsx}": "eslint --cache --fix"
},
"packageManager": "yarn@4.16.0"
"packageManager": "yarn@4.17.0"
}
30 changes: 29 additions & 1 deletion webapp/components/MapContainer/MapContainer.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
import './Map.scss'

import { GeoJSON, MapContainer as RLMapContainer, ScaleControl, ZoomControl } from 'react-leaflet'
import { useEffect } from 'react'
import {
GeoJSON,
MapContainer as RLMapContainer,
ScaleControl,
ZoomControl,
useMap as useLeafletMap,
} from 'react-leaflet'
import Ruler from 'react-leaflet-ruler'
import PropTypes from 'prop-types'

Expand Down Expand Up @@ -31,6 +38,26 @@ L.Marker.prototype.options.icon = L.icon({

const INITIAL_ZOOM_LEVEL = 3

const MapResizeHandler = () => {
const map = useLeafletMap()

useEffect(() => {
const container = map.getContainer()
let rafId
const observer = new ResizeObserver(() => {
cancelAnimationFrame(rafId)
rafId = requestAnimationFrame(() => map.invalidateSize())
})
observer.observe(container)
return () => {
observer.disconnect()
cancelAnimationFrame(rafId)
}
}, [map])

return null
}

export const MapContainer = (props) => {
const { editable = false, geoJson = null, layers = [], markerPoint, markerTitle, showOptions = true } = props
const { centerPositionLatLon, markerPointUpdated, markerPointUpdatedToString, onMarkerPointUpdated, onSaveClick } =
Expand Down Expand Up @@ -58,6 +85,7 @@ export const MapContainer = (props) => {
zoomControl={false}
zoom={INITIAL_ZOOM_LEVEL}
>
<MapResizeHandler />
<MapLayersControl layers={layers} />
<MapMarker
editable={editable}
Expand Down
1 change: 1 addition & 0 deletions webapp/components/hooks/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export { useHorizontalResize } from './useHorizontalResize'
export { default as usePrevious } from './usePrevious'
export { default as useOnUpdate } from './useOnUpdate'
export { default as useIsMountedRef } from './useIsMountedRef'
Expand Down
133 changes: 133 additions & 0 deletions webapp/components/hooks/useHorizontalResize.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
import { useCallback, useEffect, useRef, useState } from 'react'
Comment thread
SteRiccio marked this conversation as resolved.
Outdated

type Params = {
containerRef: React.RefObject<HTMLElement | null>
initialWidth: number
minLeftWidth?: number
minRightWidth?: number
}

type Result = {
width: number
maxWidth: number
onGutterMouseDown: (e: React.MouseEvent) => void
onGutterKeyDown: (e: React.KeyboardEvent) => void
onGutterTouchStart: (e: React.TouchEvent) => void
}

const KEYBOARD_STEP = 10

export const useHorizontalResize = ({
containerRef,
initialWidth,
minLeftWidth = 0,
minRightWidth = 0,
}: Params): Result => {
const [width, setWidth] = useState(initialWidth)
const [containerWidth, setContainerWidth] = useState(0)
const widthRef = useRef(initialWidth)

useEffect(() => {
const container = containerRef.current
if (!container) return
setContainerWidth(container.clientWidth)
const observer = new ResizeObserver(() => setContainerWidth(container.clientWidth))
observer.observe(container)
return () => observer.disconnect()
}, [containerRef])

const clampWidth = useCallback(
(newWidth: number): number => {
const containerWidth = containerRef.current?.clientWidth ?? window.innerWidth
return Math.min(containerWidth - minRightWidth, Math.max(minLeftWidth, newWidth))
},
[containerRef, minLeftWidth, minRightWidth]
)
Comment thread
SteRiccio marked this conversation as resolved.

const onGutterMouseDown = useCallback(
(e: React.MouseEvent) => {
e.preventDefault()
const startX = e.clientX
const startWidth = widthRef.current
document.body.style.cursor = 'ew-resize'
document.body.style.userSelect = 'none'

const onMouseMove = (moveEvent: MouseEvent) => {
const newWidth = clampWidth(startWidth + moveEvent.clientX - startX)
widthRef.current = newWidth
setWidth(newWidth)
}

const onMouseUp = () => {
document.body.style.cursor = ''
document.body.style.userSelect = ''
document.removeEventListener('mousemove', onMouseMove)
document.removeEventListener('mouseup', onMouseUp)
}

document.addEventListener('mousemove', onMouseMove)
document.addEventListener('mouseup', onMouseUp)
},
[clampWidth]
)

const onGutterKeyDown = useCallback(
(e: React.KeyboardEvent) => {
let delta = 0
if (e.key === 'ArrowRight') {
delta = KEYBOARD_STEP
} else if (e.key === 'ArrowLeft') {
delta = -KEYBOARD_STEP
} else if (e.key === 'Home') {
e.preventDefault()
const newWidth = clampWidth(minLeftWidth)
widthRef.current = newWidth
setWidth(newWidth)
return
} else if (e.key === 'End') {
e.preventDefault()
const containerWidth = containerRef.current?.clientWidth ?? window.innerWidth
const newWidth = clampWidth(containerWidth - minRightWidth)
widthRef.current = newWidth
setWidth(newWidth)
return
} else {
return
}
e.preventDefault()
const newWidth = clampWidth(widthRef.current + delta)
widthRef.current = newWidth
setWidth(newWidth)
},
[clampWidth, containerRef, minLeftWidth, minRightWidth]
)

const onGutterTouchStart = useCallback(
(e: React.TouchEvent) => {
const touch = e.touches[0]
const startX = touch.clientX
const startWidth = widthRef.current

const onTouchMove = (moveEvent: TouchEvent) => {
moveEvent.preventDefault()
const currentTouch = moveEvent.touches[0]
const newWidth = clampWidth(startWidth + currentTouch.clientX - startX)
widthRef.current = newWidth
setWidth(newWidth)
}

const onTouchEnd = () => {
document.removeEventListener('touchmove', onTouchMove)
document.removeEventListener('touchend', onTouchEnd)
}

document.addEventListener('touchmove', onTouchMove, { passive: false })
document.addEventListener('touchend', onTouchEnd)
},
[clampWidth]
)

const maxWidth = Math.max(0, containerWidth - minRightWidth)

return { width, maxWidth, onGutterMouseDown, onGutterKeyDown, onGutterTouchStart }
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export const CoordinateAttributeMarker = (props) => {
flyToPreviousPoint,
markersColor,
onPopupClose,
onPopupOpen,
onRecordEditClick,
popupOpen,
setMarkerByKey,
Expand All @@ -38,6 +39,10 @@ export const CoordinateAttributeMarker = (props) => {
flyToPoint(data)
}, [flyToPoint, data])

const handlePopupOpen = useCallback(() => {
onPopupOpen?.(key)
}, [key, onPopupOpen])

const content = useMemo(
() => (
<>
Expand Down Expand Up @@ -73,8 +78,8 @@ export const CoordinateAttributeMarker = (props) => {
)

const eventHandlers = useMemo(
() => ObjectUtils.keepNonEmptyProps({ dblclick: onDoubleClick, popupclose: onPopupClose }),
[onDoubleClick, onPopupClose]
() => ObjectUtils.keepNonEmptyProps({ dblclick: onDoubleClick, popupclose: onPopupClose, popupopen: handlePopupOpen }),
[handlePopupOpen, onDoubleClick, onPopupClose]
)

const circleMarkerPathOptions = useMemo(
Expand Down Expand Up @@ -118,6 +123,7 @@ CoordinateAttributeMarker.propTypes = {
flyToPreviousPoint: PropTypes.func,
markersColor: PropTypes.any,
onPopupClose: PropTypes.func,
onPopupOpen: PropTypes.func,
onRecordEditClick: PropTypes.any,
popupOpen: PropTypes.bool,
setMarkerByKey: PropTypes.func,
Expand Down
Loading
Loading