Added copy coords function
This commit is contained in:
@@ -2,12 +2,12 @@
|
|||||||
--viewport-padding: 25px;
|
--viewport-padding: 25px;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
right: 0;
|
right: 2rem;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
padding: var(--viewport-padding);
|
padding: var(--viewport-padding);
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
width: 390px;
|
width: 480px;
|
||||||
max-width: 100vw;
|
max-width: 100vw;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
list-style: none;
|
list-style: none;
|
||||||
@@ -16,15 +16,23 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.toast-root {
|
.toast-root {
|
||||||
background-color: white;
|
|
||||||
border-radius: 6px;
|
|
||||||
box-shadow: hsl(206 22% 7% / 35%) 0px 10px 38px -10px, hsl(206 22% 7% / 20%) 0px 10px 20px -15px;
|
|
||||||
padding: 15px;
|
padding: 15px;
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-areas: 'title action' 'description action';
|
grid-template-areas: 'title action' 'description action';
|
||||||
grid-template-columns: auto max-content;
|
grid-template-columns: auto max-content;
|
||||||
column-gap: 15px;
|
column-gap: 15px;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
color: var(--slate-800);
|
||||||
|
border: 1px solid var(--slate-400);
|
||||||
|
background-color: var(--white);
|
||||||
|
border-radius: 6px;
|
||||||
|
box-shadow: hsl(206 22% 7% / 35%) 0px 10px 38px -10px, hsl(206 22% 7% / 20%) 0px 10px 20px -15px;
|
||||||
|
|
||||||
|
&.toast-success {
|
||||||
|
color: var(--green-700);
|
||||||
|
border: 1px solid var(--green-700);
|
||||||
|
background-color: color-mix(in srgb, var(--green-500) 17.5%, var(--white));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.toast-root[data-state='open'] {
|
.toast-root[data-state='open'] {
|
||||||
animation: slideIn 150ms cubic-bezier(0.16, 1, 0.3, 1);
|
animation: slideIn 150ms cubic-bezier(0.16, 1, 0.3, 1);
|
||||||
|
|||||||
@@ -602,6 +602,19 @@ map.on('moveend', () => {
|
|||||||
setupToURL()
|
setupToURL()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listener for querying a copy of the current coordinates
|
||||||
|
*/
|
||||||
|
window.addEventListener('on-copy-coords', () => {
|
||||||
|
const lon = convertScaleToX(Number(localStorage.getItem('lastHeldXPosition')))
|
||||||
|
const lat = convertScaleToY(Number(localStorage.getItem('lastHeldYPosition')))
|
||||||
|
const coordsText = JSON.stringify({ x: lon, y: lat })
|
||||||
|
|
||||||
|
navigator.clipboard.writeText(coordsText)
|
||||||
|
|
||||||
|
window.dispatchEvent(new CustomEvent('on-toast-push', { bubbles: true, detail: { preset: 'copied-coords' }}))
|
||||||
|
})
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* UTILITIES
|
* UTILITIES
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ function switchMenuMode(newMode: MenuMode) {
|
|||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
const mapRef = document.getElementById('world')
|
const mapRef = document.getElementById('world')
|
||||||
|
|
||||||
if (mapRef) {
|
if (mapRef) {
|
||||||
mapRef.addEventListener('contextmenu', handleContextMenu)
|
mapRef.addEventListener('contextmenu', handleContextMenu)
|
||||||
mapRef.addEventListener('mousedown', hideMenu)
|
mapRef.addEventListener('mousedown', hideMenu)
|
||||||
@@ -188,6 +189,11 @@ function hideMarkerModal() {
|
|||||||
function setTitleError(error: Error | null) {
|
function setTitleError(error: Error | null) {
|
||||||
markerTitleInputError.value = error
|
markerTitleInputError.value = error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleCoordsCopy() {
|
||||||
|
markerMenu.value?.dispatchEvent(new CustomEvent('on-copy-coords', { bubbles: true }))
|
||||||
|
hideMenu()
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -196,7 +202,16 @@ function setTitleError(error: Error | null) {
|
|||||||
<menu v-show="shouldBeShown" ref="markerMenu">
|
<menu v-show="shouldBeShown" ref="markerMenu">
|
||||||
<li>
|
<li>
|
||||||
<button @click="switchMenuMode('editing-marker')">
|
<button @click="switchMenuMode('editing-marker')">
|
||||||
{{ t('maps.markers.new') }}
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="#000000" viewBox="0 0 256 256"><path d="M128,16a88.1,88.1,0,0,0-88,88c0,31.4,14.51,64.68,42,96.25a254.19,254.19,0,0,0,41.45,38.3,8,8,0,0,0,9.18,0A254.19,254.19,0,0,0,174,200.25c27.45-31.57,42-64.85,42-96.25A88.1,88.1,0,0,0,128,16Zm32,96H136v24a8,8,0,0,1-16,0V112H96a8,8,0,0,1,0-16h24V72a8,8,0,0,1,16,0V96h24a8,8,0,0,1,0,16Z"></path></svg>
|
||||||
|
|
||||||
|
<span>{{ t('maps.markers.new') }}</span>
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<button @click="handleCoordsCopy">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="#000000" viewBox="0 0 256 256"><path d="M216,32H88a8,8,0,0,0-8,8V80H40a8,8,0,0,0-8,8V216a8,8,0,0,0,8,8H168a8,8,0,0,0,8-8V176h40a8,8,0,0,0,8-8V40A8,8,0,0,0,216,32Zm-8,128H176V88a8,8,0,0,0-8-8H96V48H208Z"></path></svg>
|
||||||
|
|
||||||
|
<span>{{ t('maps.copyCoords') }}</span>
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
</menu>
|
</menu>
|
||||||
@@ -271,14 +286,23 @@ menu {
|
|||||||
|
|
||||||
li {
|
li {
|
||||||
a, button {
|
a, button {
|
||||||
display: block;
|
display: flex;
|
||||||
|
gap: .75ch;
|
||||||
|
align-items: center;
|
||||||
padding: .33rem 1rem;
|
padding: .33rem 1rem;
|
||||||
|
padding-left: .66rem;
|
||||||
font-size: .77em;
|
font-size: .77em;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
&:hover,
|
&:hover,
|
||||||
&:focus-within {
|
&:focus-within {
|
||||||
|
color: var(--blue-700);
|
||||||
background-color: var(--slate-100);
|
background-color: var(--slate-100);
|
||||||
|
|
||||||
|
svg {
|
||||||
|
fill: var(--blue-700);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,35 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { isVNode } from "vue"
|
import { isVNode, onMounted } from "vue"
|
||||||
import { useToast } from './useToast.ts'
|
import { ToastLifetime, useToast, type Toast } from './useToast.ts'
|
||||||
import { ToastDescription, ToastProvider, ToastRoot, ToastTitle, ToastViewport } from 'radix-vue'
|
import { ToastDescription, ToastProvider, ToastRoot, ToastTitle, ToastViewport } from 'radix-vue'
|
||||||
|
|
||||||
const { toasts } = useToast()
|
const { toast, toasts } = useToast()
|
||||||
|
import { t } from '@/i18n/store';
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
window.addEventListener('on-toast-push', (e) => handleInserted(e as CustomEvent))
|
||||||
|
})
|
||||||
|
|
||||||
|
function handleInserted(e: CustomEvent) {
|
||||||
|
if ( e.detail.preset) {
|
||||||
|
switch (e.detail.preset) {
|
||||||
|
case "copied-coords":
|
||||||
|
default:
|
||||||
|
toast({
|
||||||
|
description: t('toast.copyCoords.description'),
|
||||||
|
duration: ToastLifetime.SHORT,
|
||||||
|
variant: 'success'
|
||||||
|
})
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const toastData = e.detail.toast as Toast
|
||||||
|
|
||||||
|
toast(toastData)
|
||||||
|
}
|
||||||
|
|
||||||
function handleUpdate(id: string) {
|
function handleUpdate(id: string) {
|
||||||
toasts.value.forEach((t, i) => {
|
toasts.value.forEach((t, i) => {
|
||||||
@@ -12,7 +38,7 @@ function handleUpdate(id: string) {
|
|||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
toasts.value.splice(i, 1)
|
toasts.value.splice(i, 1)
|
||||||
}, 3000)
|
}, 5000)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -22,6 +48,7 @@ function handleUpdate(id: string) {
|
|||||||
<ToastProvider>
|
<ToastProvider>
|
||||||
<ToastRoot
|
<ToastRoot
|
||||||
class="toast-root"
|
class="toast-root"
|
||||||
|
:class="toast.variant ? `toast-${toast.variant}` : ''"
|
||||||
v-for="toast in toasts"
|
v-for="toast in toasts"
|
||||||
:key="toast.id"
|
:key="toast.id"
|
||||||
v-bind="toast"
|
v-bind="toast"
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ type ToasterToast = ToastProps & {
|
|||||||
id: string
|
id: string
|
||||||
title?: string
|
title?: string
|
||||||
description?: StringOrVNode
|
description?: StringOrVNode
|
||||||
action?: Component
|
action?: Component,
|
||||||
|
variant?: "default" | "success" | "destructive"
|
||||||
}
|
}
|
||||||
|
|
||||||
const actionTypes = {
|
const actionTypes = {
|
||||||
@@ -139,7 +140,7 @@ function useToast() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type Toast = Omit<ToasterToast, "id">
|
export type Toast = Omit<ToasterToast, "id">
|
||||||
|
|
||||||
function toast(props: Toast) {
|
function toast(props: Toast) {
|
||||||
const id = genId()
|
const id = genId()
|
||||||
|
|||||||
@@ -31,9 +31,11 @@ export const translations: LanguageDict = {
|
|||||||
'maps.search': 'Rechercher la carte',
|
'maps.search': 'Rechercher la carte',
|
||||||
'maps.searchPlaceholder': "Ville, point d'intérêt…",
|
'maps.searchPlaceholder': "Ville, point d'intérêt…",
|
||||||
'maps.closeSearch': 'Enlever le filtre',
|
'maps.closeSearch': 'Enlever le filtre',
|
||||||
|
'maps.copyCoords': 'Copier les coordonnées',
|
||||||
'maps.markers.new': 'Nouveau marqueur',
|
'maps.markers.new': 'Nouveau marqueur',
|
||||||
'maps.markers.addPersonal': 'Ajouter un marqueur personnel',
|
'maps.markers.addPersonal': 'Ajouter un marqueur personnel',
|
||||||
'maps.markers.newNotice': "Le marqueur sera sauvegardé mais n'apparaîtra que sur votre carte !"
|
'maps.markers.newNotice': "Le marqueur sera sauvegardé mais n'apparaîtra que sur votre carte !",
|
||||||
|
'toast.copyCoords.description': 'Les coordonnées ont été copiées dans le presse-papiers !'
|
||||||
},
|
},
|
||||||
'en': {
|
'en': {
|
||||||
'lang.fr': 'Français',
|
'lang.fr': 'Français',
|
||||||
@@ -61,8 +63,10 @@ export const translations: LanguageDict = {
|
|||||||
'maps.search': 'Search the map',
|
'maps.search': 'Search the map',
|
||||||
'maps.searchPlaceholder': "City, point of interest…",
|
'maps.searchPlaceholder': "City, point of interest…",
|
||||||
'maps.closeSearch': 'Remove filter',
|
'maps.closeSearch': 'Remove filter',
|
||||||
|
'maps.copyCoords': 'Copy coordinates',
|
||||||
'maps.markers.new': 'New marker',
|
'maps.markers.new': 'New marker',
|
||||||
'maps.markers.addPersonal': 'Add a personal marker',
|
'maps.markers.addPersonal': 'Add a personal marker',
|
||||||
'maps.markers.newNotice': "The marker will be saved but will only appear on your map!"
|
'maps.markers.newNotice': "The marker will be saved but will only appear on your map!",
|
||||||
|
'toast.copyCoords.description': 'Coordinates have been copied to your clipboard !'
|
||||||
}
|
}
|
||||||
} as const;
|
} as const;
|
||||||
|
|||||||
Reference in New Issue
Block a user