mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-03-20 12:11:28 -07:00
fix: improve secondary subtitle readability
This commit is contained in:
@@ -185,10 +185,10 @@
|
|||||||
"wordSpacing": 0, // Word spacing setting.
|
"wordSpacing": 0, // Word spacing setting.
|
||||||
"fontKerning": "normal", // Font kerning setting.
|
"fontKerning": "normal", // Font kerning setting.
|
||||||
"textRendering": "geometricPrecision", // Text rendering setting.
|
"textRendering": "geometricPrecision", // Text rendering setting.
|
||||||
"textShadow": "0 3px 10px rgba(0,0,0,0.69)", // Text shadow setting.
|
"textShadow": "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)", // Text shadow setting.
|
||||||
"backgroundColor": "transparent", // Background color setting.
|
"backgroundColor": "rgba(20, 22, 34, 0.78)", // Background color setting.
|
||||||
"backdropFilter": "blur(6px)", // Backdrop filter setting.
|
"backdropFilter": "blur(6px)", // Backdrop filter setting.
|
||||||
"fontWeight": "normal", // Font weight setting.
|
"fontWeight": "600", // Font weight setting.
|
||||||
"fontStyle": "normal" // Font style setting.
|
"fontStyle": "normal" // Font style setting.
|
||||||
} // Secondary setting.
|
} // Secondary setting.
|
||||||
}, // Primary and secondary subtitle styling.
|
}, // Primary and secondary subtitle styling.
|
||||||
|
|||||||
@@ -64,6 +64,12 @@ test('loads defaults when config is missing', () => {
|
|||||||
'Inter, Noto Sans, Helvetica Neue, sans-serif',
|
'Inter, Noto Sans, Helvetica Neue, sans-serif',
|
||||||
);
|
);
|
||||||
assert.equal(config.subtitleStyle.secondary.fontColor, '#cad3f5');
|
assert.equal(config.subtitleStyle.secondary.fontColor, '#cad3f5');
|
||||||
|
assert.equal(config.subtitleStyle.secondary.fontWeight, '600');
|
||||||
|
assert.equal(
|
||||||
|
config.subtitleStyle.secondary.textShadow,
|
||||||
|
'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)',
|
||||||
|
);
|
||||||
|
assert.equal(config.subtitleStyle.secondary.backgroundColor, 'rgba(20, 22, 34, 0.78)');
|
||||||
assert.equal(config.immersionTracking.enabled, true);
|
assert.equal(config.immersionTracking.enabled, true);
|
||||||
assert.equal(config.immersionTracking.dbPath, '');
|
assert.equal(config.immersionTracking.dbPath, '');
|
||||||
assert.equal(config.immersionTracking.batchSize, 25);
|
assert.equal(config.immersionTracking.batchSize, 25);
|
||||||
|
|||||||
@@ -50,10 +50,10 @@ export const SUBTITLE_DEFAULT_CONFIG: Pick<ResolvedConfig, 'subtitleStyle'> = {
|
|||||||
wordSpacing: 0,
|
wordSpacing: 0,
|
||||||
fontKerning: 'normal',
|
fontKerning: 'normal',
|
||||||
textRendering: 'geometricPrecision',
|
textRendering: 'geometricPrecision',
|
||||||
textShadow: '0 3px 10px rgba(0,0,0,0.69)',
|
textShadow: '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)',
|
||||||
backgroundColor: 'transparent',
|
backgroundColor: 'rgba(20, 22, 34, 0.78)',
|
||||||
backdropFilter: 'blur(6px)',
|
backdropFilter: 'blur(6px)',
|
||||||
fontWeight: 'normal',
|
fontWeight: '600',
|
||||||
fontStyle: 'normal',
|
fontStyle: 'normal',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -673,13 +673,17 @@ body.platform-macos.layer-visible #subtitleRoot {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#secondarySubContainer {
|
#secondarySubContainer {
|
||||||
|
--secondary-sub-background-color: transparent;
|
||||||
|
--secondary-sub-backdrop-filter: none;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 40px;
|
top: 40px;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
transform: translateX(-50%);
|
transform: translateX(-50%);
|
||||||
max-width: 80%;
|
max-width: 80%;
|
||||||
padding: 10px 18px;
|
padding: 10px 18px;
|
||||||
background: transparent;
|
background: var(--secondary-sub-background-color, transparent);
|
||||||
|
backdrop-filter: var(--secondary-sub-backdrop-filter, none);
|
||||||
|
-webkit-backdrop-filter: var(--secondary-sub-backdrop-filter, none);
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
pointer-events: auto;
|
pointer-events: auto;
|
||||||
}
|
}
|
||||||
@@ -736,6 +740,8 @@ body.settings-modal-open #secondarySubContainer {
|
|||||||
transform: none;
|
transform: none;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
background: transparent;
|
background: transparent;
|
||||||
|
backdrop-filter: none;
|
||||||
|
-webkit-backdrop-filter: none;
|
||||||
padding: 40px 0 0 0;
|
padding: 40px 0 0 0;
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -744,6 +750,8 @@ body.settings-modal-open #secondarySubContainer {
|
|||||||
|
|
||||||
#secondarySubContainer.secondary-sub-hover #secondarySubRoot {
|
#secondarySubContainer.secondary-sub-hover #secondarySubRoot {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
|
backdrop-filter: none;
|
||||||
|
-webkit-backdrop-filter: none;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
padding: 10px 18px;
|
padding: 10px 18px;
|
||||||
}
|
}
|
||||||
@@ -752,6 +760,12 @@ body.settings-modal-open #secondarySubContainer {
|
|||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#secondarySubContainer.secondary-sub-hover:hover #secondarySubRoot {
|
||||||
|
background: var(--secondary-sub-background-color, transparent);
|
||||||
|
backdrop-filter: var(--secondary-sub-backdrop-filter, none);
|
||||||
|
-webkit-backdrop-filter: var(--secondary-sub-backdrop-filter, none);
|
||||||
|
}
|
||||||
|
|
||||||
iframe.yomitan-popup,
|
iframe.yomitan-popup,
|
||||||
iframe[id^='yomitan-popup'] {
|
iframe[id^='yomitan-popup'] {
|
||||||
pointer-events: auto !important;
|
pointer-events: auto !important;
|
||||||
|
|||||||
@@ -347,6 +347,58 @@ test('applySubtitleStyle sets subtitle name-match color variable', () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('applySubtitleStyle stores secondary background styles in hover-aware css variables', () => {
|
||||||
|
const restoreDocument = installFakeDocument();
|
||||||
|
try {
|
||||||
|
const subtitleRoot = new FakeElement('div');
|
||||||
|
const subtitleContainer = new FakeElement('div');
|
||||||
|
const secondarySubRoot = new FakeElement('div');
|
||||||
|
const secondarySubContainer = new FakeElement('div');
|
||||||
|
const ctx = {
|
||||||
|
state: createRendererState(),
|
||||||
|
dom: {
|
||||||
|
subtitleRoot,
|
||||||
|
subtitleContainer,
|
||||||
|
secondarySubRoot,
|
||||||
|
secondarySubContainer,
|
||||||
|
},
|
||||||
|
} as never;
|
||||||
|
|
||||||
|
const renderer = createSubtitleRenderer(ctx);
|
||||||
|
renderer.applySubtitleStyle({
|
||||||
|
secondary: {
|
||||||
|
backgroundColor: 'rgba(20, 22, 34, 0.78)',
|
||||||
|
backdropFilter: 'blur(6px)',
|
||||||
|
fontWeight: '600',
|
||||||
|
},
|
||||||
|
} as never);
|
||||||
|
|
||||||
|
const secondaryStyleValues = (
|
||||||
|
secondarySubContainer.style as unknown as {
|
||||||
|
values?: Map<string, string>;
|
||||||
|
backgroundColor?: string;
|
||||||
|
backdropFilter?: string;
|
||||||
|
}
|
||||||
|
).values;
|
||||||
|
assert.equal(
|
||||||
|
secondaryStyleValues?.get('--secondary-sub-background-color'),
|
||||||
|
'rgba(20, 22, 34, 0.78)',
|
||||||
|
);
|
||||||
|
assert.equal(secondaryStyleValues?.get('--secondary-sub-backdrop-filter'), 'blur(6px)');
|
||||||
|
assert.equal(
|
||||||
|
(secondarySubContainer.style as unknown as { backgroundColor?: string }).backgroundColor,
|
||||||
|
undefined,
|
||||||
|
);
|
||||||
|
assert.equal(
|
||||||
|
(secondarySubContainer.style as unknown as { backdropFilter?: string }).backdropFilter,
|
||||||
|
undefined,
|
||||||
|
);
|
||||||
|
assert.equal((secondarySubRoot.style as unknown as { fontWeight?: string }).fontWeight, '600');
|
||||||
|
} finally {
|
||||||
|
restoreDocument();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
test('computeWordClass adds frequency class for single mode when rank is within topX', () => {
|
test('computeWordClass adds frequency class for single mode when rank is within topX', () => {
|
||||||
const token = createToken({
|
const token = createToken({
|
||||||
surface: '猫',
|
surface: '猫',
|
||||||
@@ -819,6 +871,42 @@ test('JLPT CSS rules use underline-only styling in renderer stylesheet', () => {
|
|||||||
/-webkit-text-fill-color:\s*var\(--subtitle-hover-token-color,\s*#f4dbd6\)\s*!important;/,
|
/-webkit-text-fill-color:\s*var\(--subtitle-hover-token-color,\s*#f4dbd6\)\s*!important;/,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const secondaryContainerBlock = extractClassBlock(cssText, '#secondarySubContainer');
|
||||||
|
assert.match(
|
||||||
|
secondaryContainerBlock,
|
||||||
|
/background:\s*var\(--secondary-sub-background-color,\s*transparent\);/,
|
||||||
|
);
|
||||||
|
assert.match(
|
||||||
|
secondaryContainerBlock,
|
||||||
|
/backdrop-filter:\s*var\(--secondary-sub-backdrop-filter,\s*none\);/,
|
||||||
|
);
|
||||||
|
|
||||||
|
const secondaryRootBlock = extractClassBlock(cssText, '#secondarySubRoot');
|
||||||
|
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\);/,
|
||||||
|
);
|
||||||
|
|
||||||
|
const secondaryHoverBaseBlock = extractClassBlock(
|
||||||
|
cssText,
|
||||||
|
'#secondarySubContainer.secondary-sub-hover #secondarySubRoot',
|
||||||
|
);
|
||||||
|
assert.match(secondaryHoverBaseBlock, /background:\s*transparent;/);
|
||||||
|
|
||||||
|
const secondaryHoverVisibleBlock = extractClassBlock(
|
||||||
|
cssText,
|
||||||
|
'#secondarySubContainer.secondary-sub-hover:hover #secondarySubRoot',
|
||||||
|
);
|
||||||
|
assert.match(
|
||||||
|
secondaryHoverVisibleBlock,
|
||||||
|
/background:\s*var\(--secondary-sub-background-color,\s*transparent\);/,
|
||||||
|
);
|
||||||
|
assert.match(
|
||||||
|
secondaryHoverVisibleBlock,
|
||||||
|
/backdrop-filter:\s*var\(--secondary-sub-backdrop-filter,\s*none\);/,
|
||||||
|
);
|
||||||
|
|
||||||
assert.doesNotMatch(
|
assert.doesNotMatch(
|
||||||
cssText,
|
cssText,
|
||||||
/body\.layer-visible\s+#secondarySubContainer\s*\{[^}]*display:\s*none/i,
|
/body\.layer-visible\s+#secondarySubContainer\s*\{[^}]*display:\s*none/i,
|
||||||
|
|||||||
@@ -155,6 +155,33 @@ const CONTAINER_STYLE_KEYS = new Set<string>([
|
|||||||
'-webkit-backdrop-filter',
|
'-webkit-backdrop-filter',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
function resolveSecondaryBackgroundColor(declarations: Record<string, unknown>): string {
|
||||||
|
for (const key of ['backgroundColor', 'background']) {
|
||||||
|
const value = declarations[key];
|
||||||
|
if (typeof value === 'string' && value.trim().length > 0) {
|
||||||
|
return value.trim();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 'transparent';
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveSecondaryBackdropFilter(declarations: Record<string, unknown>): string {
|
||||||
|
for (const key of [
|
||||||
|
'backdropFilter',
|
||||||
|
'WebkitBackdropFilter',
|
||||||
|
'webkitBackdropFilter',
|
||||||
|
'-webkit-backdrop-filter',
|
||||||
|
]) {
|
||||||
|
const value = declarations[key];
|
||||||
|
if (typeof value === 'string' && value.trim().length > 0) {
|
||||||
|
return value.trim();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 'none';
|
||||||
|
}
|
||||||
|
|
||||||
function getFrequencyDictionaryClass(
|
function getFrequencyDictionaryClass(
|
||||||
token: MergedToken,
|
token: MergedToken,
|
||||||
settings: FrequencyRenderSettings,
|
settings: FrequencyRenderSettings,
|
||||||
@@ -700,9 +727,17 @@ export function createSubtitleRenderer(ctx: RendererContext) {
|
|||||||
secondaryStyleDeclarations,
|
secondaryStyleDeclarations,
|
||||||
CONTAINER_STYLE_KEYS,
|
CONTAINER_STYLE_KEYS,
|
||||||
);
|
);
|
||||||
applyInlineStyleDeclarations(
|
const secondaryContainerStyleDeclarations = pickInlineStyleDeclarations(
|
||||||
ctx.dom.secondarySubContainer,
|
secondaryStyleDeclarations,
|
||||||
pickInlineStyleDeclarations(secondaryStyleDeclarations, CONTAINER_STYLE_KEYS),
|
CONTAINER_STYLE_KEYS,
|
||||||
|
);
|
||||||
|
ctx.dom.secondarySubContainer.style.setProperty(
|
||||||
|
'--secondary-sub-background-color',
|
||||||
|
resolveSecondaryBackgroundColor(secondaryContainerStyleDeclarations),
|
||||||
|
);
|
||||||
|
ctx.dom.secondarySubContainer.style.setProperty(
|
||||||
|
'--secondary-sub-backdrop-filter',
|
||||||
|
resolveSecondaryBackdropFilter(secondaryContainerStyleDeclarations),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (secondaryStyle.fontFamily) {
|
if (secondaryStyle.fontFamily) {
|
||||||
|
|||||||
Reference in New Issue
Block a user