Files
2026-09-09 14:47:29 +08:00

123 lines
3.5 KiB
JavaScript

function finiteNumber(value, fallback = 0) {
const parsed = Number(value)
return Number.isFinite(parsed) ? parsed : fallback
}
function clamp(value, minimum, maximum) {
return Math.min(maximum, Math.max(minimum, value))
}
/**
* 首页使用自定义导航栏,横屏时既要避开左右刘海与底部 Home
* Indicator,也要为微信右上角胶囊留下真实空间。CSS 的 env()
* 在部分微信横屏机型上只会返回系统安全区,不包含胶囊,因此这里
* 以运行时尺寸为准,CSS env() 只作为脚本尚未执行时的兜底。
*/
function getHomeLayoutMetrics(windowInfo = {}, menuRect = {}) {
const windowWidth = Math.max(320, finiteNumber(windowInfo.windowWidth, 844))
const windowHeight = Math.max(240, finiteNumber(windowInfo.windowHeight, 390))
const safeArea = windowInfo.safeArea || {}
const safeLeft = clamp(
finiteNumber(safeArea.left, 0),
0,
windowWidth / 3,
)
const safeRightEdge = clamp(
finiteNumber(safeArea.right, windowWidth),
windowWidth * 2 / 3,
windowWidth,
)
const safeRight = clamp(
windowWidth - safeRightEdge,
0,
windowWidth / 3,
)
const safeTop = Math.max(
0,
finiteNumber(windowInfo.statusBarHeight, 0),
finiteNumber(safeArea.top, 0),
)
const safeBottomEdge = clamp(
finiteNumber(safeArea.bottom, windowHeight),
windowHeight * 2 / 3,
windowHeight,
)
const safeBottom = clamp(
windowHeight - safeBottomEdge,
0,
windowHeight / 3,
)
const menuLeft = finiteNumber(menuRect.left, windowWidth)
const menuBottom = finiteNumber(menuRect.bottom, 0)
const hasMenuRect = (
menuLeft > windowWidth / 2
&& menuLeft < windowWidth
&& menuBottom > 0
)
const compactHeight = windowHeight <= 620
const horizontalPageGap = compactHeight ? 10 : 14
const capsuleGap = compactHeight ? 8 : 10
const leftInset = Math.ceil(safeLeft + horizontalPageGap)
const rightInset = Math.ceil(Math.max(
safeRight + horizontalPageGap,
hasMenuRect
? windowWidth - menuLeft + capsuleGap
: safeRight + horizontalPageGap,
))
const topInset = Math.ceil(safeTop + (compactHeight ? 8 : 12))
const bottomInset = Math.ceil(safeBottom + (compactHeight ? 7 : 12))
return {
windowWidth,
windowHeight,
compactHeight,
safeLeft,
safeRight,
safeTop,
safeBottom,
leftInset,
rightInset,
topInset,
bottomInset,
hasMenuRect,
}
}
function getHomeLayoutStyle(metrics = {}) {
return [
`height:${Math.max(240, finiteNumber(metrics.windowHeight, 390))}px`,
`--home-top-inset:${Math.max(0, finiteNumber(metrics.topInset, 8))}px`,
`--home-right-inset:${Math.max(0, finiteNumber(metrics.rightInset, 10))}px`,
`--home-bottom-inset:${Math.max(0, finiteNumber(metrics.bottomInset, 7))}px`,
`--home-left-inset:${Math.max(0, finiteNumber(metrics.leftInset, 10))}px`,
].join(';')
}
function hasReadingProgress(progress = {}) {
const completedChapters = Array.isArray(progress.completedChapters)
? progress.completedChapters
: []
const completedHotspots = progress.completedHotspots
&& typeof progress.completedHotspots === 'object'
? progress.completedHotspots
: {}
const hasCompletedHotspot = Object.values(completedHotspots).some(
(ids) => Array.isArray(ids) && ids.length > 0,
)
return (
completedChapters.length > 0
|| finiteNumber(progress.lastChapter, 1) > 1
|| hasCompletedHotspot
)
}
module.exports = {
getHomeLayoutMetrics,
getHomeLayoutStyle,
hasReadingProgress,
}