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:
@@ -64,6 +64,12 @@ test('loads defaults when config is missing', () => {
|
||||
'Inter, Noto Sans, Helvetica Neue, sans-serif',
|
||||
);
|
||||
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.dbPath, '');
|
||||
assert.equal(config.immersionTracking.batchSize, 25);
|
||||
|
||||
@@ -50,10 +50,10 @@ export const SUBTITLE_DEFAULT_CONFIG: Pick<ResolvedConfig, 'subtitleStyle'> = {
|
||||
wordSpacing: 0,
|
||||
fontKerning: 'normal',
|
||||
textRendering: 'geometricPrecision',
|
||||
textShadow: '0 3px 10px rgba(0,0,0,0.69)',
|
||||
backgroundColor: 'transparent',
|
||||
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: 'rgba(20, 22, 34, 0.78)',
|
||||
backdropFilter: 'blur(6px)',
|
||||
fontWeight: 'normal',
|
||||
fontWeight: '600',
|
||||
fontStyle: 'normal',
|
||||
},
|
||||
},
|
||||
|
||||
@@ -673,13 +673,17 @@ body.platform-macos.layer-visible #subtitleRoot {
|
||||
}
|
||||
|
||||
#secondarySubContainer {
|
||||
--secondary-sub-background-color: transparent;
|
||||
--secondary-sub-backdrop-filter: none;
|
||||
position: absolute;
|
||||
top: 40px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
max-width: 80%;
|
||||
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;
|
||||
pointer-events: auto;
|
||||
}
|
||||
@@ -736,6 +740,8 @@ body.settings-modal-open #secondarySubContainer {
|
||||
transform: none;
|
||||
max-width: 100%;
|
||||
background: transparent;
|
||||
backdrop-filter: none;
|
||||
-webkit-backdrop-filter: none;
|
||||
padding: 40px 0 0 0;
|
||||
border-radius: 0;
|
||||
display: flex;
|
||||
@@ -744,6 +750,8 @@ body.settings-modal-open #secondarySubContainer {
|
||||
|
||||
#secondarySubContainer.secondary-sub-hover #secondarySubRoot {
|
||||
background: transparent;
|
||||
backdrop-filter: none;
|
||||
-webkit-backdrop-filter: none;
|
||||
border-radius: 8px;
|
||||
padding: 10px 18px;
|
||||
}
|
||||
@@ -752,6 +760,12 @@ body.settings-modal-open #secondarySubContainer {
|
||||
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[id^='yomitan-popup'] {
|
||||
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', () => {
|
||||
const token = createToken({
|
||||
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;/,
|
||||
);
|
||||
|
||||
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(
|
||||
cssText,
|
||||
/body\.layer-visible\s+#secondarySubContainer\s*\{[^}]*display:\s*none/i,
|
||||
|
||||
@@ -155,6 +155,33 @@ const CONTAINER_STYLE_KEYS = new Set<string>([
|
||||
'-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(
|
||||
token: MergedToken,
|
||||
settings: FrequencyRenderSettings,
|
||||
@@ -700,9 +727,17 @@ export function createSubtitleRenderer(ctx: RendererContext) {
|
||||
secondaryStyleDeclarations,
|
||||
CONTAINER_STYLE_KEYS,
|
||||
);
|
||||
applyInlineStyleDeclarations(
|
||||
ctx.dom.secondarySubContainer,
|
||||
pickInlineStyleDeclarations(secondaryStyleDeclarations, CONTAINER_STYLE_KEYS),
|
||||
const secondaryContainerStyleDeclarations = pickInlineStyleDeclarations(
|
||||
secondaryStyleDeclarations,
|
||||
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) {
|
||||
|
||||
Reference in New Issue
Block a user