diff --git a/miniapp/assets/brand/home-hero-v2.jpg b/miniapp/assets/brand/home-hero-v2.jpg new file mode 100644 index 0000000..8f46da6 Binary files /dev/null and b/miniapp/assets/brand/home-hero-v2.jpg differ diff --git a/miniapp/assets/icons/home/activity.png b/miniapp/assets/icons/home/activity.png new file mode 100644 index 0000000..2ba1e5f Binary files /dev/null and b/miniapp/assets/icons/home/activity.png differ diff --git a/miniapp/assets/icons/home/anti-fraud.png b/miniapp/assets/icons/home/anti-fraud.png new file mode 100644 index 0000000..71ca826 Binary files /dev/null and b/miniapp/assets/icons/home/anti-fraud.png differ diff --git a/miniapp/assets/icons/home/classroom.png b/miniapp/assets/icons/home/classroom.png new file mode 100644 index 0000000..4a45a06 Binary files /dev/null and b/miniapp/assets/icons/home/classroom.png differ diff --git a/miniapp/assets/icons/home/counseling.png b/miniapp/assets/icons/home/counseling.png new file mode 100644 index 0000000..f0a910f Binary files /dev/null and b/miniapp/assets/icons/home/counseling.png differ diff --git a/miniapp/assets/icons/home/find-object.png b/miniapp/assets/icons/home/find-object.png new file mode 100644 index 0000000..069b964 Binary files /dev/null and b/miniapp/assets/icons/home/find-object.png differ diff --git a/miniapp/assets/icons/home/matchmaker.png b/miniapp/assets/icons/home/matchmaker.png new file mode 100644 index 0000000..fb59f0c Binary files /dev/null and b/miniapp/assets/icons/home/matchmaker.png differ diff --git a/miniapp/assets/icons/home/premarital.png b/miniapp/assets/icons/home/premarital.png new file mode 100644 index 0000000..444a5cb Binary files /dev/null and b/miniapp/assets/icons/home/premarital.png differ diff --git a/miniapp/assets/icons/home/service-station.png b/miniapp/assets/icons/home/service-station.png new file mode 100644 index 0000000..556e0bd Binary files /dev/null and b/miniapp/assets/icons/home/service-station.png differ diff --git a/miniapp/assets/icons/ui/back.png b/miniapp/assets/icons/ui/back.png new file mode 100644 index 0000000..6e36f7f Binary files /dev/null and b/miniapp/assets/icons/ui/back.png differ diff --git a/miniapp/assets/icons/ui/chevron-right.png b/miniapp/assets/icons/ui/chevron-right.png new file mode 100644 index 0000000..6609ac4 Binary files /dev/null and b/miniapp/assets/icons/ui/chevron-right.png differ diff --git a/miniapp/assets/icons/ui/empty.png b/miniapp/assets/icons/ui/empty.png new file mode 100644 index 0000000..eb8252b Binary files /dev/null and b/miniapp/assets/icons/ui/empty.png differ diff --git a/miniapp/assets/icons/ui/loading.png b/miniapp/assets/icons/ui/loading.png new file mode 100644 index 0000000..7b5bb58 Binary files /dev/null and b/miniapp/assets/icons/ui/loading.png differ diff --git a/miniapp/assets/icons/ui/search.png b/miniapp/assets/icons/ui/search.png new file mode 100644 index 0000000..9d0fda2 Binary files /dev/null and b/miniapp/assets/icons/ui/search.png differ diff --git a/miniapp/assets/icons/ui/warning.png b/miniapp/assets/icons/ui/warning.png new file mode 100644 index 0000000..bc9f79e Binary files /dev/null and b/miniapp/assets/icons/ui/warning.png differ diff --git a/miniapp/assets/service/anti-fraud-hero.jpg b/miniapp/assets/service/anti-fraud-hero.jpg new file mode 100644 index 0000000..43be2b0 Binary files /dev/null and b/miniapp/assets/service/anti-fraud-hero.jpg differ diff --git a/miniapp/assets/service/counseling-hero.jpg b/miniapp/assets/service/counseling-hero.jpg new file mode 100644 index 0000000..7f91c15 Binary files /dev/null and b/miniapp/assets/service/counseling-hero.jpg differ diff --git a/miniapp/assets/service/matchmaker-hero.jpg b/miniapp/assets/service/matchmaker-hero.jpg new file mode 100644 index 0000000..1e02ca6 Binary files /dev/null and b/miniapp/assets/service/matchmaker-hero.jpg differ diff --git a/miniapp/assets/service/premarital-hero.jpg b/miniapp/assets/service/premarital-hero.jpg new file mode 100644 index 0000000..51b4f12 Binary files /dev/null and b/miniapp/assets/service/premarital-hero.jpg differ diff --git a/miniapp/assets/service/station-hero.jpg b/miniapp/assets/service/station-hero.jpg new file mode 100644 index 0000000..2052ea8 Binary files /dev/null and b/miniapp/assets/service/station-hero.jpg differ diff --git a/miniapp/components/empty/index.wxml b/miniapp/components/empty/index.wxml index 76c2185..ab2db2d 100644 --- a/miniapp/components/empty/index.wxml +++ b/miniapp/components/empty/index.wxml @@ -1,6 +1,6 @@ - + {{title}} {{description}} diff --git a/miniapp/components/empty/index.wxss b/miniapp/components/empty/index.wxss index e646354..0b14330 100644 --- a/miniapp/components/empty/index.wxss +++ b/miniapp/components/empty/index.wxss @@ -16,29 +16,9 @@ margin-bottom: var(--spacing-4); } .ui-empty__icon { - width: 60rpx; - height: 60rpx; - background: var(--color-text-disabled); - opacity: 0.5; - border-radius: 50%; -} -.ui-empty__illustration--search .ui-empty__icon { - border-radius: 50% 50% 50% 0; - transform: rotate(-45deg); -} -.ui-empty__illustration--heart .ui-empty__icon { - clip-path: polygon(50% 100%, 0 38%, 18% 18%, 50% 38%, 82% 18%, 100% 38%); - border-radius: 0; -} -.ui-empty__illustration--activity .ui-empty__icon { - border-radius: var(--radius-sm); - width: 80rpx; - height: 80rpx; -} -.ui-empty__illustration--message .ui-empty__icon { - border-radius: var(--radius-md); - width: 80rpx; - height: 60rpx; + width: 72rpx; + height: 72rpx; + opacity: 0.72; } .ui-empty__title { font-size: var(--font-size-lg); diff --git a/miniapp/components/error-state/index.js b/miniapp/components/error-state/index.js index 67e392f..e2029f1 100644 --- a/miniapp/components/error-state/index.js +++ b/miniapp/components/error-state/index.js @@ -1 +1,11 @@ -Component({properties:{title:{type:String,value:'加载失败'},description:{type:String,value:'请稍后重试'}},methods:{onRetry(){this.triggerEvent('retry')}}}) \ No newline at end of file +Component({ + properties: { + title: { type: String, value: '加载失败' }, + description: { type: String, value: '请稍后重试' }, + }, + methods: { + onRetry() { + this.triggerEvent('retry') + }, + }, +}) diff --git a/miniapp/components/error-state/index.wxml b/miniapp/components/error-state/index.wxml index d2a19c7..d4fd6b8 100644 --- a/miniapp/components/error-state/index.wxml +++ b/miniapp/components/error-state/index.wxml @@ -1 +1,6 @@ -!{{title}}{{description}} \ No newline at end of file + + + {{title}} + {{description}} + + diff --git a/miniapp/components/error-state/index.wxss b/miniapp/components/error-state/index.wxss index 86253f2..7890f1d 100644 --- a/miniapp/components/error-state/index.wxss +++ b/miniapp/components/error-state/index.wxss @@ -1 +1,45 @@ -.error-state{padding:64rpx 32rpx;text-align:center;background:var(--color-bg-card);border-radius:var(--radius-lg)}.error-icon{width:72rpx;height:72rpx;margin:0 auto 20rpx;display:flex;align-items:center;justify-content:center;border-radius:50%;background:var(--color-danger-light);color:var(--color-danger);font-weight:700}.error-title,.error-desc{display:block}.error-title{font-size:30rpx;font-weight:600}.error-desc{margin-top:8rpx;font-size:24rpx;color:var(--color-text-tertiary)}.retry-btn{width:220rpx;height:80rpx;line-height:80rpx;margin-top:24rpx;border:0;border-radius:var(--radius-full);background:var(--color-primary);color:var(--color-text-inverse);font-size:26rpx}.retry-btn::after{border:0} \ No newline at end of file +.error-state { + padding: 64rpx 32rpx; + text-align: center; + background: var(--color-bg-card); + border-radius: var(--radius-lg); +} + +.error-icon { + display: block; + width: 72rpx; + height: 72rpx; + margin: 0 auto 20rpx; +} + +.error-title, +.error-desc { + display: block; +} + +.error-title { + font-size: 30rpx; + font-weight: 600; +} + +.error-desc { + margin-top: 8rpx; + color: var(--color-text-tertiary); + font-size: 24rpx; +} + +.retry-btn { + width: 220rpx; + height: 80rpx; + margin-top: 24rpx; + border: 0; + border-radius: var(--radius-full); + background: var(--color-primary); + color: var(--color-text-inverse); + font-size: 26rpx; + line-height: 80rpx; +} + +.retry-btn::after { + border: 0; +} diff --git a/miniapp/components/loading/index.wxml b/miniapp/components/loading/index.wxml index 3d555df..c537383 100644 --- a/miniapp/components/loading/index.wxml +++ b/miniapp/components/loading/index.wxml @@ -1,7 +1,7 @@ - + {{text}} diff --git a/miniapp/components/loading/index.wxss b/miniapp/components/loading/index.wxss index f227152..ff388d1 100644 --- a/miniapp/components/loading/index.wxss +++ b/miniapp/components/loading/index.wxss @@ -16,12 +16,9 @@ align-items: center; justify-content: center; } -.ui-loading__spinner-ring { +.ui-loading__spinner-icon { width: 48rpx; height: 48rpx; - border-radius: 50%; - border: 4rpx solid var(--color-divider); - border-top-color: var(--color-primary); animation: ui-loading-spin 0.8s linear infinite; } @keyframes ui-loading-spin { diff --git a/miniapp/components/nav-bar/index.wxml b/miniapp/components/nav-bar/index.wxml index 31432ec..88d9e53 100644 --- a/miniapp/components/nav-bar/index.wxml +++ b/miniapp/components/nav-bar/index.wxml @@ -1,7 +1,7 @@ - + {{title}} diff --git a/miniapp/components/nav-bar/index.wxss b/miniapp/components/nav-bar/index.wxss index 5ff9e35..662086e 100644 --- a/miniapp/components/nav-bar/index.wxss +++ b/miniapp/components/nav-bar/index.wxss @@ -28,12 +28,9 @@ justify-content: center; flex-shrink: 0; } -.ui-nav__back-arrow { - width: 20rpx; - height: 20rpx; - border-left: 4rpx solid var(--color-text-primary); - border-bottom: 4rpx solid var(--color-text-primary); - transform: rotate(45deg); +.ui-nav__back-icon { + width: 36rpx; + height: 36rpx; } .ui-nav__title { flex: 1; diff --git a/miniapp/components/section-header/index.wxml b/miniapp/components/section-header/index.wxml index 1a9a3fa..6417b6e 100644 --- a/miniapp/components/section-header/index.wxml +++ b/miniapp/components/section-header/index.wxml @@ -5,6 +5,6 @@ {{action}} - › + diff --git a/miniapp/components/section-header/index.wxss b/miniapp/components/section-header/index.wxss index 524477b..5b02240 100644 --- a/miniapp/components/section-header/index.wxss +++ b/miniapp/components/section-header/index.wxss @@ -26,6 +26,6 @@ } .ui-section__arrow { margin-left: 4rpx; - font-size: var(--font-size-md); - line-height: 1; + width: 24rpx; + height: 24rpx; } diff --git a/miniapp/components/service-hero/index.js b/miniapp/components/service-hero/index.js new file mode 100644 index 0000000..13a5d8a --- /dev/null +++ b/miniapp/components/service-hero/index.js @@ -0,0 +1,10 @@ +Component({ + options: { addGlobalClass: true }, + properties: { + eyebrow: { type: String, value: '' }, + title: { type: String, value: '' }, + subtitle: { type: String, value: '' }, + imageSrc: { type: String, value: '' }, + tone: { type: String, value: 'rose' }, + }, +}) diff --git a/miniapp/components/service-hero/index.json b/miniapp/components/service-hero/index.json new file mode 100644 index 0000000..a89ef4d --- /dev/null +++ b/miniapp/components/service-hero/index.json @@ -0,0 +1,4 @@ +{ + "component": true, + "usingComponents": {} +} diff --git a/miniapp/components/service-hero/index.wxml b/miniapp/components/service-hero/index.wxml new file mode 100644 index 0000000..85e2313 --- /dev/null +++ b/miniapp/components/service-hero/index.wxml @@ -0,0 +1,9 @@ + + + + + {{eyebrow}} + {{title}} + {{subtitle}} + + diff --git a/miniapp/components/service-hero/index.wxss b/miniapp/components/service-hero/index.wxss new file mode 100644 index 0000000..e2d67e5 --- /dev/null +++ b/miniapp/components/service-hero/index.wxss @@ -0,0 +1,63 @@ +.service-hero { + position: relative; + height: 300rpx; + overflow: hidden; + border-radius: 0 0 32rpx 32rpx; + background: #fff4f7; +} + +.service-hero__image, +.service-hero__veil { + position: absolute; + inset: 0; + width: 100%; + height: 100%; +} + +.service-hero__veil { + background: linear-gradient(90deg, rgba(255, 250, 252, 0.98) 0%, rgba(255, 250, 252, 0.82) 38%, rgba(255, 250, 252, 0.08) 70%); +} + +.service-hero--night .service-hero__veil { + background: linear-gradient(90deg, rgba(18, 24, 83, 0.92) 0%, rgba(34, 31, 111, 0.64) 42%, rgba(34, 31, 111, 0.08) 72%); +} + +.service-hero__content { + position: relative; + z-index: 1; + display: flex; + flex-direction: column; + justify-content: center; + width: 54%; + height: 100%; + padding: 0 36rpx; + box-sizing: border-box; +} + +.service-hero__eyebrow { + margin-bottom: 10rpx; + color: var(--color-primary); + font-size: 22rpx; + font-weight: 600; + letter-spacing: 2rpx; +} + +.service-hero__title { + color: #24305e; + font-size: 40rpx; + font-weight: 700; + line-height: 1.28; +} + +.service-hero__subtitle { + margin-top: 14rpx; + color: #737c96; + font-size: 24rpx; + line-height: 1.55; +} + +.service-hero--night .service-hero__eyebrow, +.service-hero--night .service-hero__title, +.service-hero--night .service-hero__subtitle { + color: #ffffff; +} diff --git a/miniapp/pages/index/index.ts b/miniapp/pages/index/index.ts index 1e9a704..1e48055 100644 --- a/miniapp/pages/index/index.ts +++ b/miniapp/pages/index/index.ts @@ -6,14 +6,14 @@ const { authStore, appStore } = require('../../stores') const api = require('../../utils/api') const ENTRY_VISUALS = { - find_object: { tone: 'rose', iconAsset: '/assets/tabbar/discover-active.png' }, - matchmaker: { tone: 'purple', iconAsset: '/assets/brand/logo-mark.png' }, - activities: { tone: 'blue', iconAsset: '/assets/tabbar/activity-active.png' }, - counseling: { tone: 'pink', iconAsset: '/assets/tabbar/message-active.png' }, - classroom: { tone: 'amber', iconAsset: '/assets/covers/classroom-default.jpg' }, - premarital: { tone: 'indigo', iconAsset: '/assets/tabbar/home-active.png' }, - anti_fraud: { tone: 'red', iconAsset: '/assets/covers/anti-fraud-default.jpg' }, - service_station: { tone: 'green', iconAsset: '/assets/covers/station-default.jpg' }, + find_object: { tone: 'rose', iconAsset: '/assets/icons/home/find-object.png' }, + matchmaker: { tone: 'purple', iconAsset: '/assets/icons/home/matchmaker.png' }, + activities: { tone: 'blue', iconAsset: '/assets/icons/home/activity.png' }, + counseling: { tone: 'pink', iconAsset: '/assets/icons/home/counseling.png' }, + classroom: { tone: 'amber', iconAsset: '/assets/icons/home/classroom.png' }, + premarital: { tone: 'indigo', iconAsset: '/assets/icons/home/premarital.png' }, + anti_fraud: { tone: 'red', iconAsset: '/assets/icons/home/anti-fraud.png' }, + service_station: { tone: 'green', iconAsset: '/assets/icons/home/service-station.png' }, } const QUICK_ENTRIES = [ diff --git a/ui-tests/brand-assets.mjs b/ui-tests/brand-assets.mjs index 6956fc3..0219cb7 100644 --- a/ui-tests/brand-assets.mjs +++ b/ui-tests/brand-assets.mjs @@ -1,6 +1,7 @@ import assert from 'node:assert/strict' import { existsSync, readFileSync } from 'node:fs' import { resolve } from 'node:path' +import { createHash } from 'node:crypto' const root = resolve(import.meta.dirname, '..') const assets = [ @@ -16,10 +17,55 @@ const assets = [ 'miniapp/assets/covers/station-default.jpg', ] +const miniappHeroAssets = [ + 'miniapp/assets/brand/home-hero-v2.jpg', + 'miniapp/assets/service/matchmaker-hero.jpg', + 'miniapp/assets/service/counseling-hero.jpg', + 'miniapp/assets/service/premarital-hero.jpg', + 'miniapp/assets/service/anti-fraud-hero.jpg', + 'miniapp/assets/service/station-hero.jpg', +] + +const homeIconAssets = [ + 'find-object.png', + 'matchmaker.png', + 'activity.png', + 'counseling.png', + 'classroom.png', + 'premarital.png', + 'anti-fraud.png', + 'service-station.png', +].map((name) => `miniapp/assets/icons/home/${name}`) + +const uiIconAssets = [ + 'back.png', + 'chevron-right.png', + 'warning.png', + 'empty.png', + 'loading.png', + 'search.png', +].map((name) => `miniapp/assets/icons/ui/${name}`) + for (const file of assets) { const path = resolve(root, file) assert.ok(existsSync(path), `缺少品牌资产 ${file}`) assert.ok(readFileSync(path).length > 4096, `品牌资产为空或过小 ${file}`) } +for (const file of miniappHeroAssets) { + const path = resolve(root, file) + assert.ok(existsSync(path), `缺少小程序 Hero 素材 ${file}`) + assert.ok(readFileSync(path).length > 16 * 1024, `小程序 Hero 素材为空或过小 ${file}`) +} + +const homeIconHashes = new Set() +for (const file of [...homeIconAssets, ...uiIconAssets]) { + const path = resolve(root, file) + assert.ok(existsSync(path), `缺少小程序图标 ${file}`) + const bytes = readFileSync(path) + assert.ok(bytes.length > 256, `小程序图标为空或过小 ${file}`) + if (homeIconAssets.includes(file)) homeIconHashes.add(createHash('sha256').update(bytes).digest('hex')) +} +assert.equal(homeIconHashes.size, homeIconAssets.length, '首页 8 个入口不得复用同一图标') + console.log('Brand asset contracts passed')