Feature: UX-Fixes — Zahnrad weg, POI-Kombi-Typen, exp-fab-Position, Welten-Config in DB (SW by-v653)

- worlds-settings Zahnrad komplett entfernt (war auf Mobile sichtbar, auf Desktop schon hidden)
- exp-fab: bottom jetzt calc(--nav-bottom-height + --safe-bottom + --space-2) — kein Overlap mit worlds-back auf iPhone
- Karte POI: neue Typen bank, bank_kotbeutel, bank_kotbeutel_abfall, kotbeutel_abfall (Backend + Frontend)
- Welten-Chip-Config: GET/PUT /profile/world-config, Spalte users.world_config TEXT (Migration), Sync bei Init + Speichern
This commit is contained in:
rene 2026-05-03 19:50:04 +02:00
parent f0b5e6e89b
commit 1fdba57365
9 changed files with 84 additions and 27 deletions

View file

@ -3,7 +3,7 @@
Router, State-Management, Navigation, Initialisierung.
============================================================ */
const APP_VER = '652'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen
const APP_VER = '653'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen
const APP_VERSION = '1.3.0'; // ← semantische Version, wird bei make release gesetzt
const IS_STAGING = location.hostname === 'staging.banyaro.app';

View file

@ -839,14 +839,18 @@ window.Page_map = (() => {
}
const PIN_TYPES = [
{ type: 'giftkoeder', icon: '<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#skull"></use></svg>', label: 'Giftköder', color: '#DC2626' }, // ← wichtigster Typ, immer oben
{ type: 'waste_basket', icon: '<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#trash"></use></svg>', label: 'Mülleimer', color: '#6B7280' },
{ type: 'kotbeutel', icon: '<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#bag"></use></svg>', label: 'Kotbeutel', color: '#84A98C' },
{ type: 'drinking_water', icon: '<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#drop"></use></svg>', label: 'Wasserstelle', color: '#0EA5E9' },
{ type: 'dog_park', icon: '<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#leaf"></use></svg>', label: 'Hundewiese', color: '#15803D' },
{ type: 'parkplatz', icon: '<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#car"></use></svg>', label: 'Parkplatz', color: '#2563EB' },
{ type: 'treffpunkt', icon: '<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#handshake"></use></svg>', label: 'Treffpunkt', color: '#7C3AED' },
{ type: 'sonstiges', icon: '<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#push-pin"></use></svg>', label: 'Sonstiges', color: '#F59E0B' },
{ type: 'giftkoeder', icon: '<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#skull"></use></svg>', label: 'Giftköder', color: '#DC2626' },
{ type: 'waste_basket', icon: '<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#trash"></use></svg>', label: 'Mülleimer', color: '#6B7280' },
{ type: 'kotbeutel', icon: '<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#bag"></use></svg>', label: 'Kotbeutel', color: '#84A98C' },
{ type: 'kotbeutel_abfall', icon: '<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#bag"></use></svg>', label: 'Kotbeutel + Mülleimer', color: '#5a8a6a' },
{ type: 'bank', icon: '<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#park"></use></svg>', label: 'Sitzbank', color: '#92400E' },
{ type: 'bank_kotbeutel', icon: '<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#park"></use></svg>', label: 'Bank + Kotbeutel', color: '#7a6030' },
{ type: 'bank_kotbeutel_abfall', icon: '<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#park"></use></svg>', label: 'Bank + Kotbeutel + Mülleimer', color: '#4a5a2a' },
{ type: 'drinking_water', icon: '<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#drop"></use></svg>', label: 'Wasserstelle', color: '#0EA5E9' },
{ type: 'dog_park', icon: '<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#leaf"></use></svg>', label: 'Hundewiese', color: '#15803D' },
{ type: 'parkplatz', icon: '<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#car"></use></svg>', label: 'Parkplatz', color: '#2563EB' },
{ type: 'treffpunkt', icon: '<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#handshake"></use></svg>', label: 'Treffpunkt', color: '#7C3AED' },
{ type: 'sonstiges', icon: '<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#push-pin"></use></svg>', label: 'Sonstiges', color: '#F59E0B' },
];
function _confirmPlacement(latlng) {

View file

@ -49,6 +49,8 @@ window.Worlds = (() => {
_setupButtons();
_goTo(_cur, false);
show();
// Config aus DB laden (async, dann neu rendern wenn nötig)
await _loadConfigFromServer();
// Welten parallel rendern
_renderJetzt();
_renderHund();
@ -159,7 +161,6 @@ window.Worlds = (() => {
function _setupButtons() {
document.getElementById('worlds-fab')?.addEventListener('click', _openFab);
document.getElementById('worlds-settings')?.addEventListener('click', () => navigateTo('settings'));
document.getElementById('worlds-back')?.addEventListener('click', () => show());
document.querySelectorAll('.wdot').forEach((dot, i) => {
dot.style.pointerEvents = 'auto';
@ -296,12 +297,33 @@ window.Worlds = (() => {
welt: ['map','forum','friends','walks','poison','recalls','lost','routes','events','jobs','knigge','movies'],
};
function _getConfig() {
try { return JSON.parse(localStorage.getItem('world_chips') || 'null') || _DEFAULT_CONFIG; }
catch { return _DEFAULT_CONFIG; }
// _cfgCache: wird beim Init aus DB geladen, Fallback localStorage → Default
let _cfgCache = null;
async function _loadConfigFromServer() {
try {
const res = await API.get('/profile/world-config');
if (res?.config) {
_cfgCache = res.config;
try { localStorage.setItem('world_chips', JSON.stringify(_cfgCache)); } catch {}
return;
}
} catch {}
// Fallback: localStorage
try { _cfgCache = JSON.parse(localStorage.getItem('world_chips') || 'null') || _DEFAULT_CONFIG; }
catch { _cfgCache = _DEFAULT_CONFIG; }
}
function _getConfig() {
return _cfgCache || _DEFAULT_CONFIG;
}
function _saveConfig(cfg) {
_cfgCache = cfg;
try { localStorage.setItem('world_chips', JSON.stringify(cfg)); } catch {}
if (_state?.user) {
API.put('/profile/world-config', { config: cfg }).catch(() => {});
}
}
function _chipMeta(page) {
return _ALL_CHIPS.find(c => c.page === page) || null;