Compare commits
28 Commits
5a14db5601
...
v1.8.10
| Author | SHA1 | Date | |
|---|---|---|---|
|
41d61be42e
|
|||
|
06b47d96a7
|
|||
|
e8af959be6
|
|||
|
254e177cbf
|
|||
|
47fbc8e7cf
|
|||
|
4ad0df22e2
|
|||
|
0decb4cf1b
|
|||
|
2193f935cc
|
|||
|
b2b03c0a38
|
|||
|
0be02c5b20
|
|||
|
653e44348c
|
|||
|
8fdc697a17
|
|||
|
d9b2a17b91
|
|||
|
85255318ba
|
|||
|
713d9d53e6
|
|||
|
e0ea0ca988
|
|||
|
3cc2a2649a
|
|||
|
924484a191
|
|||
|
b960ba0868
|
|||
|
3b22f8c2f4
|
|||
|
1a643e980d
|
|||
|
b085783ad8
|
|||
|
245f79d6f4
|
|||
|
06beb73068
|
|||
|
c3185b6a5a
|
|||
|
b6484aee9d
|
|||
|
ace2697de5
|
|||
|
14e02f3641
|
@@ -1,6 +1,6 @@
|
||||
# Project Status: Marco
|
||||
|
||||
**Last Updated:** Sat Jan 24 2026
|
||||
**Last Updated:** Mon Jan 26 2026
|
||||
|
||||
## Project Context
|
||||
|
||||
@@ -21,9 +21,14 @@ We are building **Marco**, a decentralized maps application using **Ember.js** (
|
||||
- **Visuals:** Increased bookmark marker size (Radius 9px) and added a subtle drop shadow.
|
||||
- **Feedback:** Implemented a "pulse" animation (via OpenLayers Overlay) at the click location to visualize the search radius (30m/50m).
|
||||
- **Mobile UX:**
|
||||
- Disabled browser tap highlights (`-webkit-tap-highlight-color: transparent`) to prevent blue flashing on Android.
|
||||
- Disabled "pull-to-refresh" (`overscroll-behavior: none`) on the body to prevent accidental reloads while keeping the sidebar scrollable (`contain`).
|
||||
- **Touch:** Disabled browser tap highlights (`-webkit-tap-highlight-color: transparent`) to prevent blue flashing on Android.
|
||||
- **Scroll:** Disabled "pull-to-refresh" (`overscroll-behavior: none`) on the body to prevent accidental reloads while keeping the sidebar scrollable (`contain`).
|
||||
- **Auto-Pan:** On mobile screens, if a selected pin is obscured by the bottom sheet, the map automatically pans to center the pin in the visible top half of the screen.
|
||||
- **Controls:** Fixed positioning of "Locate" and "Rotate" buttons on mobile by correcting CSS `inset` syntax.
|
||||
- **iOS Polish:**
|
||||
- Prevented input auto-zoom by ensuring `.form-control` font size is `1rem` (16px).
|
||||
- Added `-webkit-text-size-adjust: 100%` to prevent text inflation on rotation.
|
||||
- Set base `body` font size to `16px`.
|
||||
- **Geolocation ("Locate Me"):**
|
||||
- Implemented a "Locate Me" button with robust tracking logic.
|
||||
- **Dynamic Zoom:** Automatically zooms to a level where the accuracy circle covers ~10% of the map (fallback logic handles missing accuracy data).
|
||||
@@ -44,7 +49,7 @@ We are building **Marco**, a decentralized maps application using **Ember.js** (
|
||||
- configured with `maxAge: false` to ensure data freshness.
|
||||
- **Dependencies:** Uses `ulid` and `latlon-geohash` internally.
|
||||
|
||||
### 3. App Infrastructure
|
||||
### 3. App Infrastructure & Build
|
||||
|
||||
- **Services:**
|
||||
- `storage.js`: Initializes RemoteStorage, claims access, enables caching, and sets up the widget. Consumes the new `getPlaces` API.
|
||||
@@ -68,6 +73,11 @@ We are building **Marco**, a decentralized maps application using **Ember.js** (
|
||||
- **Geo Utils:**
|
||||
- `app/utils/geo.js`: Haversine distance calculations.
|
||||
- `app/utils/geohash-coverage.js`: Logic to calculate required 4-char geohash prefixes for a given bounding box.
|
||||
- **Build & DevOps:**
|
||||
- **Icon Generation:** Added `build:icons` script using `magick` and `rsvg-convert` to automate PNG generation from SVG.
|
||||
- **Dependencies:** Documented system requirements (ImageMagick, librsvg) in `README.md`.
|
||||
- **Ember CLI:** Added as dev dependency to support generator commands.
|
||||
- **License:** Added AGPLv3 license.
|
||||
|
||||
### 4. Routing & Data Optimization
|
||||
|
||||
@@ -91,16 +101,17 @@ We are building **Marco**, a decentralized maps application using **Ember.js** (
|
||||
|
||||
## Files Currently in Focus
|
||||
|
||||
- `app/templates/application.gjs`: Core layout and "Outside Click" logic.
|
||||
- `app/components/settings-pane.gjs`: Settings UI.
|
||||
- `app/services/settings.js`: Settings persistence.
|
||||
- `app/styles/app.css`: Mobile CSS fixes (font sizes, control positioning).
|
||||
- `package.json`: New scripts and dependencies.
|
||||
- `README.md`: Updated documentation.
|
||||
|
||||
## Next Steps & Pending Tasks
|
||||
|
||||
1. **Collections/Lists:** Implement ability to organize bookmarks into lists/collections.
|
||||
2. **Linting & Code Quality:** Fix remaining CSS errors, remove inline styles in `map.gjs`, and address unused variables/runloop usage.
|
||||
3. **Performance:** Monitor performance with large datasets (thousands of bookmarks).
|
||||
4. **Testing:** Add automated tests for the geohash coverage, retry logic, and new editing features.
|
||||
1. **Mobile Polish:** Verify "Locate Me" animation on iOS Safari.
|
||||
2. **Collections/Lists:** Implement ability to organize bookmarks into lists/collections.
|
||||
3. **Linting & Code Quality:** Fix remaining CSS errors, remove inline styles in `map.gjs`, and address unused variables/runloop usage.
|
||||
4. **Performance:** Monitor performance with large datasets (thousands of bookmarks).
|
||||
5. **Testing:** Add automated tests for the geohash coverage, retry logic, and new editing features.
|
||||
|
||||
## Technical Constraints
|
||||
|
||||
|
||||
@@ -73,6 +73,7 @@ To run the script, you need `imagemagick` and `librsvg` installed:
|
||||
|
||||
- [ember.js](https://emberjs.com/)
|
||||
- [remoteStorage.js](https://remotestorage.io/rs.js/docs/)
|
||||
- [@remotestorage/module-places](https://gitea.kosmos.org/raucao/remotestorage-module-places)
|
||||
- [Vite](https://vite.dev)
|
||||
- Development Browser Extensions
|
||||
- [ember inspector for chrome](https://chrome.google.com/webstore/detail/ember-inspector/bmdblncegkenkacieihfhpjfppoconhi)
|
||||
|
||||
@@ -17,6 +17,7 @@ import navigation from 'feather-icons/dist/icons/navigation.svg?raw';
|
||||
import phone from 'feather-icons/dist/icons/phone.svg?raw';
|
||||
import server from 'feather-icons/dist/icons/server.svg?raw';
|
||||
import settings from 'feather-icons/dist/icons/settings.svg?raw';
|
||||
import target from 'feather-icons/dist/icons/target.svg?raw';
|
||||
import user from 'feather-icons/dist/icons/user.svg?raw';
|
||||
import x from 'feather-icons/dist/icons/x.svg?raw';
|
||||
import zap from 'feather-icons/dist/icons/zap.svg?raw';
|
||||
@@ -38,6 +39,7 @@ const ICONS = {
|
||||
phone,
|
||||
server,
|
||||
settings,
|
||||
target,
|
||||
user,
|
||||
x,
|
||||
zap,
|
||||
|
||||
@@ -61,8 +61,8 @@ export default class MapComponent extends Component {
|
||||
});
|
||||
|
||||
// Default view settings
|
||||
let center = [99.05738, 7.55087];
|
||||
let zoom = 13.0;
|
||||
let center = [14.21683569, 27.060114248];
|
||||
let zoom = 2.661;
|
||||
|
||||
// Try to restore from localStorage
|
||||
try {
|
||||
|
||||
@@ -193,8 +193,8 @@ export default class PlaceDetails extends Component {
|
||||
></textarea>
|
||||
</div>
|
||||
<div class="edit-actions">
|
||||
<button type="submit" class="btn btn-blue btn-sm">Save</button>
|
||||
<button type="button" class="btn btn-outline btn-sm" {{on "click" this.cancelEditing}}>Cancel</button>
|
||||
<button type="submit" class="btn btn-blue">Save</button>
|
||||
<button type="button" class="btn btn-outline" {{on "click" this.cancelEditing}}>Cancel</button>
|
||||
</div>
|
||||
</form>
|
||||
{{else}}
|
||||
|
||||
@@ -122,7 +122,7 @@ export default class PlacesSidebar extends Component {
|
||||
try {
|
||||
const savedPlace = await this.storage.updatePlace(updatedPlace);
|
||||
console.log('Place updated:', savedPlace.title);
|
||||
|
||||
|
||||
// Notify parent to refresh map/lists
|
||||
if (this.args.onBookmarkChange) {
|
||||
this.args.onBookmarkChange();
|
||||
@@ -148,7 +148,7 @@ export default class PlacesSidebar extends Component {
|
||||
{{on "click" this.clearSelection}}
|
||||
><Icon @name="arrow-left" @size={{20}} @color="#333" /></button>
|
||||
{{else}}
|
||||
<h2>Nearby Places</h2>
|
||||
<h2><Icon @name="target" @size={{20}} @color="#ea4335" /> Nearby</h2>
|
||||
{{/if}}
|
||||
<button type="button" class="close-btn" {{on "click" @onClose}}><Icon
|
||||
@name="x"
|
||||
|
||||
@@ -54,7 +54,7 @@ export default class SettingsPane extends Component {
|
||||
<p>
|
||||
Connect your own <a href="https://remotestorage.io/"
|
||||
target="_blank" rel="noopener">remote storage</a> to sync place bookmarks across
|
||||
devices.
|
||||
apps and devices.
|
||||
</p>
|
||||
<ul class="link-list">
|
||||
<li>
|
||||
|
||||
@@ -4,11 +4,13 @@ html,
|
||||
body {
|
||||
height: 100%;
|
||||
overscroll-behavior: none; /* Prevent pull-to-refresh on mobile */
|
||||
-webkit-text-size-adjust: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: 'Noto Serif', serif;
|
||||
font-family: 'Noto Serif', sans-serif;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
#root,
|
||||
@@ -224,10 +226,15 @@ body {
|
||||
.sidebar-header h2 {
|
||||
margin: 0;
|
||||
font-size: 1.2rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.sidebar-content {
|
||||
padding: 1rem;
|
||||
overflow-y: auto;
|
||||
flex: 1; /* Take up remaining vertical space */
|
||||
}
|
||||
|
||||
.edit-form {
|
||||
@@ -255,7 +262,7 @@ body {
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
font-family: inherit;
|
||||
font-size: 0.95rem;
|
||||
font-size: 1rem;
|
||||
box-sizing: border-box; /* Ensure padding doesn't overflow width */
|
||||
}
|
||||
|
||||
@@ -288,6 +295,15 @@ body {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.settings-section p a {
|
||||
color: #007bff;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.settings-section p a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.btn-full {
|
||||
width: 100%;
|
||||
}
|
||||
@@ -310,6 +326,11 @@ body {
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.meta-info p {
|
||||
margin-top: 1rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.meta-info p:first-child {
|
||||
margin-top: 1.2rem;
|
||||
padding-top: 1.2rem;
|
||||
@@ -349,29 +370,31 @@ body {
|
||||
.places-list {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
margin: -1rem -1rem 0 -1rem;
|
||||
}
|
||||
|
||||
.places-list li {
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.place-item {
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
background: #f8f9fa;
|
||||
border: 1px solid #ddd;
|
||||
padding: 0.75rem;
|
||||
border-radius: 4px;
|
||||
border: none;
|
||||
border-bottom: 1px solid #eee;
|
||||
background: #fff;
|
||||
color: #333;
|
||||
padding: 1rem;
|
||||
cursor: pointer;
|
||||
transition: background 0.2s;
|
||||
font-family: inherit;
|
||||
}
|
||||
|
||||
.place-item:hover {
|
||||
background: #e9ecef;
|
||||
background: #eee;
|
||||
}
|
||||
|
||||
.place-name {
|
||||
font-size: 1rem;
|
||||
font-weight: bold;
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
@@ -417,8 +440,8 @@ body {
|
||||
margin: 0 0 1rem;
|
||||
}
|
||||
|
||||
.place-details .place-description {
|
||||
margin-bottom: 1.5rem;
|
||||
.place-details p.place-description {
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.place-details .actions {
|
||||
@@ -426,24 +449,20 @@ body {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 1rem;
|
||||
margin-top: 1.5rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
padding: 0.75rem 1.5rem;
|
||||
padding: 0.6rem 1.2rem;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-size: 1rem;
|
||||
font-size: 0.9rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.btn-sm {
|
||||
padding: 0.4rem 1rem !important;
|
||||
font-size: 0.9rem !important;
|
||||
}
|
||||
|
||||
.btn-outline {
|
||||
background: transparent;
|
||||
color: #333;
|
||||
@@ -490,11 +509,15 @@ body {
|
||||
border: 2px solid rgb(255 204 51 / 80%); /* Gold/Yellow to match markers */
|
||||
background: rgb(255 204 51 / 20%);
|
||||
position: absolute;
|
||||
transform: translate(-50%, -50%);
|
||||
/* Use translate3d for GPU acceleration on iOS */
|
||||
transform: translate3d(-50%, -50%, 0);
|
||||
pointer-events: none;
|
||||
animation: pulse 1.5s infinite ease-out;
|
||||
box-sizing: border-box; /* Ensure border is included in width/height */
|
||||
display: none; /* Hidden by default */
|
||||
will-change: transform, opacity;
|
||||
-webkit-backface-visibility: hidden;
|
||||
backface-visibility: hidden;
|
||||
}
|
||||
|
||||
.search-pulse.active {
|
||||
@@ -508,12 +531,12 @@ body {
|
||||
|
||||
@keyframes pulse {
|
||||
0% {
|
||||
transform: translate(-50%, -50%) scale(0.8);
|
||||
transform: translate3d(-50%, -50%, 0) scale(0.8);
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: translate(-50%, -50%) scale(1.4);
|
||||
transform: translate3d(-50%, -50%, 0) scale(1.4);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
@@ -524,7 +547,7 @@ body {
|
||||
}
|
||||
|
||||
.ol-touch .ol-control.ol-locate {
|
||||
inset: auto auto 3.5em;
|
||||
inset: auto 0.5em 3.5em auto;
|
||||
}
|
||||
|
||||
/* Rotate Control */
|
||||
@@ -533,7 +556,7 @@ body {
|
||||
}
|
||||
|
||||
.ol-touch .ol-rotate {
|
||||
inset: auto auto 6em;
|
||||
inset: auto 0.5em 6em auto;
|
||||
}
|
||||
|
||||
span.icon {
|
||||
|
||||
@@ -9,10 +9,10 @@
|
||||
<!-- App identity -->
|
||||
<meta name="application-name" content="Marco">
|
||||
<meta name="apple-mobile-web-app-title" content="Marco">
|
||||
<meta name="theme-color" content="#F6E9A6">
|
||||
<meta name="theme-color" content="#333333">
|
||||
|
||||
<!-- PWA Manifest -->
|
||||
<link rel="manifest" href="/manifest.webmanifest">
|
||||
<link rel="manifest" href="/web-app-manifest.json">
|
||||
|
||||
<!-- Icons -->
|
||||
<link rel="icon" href="/icons/icon.svg" type="image/svg+xml">
|
||||
|
||||
16
package.json
16
package.json
@@ -1,11 +1,14 @@
|
||||
{
|
||||
"name": "marco",
|
||||
"version": "1.8.1",
|
||||
"version": "1.8.10",
|
||||
"private": true,
|
||||
"description": "Small description for marco goes here",
|
||||
"repository": "",
|
||||
"license": "MIT",
|
||||
"author": "",
|
||||
"description": "Unhosted maps app",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://gitea.kosmos.org/raucao/marco.git"
|
||||
},
|
||||
"license": "AGPL-3.0-only",
|
||||
"author": "Râu Cao <raucao@kosmos.org>",
|
||||
"type": "module",
|
||||
"imports": {
|
||||
"#app/*": "./app/*",
|
||||
@@ -47,7 +50,7 @@
|
||||
"@embroider/vite": "^1.5.0",
|
||||
"@eslint/js": "^9.39.2",
|
||||
"@glimmer/component": "^2.0.0",
|
||||
"@remotestorage/module-places": "link:vendor/remotestorage-module-places",
|
||||
"@remotestorage/module-places": "1.x",
|
||||
"@rollup/plugin-babel": "^6.1.0",
|
||||
"@warp-drive/core": "~5.8.0",
|
||||
"@warp-drive/ember": "~5.8.0",
|
||||
@@ -57,6 +60,7 @@
|
||||
"babel-plugin-ember-template-compilation": "^3.0.1",
|
||||
"concurrently": "^9.2.1",
|
||||
"decorator-transforms": "^2.3.1",
|
||||
"ember-cli": "^6.10.0",
|
||||
"ember-cli-deprecation-workflow": "^4.0.0",
|
||||
"ember-modifier": "^4.2.2",
|
||||
"ember-page-title": "^9.0.3",
|
||||
|
||||
2472
pnpm-lock.yaml
generated
2472
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -5,8 +5,8 @@
|
||||
"start_url": "/",
|
||||
"scope": "/",
|
||||
"display": "standalone",
|
||||
"background_color": "#F6E9A6",
|
||||
"theme_color": "#F6E9A6",
|
||||
"background_color": "#f8f9fa",
|
||||
"theme_color": "#333333",
|
||||
"icons": [
|
||||
{
|
||||
"src": "/icons/icon-192.png",
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
2
release/assets/main-Din37YgL.js
Normal file
2
release/assets/main-Din37YgL.js
Normal file
File diff suppressed because one or more lines are too long
1
release/assets/main-iBIZAPnF.css
Normal file
1
release/assets/main-iBIZAPnF.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
@@ -9,10 +9,10 @@
|
||||
<!-- App identity -->
|
||||
<meta name="application-name" content="Marco">
|
||||
<meta name="apple-mobile-web-app-title" content="Marco">
|
||||
<meta name="theme-color" content="#F6E9A6">
|
||||
<meta name="theme-color" content="#333333">
|
||||
|
||||
<!-- PWA Manifest -->
|
||||
<link rel="manifest" href="/manifest.webmanifest">
|
||||
<link rel="manifest" href="/web-app-manifest.json">
|
||||
|
||||
<!-- Icons -->
|
||||
<link rel="icon" href="/icons/icon.svg" type="image/svg+xml">
|
||||
@@ -26,8 +26,8 @@
|
||||
<meta name="msapplication-TileColor" content="#F6E9A6">
|
||||
<meta name="msapplication-TileImage" content="/icons/icon-144.png">
|
||||
|
||||
<script type="module" crossorigin src="/assets/main-CYQJLBu1.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/main-B9HZHSjP.css">
|
||||
<script type="module" crossorigin src="/assets/main-Din37YgL.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/main-iBIZAPnF.css">
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "Marco",
|
||||
"short_name": "Marco",
|
||||
"description": "Marco (as in Marco Polo) is an unhosted maps application that respects your privacy and choices",
|
||||
"description": "Marco is an unhosted maps application that respects your privacy and choices",
|
||||
"start_url": "/",
|
||||
"scope": "/",
|
||||
"display": "standalone",
|
||||
"background_color": "#F6E9A6",
|
||||
"theme_color": "#F6E9A6",
|
||||
"background_color": "#f8f9fa",
|
||||
"theme_color": "#333333",
|
||||
"icons": [
|
||||
{
|
||||
"src": "/icons/icon-192.png",
|
||||
1
vendor/remotestorage-module-places
vendored
1
vendor/remotestorage-module-places
vendored
@@ -1 +0,0 @@
|
||||
/home/basti/src/remotestorage/modules/remotestorage-module-places
|
||||
Reference in New Issue
Block a user