fix: calculate vw/vh size from iframe viewport, closes #1027 (#1045)

This commit is contained in:
Huang Xin
2025-05-06 15:32:01 +08:00
committed by GitHub
parent e03636e0a1
commit c326ad402d
3 changed files with 46 additions and 25 deletions
@@ -59,27 +59,30 @@ const FoliateViewer: React.FC<{
setProgress(bookKey, detail.cfi, detail.tocItem, detail.section, detail.location, detail.range);
};
const docTransformHandler = (event: Event) => {
const { detail } = event as CustomEvent;
detail.data = Promise.resolve(detail.data)
.then((data) => {
const viewSettings = getViewSettings(bookKey);
if (detail.type === 'text/css') return transformStylesheet(data);
if (viewSettings && detail.type === 'application/xhtml+xml') {
const ctx = {
bookKey,
viewSettings,
content: data,
transformers: ['punctuation'],
};
return Promise.resolve(transformContent(ctx));
}
return data;
})
.catch((e) => {
console.error(new Error(`Failed to load ${detail.name}`, { cause: e }));
return '';
});
const getDocTransformHandler = ({ width, height }: { width: number; height: number }) => {
return (event: Event) => {
const { detail } = event as CustomEvent;
detail.data = Promise.resolve(detail.data)
.then((data) => {
const viewSettings = getViewSettings(bookKey);
if (viewSettings && detail.type === 'text/css')
return transformStylesheet(viewSettings, width, height, data);
if (viewSettings && detail.type === 'application/xhtml+xml') {
const ctx = {
bookKey,
viewSettings,
content: data,
transformers: ['punctuation'],
};
return Promise.resolve(transformContent(ctx));
}
return data;
})
.catch((e) => {
console.error(new Error(`Failed to load ${detail.name}`, { cause: e }));
return '';
});
};
};
const docLoadHandler = (event: Event) => {
@@ -163,6 +166,10 @@ const FoliateViewer: React.FC<{
document.body.append(view);
containerRef.current?.appendChild(view);
const containerRect = containerRef.current?.getBoundingClientRect();
const width = containerRect?.width || window.innerWidth;
const height = containerRect?.height || window.innerHeight;
const writingMode = viewSettings.writingMode;
if (writingMode) {
const settingsDir = getBookDirFromWritingMode(writingMode);
@@ -181,7 +188,7 @@ const FoliateViewer: React.FC<{
const { book } = view;
book.transformTarget?.addEventListener('data', docTransformHandler);
book.transformTarget?.addEventListener('data', getDocTransformHandler({ width, height }));
view.renderer.setStyles?.(getStyles(viewSettings));
const isScrolled = viewSettings.scrolled!;
+16 -2
View File
@@ -274,12 +274,16 @@ const getLayoutStyles = (
display: none;
}
/* Now begins really dirty hacks to fix some badly designed epubs */
.duokan-footnote-content,
.duokan-footnote-item {
display: none;
}
/* Now begins really dirty hacks to fix some badly designed epubs */
.duokan-image-single {
height: 100vh !important;
}
.calibre {
color: unset;
}
@@ -420,10 +424,18 @@ export const mountAdditionalFonts = (document: Document) => {
document.head.appendChild(style);
};
export const transformStylesheet = (css: string) => {
export const transformStylesheet = (
viewSettings: ViewSettings,
width: number,
height: number,
css: string,
) => {
const isMobile = ['ios', 'android'].includes(getOSPlatform());
const fontScale = isMobile ? 1.25 : 1;
const w = width * (1 - viewSettings.gapPercent / 100);
const h = height - viewSettings.marginPx * 2;
// replace absolute font sizes with rem units
// replace vw and vh as they cause problems with layout
// replace hardcoded colors
return css
.replace(/font-size\s*:\s*xx-small/gi, 'font-size: 0.6rem')
@@ -442,6 +454,8 @@ export const transformStylesheet = (css: string) => {
const rem = parseFloat(pt) / fontScale / 12;
return `font-size: ${rem}rem`;
})
.replace(/(\d*\.?\d+)vw/gi, (_, d) => (parseFloat(d) * w) / 100 + 'px')
.replace(/(\d*\.?\d+)vh/gi, (_, d) => (parseFloat(d) * h) / 100 + 'px')
.replace(/[\s;]color\s*:\s*#000000/gi, 'color: var(--theme-fg-color)')
.replace(/[\s;]color\s*:\s*#000/gi, 'color: var(--theme-fg-color)')
.replace(/[\s;]color\s*:\s*rgb\(0,\s*0,\s*0\)/gi, 'color: var(--theme-fg-color)');