mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-03-01 18:22:41 -08:00
fix(renderer): preserve jlpt hover and lookup token colors
This commit is contained in:
@@ -249,36 +249,22 @@ function M.create(ctx)
|
|||||||
raw_close_idx = #raw_ass + 1
|
raw_close_idx = #raw_ass + 1
|
||||||
end
|
end
|
||||||
|
|
||||||
local open_tag = string.format("{\\1c&H%s&}", hover_color)
|
local before = raw_ass:sub(1, raw_open_idx - 1)
|
||||||
local close_tag = string.format("{\\1c&H%s&}", base_color)
|
local hovered = raw_ass:sub(raw_open_idx, raw_close_idx - 1)
|
||||||
local changes = {
|
local after = raw_ass:sub(raw_close_idx)
|
||||||
{ idx = raw_open_idx, tag = open_tag },
|
local hover_suffix = string.format("\\1c&H%s&", hover_color)
|
||||||
{ idx = raw_close_idx, tag = close_tag },
|
|
||||||
}
|
-- Keep hover foreground stable even when inline ASS override tags (\1c/\c/\r) appear inside token.
|
||||||
table.sort(changes, function(a, b)
|
hovered = hovered:gsub("{([^}]*)}", function(inner)
|
||||||
return a.idx < b.idx
|
if inner:find("\\1c&H", 1, true) or inner:find("\\c&H", 1, true) or inner:find("\\r", 1, true) then
|
||||||
|
return "{" .. inner .. hover_suffix .. "}"
|
||||||
|
end
|
||||||
|
return "{" .. inner .. "}"
|
||||||
end)
|
end)
|
||||||
|
|
||||||
local output = {}
|
local open_tag = string.format("{\\1c&H%s&}", hover_color)
|
||||||
local cursor = 1
|
local close_tag = string.format("{\\1c&H%s&}", base_color)
|
||||||
for _, change in ipairs(changes) do
|
return before .. open_tag .. hovered .. close_tag .. after
|
||||||
if change.idx > #raw_ass + 1 then
|
|
||||||
change.idx = #raw_ass + 1
|
|
||||||
end
|
|
||||||
if change.idx < 1 then
|
|
||||||
change.idx = 1
|
|
||||||
end
|
|
||||||
if change.idx > cursor then
|
|
||||||
output[#output + 1] = raw_ass:sub(cursor, change.idx - 1)
|
|
||||||
end
|
|
||||||
output[#output + 1] = change.tag
|
|
||||||
cursor = change.idx
|
|
||||||
end
|
|
||||||
if cursor <= #raw_ass then
|
|
||||||
output[#output + 1] = raw_ass:sub(cursor)
|
|
||||||
end
|
|
||||||
|
|
||||||
return table.concat(output)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local function build_hover_subtitle_content(payload)
|
local function build_hover_subtitle_content(payload)
|
||||||
|
|||||||
@@ -406,7 +406,6 @@ body.settings-modal-open #subtitleContainer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#subtitleRoot .word.word-jlpt-n1 {
|
#subtitleRoot .word.word-jlpt-n1 {
|
||||||
color: inherit;
|
|
||||||
text-decoration-line: underline;
|
text-decoration-line: underline;
|
||||||
text-decoration-thickness: 2px;
|
text-decoration-thickness: 2px;
|
||||||
text-underline-offset: 4px;
|
text-underline-offset: 4px;
|
||||||
@@ -419,7 +418,6 @@ body.settings-modal-open #subtitleContainer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#subtitleRoot .word.word-jlpt-n2 {
|
#subtitleRoot .word.word-jlpt-n2 {
|
||||||
color: inherit;
|
|
||||||
text-decoration-line: underline;
|
text-decoration-line: underline;
|
||||||
text-decoration-thickness: 2px;
|
text-decoration-thickness: 2px;
|
||||||
text-underline-offset: 4px;
|
text-underline-offset: 4px;
|
||||||
@@ -432,7 +430,6 @@ body.settings-modal-open #subtitleContainer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#subtitleRoot .word.word-jlpt-n3 {
|
#subtitleRoot .word.word-jlpt-n3 {
|
||||||
color: inherit;
|
|
||||||
text-decoration-line: underline;
|
text-decoration-line: underline;
|
||||||
text-decoration-thickness: 2px;
|
text-decoration-thickness: 2px;
|
||||||
text-underline-offset: 4px;
|
text-underline-offset: 4px;
|
||||||
@@ -445,7 +442,6 @@ body.settings-modal-open #subtitleContainer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#subtitleRoot .word.word-jlpt-n4 {
|
#subtitleRoot .word.word-jlpt-n4 {
|
||||||
color: inherit;
|
|
||||||
text-decoration-line: underline;
|
text-decoration-line: underline;
|
||||||
text-decoration-thickness: 2px;
|
text-decoration-thickness: 2px;
|
||||||
text-underline-offset: 4px;
|
text-underline-offset: 4px;
|
||||||
@@ -458,7 +454,6 @@ body.settings-modal-open #subtitleContainer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#subtitleRoot .word.word-jlpt-n5 {
|
#subtitleRoot .word.word-jlpt-n5 {
|
||||||
color: inherit;
|
|
||||||
text-decoration-line: underline;
|
text-decoration-line: underline;
|
||||||
text-decoration-thickness: 2px;
|
text-decoration-thickness: 2px;
|
||||||
text-underline-offset: 4px;
|
text-underline-offset: 4px;
|
||||||
@@ -540,6 +535,16 @@ body.settings-modal-open #subtitleContainer {
|
|||||||
-webkit-text-fill-color: currentColor !important;
|
-webkit-text-fill-color: currentColor !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#subtitleRoot
|
||||||
|
.word:is(.word-jlpt-n1, .word-jlpt-n2, .word-jlpt-n3, .word-jlpt-n4, .word-jlpt-n5):not(
|
||||||
|
.word-known
|
||||||
|
):not(.word-n-plus-one):not(.word-frequency-single):not(.word-frequency-band-1):not(
|
||||||
|
.word-frequency-band-2
|
||||||
|
):not(.word-frequency-band-3):not(.word-frequency-band-4):not(.word-frequency-band-5):hover {
|
||||||
|
color: var(--subtitle-hover-token-color, #f4dbd6) !important;
|
||||||
|
-webkit-text-fill-color: var(--subtitle-hover-token-color, #f4dbd6) !important;
|
||||||
|
}
|
||||||
|
|
||||||
#subtitleRoot::selection,
|
#subtitleRoot::selection,
|
||||||
#subtitleRoot .word::selection,
|
#subtitleRoot .word::selection,
|
||||||
#subtitleRoot .c::selection {
|
#subtitleRoot .c::selection {
|
||||||
@@ -602,6 +607,23 @@ body.settings-modal-open #subtitleContainer {
|
|||||||
-webkit-text-fill-color: var(--subtitle-frequency-band-5-color, #8aadf4) !important;
|
-webkit-text-fill-color: var(--subtitle-frequency-band-5-color, #8aadf4) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#subtitleRoot
|
||||||
|
.word:is(.word-jlpt-n1, .word-jlpt-n2, .word-jlpt-n3, .word-jlpt-n4, .word-jlpt-n5):not(
|
||||||
|
.word-known
|
||||||
|
):not(.word-n-plus-one):not(.word-frequency-single):not(.word-frequency-band-1):not(
|
||||||
|
.word-frequency-band-2
|
||||||
|
):not(.word-frequency-band-3):not(.word-frequency-band-4):not(.word-frequency-band-5)::selection,
|
||||||
|
#subtitleRoot
|
||||||
|
.word:is(.word-jlpt-n1, .word-jlpt-n2, .word-jlpt-n3, .word-jlpt-n4, .word-jlpt-n5):not(
|
||||||
|
.word-known
|
||||||
|
):not(.word-n-plus-one):not(.word-frequency-single):not(.word-frequency-band-1):not(
|
||||||
|
.word-frequency-band-2
|
||||||
|
):not(.word-frequency-band-3):not(.word-frequency-band-4):not(.word-frequency-band-5)
|
||||||
|
.c::selection {
|
||||||
|
color: var(--subtitle-hover-token-color, #f4dbd6) !important;
|
||||||
|
-webkit-text-fill-color: var(--subtitle-hover-token-color, #f4dbd6) !important;
|
||||||
|
}
|
||||||
|
|
||||||
#subtitleRoot br {
|
#subtitleRoot br {
|
||||||
display: block;
|
display: block;
|
||||||
content: '';
|
content: '';
|
||||||
|
|||||||
@@ -353,7 +353,7 @@ test('JLPT CSS rules use underline-only styling in renderer stylesheet', () => {
|
|||||||
assert.match(block, /text-decoration-line:\s*underline;/);
|
assert.match(block, /text-decoration-line:\s*underline;/);
|
||||||
assert.match(block, /text-decoration-thickness:\s*2px;/);
|
assert.match(block, /text-decoration-thickness:\s*2px;/);
|
||||||
assert.match(block, /text-underline-offset:\s*4px;/);
|
assert.match(block, /text-underline-offset:\s*4px;/);
|
||||||
assert.match(block, /color:\s*inherit;/);
|
assert.doesNotMatch(block, /(?:^|\n)\s*color\s*:/m);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let band = 1; band <= 5; band += 1) {
|
for (let band = 1; band <= 5; band += 1) {
|
||||||
@@ -446,6 +446,15 @@ test('JLPT CSS rules use underline-only styling in renderer stylesheet', () => {
|
|||||||
assert.match(coloredCharHoverBlock, /background:\s*transparent;/);
|
assert.match(coloredCharHoverBlock, /background:\s*transparent;/);
|
||||||
assert.match(coloredCharHoverBlock, /color:\s*inherit\s*!important;/);
|
assert.match(coloredCharHoverBlock, /color:\s*inherit\s*!important;/);
|
||||||
|
|
||||||
|
assert.match(
|
||||||
|
cssText,
|
||||||
|
/\.word:is\(\.word-jlpt-n1,\s*\.word-jlpt-n2,\s*\.word-jlpt-n3,\s*\.word-jlpt-n4,\s*\.word-jlpt-n5\):not\(\s*\.word-known\s*\):not\(\.word-n-plus-one\):not\(\.word-frequency-single\):not\(\.word-frequency-band-1\):not\(\s*\.word-frequency-band-2\s*\):not\(\.word-frequency-band-3\):not\(\.word-frequency-band-4\):not\(\.word-frequency-band-5\):hover\s*\{[\s\S]*?color:\s*var\(--subtitle-hover-token-color,\s*#f4dbd6\)\s*!important;[\s\S]*?-webkit-text-fill-color:\s*var\(--subtitle-hover-token-color,\s*#f4dbd6\)\s*!important;/,
|
||||||
|
);
|
||||||
|
assert.match(
|
||||||
|
cssText,
|
||||||
|
/\.word:is\(\.word-jlpt-n1,\s*\.word-jlpt-n2,\s*\.word-jlpt-n3,\s*\.word-jlpt-n4,\s*\.word-jlpt-n5\):not\(\s*\.word-known\s*\):not\(\.word-n-plus-one\):not\(\.word-frequency-single\):not\(\.word-frequency-band-1\):not\(\s*\.word-frequency-band-2\s*\):not\(\.word-frequency-band-3\):not\(\.word-frequency-band-4\):not\(\.word-frequency-band-5\)::selection[\s\S]*?color:\s*var\(--subtitle-hover-token-color,\s*#f4dbd6\)\s*!important;[\s\S]*?-webkit-text-fill-color:\s*var\(--subtitle-hover-token-color,\s*#f4dbd6\)\s*!important;/,
|
||||||
|
);
|
||||||
|
|
||||||
const selectionBlock = extractClassBlock(cssText, '#subtitleRoot::selection');
|
const selectionBlock = extractClassBlock(cssText, '#subtitleRoot::selection');
|
||||||
assert.match(
|
assert.match(
|
||||||
selectionBlock,
|
selectionBlock,
|
||||||
|
|||||||
Reference in New Issue
Block a user