Merge branch 'dev'
This commit is contained in:
12
package.json
12
package.json
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "leim-maps",
|
"name": "leim-maps",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"version": "1.4.9",
|
"version": "1.4.10",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "astro dev",
|
"dev": "astro dev",
|
||||||
"start": "astro dev",
|
"start": "astro dev",
|
||||||
@@ -10,18 +10,18 @@
|
|||||||
"astro": "astro"
|
"astro": "astro"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@astrojs/sitemap": "^3.4.0",
|
"@astrojs/sitemap": "^3.4.1",
|
||||||
"@astrojs/vue": "^5.1.0",
|
"@astrojs/vue": "^5.1.0",
|
||||||
"@nanostores/persistent": "1.0.0",
|
"@nanostores/persistent": "1.0.0",
|
||||||
"@nanostores/vue": "^1.0.0",
|
"@nanostores/vue": "^1.0.0",
|
||||||
"@types/leaflet": "^1.9.18",
|
"@types/leaflet": "^1.9.18",
|
||||||
"@vueuse/core": "^13.2.0",
|
"@vueuse/core": "^13.3.0",
|
||||||
"astro": "^5.8.0",
|
"astro": "^5.9.3",
|
||||||
"nanostores": "^1.0.1",
|
"nanostores": "^1.0.1",
|
||||||
"radix-vue": "^1.9.17",
|
"radix-vue": "^1.9.17",
|
||||||
"vue": "^3.5.14"
|
"vue": "^3.5.16"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"sass": "^1.89.0"
|
"sass": "^1.89.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
1173
pnpm-lock.yaml
generated
1173
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
1
public/icon/question-mark.svg
Normal file
1
public/icon/question-mark.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256"><path d="M140,180a12,12,0,1,1-12-12A12,12,0,0,1,140,180ZM128,72c-22.06,0-40,16.15-40,36v4a8,8,0,0,0,16,0v-4c0-11,10.77-20,24-20s24,9,24,20-10.77,20-24,20a8,8,0,0,0-8,8v8a8,8,0,0,0,16,0v-.72c18.24-3.35,32-17.9,32-35.28C168,88.15,150.06,72,128,72Zm104,56A104,104,0,1,1,128,24,104.11,104.11,0,0,1,232,128Zm-16,0a88,88,0,1,0-88,88A88.1,88.1,0,0,0,216,128Z"></path></svg>
|
||||||
|
After Width: | Height: | Size: 428 B |
@@ -76,7 +76,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
&.btn-shadow {
|
&.btn-shadow {
|
||||||
box-shadow: rgba(0, 0, 0, 0.15) 0 .2rem .3rem;
|
box-shadow: color-mix(in srgb, var(--black) 10%, transparent) 0 .2rem .3rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,7 +87,7 @@
|
|||||||
aspect-ratio: 1;
|
aspect-ratio: 1;
|
||||||
background-color: var(--white);
|
background-color: var(--white);
|
||||||
border: 1px solid var(--slate-400);
|
border: 1px solid var(--slate-400);
|
||||||
box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 12px;
|
box-shadow: color-mix(in srgb, var(--black) 10%, transparent) 0px 4px 12px;
|
||||||
border-radius: 100vmax;
|
border-radius: 100vmax;
|
||||||
pointer-events: all;
|
pointer-events: all;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
background-color: var(--white);
|
background-color: var(--white);
|
||||||
border: 1px solid var(--slate-100);
|
border: 1px solid var(--slate-100);
|
||||||
box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 12px;
|
box-shadow: color-mix(in srgb, var(--black) 10%, transparent) 0px 4px 12px;
|
||||||
min-width: 15rem;
|
min-width: 15rem;
|
||||||
|
|
||||||
.card-arrow {
|
.card-arrow {
|
||||||
|
|||||||
80
src/assets/scss/radix/_dialog.scss
Normal file
80
src/assets/scss/radix/_dialog.scss
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
.dialog-overlay {
|
||||||
|
background-color: color-mix(in srgb, var(--black) 40%, transparent);
|
||||||
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
|
animation: show-overlay 150ms cubic-bezier(0.16, 1, 0.3, 1);
|
||||||
|
z-index: 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-content {
|
||||||
|
position: fixed;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
z-index: 200;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
width: 50rem;
|
||||||
|
max-width: calc(100% - 4rem);
|
||||||
|
max-height: 85vh;
|
||||||
|
padding: 25px;
|
||||||
|
border-radius: 8px;
|
||||||
|
background-color: var(--white);
|
||||||
|
border: 1px solid var(--slate-100);
|
||||||
|
box-shadow: color-mix(in srgb, var(--black) 10%, transparent) 0px 4px 12px;
|
||||||
|
animation: show-content 150ms cubic-bezier(0.16, 1, 0.3, 1);
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-title {
|
||||||
|
margin-bottom: .5em;
|
||||||
|
font-size: 1.5em;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-description {
|
||||||
|
h3 {
|
||||||
|
font-size: 1.25em;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
font-size: 1em;
|
||||||
|
color: var(--slate-800);
|
||||||
|
line-height: 1.5;
|
||||||
|
|
||||||
|
> * + * {
|
||||||
|
margin-top: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
text-underline-offset: 2px;
|
||||||
|
text-decoration: underline;
|
||||||
|
|
||||||
|
&:hover,
|
||||||
|
&:focus-visible {
|
||||||
|
text-decoration: none;
|
||||||
|
color: var(--green-500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes show-overlay {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes show-content {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translate(-50%, -48%) scale(0.96);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translate(-50%, -50%) scale(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,6 +10,7 @@
|
|||||||
@use 'map';
|
@use 'map';
|
||||||
|
|
||||||
@use 'radix/toast';
|
@use 'radix/toast';
|
||||||
|
@use 'radix/dialog';
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
--white: #fff;
|
--white: #fff;
|
||||||
@@ -56,6 +57,10 @@ a[href^='http']::after {
|
|||||||
margin-left: .25em;
|
margin-left: .25em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
strong {
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
.icon {
|
.icon {
|
||||||
width: 1em;
|
width: 1em;
|
||||||
}
|
}
|
||||||
@@ -1,22 +1,36 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, onUpdated, ref, watch } from 'vue';
|
import { computed, onUpdated, ref, watch } from 'vue'
|
||||||
import { useElementHover, useFocus } from '@vueuse/core'
|
import { useElementHover, useFocus } from '@vueuse/core'
|
||||||
import { PopoverArrow, PopoverContent, PopoverRoot, PopoverTrigger } from 'radix-vue'
|
import {
|
||||||
import { useStore } from '@nanostores/vue';
|
PopoverArrow,
|
||||||
|
PopoverContent,
|
||||||
|
PopoverRoot,
|
||||||
|
PopoverTrigger,
|
||||||
|
DialogContent,
|
||||||
|
DialogDescription,
|
||||||
|
DialogOverlay,
|
||||||
|
DialogPortal,
|
||||||
|
DialogRoot,
|
||||||
|
DialogTitle,
|
||||||
|
DialogTrigger
|
||||||
|
} from 'radix-vue'
|
||||||
|
|
||||||
import { currentLang } from '@/i18n/store';
|
import { useStore } from '@nanostores/vue'
|
||||||
import { t } from '@/i18n/store';
|
|
||||||
|
|
||||||
const $currentLang = useStore(currentLang);
|
import { currentLang } from '@/i18n/store'
|
||||||
|
import { t } from '@/i18n/store'
|
||||||
|
|
||||||
const navModel = ref(false);
|
const $currentLang = useStore(currentLang)
|
||||||
|
|
||||||
|
const navModel = ref(false)
|
||||||
|
const legalModelOpened = ref(false)
|
||||||
|
|
||||||
const wrapper = ref<HTMLDivElement | null>(null)
|
const wrapper = ref<HTMLDivElement | null>(null)
|
||||||
const buttonRef = ref<HTMLButtonElement | null>(null)
|
const buttonRef = ref<HTMLButtonElement | null>(null)
|
||||||
const wrapperHovered = useElementHover(wrapper, { delayEnter: 100, delayLeave: 500 })
|
const wrapperHovered = useElementHover(wrapper, { delayEnter: 100, delayLeave: 500 })
|
||||||
const { focused: buttonFocused } = useFocus(buttonRef)
|
const { focused: buttonFocused } = useFocus(buttonRef)
|
||||||
|
|
||||||
const isNavOpened = computed(() => navModel.value || wrapperHovered.value)
|
const isNavOpened = computed(() => navModel.value || wrapperHovered.value || legalModelOpened.value )
|
||||||
|
|
||||||
watch([wrapperHovered, buttonFocused], (value) => {
|
watch([wrapperHovered, buttonFocused], (value) => {
|
||||||
// Check if all values from array are false
|
// Check if all values from array are false
|
||||||
@@ -25,7 +39,7 @@ watch([wrapperHovered, buttonFocused], (value) => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
let url: URL | null = null;
|
let url: URL | null = null
|
||||||
|
|
||||||
onUpdated(() => {
|
onUpdated(() => {
|
||||||
url = new URL(window.location.href)
|
url = new URL(window.location.href)
|
||||||
@@ -130,6 +144,26 @@ const menus: Menu[] = [
|
|||||||
</li>
|
</li>
|
||||||
</menu>
|
</menu>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<div class="legal">
|
||||||
|
<DialogRoot v-model:open="legalModelOpened">
|
||||||
|
<DialogTrigger as-child>
|
||||||
|
<button :href="`/${$currentLang}/legal`">
|
||||||
|
{{ t('legal.cta') }}
|
||||||
|
</button>
|
||||||
|
</DialogTrigger>
|
||||||
|
<DialogPortal>
|
||||||
|
<DialogOverlay class="dialog-overlay" />
|
||||||
|
|
||||||
|
<DialogContent class="dialog-content">
|
||||||
|
<DialogTitle class="dialog-title">
|
||||||
|
{{ t('legal.cta') }}
|
||||||
|
</DialogTitle>
|
||||||
|
<DialogDescription class="dialog-description" v-html="t('legal.text')" />
|
||||||
|
</DialogContent>
|
||||||
|
</DialogPortal>
|
||||||
|
</DialogRoot>
|
||||||
|
</div>
|
||||||
</PopoverContent>
|
</PopoverContent>
|
||||||
</PopoverRoot>
|
</PopoverRoot>
|
||||||
</div>
|
</div>
|
||||||
@@ -151,6 +185,34 @@ const menus: Menu[] = [
|
|||||||
margin-left: .25rem;
|
margin-left: .25rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.legal {
|
||||||
|
margin-top: 1em;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
width: fit-content;
|
||||||
|
font-size: .8em;
|
||||||
|
text-underline-offset: 2px;
|
||||||
|
text-decoration: underline;
|
||||||
|
gap: .5ch;
|
||||||
|
|
||||||
|
button {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover,
|
||||||
|
&:focus-visible {
|
||||||
|
text-decoration: none;
|
||||||
|
color: var(--green-500);
|
||||||
|
}
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
content: url('/icon/question-mark.svg');
|
||||||
|
display: inline-block;
|
||||||
|
width: 1em;
|
||||||
|
height: 1em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.map-menu {
|
.map-menu {
|
||||||
margin-top: .25rem;
|
margin-top: .25rem;
|
||||||
margin-bottom: .5rem;
|
margin-bottom: .5rem;
|
||||||
|
|||||||
@@ -35,7 +35,19 @@ export const translations: LanguageDict = {
|
|||||||
'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 !'
|
'toast.copyCoords.description': 'Les coordonnées ont été copiées dans le presse-papiers !',
|
||||||
|
'legal.cta': 'Mentions légales',
|
||||||
|
'legal.text': `
|
||||||
|
<p>Cette application est construite avec <a href="https://astro.build/" target="_blank">astro</a>, <a href="https://leafletjs.com/" target="_blank">leaflet</a> et <a href="https://vuejs.org/" target="_blank">vue</a>. J'utilise également des icônes de <a href="https://phosphoricons.com/" target="_blank">phosphor</a> et elle est actuellement hébergée sur <a href="https://www.ovhcloud.com" target="_blank">OVH</a>.</p>
|
||||||
|
<p>En ce qui concerne les œuvres d'art que j'utilise sur les marqueurs, j'essaie de les trouver du mon mieux sur internet. Si vous connaissez la source originale d'une œuvre d'art, veuillez me contacter par mail.</p>
|
||||||
|
<p>Je n'inclus pas d'images d'IA car <strong>je suis farouchement opposé à l'IA générative</strong> pour la création de contenu. Si vous voyez une image qui semble être de l'IA sur ce site, faites-le moi savoir immédiatement.</p>
|
||||||
|
<h3>Données personelles</h3>
|
||||||
|
<p>Je ne collecte aucune donnée sur votre activité dans cette application. Les marqueurs personnalisés que vous pouvez placer n'existent que sur votre navigateur en tant que données de <a href="https://developer.mozilla.org/fr/docs/Web/API/Window/localStorage" target="_blank">local storage</a>.</p>
|
||||||
|
<p>Mon hébergeur collecte des données de trafic pour des raisons de sécurité ; comme les adresses IP et leur emplacement approximatif, les types de navigateurs, les agents utilisateurs (si vous êtes un robot ou un humain) et l'état de la demande. </p>
|
||||||
|
<p>Ce site n'utilise pas de pixels de suivi ou d'analyse, et je n'utilise aucune autre application tierce qui pourrait collecter des données sur vous (comme Youtube ou autre)</p>
|
||||||
|
<p>Malgré cela, <strong>aucune de vos données n'est vendue ou transmise à un tiers quel qu'il soit</strong>.</p>
|
||||||
|
<p>Si vous avez des questions, vous pouvez me contacter à <a href="mailto:contact@alexcreates.fr">contact@alexcreates.fr</a>.</p>
|
||||||
|
`
|
||||||
},
|
},
|
||||||
'en': {
|
'en': {
|
||||||
'lang.fr': 'Français',
|
'lang.fr': 'Français',
|
||||||
@@ -67,6 +79,18 @@ export const translations: LanguageDict = {
|
|||||||
'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 !'
|
'toast.copyCoords.description': 'Coordinates have been copied to your clipboard !',
|
||||||
|
'legal.cta': 'Legal notice',
|
||||||
|
'legal.text': `
|
||||||
|
<p>This app is built with <a href="https://astro.build/" target="_blank">astro</a>, <a href="https://leafletjs.com/" target="_blank">leaflet</a> and <a href="https://vuejs.org/" target="_blank">vue</a>. I also use icons from <a href="https://phosphoricons.com/" target="_blank">phosphor</a> and it's currently hosted on <a href="https://www.ovhcloud.com" target="_blank">OVH</a>.</p>
|
||||||
|
<p>For the artworks I use on the markers, I try to source them to the best of my knowledge, from what I can scrap off the internet. If you know the original source of an artwork, please contact me by email.</p>
|
||||||
|
<p>I don't include AI images as <strong>I'm vehemently opposed to generative AI</strong> for content creation. If you see an image that looks like it might be AI on this site, let me know immediately.</p>
|
||||||
|
<h3>Privacy</h3>
|
||||||
|
<p>I don't collect any data of your activity with this app. The custom markers that you may place only exist on your browser as <a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage" target="_blank">local storage</a> data.</p>
|
||||||
|
<p>My hosting provider collects traffic data for security reasons ; like IP addresses and their approximate location, browsers types, user agents (if you're a robot or a human) and the request status.</p>
|
||||||
|
<p>This website doesn't use any tracking pixels or analytics, and I don't use any other third-party app that might collect stuff from you (like Youtube or anything else)</p>
|
||||||
|
<p>Regardless, <strong>none of your data is sold or passed to any third-party whatsoever</strong>.</p>
|
||||||
|
<p>If you have any questions, you can contact me at <a href="mailto:contact@alexcreates.fr">contact@alexcreates.fr</a>.</p>
|
||||||
|
`
|
||||||
}
|
}
|
||||||
} as const;
|
} as const;
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ export interface SearchConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface MapProps {
|
export interface MapProps {
|
||||||
|
title?: string
|
||||||
/**
|
/**
|
||||||
* The ID of the map.
|
* The ID of the map.
|
||||||
* This is used to identify the map and store custom markers in the local storage.
|
* This is used to identify the map and store custom markers in the local storage.
|
||||||
|
|||||||
Reference in New Issue
Block a user