This commit is contained in:
大哥大哥的大哥哥
2026-09-09 14:47:29 +08:00
parent 4d9da40abd
commit 65755c9e96
832 changed files with 412085 additions and 0 deletions
@@ -0,0 +1,102 @@
const chapters = require('../../data/chapters')
const {
getProgress,
saveProgress,
resetStoryProgress,
getSettings,
} = require('../../utils/storage')
const { chapterRoute } = require('../../utils/chapterRoute')
Page({
data: {
chapters: [],
fontScale: 'large',
catalogListEnded: false,
},
onShow() {
const progress = getProgress()
const settings = getSettings()
const completed = new Set(progress.completedChapters)
const lastChapter = Number(progress.lastChapter) || 1
const completedHotspots = progress.completedHotspots || {}
this.setData({
chapters: chapters.map((chapter) => ({
...chapter,
completed: completed.has(chapter.chapterId),
current: chapter.number === lastChapter,
readingLabel: completed.has(chapter.chapterId)
? '重新翻看这一回'
: chapter.number === lastChapter
? '上次读到这里'
: '翻开这一回',
eventCount: Array.isArray(completedHotspots[chapter.chapterId])
? completedHotspots[chapter.chapterId].length
: 0,
})),
lastChapter,
fontScale: settings.fontScale === 'xlarge' ? 'xlarge' : 'large',
catalogListEnded: false,
})
},
markListEnd() {
if (!this.data.catalogListEnded) {
this.setData({ catalogListEnded: true })
}
},
openChapter(event) {
const chapter = Number(event.currentTarget.dataset.chapter)
const progress = getProgress()
const chapterMeta = chapters.find((item) => item.number === chapter)
const replay = Boolean(
chapterMeta
&& progress.completedChapters.includes(chapterMeta.chapterId),
)
progress.lastChapter = chapter
saveProgress(progress)
wx.navigateTo({
url: chapterRoute(chapter, { replay }),
})
},
restartStory() {
wx.showModal({
title: '从第一回重新开始?',
content: '关卡进度会清空;已经收藏的“我的桂香岁月”和大字设置会保留。',
confirmText: '重新开始',
cancelText: '先不清空',
confirmColor: '#9f3028',
success(result) {
if (!result || !result.confirm) return
if (!resetStoryProgress()) {
wx.showToast({
title: '进度暂时没有清空,请稍后再试',
icon: 'none',
})
return
}
wx.redirectTo({ url: chapterRoute(1) })
},
})
},
goBack() {
wx.reLaunch({ url: '/pages/home/home' })
},
onShareAppMessage() {
return {
title: '唐侦探:翻开十五回桂香故事',
path: '/pages/catalog/catalog',
}
},
onShareTimeline() {
return {
title: '唐侦探:翻开十五回桂香故事',
query: '',
}
},
})
@@ -0,0 +1,4 @@
{
"navigationBarTitleText": "十五回目录",
"pageOrientation": "landscape"
}
@@ -0,0 +1,63 @@
<view class="safe-shell catalog-shell font-{{fontScale}}">
<view class="catalog-head paper-panel">
<button class="quiet-button" bindtap="goBack" aria-label="返回封面">‹ 封面</button>
<view class="catalog-heading-copy">
<text class="eyebrow">桂香里的第十五桌</text>
<text class="catalog-title catalog-title-full">第一季 · 十五回目录</text>
<text class="catalog-title catalog-title-short">十五回目录</text>
</view>
<button
class="quiet-button restart-story-button"
bindtap="restartStory"
aria-label="从第一回重新开始,清空关卡进度但保留收藏"
>从头再看</button>
</view>
<scroll-view
class="chapter-scroll"
scroll-y
enhanced
show-scrollbar="{{true}}"
lower-threshold="24"
bindscrolltolower="markListEnd"
aria-label="十五回故事目录,可上下滑动"
>
<view class="chapter-grid">
<view
wx:for="{{chapters}}"
wx:key="chapterId"
class="chapter-card paper-panel {{item.completed ? 'completed' : ''}} {{item.current ? 'current' : ''}}"
aria-role="button"
aria-label="第{{item.number}}回,{{item.title}},{{item.readingLabel}}"
hover-class="chapter-card-hover"
data-chapter="{{item.number}}"
bindtap="openChapter"
>
<view class="chapter-number">
<text>第</text>
<text class="number">{{item.number < 10 ? '0' + item.number : item.number}}</text>
<text>回</text>
</view>
<view class="chapter-card-copy">
<text class="year">{{item.year}}</text>
<text class="chapter-name">{{item.title}}</text>
<view class="chapter-badges">
<text class="chapter-badge {{item.completed ? 'done-badge' : item.current ? 'current-badge' : 'read-badge'}}">
{{item.readingLabel}}
</text>
<text wx:if="{{item.current && item.eventCount > 0 && !item.completed}}" class="chapter-progress">
已看见 {{item.eventCount}} 处线索
</text>
</view>
</view>
<text class="open-arrow">›</text>
</view>
</view>
<text class="scroll-ending">十五回故事,都在这本画册里。</text>
</scroll-view>
<view class="list-scroll-guide" aria-live="polite">
<text>{{catalogListEnded ? '已经翻到最后一回' : '向下翻,还有更多故事'}}</text>
<text class="scroll-guide-mark" aria-hidden="true">{{catalogListEnded ? '✓' : '⌄'}}</text>
</view>
</view>
@@ -0,0 +1,364 @@
.catalog-shell {
display: flex;
height: 100vh;
gap: 12px;
flex-direction: column;
overflow: hidden;
}
.catalog-head {
display: grid;
flex: 0 0 auto;
min-height: 64px;
grid-template-columns: 132px minmax(0, 1fr) 132px;
align-items: center;
gap: 14px;
padding: 8px 112px 8px 14px;
}
.restart-story-button {
width: 100%;
min-width: 0;
min-height: 48px;
padding-right: 8px;
padding-left: 8px;
color: #7b2c25;
border-color: #a85d4e;
}
.catalog-heading-copy {
display: flex;
min-width: 0;
flex-direction: column;
}
.catalog-head > .quiet-button {
width: 100%;
min-width: 0;
min-height: 48px;
padding-right: 8px;
padding-left: 8px;
}
.catalog-title {
overflow: hidden;
font-size: 25px;
font-weight: 850;
letter-spacing: 2px;
text-overflow: ellipsis;
white-space: nowrap;
}
.catalog-title-short {
display: none;
}
.catalog-heading-copy .eyebrow {
overflow: hidden;
font-size: 16px;
letter-spacing: 1px;
text-overflow: ellipsis;
white-space: nowrap;
}
.chapter-scroll {
min-height: 0;
flex: 1;
}
.list-scroll-guide {
display: flex;
min-height: 40px;
flex: 0 0 auto;
align-items: center;
justify-content: center;
gap: 10px;
color: #f4e5bd;
background: rgba(58, 40, 28, 0.94);
border: 1px solid rgba(222, 194, 139, 0.55);
border-radius: 8px;
font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", sans-serif;
font-size: 17px;
font-weight: 750;
}
.scroll-guide-mark {
color: #f0c86b;
font-size: 24px;
line-height: 1;
}
.chapter-grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 12px;
padding: 0 2px 22px;
}
.chapter-card {
position: relative;
display: grid;
width: 100%;
min-height: 112px;
overflow: hidden;
grid-template-columns: 68px minmax(0, 1fr) 24px;
align-items: center;
gap: 14px;
padding: 12px 16px 12px 12px;
text-align: left;
border-radius: 8px;
}
.chapter-card.completed {
border-color: #50745f;
}
.chapter-card.current {
border: 3px solid #a23a2d;
box-shadow: 0 10px 25px rgba(94, 32, 24, 0.24);
}
.chapter-card-hover {
transform: translateY(2px);
opacity: 0.88;
}
.chapter-number {
display: flex;
height: 88px;
align-items: center;
justify-content: center;
flex-direction: column;
color: #f4e4be;
background: #432b1e;
border-left: 7px solid var(--cinnabar);
font-size: 16px;
}
.chapter-number .number {
font-family: Georgia, serif;
font-size: 32px;
font-weight: 800;
line-height: 1.1;
}
.chapter-card-copy {
display: flex;
min-width: 0;
flex-direction: column;
}
.year {
color: #9a332b;
font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", sans-serif;
font-size: 17px;
font-weight: 700;
}
.chapter-name {
display: -webkit-box;
margin-top: 4px;
overflow: hidden;
font-size: 22px;
font-weight: 800;
line-height: 1.35;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
}
.chapter-badges {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 8px;
margin-top: 8px;
font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", sans-serif;
font-size: 15px;
}
.chapter-badge {
padding: 5px 9px;
border-radius: 999px;
}
.done-badge {
color: #eff7ef;
background: #37624f;
}
.current-badge {
color: #fff1cf;
background: #943128;
}
.read-badge {
color: #725c42;
background: #e5d3a9;
}
.chapter-progress {
color: #6e5942;
font-size: 15px;
font-weight: 700;
}
.open-arrow {
color: #8e392f;
font-size: 44px;
}
.scroll-ending {
display: block;
padding: 4px 0 18px;
color: #d9c69e;
font-size: 17px;
text-align: center;
}
.font-xlarge .catalog-title {
font-size: 28px;
}
.font-xlarge .catalog-heading-copy .eyebrow {
font-size: 18px;
}
.font-xlarge .chapter-card {
min-height: 126px;
}
.font-xlarge .chapter-number {
height: 100px;
font-size: 18px;
}
.font-xlarge .chapter-number .number {
font-size: 36px;
}
.font-xlarge .year {
font-size: 19px;
}
.font-xlarge .chapter-name {
font-size: 25px;
}
.font-xlarge .chapter-badges,
.font-xlarge .chapter-progress {
font-size: 17px;
}
.font-xlarge .scroll-ending {
font-size: 19px;
}
.font-xlarge .list-scroll-guide {
font-size: 19px;
}
@media (max-width: 730px), (max-height: 400px) {
.catalog-shell {
gap: 8px;
}
.catalog-head {
min-height: 58px;
grid-template-columns: 96px minmax(0, 1fr) 116px;
gap: 9px;
padding: 6px 108px 6px 8px;
}
.catalog-title {
font-size: 21px;
}
.catalog-heading-copy .eyebrow {
display: none;
}
.catalog-title-full {
display: none;
}
.catalog-title-short {
display: block;
}
.chapter-grid {
gap: 9px;
padding-bottom: 16px;
}
.chapter-card {
min-height: 102px;
grid-template-columns: 58px minmax(0, 1fr) 20px;
gap: 10px;
padding: 9px 10px 9px 8px;
}
.chapter-number {
height: 80px;
font-size: 14px;
}
.chapter-number .number {
font-size: 27px;
}
.year {
font-size: 15px;
}
.chapter-name {
font-size: 19px;
}
.chapter-badges,
.chapter-progress {
font-size: 13px;
}
.open-arrow {
font-size: 36px;
}
.list-scroll-guide {
min-height: 36px;
font-size: 16px;
}
.scroll-guide-mark {
font-size: 21px;
}
.font-xlarge .catalog-title {
font-size: 24px;
}
.font-xlarge .chapter-card {
min-height: 116px;
}
.font-xlarge .chapter-number {
height: 94px;
font-size: 16px;
}
.font-xlarge .chapter-number .number {
font-size: 31px;
}
.font-xlarge .year {
font-size: 17px;
}
.font-xlarge .chapter-name {
font-size: 22px;
}
.font-xlarge .chapter-badges,
.font-xlarge .chapter-progress {
font-size: 15px;
}
}