]> git.localhorst.tv Git - alttp.git/commitdiff
store map position in history
authorDaniel Karbach <daniel.karbach@localhorst.tv>
Wed, 12 Jul 2023 09:16:33 +0000 (11:16 +0200)
committerDaniel Karbach <daniel.karbach@localhorst.tv>
Wed, 12 Jul 2023 09:16:33 +0000 (11:16 +0200)
app/Http/Controllers/SitemapXmlController.php
resources/js/components/app/Header.js
resources/js/components/app/index.js
resources/js/components/map/Item.js
resources/js/components/map/OpenSeadragon.js
resources/js/components/map/Pin.js
resources/js/components/pages/Map.js
resources/views/sitemap.blade.php

index 99e909212f2bbced0371e0b9c01f9f6ea9e00684..4393a30c0f88cdc0ecd6ff80587cf9fb529d74dd 100644 (file)
@@ -23,12 +23,17 @@ class SitemapXmlController extends Controller
                        $urls[] = $url;
                }
 
-               $url = new SitemapUrl();
-               $url->path = '/map';
-               $url->lastmod = TechniqueMap::latest()->first()->created_at;
-               $url->changefreq = 'monthly';
-               $url->priority = 0.9;
-               $urls[] = $url;
+               foreach (['lw', 'dw', 'sp', 'uw'] as $map) {
+                       $tech = TechniqueMap::where('map', '=', $map)->latest()->first();
+                       $url = new SitemapUrl();
+                       $url->path = '/map/'.$map;
+                       if ($tech) {
+                               $url->lastmod = $tech->created_at;
+                       }
+                       $url->changefreq = 'monthly';
+                       $url->priority = 0.9;
+                       $urls[] = $url;
+               }
 
                $url = new SitemapUrl();
                $url->path = '/tech';
