diff --git a/Makefile b/Makefile index 95d8cce6..435ea944 100644 --- a/Makefile +++ b/Makefile @@ -83,4 +83,27 @@ fix: cargo fmt cargo clippy --fix --allow-dirty --allow-staged -.PHONY: check fmt fmt-check clippy test fix check-appcontext check-handler-deps check-handler-repos check-presentation-adapters check-federation-off-social check-social-crates-are-ap-free +# Run the dev stack: +# server (:3000, in the foreground, Ctrl-C stops it) +# worker (background, log at /tmp/movies-diary-worker.log) +# spa (:5173, background, log at /tmp/movies-diary-spa.log) +# Tear down the background processes with `make dev-stop`. +# .env enables EVENT_BUS_BACKEND=nats, so both binaries are built with the nats feature. +dev: dev-worker dev-spa + cargo run -p server --features nats + +dev-stop: + -pkill -f '[t]arget.debug.worker' || true + -pkill -f '[s]pa/node_modules/[.]bin/vite' || true + @echo "dev stack stopped" + +dev-worker: + @bash -c 'nohup cargo run -p worker --features nats >> /tmp/movies-diary-worker.log 2>&1 & echo "worker → pid $$! (log: /tmp/movies-diary-worker.log)"' + +dev-spa: + @bash -c 'nohup npm --prefix spa run dev >> /tmp/movies-diary-spa.log 2>&1 & echo "spa → pid $$! (log: /tmp/movies-diary-spa.log, http://localhost:5173)"' + +spa-dev: + @npm --prefix spa run dev + +.PHONY: check fmt fmt-check clippy test fix dev dev-stop dev-worker dev-spa spa-dev check-appcontext check-handler-deps check-handler-repos check-presentation-adapters check-federation-off-social check-social-crates-are-ap-free diff --git a/spa/src/locales/en.json b/spa/src/locales/en.json index f187cfce..385b36cc 100644 --- a/spa/src/locales/en.json +++ b/spa/src/locales/en.json @@ -267,14 +267,14 @@ "seasons": "Seasons", "mediums": "How you watch", "rhythm": "When you watch", - "ratingLiftUp": "You rate {{genre}} higher than your own average — {{genreAvg}}★ vs {{userAvg}}★", - "ratingLiftDown": "You rate {{genre}} lower than your own average — {{genreAvg}}★ vs {{userAvg}}★", + "ratingLiftUp": "You rate {{genre}} higher than your own average — {{genreAvg}}★ vs {{userAvg}}★", + "ratingLiftDown": "You rate {{genre}} lower than your own average — {{genreAvg}}★ vs {{userAvg}}★", "yourAverage": "your average", - "seasonality": "{{genre}} is your {{month}} genre — {{multiplier}}× your yearly baseline", - "mediumTiming": "You watch {{medium}} on weekends {{multiplier}}× more than your baseline", + "seasonality": "{{genre}} is your {{month}} genre — {{multiplier}}× your yearly baseline", + "mediumTiming": "You watch {{medium}} on weekends {{multiplier}}× more than your baseline", "weekends": "weekends", "yourBaseline": "your baseline", - "rhythm": "You watch mostly {{start}}–{{end}} on {{days}}", + "rhythmBody": "You watch mostly {{start}}–{{end}} on {{days}}", "filmsSample": "{{count}} films" }, "wrapup": { diff --git a/spa/src/routes/_app/insights.tsx b/spa/src/routes/_app/insights.tsx index 06ada321..2584fcee 100644 --- a/spa/src/routes/_app/insights.tsx +++ b/spa/src/routes/_app/insights.tsx @@ -1,6 +1,6 @@ import { createFileRoute } from "@tanstack/react-router" import type { ReactNode } from "react" -import { useTranslation } from "react-i18next" +import { Trans, useTranslation } from "react-i18next" import { CalendarDays, Clapperboard, @@ -26,6 +26,8 @@ export const Route = createFileRoute("/_app/insights")({ const MONTH_BASE = new Date(2024, 0, 1) // any year; only the month name matters const MONDAY_BASE = new Date(2024, 2, 4) // 2024-03-04 is a Monday +const hl = + function isKind(kind: K) { return (insight: Insight): insight is Extract => insight.kind === kind } @@ -138,11 +140,17 @@ function RatingLiftCard({ insight }: RatingLiftCardProps) { - {t(up ? "insights.ratingLiftUp" : "insights.ratingLiftDown", { - genre: insight.genre, - genreAvg: insight.genre_avg.toFixed(1), - userAvg: insight.user_avg.toFixed(1), - })} + + + @@ -161,17 +169,22 @@ function RatingLiftCard({ insight }: RatingLiftCardProps) { } function SeasonalityCard({ insight }: SeasonalityCardProps) { - const { t } = useTranslation() return ( - {t("insights.seasonality", { - genre: insight.genre, - multiplier: insight.multiplier.toFixed(1), - month: monthName(insight.month), - })} + + + @@ -194,10 +207,16 @@ function MediumTimingCard({ insight }: MediumTimingCardProps) { - {t("insights.mediumTiming", { - medium: mediumLabel(insight.medium, t), - multiplier: insight.multiplier.toFixed(1), - })} + + + @@ -216,17 +235,22 @@ function MediumTimingCard({ insight }: MediumTimingCardProps) { } function RhythmCard({ insight }: RhythmCardProps) { - const { t } = useTranslation() return ( - {t("insights.rhythm", { - start: hourLabel(insight.peak_hour_start), - end: hourLabel(insight.peak_hour_end), - days: dayNames(insight.top_days).join(", "), - })} + + +