Compare commits
10 Commits
feature/so
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
466b1d5383
|
|||
|
ea7cb2f895
|
|||
|
7e94f335ac
|
|||
|
066ddb240d
|
|||
|
df336b87ac
|
|||
|
dbf71e366a
|
|||
|
6a83003acb
|
|||
|
bcc7c2a011
|
|||
|
19f04efecb
|
|||
|
c79bbaa41a
|
@@ -441,6 +441,7 @@ export default class MapComponent extends Component {
|
|||||||
// Track the selected place from the UI Service (Router -> Map)
|
// Track the selected place from the UI Service (Router -> Map)
|
||||||
updateSelectedPin = modifier(() => {
|
updateSelectedPin = modifier(() => {
|
||||||
const selected = this.mapUi.selectedPlace;
|
const selected = this.mapUi.selectedPlace;
|
||||||
|
const options = this.mapUi.selectionOptions || {};
|
||||||
|
|
||||||
if (!this.selectedPinOverlay || !this.selectedPinElement) return;
|
if (!this.selectedPinOverlay || !this.selectedPinElement) return;
|
||||||
|
|
||||||
@@ -471,7 +472,12 @@ export default class MapComponent extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (selected.bbox) {
|
if (options.preventZoom) {
|
||||||
|
// If we are preventing zoom (e.g. user clicked a bookmark), we still need to center
|
||||||
|
// but without changing the zoom level.
|
||||||
|
// We use animateToSmartCenter without a second argument (zoom=null).
|
||||||
|
this.animateToSmartCenter(coords);
|
||||||
|
} else if (selected.bbox) {
|
||||||
this.zoomToBbox(selected.bbox);
|
this.zoomToBbox(selected.bbox);
|
||||||
} else {
|
} else {
|
||||||
this.handlePinVisibility(coords);
|
this.handlePinVisibility(coords);
|
||||||
@@ -530,13 +536,22 @@ export default class MapComponent extends Component {
|
|||||||
padding: padding,
|
padding: padding,
|
||||||
duration: 1000,
|
duration: 1000,
|
||||||
easing: (t) => t * (2 - t),
|
easing: (t) => t * (2 - t),
|
||||||
maxZoom: currentZoom,
|
maxZoom: Math.max(currentZoom, 18),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
handlePinVisibility(coords) {
|
handlePinVisibility(coords) {
|
||||||
if (!this.mapInstance) return;
|
if (!this.mapInstance) return;
|
||||||
|
|
||||||
|
const view = this.mapInstance.getView();
|
||||||
|
const currentZoom = view.getZoom();
|
||||||
|
|
||||||
|
// If too far out (e.g. world view), zoom in to neighborhood level (16)
|
||||||
|
if (currentZoom < 16) {
|
||||||
|
this.animateToSmartCenter(coords, 16);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const pixel = this.mapInstance.getPixelFromCoordinate(coords);
|
const pixel = this.mapInstance.getPixelFromCoordinate(coords);
|
||||||
const size = this.mapInstance.getSize();
|
const size = this.mapInstance.getSize();
|
||||||
|
|
||||||
@@ -555,12 +570,17 @@ export default class MapComponent extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
animateToSmartCenter(coords) {
|
animateToSmartCenter(coords, zoom = null) {
|
||||||
if (!this.mapInstance) return;
|
if (!this.mapInstance) return;
|
||||||
|
|
||||||
const size = this.mapInstance.getSize();
|
const size = this.mapInstance.getSize();
|
||||||
const view = this.mapInstance.getView();
|
const view = this.mapInstance.getView();
|
||||||
const resolution = view.getResolution();
|
let resolution = view.getResolution();
|
||||||
|
|
||||||
|
if (zoom !== null) {
|
||||||
|
resolution = view.getResolutionForZoom(zoom);
|
||||||
|
}
|
||||||
|
|
||||||
let targetCenter = coords;
|
let targetCenter = coords;
|
||||||
|
|
||||||
// Check if mobile (width <= 768px matches CSS)
|
// Check if mobile (width <= 768px matches CSS)
|
||||||
@@ -582,11 +602,17 @@ export default class MapComponent extends Component {
|
|||||||
targetCenter = [coords[0], coords[1] - offsetMapUnits];
|
targetCenter = [coords[0], coords[1] - offsetMapUnits];
|
||||||
}
|
}
|
||||||
|
|
||||||
view.animate({
|
const animationOptions = {
|
||||||
center: targetCenter,
|
center: targetCenter,
|
||||||
duration: 1000,
|
duration: 1000,
|
||||||
easing: (t) => t * (2 - t), // Ease-out
|
easing: (t) => t * (2 - t), // Ease-out
|
||||||
});
|
};
|
||||||
|
|
||||||
|
if (zoom !== null) {
|
||||||
|
animationOptions.zoom = zoom;
|
||||||
|
}
|
||||||
|
|
||||||
|
view.animate(animationOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
panIfObscured(coords) {
|
panIfObscured(coords) {
|
||||||
@@ -850,6 +876,7 @@ export default class MapComponent extends Component {
|
|||||||
'Clicked bookmark while sidebar open (switching):',
|
'Clicked bookmark while sidebar open (switching):',
|
||||||
clickedBookmark
|
clickedBookmark
|
||||||
);
|
);
|
||||||
|
this.mapUi.preventNextZoom = true;
|
||||||
this.router.transitionTo('place', clickedBookmark);
|
this.router.transitionTo('place', clickedBookmark);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -864,6 +891,7 @@ export default class MapComponent extends Component {
|
|||||||
// Normal behavior (sidebar is closed)
|
// Normal behavior (sidebar is closed)
|
||||||
if (clickedBookmark) {
|
if (clickedBookmark) {
|
||||||
console.debug('Clicked bookmark:', clickedBookmark);
|
console.debug('Clicked bookmark:', clickedBookmark);
|
||||||
|
this.mapUi.preventNextZoom = true;
|
||||||
this.router.transitionTo('place', clickedBookmark);
|
this.router.transitionTo('place', clickedBookmark);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -72,7 +72,9 @@ export default class PlaceRoute extends Route {
|
|||||||
|
|
||||||
// Notify the Map UI to show the pin
|
// Notify the Map UI to show the pin
|
||||||
if (model) {
|
if (model) {
|
||||||
this.mapUi.selectPlace(model);
|
const options = { preventZoom: this.mapUi.preventNextZoom };
|
||||||
|
this.mapUi.selectPlace(model, options);
|
||||||
|
this.mapUi.preventNextZoom = false;
|
||||||
}
|
}
|
||||||
// Stop the pulse animation if it was running (e.g. redirected from search)
|
// Stop the pulse animation if it was running (e.g. redirected from search)
|
||||||
this.mapUi.stopSearch();
|
this.mapUi.stopSearch();
|
||||||
|
|||||||
@@ -9,18 +9,24 @@ export default class MapUiService extends Service {
|
|||||||
@tracked returnToSearch = false;
|
@tracked returnToSearch = false;
|
||||||
@tracked currentCenter = null;
|
@tracked currentCenter = null;
|
||||||
@tracked searchBoxHasFocus = false;
|
@tracked searchBoxHasFocus = false;
|
||||||
|
@tracked selectionOptions = {};
|
||||||
|
@tracked preventNextZoom = false;
|
||||||
|
|
||||||
selectPlace(place) {
|
selectPlace(place, options = {}) {
|
||||||
this.selectedPlace = place;
|
this.selectedPlace = place;
|
||||||
|
this.selectionOptions = options;
|
||||||
}
|
}
|
||||||
|
|
||||||
clearSelection() {
|
clearSelection() {
|
||||||
this.selectedPlace = null;
|
this.selectedPlace = null;
|
||||||
|
this.selectionOptions = {};
|
||||||
|
this.preventNextZoom = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
startSearch() {
|
startSearch() {
|
||||||
this.isSearching = true;
|
this.isSearching = true;
|
||||||
this.isCreating = false;
|
this.isCreating = false;
|
||||||
|
this.preventNextZoom = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
stopSearch() {
|
stopSearch() {
|
||||||
|
|||||||
@@ -203,6 +203,7 @@ body {
|
|||||||
box-shadow: 2px 0 5px rgb(0 0 0 / 10%);
|
box-shadow: 2px 0 5px rgb(0 0 0 / 10%);
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
overflow: hidden; /* Ensure flex children are contained */
|
||||||
}
|
}
|
||||||
|
|
||||||
.settings-pane.sidebar {
|
.settings-pane.sidebar {
|
||||||
@@ -239,7 +240,11 @@ body {
|
|||||||
.sidebar-content {
|
.sidebar-content {
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
flex: 1; /* Take up remaining vertical space */
|
-webkit-overflow-scrolling: touch;
|
||||||
|
flex: 1;
|
||||||
|
min-height: 0;
|
||||||
|
touch-action: pan-y;
|
||||||
|
overscroll-behavior: contain;
|
||||||
}
|
}
|
||||||
|
|
||||||
.edit-form {
|
.edit-form {
|
||||||
@@ -772,7 +777,6 @@ button.create-place {
|
|||||||
|
|
||||||
.sidebar-content {
|
.sidebar-content {
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
overscroll-behavior: contain; /* Prevent scroll chaining */
|
|
||||||
|
|
||||||
/* Ensure content doesn't get hidden behind bottom safe areas on mobile */
|
/* Ensure content doesn't get hidden behind bottom safe areas on mobile */
|
||||||
padding-bottom: env(safe-area-inset-bottom, 20px);
|
padding-bottom: env(safe-area-inset-bottom, 20px);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "marco",
|
"name": "marco",
|
||||||
"version": "1.12.3",
|
"version": "1.13.3",
|
||||||
"private": true,
|
"private": true,
|
||||||
"description": "Unhosted maps app",
|
"description": "Unhosted maps app",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|||||||
1
release/assets/main-DAo4Q0R2.css
Normal file
1
release/assets/main-DAo4Q0R2.css
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -39,8 +39,8 @@
|
|||||||
<meta name="msapplication-TileColor" content="#F6E9A6">
|
<meta name="msapplication-TileColor" content="#F6E9A6">
|
||||||
<meta name="msapplication-TileImage" content="/icons/icon-144.png">
|
<meta name="msapplication-TileImage" content="/icons/icon-144.png">
|
||||||
|
|
||||||
<script type="module" crossorigin src="/assets/main-dKBF4UHr.js"></script>
|
<script type="module" crossorigin src="/assets/main-gjk9d6Ld.js"></script>
|
||||||
<link rel="stylesheet" crossorigin href="/assets/main-DoLYcE7E.css">
|
<link rel="stylesheet" crossorigin href="/assets/main-DAo4Q0R2.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { babel } from '@rollup/plugin-babel';
|
|||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
// server: {
|
// server: {
|
||||||
// host: '0.0.0.0'
|
// host: '0.0.0.0',
|
||||||
// },
|
// },
|
||||||
plugins: [
|
plugins: [
|
||||||
ember(),
|
ember(),
|
||||||
|
|||||||
Reference in New Issue
Block a user