feat(miniapp): 首页 4×2 入口宫格图标改版为参考图 2 的渐变砖 + 白色图形

参考图 2 的视觉语言是「高饱和渐变圆角砖 + 白色描画图形 + 主标题/副标题双层文字」,
原实现是「浅色底砖 + 彩色线性 PNG + 单行标题」,两者差异较大,本轮按参考图重做。

- app.wxss:新增 8 个 --gradient-entry-* 渐变 token 与 --mini-entry-shadow。
  白图形的判据取**非文本图形 3:1**(WCAG 1.4.11);渐变是斜向的、图形又跨在两色之间,
  故以「较亮端」为准逐色实算(3.00~3.02:1,较暗端 3.54~4.08:1),实算值写在 token 注释里。
- index.wxss:.entry-icon 由 72rpx 浅色砖改为 96rpx 渐变砖(radius 28rpx + 落影);
  图形改用 data-uri SVG 背景层(几何图形统一 24×24 viewBox),砖面走 --gradient-entry-*;
  新增 .entry-sub(12px muted 副标题);删除已无用的 .entry-icon-image。
  小屏 @media(≤340px) 同步收紧,副标题不降到 micro —— micro 在本项目是「仅角标/装饰」档位,
  这行字承载语义,不属于装饰。
- index.wxml:宫格项去掉 <image>,图标改为纯 CSS 砖;补 aria-label 承接图形语义。
- index.ts:tone 名与色相语义对齐(rose/orange/violet/blue/purple/pink/green/amber),
  并补 subtitle;entry 不再持有 iconAsset(图标不再是图片资源)。
- preview-miniapp.mjs:首页 mock 同步 tone/subtitle,预览才能看到真实砖面与副标题。

渲染态实测(无头浏览器 + CDP,非真机渲染):
- 8 个 .entry-item 均渲染出 label + subtitle;.entry-icon 计算样式 48×48px / radius 14px /
  background-image 含 svg 且为两层(图形 26px + 渐变铺满);label 14px/600;sub 12px #7D839B。
- 证据截图:artifacts/ui-redesign/miniapp/home-entries-page.png 与 home-entries-grid-zoom.png。

门禁:UI 契约 23/23;语种审计 0 命中;tsc --noEmit 通过;wcc/wcsc 真编译 88 WXSS + 86 WXML / 0 失败。

