123 lines
3.5 KiB
JavaScript
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,
|
|
}
|