diff --git a/docs-site/changelog.md b/docs-site/changelog.md index 9cc40bc..9c8348d 100644 --- a/docs-site/changelog.md +++ b/docs-site/changelog.md @@ -6,6 +6,8 @@ - Improved stats accuracy and scale handling with Yomitan token counts, full session timelines, known-word timeline fixes, cross-media vocabulary fixes, and clearer session charts. - Improved overlay/runtime stability with quieter macOS fullscreen recovery, reduced repeated loading OSD popups, and better frequency/noise handling for subtitle annotations. - Added launcher mpv-args passthrough plus Linux plugin wrapper-name fallback for packaged installs. +- Added a hover-revealed ↗ button on Sessions tab rows to navigate directly to the anime media-detail view, with correct "Back to Sessions" back-navigation. +- Excluded auxiliary-stem `そうだ` grammar tails (MeCab POS3 `助動詞語幹`) from subtitle annotation metadata so frequency, JLPT, and N+1 styling no longer bleed onto grammar-tail tokens. ## v0.6.5 (2026-03-15) - Seeded the AUR checkout with the repo `.SRCINFO` template before rewriting metadata so tagged releases do not depend on prior AUR state. diff --git a/docs-site/immersion-tracking.md b/docs-site/immersion-tracking.md index 076c396..0614dd2 100644 --- a/docs-site/immersion-tracking.md +++ b/docs-site/immersion-tracking.md @@ -52,7 +52,7 @@ Watch time, sessions, words seen, and per-anime progress/pattern charts with con #### Sessions -Expandable session history with new-word activity, cumulative totals, and pause/seek/card markers. +Expandable session history with new-word activity, cumulative totals, and pause/seek/card markers. Each session row exposes a hover-revealed ↗ button that navigates to the anime media-detail view for that session; pressing the back button there returns to the Sessions tab. ![Stats Sessions](/screenshots/stats-sessions.png) diff --git a/docs-site/subtitle-annotations.md b/docs-site/subtitle-annotations.md index 6dea3b8..686908c 100644 --- a/docs-site/subtitle-annotations.md +++ b/docs-site/subtitle-annotations.md @@ -4,7 +4,7 @@ SubMiner annotates subtitle tokens in real time as they appear in the overlay. F All four are opt-in and configured under `subtitleStyle`, `ankiConnect.knownWords`, and `ankiConnect.nPlusOne` in your config. They apply independently — you can enable any combination. -Before any of those layers render, SubMiner strips annotation metadata from tokens that are usually just subtitle glue or annotation noise. Standalone particles, auxiliaries, adnominals, common explanatory endings like `んです` / `のだ`, merged trailing quote-particle forms like `...って`, repeated kana interjections, and similar non-lexical helper tokens remain hoverable in the subtitle text, but they render as plain tokens without known-word, N+1, frequency, JLPT, or name-match annotation styling. +Before any of those layers render, SubMiner strips annotation metadata from tokens that are usually just subtitle glue or annotation noise. Standalone particles, auxiliaries, adnominals, common explanatory endings like `んです` / `のだ`, merged trailing quote-particle forms like `...って`, auxiliary-stem grammar tails like `そうだ` (MeCab POS3 `助動詞語幹`), repeated kana interjections, and similar non-lexical helper tokens remain hoverable in the subtitle text, but they render as plain tokens without known-word, N+1, frequency, JLPT, or name-match annotation styling. ## N+1 Word Highlighting diff --git a/stats/src/App.tsx b/stats/src/App.tsx index 9d93a57..2fa9bc4 100644 --- a/stats/src/App.tsx +++ b/stats/src/App.tsx @@ -10,6 +10,7 @@ import { navigateToSession as navigateToSessionState, openAnimeEpisodeDetail, openOverviewMediaDetail, + openSessionsMediaDetail, switchTab, } from './lib/stats-navigation'; @@ -110,6 +111,10 @@ export function App() { [], ); + const navigateToSessionsMediaDetail = useCallback((videoId: number) => { + setViewState((prev) => openSessionsMediaDetail(prev, videoId)); + }, []); + const openWordDetail = useCallback((wordId: number) => { setGlobalWordId(wordId); }, []); @@ -155,7 +160,14 @@ export function App() { } onBack={() => setViewState((prev) => closeMediaDetail(prev))} backLabel={ - mediaDetail.origin.type === 'overview' ? 'Back to Overview' : 'Back to Library' + mediaDetail.origin.type === 'overview' + ? 'Back to Overview' + : mediaDetail.origin.type === 'sessions' + ? 'Back to Sessions' + : 'Back to Library' + } + onNavigateToAnime={ + mediaDetail.origin.type === 'anime' ? undefined : navigateToAnime } /> @@ -242,6 +254,7 @@ export function App() { onClearInitialSession={() => setViewState((prev) => ({ ...prev, focusedSessionId: null })) } + onNavigateToMediaDetail={navigateToSessionsMediaDetail} /> diff --git a/stats/src/components/sessions/SessionRow.tsx b/stats/src/components/sessions/SessionRow.tsx index dc30825..1d4d503 100644 --- a/stats/src/components/sessions/SessionRow.tsx +++ b/stats/src/components/sessions/SessionRow.tsx @@ -11,6 +11,7 @@ interface SessionRowProps { onToggle: () => void; onDelete: () => void; deleteDisabled?: boolean; + onNavigateToMediaDetail?: (videoId: number) => void; } function CoverThumbnail({ @@ -56,6 +57,7 @@ export function SessionRow({ onToggle, onDelete, deleteDisabled = false, + onNavigateToMediaDetail, }: SessionRowProps) { const displayWordCount = getSessionDisplayWordCount(session); const knownWordsSeen = session.knownWordsSeen; @@ -109,6 +111,20 @@ export function SessionRow({ {'\u25B8'} + {onNavigateToMediaDetail != null && session.videoId != null ? ( + + ) : null}