diff --git a/apps/mana/apps/web/src/lib/modules/wetter/ListView.svelte b/apps/mana/apps/web/src/lib/modules/wetter/ListView.svelte index 23aeee591..86ac215a5 100644 --- a/apps/mana/apps/web/src/lib/modules/wetter/ListView.svelte +++ b/apps/mana/apps/web/src/lib/modules/wetter/ListView.svelte @@ -35,6 +35,14 @@ await locationsStore.addLocation(name, lat, lon); } + async function removeLocation(id: string) { + await locationsStore.removeLocation(id); + } + + async function setDefaultLocation(id: string) { + await locationsStore.setDefault(id); + } + onMount(() => { if (weatherStore.weatherData) return; @@ -66,6 +74,8 @@ {selectedLon} onSelect={selectLocation} onSave={saveLocation} + onRemove={removeLocation} + onSetDefault={setDefaultLocation} /> diff --git a/apps/mana/apps/web/src/lib/modules/wetter/components/LocationPicker.svelte b/apps/mana/apps/web/src/lib/modules/wetter/components/LocationPicker.svelte index 9a5c29af0..0690fb3ac 100644 --- a/apps/mana/apps/web/src/lib/modules/wetter/components/LocationPicker.svelte +++ b/apps/mana/apps/web/src/lib/modules/wetter/components/LocationPicker.svelte @@ -1,5 +1,6 @@
+
{#if locations.length > 0}
@@ -71,68 +89,127 @@ {/each}
+ {:else} + Keine Orte gespeichert {/if}
- + {#if locations.length > 0} + + {/if}
+ {#if showSearch} -
- - -
+
+
+ + +
- {#if searchResults.length > 0} -
- {#each searchResults as result} -
selectSearchResult(result)} - onkeydown={(e: KeyboardEvent) => { - if (e.key === 'Enter') selectSearchResult(result); - }} - > - {result.name} - - {result.admin1 ? `${result.admin1}, ` : ''}{result.country} - -
+ {/if} + + + {#if showManage} +
+ Gespeicherte Orte + {#each locations as loc (loc.id)} +
+ + {#if loc.isDefault}{/if} + {loc.name} + + {loc.lat.toFixed(2)}, {loc.lon.toFixed(2)} +
+ {#if !loc.isDefault} + + {/if} +
- {/each} -
- {/if} +
+ {/each} +

★ = Standard-Ort beim Oeffnen

+
{/if}
@@ -153,7 +230,15 @@ flex-wrap: wrap; flex: 1; } + .no-locations { + font-size: 0.8rem; + color: var(--text-tertiary, #6b7280); + flex: 1; + } .loc-chip { + display: flex; + align-items: center; + gap: 4px; padding: 6px 12px; border-radius: 20px; font-size: 0.8rem; @@ -168,6 +253,13 @@ color: #38bdf8; border-color: rgba(56, 189, 248, 0.3); } + .default-dot { + width: 5px; + height: 5px; + border-radius: 50%; + background: #38bdf8; + flex-shrink: 0; + } .picker-actions { display: flex; gap: 4px; @@ -184,10 +276,36 @@ display: flex; align-items: center; justify-content: center; + color: var(--text-secondary, #9ca3af); } - .action-btn:hover { + .action-btn:hover, + .action-btn.active { background: var(--card-bg-hover, rgba(255, 255, 255, 0.1)); + color: var(--text-primary, #f3f4f6); } + .manage-btn { + font-size: 0.85rem; + } + + /* Panels */ + .panel { + background: var(--card-bg, rgba(255, 255, 255, 0.06)); + border: 1px solid var(--border-subtle, rgba(255, 255, 255, 0.08)); + border-radius: 12px; + padding: 10px; + display: flex; + flex-direction: column; + gap: 8px; + } + .panel-title { + font-size: 0.75rem; + font-weight: 500; + color: var(--text-secondary, #9ca3af); + text-transform: uppercase; + letter-spacing: 0.05em; + } + + /* Search */ .search-form { display: flex; gap: 8px; @@ -197,7 +315,7 @@ padding: 8px 12px; border-radius: 8px; border: 1px solid var(--border-subtle, rgba(255, 255, 255, 0.1)); - background: var(--card-bg, rgba(255, 255, 255, 0.06)); + background: var(--card-bg, rgba(255, 255, 255, 0.04)); color: var(--text-primary, #f3f4f6); font-size: 0.85rem; outline: none; @@ -221,23 +339,19 @@ .search-results { display: flex; flex-direction: column; - gap: 2px; - background: var(--card-bg, rgba(255, 255, 255, 0.06)); - border: 1px solid var(--border-subtle, rgba(255, 255, 255, 0.08)); - border-radius: 10px; - overflow: hidden; } .result-item { display: flex; align-items: center; gap: 8px; - padding: 10px 12px; + padding: 8px 6px; border: none; background: none; color: var(--text-primary, #f3f4f6); cursor: pointer; text-align: left; width: 100%; + border-radius: 6px; } .result-item:hover { background: var(--card-bg-hover, rgba(255, 255, 255, 0.06)); @@ -251,22 +365,74 @@ color: var(--text-secondary, #9ca3af); flex: 1; } - .save-btn { - width: 24px; - height: 24px; - border-radius: 12px; - border: 1px solid var(--border-subtle, rgba(255, 255, 255, 0.15)); + .save-label { + font-size: 0.7rem; + color: #38bdf8; + flex-shrink: 0; + } + .already-saved { + font-size: 0.7rem; + color: var(--text-tertiary, #6b7280); + flex-shrink: 0; + } + + /* Manage panel */ + .manage-panel { + gap: 4px; + } + .manage-row { + display: flex; + align-items: center; + gap: 8px; + padding: 8px 6px; + border-radius: 6px; + } + .manage-row:hover { + background: var(--card-bg-hover, rgba(255, 255, 255, 0.04)); + } + .manage-name { + font-size: 0.85rem; + color: var(--text-primary, #f3f4f6); + flex: 1; + display: flex; + align-items: center; + gap: 4px; + } + .default-star { + color: #f59e0b; + font-size: 0.8rem; + } + .manage-coords { + font-size: 0.7rem; + color: var(--text-tertiary, #6b7280); + } + .manage-actions { + display: flex; + gap: 4px; + } + .manage-action { + width: 26px; + height: 26px; + border-radius: 6px; + border: 1px solid var(--border-subtle, rgba(255, 255, 255, 0.1)); background: none; color: var(--text-secondary, #9ca3af); - font-size: 1rem; + font-size: 0.9rem; cursor: pointer; display: flex; align-items: center; justify-content: center; - flex-shrink: 0; } - .save-btn:hover { - background: var(--accent-subtle, rgba(56, 189, 248, 0.15)); - color: #38bdf8; + .manage-action:hover { + background: var(--card-bg-hover, rgba(255, 255, 255, 0.08)); + color: #f59e0b; + } + .manage-action.delete:hover { + color: #ef4444; + } + .manage-hint { + font-size: 0.65rem; + color: var(--text-tertiary, #6b7280); + margin: 4px 0 0; } diff --git a/apps/mana/apps/web/src/routes/(app)/wetter/+page.svelte b/apps/mana/apps/web/src/routes/(app)/wetter/+page.svelte index 346a164b2..f3bf252d2 100644 --- a/apps/mana/apps/web/src/routes/(app)/wetter/+page.svelte +++ b/apps/mana/apps/web/src/routes/(app)/wetter/+page.svelte @@ -35,6 +35,14 @@ await locationsStore.addLocation(name, lat, lon); } + async function removeLocation(id: string) { + await locationsStore.removeLocation(id); + } + + async function setDefaultLocation(id: string) { + await locationsStore.setDefault(id); + } + // On mount: use default location, or first saved, or GPS onMount(() => { const defaultLoc = locations.find((l) => l.isDefault) ?? locations[0]; @@ -72,6 +80,8 @@ {selectedLon} onSelect={selectLocation} onSave={saveLocation} + onRemove={removeLocation} + onSetDefault={setDefaultLocation} />