diff --git a/index.html b/index.html index 6649858..2825b99 100644 --- a/index.html +++ b/index.html @@ -44,11 +44,11 @@ - - - - - + + + + + diff --git a/public/images/brand-1024.png b/public/images/brand-1024.png new file mode 100644 index 0000000..0a5b808 Binary files /dev/null and b/public/images/brand-1024.png differ diff --git a/public/images/brand-180.png b/public/images/brand-180.png new file mode 100644 index 0000000..3a3348b Binary files /dev/null and b/public/images/brand-180.png differ diff --git a/public/images/brand-192.png b/public/images/brand-192.png new file mode 100644 index 0000000..5fb11f0 Binary files /dev/null and b/public/images/brand-192.png differ diff --git a/public/images/brand-512.png b/public/images/brand-512.png new file mode 100644 index 0000000..649b331 Binary files /dev/null and b/public/images/brand-512.png differ diff --git a/public/images/brand-maskable-1024.png b/public/images/brand-maskable-1024.png new file mode 100644 index 0000000..b1b695a Binary files /dev/null and b/public/images/brand-maskable-1024.png differ diff --git a/public/images/brand-maskable-512.png b/public/images/brand-maskable-512.png new file mode 100644 index 0000000..5916909 Binary files /dev/null and b/public/images/brand-maskable-512.png differ diff --git a/public/manifest.webmanifest b/public/manifest.webmanifest index fd1e0d7..4c3424f 100644 --- a/public/manifest.webmanifest +++ b/public/manifest.webmanifest @@ -1,8 +1,8 @@ { - "name": "SkateSpots - Decentralized Skate Map", + "name": "SkateSpots — Open-sourced Skate Community App", "short_name": "SkateSpots", "id": "/", - "description": "Discover skate spots, find coaches, join events, and connect with the skateboarding community on Nostr. Free, decentralized, censorship-resistant.", + "description": "Map, crews, events, gear and more — an open-sourced skate community app.", "start_url": "/", "scope": "/", "display": "standalone", @@ -18,25 +18,25 @@ "related_applications": [], "icons": [ { - "src": "/images/icon-192.png", + "src": "/images/brand-192.png", "sizes": "192x192", "type": "image/png", "purpose": "any" }, { - "src": "/images/icon-512.png", + "src": "/images/brand-512.png", "sizes": "512x512", "type": "image/png", "purpose": "any" }, { - "src": "/images/icon-maskable-512.png", + "src": "/images/brand-maskable-512.png", "sizes": "512x512", "type": "image/png", "purpose": "maskable" }, { - "src": "/images/icon-1024.png", + "src": "/images/brand-1024.png", "sizes": "1024x1024", "type": "image/png", "purpose": "any" @@ -66,7 +66,7 @@ "url": "/map", "icons": [ { - "src": "/images/icon-1024.png", + "src": "/images/brand-180.png", "sizes": "180x180", "type": "image/png" } @@ -79,7 +79,7 @@ "url": "/events", "icons": [ { - "src": "/images/icon-1024.png", + "src": "/images/brand-180.png", "sizes": "180x180", "type": "image/png" } @@ -92,7 +92,7 @@ "url": "/coaches", "icons": [ { - "src": "/images/icon-1024.png", + "src": "/images/brand-180.png", "sizes": "180x180", "type": "image/png" } @@ -105,7 +105,7 @@ "url": "/wallet", "icons": [ { - "src": "/images/icon-1024.png", + "src": "/images/brand-180.png", "sizes": "180x180", "type": "image/png" } diff --git a/src/components/Layout.tsx b/src/components/Layout.tsx index 0224d7f..888887c 100644 --- a/src/components/Layout.tsx +++ b/src/components/Layout.tsx @@ -630,7 +630,7 @@ export function Layout({ children, noPadding }: LayoutProps) { title={user ? t('chromeUi.viewMyProfile') : t('nav.map')} > SkateSpots @@ -857,7 +857,7 @@ export function Layout({ children, noPadding }: LayoutProps) { aria-label={user ? t('chromeUi.viewMyProfile') : t('nav.map')} > SkateSpots diff --git a/src/components/RouteDialog.tsx b/src/components/RouteDialog.tsx index 6e12742..3639b28 100644 --- a/src/components/RouteDialog.tsx +++ b/src/components/RouteDialog.tsx @@ -22,6 +22,12 @@ import { import { getLastLocation } from '@/lib/lastLocation'; import { saveRoute, loadRoute, formatAge } from '@/lib/routeCache'; import { createCachedTileLayer } from '@/lib/cachedTileLayer'; +import { + MAP_TILE_URL, + MAP_TILE_SUBDOMAINS, + MAP_TILE_CACHE_NAMESPACE, + MAP_TILE_ATTRIBUTION, +} from '@/lib/mapTiles'; import { calculateDistance } from '@/lib/sortOptions'; import { fetchRoute, @@ -598,13 +604,13 @@ export function RouteDialog({ minZoom: 2, }); - createCachedTileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { - attribution: '', - subdomains: 'abc', + createCachedTileLayer(MAP_TILE_URL, { + attribution: MAP_TILE_ATTRIBUTION, + subdomains: MAP_TILE_SUBDOMAINS, maxZoom: 19, noWrap: true, className: 'skatespots-dark-tiles', - }).addTo(map); + }, MAP_TILE_CACHE_NAMESPACE).addTo(map); // Metric scale bar — genuinely useful on a route map (how long is that line?). L.control.scale({ imperial: false, position: 'topleft' }).addTo(map); diff --git a/src/components/SplashScreen.tsx b/src/components/SplashScreen.tsx index e0d9f6c..941c99b 100644 --- a/src/components/SplashScreen.tsx +++ b/src/components/SplashScreen.tsx @@ -258,7 +258,7 @@ export function SplashScreen() { className="relative" > SkateSpots { onChangeRef.current({ lat: e.latlng.lat, lng: e.latlng.lng }); diff --git a/src/components/SpotMap.tsx b/src/components/SpotMap.tsx index 2f98f4e..83c32eb 100644 --- a/src/components/SpotMap.tsx +++ b/src/components/SpotMap.tsx @@ -15,6 +15,12 @@ import type { BtcMapPlace } from '@/hooks/useBtcMapPlaces'; import { isRecentlyVerified, isBoosted } from '@/hooks/useBtcMapPlaces'; import { sanitizeUrl } from '@/lib/sanitizeUrl'; import { createCachedTileLayer } from '@/lib/cachedTileLayer'; +import { + MAP_TILE_URL, + MAP_TILE_SUBDOMAINS, + MAP_TILE_CACHE_NAMESPACE, + MAP_TILE_ATTRIBUTION, +} from '@/lib/mapTiles'; import { FORECAST_DAYS } from '@/lib/weather'; import { useTranslation } from '@/contexts/language'; @@ -955,17 +961,18 @@ export function SpotMap({ applyWorldMinZoom(map); - // Free, no-API-key basemap: OpenStreetMap standard tiles, darkened via a CSS - // filter (see the `.skatespots-dark-tiles` rule in index.css) so it matches - // the app's dark theme without depending on a keyed provider like CARTO. - // Wrapped in an on-device tile cache so the basemap still draws at the park. - createCachedTileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { - attribution: '', - subdomains: 'abc', + // OpenStreetMap standard tiles, darkened via a CSS filter (see the + // `.skatespots-dark-tiles` rule in index.css) so they match the app's dark + // theme. Wrapped in an on-device tile cache so the basemap still draws at + // the park, with a fresh cache namespace so old access-blocked tiles are + // never reused. + createCachedTileLayer(MAP_TILE_URL, { + attribution: MAP_TILE_ATTRIBUTION, + subdomains: MAP_TILE_SUBDOMAINS, minZoom: 1, maxZoom: 19, className: 'skatespots-dark-tiles', - }).addTo(map); + }, MAP_TILE_CACHE_NAMESPACE).addTo(map); // Add click handler if enabled if (enableClickToAdd && onMapClick) { diff --git a/src/components/auth/LoginDialog.tsx b/src/components/auth/LoginDialog.tsx index 7139d26..bbe64d8 100644 --- a/src/components/auth/LoginDialog.tsx +++ b/src/components/auth/LoginDialog.tsx @@ -212,7 +212,7 @@ export const LoginDialog: React.FC = ({ isOpen, onClose, onLog setConnectError(''); setConnectState('waiting'); const session = startNostrConnect(nostr, { - appImage: 'https://skate-spots.org/images/icon-1024.png', + appImage: 'https://skate-spots.org/images/brand-1024.png', timeoutMs: 180_000, }); connectRef.current = session; diff --git a/src/lib/cachedTileLayer.ts b/src/lib/cachedTileLayer.ts index f2bdf65..399178d 100644 --- a/src/lib/cachedTileLayer.ts +++ b/src/lib/cachedTileLayer.ts @@ -14,12 +14,15 @@ import { getTile, putTile } from '@/lib/tileCache'; * Works on web and in the Capacitor WebView alike, unlike a service worker. */ export class CachedTileLayer extends L.TileLayer { + /** Change this whenever the basemap/provider/cache contract changes. */ + cacheNamespace = 'default'; + protected createTile(coords: L.Coords, done: L.DoneCallback): HTMLElement { const tile = document.createElement('img'); tile.alt = ''; tile.setAttribute('role', 'presentation'); - const key = `${coords.z}/${coords.x}/${coords.y}`; + const key = `${this.cacheNamespace}:${coords.z}/${coords.x}/${coords.y}`; const url = this.getTileUrl(coords); const useSrc = (src: string, revoke: boolean) => { @@ -57,6 +60,9 @@ export class CachedTileLayer extends L.TileLayer { export function createCachedTileLayer( urlTemplate: string, options?: L.TileLayerOptions, + cacheNamespace = 'default', ): CachedTileLayer { - return new CachedTileLayer(urlTemplate, options); + const layer = new CachedTileLayer(urlTemplate, options); + layer.cacheNamespace = cacheNamespace; + return layer; } diff --git a/src/lib/mapTiles.ts b/src/lib/mapTiles.ts new file mode 100644 index 0000000..7666c6d --- /dev/null +++ b/src/lib/mapTiles.ts @@ -0,0 +1,15 @@ +/** + * OpenStreetMap basemap configuration. + * + * Keep the OSM tile provider. `osm-v2` intentionally changes the cache + * namespace so old cached "Access blocked" tiles are never reused; it does not + * change the tile source. + */ +export const MAP_TILE_URL = + 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png'; + +export const MAP_TILE_SUBDOMAINS = 'abc'; + +export const MAP_TILE_CACHE_NAMESPACE = 'osm-v2'; + +export const MAP_TILE_ATTRIBUTION = '© OpenStreetMap contributors'; diff --git a/src/pages/Index.tsx b/src/pages/Index.tsx index 8a5e2d1..1ede043 100644 --- a/src/pages/Index.tsx +++ b/src/pages/Index.tsx @@ -593,7 +593,7 @@ function Footer() {
SkateSpots diff --git a/zapstore.yaml b/zapstore.yaml index cb44bbe..36f538a 100644 --- a/zapstore.yaml +++ b/zapstore.yaml @@ -48,7 +48,7 @@ website: https://skate-spots.org license: AGPL-3.0-only # Launcher / listing icon. -icon: ./public/images/icon-1024.png +icon: ./public/images/brand-1024.png # Listing screenshots (uploaded by zsp to the Zapstore CDN). images: