23 Commits

Author SHA1 Message Date
Zsolt Ero
df4711fc55 Add dark and fiord styles to selector 2026-05-02 19:23:20 +02:00
Zsolt Ero
afc204d8c5 work 2025-10-22 14:55:38 +02:00
Zsolt Ero
68d820f4d1 work 2025-10-22 14:45:37 +02:00
Zsolt Ero
b6d26605e3 work 2025-10-22 14:37:35 +02:00
Zsolt Ero
c4aecd01f6 work 2025-10-22 14:36:29 +02:00
Zsolt Ero
ca337345f2 readonly fields 2025-10-22 14:29:29 +02:00
Zsolt Ero
3cec51d0b1 work 2025-10-22 13:07:19 +02:00
Zsolt Ero
f12ffcb032 work 2025-10-22 13:00:43 +02:00
Zsolt Ero
f2161e868d work 2025-10-22 12:42:58 +02:00
Zsolt Ero
cd76d94aac mix 2025-10-22 12:35:46 +02:00
Zsolt Ero
0dc7551eca work 2025-10-22 11:50:35 +02:00
Zsolt Ero
b43a1f5830 work 2025-10-22 11:23:03 +02:00
Zsolt Ero
b06f5f248f terrain example 2025-10-22 10:10:41 +02:00
Zsolt Ero
bdb142d9ec work 2025-10-17 22:12:24 +02:00
Zsolt Ero
fff93d5146 work 2025-10-17 22:10:37 +02:00
Zsolt Ero
722a87a737 work 2025-10-17 22:09:11 +02:00
Zsolt Ero
fa2f0d14cd work 2025-10-17 22:04:16 +02:00
Zsolt Ero
f91dc2aaa3 wrangler 2025-10-17 22:00:23 +02:00
Zsolt Ero
d46e26e971 work 2025-10-17 12:03:31 +02:00
Zsolt Ero
6cf7ddc672 work 2025-10-17 12:00:31 +02:00
Zsolt Ero
8ce37a96b2 debug 2025-10-17 11:46:44 +02:00
Zsolt Ero
24e1e636b9 work 2025-10-17 11:38:42 +02:00
Zsolt Ero
c75a87b151 add lang debug 2025-10-17 11:37:36 +02:00
15 changed files with 1974 additions and 41 deletions

View File

@@ -1,13 +1,10 @@
{ {
"$schema": "https://biomejs.dev/schemas/1.8.3/schema.json", "$schema": "https://biomejs.dev/schemas/2.2.4/schema.json",
"formatter": { "formatter": {
"indentStyle": "space", "indentStyle": "space",
"lineWidth": 100 "lineWidth": 100
}, },
"organizeImports": { "assist": { "actions": { "source": { "organizeImports": "on" } } },
"enabled": true,
"ignore": []
},
"linter": { "linter": {
"enabled": true, "enabled": true,
"rules": { "rules": {
@@ -16,7 +13,7 @@
"noForEach": "off" "noForEach": "off"
} }
}, },
"ignore": [] "includes": ["**"]
}, },
"javascript": { "javascript": {
"formatter": { "formatter": {
@@ -26,6 +23,6 @@
}, },
"files": { "files": {
"maxSize": 100000, "maxSize": 100000,
"ignore": ["venv", "dist", ".astro"] "includes": ["**", "!**/venv", "!**/dist", "!**/.astro"]
} }
} }

View File

@@ -3,18 +3,28 @@
"type": "module", "type": "module",
"version": "0.0.1", "version": "0.0.1",
"scripts": { "scripts": {
"dev": "astro dev", "clean": "rm -rf .astro dist ___node_modules/.astro ",
"start": "astro dev", "dev": "pnpm clean; astro dev",
"build": "astro build", "build": "pnpm clean; astro check && pnpm tsc && astro build",
"preview": "astro preview", "preview": "pnpm build && astro preview",
"astro": "astro" "preview_w": "pnpm build && wrangler dev",
"deploy_w": "pnpm build && wrangler deploy"
}, },
"dependencies": { "dependencies": {
"@astrojs/check": "^0.9.4",
"@astrojs/sitemap": "^3.2.1", "@astrojs/sitemap": "^3.2.1",
"astro": "^5.4.0", "astro": "^5.4.0",
"lightningcss": "^1.29.1" "lightningcss": "^1.29.1",
"typescript": "^5.9.3"
}, },
"pnpm": { "pnpm": {
"onlyBuiltDependencies": ["esbuild", "sharp"] "onlyBuiltDependencies": [
"esbuild",
"sharp",
"workerd"
]
},
"devDependencies": {
"wrangler": "^4.43.0"
} }
} }

1307
website/pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,15 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>OpenFreeMap Debug</title>
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
<link href="https://unpkg.com/maplibre-gl/dist/maplibre-gl.css" rel="stylesheet" />
</head>
<body>
<div id="map" class="w-full h-screen"></div>
<script src="https://unpkg.com/maplibre-gl/dist/maplibre-gl.js"></script>
<script src="colon.js"></script>
</body>
</html>

View File

@@ -0,0 +1,65 @@
const map = new maplibregl.Map({
container: 'map',
style: 'https://tiles.openfreemap.org/styles/liberty',
center: [0, 0],
zoom: 2,
})
function modifyStyle({ style, langCode }) {
if (!langCode) {
langCode = 'en'
}
for (const layer of style.layers) {
if (layer.source !== 'openmaptiles') continue
if (!layer.layout) continue
const textField = layer.layout['text-field']
if (!textField) continue
// highway numbers, etc. - skip ref-only fields
if (JSON.stringify(textField) === JSON.stringify(['to-string', ['get', 'ref']])) continue
const nameUnderscore = `name_${langCode}`
const nameColon = `name:${langCode}`
// Always display both values
layer.layout['text-field'] = ['concat', ['get', nameUnderscore], '\n', ['get', nameColon]]
// Color red when they are different
if (!layer.paint) layer.paint = {}
layer.paint['text-color'] = [
'case',
['!=', ['get', nameUnderscore], ['get', nameColon]],
'#ff0000', // Red when different
'#000000', // Default color when same (adjust as needed)
]
}
}
function applyLanguage() {
const hash = window.location.hash.substring(1) // Remove the '#'
const langCode = hash || null
const style = map.getStyle()
modifyStyle({ style, langCode })
map.setStyle(style, { diff: false })
}
map.on('load', () => {
// Add default hash if not present
if (!window.location.hash) {
alert(
'To change the map language, modify the language code in the URL #.\nLabels will be RED when different.\nname_xx on line 1, name:xx on line 2',
)
window.location.hash = '#en'
// The hashchange event will trigger applyLanguage()
} else {
applyLanguage()
}
})
// Listen for hash changes in URL
window.addEventListener('hashchange', () => {
applyLanguage()
})

View File

