Persist stats exclusions in DB and fix word metrics filtering (#60)

This commit is contained in:
2026-05-03 20:06:13 -07:00
committed by GitHub
parent db30c61327
commit 0915b23dc8
33 changed files with 1890 additions and 208 deletions
+30 -75
View File
@@ -793,105 +793,60 @@ body.settings-modal-open [data-subminer-yomitan-popup-host='true'] {
color: var(--subtitle-name-match-color, #f5bde6);
}
#subtitleRoot
.word.word-jlpt-n1:not(
:is(
.word-known,
.word-n-plus-one,
.word-name-match,
.word-frequency-single,
.word-frequency-band-1,
.word-frequency-band-2,
.word-frequency-band-3,
.word-frequency-band-4,
.word-frequency-band-5
)
) {
color: var(--subtitle-jlpt-n1-color, #ed8796);
#subtitleRoot .word.word-jlpt-n1 {
text-decoration-line: underline;
text-decoration-color: var(--subtitle-jlpt-n1-color, #ed8796);
text-decoration-thickness: 0.08em;
text-underline-offset: 0.12em;
text-decoration-skip-ink: none;
}
#subtitleRoot .word.word-jlpt-n1[data-jlpt-level]::after {
color: var(--subtitle-jlpt-n1-color, #ed8796);
}
#subtitleRoot
.word.word-jlpt-n2:not(
:is(
.word-known,
.word-n-plus-one,
.word-name-match,
.word-frequency-single,
.word-frequency-band-1,
.word-frequency-band-2,
.word-frequency-band-3,
.word-frequency-band-4,
.word-frequency-band-5
)
) {
color: var(--subtitle-jlpt-n2-color, #f5a97f);
#subtitleRoot .word.word-jlpt-n2 {
text-decoration-line: underline;
text-decoration-color: var(--subtitle-jlpt-n2-color, #f5a97f);
text-decoration-thickness: 0.08em;
text-underline-offset: 0.12em;
text-decoration-skip-ink: none;
}
#subtitleRoot .word.word-jlpt-n2[data-jlpt-level]::after {
color: var(--subtitle-jlpt-n2-color, #f5a97f);
}
#subtitleRoot
.word.word-jlpt-n3:not(
:is(
.word-known,
.word-n-plus-one,
.word-name-match,
.word-frequency-single,
.word-frequency-band-1,
.word-frequency-band-2,
.word-frequency-band-3,
.word-frequency-band-4,
.word-frequency-band-5
)
) {
color: var(--subtitle-jlpt-n3-color, #f9e2af);
#subtitleRoot .word.word-jlpt-n3 {
text-decoration-line: underline;
text-decoration-color: var(--subtitle-jlpt-n3-color, #f9e2af);
text-decoration-thickness: 0.08em;
text-underline-offset: 0.12em;
text-decoration-skip-ink: none;
}
#subtitleRoot .word.word-jlpt-n3[data-jlpt-level]::after {
color: var(--subtitle-jlpt-n3-color, #f9e2af);
}
#subtitleRoot
.word.word-jlpt-n4:not(
:is(
.word-known,
.word-n-plus-one,
.word-name-match,
.word-frequency-single,
.word-frequency-band-1,
.word-frequency-band-2,
.word-frequency-band-3,
.word-frequency-band-4,
.word-frequency-band-5
)
) {
color: var(--subtitle-jlpt-n4-color, #a6e3a1);
#subtitleRoot .word.word-jlpt-n4 {
text-decoration-line: underline;
text-decoration-color: var(--subtitle-jlpt-n4-color, #a6e3a1);
text-decoration-thickness: 0.08em;
text-underline-offset: 0.12em;
text-decoration-skip-ink: none;
}
#subtitleRoot .word.word-jlpt-n4[data-jlpt-level]::after {
color: var(--subtitle-jlpt-n4-color, #a6e3a1);
}
#subtitleRoot
.word.word-jlpt-n5:not(
:is(
.word-known,
.word-n-plus-one,
.word-name-match,
.word-frequency-single,
.word-frequency-band-1,
.word-frequency-band-2,
.word-frequency-band-3,
.word-frequency-band-4,
.word-frequency-band-5
)
) {
color: var(--subtitle-jlpt-n5-color, #8aadf4);
#subtitleRoot .word.word-jlpt-n5 {
text-decoration-line: underline;
text-decoration-color: var(--subtitle-jlpt-n5-color, #8aadf4);
text-decoration-thickness: 0.08em;
text-underline-offset: 0.12em;
text-decoration-skip-ink: none;
}
#subtitleRoot .word.word-jlpt-n5[data-jlpt-level]::after {
+11 -20
View File
@@ -220,20 +220,8 @@ function normalizeCssSelector(selector: string): string {
.trim();
}
function buildJlptColorSelector(level: number): string {
const higherPriorityClasses = [
'.word-known',
'.word-n-plus-one',
'.word-name-match',
'.word-frequency-single',
'.word-frequency-band-1',
'.word-frequency-band-2',
'.word-frequency-band-3',
'.word-frequency-band-4',
'.word-frequency-band-5',
].join(', ');
return `#subtitleRoot .word.word-jlpt-n${level}:not(:is(${higherPriorityClasses}))`;
function buildJlptUnderlineSelector(level: number): string {
return `#subtitleRoot .word.word-jlpt-n${level}`;
}
test('computeWordClass preserves known and n+1 classes while adding JLPT classes', () => {
@@ -885,7 +873,7 @@ test('shouldRenderTokenizedSubtitle enables token rendering when tokens exist',
assert.equal(shouldRenderTokenizedSubtitle(0), false);
});
test('subtitle annotation CSS changes token color without overriding typography', () => {
test('subtitle annotation CSS underlines JLPT tokens without changing token color', () => {
const distCssPath = path.join(process.cwd(), 'dist', 'renderer', 'style.css');
const srcCssPath = path.join(process.cwd(), 'src', 'renderer', 'style.css');
@@ -899,12 +887,15 @@ test('subtitle annotation CSS changes token color without overriding typography'
const cssText = fs.readFileSync(cssPath, 'utf-8');
for (let level = 1; level <= 5; level += 1) {
const plainJlptBlock = extractClassBlock(cssText, `#subtitleRoot .word.word-jlpt-n${level}`);
assert.doesNotMatch(plainJlptBlock, /(?:^|\n)\s*color\s*:/m);
const block = extractClassBlock(cssText, buildJlptColorSelector(level));
const block = extractClassBlock(cssText, buildJlptUnderlineSelector(level));
assert.ok(block.length > 0, `word-jlpt-n${level} class should exist`);
assert.match(block, new RegExp(`color:\\s*var\\(--subtitle-jlpt-n${level}-color,`));
assert.doesNotMatch(block, /(?:^|\n)\s*color\s*:/m);
assert.doesNotMatch(block, /-webkit-text-fill-color\s*:/);
assert.match(block, /text-decoration-line:\s*underline;/);
assert.match(
block,
new RegExp(`text-decoration-color:\\s*var\\(--subtitle-jlpt-n${level}-color,`),
);
assert.doesNotMatch(block, /border-bottom\s*:/);
assert.doesNotMatch(block, /padding-bottom\s*:/);
assert.doesNotMatch(block, /box-decoration-break\s*:/);