diff --git a/.forgejo/workflows/ci.yml b/.forgejo/workflows/ci.yml index 18f566d..f657f3e 100644 --- a/.forgejo/workflows/ci.yml +++ b/.forgejo/workflows/ci.yml @@ -68,19 +68,14 @@ jobs: steps: - uses: actions/checkout@v6 - # Cache node_modules directly (not the npm download cache). - # npm ci still has to extract + link every module even with a - # warm download cache, which is where the real time goes. Caching - # the output directory lets us skip npm ci entirely on hits. - - name: Cache node_modules - id: npm-cache + - name: Cache npm download cache uses: actions/cache@v4 with: - path: frontend/node_modules - key: node-modules-${{ hashFiles('frontend/package-lock.json') }} + path: ~/.npm + key: npm-cache-${{ hashFiles('frontend/package-lock.json') }} + restore-keys: npm-cache- - name: Install dependencies - if: steps.npm-cache.outputs.cache-hit != 'true' run: npm ci working-directory: frontend diff --git a/frontend/src/components/WeatherCard.vue b/frontend/src/components/WeatherCard.vue index c25cebd..e884199 100644 --- a/frontend/src/components/WeatherCard.vue +++ b/frontend/src/components/WeatherCard.vue @@ -85,22 +85,30 @@ const fetchedAtLabel = computed(() => { Today: {{ weather.today_high }}° / {{ weather.today_low }}° · {{ tempDelta }} -
-
- {{ day.day }} - {{ weatherIcon(day.condition) }} - {{ day.condition }} - {{ day.high }}° / {{ day.low }}° - - 💧 {{ day.precip_probability }}% - - - 💧 {{ day.precip_mm.toFixed(1) }}mm - - 💧 — - 💨 {{ day.windspeed_max }} {{ weather.wind_unit ?? 'km/h' }} -
-
+ + + + + + + + + + + + + + + + + + + +
Hi / Lo💧💨 {{ weather.wind_unit ?? 'km/h' }}
{{ day.day }}{{ weatherIcon(day.condition) }}{{ day.high }}° / {{ day.low }}° + + + + {{ day.windspeed_max }}
Weather data unavailable — will retry at next slot. @@ -169,20 +177,31 @@ const fetchedAtLabel = computed(() => { } .weather-forecast { - display: flex; - gap: 0.75rem; - overflow-x: auto; - padding-top: 0.75rem; + width: 100%; + border-collapse: collapse; + margin-top: 0.75rem; border-top: 1px solid var(--color-border); + font-size: 0.8rem; } -.weather-forecast-day { - display: flex; - flex-direction: column; - align-items: center; - gap: 0.25rem; - min-width: 4.5rem; - font-size: 0.8rem; +.weather-forecast thead th { + font-size: 0.68rem; + font-weight: 600; + color: var(--color-text-muted); + text-align: right; + padding: 0.5rem 0.4rem 0.25rem; + white-space: nowrap; +} + +.weather-forecast thead th:first-child, +.weather-forecast thead th:nth-child(2) { + text-align: left; +} + +.weather-forecast tbody td { + padding: 0.3rem 0.4rem; + white-space: nowrap; + vertical-align: middle; } .forecast-day-name { @@ -190,26 +209,16 @@ const fetchedAtLabel = computed(() => { } .forecast-icon { - font-size: 1.2rem; + font-size: 1.1rem; line-height: 1; } -.forecast-condition { - font-size: 0.7rem; - color: var(--color-text-muted); - text-align: center; - line-height: 1.2; - word-break: break-word; -} - .forecast-temps { - white-space: nowrap; + text-align: right; } -.forecast-precip, -.forecast-wind { - font-size: 0.72rem; - white-space: nowrap; +.forecast-precip { + text-align: right; color: var(--color-text-muted); } @@ -217,6 +226,11 @@ const fetchedAtLabel = computed(() => { opacity: 0.35; } +.forecast-wind { + text-align: right; + color: var(--color-text-muted); +} + .weather-unavailable { color: var(--color-text-muted); font-style: italic; diff --git a/frontend/src/views/BriefingView.vue b/frontend/src/views/BriefingView.vue index 53a6c63..77d2144 100644 --- a/frontend/src/views/BriefingView.vue +++ b/frontend/src/views/BriefingView.vue @@ -261,22 +261,7 @@ onMounted(async () => {
- -
-
Weather
- - -
No weather configured
-
- - +
{ />
- +
+ + + +
Today's News
{{ newsItems.length }} items @@ -348,7 +344,7 @@ onMounted(async () => { .briefing-shell { display: grid; - grid-template-columns: 1fr 2fr 1fr; + grid-template-columns: 1fr minmax(320px, 420px); grid-template-rows: auto 1fr; height: 100%; min-height: 0; @@ -421,27 +417,10 @@ onMounted(async () => { } .btn-trigger:disabled { opacity: 0.5; cursor: not-allowed; } -/* ─── Left column (Weather) ──────────────────────────────────────────────── */ - -.briefing-left { - grid-column: 1; - grid-row: 2; - border-right: 1px solid var(--color-border); - overflow-y: auto; - padding: 1rem; - display: flex; - flex-direction: column; - gap: 0.75rem; -} - -.briefing-left :deep(.weather-card) { - margin-bottom: 0; -} - -/* ─── Center column (Chat) ───────────────────────────────────────────────── */ +/* ─── Left column (Chat) ─────────────────────────────────────────────────── */ .briefing-center { - grid-column: 2; + grid-column: 1; grid-row: 2; display: flex; flex-direction: column; @@ -453,10 +432,10 @@ onMounted(async () => { min-height: 0; } -/* ─── Right column (News) ────────────────────────────────────────────────── */ +/* ─── Right column (Weather + News) ──────────────────────────────────────── */ .briefing-right { - grid-column: 3; + grid-column: 2; grid-row: 2; border-left: 1px solid var(--color-border); overflow-y: auto; @@ -466,6 +445,10 @@ onMounted(async () => { gap: 0.5rem; } +.briefing-right :deep(.weather-card) { + margin-bottom: 0.25rem; +} + .panel-label { font-size: 0.72rem; font-weight: 700; @@ -578,32 +561,21 @@ a.news-title:hover { text-decoration: underline; color: var(--color-primary); } /* ─── Responsive ─────────────────────────────────────────────────────────── */ -@media (max-width: 900px) { +@media (max-width: 700px) { .briefing-shell { grid-template-columns: 1fr; - grid-template-rows: auto auto 1fr auto; - } - .briefing-header { - grid-column: 1; - grid-row: 1; - } - .briefing-left { - grid-column: 1; - grid-row: 2; - border-right: none; - border-bottom: 1px solid var(--color-border); - max-height: 220px; + grid-template-rows: auto 1fr auto; } .briefing-center { grid-column: 1; - grid-row: 3; + grid-row: 2; } .briefing-right { grid-column: 1; - grid-row: 4; + grid-row: 3; border-left: none; border-top: 1px solid var(--color-border); - max-height: 260px; + max-height: 300px; } }