@@ -0,0 +1,114 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>OpenFreeMap Debug</title>
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
<link href="https://unpkg.com/maplibre-gl/dist/maplibre-gl.css" rel="stylesheet" />
</head>
<body class="flex flex-col h-screen">
<!-- UI Panel -->
<div class="bg-gray-900 border-b border-gray-700 shadow-md">
<div class="max-w-7xl mx-auto px-4 py-2">
<div class="flex items-start gap-3">
<div class="flex-1">
<label for="line1" class="block text-xs font-medium text-gray-400 mb-1"> Line 1 </label>
<input
type="text"
id="line1"
class="w-full px-3 py-1.5 text-sm border border-gray-600 rounded bg-gray-800 text-gray-100 focus:outline-none focus:border-blue-500 focus:ring-1 focus:ring-blue-500 transition-all font-mono"
/>
<input
type="text"
id="line1-expr"
readonly
class="w-full px-3 py-1 text-xs border border-gray-700 rounded bg-gray-900 text-gray-400 font-mono mt-1 cursor-default focus:outline-none focus:ring-0 focus:border-gray-700 selection:bg-gray-700 selection:text-gray-200"
/>
</div>
<div class="flex-1">
<label for="line2" class="block text-xs font-medium text-gray-400 mb-1"> Line 2 </label>
<input
type="text"
id="line2"
class="w-full px-3 py-1.5 text-sm border border-gray-600 rounded bg-gray-800 text-gray-100 focus:outline-none focus:border-blue-500 focus:ring-1 focus:ring-blue-500 transition-all font-mono"
/>
<input
type="text"
id="line2-expr"
readonly
class="w-full px-3 py-1 text-xs border border-gray-700 rounded bg-gray-900 text-gray-400 font-mono mt-1 cursor-default focus:outline-none focus:ring-0 focus:border-gray-700 selection:bg-gray-700 selection:text-gray-200"
/>
</div>
<div class="flex flex-col gap-2">
<div class="flex items-start gap-2">
<div class="w-24">
<label for="lang" class="block text-xs font-medium text-gray-400 mb-1">
Lang
</label>
<input
type="text"
id="lang"
class="w-full px-3 py-1.5 text-sm border border-gray-600 rounded bg-gray-800 text-gray-100 focus:outline-none focus:border-blue-500 focus:ring-1 focus:ring-blue-500 transition-all font-mono text-center"
maxlength="5"
/>
</div>
<div class="flex gap-2">
<button
id="shareBtn"
class="px-4 py-1.5 text-sm font-medium text-white bg-blue-600 rounded hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 focus:ring-offset-gray-900 transition-all mt-5"
>
Share
</button>
<button
id="resetBtn"
class="px-4 py-1.5 text-sm font-medium text-white bg-gray-700 rounded hover:bg-gray-600 focus:outline-none focus:ring-2 focus:ring-gray-500 focus:ring-offset-2 focus:ring-offset-gray-900 transition-all mt-5"
>
Reset
</button>
</div>
</div>
<label
class="flex items-center gap-2 text-xs text-gray-300 cursor-pointer whitespace-nowrap"
>
<input
type="checkbox"
id="showDifferencesRed"
class="w-4 h-4 text-blue-600 bg-gray-700 border-gray-600 rounded focus:ring-blue-500 focus:ring-2"
/>
<span>highlight line1 != line2</span>
</label>
</div>
</div>
</div>
</div>
<div id="map" class="flex-1"></div>
<!-- Modal Dialog -->
<div id="shareModal" class="hidden fixed inset-0 z-50">
<div id="modalOverlay" class="fixed inset-0 bg-black/50"></div>
<div class="fixed inset-0 flex items-center justify-center p-4">
<div class="relative bg-gray-800 rounded-lg p-8 max-w-md shadow-2xl">
<p class="text-gray-300 text-center leading-relaxed mb-6">
Your settings have been saved to the URL.<br />
Copy the address bar to share this map.
</p>
<button
id="closeModalBtn"
class="w-full py-2.5 text-sm text-white bg-gray-700 rounded hover:bg-gray-600 transition-all"
>
Close
</button>
</div>
</div>
</div>
<script src="https://unpkg.com/maplibre-gl/dist/maplibre-gl.js"></script>
<script src="mix.js"></script>
</body>
</html>

View File

