feat(config): add configuration window (#70)

This commit is contained in:
2026-05-21 04:16:21 -07:00
committed by GitHub
parent a54f03f0cd
commit dc52bc2fba
287 changed files with 14507 additions and 8134 deletions
+1 -1
View File
@@ -86,7 +86,7 @@ export interface AnkiConnectConfig {
color?: string;
};
nPlusOne?: {
nPlusOne?: string;
enabled?: boolean;
minSentenceWords?: number;
};
behavior?: {
+18 -6
View File
@@ -30,6 +30,7 @@ import type {
FrequencyDictionaryMatchMode,
FrequencyDictionaryMode,
NPlusOneMatchMode,
ResolvedSubtitleSidebarConfig,
SecondarySubConfig,
SubtitlePosition,
SubtitleSidebarConfig,
@@ -52,16 +53,21 @@ export interface TexthookerConfig {
}
export type MpvLaunchMode = 'normal' | 'maximized' | 'fullscreen';
export type MpvBackend = 'auto' | 'hyprland' | 'sway' | 'x11' | 'macos' | 'windows';
export interface MpvConfig {
executablePath?: string;
launchMode?: MpvLaunchMode;
socketPath?: string;
backend?: MpvBackend;
autoStartSubMiner?: boolean;
pauseUntilOverlayReady?: boolean;
subminerBinaryPath?: string;
aniskipEnabled?: boolean;
aniskipButtonKey?: string;
}
export type SubsyncMode = 'auto' | 'manual';
export interface SubsyncConfig {
defaultMode?: SubsyncMode;
alass_path?: string;
ffsubsync_path?: string;
ffmpeg_path?: string;
@@ -150,6 +156,13 @@ export interface ResolvedConfig {
mpv: {
executablePath: string;
launchMode: MpvLaunchMode;
socketPath: string;
backend: MpvBackend;
autoStartSubMiner: boolean;
pauseUntilOverlayReady: boolean;
subminerBinaryPath: string;
aniskipEnabled: boolean;
aniskipButtonKey: string;
};
controller: {
enabled: boolean;
@@ -212,10 +225,9 @@ export interface ResolvedConfig {
addMinedWordsImmediately: boolean;
matchMode: NPlusOneMatchMode;
decks: Record<string, string[]>;
color: string;
};
nPlusOne: {
nPlusOne: string;
enabled: boolean;
minSentenceWords: number;
};
behavior: {
@@ -261,7 +273,7 @@ export interface ResolvedConfig {
bandedColors: [string, string, string, string, string];
};
};
subtitleSidebar: Required<SubtitleSidebarConfig>;
subtitleSidebar: ResolvedSubtitleSidebarConfig;
auto_start_overlay: boolean;
jimaku: JimakuConfig & {
apiBaseUrl: string;
+1
View File
@@ -1,5 +1,6 @@
export type RuntimeOptionId =
| 'anki.autoUpdateNewCards'
| 'subtitle.annotation.knownWords.highlightEnabled'
| 'subtitle.annotation.nPlusOne'
| 'subtitle.annotation.jlpt'
| 'subtitle.annotation.frequency'
+5 -4
View File
@@ -26,11 +26,12 @@ import type {
} from './integrations';
import type {
PrimarySubMode,
ResolvedSubtitleSidebarConfig,
SecondarySubMode,
SubtitleData,
SubtitlePosition,
SubtitleSidebarConfig,
SubtitleSidebarSnapshot,
SubtitleRendererStyleConfig,
SubtitleStyleConfig,
} from './subtitle';
import type {
@@ -343,8 +344,8 @@ export interface ConfigHotReloadPayload {
keybindings: Keybinding[];
sessionBindings: CompiledSessionBinding[];
sessionBindingWarnings: SessionBindingWarning[];
subtitleStyle: SubtitleStyleConfig | null;
subtitleSidebar: Required<SubtitleSidebarConfig>;
subtitleStyle: SubtitleRendererStyleConfig | null;
subtitleSidebar: ResolvedSubtitleSidebarConfig;
primarySubMode: PrimarySubMode;
secondarySubMode: SecondarySubMode;
}
@@ -426,7 +427,7 @@ export interface ElectronAPI {
getSecondarySubMode: () => Promise<SecondarySubMode>;
getCurrentSecondarySub: () => Promise<string>;
focusMainWindow: () => Promise<void>;
getSubtitleStyle: () => Promise<SubtitleStyleConfig | null>;
getSubtitleStyle: () => Promise<SubtitleRendererStyleConfig | null>;
onSubsyncManualOpen: (callback: (payload: SubsyncManualPayload) => void) => void;
runSubsyncManual: (request: SubsyncManualRunRequest) => Promise<SubsyncResult>;
onKikuFieldGroupingRequest: (callback: (data: KikuFieldGroupingRequestData) => void) => void;
+1
View File
@@ -2,6 +2,7 @@ export type SessionKeyModifier = 'ctrl' | 'alt' | 'shift' | 'meta';
export type SessionActionId =
| 'toggleStatsOverlay'
| 'markWatched'
| 'toggleVisibleOverlay'
| 'copySubtitle'
| 'copySubtitleMultiple'
+28 -3
View File
@@ -1,9 +1,9 @@
import type { ConfigValidationWarning } from './config';
export type ConfigSettingsCategory =
| 'viewing'
| 'appearance'
| 'behavior'
| 'mining-anki'
| 'playback-sources'
| 'input'
| 'integrations'
| 'tracking-app'
@@ -18,7 +18,16 @@ export type ConfigSettingsControl =
| 'color'
| 'string-list'
| 'json'
| 'secret';
| 'secret'
| 'keyboard-shortcut'
| 'key-code'
| 'mpv-key'
| 'known-words-decks'
| 'anki-note-type'
| 'anki-field'
| 'mpv-keybindings'
| 'color-list'
| 'css-declarations';
export type ConfigSettingsRestartBehavior = 'hot-reload' | 'restart';
@@ -29,6 +38,7 @@ export interface ConfigSettingsField {
configPath: string;
category: ConfigSettingsCategory;
section: string;
subsection?: string;
control: ConfigSettingsControl;
defaultValue: unknown;
enumValues?: readonly string[];
@@ -36,6 +46,7 @@ export interface ConfigSettingsField {
advanced?: boolean;
secret?: boolean;
legacyHidden?: boolean;
settingsHidden?: boolean;
}
export type ConfigSettingsSnapshotValue = unknown;
@@ -77,4 +88,18 @@ export interface ConfigSettingsAPI {
savePatch(patch: ConfigSettingsPatch): Promise<ConfigSettingsSaveResult>;
openSettingsFile(): Promise<boolean>;
openSettingsWindow(): Promise<boolean>;
getAnkiDeckNames(draftUrl?: string): Promise<ConfigSettingsAnkiListResult>;
getAnkiDeckFieldNames(deckName: string, draftUrl?: string): Promise<ConfigSettingsAnkiListResult>;
getAnkiDeckModelNames(deckName: string, draftUrl?: string): Promise<ConfigSettingsAnkiListResult>;
getAnkiModelNames(draftUrl?: string): Promise<ConfigSettingsAnkiListResult>;
getAnkiModelFieldNames(
modelName: string,
draftUrl?: string,
): Promise<ConfigSettingsAnkiListResult>;
}
export interface ConfigSettingsAnkiListResult {
ok: boolean;
values: string[];
error?: string;
}
+18 -1
View File
@@ -70,6 +70,7 @@ export type FrequencyDictionaryMatchMode = 'headword' | 'surface';
export interface SubtitleStyleConfig {
primaryDefaultMode?: PrimarySubMode;
css?: Record<string, string>;
enableJlpt?: boolean;
preserveLineBreaks?: boolean;
autoPauseVideoOnHover?: boolean;
@@ -89,6 +90,8 @@ export interface SubtitleStyleConfig {
fontKerning?: string;
textRendering?: string;
textShadow?: string;
paintOrder?: string;
WebkitTextStroke?: string;
backdropFilter?: string;
backgroundColor?: string;
nPlusOneColor?: string;
@@ -110,6 +113,7 @@ export interface SubtitleStyleConfig {
bandedColors?: [string, string, string, string, string];
};
secondary?: {
css?: Record<string, string>;
fontFamily?: string;
fontSize?: number;
fontColor?: string;
@@ -121,11 +125,15 @@ export interface SubtitleStyleConfig {
fontKerning?: string;
textRendering?: string;
textShadow?: string;
paintOrder?: string;
WebkitTextStroke?: string;
backdropFilter?: string;
backgroundColor?: string;
};
}
export type SubtitleRendererStyleConfig = SubtitleStyleConfig;
export interface TokenPos1ExclusionConfig {
defaults?: string[];
add?: string[];
@@ -163,6 +171,7 @@ export interface SubtitleSidebarConfig {
toggleKey?: string;
pauseVideoOnHover?: boolean;
autoScroll?: boolean;
css?: Record<string, string>;
maxWidth?: number;
opacity?: number;
backgroundColor?: string;
@@ -175,6 +184,14 @@ export interface SubtitleSidebarConfig {
hoverLineBackgroundColor?: string;
}
export type ResolvedSubtitleSidebarConfig = Required<Omit<SubtitleSidebarConfig, 'css'>> & {
css: Record<string, string>;
};
export type SubtitleSidebarSnapshotConfig = Required<Omit<SubtitleSidebarConfig, 'css'>> & {
css?: Record<string, string>;
};
export interface SubtitleData {
text: string;
tokens: MergedToken[] | null;
@@ -190,7 +207,7 @@ export interface SubtitleSidebarSnapshot {
startTime: number | null;
endTime: number | null;
};
config: Required<SubtitleSidebarConfig>;
config: SubtitleSidebarSnapshotConfig;
}
export interface SubtitleHoverTokenPayload {