stuff like that

This commit is contained in:
lovebird 2026-03-28 21:05:41 +01:00
parent 0c0bb53915
commit 990475bcf3
10 changed files with 327 additions and 323 deletions

View File

@ -83,11 +83,14 @@ if (enablePlaygrounds) {
I18nPlayground = React.lazy(() => import("./components/playground/I18nPlayground"));
PlaygroundChat = React.lazy(() => import("./pages/PlaygroundChat"));
Tetris = React.lazy(() => import("./apps/tetris/Tetris"));
FileBrowser = React.lazy(() => import("./apps/filebrowser/FileBrowser"));
SupportChat = React.lazy(() => import("./pages/SupportChat"));
}
Tetris = React.lazy(() => import("./apps/tetris/Tetris"));
FileBrowser = React.lazy(() => import("./apps/filebrowser/FileBrowser"));
const VersionMap = React.lazy(() => import("./pages/VersionMap"));
const UserCollections = React.lazy(() => import("./pages/UserCollections"));
const Collections = React.lazy(() => import("./pages/Collections"));
@ -202,8 +205,9 @@ const AppWrapper = () => {
<Route path="/logs" element={<React.Suspense fallback={<div>Loading...</div>}><LogsPage /></React.Suspense>} />
{/* Apps */}
{enablePlaygrounds && <Route path="/app/tetris" element={<React.Suspense fallback={<div>Loading...</div>}><Tetris /></React.Suspense>} />}
{enablePlaygrounds && <Route path="/app/filebrowser/*" element={<React.Suspense fallback={<div>Loading...</div>}><FileBrowser /></React.Suspense>} />}
<Route path="/app/tetris" element={<React.Suspense fallback={<div>Loading...</div>}><Tetris /></React.Suspense>} />
<Route path="/app/filebrowser/*" element={<React.Suspense fallback={<div>Loading...</div>}><FileBrowser /></React.Suspense>} />
{enablePlaygrounds && <Route path="/support-chat" element={<React.Suspense fallback={<div>Loading...</div>}><SupportChat /></React.Suspense>} />}
{/* Ecommerce Routes */}
{(ecommerce) && (

View File

@ -624,8 +624,8 @@ export const CompetitorsMapView: React.FC<CompetitorsMapViewProps> = ({ competit
{/* Map Viewport */}
<div className="relative flex-1 min-h-0 w-full overflow-hidden">
<div
ref={mapContainer}
<div
ref={mapContainer}
className="w-full h-full relative"
/>
@ -660,7 +660,7 @@ export const CompetitorsMapView: React.FC<CompetitorsMapViewProps> = ({ competit
pickerPolygons={pickerPolygons}
posterTheme={posterTheme}
setPosterTheme={setPosterTheme}
onClose={onClosePosterMode || (() => {})}
onClose={onClosePosterMode || (() => { })}
/>
)}
</>

View File

@ -39,7 +39,7 @@ export const InfoPanel: React.FC<InfoPanelProps> = ({ isOpen, onClose, lat, lng,
setLoadingWiki(true);
setErrorWiki(null);
try {
const apiUrl = import.meta.env.VITE_API_URL || 'http://localhost:3333';
const apiUrl = import.meta.env.VITE_SERVER_IMAGE_API_URL || '';
const res = await fetch(`${apiUrl}/api/locations/wiki?lat=${lat}&lon=${lng}&limit=20`);
if (res.ok) {
const json = await res.json();
@ -67,7 +67,7 @@ export const InfoPanel: React.FC<InfoPanelProps> = ({ isOpen, onClose, lat, lng,
setLoadingLlm(true);
setLlmInfo(null);
try {
const apiUrl = import.meta.env.VITE_API_URL || 'http://localhost:3333';
const apiUrl = import.meta.env.VITE_SERVER_IMAGE_API_URL || '';
const res = await fetch(`${apiUrl}/api/locations/llm-info?location=${encodeURIComponent(locationName)}`);
if (res.ok) {
const json = await res.json();

View File

@ -399,7 +399,7 @@ export const fetchReverseGeocode = async (lat: number, lon: number): Promise<any
export const fetchIpLocation = async (): Promise<any> => {
return fetchWithDeduplication('ip-api-location', async () => {
const res = await fetch('http://ip-api.com/json/');
const res = await fetch('https://ipapi.co/json/');
if (!res.ok) throw new Error(`Failed to fetch IP location: ${res.statusText}`);
return await res.json();
}, 600000); // 10 minutes cache

View File

@ -7,7 +7,7 @@ const XIcon = ({ className }: { className?: string }) => (
<svg className={className} xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg>
);
const PaletteIcon = ({ className }: { className?: string }) => (
<svg className={className} xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="13.5" cy="6.5" r=".5" fill="currentColor"/><circle cx="17.5" cy="10.5" r=".5" fill="currentColor"/><circle cx="8.5" cy="7.5" r=".5" fill="currentColor"/><circle cx="6.5" cy="12.5" r=".5" fill="currentColor"/><path d="M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10c.926 0 1.648-.746 1.648-1.688 0-.437-.18-.835-.437-1.125-.29-.289-.438-.652-.438-1.125a1.64 1.64 0 0 1 1.668-1.668h1.996c3.051 0 5.555-2.503 5.555-5.554C21.965 6.012 17.461 2 12 2z"/></svg>
<svg className={className} xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="13.5" cy="6.5" r=".5" fill="currentColor" /><circle cx="17.5" cy="10.5" r=".5" fill="currentColor" /><circle cx="8.5" cy="7.5" r=".5" fill="currentColor" /><circle cx="6.5" cy="12.5" r=".5" fill="currentColor" /><path d="M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10c.926 0 1.648-.746 1.648-1.688 0-.437-.18-.835-.437-1.125-.29-.289-.438-.652-.438-1.125a1.64 1.64 0 0 1 1.668-1.668h1.996c3.051 0 5.555-2.503 5.555-5.554C21.965 6.012 17.461 2 12 2z" /></svg>
);
interface MapPosterOverlayProps {
@ -36,25 +36,25 @@ export function MapPosterOverlay({ map, pickerRegions, pickerPolygons, posterThe
const c = map.getCenter();
setCenter({ lat: c.lat, lng: c.lng });
};
const fetchGeo = async () => {
const c = map.getCenter();
try {
const apiUrl = import.meta.env.VITE_API_URL || 'http://localhost:3333';
const apiUrl = import.meta.env.VITE_SERVER_IMAGE_API_URL || '';
const res = await fetch(`${apiUrl}/api/regions/reverse?lat=${c.lat}&lon=${c.lng}`);
if (res.ok) {
const json = await res.json();
if (json.data) {
const geo = json.data;
let cty = geo.city && geo.city !== 'unknown' ? geo.city :
geo.locality && geo.locality !== 'unknown' ? geo.locality :
geo.principalSubdivision && geo.principalSubdivision !== 'unknown' ? geo.principalSubdivision : null;
let cty = geo.city && geo.city !== 'unknown' ? geo.city :
geo.locality && geo.locality !== 'unknown' ? geo.locality :
geo.principalSubdivision && geo.principalSubdivision !== 'unknown' ? geo.principalSubdivision : null;
let ctry = geo.countryName || null;
if (cty && cty !== "unknown") setInferredCity(cty);
if (ctry && ctry !== "unknown") setInferredCountry(ctry);
}
}
} catch (e) {}
} catch (e) { }
};
updateCenter();
@ -62,8 +62,8 @@ export function MapPosterOverlay({ map, pickerRegions, pickerPolygons, posterThe
map.on('move', updateCenter);
map.on('moveend', fetchGeo);
return () => {
return () => {
map.off('move', updateCenter);
map.off('moveend', fetchGeo);
}
@ -71,7 +71,7 @@ export function MapPosterOverlay({ map, pickerRegions, pickerPolygons, posterThe
let city = "CITY NAME";
let country = "COUNTRY";
if (pickerRegions && pickerRegions.length > 0) {
const countryRegion = pickerRegions.find(r => r.level === 0);
const cityRegion = pickerRegions.slice().reverse().find(r => r.level > 0);
@ -90,7 +90,7 @@ export function MapPosterOverlay({ map, pickerRegions, pickerPolygons, posterThe
};
const displayCity = city.toUpperCase().split('').join(' ');
const gradientTop = `linear-gradient(to bottom, ${theme.gradient_color}FF 0%, ${theme.gradient_color}00 100%)`;
const gradientBottom = `linear-gradient(to top, ${theme.gradient_color}FF 30%, ${theme.gradient_color}00 100%)`;
@ -103,12 +103,12 @@ export function MapPosterOverlay({ map, pickerRegions, pickerPolygons, posterThe
const isDark = document.documentElement.classList.contains('dark');
applyPosterTheme(map, theme, isDark);
};
if (map.isStyleLoaded()) _apply();
map.on('style.load', _apply);
map.on('styledata', _apply);
return () => {
map.off('style.load', _apply);
map.off('styledata', _apply);
@ -117,10 +117,10 @@ export function MapPosterOverlay({ map, pickerRegions, pickerPolygons, posterThe
useEffect(() => {
if (!map || !pickerPolygons || pickerPolygons.length === 0) return;
const combinedFeatures = pickerPolygons.flatMap(fc => fc.features || []);
const fc = { type: 'FeatureCollection', features: combinedFeatures };
if (!map.getSource('poster-gadm')) {
map.addSource('poster-gadm', { type: 'geojson', data: fc as any });
map.addLayer({
@ -134,7 +134,7 @@ export function MapPosterOverlay({ map, pickerRegions, pickerPolygons, posterThe
}
});
}
if (showGadmBorders) {
map.setLayoutProperty('poster-gadm-borders', 'visibility', 'visible');
map.setPaintProperty('poster-gadm-borders', 'line-color', theme.text);
@ -152,21 +152,21 @@ export function MapPosterOverlay({ map, pickerRegions, pickerPolygons, posterThe
<div className="absolute inset-0 z-40 pointer-events-none flex flex-col justify-between overflow-hidden mix-blend-normal">
{/* Top Gradient */}
<div className="w-full h-32 absolute top-0 left-0" style={{ background: gradientTop }} />
{/* Controls (pointer events auto) */}
<div id="poster-controls" className="absolute top-4 left-4 flex gap-2 pointer-events-auto z-50">
{pickerPolygons && pickerPolygons.length > 0 && (
<button
onClick={() => setShowGadmBorders(!showGadmBorders)}
<button
onClick={() => setShowGadmBorders(!showGadmBorders)}
className={`flex items-center px-3 py-1.5 ${showGadmBorders ? 'bg-indigo-100 text-indigo-700 dark:bg-indigo-900/40 dark:text-indigo-300' : 'bg-gray-100 hover:bg-gray-200 dark:bg-gray-700 dark:hover:bg-gray-600 text-gray-800 dark:text-gray-100'} rounded text-sm font-medium transition-colors shadow-sm`}
title="Toggle GADM Borders"
>
<MapIcon className="w-4 h-4" />
</button>
)}
<button
onClick={onClose}
<button
onClick={onClose}
className="flex items-center px-3 py-1.5 bg-red-100 hover:bg-red-200 dark:bg-red-900/40 dark:hover:bg-red-900/60 text-red-700 dark:text-red-300 rounded text-sm font-medium transition-colors shadow-sm"
>
<XIcon className="w-4 h-4 mr-1.5" /> Exit Poster Mode
@ -175,27 +175,27 @@ export function MapPosterOverlay({ map, pickerRegions, pickerPolygons, posterThe
{/* Bottom Content Area */}
<div className="w-full h-72 absolute bottom-0 left-0 flex flex-col justify-end items-center pb-12" style={{ background: gradientBottom }}>
<div
<div
className="text-center transition-colors duration-500"
style={{ color: theme.text }}
>
<div className="font-bold tracking-[0.2em] text-5xl mb-6 font-mono leading-none drop-shadow-sm">
{displayCity}
</div>
<div className="w-20 h-[2px] mx-auto opacity-70 mb-5 drop-shadow-sm" style={{ backgroundColor: theme.text }} />
<div className="text-2xl tracking-[0.3em] font-light mb-3 drop-shadow-sm">
{country.toUpperCase()}
</div>
<div className="text-sm opacity-80 font-mono tracking-wider drop-shadow-sm">
{center ? formatCoords(center) : 'Loading...'}
</div>
</div>
{/* Attribution */}
<div
<div
className="absolute bottom-4 right-4 text-xs opacity-50 font-mono"
style={{ color: theme.text }}
>
@ -204,4 +204,4 @@ export function MapPosterOverlay({ map, pickerRegions, pickerPolygons, posterThe
</div>
</div>
);
}
}

View File

@ -92,8 +92,8 @@ export function GadmRegionCollector({
setIsLocating(true);
try {
const data = await fetchIpLocation();
if (data && data.status === 'success' && data.lat && data.lon) {
const hierarchy = await fetchRegionHierarchy(data.lat, data.lon);
if (data && !data.error && data.latitude && data.longitude) {
const hierarchy = await fetchRegionHierarchy(data.latitude, data.longitude);
if (hierarchy && hierarchy.length > 0) {
const pathGids = hierarchy.map((d: any) => d.gid);
const l0 = hierarchy[0];

View File

@ -146,7 +146,7 @@ function applyEventToState(
const stats = parsed.stats || data?.stats;
if (stats) next.stats = { ...next.stats, ...stats };
// console.log(`SSE ${type}`, parsed);
console.log(`SSE ${type}`, parsed);
switch (type) {
case 'grid-ready':
next.stats = { ...next.stats, totalWaypoints: data?.totalWaypoints || data?.waypoints?.length || 0, phase: 'searching' };

View File

@ -201,7 +201,7 @@ export function JobViewer({ jobId }: { jobId: string }) {
const allResults = jobData?.result?.searchResult?.results || competitors;
const foundTypes = Array.from(new Set(allResults.flatMap((r: any) => r.types || []).filter(Boolean))).sort() as string[];
return (
<div className="flex flex-col flex-1 w-full overflow-hidden min-h-0 mt-2">
<div className="flex flex-col flex-1 w-full overflow-hidden min-h-0 mt-2 dark:bg-gray-800/70 p-1">
<div className="w-full flex-1 min-h-0 flex flex-col rounded-2xl shadow-xl transition-all duration-300">
<div className="flex flex-col md:flex-row md:items-start justify-between">
<div className="w-full">

View File

@ -74,19 +74,19 @@ export function useMapControls(onMapCenterUpdate?: (loc: string, zoom?: number)
setIsLocating(true);
try {
const data = await fetchIpLocation();
if (data.status === 'success' && data.lat && data.lon) {
if (!data.error && data.latitude && data.longitude) {
if (userLocationMarkerRef.current) {
userLocationMarkerRef.current.remove();
}
const marker = new maplibregl.Marker({ color: '#ef4444' })
.setLngLat([data.lon, data.lat])
.setLngLat([data.longitude, data.latitude])
.setPopup(new maplibregl.Popup({ closeButton: false }).setText('Your Location (IP)'))
.addTo(map);
userLocationMarkerRef.current = marker;
map.flyTo({
center: [data.lon, data.lat],
center: [data.longitude, data.latitude],
zoom: 12
});
}

View File

@ -1,280 +1,280 @@
export interface PosterTheme {
name: string;
description?: string;
bg: string;
text: string;
gradient_color: string;
water: string;
parks: string;
road_motorway: string;
road_primary: string;
road_secondary: string;
road_tertiary: string;
road_residential: string;
road_default: string;
name: string;
description?: string;
bg: string;
text: string;
gradient_color: string;
water: string;
parks: string;
road_motorway: string;
road_primary: string;
road_secondary: string;
road_tertiary: string;
road_residential: string;
road_default: string;
}
export const POSTER_THEMES: Record<string, PosterTheme> = {
"autumn": {
"name": "Autumn",
"description": "Burnt oranges, deep reds, golden yellows - seasonal warmth",
"bg": "#FBF7F0",
"text": "#8B4513",
"gradient_color": "#FBF7F0",
"water": "#D8CFC0",
"parks": "#E8E0D0",
"road_motorway": "#8B2500",
"road_primary": "#B8450A",
"road_secondary": "#CC7A30",
"road_tertiary": "#D9A050",
"road_residential": "#E8C888",
"road_default": "#CC7A30"
},
"blueprint": {
"name": "Blueprint",
"description": "Classic architectural blueprint - technical drawing aesthetic",
"bg": "#1A3A5C",
"text": "#E8F4FF",
"gradient_color": "#1A3A5C",
"water": "#0F2840",
"parks": "#1E4570",
"road_motorway": "#E8F4FF",
"road_primary": "#C5DCF0",
"road_secondary": "#9FC5E8",
"road_tertiary": "#7BAED4",
"road_residential": "#5A96C0",
"road_default": "#7BAED4"
},
"contrast_zones": {
"name": "Contrast Zones",
"description": "Strong contrast showing urban density - darker in center, lighter at edges",
"bg": "#FFFFFF",
"text": "#000000",
"gradient_color": "#FFFFFF",
"water": "#B0B0B0",
"parks": "#ECECEC",
"road_motorway": "#000000",
"road_primary": "#0F0F0F",
"road_secondary": "#252525",
"road_tertiary": "#404040",
"road_residential": "#5A5A5A",
"road_default": "#404040"
},
"copper_patina": {
"name": "Copper Patina",
"description": "Oxidized copper aesthetic - teal-green patina with copper accents",
"bg": "#E8F0F0",
"text": "#2A5A5A",
"gradient_color": "#E8F0F0",
"water": "#C0D8D8",
"parks": "#D8E8E0",
"road_motorway": "#B87333",
"road_primary": "#5A8A8A",
"road_secondary": "#6B9E9E",
"road_tertiary": "#88B4B4",
"road_residential": "#A8CCCC",
"road_default": "#88B4B4"
},
"emerald": {
"name": "Emerald City",
"description": "Lush dark green aesthetic with mint accents",
"bg": "#062C22",
"text": "#E3F9F1",
"gradient_color": "#062C22",
"water": "#0D4536",
"parks": "#0F523E",
"road_motorway": "#4ADEB0",
"road_primary": "#2DB88F",
"road_secondary": "#249673",
"road_tertiary": "#1B7559",
"road_residential": "#155C46",
"road_default": "#155C46"
},
"forest": {
"name": "Forest",
"description": "Deep greens and sage tones - organic botanical aesthetic",
"bg": "#F0F4F0",
"text": "#2D4A3E",
"gradient_color": "#F0F4F0",
"water": "#B8D4D4",
"parks": "#D4E8D4",
"road_motorway": "#2D4A3E",
"road_primary": "#3D6B55",
"road_secondary": "#5A8A70",
"road_tertiary": "#7AAA90",
"road_residential": "#A0C8B0",
"road_default": "#7AAA90"
},
"gradient_roads": {
"name": "Gradient Roads",
"description": "Smooth gradient from dark center to light edges with subtle features",
"bg": "#FFFFFF",
"text": "#000000",
"gradient_color": "#FFFFFF",
"water": "#D5D5D5",
"parks": "#EFEFEF",
"road_motorway": "#050505",
"road_primary": "#151515",
"road_secondary": "#2A2A2A",
"road_tertiary": "#404040",
"road_residential": "#555555",
"road_default": "#404040"
},
"japanese_ink": {
"name": "Japanese Ink",
"description": "Traditional ink wash inspired - minimalist with subtle red accent",
"bg": "#FAF8F5",
"text": "#2C2C2C",
"gradient_color": "#FAF8F5",
"water": "#E8E4E0",
"parks": "#F0EDE8",
"road_motorway": "#8B2500",
"road_primary": "#4A4A4A",
"road_secondary": "#6A6A6A",
"road_tertiary": "#909090",
"road_residential": "#B8B8B8",
"road_default": "#909090"
},
"midnight_blue": {
"name": "Midnight Blue",
"description": "Deep navy background with gold/copper roads - luxury atlas aesthetic",
"bg": "#0A1628",
"text": "#D4AF37",
"gradient_color": "#0A1628",
"water": "#061020",
"parks": "#0F2235",
"road_motorway": "#D4AF37",
"road_primary": "#C9A227",
"road_secondary": "#A8893A",
"road_tertiary": "#8B7355",
"road_residential": "#6B5B4F",
"road_default": "#8B7355"
},
"monochrome_blue": {
"name": "Monochrome Blue",
"description": "Single blue color family with varying saturation - clean and cohesive",
"bg": "#F5F8FA",
"text": "#1A3A5C",
"gradient_color": "#F5F8FA",
"water": "#D0E0F0",
"parks": "#E0EAF2",
"road_motorway": "#1A3A5C",
"road_primary": "#2A5580",
"road_secondary": "#4A7AA8",
"road_tertiary": "#7AA0C8",
"road_residential": "#A8C4E0",
"road_default": "#4A7AA8"
},
"neon_cyberpunk": {
"name": "Neon Cyberpunk",
"description": "Dark background with electric pink/cyan - bold night city vibes",
"bg": "#0D0D1A",
"text": "#00FFFF",
"gradient_color": "#0D0D1A",
"water": "#0A0A15",
"parks": "#151525",
"road_motorway": "#FF00FF",
"road_primary": "#00FFFF",
"road_secondary": "#00C8C8",
"road_tertiary": "#0098A0",
"road_residential": "#006870",
"road_default": "#0098A0"
},
"noir": {
"name": "Noir",
"description": "Pure black background with white/gray roads - modern gallery aesthetic",
"bg": "#000000",
"text": "#FFFFFF",
"gradient_color": "#000000",
"water": "#0A0A0A",
"parks": "#111111",
"road_motorway": "#FFFFFF",
"road_primary": "#E0E0E0",
"road_secondary": "#B0B0B0",
"road_tertiary": "#808080",
"road_residential": "#505050",
"road_default": "#808080"
},
"ocean": {
"name": "Ocean",
"description": "Various blues and teals - perfect for coastal cities",
"bg": "#F0F8FA",
"text": "#1A5F7A",
"gradient_color": "#F0F8FA",
"water": "#B8D8E8",
"parks": "#D8EAE8",
"road_motorway": "#1A5F7A",
"road_primary": "#2A7A9A",
"road_secondary": "#4A9AB8",
"road_tertiary": "#70B8D0",
"road_residential": "#A0D0E0",
"road_default": "#4A9AB8"
},
"pastel_dream": {
"name": "Pastel Dream",
"description": "Soft muted pastels with dusty blues and mauves - dreamy artistic aesthetic",
"bg": "#FAF7F2",
"text": "#5D5A6D",
"gradient_color": "#FAF7F2",
"water": "#D4E4ED",
"parks": "#E8EDE4",
"road_motorway": "#7B8794",
"road_primary": "#9BA4B0",
"road_secondary": "#B5AEBB",
"road_tertiary": "#C9C0C9",
"road_residential": "#D8D2D8",
"road_default": "#C9C0C9"
},
"sunset": {
"name": "Sunset",
"description": "Warm oranges and pinks on soft peach - dreamy golden hour aesthetic",
"bg": "#FDF5F0",
"text": "#C45C3E",
"gradient_color": "#FDF5F0",
"water": "#F0D8D0",
"parks": "#F8E8E0",
"road_motorway": "#C45C3E",
"road_primary": "#D87A5A",
"road_secondary": "#E8A088",
"road_tertiary": "#F0B8A8",
"road_residential": "#F5D0C8",
"road_default": "#E8A088"
},
"terracotta": {
"name": "Terracotta",
"description": "Mediterranean warmth - burnt orange and clay tones on cream",
"bg": "#F5EDE4",
"text": "#8B4513",
"gradient_color": "#F5EDE4",
"water": "#A8C4C4",
"parks": "#E8E0D0",
"road_motorway": "#A0522D",
"road_primary": "#B8653A",
"road_secondary": "#C9846A",
"road_tertiary": "#D9A08A",
"road_residential": "#E5C4B0",
"road_default": "#D9A08A"
},
"warm_beige": {
"name": "Warm Beige",
"description": "Earthy warm neutrals with sepia tones - vintage map aesthetic",
"bg": "#F5F0E8",
"text": "#6B5B4F",
"gradient_color": "#F5F0E8",
"water": "#DDD5C8",
"parks": "#E8E4D8",
"road_motorway": "#8B7355",
"road_primary": "#A08B70",
"road_secondary": "#B5A48E",
"road_tertiary": "#C9BBAA",
"road_residential": "#D9CFC2",
"road_default": "#C9BBAA"
},
"autumn": {
"name": "Autumn",
"description": "Burnt oranges, deep reds, golden yellows - seasonal warmth",
"bg": "#FBF7F0",
"text": "#8B4513",
"gradient_color": "#FBF7F0",
"water": "#D8CFC0",
"parks": "#E8E0D0",
"road_motorway": "#8B2500",
"road_primary": "#B8450A",
"road_secondary": "#CC7A30",
"road_tertiary": "#D9A050",
"road_residential": "#E8C888",
"road_default": "#CC7A30"
},
"blueprint": {
"name": "Blueprint",
"description": "Classic architectural blueprint - technical drawing aesthetic",
"bg": "#1A3A5C",
"text": "#E8F4FF",
"gradient_color": "#1A3A5C",
"water": "#0F2840",
"parks": "#1E4570",
"road_motorway": "#E8F4FF",
"road_primary": "#C5DCF0",
"road_secondary": "#9FC5E8",
"road_tertiary": "#7BAED4",
"road_residential": "#5A96C0",
"road_default": "#7BAED4"
},
"contrast_zones": {
"name": "Contrast Zones",
"description": "Strong contrast showing urban density - darker in center, lighter at edges",
"bg": "#FFFFFF",
"text": "#000000",
"gradient_color": "#FFFFFF",
"water": "#B0B0B0",
"parks": "#ECECEC",
"road_motorway": "#000000",
"road_primary": "#0F0F0F",
"road_secondary": "#252525",
"road_tertiary": "#404040",
"road_residential": "#5A5A5A",
"road_default": "#404040"
},
"copper_patina": {
"name": "Copper Patina",
"description": "Oxidized copper aesthetic - teal-green patina with copper accents",
"bg": "#E8F0F0",
"text": "#2A5A5A",
"gradient_color": "#E8F0F0",
"water": "#C0D8D8",
"parks": "#D8E8E0",
"road_motorway": "#B87333",
"road_primary": "#5A8A8A",
"road_secondary": "#6B9E9E",
"road_tertiary": "#88B4B4",
"road_residential": "#A8CCCC",
"road_default": "#88B4B4"
},
"emerald": {
"name": "Emerald City",
"description": "Lush dark green aesthetic with mint accents",
"bg": "#062C22",
"text": "#E3F9F1",
"gradient_color": "#062C22",
"water": "#0D4536",
"parks": "#0F523E",
"road_motorway": "#4ADEB0",
"road_primary": "#2DB88F",
"road_secondary": "#249673",
"road_tertiary": "#1B7559",
"road_residential": "#155C46",
"road_default": "#155C46"
},
"forest": {
"name": "Forest",
"description": "Deep greens and sage tones - organic botanical aesthetic",
"bg": "#F0F4F0",
"text": "#2D4A3E",
"gradient_color": "#F0F4F0",
"water": "#B8D4D4",
"parks": "#D4E8D4",
"road_motorway": "#2D4A3E",
"road_primary": "#3D6B55",
"road_secondary": "#5A8A70",
"road_tertiary": "#7AAA90",
"road_residential": "#A0C8B0",
"road_default": "#7AAA90"
},
"gradient_roads": {
"name": "Gradient Roads",
"description": "Smooth gradient from dark center to light edges with subtle features",
"bg": "#FFFFFF",
"text": "#000000",
"gradient_color": "#FFFFFF",
"water": "#D5D5D5",
"parks": "#EFEFEF",
"road_motorway": "#050505",
"road_primary": "#151515",
"road_secondary": "#2A2A2A",
"road_tertiary": "#404040",
"road_residential": "#555555",
"road_default": "#404040"
},
"japanese_ink": {
"name": "Japanese Ink",
"description": "Traditional ink wash inspired - minimalist with subtle red accent",
"bg": "#FAF8F5",
"text": "#2C2C2C",
"gradient_color": "#FAF8F5",
"water": "#E8E4E0",
"parks": "#F0EDE8",
"road_motorway": "#8B2500",
"road_primary": "#4A4A4A",
"road_secondary": "#6A6A6A",
"road_tertiary": "#909090",
"road_residential": "#B8B8B8",
"road_default": "#909090"
},
"midnight_blue": {
"name": "Midnight Blue",
"description": "Deep navy background with gold/copper roads - luxury atlas aesthetic",
"bg": "#0A1628",
"text": "#D4AF37",
"gradient_color": "#0A1628",
"water": "#061020",
"parks": "#0F2235",
"road_motorway": "#D4AF37",
"road_primary": "#C9A227",
"road_secondary": "#A8893A",
"road_tertiary": "#8B7355",
"road_residential": "#6B5B4F",
"road_default": "#8B7355"
},
"monochrome_blue": {
"name": "Monochrome Blue",
"description": "Single blue color family with varying saturation - clean and cohesive",
"bg": "#F5F8FA",
"text": "#1A3A5C",
"gradient_color": "#F5F8FA",
"water": "#D0E0F0",
"parks": "#E0EAF2",
"road_motorway": "#1A3A5C",
"road_primary": "#2A5580",
"road_secondary": "#4A7AA8",
"road_tertiary": "#7AA0C8",
"road_residential": "#A8C4E0",
"road_default": "#4A7AA8"
},
"neon_cyberpunk": {
"name": "Neon Cyberpunk",
"description": "Dark background with electric pink/cyan - bold night city vibes",
"bg": "#0D0D1A",
"text": "#00FFFF",
"gradient_color": "#0D0D1A",
"water": "#0A0A15",
"parks": "#151525",
"road_motorway": "#FF00FF",
"road_primary": "#00FFFF",
"road_secondary": "#00C8C8",
"road_tertiary": "#0098A0",
"road_residential": "#006870",
"road_default": "#0098A0"
},
"noir": {
"name": "Noir",
"description": "Pure black background with white/gray roads - modern gallery aesthetic",
"bg": "#000000",
"text": "#FFFFFF",
"gradient_color": "#000000",
"water": "#0A0A0A",
"parks": "#111111",
"road_motorway": "#FFFFFF",
"road_primary": "#E0E0E0",
"road_secondary": "#B0B0B0",
"road_tertiary": "#808080",
"road_residential": "#505050",
"road_default": "#808080"
},
"ocean": {
"name": "Ocean",
"description": "Various blues and teals - perfect for coastal cities",
"bg": "#F0F8FA",
"text": "#1A5F7A",
"gradient_color": "#F0F8FA",
"water": "#B8D8E8",
"parks": "#D8EAE8",
"road_motorway": "#1A5F7A",
"road_primary": "#2A7A9A",
"road_secondary": "#4A9AB8",
"road_tertiary": "#70B8D0",
"road_residential": "#A0D0E0",
"road_default": "#4A9AB8"
},
"pastel_dream": {
"name": "Pastel Dream",
"description": "Soft muted pastels with dusty blues and mauves - dreamy artistic aesthetic",
"bg": "#FAF7F2",
"text": "#5D5A6D",
"gradient_color": "#FAF7F2",
"water": "#D4E4ED",
"parks": "#E8EDE4",
"road_motorway": "#7B8794",
"road_primary": "#9BA4B0",
"road_secondary": "#B5AEBB",
"road_tertiary": "#C9C0C9",
"road_residential": "#D8D2D8",
"road_default": "#C9C0C9"
},
"sunset": {
"name": "Sunset",
"description": "Warm oranges and pinks on soft peach - dreamy golden hour aesthetic",
"bg": "#FDF5F0",
"text": "#C45C3E",
"gradient_color": "#FDF5F0",
"water": "#F0D8D0",
"parks": "#F8E8E0",
"road_motorway": "#C45C3E",
"road_primary": "#D87A5A",
"road_secondary": "#E8A088",
"road_tertiary": "#F0B8A8",
"road_residential": "#F5D0C8",
"road_default": "#E8A088"
},
"terracotta": {
"name": "Terracotta",
"description": "Mediterranean warmth - burnt orange and clay tones on cream",
"bg": "#F5EDE4",
"text": "#8B4513",
"gradient_color": "#F5EDE4",
"water": "#A8C4C4",
"parks": "#E8E0D0",
"road_motorway": "#A0522D",
"road_primary": "#B8653A",
"road_secondary": "#C9846A",
"road_tertiary": "#D9A08A",
"road_residential": "#E5C4B0",
"road_default": "#D9A08A"
},
"warm_beige": {
"name": "Warm Beige",
"description": "Earthy warm neutrals with sepia tones - vintage map aesthetic",
"bg": "#F5F0E8",
"text": "#6B5B4F",
"gradient_color": "#F5F0E8",
"water": "#DDD5C8",
"parks": "#E8E4D8",
"road_motorway": "#8B7355",
"road_primary": "#A08B70",
"road_secondary": "#B5A48E",
"road_tertiary": "#C9BBAA",
"road_residential": "#D9CFC2",
"road_default": "#C9BBAA"
},
};
export function applyPosterTheme(map: maplibregl.Map | any, theme: PosterTheme, isDark: boolean = false) {
if (!map || !map.getStyle()) return;
const setPaintSafe = (layer: string, prop: string, val: string | number) => {
if (map.getLayer(layer)) {
try {
@ -286,10 +286,10 @@ export function applyPosterTheme(map: maplibregl.Map | any, theme: PosterTheme,
};
const layers = map.getStyle().layers || [];
layers.forEach((layer: any) => {
const id = layer.id.toLowerCase();
// Hide all symbols (labels, POIs, etc)
if (layer.type === 'symbol') {
map.setLayoutProperty(id, 'visibility', 'none');
@ -323,10 +323,10 @@ export function applyPosterTheme(map: maplibregl.Map | any, theme: PosterTheme,
if (id.includes('building')) {
setPaintSafe(id, 'fill-color', theme.road_residential || theme.road_default);
setPaintSafe(id, 'line-color', theme.road_residential || theme.road_default);
// Try wrapping opacity changes safely
try { map.setPaintProperty(id, 'fill-opacity', 0.2); } catch(e){}
try { map.setPaintProperty(id, 'line-opacity', 0.1); } catch(e){}
try { map.setPaintProperty(id, 'fill-opacity', 0.2); } catch (e) { }
try { map.setPaintProperty(id, 'line-opacity', 0.1); } catch (e) { }
return;
}
@ -334,16 +334,16 @@ export function applyPosterTheme(map: maplibregl.Map | any, theme: PosterTheme,
if (id.includes('road') || id.includes('highway') || id.includes('tunnel') || id.includes('bridge') || id.includes('aeroway')) {
if (id.includes('mot') || id.includes('motorway') || id.includes('trunk') || id.includes('runway')) {
setPaintSafe(id, 'line-color', theme.road_motorway);
}
}
else if (id.includes('pri') || id.includes('primary') || id.includes('major')) {
setPaintSafe(id, 'line-color', theme.road_primary);
}
}
else if (id.includes('sec') || id.includes('secondary')) {
setPaintSafe(id, 'line-color', theme.road_secondary);
}
}
else if (id.includes('ter') || id.includes('tertiary')) {
setPaintSafe(id, 'line-color', theme.road_tertiary);
}
}
else {
// Minor / Residential / Path / Track / Service / Taxiway
setPaintSafe(id, 'line-color', theme.road_residential || theme.road_default);