@@ -0,0 +1,240 @@
// ============================================
// 1. MAIN EXECUTION (Entry Point)
// ============================================
const map = new maplibregl.Map({
container: 'map',
style: 'https://tiles.openfreemap.org/styles/liberty',
center: [0, 0],
zoom: 2,
hash: true,
})
const line1Input = document.getElementById('line1')
const line2Input = document.getElementById('line2')
const langInput = document.getElementById('lang')
const line1ExprInput = document.getElementById('line1-expr')
const line2ExprInput = document.getElementById('line2-expr')
const showDifferencesRedCheckbox = document.getElementById('showDifferencesRed')
map.on('load', () => {
const params = new URLSearchParams(window.location.search)
// Set defaults if no params present
if (!params.has('line1') && !params.has('line2') && !params.has('lang')) {
const url = new URL(window.location)
url.searchParams.set('line1', 'colon,underscore,latin,name')
url.searchParams.set('line2', 'nonlatin')
url.searchParams.set('lang', 'en')
window.history.replaceState({}, '', url)
}
syncInputsFromParams()
applyConfiguration()
initializeInputListeners()
initializeModal()
initializeResetButton()
})
// ============================================
// 2. UI INITIALIZATION
// ============================================
function initializeInputListeners() {
const debouncedApplyConfig = debounce(applyConfiguration, 500)
const handleInput = () => {
updateParamsFromInputs()
updateExpressionDisplays()
debouncedApplyConfig()
}
line1Input.addEventListener('input', handleInput)
line2Input.addEventListener('input', handleInput)
langInput.addEventListener('input', handleInput)
showDifferencesRedCheckbox.addEventListener('change', handleInput)
}
function initializeModal() {
const modal = document.getElementById('shareModal')
document.getElementById('shareBtn').addEventListener('click', () => {
modal.classList.remove('hidden')
})
document.getElementById('closeModalBtn').addEventListener('click', () => {
modal.classList.add('hidden')
})
document.addEventListener('keydown', e => {
if (e.key === 'Escape' && !modal.classList.contains('hidden')) {
modal.classList.add('hidden')
}
})
}
function initializeResetButton() {
document.getElementById('resetBtn').addEventListener('click', () => {
const hash = window.location.hash
window.location.href = `${window.location.pathname}${hash}`
})
}
// ============================================
// 3. CONFIGURATION & SYNC
// ============================================
function applyConfiguration() {
const { line1, line2, lang, showDifferencesRed } = parseParams()
if (!map.getStyle()) return
const style = map.getStyle()
modifyStyle({
style,
line1Config: line1 ?? '',
line2Config: line2 ?? '',
langCode: lang,
showDifferencesRed,
})
map.setStyle(style, { diff: true })
updateExpressionDisplays()
}
function syncInputsFromParams() {
const { line1, line2, lang, showDifferencesRed } = parseParams()
line1Input.value = line1 ?? ''
line2Input.value = line2 ?? ''
langInput.value = lang ?? ''
showDifferencesRedCheckbox.checked = showDifferencesRed
}
function updateParamsFromInputs() {
const params = new URLSearchParams(window.location.search)
params.set('line1', line1Input.value)
params.set('line2', line2Input.value)
params.set('lang', langInput.value)
if (showDifferencesRedCheckbox.checked) {
params.set('showDifferencesRed', '1')
} else {
params.delete('showDifferencesRed')
}
const queryString = params.toString()
const hash = window.location.hash
const newUrl = `${window.location.pathname}?${queryString}${hash}`
window.history.replaceState({}, '', newUrl)
}
function updateExpressionDisplays() {
const { line1, line2, lang } = parseParams()
const langCode = lang
const line1Expr = buildFieldAccessor(line1 ?? '', langCode)
const line2Expr = buildFieldAccessor(line2 ?? '', langCode)
line1ExprInput.value = line1Expr ? JSON.stringify(line1Expr) : ''
line2ExprInput.value = line2Expr ? JSON.stringify(line2Expr) : ''
}
// ============================================
// 4. STYLE MODIFICATION
// ============================================
function modifyStyle({ style, line1Config, line2Config, langCode, showDifferencesRed }) {
for (const layer of style.layers) {
if (layer.source !== 'openmaptiles') continue
if (!layer.layout) continue
const textField = layer.layout['text-field']
if (!textField) continue
if (JSON.stringify(textField) === JSON.stringify(['to-string', ['get', 'ref']])) continue
const id = layer.id
const separator = id.includes('line') || id.includes('highway') ? ' ' : '\n'
const line1Expr = buildFieldAccessor(line1Config, langCode)
const line2Expr = buildFieldAccessor(line2Config, langCode)
if (line1Expr && line2Expr) {
layer.layout['text-field'] = ['concat', line1Expr, separator, line2Expr]
} else if (line1Expr) {
layer.layout['text-field'] = line1Expr
} else if (line2Expr) {
layer.layout['text-field'] = line2Expr
} else {
layer.layout['text-field'] = ['get', 'name']
}
// Apply red color when differences should be shown
if (showDifferencesRed && line1Expr && line2Expr) {
if (!layer.paint) layer.paint = {}
layer.paint['text-color'] = [
'case',
['!=', line1Expr, line2Expr],
'#ff0000', // Red when different
'#000000', // Black when same
]
} else {
// Reset to default color if checkbox is unchecked
if (layer.paint && layer.paint['text-color']) {
delete layer.paint['text-color']
}
}
}
}
// ============================================
// 5. UTILITY FUNCTIONS
// ============================================
function debounce(func, delay) {
let timeoutId
return function (...args) {
clearTimeout(timeoutId)
timeoutId = setTimeout(() => {
func.apply(this, args)
}, delay)
}
}
function parseParams() {
const params = new URLSearchParams(window.location.search)
return {
line1: params.get('line1'),
line2: params.get('line2'),
lang: params.get('lang') || 'en',
showDifferencesRed: params.has('showDifferencesRed'),
}
}
function buildFieldAccessor(config, langCode) {
if (!config) return null
const parts = []
const fields = config
.split(',')
.map(f => f.trim())
.filter(f => f)
for (const field of fields) {
if (field === 'underscore') {
parts.push(['get', `name_${langCode}`])
} else if (field === 'colon') {
parts.push(['get', `name:${langCode}`])
} else if (field === 'latin') {
parts.push(['get', 'name:latin'])
} else if (field === 'nonlatin') {
parts.push(['get', 'name:nonlatin'])
} else if (field === 'name') {
parts.push(['get', 'name'])
} else {
parts.push(['get', field])
}
}
return parts.length > 0 ? ['coalesce', ...parts] : null
}

