mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-05-29 00:55:15 -07:00
style: update subtitle text shadow, JLPT underlines, and frequency topX default (#96)
* style: update subtitle text shadow, JLPT underlines, and frequency topX - Replace directional text-shadow with 4-corner outline shadow for sharper readability - Increase JLPT level border-bottom from 2px to 3px; add drop-shadow filter - Add margin-left 0.18em to character image token - Raise frequencyDictionary topX default from 1000 to 10000 * docs: add subtitle style changelog fragment * docs: update generated config examples * style: wrap long textShadow strings and add blank line in CSS
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
type: changed
|
||||
area: subtitles
|
||||
|
||||
- Updated subtitle defaults with a stronger outline-style text shadow, thicker JLPT underlines, and a `topX` frequency highlighting default of `10000`.
|
||||
@@ -380,7 +380,7 @@
|
||||
"word-spacing": "0", // Word spacing setting.
|
||||
"font-kerning": "normal", // Font kerning setting.
|
||||
"text-rendering": "geometricPrecision", // Text rendering setting.
|
||||
"text-shadow": "0 2px 6px rgba(0,0,0,0.9), 0 0 12px rgba(0,0,0,0.55)", // Text shadow setting.
|
||||
"text-shadow": "-1px -1px 2px rgba(0,0,0,0.95), 1px -1px 2px rgba(0,0,0,0.95), -1px 1px 2px rgba(0,0,0,0.95), 1px 1px 2px rgba(0,0,0,0.95), 0 0 8px rgba(0,0,0,0.5)", // Text shadow setting.
|
||||
"backdrop-filter": "blur(6px)", // Backdrop filter setting.
|
||||
"--subtitle-hover-token-color": "#f4dbd6", // Subtitle hover token color setting.
|
||||
"--subtitle-hover-token-background-color": "transparent" // Subtitle hover token background color setting.
|
||||
@@ -405,7 +405,7 @@
|
||||
"frequencyDictionary": {
|
||||
"enabled": false, // Enable frequency-dictionary-based highlighting based on token rank. Values: true | false
|
||||
"sourcePath": "", // Optional absolute path to a frequency dictionary directory. If empty, built-in discovery search paths are used.
|
||||
"topX": 1000, // Only color tokens with frequency rank <= topX (default: 1000).
|
||||
"topX": 10000, // Only color tokens with frequency rank <= topX (default: 10000).
|
||||
"mode": "single", // single: use one color for all matching tokens. banded: use color ramp by frequency band. Values: single | banded
|
||||
"matchMode": "headword", // headword: frequency lookup uses dictionary form. surface: lookup uses subtitle-visible token text. Values: headword | surface
|
||||
"singleColor": "#f5a97f", // Color used when frequencyDictionary.mode is `single`.
|
||||
@@ -430,7 +430,7 @@
|
||||
"word-spacing": "0", // Word spacing setting.
|
||||
"font-kerning": "normal", // Font kerning setting.
|
||||
"text-rendering": "geometricPrecision", // Text rendering setting.
|
||||
"text-shadow": "0 2px 6px rgba(0,0,0,0.9), 0 0 12px rgba(0,0,0,0.55)", // Text shadow setting.
|
||||
"text-shadow": "-1px -1px 2px rgba(0,0,0,0.95), 1px -1px 2px rgba(0,0,0,0.95), -1px 1px 2px rgba(0,0,0,0.95), 1px 1px 2px rgba(0,0,0,0.95), 0 0 8px rgba(0,0,0,0.5)", // Text shadow setting.
|
||||
"backdrop-filter": "blur(6px)" // Backdrop filter setting.
|
||||
} // CSS declaration object applied to secondary subtitles after normal subtitle style defaults.
|
||||
} // Secondary setting.
|
||||
|
||||
@@ -380,7 +380,7 @@
|
||||
"word-spacing": "0", // Word spacing setting.
|
||||
"font-kerning": "normal", // Font kerning setting.
|
||||
"text-rendering": "geometricPrecision", // Text rendering setting.
|
||||
"text-shadow": "0 2px 6px rgba(0,0,0,0.9), 0 0 12px rgba(0,0,0,0.55)", // Text shadow setting.
|
||||
"text-shadow": "-1px -1px 2px rgba(0,0,0,0.95), 1px -1px 2px rgba(0,0,0,0.95), -1px 1px 2px rgba(0,0,0,0.95), 1px 1px 2px rgba(0,0,0,0.95), 0 0 8px rgba(0,0,0,0.5)", // Text shadow setting.
|
||||
"backdrop-filter": "blur(6px)", // Backdrop filter setting.
|
||||
"--subtitle-hover-token-color": "#f4dbd6", // Subtitle hover token color setting.
|
||||
"--subtitle-hover-token-background-color": "transparent" // Subtitle hover token background color setting.
|
||||
@@ -405,7 +405,7 @@
|
||||
"frequencyDictionary": {
|
||||
"enabled": false, // Enable frequency-dictionary-based highlighting based on token rank. Values: true | false
|
||||
"sourcePath": "", // Optional absolute path to a frequency dictionary directory. If empty, built-in discovery search paths are used.
|
||||
"topX": 1000, // Only color tokens with frequency rank <= topX (default: 1000).
|
||||
"topX": 10000, // Only color tokens with frequency rank <= topX (default: 10000).
|
||||
"mode": "single", // single: use one color for all matching tokens. banded: use color ramp by frequency band. Values: single | banded
|
||||
"matchMode": "headword", // headword: frequency lookup uses dictionary form. surface: lookup uses subtitle-visible token text. Values: headword | surface
|
||||
"singleColor": "#f5a97f", // Color used when frequencyDictionary.mode is `single`.
|
||||
@@ -430,7 +430,7 @@
|
||||
"word-spacing": "0", // Word spacing setting.
|
||||
"font-kerning": "normal", // Font kerning setting.
|
||||
"text-rendering": "geometricPrecision", // Text rendering setting.
|
||||
"text-shadow": "0 2px 6px rgba(0,0,0,0.9), 0 0 12px rgba(0,0,0,0.55)", // Text shadow setting.
|
||||
"text-shadow": "-1px -1px 2px rgba(0,0,0,0.95), 1px -1px 2px rgba(0,0,0,0.95), -1px 1px 2px rgba(0,0,0,0.95), 1px 1px 2px rgba(0,0,0,0.95), 0 0 8px rgba(0,0,0,0.5)", // Text shadow setting.
|
||||
"backdrop-filter": "blur(6px)" // Backdrop filter setting.
|
||||
} // CSS declaration object applied to secondary subtitles after normal subtitle style defaults.
|
||||
} // Secondary setting.
|
||||
|
||||
@@ -22,7 +22,8 @@ import {
|
||||
const DEFAULT_SUBTITLE_FONT_FAMILY =
|
||||
'Hiragino Sans, M PLUS 1, Source Han Sans JP, Noto Sans CJK JP';
|
||||
const DEFAULT_SECONDARY_SUBTITLE_FONT_FAMILY = DEFAULT_SUBTITLE_FONT_FAMILY;
|
||||
const DEFAULT_SUBTITLE_TEXT_SHADOW = '0 2px 6px rgba(0,0,0,0.9), 0 0 12px rgba(0,0,0,0.55)';
|
||||
const DEFAULT_SUBTITLE_TEXT_SHADOW =
|
||||
'-1px -1px 2px rgba(0,0,0,0.95), 1px -1px 2px rgba(0,0,0,0.95), -1px 1px 2px rgba(0,0,0,0.95), 1px 1px 2px rgba(0,0,0,0.95), 0 0 8px rgba(0,0,0,0.5)';
|
||||
const SUBTITLE_CSS_SCOPES: SubtitleCssScope[] = ['primary', 'secondary', 'sidebar'];
|
||||
|
||||
function makeTempDir(): string {
|
||||
|
||||
@@ -23,7 +23,8 @@ export const SUBTITLE_DEFAULT_CONFIG: Pick<ResolvedConfig, 'subtitleStyle' | 'su
|
||||
wordSpacing: 0,
|
||||
fontKerning: 'normal',
|
||||
textRendering: 'geometricPrecision',
|
||||
textShadow: '0 2px 6px rgba(0,0,0,0.9), 0 0 12px rgba(0,0,0,0.55)',
|
||||
textShadow:
|
||||
'-1px -1px 2px rgba(0,0,0,0.95), 1px -1px 2px rgba(0,0,0,0.95), -1px 1px 2px rgba(0,0,0,0.95), 1px 1px 2px rgba(0,0,0,0.95), 0 0 8px rgba(0,0,0,0.5)',
|
||||
paintOrder: '',
|
||||
WebkitTextStroke: '',
|
||||
fontStyle: 'normal',
|
||||
@@ -41,7 +42,7 @@ export const SUBTITLE_DEFAULT_CONFIG: Pick<ResolvedConfig, 'subtitleStyle' | 'su
|
||||
frequencyDictionary: {
|
||||
enabled: false,
|
||||
sourcePath: '',
|
||||
topX: 1000,
|
||||
topX: 10000,
|
||||
mode: 'single',
|
||||
matchMode: 'headword',
|
||||
singleColor: '#f5a97f',
|
||||
@@ -57,7 +58,8 @@ export const SUBTITLE_DEFAULT_CONFIG: Pick<ResolvedConfig, 'subtitleStyle' | 'su
|
||||
wordSpacing: 0,
|
||||
fontKerning: 'normal',
|
||||
textRendering: 'geometricPrecision',
|
||||
textShadow: '0 2px 6px rgba(0,0,0,0.9), 0 0 12px rgba(0,0,0,0.55)',
|
||||
textShadow:
|
||||
'-1px -1px 2px rgba(0,0,0,0.95), 1px -1px 2px rgba(0,0,0,0.95), -1px 1px 2px rgba(0,0,0,0.95), 1px 1px 2px rgba(0,0,0,0.95), 0 0 8px rgba(0,0,0,0.5)',
|
||||
paintOrder: '',
|
||||
WebkitTextStroke: '',
|
||||
backgroundColor: 'transparent',
|
||||
|
||||
@@ -127,7 +127,7 @@ export function buildSubtitleConfigOptionRegistry(
|
||||
path: 'subtitleStyle.frequencyDictionary.topX',
|
||||
kind: 'number',
|
||||
defaultValue: defaultConfig.subtitleStyle.frequencyDictionary.topX,
|
||||
description: 'Only color tokens with frequency rank <= topX (default: 1000).',
|
||||
description: 'Only color tokens with frequency rank <= topX (default: 10000).',
|
||||
},
|
||||
{
|
||||
path: 'subtitleStyle.frequencyDictionary.mode',
|
||||
|
||||
+22
-10
@@ -667,9 +667,13 @@ body.subtitle-sidebar-embedded-open #subtitleContainer {
|
||||
--subtitle-frequency-band-3-color: #f9e2af;
|
||||
--subtitle-frequency-band-4-color: #8bd5ca;
|
||||
--subtitle-frequency-band-5-color: #8aadf4;
|
||||
|
||||
text-shadow:
|
||||
2px 2px 4px rgba(0, 0, 0, 0.8),
|
||||
-1px -1px 2px rgba(0, 0, 0, 0.5);
|
||||
-1px -1px 2px rgba(0, 0, 0, 0.95),
|
||||
1px -1px 2px rgba(0, 0, 0, 0.95),
|
||||
-1px 1px 2px rgba(0, 0, 0, 0.95),
|
||||
1px 1px 2px rgba(0, 0, 0, 0.95),
|
||||
0 0 8px rgba(0, 0, 0, 0.5);
|
||||
/* Enable text selection for Yomitan */
|
||||
user-select: text;
|
||||
cursor: text;
|
||||
@@ -817,6 +821,7 @@ body.settings-modal-open [data-subminer-yomitan-popup-host='true'] {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
padding-left: 1.08em;
|
||||
margin-left: 0.18em;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
@@ -837,7 +842,8 @@ body.settings-modal-open [data-subminer-yomitan-popup-host='true'] {
|
||||
|
||||
#subtitleRoot .word.word-jlpt-n1 {
|
||||
text-decoration-line: none;
|
||||
border-bottom: 2px solid var(--subtitle-jlpt-n1-color, #ed8796);
|
||||
border-bottom: 3px solid var(--subtitle-jlpt-n1-color, #ed8796);
|
||||
filter: drop-shadow(0 1px 1px rgba(0, 0, 0, 0.5));
|
||||
}
|
||||
|
||||
#subtitleRoot .word.word-jlpt-n1[data-jlpt-level]::after {
|
||||
@@ -846,7 +852,8 @@ body.settings-modal-open [data-subminer-yomitan-popup-host='true'] {
|
||||
|
||||
#subtitleRoot .word.word-jlpt-n2 {
|
||||
text-decoration-line: none;
|
||||
border-bottom: 2px solid var(--subtitle-jlpt-n2-color, #f5a97f);
|
||||
border-bottom: 3px solid var(--subtitle-jlpt-n2-color, #f5a97f);
|
||||
filter: drop-shadow(0 1px 1px rgba(0, 0, 0, 0.5));
|
||||
}
|
||||
|
||||
#subtitleRoot .word.word-jlpt-n2[data-jlpt-level]::after {
|
||||
@@ -855,7 +862,8 @@ body.settings-modal-open [data-subminer-yomitan-popup-host='true'] {
|
||||
|
||||
#subtitleRoot .word.word-jlpt-n3 {
|
||||
text-decoration-line: none;
|
||||
border-bottom: 2px solid var(--subtitle-jlpt-n3-color, #f9e2af);
|
||||
border-bottom: 3px solid var(--subtitle-jlpt-n3-color, #f9e2af);
|
||||
filter: drop-shadow(0 1px 1px rgba(0, 0, 0, 0.5));
|
||||
}
|
||||
|
||||
#subtitleRoot .word.word-jlpt-n3[data-jlpt-level]::after {
|
||||
@@ -864,7 +872,8 @@ body.settings-modal-open [data-subminer-yomitan-popup-host='true'] {
|
||||
|
||||
#subtitleRoot .word.word-jlpt-n4 {
|
||||
text-decoration-line: none;
|
||||
border-bottom: 2px solid var(--subtitle-jlpt-n4-color, #a6e3a1);
|
||||
border-bottom: 3px solid var(--subtitle-jlpt-n4-color, #a6e3a1);
|
||||
filter: drop-shadow(0 1px 1px rgba(0, 0, 0, 0.5));
|
||||
}
|
||||
|
||||
#subtitleRoot .word.word-jlpt-n4[data-jlpt-level]::after {
|
||||
@@ -873,7 +882,8 @@ body.settings-modal-open [data-subminer-yomitan-popup-host='true'] {
|
||||
|
||||
#subtitleRoot .word.word-jlpt-n5 {
|
||||
text-decoration-line: none;
|
||||
border-bottom: 2px solid var(--subtitle-jlpt-n5-color, #8aadf4);
|
||||
border-bottom: 3px solid var(--subtitle-jlpt-n5-color, #8aadf4);
|
||||
filter: drop-shadow(0 1px 1px rgba(0, 0, 0, 0.5));
|
||||
}
|
||||
|
||||
#subtitleRoot .word.word-jlpt-n5[data-jlpt-level]::after {
|
||||
@@ -1186,9 +1196,11 @@ body.layer-modal #overlay {
|
||||
-webkit-text-stroke: 0.45px rgba(0, 0, 0, 0.7);
|
||||
paint-order: stroke fill;
|
||||
text-shadow:
|
||||
0 2px 4px rgba(0, 0, 0, 0.95),
|
||||
0 0 8px rgba(0, 0, 0, 0.8),
|
||||
0 0 16px rgba(0, 0, 0, 0.55);
|
||||
-1px -1px 2px rgba(0, 0, 0, 0.95),
|
||||
1px -1px 2px rgba(0, 0, 0, 0.95),
|
||||
-1px 1px 2px rgba(0, 0, 0, 0.95),
|
||||
1px 1px 2px rgba(0, 0, 0, 0.95),
|
||||
0 0 8px rgba(0, 0, 0, 0.5);
|
||||
user-select: text;
|
||||
cursor: text;
|
||||
}
|
||||
|
||||
@@ -909,8 +909,8 @@ test('subtitle annotation CSS underlines JLPT tokens without changing token colo
|
||||
assert.doesNotMatch(plainJlptBlock, /text-decoration\s*:[^;]*\bunderline\b/i);
|
||||
assert.match(
|
||||
plainJlptBlock,
|
||||
new RegExp(`border-bottom:\\s*2px\\s+solid\\s+var\\(--subtitle-jlpt-n${level}-color,`),
|
||||
`JLPT level must paint a permanent 2px border-bottom in the level color`,
|
||||
new RegExp(`border-bottom:\\s*3px\\s+solid\\s+var\\(--subtitle-jlpt-n${level}-color,`),
|
||||
`JLPT level must paint a permanent 3px border-bottom in the level color`,
|
||||
);
|
||||
|
||||
// JLPT tagging must communicate level *only* via the underline; it must
|
||||
@@ -973,6 +973,7 @@ test('subtitle annotation CSS underlines JLPT tokens without changing token colo
|
||||
assert.match(characterImageTokenBlock, /display:\s*inline-block;/);
|
||||
assert.match(characterImageTokenBlock, /position:\s*relative;/);
|
||||
assert.match(characterImageTokenBlock, /padding-left:\s*1\.08em;/);
|
||||
assert.match(characterImageTokenBlock, /margin-left:\s*0\.18em;/);
|
||||
|
||||
const characterImageBlock = extractClassBlock(cssText, '#subtitleRoot .word-character-image');
|
||||
assert.match(characterImageBlock, /position:\s*absolute;/);
|
||||
@@ -1186,7 +1187,7 @@ test('subtitle annotation CSS underlines JLPT tokens without changing token colo
|
||||
assert.match(secondaryRootBlock, /-webkit-text-stroke:\s*0\.45px rgba\(0,\s*0,\s*0,\s*0\.7\);/);
|
||||
assert.match(
|
||||
secondaryRootBlock,
|
||||
/text-shadow:\s*0 2px 4px rgba\(0,\s*0,\s*0,\s*0\.95\),\s*0 0 8px rgba\(0,\s*0,\s*0,\s*0\.8\),\s*0 0 16px rgba\(0,\s*0,\s*0,\s*0\.55\);/,
|
||||
/text-shadow:\s*-1px -1px 2px rgba\(0,\s*0,\s*0,\s*0\.95\),\s*1px -1px 2px rgba\(0,\s*0,\s*0,\s*0\.95\),\s*-1px 1px 2px rgba\(0,\s*0,\s*0,\s*0\.95\),\s*1px 1px 2px rgba\(0,\s*0,\s*0,\s*0\.95\),\s*0 0 8px rgba\(0,\s*0,\s*0,\s*0\.5\);/,
|
||||
);
|
||||
|
||||
const secondaryHoverBaseBlock = extractClassBlock(
|
||||
|
||||
@@ -89,7 +89,7 @@ function sanitizeSubtitleHoverTokenBackgroundColor(value: unknown): string {
|
||||
|
||||
const DEFAULT_FREQUENCY_RENDER_SETTINGS: FrequencyRenderSettings = {
|
||||
enabled: false,
|
||||
topX: 1000,
|
||||
topX: 10000,
|
||||
mode: 'single',
|
||||
singleColor: '#f5a97f',
|
||||
bandedColors: ['#ed8796', '#f5a97f', '#f9e2af', '#8bd5ca', '#8aadf4'],
|
||||
|
||||
Reference in New Issue
Block a user