mirror of
https://github.com/LifeArchiveProject/WeChatDataAnalysis.git
synced 2026-02-19 06:10:52 +08:00
feat(wrapped-ui): 新增年度总结页面与热力图卡片
- 新增 /wrapped PPT 风格滑动浏览(封面 + 卡片页) - 新增 Card#1 组件与 24×7 周-小时热力图可视化 - 首页新增年度总结入口;useApi 增加 getWrappedAnnual;补充 wrapped 背景纹理
This commit is contained in:
47
frontend/utils/wrapped/heatmap.js
Normal file
47
frontend/utils/wrapped/heatmap.js
Normal file
@@ -0,0 +1,47 @@
|
||||
// Utilities for Wrapped heatmap rendering.
|
||||
|
||||
export const clamp01 = (v) => {
|
||||
const n = Number(v)
|
||||
if (!Number.isFinite(n)) return 0
|
||||
if (n < 0) return 0
|
||||
if (n > 1) return 1
|
||||
return n
|
||||
}
|
||||
|
||||
export const maxInMatrix = (matrix) => {
|
||||
if (!Array.isArray(matrix)) return 0
|
||||
let m = 0
|
||||
for (const row of matrix) {
|
||||
if (!Array.isArray(row)) continue
|
||||
for (const v of row) {
|
||||
const n = Number(v)
|
||||
if (Number.isFinite(n) && n > m) m = n
|
||||
}
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// Color inspired by WeChat green, with a slight "gold" shift on high intensity
|
||||
// (EchoTrace-style accent) while keeping the overall WeChat vibe.
|
||||
export const heatColor = (value, max) => {
|
||||
const v = Number(value) || 0
|
||||
const m = Number(max) || 0
|
||||
if (!(v > 0) || !(m > 0)) return 'rgba(0,0,0,0.05)'
|
||||
|
||||
// Use sqrt scaling to make low values still visible.
|
||||
const t = clamp01(Math.sqrt(v / m))
|
||||
|
||||
// Hue from green (~145) -> yellow-green (~95)
|
||||
const hue = 145 - 50 * t
|
||||
const sat = 70
|
||||
const light = 92 - 42 * t
|
||||
return `hsl(${hue.toFixed(1)} ${sat}% ${light.toFixed(1)}%)`
|
||||
}
|
||||
|
||||
export const formatHourRange = (hour) => {
|
||||
const h = Number(hour)
|
||||
if (!Number.isFinite(h)) return ''
|
||||
const hh = String(h).padStart(2, '0')
|
||||
return `${hh}:00-${hh}:59`
|
||||
}
|
||||
|
||||
27
frontend/utils/wrapped/types.js
Normal file
27
frontend/utils/wrapped/types.js
Normal file
@@ -0,0 +1,27 @@
|
||||
// JSDoc types for the Wrapped API (kept in JS to match the current codebase).
|
||||
|
||||
/**
|
||||
* @typedef {Object} WrappedCardBase
|
||||
* @property {number} id
|
||||
* @property {string} title
|
||||
* @property {'global'} scope
|
||||
* @property {'A'|'B'|'C'|'D'|'E'} category
|
||||
* @property {'ok'|'error'} status
|
||||
* @property {string} kind
|
||||
* @property {string} narrative
|
||||
* @property {Record<string, any>} data
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} WrappedAnnualResponse
|
||||
* @property {string} account
|
||||
* @property {number} year
|
||||
* @property {'global'} scope
|
||||
* @property {string|null} username
|
||||
* @property {number} generated_at
|
||||
* @property {boolean} cached
|
||||
* @property {WrappedCardBase[]} cards
|
||||
*/
|
||||
|
||||
export {}
|
||||
|
||||
Reference in New Issue
Block a user