migrate subtitle style config to CSS declaration shape

- Flat style keys (fontFamily, fontSize, hoverTokenColor, etc.) consolidated into subtitleStyle.css, secondary.css, and subtitleSidebar.css objects
- Hover token colors migrated to --subtitle-hover-token-color CSS custom properties
- Plugin app-ping now checks result.status (0=running, 1=stopped) to avoid treating transient failures as stopped
- Note-fields note type picker defaults to configured deck's note type before falling back to Kiku/Lapis
- New migration for legacy ankiConnect N+1 config paths
This commit is contained in:
2026-05-18 03:01:31 -07:00
parent 1bb7b26641
commit 193b3136f2
33 changed files with 990 additions and 339 deletions
+6 -6
View File
@@ -2,17 +2,17 @@ import test from 'node:test';
import assert from 'node:assert/strict';
import * as ankiControls from './settings-anki-controls';
test('note field model preference keeps a matching configured model before Kiku fallback', () => {
test('note field model preference ignores configured sentence-card model before Kiku fallback', () => {
assert.equal(
ankiControls.selectPreferredNoteFieldModelName(['Lapis Morph', 'Kiku'], 'Lapis Morph'),
'Lapis Morph',
'Kiku',
);
});
test('note field model preference matches configured model case-insensitively', () => {
test('note field model preference ignores configured sentence-card model case-insensitively', () => {
assert.equal(
ankiControls.selectPreferredNoteFieldModelName(['Lapis Morph', 'Kiku'], 'lapis morph'),
'Lapis Morph',
'Kiku',
);
});
@@ -28,10 +28,10 @@ test('note field model preference does not treat partial Kiku matches as Kiku',
assert.equal(ankiControls.selectPreferredNoteFieldModelName(['Kikuchi', 'Mining'], ''), '');
});
test('note field model preference accepts partial Lapis matches', () => {
test('note field model preference does not treat partial Lapis matches as Lapis', () => {
assert.equal(
ankiControls.selectPreferredNoteFieldModelName(['Mining', 'Lapis Morph'], ''),
'Lapis Morph',
'',
);
});
+8 -22
View File
@@ -46,39 +46,25 @@ export function configureAnkiControls(options: { requestRender: () => void }): v
requestRender = options.requestRender;
}
export function initializeAnkiControls(values: Record<string, ConfigSettingsSnapshotValue>): void {
const configuredNoteType = values['ankiConnect.isLapis.sentenceCardModel'];
if (
!state.noteFieldModelName &&
!state.noteFieldModelNameManuallySelected &&
typeof configuredNoteType === 'string'
) {
state.noteFieldModelName = configuredNoteType;
}
export function initializeAnkiControls(_values: Record<string, ConfigSettingsSnapshotValue>): void {
state.noteFieldModelName = '';
state.noteFieldModelNameManuallySelected = false;
}
export function selectPreferredNoteFieldModelName(
modelNames: readonly string[],
currentModelName = '',
): string {
const normalizedCurrentModelName = currentModelName.trim().toLowerCase();
if (normalizedCurrentModelName) {
const currentModel = modelNames.find(
(name) => name.toLowerCase() === normalizedCurrentModelName,
);
if (currentModel) {
return currentModel;
}
}
void currentModelName;
const exactKiku = modelNames.find((name) => name.toLowerCase() === 'kiku');
const exactKiku = modelNames.find((name) => name.trim().toLowerCase() === 'kiku');
if (exactKiku) {
return exactKiku;
}
const lapis = modelNames.find((name) => name.toLowerCase().includes('lapis'));
if (lapis) {
return lapis;
const exactLapis = modelNames.find((name) => name.trim().toLowerCase() === 'lapis');
if (exactLapis) {
return exactLapis;
}
return '';