diff --git a/.env.example b/.env.example index e84f494..749786e 100644 --- a/.env.example +++ b/.env.example @@ -66,3 +66,9 @@ MAIL_CONTACT_REMARK="equipe.web@ldc.fr" MAIL_CONTACT_SPONSORING="equipe.web@ldc.fr" MAIL_CONTACT_SERVICE="equipe.web@ldc.fr" MAIL_CONTACT_OTHER="equipe.web@ldc.fr" + +# GOOGLE +# - RECAPTCHA +GOOGLE_RECAPTCHA_PUBLIC= +GOOGLE_RECAPTCHA_PRIVATE= +GOOGLE_RECAPTCHA_VERSION= diff --git a/app/Http/Controllers/Fo/StaticPageController.php b/app/Http/Controllers/Fo/StaticPageController.php index 159731d..de72f36 100644 --- a/app/Http/Controllers/Fo/StaticPageController.php +++ b/app/Http/Controllers/Fo/StaticPageController.php @@ -71,25 +71,37 @@ class StaticPageController extends Controller $staticPageModel = StaticPage::query()->where('type', StaticPageType::unveil)->first(); $sectionModels = Section::query()->where('page_id', $staticPageModel->id)->get(); $historicalMilestoneModels = HistoricalMilestone::query()->orderBy('year', 'ASC')->get(); - $siteModel = Site::query()->first(); - $keySection = $sectionModels->where('section', PageSectionEnum::unveil_pole)->first(); - $missionsSection = $sectionModels->where('section', PageSectionEnum::unveil_missions)->first(); - $localSection = $sectionModels->where('section', PageSectionEnum::unveil_local)->first(); - $siteSection = $sectionModels->where('section', PageSectionEnum::unveil_sites)->first(); - $historySection = $sectionModels->where('section', PageSectionEnum::unveil_history)->first(); - $commitmentSection = $sectionModels->where('section', PageSectionEnum::unveil_commitments)->first(); + /** @var \Illuminate\Database\Eloquent\Collection<\App\Models\Site> */ + $siteModelList = Site::query()->orderBy('order')->get(); + $keySection = $sectionModels->where('section', PageSectionEnum::unveil_pole)->first(); + $missionsSection = $sectionModels->where('section', PageSectionEnum::unveil_missions)->first(); + $localSection = $sectionModels->where('section', PageSectionEnum::unveil_local)->first(); + $siteSection = $sectionModels->where('section', PageSectionEnum::unveil_sites)->first(); + $historySection = $sectionModels->where('section', PageSectionEnum::unveil_history)->first(); + $commitmentSection = $sectionModels->where('section', PageSectionEnum::unveil_commitments)->first(); + + // * Calcul Viewbox leaflet map. + $viewBox = (object)[ + // @phpstan-ignore-next-line + 'lat' => \round($siteModelList->sum(fn (Site $siteModel) => + $siteModel->latitude) / $siteModelList->count(), 6), + // @phpstan-ignore-next-line + 'lng' => \round($siteModelList->sum(fn (Site $siteModel) => + $siteModel->longitude) / $siteModelList->count(), 6) + ]; return view('fo.pages.unveil', compact( + 'viewBox', 'staticPageModel', 'sectionModels', 'historicalMilestoneModels', - 'siteModel', + 'siteModelList', 'keySection', 'missionsSection', 'localSection', 'siteSection', 'historySection', - 'commitmentSection', + 'commitmentSection' )); } @@ -269,4 +281,4 @@ class StaticPageController extends Controller 'nextSiteModel' => $nextSiteModel ]); } -} +} \ No newline at end of file diff --git a/app/Http/Middleware/SecureHeaders.php b/app/Http/Middleware/SecureHeaders.php index 98ebfdd..3429977 100644 --- a/app/Http/Middleware/SecureHeaders.php +++ b/app/Http/Middleware/SecureHeaders.php @@ -59,6 +59,8 @@ class SecureHeaders 'https://yl.s-web.fr' ]) . ';', "img-src 'self' data: blob: " . implode(' ', [ + // * Leaftlet With OpenStreetmaps + 'https://tile.openstreetmap.org', // * VITE DEV config('app.debug') ? "https://{$host}:4443" : '', ]) . ';', @@ -66,7 +68,6 @@ class SecureHeaders "frame-src 'self' " . implode(' ', [ 'https://www.google.com/recaptcha/', 'https://recaptcha.google.com/recaptcha/', - 'https://www.google.com/maps/', 'https://www.youtube.com', ]) . ';', "font-src 'self' data: " . \implode(' ', [ diff --git a/artisan b/artisan old mode 100755 new mode 100644 diff --git a/package-lock.json b/package-lock.json index 7ee3791..5e6cc8f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,11 +13,10 @@ "@fortawesome/free-regular-svg-icons": "^6.5.1", "@fortawesome/free-solid-svg-icons": "^6.5.1", "@fortawesome/vue-fontawesome": "^3.0.5", - "@googlemaps/js-api-loader": "^1.16.6", "@ldc-web/cookie-notice": "^4.0.1", "@sipec/vue3-tags-input": "^3.0.4", "@types/bootstrap": "^5.2.7", - "@types/google.maps": "^3.55.4", + "@types/leaflet": "^1.9.8", "@types/node": "^20.8.2", "@types/toastify-js": "^1.12.1", "@typescript-eslint/eslint-plugin": "^5.62.0", @@ -37,6 +36,9 @@ "eslint-plugin-vue": "latest", "fslightbox": "^3.4.1", "laravel-vite-plugin": "^0.8.1", + "leaflet": "^1.9.4", + "leaflet.fullscreen": "^3.0.1", + "overlapping-marker-spiderfier-leaflet": "^0.2.7", "postcss-discard-comments": "^6.0.0", "prettier": "latest", "print-js": "^1.6.0", @@ -54,6 +56,7 @@ "terser": "latest", "toastify-js": "^1.12.0", "ts-loader": "^9.3.1", + "ts-overlapping-marker-spiderfier": "^1.0.3", "typescript": ">=3.3.1 <5.2.0", "typescript-eslint": "latest", "vite": "^4.5.1", @@ -968,15 +971,6 @@ "vue": ">= 3.0.0 < 4" } }, - "node_modules/@googlemaps/js-api-loader": { - "version": "1.16.6", - "resolved": "https://registry.npmjs.org/@googlemaps/js-api-loader/-/js-api-loader-1.16.6.tgz", - "integrity": "sha512-V8p5W9DbPQx74jWUmyYJOerhiB4C+MHekaO0ZRmc6lrOYrvY7+syLhzOWpp55kqSPeNb+qbC2h8i69aLIX6krQ==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.3" - } - }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.14", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", @@ -1195,6 +1189,12 @@ "@types/node": "*" } }, + "node_modules/@types/geojson": { + "version": "7946.0.14", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.14.tgz", + "integrity": "sha512-WCfD5Ht3ZesJUsONdhvm84dmzWOiOzOAqOncN0++w0lBw1o8OuDNJF2McvvCef/yBqb/HYRahp1BYtODFQ8bRg==", + "dev": true + }, "node_modules/@types/glob": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", @@ -1205,10 +1205,11 @@ "@types/node": "*" } }, - "node_modules/@types/google.maps": { - "version": "3.55.4", - "resolved": "https://registry.npmjs.org/@types/google.maps/-/google.maps-3.55.4.tgz", - "integrity": "sha512-Ip3IfRs3RZjeC88V8FGnWQTQXeS5gkJedPSosN6DMi9Xs8buGTpsPq6UhREoZsGH+62VoQ6jiRBUR8R77If69w==", + "node_modules/@types/googlemaps": { + "version": "3.43.3", + "resolved": "https://registry.npmjs.org/@types/googlemaps/-/googlemaps-3.43.3.tgz", + "integrity": "sha512-ZWNoz/O8MPEpiajvj7QiqCY8tTLFNqNZ/a+s+zTV58wFVNAvvqV4bdGfnsjTb5Cs4V6wEsLrX8XRhmnyYJ2Tdg==", + "deprecated": "Types for the Google Maps browser API have moved to @types/google.maps. Note: these types are not for the googlemaps npm package, which is a Node API.", "dev": true }, "node_modules/@types/json-schema": { @@ -1224,6 +1225,15 @@ "dev": true, "peer": true }, + "node_modules/@types/leaflet": { + "version": "1.9.8", + "resolved": "https://registry.npmjs.org/@types/leaflet/-/leaflet-1.9.8.tgz", + "integrity": "sha512-EXdsL4EhoUtGm2GC2ZYtXn+Fzc6pluVgagvo2VC1RHWToLGlTRwVYoDpqS/7QXa01rmDyBjJk3Catpf60VMkwg==", + "dev": true, + "dependencies": { + "@types/geojson": "*" + } + }, "node_modules/@types/minimatch": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", @@ -4984,6 +4994,18 @@ "vite": "^3.0.0 || ^4.0.0" } }, + "node_modules/leaflet": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.9.4.tgz", + "integrity": "sha512-nxS1ynzJOmOlHp+iL3FyWqK89GtNL8U8rvlMOsQdTTssxZwCXh8N2NB3GDQOL+YR3XnWyZAxwQixURb+FA74PA==", + "dev": true + }, + "node_modules/leaflet.fullscreen": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/leaflet.fullscreen/-/leaflet.fullscreen-3.0.1.tgz", + "integrity": "sha512-Lsg49e4AYSjHOhmy+VOm4+O6Urim2UvthydKJI3KzfwC3InYkfvJtv1mWuOb9K7qG4H2MtEut09Dz6noQyJARQ==", + "dev": true + }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -5506,6 +5528,12 @@ "node": ">= 0.8.0" } }, + "node_modules/overlapping-marker-spiderfier-leaflet": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/overlapping-marker-spiderfier-leaflet/-/overlapping-marker-spiderfier-leaflet-0.2.7.tgz", + "integrity": "sha512-U2biV2Ge0SU+4IEmq4BZOglvzA8Aj8G7/hp5v6lBnF9Kd3/Xf6ZEPsJyPOExtLvMxOqlrlTAfl55s6JJDND7Ew==", + "dev": true + }, "node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -7524,6 +7552,15 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, + "node_modules/ts-overlapping-marker-spiderfier": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/ts-overlapping-marker-spiderfier/-/ts-overlapping-marker-spiderfier-1.0.3.tgz", + "integrity": "sha512-WqA+tpJHZHpGS8fL1C/cOPue72doG2yfNoxK7cUuLwH108hoQkjd6R52c3hYiFdVc1UvGuA/wXzAJYXPi+L9YQ==", + "dev": true, + "dependencies": { + "@types/googlemaps": "^3.30.7" + } + }, "node_modules/tsconfig-paths": { "version": "3.15.0", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", diff --git a/package.json b/package.json index f6dc1c0..ee33602 100644 --- a/package.json +++ b/package.json @@ -21,11 +21,10 @@ "@fortawesome/free-regular-svg-icons": "^6.5.1", "@fortawesome/free-solid-svg-icons": "^6.5.1", "@fortawesome/vue-fontawesome": "^3.0.5", - "@googlemaps/js-api-loader": "^1.16.6", "@ldc-web/cookie-notice": "^4.0.1", "@sipec/vue3-tags-input": "^3.0.4", "@types/bootstrap": "^5.2.7", - "@types/google.maps": "^3.55.4", + "@types/leaflet": "^1.9.8", "@types/node": "^20.8.2", "@types/toastify-js": "^1.12.1", "@typescript-eslint/eslint-plugin": "^5.62.0", @@ -45,6 +44,9 @@ "eslint-plugin-vue": "latest", "fslightbox": "^3.4.1", "laravel-vite-plugin": "^0.8.1", + "leaflet": "^1.9.4", + "leaflet.fullscreen": "^3.0.1", + "overlapping-marker-spiderfier-leaflet": "^0.2.7", "postcss-discard-comments": "^6.0.0", "prettier": "latest", "print-js": "^1.6.0", @@ -62,6 +64,7 @@ "terser": "latest", "toastify-js": "^1.12.0", "ts-loader": "^9.3.1", + "ts-overlapping-marker-spiderfier": "^1.0.3", "typescript": ">=3.3.1 <5.2.0", "typescript-eslint": "latest", "vite": "^4.5.1", diff --git a/resources/lang/fr/models.php b/resources/lang/fr/models.php index 188a00e..84209d7 100644 --- a/resources/lang/fr/models.php +++ b/resources/lang/fr/models.php @@ -8,7 +8,7 @@ return [ 'section' => 'section', 'news' => 'actualité', 'site' => 'site', - 'logo' => 'logo', + 'logo' => 'logo de marques', 'historicalMilestone' => 'jalon historique|jalons historiques', 'slide' => 'slide', 'job_video' => 'vidéo métier|vidéos métiers', diff --git a/resources/lang/fr/validation.php b/resources/lang/fr/validation.php index 9b2a3ad..3e9bb1e 100644 --- a/resources/lang/fr/validation.php +++ b/resources/lang/fr/validation.php @@ -224,6 +224,8 @@ return [ ], 'youtube_id' => ':attribute doit être un ID de vidéo Youtube valide', 'vimeo_id' => ':attribute doit être un ID de vidéo Vimeo valide', + 'latitude' => 'Latitude entre -90 et 90 - ex : 48.858502757201', + 'longitude' => 'Longitude entre -180 et 180 - ex : 2.2944636160339', 'custom' => [ 'of_the' => [ 'male' => 'du ', diff --git a/resources/sass/fo/base/_layout.scss b/resources/sass/fo/base/_layout.scss index 81a437e..fd6578f 100644 --- a/resources/sass/fo/base/_layout.scss +++ b/resources/sass/fo/base/_layout.scss @@ -176,7 +176,7 @@ body { > header { position: fixed; - z-index: 50; + z-index: 10001; top: 0; left: 0; width: 100%; diff --git a/resources/sass/fo/fo.scss b/resources/sass/fo/fo.scss index 966401b..6083b66 100644 --- a/resources/sass/fo/fo.scss +++ b/resources/sass/fo/fo.scss @@ -8,6 +8,7 @@ @import "./vendor/bootstrap"; @import "./vendor/swiper"; @import "./vendor/cookie-notice"; +@import "leaflet"; // * BASE @import "./base/bootstrap-overload"; diff --git a/resources/ts/fo/components/LeafletMapVueComponent.vue b/resources/ts/fo/components/LeafletMapVueComponent.vue new file mode 100644 index 0000000..6c869d7 --- /dev/null +++ b/resources/ts/fo/components/LeafletMapVueComponent.vue @@ -0,0 +1,233 @@ + + + + + + + diff --git a/resources/ts/fo/utilities/fontawesome.ts b/resources/ts/fo/utilities/fontawesome.ts index 0a1ccb0..e15d068 100644 --- a/resources/ts/fo/utilities/fontawesome.ts +++ b/resources/ts/fo/utilities/fontawesome.ts @@ -15,7 +15,8 @@ import { faPlay, faPlus, faQuestionCircle, - faUserGroup + faUserGroup, + faUsers } from "@fortawesome/free-solid-svg-icons"; config.autoReplaceSvg = false; @@ -35,5 +36,6 @@ library.add(faMinus); library.add(faPlus); library.add(faPlay); library.add(faPause); +library.add(faUsers); dom.watch(); diff --git a/resources/ts/utilities/sass-safelist.ts b/resources/ts/utilities/sass-safelist.ts index c55f5a1..a06ab57 100644 --- a/resources/ts/utilities/sass-safelist.ts +++ b/resources/ts/utilities/sass-safelist.ts @@ -11,6 +11,13 @@ const sassSafelist: UserDefinedSafelist = [ /^bs-popover/, /^popover/, /^bg-.*/, + /^img-.*/, + // * Fonts + /^f-.*/, + // * Leaflet + /^leaflet-.*/, + // * Leaflet Fullscreen plugin + /^fullscreen-icon$/, // Vue /-(leave|enter|appear)(|-(to|from|active))$/, /^(?!(|.*?:)cursor-move).+-move$/, diff --git a/resources/views/bo/pages/sites/form.blade.php b/resources/views/bo/pages/sites/form.blade.php index 5365026..05eb2a2 100644 --- a/resources/views/bo/pages/sites/form.blade.php +++ b/resources/views/bo/pages/sites/form.blade.php @@ -503,7 +503,7 @@ 'name' => 'longitude', 'required' => true, 'model' => $siteModel ?? null, - 'helper' => __('crud.helpers.longitude'), + 'helper' => __('validation.longitude'), ]) diff --git a/resources/views/fo/pages/unveil.blade.php b/resources/views/fo/pages/unveil.blade.php index f70a76c..d3f67bb 100644 --- a/resources/views/fo/pages/unveil.blade.php +++ b/resources/views/fo/pages/unveil.blade.php @@ -18,10 +18,12 @@ @section('content')
{{-- KEY NUMBERS --}} -
-
-
-

{{ $keySection->h2_title }}

+
+
+
+
+

{{ $keySection->h2_title }}

+
@@ -103,14 +105,23 @@
@endif
-
- {{-- FIXME: remplacer map --}} -
- -
+
+ @php + $data = [ + 'wrapperClasses' => 'rounded-3 embed-map w-100 my-3', + 'coordinates' => [ + 'lat' => $viewBox->lat, + 'lng' => $viewBox->lng, + ], + 'siteModelList' => $siteModelList, + ]; + @endphp +
+ {{-- FIXME: Quelles coordonnées pour la map ? --}} + {{-- --}}