feat(briefing): tabbed weather locations, sticky weather, wider sidebar

Add location tabs when multiple weather sources configured. Weather
section stays pinned at top of sidebar while news scrolls independently.
Bump sidebar width from 420px to 620px max for better readability.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-16 18:30:16 -04:00
parent f12d29563a
commit 8b0dd732f7
+68 -15
View File
@@ -56,8 +56,9 @@ const todayConvId = ref<number | null>(null)
const isToday = computed(() => selectedConvId.value === todayConvId.value)
// Weather panel (left column)
// Weather panel
const weatherData = ref<WeatherData[]>([])
const selectedWeatherIdx = ref(0)
const tempUnit = ref<string>('C')
interface CurrentConditions {
@@ -274,17 +275,25 @@ onMounted(async () => {
<!-- Right column: Weather + News -->
<div class="briefing-right">
<!-- Weather section -->
<template v-if="weatherData.length">
<!-- Weather section (sticky) -->
<div class="weather-section" v-if="weatherData.length">
<div class="weather-tabs" v-if="weatherData.length > 1">
<button
v-for="(loc, i) in weatherData"
:key="(loc as WeatherData).location"
class="weather-tab"
:class="{ active: selectedWeatherIdx === i }"
@click="selectedWeatherIdx = i"
>{{ (loc as WeatherData).location }}</button>
</div>
<WeatherCard
v-for="loc in weatherData"
:key="(loc as WeatherData).location"
:weather="loc"
:weather="weatherData[selectedWeatherIdx]"
:temp-unit="tempUnit"
/>
</template>
</div>
<!-- News section -->
<!-- News section (scrollable) -->
<div class="news-section">
<div class="panel-label-row">
<div class="panel-label">Today's News</div>
<span v-if="newsItems.length" class="news-count">{{ newsItems.length }} items</span>
@@ -329,6 +338,7 @@ onMounted(async () => {
>💬</button>
</div>
</div>
</div>
</div>
</div>
</div>
@@ -344,7 +354,7 @@ onMounted(async () => {
.briefing-shell {
display: grid;
grid-template-columns: 1fr minmax(320px, 420px);
grid-template-columns: 1fr minmax(420px, 620px);
grid-template-rows: auto 1fr;
height: 100%;
min-height: 0;
@@ -438,17 +448,60 @@ onMounted(async () => {
grid-column: 2;
grid-row: 2;
border-left: 1px solid var(--color-border);
display: flex;
flex-direction: column;
min-height: 0;
}
.weather-section {
flex-shrink: 0;
padding: 1rem 1rem 0.5rem;
border-bottom: 1px solid var(--color-border);
}
.weather-section :deep(.weather-card) {
margin-bottom: 0;
}
.weather-tabs {
display: flex;
gap: 0.25rem;
margin-bottom: 0.5rem;
}
.weather-tab {
padding: 0.3rem 0.7rem;
border: 1px solid var(--color-border);
border-radius: 6px;
background: none;
color: var(--color-text-muted);
font-size: 0.78rem;
font-family: inherit;
cursor: pointer;
transition: all 0.15s;
}
.weather-tab:hover {
border-color: var(--color-primary);
color: var(--color-primary);
}
.weather-tab.active {
background: color-mix(in srgb, var(--color-primary) 12%, transparent);
border-color: var(--color-primary);
color: var(--color-primary);
font-weight: 600;
}
.news-section {
flex: 1;
overflow-y: auto;
padding: 1rem;
padding: 0.75rem 1rem 1rem;
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.briefing-right :deep(.weather-card) {
margin-bottom: 0.25rem;
}
.panel-label {
font-size: 0.72rem;
font-weight: 700;
@@ -561,7 +614,7 @@ a.news-title:hover { text-decoration: underline; color: var(--color-primary); }
/* ─── Responsive ─────────────────────────────────────────────────────────── */
@media (max-width: 700px) {
@media (max-width: 900px) {
.briefing-shell {
grid-template-columns: 1fr;
grid-template-rows: auto 1fr auto;