index db59b40bf4844cbf41362f03f62380fec84249c4..f806bbc7ddeaf38f575c2d7ec0b8ca85aed07b46 100644 (file)
@@ -39,8 +39,8 @@ const Header = ({ doLogout, user }) => {
                                                {t('menu.tech')}
                                        </Nav.Link>
                                </LinkContainer>
-                               <LinkContainer to="/map">
-                                       <Nav.Link href="/map">
+                               <LinkContainer to="/map/lw">
+                                       <Nav.Link href="/map/lw">
                                                {t('menu.map')}
                                        </Nav.Link>
                                </LinkContainer>
index e8a56e63b681f2ea5b24f4aa2d763122cbcd924c..e7298d7b00a327be31f58f6b9540943728feb758 100644 (file)
@@ -87,7 +87,10 @@ const App = () => {
                                                        path="locations/:name"
                                                        element={<Technique namespace="locations" type="location" />}
                                                />
-                                               <Route path="map" element={<Map />} />
+                                               <Route path="map">
+                                                       <Route index element={<Navigate replace to="lw" />} />
+                                                       <Route path=":activeMap" element={<Map />} />
+                                               </Route>
                                                <Route
                                                        path="modes"
                                                        element={<Techniques namespace="modes" type="mode" />}
index 4bd209acbcb8e617605040d65e0a5dcb3589c060..a29443bac3bb8f2eda5bd391407ddc4505e10937 100644 (file)
@@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
 import React from 'react';
 import { Button } from 'react-bootstrap';
 import { useTranslation } from 'react-i18next';
-import { Link } from 'react-router-dom';
+import { Link, useSearchParams } from 'react-router-dom';
 
 import { useOpenSeadragon } from './OpenSeadragon';
 import Icon from '../common/Icon';
@@ -19,12 +19,12 @@ import i18n from '../../i18n';
 
 const Item = ({ pin }) => {
        const { viewer } = useOpenSeadragon();
+       const [, setSearchParams] = useSearchParams();
        const { t } = useTranslation();
 
        const goToLocation = React.useCallback(pin => {
-               if (viewer && viewer.viewport) {
-                       viewer.viewport.panTo(new OpenSeadragon.Point(pin.x, pin.y));
-                       viewer.viewport.zoomTo(4);
+               setSearchParams({ x: pin.x, y: pin.y, z: 4 });
+               if (viewer && viewer.element) {
                        viewer.element.scrollIntoView();
                }
        }, [viewer]);
index b6158a5aea79ca3a03f964deb4f5dc413cfa52c0..52c0506b13fc8ffa89214431562cde8158c29417 100644 (file)
@@ -2,16 +2,54 @@ import axios from 'axios';
 import OpenSeadragon from 'openseadragon';
 import PropTypes from 'prop-types';
 import React from 'react';
+import { useNavigate, useParams } from 'react-router';
+import { createSearchParams, useSearchParams } from 'react-router-dom';
 
 export const Context = React.createContext({});
 
 export const useOpenSeadragon = () => React.useContext(Context);
 
 export const Provider = React.forwardRef(({ children }, ref) => {
-       const [activeMap, setActiveMap] = React.useState('lw');
+       const { activeMap } = useParams();
+       const navigate = useNavigate();
+       const [searchParams, setSearchParams] = useSearchParams();
        const [pins, setPins] = React.useState([]);
        const [viewer, setViewer] = React.useState(null);
 
+       const storePosition = React.useCallback(() => {
+               if (!viewer || !viewer.viewport) return;
+               const center = viewer.viewport.getCenter();
+               const zoom = viewer.viewport.getZoom();
+               setSearchParams({ x: center.x, y: center.y, z: zoom }, { replace: true });
+       }, [setSearchParams, viewer]);
+
+       const setActiveMap = React.useCallback(map => {
+               if (viewer && viewer.viewport) {
+                       const center = viewer.viewport.getCenter();
+                       const zoom = viewer.viewport.getZoom();
+                       const params = { x: center.x, y: center.y, z: zoom };
+                       navigate(
+                               { pathname: `../${map}`, search: `?${createSearchParams(params)}` },
+                               { replace: true },
+                       );
+               } else {
+                       navigate(`../${map}`, { replace: true });
+               }
+       }, [navigate, viewer]);
+
+       React.useEffect(() => {
+               if (!viewer || !viewer.viewport) return;
+               if (searchParams.has('x') && searchParams.has('y')) {
+                       viewer.viewport.panTo(new OpenSeadragon.Point(
+                               parseFloat(searchParams.get('x')),
+                               parseFloat(searchParams.get('y')),
+                       ));
+               }
+               if (searchParams.has('z')) {
+                       viewer.viewport.zoomTo(parseFloat(searchParams.get('z')));
+               }
+       }, [searchParams, viewer]);
+
        React.useEffect(() => {
                if (!ref.current) return;
 
@@ -99,7 +137,7 @@ export const Provider = React.forwardRef(({ children }, ref) => {
                };
        }, [activeMap, viewer]);
 
-       return <Context.Provider value={{ activeMap, setActiveMap, pins, viewer }}>
+       return <Context.Provider value={{ activeMap, pins, setActiveMap, storePosition, viewer }}>
                {children}
        </Context.Provider>;
 });
index 69b6d77e389eccc9609033a8babb7a03afdac8fa..442e16d638675ba8574bf46316e158fa003da2b9 100644 (file)
@@ -2,6 +2,7 @@ import PropTypes from 'prop-types';
 import React from 'react';
 import { Link, useNavigate } from 'react-router-dom';
 
+import { useOpenSeadragon } from './OpenSeadragon';
 import Overlay from './Overlay';
 import Popover from './Popover';
 import Icon from '../common/Icon';
@@ -9,6 +10,7 @@ import { getLink, getTranslation } from '../../helpers/Technique';
 import i18n from '../../i18n';
 
 const Pin = ({ pin }) => {
+       const { storePosition } = useOpenSeadragon();
        const [showPopover, setShowPopover] = React.useState(false);
        const ref = React.useRef();
 
@@ -17,12 +19,14 @@ const Pin = ({ pin }) => {
        const onClick = React.useCallback((e) => {
                if (ref.current && ref.current.contains(e.originalTarget)) {
                        if (e.originalTarget.tagName === 'A') {
+                               storePosition();
                                navigate(new URL(e.originalTarget.href).pathname);
                        }
                } else {
                        if (pin.technique.type === 'location') {
                                setShowPopover(s => !s);
                        } else {
+                               storePosition();
                                navigate(getLink(pin.technique));
                        }
                }
index 09e381a3af8bcb3c9a2ea67b9c15571dc585495d..3cbd31f6025367f1bb98f3d16f3adc7e8f245cb2 100644 (file)
@@ -2,6 +2,7 @@ import React from 'react';
 import { Container } from 'react-bootstrap';
 import { Helmet } from 'react-helmet';
 import { useTranslation } from 'react-i18next';
+import { useParams } from 'react-router';
 
 import CanonicalLinks from '../common/CanonicalLinks';
 import Buttons from '../map/Buttons';
@@ -13,6 +14,7 @@ import UWSuperTiles from '../map/UWSuperTiles';
 const Map = () => {
        const [uwOverlay, setUWOverlay] = React.useState(false);
 
+       const { activeMap } = useParams();
        const container = React.useRef();
        const { t } = useTranslation();
 
@@ -21,7 +23,7 @@ const Map = () => {
                        <title>{t('map.heading')}</title>
                        <meta name="description" content={t('map.description')} />
                </Helmet>
-               <CanonicalLinks base="/map" />
+               <CanonicalLinks base={`/map/${activeMap}`} />
                <OpenSeadragon ref={container}>
                        <div className="d-flex align-items-start justify-content-between">
                                <h1>{t('map.heading')}</h1>
index f9cf5bf3c8089c2f1cc9d46587aab606e1f13219..375be393fd11a0028a0e8eb9916d4807cf6b29be 100644 (file)
@@ -3,7 +3,9 @@
 @foreach ($urls as $url)
        <url>
                <loc>{{ url($url->path) }}</loc>
-               <lastmod>{{ $url->lastmod->tz('UTC')->toAtomString() }}</lastmod>
+               @if ($url->lastmod)
+                       <lastmod>{{ $url->lastmod->tz('UTC')->toAtomString() }}</lastmod>
+               @endif
                <changefreq>{{ $url->changefreq }}</changefreq>
                <priority>{{ $url->priority }}</priority>
        </url>