feat: migrate static pages to native tabbar
This commit is contained in:
@@ -1,93 +1,205 @@
|
||||
const { getRuntimeConfig } = require('../../config/env')
|
||||
const { sessionStore } = require('../../stores')
|
||||
const { maskToken } = require('../../utils/util')
|
||||
const { ROUTES, openStaticRoute } = require('../../utils/static-ux/route-map')
|
||||
const { createTcmHomeHubCards } = require('../../utils/static-ux/tcm')
|
||||
|
||||
const QUICK_ENTRIES = [
|
||||
{
|
||||
title: '登录主包',
|
||||
description: '演示主包内的认证入口、全局会话同步和基础 UI 组件封装。',
|
||||
badge: '主包',
|
||||
actionText: '打开登录页',
|
||||
actionPath: '/pages/login/index'
|
||||
},
|
||||
{
|
||||
title: '业务工作台',
|
||||
description: '演示分包页面,只在需要时加载,保持主包轻量和首页启动稳定。',
|
||||
badge: '分包',
|
||||
actionText: '进入工作台',
|
||||
actionPath: '/packages/demo/pages/workbench/index'
|
||||
}
|
||||
]
|
||||
const HOME_PAGE_BLUEPRINT = Object.freeze({
|
||||
brandName: '玄知中医',
|
||||
greeting: '晚上好',
|
||||
subtitle: '今天想学点什么?从典籍、工具或养生主题开始。',
|
||||
searchPlaceholder: '搜索典籍、术语、AI问答...',
|
||||
searchBadge: 'AI',
|
||||
searchRoute: ROUTES.tcm.searchBooks,
|
||||
portalTitle: '学习入口',
|
||||
encyclopediaTitle: '中医百科',
|
||||
encyclopediaCards: [
|
||||
{
|
||||
key: 'classic',
|
||||
icon: '书',
|
||||
title: '经典书城',
|
||||
route: ROUTES.tabs.library
|
||||
},
|
||||
{
|
||||
key: 'meridian',
|
||||
icon: '穴',
|
||||
title: '经络穴位',
|
||||
status: '待开放'
|
||||
},
|
||||
{
|
||||
key: 'disease',
|
||||
icon: '病',
|
||||
title: '疾病百科',
|
||||
status: '待开放'
|
||||
}
|
||||
],
|
||||
toolsTitle: '学习工具',
|
||||
toolCards: [
|
||||
{
|
||||
key: 'qa',
|
||||
icon: '问',
|
||||
title: 'AI问答',
|
||||
route: ROUTES.tabs.ai
|
||||
},
|
||||
{
|
||||
key: 'formula',
|
||||
icon: '方',
|
||||
title: '方剂笔记',
|
||||
route: `${ROUTES.tcm.assets}?kind=notes`
|
||||
},
|
||||
{
|
||||
key: 'constitution',
|
||||
icon: '诊',
|
||||
title: '体质诊断',
|
||||
route: ROUTES.tabs.ai
|
||||
},
|
||||
{
|
||||
key: 'wellness',
|
||||
icon: '养',
|
||||
title: '智能饮片'
|
||||
}
|
||||
],
|
||||
wellnessTitle: '养生调理',
|
||||
wellnessCards: [
|
||||
{
|
||||
key: 'constitution-check',
|
||||
icon: '🧬',
|
||||
title: 'AI体质检测',
|
||||
status: '待开放',
|
||||
route: ROUTES.tabs.ai
|
||||
},
|
||||
{
|
||||
key: 'medicated-diet',
|
||||
icon: '🍲',
|
||||
title: '药膳',
|
||||
status: '待开放'
|
||||
},
|
||||
{
|
||||
key: 'ingredient',
|
||||
icon: '🥬',
|
||||
title: '食材',
|
||||
status: '待开放'
|
||||
}
|
||||
],
|
||||
classicsTitle: '热门典籍',
|
||||
classicsActionText: '进入书城',
|
||||
classicsActionRoute: ROUTES.tabs.library,
|
||||
classicsBooks: [
|
||||
{
|
||||
key: 'huangdi-neijing-suwen',
|
||||
coverText: '黄',
|
||||
title: '黄帝内经素问',
|
||||
route: `${ROUTES.tcm.bookDetail}?scene=classic-a`
|
||||
},
|
||||
{
|
||||
key: 'shang-han-lun',
|
||||
coverText: '伤',
|
||||
title: '伤寒论',
|
||||
route: `${ROUTES.tcm.bookDetail}?scene=classic-b`
|
||||
},
|
||||
{
|
||||
key: 'wen-bing-tiao-bian',
|
||||
coverText: '温',
|
||||
title: '温病条辨',
|
||||
route: `${ROUTES.tcm.searchBooks}?keyword=温病条辨`
|
||||
},
|
||||
{
|
||||
key: 'bencao-gangmu-bieming-lu',
|
||||
coverText: '本',
|
||||
title: '本草纲目别名录',
|
||||
route: `${ROUTES.tcm.searchBooks}?keyword=本草纲目`
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
function buildSessionView(state) {
|
||||
const userName = state.userInfo?.nickname || state.userInfo?.name || '访客'
|
||||
function cloneItems(items) {
|
||||
return items.map(item => ({ ...item }))
|
||||
}
|
||||
|
||||
function createHomePageData() {
|
||||
return {
|
||||
statusLabel: state.isLoggedIn ? '已登录' : '未登录',
|
||||
userName,
|
||||
tokenLabel: maskToken(state.token),
|
||||
permissionsLabel: state.permissions.length ? state.permissions.join(' / ') : '暂无权限'
|
||||
brandName: HOME_PAGE_BLUEPRINT.brandName,
|
||||
greeting: HOME_PAGE_BLUEPRINT.greeting,
|
||||
subtitle: HOME_PAGE_BLUEPRINT.subtitle,
|
||||
searchPlaceholder: HOME_PAGE_BLUEPRINT.searchPlaceholder,
|
||||
searchBadge: HOME_PAGE_BLUEPRINT.searchBadge,
|
||||
searchRoute: HOME_PAGE_BLUEPRINT.searchRoute,
|
||||
portalTitle: HOME_PAGE_BLUEPRINT.portalTitle,
|
||||
portalCards: createTcmHomeHubCards(),
|
||||
encyclopediaTitle: HOME_PAGE_BLUEPRINT.encyclopediaTitle,
|
||||
encyclopediaCards: cloneItems(HOME_PAGE_BLUEPRINT.encyclopediaCards),
|
||||
toolsTitle: HOME_PAGE_BLUEPRINT.toolsTitle,
|
||||
toolCards: cloneItems(HOME_PAGE_BLUEPRINT.toolCards),
|
||||
wellnessTitle: HOME_PAGE_BLUEPRINT.wellnessTitle,
|
||||
wellnessCards: cloneItems(HOME_PAGE_BLUEPRINT.wellnessCards),
|
||||
classicsTitle: HOME_PAGE_BLUEPRINT.classicsTitle,
|
||||
classicsActionText: HOME_PAGE_BLUEPRINT.classicsActionText,
|
||||
classicsActionRoute: HOME_PAGE_BLUEPRINT.classicsActionRoute,
|
||||
classicsBooks: cloneItems(HOME_PAGE_BLUEPRINT.classicsBooks)
|
||||
}
|
||||
}
|
||||
|
||||
function navigateToRoute(route) {
|
||||
openStaticRoute(route, wx)
|
||||
}
|
||||
|
||||
function showPendingToast(title) {
|
||||
if (typeof wx?.showToast !== 'function') {
|
||||
return
|
||||
}
|
||||
|
||||
wx.showToast({
|
||||
title: title ? `${title}待开放` : '功能建设中',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
|
||||
function handleHomeEntry(route, title) {
|
||||
if (openStaticRoute(route, wx)) {
|
||||
return
|
||||
}
|
||||
|
||||
showPendingToast(title)
|
||||
}
|
||||
|
||||
Page({
|
||||
data: {
|
||||
quickEntries: QUICK_ENTRIES,
|
||||
envName: '',
|
||||
apiBaseUrl: '',
|
||||
isLoggedIn: false,
|
||||
sessionView: buildSessionView(sessionStore.getState())
|
||||
},
|
||||
onLoad() {
|
||||
const runtimeConfig = getRuntimeConfig()
|
||||
data: createHomePageData(),
|
||||
|
||||
this.unsubscribe = sessionStore.subscribe(nextState => {
|
||||
this.syncSession(nextState)
|
||||
})
|
||||
handleSearchTap() {
|
||||
handleHomeEntry(this.data.searchRoute, '搜索')
|
||||
},
|
||||
|
||||
this.setData({
|
||||
envName: runtimeConfig.name.toUpperCase(),
|
||||
apiBaseUrl: runtimeConfig.baseURL
|
||||
})
|
||||
this.syncSession(sessionStore.getState())
|
||||
},
|
||||
onUnload() {
|
||||
this.unsubscribe?.()
|
||||
},
|
||||
syncSession(state) {
|
||||
this.setData({
|
||||
isLoggedIn: state.isLoggedIn,
|
||||
sessionView: buildSessionView(state)
|
||||
})
|
||||
},
|
||||
handlePrimaryAction() {
|
||||
if (this.data.isLoggedIn) {
|
||||
wx.navigateTo({
|
||||
url: '/packages/demo/pages/workbench/index'
|
||||
})
|
||||
return
|
||||
}
|
||||
handleEncyclopediaTap(event) {
|
||||
const { route, title } = event.currentTarget.dataset
|
||||
|
||||
wx.navigateTo({
|
||||
url: '/pages/login/index'
|
||||
})
|
||||
handleHomeEntry(route, title)
|
||||
},
|
||||
handleLogout() {
|
||||
sessionStore.clearSession()
|
||||
wx.showToast({
|
||||
title: '已清理登录态',
|
||||
icon: 'success'
|
||||
})
|
||||
|
||||
handlePortalTap(event) {
|
||||
navigateToRoute(event.currentTarget.dataset.route)
|
||||
},
|
||||
handleEntryAction(event) {
|
||||
const { path } = event.detail
|
||||
|
||||
if (!path) {
|
||||
return
|
||||
}
|
||||
handleToolTap(event) {
|
||||
const { route, title } = event.currentTarget.dataset
|
||||
|
||||
wx.navigateTo({
|
||||
url: path
|
||||
})
|
||||
handleHomeEntry(route, title)
|
||||
},
|
||||
|
||||
handleWellnessTap(event) {
|
||||
const { route, title } = event.currentTarget.dataset
|
||||
|
||||
handleHomeEntry(route, title)
|
||||
},
|
||||
|
||||
handleClassicActionTap() {
|
||||
handleHomeEntry(this.data.classicsActionRoute, this.data.classicsActionText)
|
||||
},
|
||||
|
||||
handleClassicTap(event) {
|
||||
const { route, title } = event.currentTarget.dataset
|
||||
|
||||
handleHomeEntry(route, title)
|
||||
}
|
||||
})
|
||||
|
||||
module.exports = {
|
||||
HOME_PAGE_BLUEPRINT,
|
||||
createHomePageData
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
{
|
||||
"navigationBarTitleText": "首页",
|
||||
"usingComponents": {
|
||||
"app-button": "../../components/base/app-button/index",
|
||||
"entry-card": "../../components/biz/entry-card/index"
|
||||
}
|
||||
"navigationBarTitleText": "玄知中医",
|
||||
"navigationBarBackgroundColor": "#f8ecd8",
|
||||
"navigationBarTextStyle": "black"
|
||||
}
|
||||
|
||||
@@ -1,65 +1,105 @@
|
||||
<view class="page-shell">
|
||||
<view class="panel hero">
|
||||
<text class="hero__eyebrow">Stable Native Architecture</text>
|
||||
<text class="hero__title">玄志小程序基础骨架</text>
|
||||
<text class="hero__summary">
|
||||
原生小程序 + JS + npm + TDesign + 分包 + service/store 分层,保留微信原生性能和长期维护边界。
|
||||
</text>
|
||||
<app-button
|
||||
block
|
||||
text="{{isLoggedIn ? '进入业务工作台' : '前往登录页'}}"
|
||||
bind:tap="handlePrimaryAction"
|
||||
></app-button>
|
||||
<app-button
|
||||
wx:if="{{isLoggedIn}}"
|
||||
block
|
||||
text="清理登录态"
|
||||
theme="default"
|
||||
variant="outline"
|
||||
bind:tap="handleLogout"
|
||||
></app-button>
|
||||
<view class="home-page">
|
||||
<view class="home-page__brand">{{brandName}}</view>
|
||||
<text class="home-page__greeting">{{greeting}}</text>
|
||||
<text class="home-page__subtitle">{{subtitle}}</text>
|
||||
|
||||
<view class="search-card" bindtap="handleSearchTap">
|
||||
<view class="search-card__leading">搜</view>
|
||||
<text class="search-card__placeholder">{{searchPlaceholder}}</text>
|
||||
<view class="search-card__badge">{{searchBadge}}</view>
|
||||
</view>
|
||||
|
||||
<view class="panel session-card">
|
||||
<text class="section-title">当前会话</text>
|
||||
<view class="session-card__rows">
|
||||
<view class="meta-row">
|
||||
<text class="session-card__label">运行环境</text>
|
||||
<text class="session-card__value">{{envName}}</text>
|
||||
</view>
|
||||
<view class="meta-row">
|
||||
<text class="session-card__label">API 地址</text>
|
||||
<text class="session-card__value session-card__value--mono">{{apiBaseUrl}}</text>
|
||||
</view>
|
||||
<view class="meta-row">
|
||||
<text class="session-card__label">登录状态</text>
|
||||
<text class="session-card__value">{{sessionView.statusLabel}}</text>
|
||||
</view>
|
||||
<view class="meta-row">
|
||||
<text class="session-card__label">当前用户</text>
|
||||
<text class="session-card__value">{{sessionView.userName}}</text>
|
||||
</view>
|
||||
<view class="meta-row">
|
||||
<text class="session-card__label">Token</text>
|
||||
<text class="session-card__value session-card__value--mono">{{sessionView.tokenLabel}}</text>
|
||||
</view>
|
||||
<view class="meta-row meta-row--top">
|
||||
<text class="session-card__label">权限</text>
|
||||
<text class="session-card__value session-card__value--mono">{{sessionView.permissionsLabel}}</text>
|
||||
<view class="section-card">
|
||||
<text class="section-card__title">{{encyclopediaTitle}}</text>
|
||||
<view class="feature-grid feature-grid--four">
|
||||
<view class="feature-grid__item" wx:for="{{encyclopediaCards}}" wx:key="key">
|
||||
<view
|
||||
class="feature-card"
|
||||
data-route="{{item.route}}"
|
||||
data-title="{{item.title}}"
|
||||
bindtap="handleEncyclopediaTap"
|
||||
>
|
||||
<text class="feature-card__status" wx:if="{{item.status}}">{{item.status}}</text>
|
||||
<view class="feature-card__icon">{{item.icon}}</view>
|
||||
<text class="feature-card__title">{{item.title}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="entry-list">
|
||||
<entry-card
|
||||
wx:for="{{quickEntries}}"
|
||||
wx:key="actionPath"
|
||||
title="{{item.title}}"
|
||||
description="{{item.description}}"
|
||||
badge="{{item.badge}}"
|
||||
actionText="{{item.actionText}}"
|
||||
actionPath="{{item.actionPath}}"
|
||||
bind:action="handleEntryAction"
|
||||
></entry-card>
|
||||
<view class="section-card">
|
||||
<text class="section-card__title">{{portalTitle}}</text>
|
||||
<view class="portal-grid">
|
||||
<view
|
||||
class="portal-grid__item"
|
||||
wx:for="{{portalCards}}"
|
||||
wx:key="key"
|
||||
>
|
||||
<view class="portal-card" data-route="{{item.route}}" bindtap="handlePortalTap">
|
||||
<text class="portal-card__badge">{{item.badge}}</text>
|
||||
<text class="portal-card__title">{{item.title}}</text>
|
||||
<text class="portal-card__subtitle">{{item.subtitle}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="section-card">
|
||||
<text class="section-card__title">{{toolsTitle}}</text>
|
||||
<view class="feature-grid feature-grid--four">
|
||||
<view class="feature-grid__item" wx:for="{{toolCards}}" wx:key="key">
|
||||
<view
|
||||
class="feature-card"
|
||||
data-route="{{item.route}}"
|
||||
data-title="{{item.title}}"
|
||||
bindtap="handleToolTap"
|
||||
>
|
||||
<view class="feature-card__icon">{{item.icon}}</view>
|
||||
<text class="feature-card__title">{{item.title}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="section-card">
|
||||
<text class="section-card__title">{{wellnessTitle}}</text>
|
||||
<view class="feature-grid feature-grid--three">
|
||||
<view class="feature-grid__item" wx:for="{{wellnessCards}}" wx:key="key">
|
||||
<view
|
||||
class="feature-card feature-card--wellness"
|
||||
data-route="{{item.route}}"
|
||||
data-title="{{item.title}}"
|
||||
bindtap="handleWellnessTap"
|
||||
>
|
||||
<text class="feature-card__status" wx:if="{{item.status}}">{{item.status}}</text>
|
||||
<view class="feature-card__emoji-box">
|
||||
<text class="feature-card__emoji">{{item.icon}}</text>
|
||||
</view>
|
||||
<text class="feature-card__title feature-card__title--wellness">{{item.title}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="section-card section-card--last">
|
||||
<view class="section-card__header">
|
||||
<text class="section-card__title">{{classicsTitle}}</text>
|
||||
<text class="section-card__action" bindtap="handleClassicActionTap">{{classicsActionText}} →</text>
|
||||
</view>
|
||||
<view class="feature-grid feature-grid--four">
|
||||
<view class="feature-grid__item" wx:for="{{classicsBooks}}" wx:key="key">
|
||||
<view
|
||||
class="feature-card feature-card--classic"
|
||||
data-route="{{item.route}}"
|
||||
data-title="{{item.title}}"
|
||||
bindtap="handleClassicTap"
|
||||
>
|
||||
<view class="feature-card__book">
|
||||
<text class="feature-card__book-char">{{item.coverText}}</text>
|
||||
</view>
|
||||
<text class="feature-card__title feature-card__title--classic">{{item.title}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@@ -1,68 +1,323 @@
|
||||
.hero {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 24rpx;
|
||||
padding: 36rpx 32rpx;
|
||||
background: linear-gradient(160deg, #0f172a 0%, #1e293b 100%);
|
||||
color: #f8fafc;
|
||||
page {
|
||||
min-height: 100%;
|
||||
background:
|
||||
linear-gradient(180deg, #f8edd6 0%, #f9f0de 24%, #f6ead4 100%);
|
||||
}
|
||||
|
||||
.hero__eyebrow {
|
||||
font-size: 22rpx;
|
||||
letter-spacing: 4rpx;
|
||||
text-transform: uppercase;
|
||||
color: #93c5fd;
|
||||
.home-page {
|
||||
position: relative;
|
||||
min-height: 100vh;
|
||||
box-sizing: border-box;
|
||||
padding: 12rpx 18rpx 36rpx;
|
||||
background:
|
||||
linear-gradient(135deg, rgba(255, 255, 255, 0.65) 0%, rgba(255, 248, 236, 0) 36%),
|
||||
linear-gradient(225deg, rgba(255, 245, 227, 0.7) 0%, rgba(255, 245, 227, 0) 44%);
|
||||
}
|
||||
|
||||
.hero__title {
|
||||
font-size: 48rpx;
|
||||
.home-page__brand {
|
||||
display: inline-flex;
|
||||
padding: 12rpx 20rpx;
|
||||
border-radius: 999rpx;
|
||||
background: rgba(241, 222, 190, 0.95);
|
||||
color: #946739;
|
||||
font-size: 26rpx;
|
||||
line-height: 1;
|
||||
box-shadow: 0 12rpx 24rpx rgba(173, 120, 56, 0.08);
|
||||
}
|
||||
|
||||
.home-page__greeting {
|
||||
display: block;
|
||||
margin-top: 12rpx;
|
||||
font-family: 'STSong', 'Songti SC', serif;
|
||||
font-size: 60rpx;
|
||||
font-weight: 700;
|
||||
line-height: 1.1;
|
||||
color: #2f1f12;
|
||||
}
|
||||
|
||||
.home-page__subtitle {
|
||||
display: block;
|
||||
margin-top: 10rpx;
|
||||
font-family: 'STSong', 'Songti SC', serif;
|
||||
font-size: 24rpx;
|
||||
line-height: 1.65;
|
||||
color: #8f6a42;
|
||||
}
|
||||
|
||||
.search-card {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-top: 16rpx;
|
||||
padding: 16rpx 18rpx 16rpx 20rpx;
|
||||
border: 1rpx solid rgba(182, 151, 112, 0.24);
|
||||
border-radius: 30rpx;
|
||||
background: rgba(255, 251, 245, 0.96);
|
||||
box-shadow: 0 16rpx 30rpx rgba(185, 152, 108, 0.14);
|
||||
}
|
||||
|
||||
.search-card__leading {
|
||||
margin-right: 12rpx;
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
border-radius: 50%;
|
||||
background: linear-gradient(135deg, #78c7dd 0%, #7b60bf 100%);
|
||||
color: #ffffff;
|
||||
font-size: 22rpx;
|
||||
font-weight: 700;
|
||||
line-height: 40rpx;
|
||||
text-align: center;
|
||||
box-shadow: 0 10rpx 18rpx rgba(123, 96, 191, 0.22);
|
||||
}
|
||||
|
||||
.search-card__placeholder {
|
||||
flex: 1;
|
||||
margin-right: 12rpx;
|
||||
font-size: 26rpx;
|
||||
color: #a18463;
|
||||
}
|
||||
|
||||
.search-card__badge {
|
||||
flex-shrink: 0;
|
||||
min-width: 80rpx;
|
||||
padding: 10rpx 18rpx;
|
||||
border-radius: 999rpx;
|
||||
background: linear-gradient(135deg, #b67b35 0%, #8f5e21 100%);
|
||||
color: #fff4de;
|
||||
font-family: 'Georgia', 'Times New Roman', serif;
|
||||
font-size: 24rpx;
|
||||
font-weight: 700;
|
||||
line-height: 1;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.section-card {
|
||||
margin-top: 16rpx;
|
||||
padding: 24rpx 18rpx 16rpx;
|
||||
border: 1rpx solid rgba(189, 155, 105, 0.14);
|
||||
border-radius: 30rpx;
|
||||
background: rgba(255, 250, 243, 0.94);
|
||||
box-shadow: 0 18rpx 36rpx rgba(178, 144, 99, 0.12);
|
||||
}
|
||||
|
||||
.section-card--last {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.section-card__header {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 18rpx;
|
||||
padding: 0 4rpx;
|
||||
}
|
||||
|
||||
.section-card__header .section-card__title {
|
||||
margin-bottom: 0;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.section-card__title {
|
||||
display: block;
|
||||
margin-bottom: 18rpx;
|
||||
padding-left: 4rpx;
|
||||
font-family: 'STSong', 'Songti SC', serif;
|
||||
font-size: 42rpx;
|
||||
font-weight: 700;
|
||||
line-height: 1.2;
|
||||
color: #2f1f12;
|
||||
}
|
||||
|
||||
.section-card__action {
|
||||
color: #be8b4a;
|
||||
font-family: 'STSong', 'Songti SC', serif;
|
||||
font-size: 24rpx;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.hero__summary {
|
||||
font-size: 26rpx;
|
||||
line-height: 1.8;
|
||||
color: rgba(248, 250, 252, 0.8);
|
||||
.portal-grid {
|
||||
overflow: hidden;
|
||||
margin: 0 -5rpx;
|
||||
}
|
||||
|
||||
.session-card {
|
||||
.portal-grid__item {
|
||||
box-sizing: border-box;
|
||||
float: left;
|
||||
width: 50%;
|
||||
padding: 0 5rpx 10rpx;
|
||||
}
|
||||
|
||||
.portal-card {
|
||||
min-height: 164rpx;
|
||||
padding: 18rpx 18rpx 16rpx;
|
||||
border: 1rpx solid rgba(191, 169, 140, 0.46);
|
||||
border-radius: 24rpx;
|
||||
background: linear-gradient(180deg, rgba(255, 255, 255, 0.78) 0%, rgba(250, 243, 232, 0.96) 100%);
|
||||
box-shadow: 0 10rpx 20rpx rgba(182, 150, 107, 0.1);
|
||||
}
|
||||
|
||||
.portal-card__badge {
|
||||
display: inline-block;
|
||||
padding: 6rpx 14rpx;
|
||||
border-radius: 999rpx;
|
||||
background: rgba(246, 234, 214, 0.94);
|
||||
color: #b67c31;
|
||||
font-size: 18rpx;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.portal-card__title {
|
||||
display: block;
|
||||
margin-top: 18rpx;
|
||||
font-family: 'STSong', 'Songti SC', serif;
|
||||
font-size: 28rpx;
|
||||
font-weight: 700;
|
||||
line-height: 1.2;
|
||||
color: #38261a;
|
||||
}
|
||||
|
||||
.portal-card__subtitle {
|
||||
display: block;
|
||||
margin-top: 10rpx;
|
||||
font-size: 22rpx;
|
||||
line-height: 1.55;
|
||||
color: #8f6a42;
|
||||
}
|
||||
|
||||
.feature-grid {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 24rpx;
|
||||
padding: 32rpx;
|
||||
flex-wrap: wrap;
|
||||
margin: 0 -4rpx;
|
||||
}
|
||||
|
||||
.session-card__rows {
|
||||
.feature-grid__item {
|
||||
box-sizing: border-box;
|
||||
padding: 0 4rpx 10rpx;
|
||||
}
|
||||
|
||||
.feature-grid--four .feature-grid__item {
|
||||
width: 25%;
|
||||
}
|
||||
|
||||
.feature-grid--three .feature-grid__item {
|
||||
width: 33.3333%;
|
||||
}
|
||||
|
||||
.feature-card {
|
||||
position: relative;
|
||||
display: flex;
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
flex-direction: column;
|
||||
gap: 20rpx;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 18rpx 8rpx;
|
||||
border: 1rpx solid rgba(191, 169, 140, 0.46);
|
||||
border-radius: 22rpx;
|
||||
background: linear-gradient(180deg, rgba(255, 255, 255, 0.7) 0%, rgba(250, 243, 232, 0.92) 100%);
|
||||
}
|
||||
|
||||
.session-card__label {
|
||||
flex-shrink: 0;
|
||||
.feature-grid--four .feature-card {
|
||||
min-height: 152rpx;
|
||||
}
|
||||
|
||||
.feature-grid--three .feature-card {
|
||||
min-height: 182rpx;
|
||||
}
|
||||
|
||||
.feature-card__status {
|
||||
position: absolute;
|
||||
top: 8rpx;
|
||||
right: 8rpx;
|
||||
padding: 6rpx 12rpx;
|
||||
border-radius: 999rpx;
|
||||
background: rgba(246, 234, 214, 0.94);
|
||||
color: #c39d6a;
|
||||
font-size: 18rpx;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.feature-card__icon {
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
border-radius: 20rpx;
|
||||
background: linear-gradient(180deg, #f5ebdc 0%, #efe1cc 100%);
|
||||
color: #b67c31;
|
||||
font-size: 28rpx;
|
||||
font-weight: 700;
|
||||
line-height: 60rpx;
|
||||
text-align: center;
|
||||
box-shadow: inset 0 -8rpx 16rpx rgba(189, 150, 95, 0.08);
|
||||
}
|
||||
|
||||
.feature-card__emoji-box {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 72rpx;
|
||||
height: 72rpx;
|
||||
border-radius: 20rpx;
|
||||
background: linear-gradient(180deg, #f7efe3 0%, #efe0ca 100%);
|
||||
box-shadow: inset 0 -8rpx 16rpx rgba(189, 150, 95, 0.06);
|
||||
}
|
||||
|
||||
.feature-card__emoji {
|
||||
font-size: 36rpx;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.feature-card__icon + .feature-card__title {
|
||||
margin-top: 12rpx;
|
||||
}
|
||||
|
||||
.feature-card__title {
|
||||
font-family: 'STSong', 'Songti SC', serif;
|
||||
font-size: 22rpx;
|
||||
font-weight: 700;
|
||||
line-height: 1.35;
|
||||
color: #38261a;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.feature-card__title--wellness {
|
||||
margin-top: 16rpx;
|
||||
font-size: 24rpx;
|
||||
color: #64748b;
|
||||
}
|
||||
|
||||
.session-card__value {
|
||||
flex: 1;
|
||||
text-align: right;
|
||||
font-size: 24rpx;
|
||||
color: #0f172a;
|
||||
.feature-card--classic {
|
||||
justify-content: flex-start;
|
||||
padding-top: 18rpx;
|
||||
padding-bottom: 14rpx;
|
||||
}
|
||||
|
||||
.session-card__value--mono {
|
||||
font-family: 'Cascadia Code', 'Courier New', monospace;
|
||||
word-break: break-all;
|
||||
.feature-card__book {
|
||||
position: relative;
|
||||
width: 76rpx;
|
||||
height: 112rpx;
|
||||
border-radius: 8rpx;
|
||||
background:
|
||||
linear-gradient(90deg, rgba(138, 93, 48, 0.44) 0, rgba(138, 93, 48, 0.44) 10rpx, transparent 10rpx, transparent 100%),
|
||||
linear-gradient(180deg, #cfaa75 0%, #c79d67 100%);
|
||||
box-shadow: 0 10rpx 18rpx rgba(173, 128, 70, 0.12);
|
||||
}
|
||||
|
||||
.entry-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 24rpx;
|
||||
.feature-card__book-char {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 10rpx;
|
||||
right: 0;
|
||||
transform: translateY(-50%);
|
||||
color: #fff7eb;
|
||||
font-family: 'STSong', 'Songti SC', serif;
|
||||
font-size: 28rpx;
|
||||
font-weight: 700;
|
||||
line-height: 1;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.meta-row--top {
|
||||
align-items: flex-start;
|
||||
.feature-card__title--classic {
|
||||
margin-top: 14rpx;
|
||||
min-height: 56rpx;
|
||||
padding: 0 4rpx;
|
||||
font-size: 20rpx;
|
||||
line-height: 1.45;
|
||||
}
|
||||
|
||||
BIN
pages/home/tab-home-active.png
Normal file
BIN
pages/home/tab-home-active.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.5 KiB |
BIN
pages/home/tab-home.png
Normal file
BIN
pages/home/tab-home.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.6 KiB |
Reference in New Issue
Block a user