View File

@@ -0,0 +1,15 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>OpenFreeMap Debug</title>
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
<link href="https://unpkg.com/maplibre-gl/dist/maplibre-gl.css" rel="stylesheet" />
</head>
<body>
<div id="map" class="w-full h-screen"></div>
<script src="https://unpkg.com/maplibre-gl/dist/maplibre-gl.js"></script>
<script src="params.js"></script>
</body>
</html>

View File

@@ -0,0 +1,78 @@
const map = new maplibregl.Map({
container: 'map',
hash: 'map',
style: 'https://tiles.openfreemap.org/styles/liberty',
center: [0, 0],
zoom: 2,
})
function modifyStyle({ style, langCode }) {
if (!langCode) {
langCode = 'en'
}
for (const layer of style.layers) {
if (layer.source !== 'openmaptiles') continue
if (!layer.layout) continue
const textField = layer.layout['text-field']
if (!textField) continue
// highway numbers, etc. - skip ref-only fields
if (JSON.stringify(textField) === JSON.stringify(['to-string', ['get', 'ref']])) continue
const nameUnderscore = `name_${langCode}`
const nameColon = `name:${langCode}`
// Always display both values
layer.layout['text-field'] = ['concat', ['get', nameUnderscore], '\n', ['get', nameColon]]
// Color red when they are different
if (!layer.paint) layer.paint = {}
layer.paint['text-color'] = [
'case',
['!=', ['get', nameUnderscore], ['get', nameColon]],
'#ff0000', // Red when different
'#000000', // Default color when same (adjust as needed)
]
}
}
function getLanguageParam() {
const urlParams = new URLSearchParams(window.location.search)
return urlParams.get('lang')
}
function applyLanguage() {
const langCode = getLanguageParam() || null
const style = map.getStyle()
modifyStyle({ style, langCode })
map.setStyle(style, { diff: false })
}
map.on('load', () => {
const langCode = getLanguageParam()
// Alert the URL param value on first load
alert(
`Language parameter: ${langCode || 'not set (defaulting to en)'}\n\n` +
'To change the map language, modify the ?lang= parameter in the URL.\n' +
'Labels will be RED when different.\n' +
'name_xx on line 1, name:xx on line 2',
)
// Add default param if not present
if (!langCode) {
const url = new URL(window.location)
url.searchParams.set('lang', 'en')
window.history.replaceState({}, '', url)
}
applyLanguage()
})
// Listen for URL changes (e.g., browser back/forward)
window.addEventListener('popstate', () => {
applyLanguage()
})

View File

@@ -0,0 +1,15 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>OpenFreeMap Debug</title>
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
<link href="https://unpkg.com/maplibre-gl/dist/maplibre-gl.css" rel="stylesheet" />
</head>
<body>
<div id="map" class="w-full h-screen"></div>
<script src="https://unpkg.com/maplibre-gl/dist/maplibre-gl.js"></script>
<script src="switch.js"></script>
</body>
</html>

