fix: floating mini-chat overlay style + weather precip fallback
- KnowledgeView mini-chat: replace harsh border-top with upward box-shadow and rounded top corners (16px); remove padding-bottom from content area so widget truly overlays cards without pushing layout; add collapse toggle (chevron) that hides messages without closing the conversation - WeatherCard: show precip_mm as fallback when precipitation_probability_max is null but actual rainfall is expected (Open-Meteo omits probability for some forecast days even when rain is shown) - Pass precip_mm through weather service → frontend type definitions Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -7,6 +7,7 @@ interface ForecastDay {
|
|||||||
high: number
|
high: number
|
||||||
low: number
|
low: number
|
||||||
precip_probability: number | null
|
precip_probability: number | null
|
||||||
|
precip_mm: number | null
|
||||||
windspeed_max: number
|
windspeed_max: number
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,7 +91,12 @@ const fetchedAtLabel = computed(() => {
|
|||||||
<span class="forecast-icon">{{ weatherIcon(day.condition) }}</span>
|
<span class="forecast-icon">{{ weatherIcon(day.condition) }}</span>
|
||||||
<span class="forecast-condition">{{ day.condition }}</span>
|
<span class="forecast-condition">{{ day.condition }}</span>
|
||||||
<span class="forecast-temps">{{ day.high }}° / {{ day.low }}°</span>
|
<span class="forecast-temps">{{ day.high }}° / {{ day.low }}°</span>
|
||||||
<span v-if="day.precip_probability != null && day.precip_probability > 0" class="forecast-precip">💧 {{ day.precip_probability }}%</span>
|
<span v-if="day.precip_probability != null && day.precip_probability > 0" class="forecast-precip">
|
||||||
|
💧 {{ day.precip_probability }}%
|
||||||
|
</span>
|
||||||
|
<span v-else-if="day.precip_mm != null && day.precip_mm > 0" class="forecast-precip">
|
||||||
|
💧 {{ day.precip_mm.toFixed(1) }}mm
|
||||||
|
</span>
|
||||||
<span v-else class="forecast-precip forecast-precip--dry">💧 —</span>
|
<span v-else class="forecast-precip forecast-precip--dry">💧 —</span>
|
||||||
<span class="forecast-wind">💨 {{ day.windspeed_max }} {{ weather.wind_unit ?? 'km/h' }}</span>
|
<span class="forecast-wind">💨 {{ day.windspeed_max }} {{ weather.wind_unit ?? 'km/h' }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ interface WeatherData {
|
|||||||
yesterday_high: number | null
|
yesterday_high: number | null
|
||||||
yesterday_low: number | null
|
yesterday_low: number | null
|
||||||
wind_unit?: string
|
wind_unit?: string
|
||||||
forecast: { day: string; condition: string; high: number; low: number; precip_probability: number | null; windspeed_max: number }[]
|
forecast: { day: string; condition: string; high: number; low: number; precip_probability: number | null; precip_mm: number | null; windspeed_max: number }[]
|
||||||
}
|
}
|
||||||
|
|
||||||
const chatStore = useChatStore()
|
const chatStore = useChatStore()
|
||||||
|
|||||||
@@ -136,6 +136,7 @@ function toggleGraph() {
|
|||||||
|
|
||||||
const chatInput = ref("");
|
const chatInput = ref("");
|
||||||
const chatOpen = ref(false);
|
const chatOpen = ref(false);
|
||||||
|
const chatCollapsed = ref(false);
|
||||||
const chatConvId = ref<number | null>(null);
|
const chatConvId = ref<number | null>(null);
|
||||||
const chatSending = ref(false);
|
const chatSending = ref(false);
|
||||||
const chatMessages = computed(() => {
|
const chatMessages = computed(() => {
|
||||||
@@ -437,8 +438,8 @@ onUnmounted(() => {
|
|||||||
|
|
||||||
<!-- Floating mini-chat -->
|
<!-- Floating mini-chat -->
|
||||||
<div class="minichat" :class="{ 'minichat--open': chatOpen }">
|
<div class="minichat" :class="{ 'minichat--open': chatOpen }">
|
||||||
<!-- Message history (shown when chatOpen) -->
|
<!-- Message history (shown when chatOpen and not collapsed) -->
|
||||||
<div v-if="chatOpen" class="minichat-messages" ref="chatScrollEl">
|
<div v-if="chatOpen && !chatCollapsed" class="minichat-messages" ref="chatScrollEl">
|
||||||
<template v-if="chatMessages.length === 0 && !chatStore.streaming">
|
<template v-if="chatMessages.length === 0 && !chatStore.streaming">
|
||||||
<div class="minichat-welcome">Ask me anything about your notes, tasks, or ideas.</div>
|
<div class="minichat-welcome">Ask me anything about your notes, tasks, or ideas.</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -495,6 +496,17 @@ onUnmounted(() => {
|
|||||||
title="Send"
|
title="Send"
|
||||||
>↑</button>
|
>↑</button>
|
||||||
</div>
|
</div>
|
||||||
|
<button
|
||||||
|
v-if="chatOpen"
|
||||||
|
class="btn-close-chat"
|
||||||
|
@click="chatCollapsed = !chatCollapsed"
|
||||||
|
:title="chatCollapsed ? 'Expand chat' : 'Collapse chat'"
|
||||||
|
>
|
||||||
|
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5">
|
||||||
|
<polyline v-if="chatCollapsed" points="18 15 12 9 6 15"/>
|
||||||
|
<polyline v-else points="6 9 12 15 18 9"/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
<button
|
<button
|
||||||
v-if="chatOpen"
|
v-if="chatOpen"
|
||||||
class="btn-close-chat"
|
class="btn-close-chat"
|
||||||
@@ -633,7 +645,6 @@ onUnmounted(() => {
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
padding-bottom: 64px; /* space for minichat input */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Toolbar ─────────────────────────────────────────────── */
|
/* ── Toolbar ─────────────────────────────────────────────── */
|
||||||
@@ -904,9 +915,10 @@ onUnmounted(() => {
|
|||||||
z-index: 20;
|
z-index: 20;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
border-top: 1px solid var(--color-border, rgba(255,255,255,0.06));
|
|
||||||
background: var(--color-bg-secondary);
|
background: var(--color-bg-secondary);
|
||||||
transition: all 0.2s;
|
border-radius: 16px 16px 0 0;
|
||||||
|
box-shadow: 0 -8px 32px rgba(0,0,0,0.35), 0 -1px 0 rgba(255,255,255,0.05);
|
||||||
|
transition: box-shadow 0.2s;
|
||||||
}
|
}
|
||||||
.knowledge-root.graph-open .minichat {
|
.knowledge-root.graph-open .minichat {
|
||||||
right: 420px;
|
right: 420px;
|
||||||
@@ -918,8 +930,9 @@ onUnmounted(() => {
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
background: var(--color-bg);
|
background: transparent;
|
||||||
border-bottom: 1px solid var(--color-border, rgba(255,255,255,0.06));
|
border-bottom: 1px solid rgba(255,255,255,0.05);
|
||||||
|
border-radius: 16px 16px 0 0;
|
||||||
}
|
}
|
||||||
.minichat-welcome {
|
.minichat-welcome {
|
||||||
color: var(--color-muted);
|
color: var(--color-muted);
|
||||||
|
|||||||
@@ -155,6 +155,7 @@ def parse_weather_card_data(
|
|||||||
"high": to_temp(d["temp_max"]),
|
"high": to_temp(d["temp_max"]),
|
||||||
"low": to_temp(d["temp_min"]),
|
"low": to_temp(d["temp_min"]),
|
||||||
"precip_probability": d["precip_probability"],
|
"precip_probability": d["precip_probability"],
|
||||||
|
"precip_mm": d["precip_mm"],
|
||||||
"windspeed_max": to_wind(d["windspeed_max"]),
|
"windspeed_max": to_wind(d["windspeed_max"]),
|
||||||
}
|
}
|
||||||
for d in future_days
|
for d in future_days
|
||||||
|
|||||||
Reference in New Issue
Block a user