mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-05-27 12:55:20 -07:00
feat(config): add subtitle CSS editor, nPlusOne.enabled flag, and fix se
- subtitleStyle.css / subtitleStyle.secondary.css replace flat style fields in the settings window - ankiConnect.nPlusOne.enabled gates known-word cache independently of knownWords.highlightEnabled - Settings search now covers all categories, narrows on multi-word terms, and hides editor-owned fields - Default note-type picker to Kiku then Lapis; rename isLapis.sentenceCardModel default to "Lapis"
This commit is contained in:
@@ -10,12 +10,23 @@ import {
|
||||
} from './settings-anki-controls';
|
||||
import type { SettingsControlContext } from './settings-control-context';
|
||||
import { createElement, isSecretSnapshotValue } from './settings-control-dom';
|
||||
import { renderKeyboardInput, renderMpvKeybindingsInput } from './settings-keybinding-controls';
|
||||
import {
|
||||
configureKeybindingControls,
|
||||
renderKeyboardInput,
|
||||
renderMpvKeybindingsInput,
|
||||
} from './settings-keybinding-controls';
|
||||
import {
|
||||
getSubtitleCssManagedConfigPaths,
|
||||
getSubtitleCssScopeForPath,
|
||||
parseSubtitleCssDeclarations,
|
||||
serializeSubtitleCssDeclarations,
|
||||
} from './subtitle-style-css';
|
||||
|
||||
export { renderNoteFieldModelPicker };
|
||||
|
||||
export function configureSettingsControls(options: { requestRender: () => void }): void {
|
||||
configureAnkiControls(options);
|
||||
configureKeybindingControls(options);
|
||||
}
|
||||
|
||||
export function initializeSettingsControls(
|
||||
@@ -90,6 +101,44 @@ function renderStringListInput(
|
||||
return textarea;
|
||||
}
|
||||
|
||||
function renderCssDeclarationsInput(
|
||||
context: SettingsControlContext,
|
||||
field: ConfigSettingsField,
|
||||
): HTMLElement {
|
||||
const scope = getSubtitleCssScopeForPath(field.configPath);
|
||||
const textarea = createElement(
|
||||
'textarea',
|
||||
'config-textarea css-declarations',
|
||||
) as HTMLTextAreaElement;
|
||||
textarea.spellcheck = false;
|
||||
if (!scope) return textarea;
|
||||
|
||||
const managedPaths = getSubtitleCssManagedConfigPaths(scope);
|
||||
const values: Record<string, ConfigSettingsSnapshotValue | undefined> = {
|
||||
[field.configPath]: context.valueForPath(field.configPath),
|
||||
};
|
||||
for (const path of managedPaths) {
|
||||
values[path] = context.valueForPath(path);
|
||||
}
|
||||
textarea.value = serializeSubtitleCssDeclarations(scope, values);
|
||||
textarea.addEventListener('input', () => {
|
||||
const parsed = parseSubtitleCssDeclarations(textarea.value);
|
||||
if (!parsed.ok) {
|
||||
textarea.classList.add('invalid');
|
||||
context.setFieldError(field.configPath, parsed.error);
|
||||
return;
|
||||
}
|
||||
|
||||
textarea.classList.remove('invalid');
|
||||
context.setFieldError(field.configPath, null);
|
||||
context.updateDraft(field.configPath, parsed.declarations);
|
||||
for (const path of managedPaths) {
|
||||
context.resetDraftPath(path, undefined);
|
||||
}
|
||||
});
|
||||
return textarea;
|
||||
}
|
||||
|
||||
export function renderControl(
|
||||
field: ConfigSettingsField,
|
||||
context: SettingsControlContext,
|
||||
@@ -134,7 +183,13 @@ export function renderControl(
|
||||
if (field.control === 'number') {
|
||||
const input = createElement('input', 'config-input') as HTMLInputElement;
|
||||
input.type = 'number';
|
||||
input.value = typeof value === 'number' ? String(value) : '';
|
||||
const numericValue =
|
||||
typeof value === 'number'
|
||||
? value
|
||||
: typeof field.defaultValue === 'number'
|
||||
? field.defaultValue
|
||||
: NaN;
|
||||
input.value = Number.isFinite(numericValue) ? String(numericValue) : '';
|
||||
input.addEventListener('input', () => {
|
||||
const next = parseOptionalNumberInputValue(input.value);
|
||||
if (next.ok) {
|
||||
@@ -174,6 +229,10 @@ export function renderControl(
|
||||
return renderJsonInput(context, field, value);
|
||||
}
|
||||
|
||||
if (field.control === 'css-declarations') {
|
||||
return renderCssDeclarationsInput(context, field);
|
||||
}
|
||||
|
||||
if (field.control === 'textarea') {
|
||||
const textarea = createElement('textarea', 'config-textarea compact') as HTMLTextAreaElement;
|
||||
textarea.spellcheck = false;
|
||||
|
||||
Reference in New Issue
Block a user