View File

@@ -0,0 +1,78 @@
const map = new maplibregl.Map({
container: 'map',
style: 'https://tiles.openfreemap.org/styles/liberty',
center: [0, 0],
zoom: 2,
})
function modifyStyle({ style, langCode }) {
if (!langCode) {
langCode = 'en'
}
for (const layer of style.layers) {
if (layer.source !== 'openmaptiles') continue
if (!layer.layout) continue
const textField = layer.layout['text-field']
if (!textField) continue
// highway numbers, etc. - skip ref-only fields
if (JSON.stringify(textField) === JSON.stringify(['to-string', ['get', 'ref']])) continue
const id = layer.id
let separator
if (id.includes('line') || id.includes('highway')) {
separator = ' '
} else {
separator = '\n'
}
// the default is "en", not "int"
let parts
if (langCode === 'int') {
parts = [['get', 'name']]
} else {
parts = [
['get', `name_${langCode}`],
['get', `name:${langCode}`],
['get', 'name'],
]
}
layer.layout['text-field'] = [
'case',
['has', 'name:nonlatin'],
['concat', ['get', 'name:latin'], separator, ['get', 'name:nonlatin']],
['coalesce', ...parts],
]
}
}
function applyLanguage() {
const hash = window.location.hash.substring(1) // Remove the '#'
const langCode = hash || null
const style = map.getStyle()
modifyStyle({ style, langCode })
map.setStyle(style, { diff: false })
}
map.on('load', () => {
// Add default hash if not present
if (!window.location.hash) {
alert(
'To change the map language, modify the language code in the URL.\n\nExamples:\n• #en → English\n• #de → German\n• #fr → French\n• #es → Spanish\n• #int → International names',
)
window.location.hash = '#es'
// The hashchange event will trigger applyLanguage()
} else {
applyLanguage()
}
})
// Listen for hash changes in URL
window.addEventListener('hashchange', () => {
applyLanguage()
})

View File

@@ -0,0 +1,15 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>OpenFreeMap Debug</title>
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
<link href="https://unpkg.com/maplibre-gl/dist/maplibre-gl.css" rel="stylesheet" />
</head>
<body>
<div id="map" class="w-full h-screen"></div>
<script src="https://unpkg.com/maplibre-gl/dist/maplibre-gl.js"></script>
<script src="terrain.js"></script>
</body>
</html>

View File

@@ -0,0 +1,26 @@
const map = new maplibregl.Map({
container: 'map',
hash: 'map',
zoom: 10.5,
center: [9.0788, 47.1194],
style: {
version: 8,
sources: {
hillshadeSource: {
type: 'raster-dem',
url: 'https://tiles.mapterhorn.com/tilejson.json',
},
},
layers: [
{
id: 'hillshade',
type: 'hillshade',
source: 'hillshadeSource',
},
],
},
})
map.on('load', () => {
console.log('Terrain map loaded')
})

View File

@@ -17,6 +17,8 @@ const { showStyleURL } = Astro.props
<button data-style="positron" class="btn">Positron</button> <button data-style="positron" class="btn">Positron</button>
<button data-style="bright" class="btn">Bright</button> <button data-style="bright" class="btn">Bright</button>
<button data-style="liberty" class="btn selected">Liberty</button> <button data-style="liberty" class="btn selected">Liberty</button>
<button data-style="dark" class="btn">Dark</button>
<button data-style="fiord" class="btn">Fiord</button>
<button data-style="liberty-3d" class="btn">3D</button> <button data-style="liberty-3d" class="btn">3D</button>
</div> </div>

10
website/wrangler.jsonc Normal file
View File

@@ -0,0 +1,10 @@
{
"$schema": "node_modules/wrangler/config-schema.json",
"name": "openfreemap-website",
"compatibility_date": "2025-10-17",
"assets": {
"directory": "./dist"
},
"account_id": "99fde2e5efdeb199c6910cdeaa276a97",
"workers_dev": false
}