Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
C
canifa_note
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Vũ Hoàng Anh
canifa_note
Commits
95a50b65
Commit
95a50b65
authored
Sep 26, 2024
by
Steven
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
chore: tweak leaflet map
parent
9c41c8d5
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
67 additions
and
21 deletions
+67
-21
LeafletMap.tsx
web/src/components/LeafletMap.tsx
+7
-4
LocationSelector.tsx
...c/components/MemoEditor/ActionButton/LocationSelector.tsx
+22
-8
MemoLocationView.tsx
web/src/components/MemoLocationView.tsx
+35
-0
MemoView.tsx
web/src/components/MemoView.tsx
+3
-9
No files found.
web/src/components/LeafletMap.tsx
View file @
95a50b65
...
...
@@ -5,8 +5,8 @@ import ReactDOMServer from "react-dom/server";
import
{
MapContainer
,
Marker
,
TileLayer
,
useMapEvents
}
from
"react-leaflet"
;
const
markerIcon
=
new
DivIcon
({
className
:
"border-none"
,
html
:
ReactDOMServer
.
renderToString
(<
MapPinIcon
size=
{
24
}
/>),
className
:
"
relative
border-none"
,
html
:
ReactDOMServer
.
renderToString
(<
MapPinIcon
className=
"absolute bottom-1/2 -left-1/2"
fill=
"pink"
size=
{
24
}
/>),
});
interface
MarkerProps
{
...
...
@@ -41,11 +41,14 @@ interface MapProps {
onChange
?:
(
position
:
LatLng
)
=>
void
;
}
const
DEFAULT_CENTER_LAT_LNG
=
new
LatLng
(
48.8584
,
2.2945
);
const
LeafletMap
=
(
props
:
MapProps
)
=>
{
const
position
=
props
.
latlng
||
DEFAULT_CENTER_LAT_LNG
;
return
(
<
MapContainer
className=
"w-full h-72"
center=
{
p
rops
.
latlng
}
zoom=
{
13
}
scrollWheelZoom=
{
false
}
>
<
MapContainer
className=
"w-full h-72"
center=
{
p
osition
}
zoom=
{
13
}
scrollWheelZoom=
{
false
}
>
<
TileLayer
url=
"https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
<
LocationMarker
position=
{
p
rops
.
latlng
}
onChange=
{
props
.
onChange
?
props
.
onChange
:
()
=>
{}
}
/>
<
LocationMarker
position=
{
p
osition
}
onChange=
{
props
.
onChange
?
props
.
onChange
:
()
=>
{}
}
/>
</
MapContainer
>
);
};
...
...
web/src/components/MemoEditor/ActionButton/LocationSelector.tsx
View file @
95a50b65
...
...
@@ -16,7 +16,7 @@ interface Props {
interface
State
{
initilized
:
boolean
;
placeholder
:
string
;
position
:
LatLng
;
position
?
:
LatLng
;
}
const
LocationSelector
=
(
props
:
Props
)
=>
{
...
...
@@ -24,7 +24,7 @@ const LocationSelector = (props: Props) => {
const
[
state
,
setState
]
=
useState
<
State
>
({
initilized
:
false
,
placeholder
:
props
.
location
?.
placeholder
||
""
,
position
:
new
LatLng
(
props
.
location
?.
latitude
||
0
,
props
.
location
?.
longitude
||
0
)
,
position
:
props
.
location
?
new
LatLng
(
props
.
location
.
latitude
,
props
.
location
.
longitude
)
:
undefined
,
});
const
[
popoverOpen
,
setPopoverOpen
]
=
useState
<
boolean
>
(
false
);
...
...
@@ -52,7 +52,7 @@ const LocationSelector = (props: Props) => {
setState
({
...
state
,
position
:
new
LatLng
(
lat
,
lng
),
initilized
:
true
});
},
(
error
)
=>
{
handleError
(
error
,
"
Error getting
current position"
);
handleError
(
error
,
"
Failed to get
current position"
);
},
);
}
else
{
...
...
@@ -62,6 +62,11 @@ const LocationSelector = (props: Props) => {
},
[
popoverOpen
]);
useEffect
(()
=>
{
if
(
!
state
.
position
)
{
setState
({
...
state
,
placeholder
:
""
});
return
;
}
// Fetch reverse geocoding data.
fetch
(
`https://nominatim.openstreetmap.org/reverse?lat=
${
state
.
position
.
lat
}
&lon=
${
state
.
position
.
lng
}
&format=json`
)
.
then
((
response
)
=>
response
.
json
())
...
...
@@ -96,7 +101,7 @@ const LocationSelector = (props: Props) => {
<
span
className=
"font-normal ml-0.5 text-ellipsis whitespace-nowrap overflow-hidden max-w-32"
>
{
props
.
location
.
placeholder
}
</
span
>
<
XIcon
className=
"w-5 h-5 mx-auto shrink-0 hidden group-hover:block hover:opacity-80"
onClick=
{
removeLocation
}
/>
<
XIcon
className=
"w-5 h-5 mx-auto shrink-0 hidden group-hover:block
opacity-60
hover:opacity-80"
onClick=
{
removeLocation
}
/>
</>
)
}
</
IconButton
>
...
...
@@ -106,25 +111,34 @@ const LocationSelector = (props: Props) => {
<
LeafletMap
key=
{
JSON
.
stringify
(
state
.
initilized
)
}
latlng=
{
state
.
position
}
onChange=
{
onPositionChanged
}
/>
<
div
className=
"mt-2 w-full flex flex-row justify-between items-center gap-2"
>
<
Input
placeholder=
"Choose
location
"
placeholder=
"Choose
a position first.
"
value=
{
state
.
placeholder
}
disabled=
{
!
state
.
position
}
startDecorator=
{
state
.
position
?
(
<
span
>
[
{
state
.
position
.
lat
.
toFixed
(
3
)
}
,
{
state
.
position
.
lng
.
toFixed
(
3
)
}
]
</
span
>
)
:
null
}
onChange=
{
(
e
)
=>
setState
((
state
)
=>
({
...
state
,
placeholder
:
e
.
target
.
value
}))
}
/>
<
Button
className=
"shrink-0"
size=
"sm"
onClick=
{
()
=>
{
props
.
onChange
(
Location
.
fromPartial
({
placeholder
:
state
.
placeholder
,
latitude
:
state
.
position
.
lat
,
longitude
:
state
.
position
.
lng
,
latitude
:
state
.
position
?
.
lat
,
longitude
:
state
.
position
?
.
lng
,
}),
);
setPopoverOpen
(
false
);
}
}
disabled=
{
!
state
.
position
||
state
.
placeholder
.
length
===
0
}
>
{
t
(
"common.
add
"
)
}
{
t
(
"common.
confirm
"
)
}
</
Button
>
</
div
>
</
div
>
...
...
web/src/components/MemoLocationView.tsx
0 → 100644
View file @
95a50b65
import
{
LatLng
}
from
"leaflet"
;
import
{
MapPinIcon
}
from
"lucide-react"
;
import
{
useState
}
from
"react"
;
import
{
Location
}
from
"@/types/proto/api/v1/memo_service"
;
import
LeafletMap
from
"./LeafletMap"
;
import
{
Popover
,
PopoverContent
,
PopoverTrigger
}
from
"./ui/Popover"
;
interface
Props
{
location
:
Location
;
}
const
MemoLocationView
:
React
.
FC
<
Props
>
=
(
props
:
Props
)
=>
{
const
{
location
}
=
props
;
const
[
popoverOpen
,
setPopoverOpen
]
=
useState
<
boolean
>
(
false
);
return
(
<
Popover
open=
{
popoverOpen
}
onOpenChange=
{
setPopoverOpen
}
>
<
PopoverTrigger
asChild
>
<
p
className=
"w-full flex flex-row gap-0.5 items-center text-gray-500"
>
<
MapPinIcon
className=
"w-4 h-auto shrink-0"
/>
<
span
className=
"text-sm font-normal text-ellipsis whitespace-nowrap overflow-hidden"
>
{
location
.
placeholder
?
location
.
placeholder
:
`[${location.latitude}, ${location.longitude}]`
}
</
span
>
</
p
>
</
PopoverTrigger
>
<
PopoverContent
align=
"start"
>
<
div
className=
"min-w-80 sm:w-128 flex flex-col justify-start items-start"
>
<
LeafletMap
latlng=
{
new
LatLng
(
location
.
latitude
,
location
.
longitude
)
}
/>
</
div
>
</
PopoverContent
>
</
Popover
>
);
};
export
default
MemoLocationView
;
web/src/components/MemoView.tsx
View file @
95a50b65
import
{
Tooltip
}
from
"@mui/joy"
;
import
clsx
from
"clsx"
;
import
{
BookmarkIcon
,
M
apPinIcon
,
M
essageCircleMoreIcon
}
from
"lucide-react"
;
import
{
BookmarkIcon
,
MessageCircleMoreIcon
}
from
"lucide-react"
;
import
{
memo
,
useCallback
,
useEffect
,
useRef
,
useState
}
from
"react"
;
import
{
Link
,
useLocation
}
from
"react-router-dom"
;
import
useCurrentUser
from
"@/hooks/useCurrentUser"
;
...
...
@@ -16,6 +16,7 @@ import { isSuperUser } from "@/utils/user";
import
MemoActionMenu
from
"./MemoActionMenu"
;
import
MemoContent
from
"./MemoContent"
;
import
MemoEditor
from
"./MemoEditor"
;
import
MemoLocationView
from
"./MemoLocationView"
;
import
MemoReactionistView
from
"./MemoReactionListView"
;
import
MemoRelationListView
from
"./MemoRelationListView"
;
import
MemoResourceListView
from
"./MemoResourceListView"
;
...
...
@@ -198,14 +199,7 @@ const MemoView: React.FC<Props> = (props: Props) => {
onDoubleClick=
{
handleMemoContentDoubleClick
}
compact=
{
props
.
compact
&&
workspaceMemoRelatedSetting
.
enableAutoCompact
}
/>
{
memo
.
location
&&
(
<
p
className=
"w-full flex flex-row gap-0.5 items-center text-gray-500"
>
<
MapPinIcon
className=
"w-4 h-auto shrink-0"
/>
<
span
className=
"text-sm font-normal text-ellipsis whitespace-nowrap overflow-hidden"
>
{
memo
.
location
.
placeholder
?
memo
.
location
.
placeholder
:
`[${memo.location.latitude}, ${memo.location.longitude}]`
}
</
span
>
</
p
>
)
}
{
memo
.
location
&&
<
MemoLocationView
location=
{
memo
.
location
}
/>
}
<
MemoResourceListView
resources=
{
memo
.
resources
}
/>
<
MemoRelationListView
memo=
{
memo
}
relations=
{
referencedMemos
}
/>
<
MemoReactionistView
memo=
{
memo
}
reactions=
{
memo
.
reactions
}
/>
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment