Feature: Hundesalons in der Karte, SW by-v1098

- OSM-Query 'hundesalon' nutzt shop=pet_grooming + craft=pet_grooming
- map.js: neuer Layer 'hundesalon' mit Schere-Icon (#EC4899 Pink),
  in Layer-Liste, TYPEN, OSM_LAYER_MAP und PIN_TYPES eingetragen
- User können selbst Hundesalons als POI anlegen
  (places.py TYPEN + osm.py ALLOWED_TYPES erweitert)
This commit is contained in:
rene 2026-05-26 21:13:16 +02:00
parent 6ad7c4be77
commit cc4f030fd0
7 changed files with 18 additions and 12 deletions

View file

@ -46,6 +46,7 @@ OSM_QUERIES = {
'drinking_water': '[out:json][timeout:20];node["amenity"="drinking_water"]({bbox});out;',
'tierarzt': '[out:json][timeout:25];(node["amenity"="veterinary"]({bbox});way["amenity"="veterinary"]({bbox}););out center;',
'shop': '[out:json][timeout:25];(node["shop"="pet"]({bbox});way["shop"="pet"]({bbox}););out center;',
'hundesalon': '[out:json][timeout:25];(node["shop"="pet_grooming"]({bbox});way["shop"="pet_grooming"]({bbox});node["craft"="pet_grooming"]({bbox});way["craft"="pet_grooming"]({bbox}););out center;',
'restaurant': '[out:json][timeout:35];(node["amenity"~"restaurant|cafe"]["dog"~"yes|allowed"]({bbox});way["amenity"~"restaurant|cafe"]["dog"~"yes|allowed"]({bbox});node["amenity"="biergarten"]({bbox});way["amenity"="biergarten"]({bbox}););out center;',
'bank': '[out:json][timeout:20];node["amenity"="bench"]({bbox});out;',
'hotel': '[out:json][timeout:25];(node["tourism"~"hotel|guest_house|hostel"]["dog"~"yes|allowed"]({bbox});way["tourism"~"hotel|guest_house|hostel"]["dog"~"yes|allowed"]({bbox}););out center;',
@ -286,6 +287,7 @@ ALLOWED_TYPES = {
'restaurant', # Hundefreundliches Restaurant / Café
'shop', # Hundefreundlicher Shop
'tierarzt', # Tierarzt / Tierklinik
'hundesalon', # Hundesalon / Hundefriseur / Groomer
'hundeschule', # Hundeschule / Trainer
'kotbeutel', # Kotbeutelspender
'bank', # Sitzbank

View file

@ -9,7 +9,7 @@ from auth import get_current_user
router = APIRouter()
TYPEN = {'restaurant', 'shop', 'freilauf', 'kotbeutel', 'tierarzt', 'hundeschule'}
TYPEN = {'restaurant', 'shop', 'freilauf', 'kotbeutel', 'tierarzt', 'hundesalon', 'hundeschule'}
def _haversine(lat1: float, lon1: float, lat2: float, lon2: float) -> float:

View file

@ -101,9 +101,9 @@
</script>
<!-- CSS: Reihenfolge ist wichtig — ?v= zwingt Browser zur Neuladung -->
<link rel="stylesheet" href="/css/design-system.css?v=1097">
<link rel="stylesheet" href="/css/layout.css?v=1097">
<link rel="stylesheet" href="/css/components.css?v=1097">
<link rel="stylesheet" href="/css/design-system.css?v=1098">
<link rel="stylesheet" href="/css/layout.css?v=1098">
<link rel="stylesheet" href="/css/components.css?v=1098">
</head>
<body>
@ -625,11 +625,11 @@
<div id="modal-container"></div>
<!-- JS: Reihenfolge ist wichtig — erst Basis, dann Features -->
<script src="/js/api.js?v=1097"></script>
<script src="/js/ui.js?v=1097"></script>
<script src="/js/app.js?v=1097"></script>
<script src="/js/worlds.js?v=1097"></script>
<script src="/js/offline-indicator.js?v=1097"></script>
<script src="/js/api.js?v=1098"></script>
<script src="/js/ui.js?v=1098"></script>
<script src="/js/app.js?v=1098"></script>
<script src="/js/worlds.js?v=1098"></script>
<script src="/js/offline-indicator.js?v=1098"></script>
<!-- Feature-Seiten werden lazy geladen -->

View file

@ -3,7 +3,7 @@
Router, State-Management, Navigation, Initialisierung.
============================================================ */
const APP_VER = '1097'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen
const APP_VER = '1098'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen
const APP_VERSION = '1.6.0'; // ← semantische Version, wird bei make release gesetzt
window.APP_VER = APP_VER; // global verfügbar für andere Module (z.B. offline-indicator)
window.APP_VERSION = APP_VERSION;

View file

@ -46,6 +46,7 @@ window.Page_map = (() => {
shop: [],
kotbeutel: [],
tierarzt: [],
hundesalon: [],
hundeschule: [],
poison: [],
muell: [],
@ -83,6 +84,7 @@ window.Page_map = (() => {
shop: { icon: '<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#shopping-cart"></use></svg>', label: 'Shop', color: '#3B82F6', z: 15 },
kotbeutel: { icon: '<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#bag"></use></svg>', label: 'Kotbeutel', color: '#84A98C', z: 5 },
tierarzt: { icon: '<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#first-aid"></use></svg>', label: 'Tierarzt', color: '#EF4444', z: 40 },
hundesalon: { icon: '<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#scissors"></use></svg>', label: 'Hundesalon', color: '#EC4899', z: 25 },
hundeschule: { icon: '<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#graduation-cap"></use></svg>', label: 'Hundeschule', color: '#8B5CF6', z: 30 },
poison: { icon: '<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#warning"></use></svg>', label: 'Giftköder', color: '#DC2626', z: 100 },
muell: { icon: '<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#trash"></use></svg>', label: 'Mülleimer', color: '#6B7280', z: -20 },
@ -104,6 +106,7 @@ window.Page_map = (() => {
dog_park: 'dog_park',
wasser: 'drinking_water',
tierarzt: 'tierarzt',
hundesalon: 'hundesalon',
shop: 'shop',
restaurant: 'restaurant',
bank: 'bank',
@ -1069,6 +1072,7 @@ window.Page_map = (() => {
{ type: 'restaurant', icon: '<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#fork-knife"></use></svg>', label: 'Restaurant', color: '#F97316' },
{ type: 'shop', icon: '<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#shopping-cart"></use></svg>', label: 'Shop', color: '#3B82F6' },
{ type: 'tierarzt', icon: '<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#first-aid"></use></svg>', label: 'Tierarzt', color: '#EF4444' },
{ type: 'hundesalon', icon: '<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#scissors"></use></svg>', label: 'Hundesalon', color: '#EC4899' },
{ type: 'hundeschule', icon: '<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#graduation-cap"></use></svg>', label: 'Hundeschule', color: '#8B5CF6' },
{ 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' },

View file

@ -4,7 +4,7 @@
============================================================ */
// ← EINZIGE Stelle für die Version — STATIC_ASSETS und CACHE_VERSION leiten sich ab
const VER = '1097';
const VER = '1098';
const CACHE_VERSION = `by-v${VER}`;
const CACHE_STATIC = `${CACHE_VERSION}-static`;
const CACHE_TILES = 'ban-yaro-tiles-v1'; // bleibt über SW-Updates erhalten