未改(需产品确认):第 8 项业务名仍是「善缘服务站」(参考图 2 写作「万善缘地」),
副标题自拟为「就在身边」;渐变整体比参考图略深,以保证白图形对比度达标。
This commit is contained in:
WorkBuddy
2026-09-23 15:22:23 +08:00
parent e740cbf403
commit f4e00b4d95
5 changed files with 112 additions and 42 deletions
+16
View File
@@ -66,6 +66,22 @@ page {
--gradient-night: linear-gradient(160deg, #172A72 0%, #25104F 100%); --gradient-night: linear-gradient(160deg, #172A72 0%, #25104F 100%);
--gradient-night-soft: linear-gradient(160deg, #3445A1 0%, #172A72 100%); --gradient-night-soft: linear-gradient(160deg, #3445A1 0%, #172A72 100%);
/* ---- 首页 4×2 入口宫格图标渐变(参考图 2:高饱和圆角砖 + 白色描画图标) ----
白图标的对比度判据是**非文本图形 3:1**(WCAG 1.4.11)。渐变是斜向的、图标又跨在
两色之间,所以**较亮的一端也必须达标** —— 下表注释给的是 0% 处实算值,100% 更暗只会更高。
色相按业务语义固定(不随 tone 名漂移):找对象/婚前辅导=玫瑰粉系、公益红娘/服务站=暖橙系、
公益活动=紫罗兰、婚恋咨询=蓝、婚恋课堂=紫、婚恋反诈=绿。 */
--gradient-entry-rose: linear-gradient(135deg, #F56287 0%, #F34671 100%); /* 3.01:1 / 3.54:1 */
--gradient-entry-orange: linear-gradient(135deg, #F66A06 0%, #D95E06 100%); /* 3.01:1 / 3.78:1 */
--gradient-entry-violet: linear-gradient(135deg, #A380F5 0%, #8F64F2 100%); /* 3.02:1 / 3.98:1 */
--gradient-entry-blue: linear-gradient(135deg, #5195F6 0%, #3484F4 100%); /* 3.01:1 / 3.65:1 */
--gradient-entry-purple: linear-gradient(135deg, #B27BF0 0%, #A260ED 100%); /* 3.01:1 / 3.87:1 */
--gradient-entry-pink: linear-gradient(135deg, #F2619E 0%, #F0458C 100%); /* 3.01:1 / 3.54:1 */
--gradient-entry-green: linear-gradient(135deg, #18A979 0%, #148F66 100%); /* 3.00:1 / 4.08:1 */
--gradient-entry-amber: linear-gradient(135deg, #E9740C 0%, #CC650B 100%); /* 3.01:1 / 3.86:1 */
/* 图标砖落影:比 --mini-shadow 更小,避免 4 列宫格里相邻砖块的投影互相压边 */
--mini-entry-shadow: 0 8rpx 18rpx rgba(28, 30, 88, 0.18);
/* ---- 夜间氛围层(v2 新增;参考图有光晕与星点,此前完全没有) ---- */ /* ---- 夜间氛围层(v2 新增;参考图有光晕与星点,此前完全没有) ---- */
--mini-glow-coral: rgba(255, 79, 145, 0.40); --mini-glow-coral: rgba(255, 79, 145, 0.40);
--mini-glow-indigo: rgba(94, 124, 255, 0.32); --mini-glow-indigo: rgba(94, 124, 255, 0.32);
+12 -8
View File
@@ -7,15 +7,19 @@ const api = require('../../utils/api')
// 顶部安全区:实测右上角胶囊按钮矩形,避免品牌栏「消息」入口被胶囊压住(见 utils/nav-metrics.js) // 顶部安全区:实测右上角胶囊按钮矩形,避免品牌栏「消息」入口被胶囊压住(见 utils/nav-metrics.js)
const { navSafeData } = require('../../utils/nav-metrics') const { navSafeData } = require('../../utils/nav-metrics')
// 4×2 宫格的视觉映射(tone → index.wxss 的 .tone-* 渐变砖;subtitle → 主标题下的说明行)。
// 图标不再走图片资源:改成「CSS 渐变砖 + 白色矢量图形」(见 index.wxss .tone-* 的 data-uri 背景层),
// 所以这里没有 iconAsset。tone 名与色相语义一一对应(app.wxss --gradient-entry-* 注释里有实算对比度):
// 3.01:1 是「白图形 vs 渐变较亮端」的实算值,7 个色相均 ≥3:1(WCAG 1.4.11 非文本图形)。
const ENTRY_VISUALS = { const ENTRY_VISUALS = {
find_object: { tone: 'rose', iconAsset: '/assets/icons/home/find-object.png' }, find_object: { tone: 'rose', subtitle: '真实邂逅' },
matchmaker: { tone: 'purple', iconAsset: '/assets/icons/home/matchmaker.png' }, matchmaker: { tone: 'orange', subtitle: '官方牵线' },
activities: { tone: 'blue', iconAsset: '/assets/icons/home/activity.png' }, activities: { tone: 'violet', subtitle: '线下联谊' },
counseling: { tone: 'pink', iconAsset: '/assets/icons/home/counseling.png' }, counseling: { tone: 'blue', subtitle: '专业指导' },
classroom: { tone: 'amber', iconAsset: '/assets/icons/home/classroom.png' }, classroom: { tone: 'purple', subtitle: '提升自我' },
premarital: { tone: 'indigo', iconAsset: '/assets/icons/home/premarital.png' }, premarital: { tone: 'pink', subtitle: '幸福起航' },
anti_fraud: { tone: 'red', iconAsset: '/assets/icons/home/anti-fraud.png' }, anti_fraud: { tone: 'green', subtitle: '守护真爱' },
service_station: { tone: 'green', iconAsset: '/assets/icons/home/service-station.png' }, service_station: { tone: 'amber', subtitle: '就在身边' },
} }
const QUICK_ENTRIES = [ const QUICK_ENTRIES = [
+6 -1
View File
@@ -55,8 +55,13 @@
<view class="entries-card"> <view class="entries-card">
<view class="entries-grid"> <view class="entries-grid">
<view wx:for="{{quickEntries}}" wx:key="code" class="entry-item {{!item.enabled ? 'disabled' : ''}}" bindtap="onEntryTap" data-entry="{{item}}"> <view wx:for="{{quickEntries}}" wx:key="code" class="entry-item {{!item.enabled ? 'disabled' : ''}}" bindtap="onEntryTap" data-entry="{{item}}">
<view class="entry-icon tone-{{item.tone}}"><image class="entry-icon-image" src="{{item.iconAsset}}" mode="aspectFit" /></view> <!-- 图标改为「高饱和渐变圆角砖 + 白色矢量描画」(参考图 2)。
砖面与图形都由 CSS 提供:渐变走 --gradient-entry-*(app.wxss 事实源),
白色图形走 data-uri SVG 背景层,因此不再需要 <image>。
aria-label 承接原 <image> 缺失的可读名称(图形现在是纯装饰层)。 -->
<view class="entry-icon tone-{{item.tone}}" aria-role="img" aria-label="{{item.label}}"></view>
<text class="entry-label">{{item.label}}</text> <text class="entry-label">{{item.label}}</text>
<text class="entry-sub">{{item.subtitle}}</text>
</view> </view>
</view> </view>
</view> </view>
+67 -25
View File
@@ -289,7 +289,7 @@
.entry-item { .entry-item {
width: 25%; width: 25%;
box-sizing: border-box; box-sizing: border-box;
min-height: 116rpx; min-height: 176rpx;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
@@ -298,34 +298,73 @@
.entry-item.disabled { .entry-item.disabled {
opacity: 0.4; opacity: 0.4;
} }
/* 图标砖(参考图 2):96rpx 圆角方 + 高饱和渐变面 + 白色描画图形。
两层背景:上层 52rpx = 白色图形(data-uri SVG),下层 100% = 渐变砖面。
background-color 是**兜底**:万一 SVG 背景层被解析器丢弃,砖面仍在(只是没有图形),
不会退化成「白底白图标」这种彻底不可见的形态。 */
.entry-icon { .entry-icon {
width: 72rpx; width: 96rpx;
height: 72rpx; height: 96rpx;
display: flex; border-radius: 28rpx;
align-items: center; background-repeat: no-repeat, no-repeat;
justify-content: center; background-position: center, center;
border-radius: var(--radius-md); background-size: 52rpx 52rpx, 100% 100%;
overflow: hidden; box-shadow: var(--mini-entry-shadow);
}
.entry-icon-image {
width: 48rpx;
height: 48rpx;
} }
.entry-label { .entry-label {
margin-top: var(--spacing-1); margin-top: var(--spacing-1);
font-size: var(--font-size-sm); font-size: var(--font-size-md);
font-weight: var(--font-weight-medium); font-weight: var(--font-weight-semibold);
color: var(--color-text-strong); color: var(--color-text-strong);
letter-spacing: var(--letter-spacing-tight);
}
/* 副标题:承接参考图「主标题 + 一行说明」的双层信息结构。
字号用 --font-size-xs(12px,本项目的元信息下限),不再往下探 micro ——
micro 是「仅角标/装饰、禁用于正文」的档位,这行字承载语义,不属于装饰。 */
.entry-sub {
margin-top: 2rpx;
font-size: var(--font-size-xs);
font-weight: var(--font-weight-regular);
color: var(--mini-muted);
line-height: 1.3;
} }
.tone-rose { background: var(--color-primary-light); } /* ---- tone → 渐变砖面 + 白色图形 ----------------------------------------
.tone-purple { background: var(--color-accent-purple-light); } 色相语义与实算对比度见 app.wxss 的 --gradient-entry-* 注释块;
.tone-blue { background: var(--color-info-light); } 本处只负责「把哪个图形放到哪种砖上」,颜色事实源仍在 app.wxss。
.tone-pink { background: var(--color-primary-light); } 图形均为 24×24 viewBox 白色矢量,随 background-size 等比缩放到 52rpx。 */
.tone-amber { background: var(--color-warning-light); } .tone-rose {
.tone-indigo { background: var(--color-info-light); } background-color: #F34671;
.tone-red { background: var(--color-danger-light); } background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23fff' d='M12 21.2l-1.4-1.3C5.5 15.3 2.2 12.3 2.2 8.6 2.2 5.6 4.6 3.2 7.6 3.2c1.7 0 3.3.8 4.4 2 1.1-1.2 2.7-2 4.4-2 3 0 5.4 2.4 5.4 5.4 0 3.7-3.3 6.7-8.4 11.3z'/%3E%3C/svg%3E"), var(--gradient-entry-rose);
.tone-green { background: var(--color-success-light); } }
.tone-orange {
background-color: #D95E06;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='%23fff'%3E%3Ccircle cx='9' cy='7.6' r='3.4'/%3E%3Ccircle cx='17.2' cy='9.8' r='2.7'/%3E%3Crect x='2.4' y='15.2' width='13.2' height='6.4' rx='3.2'/%3E%3Crect x='13.8' y='16.4' width='8.6' height='5.2' rx='2.6'/%3E%3C/g%3E%3C/svg%3E"), var(--gradient-entry-orange);
}
.tone-violet {
background-color: #8F64F2;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='none' stroke='%23fff' stroke-width='1.8'%3E%3Crect x='3.2' y='5.4' width='17.6' height='15.4' rx='3.2'/%3E%3C/g%3E%3Cg fill='%23fff'%3E%3Crect x='7.6' y='2.6' width='2.1' height='4.3' rx='1.05'/%3E%3Crect x='14.3' y='2.6' width='2.1' height='4.3' rx='1.05'/%3E%3Cpath d='M12.00 10.65L12.74 12.58L14.81 12.69L13.20 13.99L13.73 15.99L12.00 14.86L10.27 15.99L10.80 13.99L9.19 12.69L11.26 12.58Z'/%3E%3C/g%3E%3C/svg%3E"), var(--gradient-entry-violet);
}
.tone-blue {
background-color: #3484F4;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='none' stroke='%23fff' stroke-width='1.7' stroke-linejoin='round'%3E%3Cpath d='M3.7 7.1a3.4 3.4 0 0 1 3.4-3.4h6.6a3.4 3.4 0 0 1 3.4 3.4v3.6a3.4 3.4 0 0 1-3.4 3.4H9.3l-4 3.4a.8.8 0 0 1-1.6-.5z'/%3E%3C/g%3E%3Cg fill='none' stroke='%23fff' stroke-width='1.6'%3E%3Cpath d='M18.1 9.4h.4a2.5 2.5 0 0 1 2.5 2.5v2.3a2.5 2.5 0 0 1-2.5 2.5h-.4v2.1l-2.5-2.1h-2a2.5 2.5 0 0 1-2.5-2.5'/%3E%3C/g%3E%3C/svg%3E"), var(--gradient-entry-blue);
}
.tone-purple {
background-color: #A260ED;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='%23fff'%3E%3Cpath d='M11.3 7.4C9.6 5.9 7.2 5.2 4.6 5.2H2.8v12.9h1.8c2.6 0 5 .7 6.7 2.2z'/%3E%3Cpath d='M12.7 7.4c1.7-1.5 4.1-2.2 6.7-2.2h1.8v12.9h-1.8c-2.6 0-5 .7-6.7 2.2z'/%3E%3C/g%3E%3C/svg%3E"), var(--gradient-entry-purple);
}
.tone-pink {
background-color: #F0458C;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='%23fff'%3E%3Cpath d='M12 13.6l-1.05-1C7.2 9.3 5 7.2 5 5 5 3.2 6.5 1.8 8.3 1.8c1.1 0 2.1.5 2.7 1.4.6-.9 1.6-1.4 2.7-1.4 1.8 0 3.3 1.4 3.3 3.2 0 2.2-2.2 4.3-5.8 7.7z'/%3E%3Crect x='3.4' y='15.6' width='10' height='3.6' rx='1.8' transform='rotate(18 8.4 17.4)'/%3E%3Crect x='10.6' y='15.6' width='10' height='3.6' rx='1.8' transform='rotate(-18 15.6 17.4)'/%3E%3C/g%3E%3C/svg%3E"), var(--gradient-entry-pink);
}
.tone-green {
background-color: #148F66;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='none' stroke='%23fff' stroke-width='1.8' stroke-linejoin='round'%3E%3Cpath d='M12 2.6l7.4 2.8v6.2c0 4.6-3.1 8.7-7.4 9.8-4.3-1.1-7.4-5.2-7.4-9.8V5.4z'/%3E%3C/g%3E%3Cpath d='M8.4 12.2l2.5 2.5 4.7-5' fill='none' stroke='%23fff' stroke-width='2.1' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E"), var(--gradient-entry-green);
}
.tone-amber {
background-color: #CC650B;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23fff' d='M12 3.1l9.2 7.5h-2.3v9.4h-4.3v-5.7H9.4v5.7H5.1v-9.4H2.8z'/%3E%3C/svg%3E"), var(--gradient-entry-amber);
}
/* ============================== 区块容器 ============================== */ /* ============================== 区块容器 ============================== */
@@ -674,11 +713,14 @@
@media (max-width: 340px) { @media (max-width: 340px) {
.entry-label { .entry-label {
font-size: var(--font-size-micro); font-size: var(--font-size-xs);
} }
/* 图标砖与副标题按同一比例收紧。副标题不再往下缩到 micro:
340px 机型下单元格约 72px 宽,4 字副标题 12px 仍放得下,没必要牺牲可读性。 */
.entry-icon { .entry-icon {
width: 64rpx; width: 80rpx;
height: 64rpx; height: 80rpx;
background-size: 44rpx 44rpx, 100% 100%;
} }
.banner-title { .banner-title {
font-size: var(--font-size-xl); font-size: var(--font-size-xl);
+11 -8
View File
@@ -51,15 +51,18 @@ const MOCK = {
], ],
banners: [{ id: 'b1', title: '在丹阳,遇见认真的彼此', subtitle: '公益 · 本地 · 真实 · 安全' }], banners: [{ id: 'b1', title: '在丹阳,遇见认真的彼此', subtitle: '公益 · 本地 · 真实 · 安全' }],
currentBannerIndex: 0, currentBannerIndex: 0,
// 与 pages/index/index.ts 的 ENTRY_VISUALS 保持一致(tone + subtitle)。
// 图标已改为 CSS 渐变砖 + data-uri 白色图形,故此处不再有 iconAsset ——
// 预览要看到的是真实砖面与副标题,而不是一张假的图片路径。
quickEntries: [ quickEntries: [
{ code: 'find_object', label: '找对象', enabled: true, tone: 'rose', iconAsset: '/assets/icons/home/find-object.png' }, { code: 'find_object', label: '找对象', enabled: true, tone: 'rose', subtitle: '真实邂逅' },
{ code: 'matchmaker', label: '公益红娘', enabled: true, tone: 'purple', iconAsset: '/assets/icons/home/matchmaker.png' }, { code: 'matchmaker', label: '公益红娘', enabled: true, tone: 'orange', subtitle: '官方牵线' },
{ code: 'activities', label: '公益活动', enabled: true, tone: 'blue', iconAsset: '/assets/icons/home/activity.png' }, { code: 'activities', label: '公益活动', enabled: true, tone: 'violet', subtitle: '线下联谊' },
{ code: 'counseling', label: '婚恋咨询', enabled: true, tone: 'pink', iconAsset: '/assets/icons/home/counseling.png' }, { code: 'counseling', label: '婚恋咨询', enabled: true, tone: 'blue', subtitle: '专业指导' },
{ code: 'classroom', label: '婚恋课堂', enabled: true, tone: 'amber', iconAsset: '/assets/icons/home/classroom.png' }, { code: 'classroom', label: '婚恋课堂', enabled: true, tone: 'purple', subtitle: '提升自我' },
{ code: 'premarital', label: '婚前辅导', enabled: true, tone: 'indigo', iconAsset: '/assets/icons/home/premarital.png' }, { code: 'premarital', label: '婚前辅导', enabled: true, tone: 'pink', subtitle: '幸福起航' },
{ code: 'anti_fraud', label: '婚恋反诈', enabled: true, tone: 'red', iconAsset: '/assets/icons/home/anti-fraud.png' }, { code: 'anti_fraud', label: '婚恋反诈', enabled: true, tone: 'green', subtitle: '守护真爱' },
{ code: 'service_station', label: '善缘服务站', enabled: true, tone: 'green', iconAsset: '/assets/icons/home/service-station.png' }, { code: 'service_station', label: '善缘服务站', enabled: true, tone: 'amber', subtitle: '就在身边' },
], ],
recommendations: [ recommendations: [
{ userId: 'u1', displayName: '王女士', age: 28, heightCm: 163, regionName: '丹阳', educationCode: '本科', occupationCode: '教育', verified: true, reviewed: true, recommendationReasons: ['同城', '年龄相近', '兴趣重合'] }, { userId: 'u1', displayName: '王女士', age: 28, heightCm: 163, regionName: '丹阳', educationCode: '本科', occupationCode: '教育', verified: true, reviewed: true, recommendationReasons: ['同城', '年龄相近', '兴趣重合'] },