aboutsummaryrefslogtreecommitdiff
path: root/src/frontend/app/maps/styleloader.ts
diff options
context:
space:
mode:
authorcopilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>2026-02-25 14:00:51 +0000
committercopilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>2026-02-25 14:00:51 +0000
commite0ad08318d5834b9eaec2470c98faa2c4a23bd98 (patch)
tree6181be67a333c7afc1b39f81b49457dbc3fa1819 /src/frontend/app/maps/styleloader.ts
parent93057451330a825568d181869039d126c16749c4 (diff)
feat: single light style, remove 3D buildings, language labels, stop disambiguation
Co-authored-by: arielcostas <94913521+arielcostas@users.noreply.github.com>
Diffstat (limited to 'src/frontend/app/maps/styleloader.ts')
-rw-r--r--src/frontend/app/maps/styleloader.ts92
1 files changed, 85 insertions, 7 deletions
diff --git a/src/frontend/app/maps/styleloader.ts b/src/frontend/app/maps/styleloader.ts
index 7d90116..62ab2fc 100644
--- a/src/frontend/app/maps/styleloader.ts
+++ b/src/frontend/app/maps/styleloader.ts
@@ -3,6 +3,7 @@ import type { Theme } from "~/AppContext";
export interface StyleLoaderOptions {
includeTraffic?: boolean;
+ language?: string;
}
export const DEFAULT_STYLE: StyleSpecification = {
@@ -13,19 +14,76 @@ export const DEFAULT_STYLE: StyleSpecification = {
layers: [],
};
+/**
+ * Builds a MapLibre text-field expression that prefers the given language.
+ */
+function buildLanguageTextField(language: string): unknown[] {
+ const lang = language.toLowerCase().split("-")[0];
+ switch (lang) {
+ case "es":
+ return [
+ "coalesce",
+ ["get", "name:es"],
+ ["get", "name:latin"],
+ ["get", "name"],
+ ];
+ case "gl":
+ return [
+ "coalesce",
+ ["get", "name:gl"],
+ ["get", "name:es"],
+ ["get", "name:latin"],
+ ["get", "name"],
+ ];
+ case "en":
+ return [
+ "coalesce",
+ ["get", "name:en"],
+ ["get", "name_en"],
+ ["get", "name:latin"],
+ ["get", "name"],
+ ];
+ default:
+ return ["coalesce", ["get", "name:latin"], ["get", "name"]];
+ }
+}
+
+/**
+ * Returns true for text-field expressions that encode multi-language name
+ * logic (they reference name:latin or name_en). These are the label layers
+ * produced by OpenMapTiles / OpenFreeMap that need localisation.
+ */
+function isMultiLanguageTextField(textField: unknown): boolean {
+ if (!Array.isArray(textField)) return false;
+ const str = JSON.stringify(textField);
+ return str.includes('"name:latin"') || str.includes('"name_en"');
+}
+
+/**
+ * Mutates the loaded style to replace multi-language label expressions with
+ * a localised version appropriate for the given language code.
+ */
+function applyLanguageToStyle(style: any, language: string): void {
+ const newTextField = buildLanguageTextField(language);
+ for (const layer of style.layers ?? []) {
+ if (
+ layer.layout?.["text-field"] &&
+ isMultiLanguageTextField(layer.layout["text-field"])
+ ) {
+ layer.layout["text-field"] = newTextField;
+ }
+ }
+}
+
export async function loadStyle(
styleName: string,
colorScheme: Theme,
options?: StyleLoaderOptions
): Promise<StyleSpecification> {
- const { includeTraffic = true } = options || {};
+ const { includeTraffic = true, language } = options || {};
- if (colorScheme == "system") {
- const isDarkMode = window.matchMedia(
- "(prefers-color-scheme: dark)"
- ).matches;
- colorScheme = isDarkMode ? "dark" : "light";
- }
+ // Always use the light style as the single canonical base style.
+ colorScheme = "light";
if (styleName == "openfreemap") {
const url = `/maps/styles/openfreemap-${colorScheme}.json`;
@@ -45,6 +103,16 @@ export async function loadStyle(
delete style.sources?.vigo_traffic;
}
+ // Remove the pseudo-3D building-top layer (fill-translate shadow effect).
+ style.layers = (style.layers || []).filter(
+ (layer: any) => layer.id !== "building-top"
+ );
+
+ // Apply language-aware label expressions.
+ if (language) {
+ applyLanguageToStyle(style, language);
+ }
+
return style as StyleSpecification;
}
@@ -106,5 +174,15 @@ export async function loadStyle(
}
}
+ // Remove the pseudo-3D building-top layer.
+ style.layers = (style.layers || []).filter(
+ (layer: any) => layer.id !== "building-top"
+ );
+
+ // Apply language-aware label expressions.
+ if (language) {
+ applyLanguageToStyle(style, language);
+ }
+
return style as StyleSpecification;
}