feat: v0.4.0 — self-host OFM styles/fonts/sprites (tiles stay remote) + top-bar style switcher defaulting to Fiord
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
// Map style registry + rewriting of OpenFreeMap styles for self-hosted assets.
|
||||
// Styles, fonts and sprites are served locally from /public (populated by
|
||||
// scripts/download-map-assets.mjs); only vector tiles (/planet) and the ne2_shaded
|
||||
// raster tiles stay remote on tiles.openfreemap.org.
|
||||
|
||||
export interface MapStyle {
|
||||
id: string;
|
||||
label: string;
|
||||
}
|
||||
|
||||
export const STYLES: MapStyle[] = [
|
||||
{ id: 'liberty', label: 'Liberty' },
|
||||
{ id: 'bright', label: 'Bright' },
|
||||
{ id: 'positron', label: 'Positron' },
|
||||
{ id: 'dark', label: 'Dark' },
|
||||
{ id: 'fiord', label: 'Fiord' },
|
||||
];
|
||||
|
||||
export const DEFAULT_STYLE_ID = 'fiord';
|
||||
|
||||
// localStorage key for the persisted style choice.
|
||||
export const STYLE_STORAGE_KEY = 'flight-ops-style';
|
||||
|
||||
const OFM_FONTS_PREFIX = 'https://tiles.openfreemap.org/fonts/';
|
||||
const OFM_SPRITE_URL = 'https://tiles.openfreemap.org/sprites/ofm_f384/ofm';
|
||||
// Sprite files are extracted flat into public/sprites/, so the sprite base URL
|
||||
// (MapLibre appends .json / @2x.png) points straight at them.
|
||||
export const LOCAL_SPRITE_URL = '/sprites/ofm';
|
||||
|
||||
// OFM styles ship no attribution; ODbL requires visible OSM credit.
|
||||
export const ATTRIBUTION = '© OpenStreetMap contributors © OpenFreeMap';
|
||||
|
||||
export function isStyleId(id: string): boolean {
|
||||
return STYLES.some((s) => s.id === id);
|
||||
}
|
||||
|
||||
export function styleUrl(id: string): string {
|
||||
return `/styles/${id}.json`;
|
||||
}
|
||||
|
||||
type Source = Record<string, unknown>;
|
||||
|
||||
// Takes a raw OFM style object and returns a new one with glyphs/sprite pointed at the
|
||||
// self-hosted copies under /fonts and /sprites. Only those two fields are rewritten —
|
||||
// the vector tile url (/planet) and raster tiles (/natural_earth/...) stay remote.
|
||||
// Sources without an attribution get one added (ODbL requires visible OSM credit).
|
||||
export function rewriteStyle(raw: unknown): unknown {
|
||||
if (typeof raw !== 'object' || raw === null) return raw;
|
||||
const style = { ...(raw as Record<string, unknown>) };
|
||||
|
||||
const glyphs = style.glyphs;
|
||||
if (typeof glyphs === 'string' && glyphs.startsWith(OFM_FONTS_PREFIX)) {
|
||||
style.glyphs = '/fonts/' + glyphs.slice(OFM_FONTS_PREFIX.length);
|
||||
}
|
||||
|
||||
if (style.sprite === OFM_SPRITE_URL) {
|
||||
style.sprite = LOCAL_SPRITE_URL;
|
||||
}
|
||||
|
||||
const sources = style.sources;
|
||||
if (sources && typeof sources === 'object') {
|
||||
const next: Record<string, unknown> = { ...(sources as Source) };
|
||||
for (const [id, src] of Object.entries(next)) {
|
||||
if (src && typeof src === 'object' && !('attribution' in (src as Source))) {
|
||||
next[id] = { ...(src as Source), attribution: ATTRIBUTION };
|
||||
}
|
||||
}
|
||||
style.sources = next;
|
||||
}
|
||||
|
||||
return style;
|
||||
}
|
||||
Reference in New Issue
Block a user