fix: restore orange brand icon and harden OSM tile cache
Some checks are pending
Deploy to GitHub Pages / deploy (push) Waiting to run
Some checks are pending
Deploy to GitHub Pages / deploy (push) Waiting to run
This commit is contained in:
parent
f75bad3e8d
commit
579dcddc1d
18 changed files with 79 additions and 39 deletions
10
index.html
10
index.html
|
|
@ -44,11 +44,11 @@
|
|||
<link rel="manifest" href="/manifest.webmanifest">
|
||||
|
||||
<!-- App Icons -->
|
||||
<link rel="icon" type="image/png" href="/images/icon-1024.png">
|
||||
<link rel="apple-touch-icon" href="/images/icon-180.png">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/images/icon-180.png">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/images/icon-180.png">
|
||||
<link rel="apple-touch-startup-image" href="/images/icon-1024.png">
|
||||
<link rel="icon" type="image/png" href="/images/brand-192.png">
|
||||
<link rel="apple-touch-icon" href="/images/brand-180.png">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/images/brand-180.png">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/images/brand-180.png">
|
||||
<link rel="apple-touch-startup-image" href="/images/brand-1024.png">
|
||||
|
||||
<!-- Theme Color -->
|
||||
<meta name="theme-color" content="#ff0040">
|
||||
|
|
|
|||
BIN
public/images/brand-1024.png
Normal file
BIN
public/images/brand-1024.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 218 KiB |
BIN
public/images/brand-180.png
Normal file
BIN
public/images/brand-180.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
BIN
public/images/brand-192.png
Normal file
BIN
public/images/brand-192.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
BIN
public/images/brand-512.png
Normal file
BIN
public/images/brand-512.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 64 KiB |
BIN
public/images/brand-maskable-1024.png
Normal file
BIN
public/images/brand-maskable-1024.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 146 KiB |
BIN
public/images/brand-maskable-512.png
Normal file
BIN
public/images/brand-maskable-512.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 43 KiB |
|
|
@ -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"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -630,7 +630,7 @@ export function Layout({ children, noPadding }: LayoutProps) {
|
|||
title={user ? t('chromeUi.viewMyProfile') : t('nav.map')}
|
||||
>
|
||||
<img
|
||||
src="/images/icon-1024.png"
|
||||
src="/images/logo.png"
|
||||
alt="SkateSpots"
|
||||
className="w-10 h-10 shrink-0 rounded-xl shadow-lg shadow-red-500/30 group-hover:shadow-red-500/50 transition-shadow"
|
||||
/>
|
||||
|
|
@ -857,7 +857,7 @@ export function Layout({ children, noPadding }: LayoutProps) {
|
|||
aria-label={user ? t('chromeUi.viewMyProfile') : t('nav.map')}
|
||||
>
|
||||
<img
|
||||
src="/images/icon-1024.png"
|
||||
src="/images/logo.png"
|
||||
alt="SkateSpots"
|
||||
className="w-9 h-9 rounded-lg flex-shrink-0 shadow-lg shadow-red-500/30"
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -258,7 +258,7 @@ export function SplashScreen() {
|
|||
className="relative"
|
||||
>
|
||||
<img
|
||||
src="/images/icon-1024.png"
|
||||
src="/images/logo.png"
|
||||
alt="SkateSpots"
|
||||
draggable={false}
|
||||
className="relative h-28 w-28 select-none drop-shadow-[0_0_34px_rgba(255,106,0,0.65)]"
|
||||
|
|
|
|||
|
|
@ -2,6 +2,12 @@ import { useEffect, useRef } from 'react';
|
|||
import L from 'leaflet';
|
||||
|
||||
import { createCachedTileLayer } from '@/lib/cachedTileLayer';
|
||||
import {
|
||||
MAP_TILE_URL,
|
||||
MAP_TILE_SUBDOMAINS,
|
||||
MAP_TILE_CACHE_NAMESPACE,
|
||||
MAP_TILE_ATTRIBUTION,
|
||||
} from '@/lib/mapTiles';
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
export interface LatLng {
|
||||
|
|
@ -53,14 +59,14 @@ export function SpotLocationPicker({ value, onChange, className }: SpotLocationP
|
|||
attributionControl: true,
|
||||
});
|
||||
|
||||
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,
|
||||
minZoom: 2,
|
||||
maxZoom: 19,
|
||||
noWrap: true,
|
||||
className: 'skatespots-dark-tiles',
|
||||
}).addTo(map);
|
||||
}, MAP_TILE_CACHE_NAMESPACE).addTo(map);
|
||||
|
||||
map.on('click', (e: L.LeafletMouseEvent) => {
|
||||
onChangeRef.current({ lat: e.latlng.lat, lng: e.latlng.lng });
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -212,7 +212,7 @@ export const LoginDialog: React.FC<LoginDialogProps> = ({ 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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
15
src/lib/mapTiles.ts
Normal file
15
src/lib/mapTiles.ts
Normal file
|
|
@ -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';
|
||||
|
|
@ -593,7 +593,7 @@ function Footer() {
|
|||
<div className="flex flex-col md:flex-row items-center justify-between gap-6">
|
||||
<div className="flex items-center gap-3">
|
||||
<img
|
||||
src="/images/icon-1024.png"
|
||||
src="/images/logo.png"
|
||||
alt="SkateSpots"
|
||||
className="w-10 h-10 rounded-lg shadow-[0_0_20px_rgba(255,0,64,0.5)]"
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
Loading…
Reference in a new issue