mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-03-22 12:11:27 -07:00
fix: align subtitle sidebar state and behavior updates
This commit is contained in:
@@ -1,11 +1,11 @@
|
||||
---
|
||||
id: TASK-216
|
||||
title: 'Address PR #28 CodeRabbit follow-ups on subtitle sidebar'
|
||||
status: In Progress
|
||||
status: Completed
|
||||
assignee:
|
||||
- '@codex'
|
||||
created_date: '2026-03-21 00:00'
|
||||
updated_date: '2026-03-22 04:05'
|
||||
updated_date: '2026-03-21 00:00'
|
||||
labels:
|
||||
- pr-review
|
||||
- subtitle-sidebar
|
||||
@@ -64,6 +64,8 @@ Verification:
|
||||
2026-03-22: Addressed the live hover-state and startup mouse-ignore follow-ups from the latest CodeRabbit pass. `handleMouseLeave()` now clears `isOverSubtitle` and drops `secondary-sub-hover-active` when leaving the secondary subtitle container toward the primary container, and renderer startup now calls `syncOverlayMouseIgnoreState(ctx)` instead of forcing `setIgnoreMouseEvents(true, { forward: true })`. The sidebar IPC hover catch and CSS spacing comments were already satisfied in the current tree.
|
||||
|
||||
2026-03-22: Regenerated `bun.lock` from a clean install so the `electron-builder-squirrel-windows` override now resolves at `26.8.2` in the lockfile alongside `app-builder-lib@26.8.2`.
|
||||
|
||||
2026-03-21: Finished the remaining cleanup pass from the latest review. `subtitleSidebar.layout` now uses enum validation, `SubtitleCue` is re-exported from `src/types.ts` as the single public type path, and the subtitle sidebar resize listener now has unload cleanup wired through the renderer.
|
||||
<!-- SECTION:NOTES:END -->
|
||||
|
||||
## Final Summary
|
||||
|
||||
@@ -124,7 +124,8 @@ export function buildSubtitleConfigOptionRegistry(
|
||||
},
|
||||
{
|
||||
path: 'subtitleSidebar.layout',
|
||||
kind: 'string',
|
||||
kind: 'enum',
|
||||
enumValues: ['overlay', 'embedded'],
|
||||
defaultValue: defaultConfig.subtitleSidebar.layout,
|
||||
description: 'Render the subtitle sidebar as a floating overlay or reserve space inside mpv.',
|
||||
},
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import test from 'node:test';
|
||||
import { parseSrtCues, parseAssCues, parseSubtitleCues } from './subtitle-cue-parser';
|
||||
import type { SubtitleCue } from './subtitle-cue-parser';
|
||||
import type { SubtitleCue } from '../../types';
|
||||
|
||||
test('parseSrtCues parses basic SRT content', () => {
|
||||
const content = [
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import test from 'node:test';
|
||||
import { computePriorityWindow, createSubtitlePrefetchService } from './subtitle-prefetch';
|
||||
import type { SubtitleCue } from './subtitle-cue-parser';
|
||||
import type { SubtitleData } from '../../types';
|
||||
import type { SubtitleCue } from '../../types';
|
||||
|
||||
function makeCues(count: number, startOffset = 0): SubtitleCue[] {
|
||||
return Array.from({ length: count }, (_, i) => ({
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { SubtitleCue } from './subtitle-cue-parser';
|
||||
import type { SubtitleData } from '../../types';
|
||||
import type { SubtitleCue } from '../../types';
|
||||
|
||||
export interface SubtitlePrefetchServiceDeps {
|
||||
cues: SubtitleCue[];
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import test from 'node:test';
|
||||
import type { SubtitleCue } from '../../core/services/subtitle-cue-parser';
|
||||
import type { SubtitlePrefetchService } from '../../core/services/subtitle-prefetch';
|
||||
import type { SubtitleCue } from '../../types';
|
||||
import { createSubtitlePrefetchInitController } from './subtitle-prefetch-init';
|
||||
|
||||
function createDeferred<T>(): {
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import type { SubtitleCue } from '../../core/services/subtitle-cue-parser';
|
||||
import type {
|
||||
SubtitlePrefetchService,
|
||||
SubtitlePrefetchServiceDeps,
|
||||
} from '../../core/services/subtitle-prefetch';
|
||||
import type { SubtitleData } from '../../types';
|
||||
import type { SubtitleCue } from '../../types';
|
||||
|
||||
export interface SubtitlePrefetchInitControllerDeps {
|
||||
getCurrentService: () => SubtitlePrefetchService | null;
|
||||
|
||||
@@ -5,11 +5,11 @@ import type {
|
||||
MpvSubtitleRenderMetrics,
|
||||
SecondarySubMode,
|
||||
SubtitleData,
|
||||
SubtitleCue,
|
||||
SubtitlePosition,
|
||||
KikuFieldGroupingChoice,
|
||||
JlptLevel,
|
||||
FrequencyDictionaryLookup,
|
||||
SubtitleCue,
|
||||
} from '../types';
|
||||
import type { CliArgs } from '../cli/args';
|
||||
import type { SubtitleTimingTracker } from '../subtitle-timing-tracker';
|
||||
|
||||
@@ -145,6 +145,7 @@ export function createSubtitleSidebarModal(
|
||||
let snapshotPollInterval: ReturnType<typeof setTimeout> | null = null;
|
||||
let lastAppliedVideoMarginRatio: number | null = null;
|
||||
let subtitleSidebarHoverRequestId = 0;
|
||||
let disposeDomEvents: (() => void) | null = null;
|
||||
|
||||
function restoreEmbeddedSidebarPassthrough(): void {
|
||||
syncOverlayMouseIgnoreState(ctx);
|
||||
@@ -515,6 +516,10 @@ export function createSubtitleSidebarModal(
|
||||
}
|
||||
|
||||
function wireDomEvents(): void {
|
||||
if (disposeDomEvents) {
|
||||
return;
|
||||
}
|
||||
|
||||
ctx.dom.subtitleSidebarClose.addEventListener('click', () => {
|
||||
closeSubtitleSidebarModal();
|
||||
});
|
||||
@@ -565,12 +570,17 @@ export function createSubtitleSidebarModal(
|
||||
ctx.state.isOverSubtitleSidebar = false;
|
||||
resumeSubtitleSidebarHoverPause();
|
||||
});
|
||||
window.addEventListener('resize', () => {
|
||||
const resizeHandler = () => {
|
||||
if (!ctx.state.subtitleSidebarModalOpen) {
|
||||
return;
|
||||
}
|
||||
syncEmbeddedSidebarLayout();
|
||||
});
|
||||
};
|
||||
window.addEventListener('resize', resizeHandler);
|
||||
disposeDomEvents = () => {
|
||||
window.removeEventListener('resize', resizeHandler);
|
||||
disposeDomEvents = null;
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -580,6 +590,9 @@ export function createSubtitleSidebarModal(
|
||||
toggleSubtitleSidebarModal,
|
||||
refreshSubtitleSidebarSnapshot: refreshSnapshot,
|
||||
wireDomEvents,
|
||||
disposeDomEvents: () => {
|
||||
disposeDomEvents?.();
|
||||
},
|
||||
handleSubtitleUpdated,
|
||||
seekToCue,
|
||||
};
|
||||
|
||||
@@ -543,6 +543,9 @@ async function init(): Promise<void> {
|
||||
controllerDebugModal.wireDomEvents();
|
||||
sessionHelpModal.wireDomEvents();
|
||||
subtitleSidebarModal.wireDomEvents();
|
||||
window.addEventListener('beforeunload', () => {
|
||||
subtitleSidebarModal.disposeDomEvents();
|
||||
});
|
||||
|
||||
window.electronAPI.onRuntimeOptionsChanged((options: RuntimeOptionState[]) => {
|
||||
runGuarded('runtime-options:changed', () => {
|
||||
|
||||
@@ -10,8 +10,8 @@ import type {
|
||||
RuntimeOptionState,
|
||||
RuntimeOptionValue,
|
||||
SubtitlePosition,
|
||||
SubtitleCue,
|
||||
SubtitleSidebarConfig,
|
||||
SubtitleCue,
|
||||
SubsyncSourceTrack,
|
||||
} from '../types';
|
||||
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type { SubtitleCue } from './core/services/subtitle-cue-parser';
|
||||
|
||||
export enum PartOfSpeech {
|
||||
noun = 'noun',
|
||||
verb = 'verb',
|
||||
@@ -364,11 +366,7 @@ export interface ResolvedTokenPos2ExclusionConfig {
|
||||
|
||||
export type FrequencyDictionaryMode = 'single' | 'banded';
|
||||
|
||||
export interface SubtitleCue {
|
||||
startTime: number;
|
||||
endTime: number;
|
||||
text: string;
|
||||
}
|
||||
export type { SubtitleCue } from './core/services/subtitle-cue-parser';
|
||||
|
||||
export type SubtitleSidebarLayout = 'overlay' | 'embedded';
|
||||
|
||||
|
||||
Reference in New Issue
Block a user