feat: 排行榜虚拟领奖台 + 勋章对齐与尺寸统一
- 领奖台数据不足 3 名时显示虚拟空位(虚线轮廓+虚位以待) - 领奖台勋章与昵称对齐改为等高盒结构性修复(移除 margin 盲推) - 全 app 成就勋章图标尺寸统一为 30rpx(前三名/列表/设置页/记录页一致) - 勋章 SVG 按包围盒精确居中(utils/icons.js) - 设置页/记录页勋章展示配套调整
This commit is contained in:
@@ -65,6 +65,37 @@ Page({
|
||||
this.fetchRank()
|
||||
},
|
||||
|
||||
/**
|
||||
* totalDays → 最新解锁勋章(trainingDayBadges 按天数递增,取 days <= totalDays 最后一项)。
|
||||
* 返回 badge 定义(含 days/name/icon),无解锁或异常返回 null。
|
||||
* 云函数路径:item.totalDays 是云端算的(全榜通用,别人的行也能显示);
|
||||
* 本地兜底:用 storage 本地 totalDays 算自己那条。
|
||||
*/
|
||||
_badgeOf(totalDays) {
|
||||
try {
|
||||
const days = Math.max(0, Number(totalDays) || 0)
|
||||
const badges = config.trainingDayBadges || []
|
||||
let latest = null
|
||||
for (const b of badges) {
|
||||
if (days >= b.days) latest = b
|
||||
}
|
||||
return latest
|
||||
} catch (e) {
|
||||
return null
|
||||
}
|
||||
},
|
||||
|
||||
/** 点击勋章:toast 展示勋章名与解锁天数门槛 */
|
||||
onBadgeTap(e) {
|
||||
const badge = e.currentTarget.dataset
|
||||
if (!badge || !badge.name) return
|
||||
wx.showToast({
|
||||
title: badge.name + ' · 累计 ' + badge.days + ' 天解锁',
|
||||
icon: 'none',
|
||||
duration: 1800
|
||||
})
|
||||
},
|
||||
|
||||
fetchRank(cb, force) {
|
||||
// 序列号:快速切换周期时丢弃旧响应,避免旧 period 的数据覆盖新 period
|
||||
this._fetchSeq = (this._fetchSeq || 0) + 1
|
||||
@@ -131,6 +162,17 @@ Page({
|
||||
} else {
|
||||
base.subText = `${item.sessions}次`
|
||||
}
|
||||
// 勋章:云函数下发每个用户的 totalDays,映射最新解锁勋章(全榜可见)。
|
||||
// 浅底行用主题色版 iconFill;旧快照无 totalDays 时 badge 为 null,不渲染。
|
||||
// 注意:badgeIcon 必须赋图标 data URI(从 icons 映射查),不能赋字符串 key,
|
||||
// 否则 WXML src 会当成路径加载报 500。
|
||||
const badge = this._badgeOf(item.totalDays)
|
||||
if (badge) {
|
||||
const icons = this.data.icons || iconsMod.build()
|
||||
base.badgeIcon = icons[badge.icon + 'Fill']
|
||||
base.badgeName = badge.name
|
||||
base.badgeDays = badge.days
|
||||
}
|
||||
return base
|
||||
})
|
||||
const myEntry = result.myEntry ? (() => {
|
||||
@@ -147,6 +189,16 @@ Page({
|
||||
} else {
|
||||
base.subText = `${result.myEntry.sessions}次`
|
||||
}
|
||||
// my-bar 是主题渐变底,需要白版图标;badgeIcon(主题色)给 is-me 行用。
|
||||
// 同样必须赋 data URI,不能赋字符串 key。
|
||||
const badge = this._badgeOf(result.myEntry.totalDays)
|
||||
if (badge) {
|
||||
const icons = this.data.icons || iconsMod.build()
|
||||
base.badgeIcon = icons[badge.icon + 'Fill']
|
||||
base.badgeIconWhite = icons[badge.icon + 'White']
|
||||
base.badgeName = badge.name
|
||||
base.badgeDays = badge.days
|
||||
}
|
||||
return base
|
||||
})() : null
|
||||
const empty = list.length === 0 && !myEntry
|
||||
@@ -168,6 +220,17 @@ Page({
|
||||
const profile = storage.getProfile()
|
||||
const localName = profile.nickname || '我'
|
||||
|
||||
// 本地兜底勋章:从本地记录算去重训练日(与云函数 totalDays 口径一致),
|
||||
// 映射最新解锁勋章。云函数不可用时自己的行/my-bar 仍能显示勋章。
|
||||
// 注意:badgeIcon 必须是 data URI(从 icons 映射查),不能是字符串 key。
|
||||
const trainedDays = new Set()
|
||||
allRecords.forEach(r => { if (r && r.date) trainedDays.add(util.dateOnly(r.date)) })
|
||||
const localBadge = this._badgeOf(trainedDays.size)
|
||||
const _icons = this.data.icons || iconsMod.build()
|
||||
const localBadgeFields = localBadge
|
||||
? { badgeIcon: _icons[localBadge.icon + 'Fill'], badgeIconWhite: _icons[localBadge.icon + 'White'], badgeName: localBadge.name, badgeDays: localBadge.days }
|
||||
: {}
|
||||
|
||||
// 耐力榜本地兜底:取本地全部记录里单次最久 + 其日期
|
||||
if (period === 'endurance') {
|
||||
let bestDuration = 0
|
||||
@@ -181,7 +244,11 @@ Page({
|
||||
const entry = {
|
||||
rank: 1, openid: 'local', name: localName, nickname: profile.nickname || '',
|
||||
duration: bestDuration, durationText: util.formatDuration(bestDuration),
|
||||
bestDate, subText: this._formatBestDate(bestDate), subDate: date, subTime: time
|
||||
bestDate, subText: this._formatBestDate(bestDate), subDate: date, subTime: time,
|
||||
// 本地兜底也要 isMe:否则 is-me 行不渲染勋章、my-bar 条件(rank>length)又不满足,
|
||||
// 勋章在弱网/云函数故障时完全不可见
|
||||
isMe: true,
|
||||
...localBadgeFields
|
||||
}
|
||||
this.setData({ rankedList: [entry], myEntry: { ...entry, isMe: true }, loading: false, refreshing: false, empty: false })
|
||||
} else {
|
||||
@@ -206,7 +273,10 @@ Page({
|
||||
const entry = {
|
||||
rank: 1, openid: 'local', name: localName, nickname: profile.nickname || '',
|
||||
duration, durationText: util.formatDuration(duration), sessions,
|
||||
subText: `${sessions}次`
|
||||
subText: `${sessions}次`,
|
||||
// 同耐力榜:本地兜底 entry 必须带 isMe,否则勋章不渲染
|
||||
isMe: true,
|
||||
...localBadgeFields
|
||||
}
|
||||
this.setData({ rankedList: [entry], myEntry: { ...entry, isMe: true }, loading: false, refreshing: false, empty: false })
|
||||
} else {
|
||||
|
||||
@@ -44,38 +44,75 @@
|
||||
<!-- 耐力榜领奖台顶部文案:哲理注脚,点出"撑得越久不一定越好" -->
|
||||
<view class="podium-slogan" wx:if="{{activePeriod === 'endurance'}}">{{podiumSlogan}}</view>
|
||||
|
||||
<!-- Podium: top 3 (only when there are at least 3 entries) -->
|
||||
<view class="podium" wx:if="{{rankedList.length >= 3}}">
|
||||
<!-- Podium: top 3 (shown whenever there is at least 1 entry; empty slots render as virtual placeholders) -->
|
||||
<view class="podium" wx:if="{{rankedList.length >= 1}}">
|
||||
<!-- 2nd -->
|
||||
<view class="podium-slot podium-slot--second rank-item--enter" style="animation-delay: 60ms;">
|
||||
<view class="podium-avatar-wrap">
|
||||
<view class="avatar avatar--md {{rankedList[1].avatarUrl ? 'has-avatar' : ''}}"><image class="avatar__img" src="{{rankedList[1].avatarUrl || icons.peopleFill}}" mode="{{rankedList[1].avatarUrl ? 'aspectFill' : 'aspectFit'}}"></image></view>
|
||||
<view class="podium-medal podium-medal--silver">2</view>
|
||||
</view>
|
||||
<text class="podium-name">{{rankedList[1].name}}</text>
|
||||
<text class="podium-dur">{{rankedList[1].durationText}}</text>
|
||||
<view class="podium-base podium-base--second"><view class="podium-base__label {{activePeriod === 'endurance' ? 'is-two' : ''}}"><block wx:if="{{activePeriod === 'endurance'}}"><text class="podium-base__date">{{rankedList[1].subDate}}</text><text class="podium-base__time">{{rankedList[1].subTime}}</text></block><text wx:else>{{rankedList[1].subText}}</text></view></view>
|
||||
<block wx:if="{{rankedList[1]}}">
|
||||
<view class="podium-avatar-wrap">
|
||||
<view class="avatar avatar--md {{rankedList[1].avatarUrl ? 'has-avatar' : ''}}"><image class="avatar__img" src="{{rankedList[1].avatarUrl || icons.peopleFill}}" mode="{{rankedList[1].avatarUrl ? 'aspectFill' : 'aspectFit'}}"></image></view>
|
||||
<view class="podium-medal podium-medal--silver">2</view>
|
||||
</view>
|
||||
<view class="podium-name-row">
|
||||
<text class="podium-name">{{rankedList[1].name}}</text>
|
||||
<image wx:if="{{rankedList[1].badgeIcon}}" class="podium-badge" src="{{rankedList[1].badgeIcon}}" mode="aspectFit" data-name="{{rankedList[1].badgeName}}" data-days="{{rankedList[1].badgeDays}}" bindtap="onBadgeTap"></image>
|
||||
</view>
|
||||
<text class="podium-dur">{{rankedList[1].durationText}}</text>
|
||||
<view class="podium-base podium-base--second"><view class="podium-base__label {{activePeriod === 'endurance' ? 'is-two' : ''}}"><block wx:if="{{activePeriod === 'endurance'}}"><text class="podium-base__date">{{rankedList[1].subDate}}</text><text class="podium-base__time">{{rankedList[1].subTime}}</text></block><text wx:else>{{rankedList[1].subText}}</text></view></view>
|
||||
</block>
|
||||
<block wx:else>
|
||||
<view class="podium-avatar-wrap">
|
||||
<view class="avatar avatar--md podium-avatar--empty"><image class="avatar__img podium-avatar__img--empty" src="{{icons.peopleFill}}" mode="aspectFit"></image></view>
|
||||
<view class="podium-medal podium-medal--silver">2</view>
|
||||
</view>
|
||||
<view class="podium-base podium-base--second"><view class="podium-base__label"><text class="podium-empty-label">虚位以待</text></view></view>
|
||||
</block>
|
||||
</view>
|
||||
<!-- 1st -->
|
||||
<view class="podium-slot podium-slot--first rank-item--enter" style="animation-delay: 0ms;">
|
||||
<image class="podium-crown" src="{{icons.crownFill}}" mode="aspectFit"></image>
|
||||
<view class="podium-avatar-wrap">
|
||||
<view class="avatar avatar--md avatar--lg {{rankedList[0].avatarUrl ? 'has-avatar' : ''}}"><image class="avatar__img" src="{{rankedList[0].avatarUrl || icons.peopleFill}}" mode="{{rankedList[0].avatarUrl ? 'aspectFill' : 'aspectFit'}}"></image></view>
|
||||
<view class="podium-medal podium-medal--gold">1</view>
|
||||
</view>
|
||||
<text class="podium-name podium-name--first">{{rankedList[0].name}}</text>
|
||||
<text class="podium-dur podium-dur--first">{{rankedList[0].durationText}}</text>
|
||||
<view class="podium-base podium-base--first"><view class="podium-base__label {{activePeriod === 'endurance' ? 'is-two' : ''}}"><block wx:if="{{activePeriod === 'endurance'}}"><text class="podium-base__date">{{rankedList[0].subDate}}</text><text class="podium-base__time">{{rankedList[0].subTime}}</text></block><text wx:else>{{rankedList[0].subText}}</text></view></view>
|
||||
<block wx:if="{{rankedList[0]}}">
|
||||
<image class="podium-crown" src="{{icons.crownFill}}" mode="aspectFit"></image>
|
||||
<view class="podium-avatar-wrap">
|
||||
<view class="avatar avatar--md avatar--lg {{rankedList[0].avatarUrl ? 'has-avatar' : ''}}"><image class="avatar__img" src="{{rankedList[0].avatarUrl || icons.peopleFill}}" mode="{{rankedList[0].avatarUrl ? 'aspectFill' : 'aspectFit'}}"></image></view>
|
||||
<view class="podium-medal podium-medal--gold">1</view>
|
||||
</view>
|
||||
<view class="podium-name-row">
|
||||
<text class="podium-name podium-name--first">{{rankedList[0].name}}</text>
|
||||
<image wx:if="{{rankedList[0].badgeIcon}}" class="podium-badge podium-badge--first" src="{{rankedList[0].badgeIcon}}" mode="aspectFit" data-name="{{rankedList[0].badgeName}}" data-days="{{rankedList[0].badgeDays}}" bindtap="onBadgeTap"></image>
|
||||
</view>
|
||||
<text class="podium-dur podium-dur--first">{{rankedList[0].durationText}}</text>
|
||||
<view class="podium-base podium-base--first"><view class="podium-base__label {{activePeriod === 'endurance' ? 'is-two' : ''}}"><block wx:if="{{activePeriod === 'endurance'}}"><text class="podium-base__date">{{rankedList[0].subDate}}</text><text class="podium-base__time">{{rankedList[0].subTime}}</text></block><text wx:else>{{rankedList[0].subText}}</text></view></view>
|
||||
</block>
|
||||
<block wx:else>
|
||||
<image class="podium-crown podium-crown--empty" src="{{icons.crownFill}}" mode="aspectFit"></image>
|
||||
<view class="podium-avatar-wrap">
|
||||
<view class="avatar avatar--md avatar--lg podium-avatar--empty"><image class="avatar__img podium-avatar__img--empty" src="{{icons.peopleFill}}" mode="aspectFit"></image></view>
|
||||
<view class="podium-medal podium-medal--gold">1</view>
|
||||
</view>
|
||||
<view class="podium-base podium-base--first"><view class="podium-base__label"><text class="podium-empty-label">虚位以待</text></view></view>
|
||||
</block>
|
||||
</view>
|
||||
<!-- 3rd -->
|
||||
<view class="podium-slot podium-slot--third rank-item--enter" style="animation-delay: 120ms;">
|
||||
<view class="podium-avatar-wrap">
|
||||
<view class="avatar avatar--md {{rankedList[2].avatarUrl ? 'has-avatar' : ''}}"><image class="avatar__img" src="{{rankedList[2].avatarUrl || icons.peopleFill}}" mode="{{rankedList[2].avatarUrl ? 'aspectFill' : 'aspectFit'}}"></image></view>
|
||||
<view class="podium-medal podium-medal--bronze">3</view>
|
||||
</view>
|
||||
<text class="podium-name">{{rankedList[2].name}}</text>
|
||||
<text class="podium-dur">{{rankedList[2].durationText}}</text>
|
||||
<view class="podium-base podium-base--third"><view class="podium-base__label {{activePeriod === 'endurance' ? 'is-two' : ''}}"><block wx:if="{{activePeriod === 'endurance'}}"><text class="podium-base__date">{{rankedList[2].subDate}}</text><text class="podium-base__time">{{rankedList[2].subTime}}</text></block><text wx:else>{{rankedList[2].subText}}</text></view></view>
|
||||
<block wx:if="{{rankedList[2]}}">
|
||||
<view class="podium-avatar-wrap">
|
||||
<view class="avatar avatar--md {{rankedList[2].avatarUrl ? 'has-avatar' : ''}}"><image class="avatar__img" src="{{rankedList[2].avatarUrl || icons.peopleFill}}" mode="{{rankedList[2].avatarUrl ? 'aspectFill' : 'aspectFit'}}"></image></view>
|
||||
<view class="podium-medal podium-medal--bronze">3</view>
|
||||
</view>
|
||||
<view class="podium-name-row">
|
||||
<text class="podium-name">{{rankedList[2].name}}</text>
|
||||
<image wx:if="{{rankedList[2].badgeIcon}}" class="podium-badge" src="{{rankedList[2].badgeIcon}}" mode="aspectFit" data-name="{{rankedList[2].badgeName}}" data-days="{{rankedList[2].badgeDays}}" bindtap="onBadgeTap"></image>
|
||||
</view>
|
||||
<text class="podium-dur">{{rankedList[2].durationText}}</text>
|
||||
<view class="podium-base podium-base--third"><view class="podium-base__label {{activePeriod === 'endurance' ? 'is-two' : ''}}"><block wx:if="{{activePeriod === 'endurance'}}"><text class="podium-base__date">{{rankedList[2].subDate}}</text><text class="podium-base__time">{{rankedList[2].subTime}}</text></block><text wx:else>{{rankedList[2].subText}}</text></view></view>
|
||||
</block>
|
||||
<block wx:else>
|
||||
<view class="podium-avatar-wrap">
|
||||
<view class="avatar avatar--md podium-avatar--empty"><image class="avatar__img podium-avatar__img--empty" src="{{icons.peopleFill}}" mode="aspectFit"></image></view>
|
||||
<view class="podium-medal podium-medal--bronze">3</view>
|
||||
</view>
|
||||
<view class="podium-base podium-base--third"><view class="podium-base__label"><text class="podium-empty-label">虚位以待</text></view></view>
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@@ -84,7 +121,7 @@
|
||||
<view
|
||||
wx:for="{{rankedList}}"
|
||||
wx:key="rank"
|
||||
wx:if="{{rankedList.length < 3 || index >= 3}}"
|
||||
wx:if="{{index >= 3}}"
|
||||
class="rank-item {{item.isMe ? 'is-me' : ''}} rank-item--enter"
|
||||
style="animation-delay: {{index < 10 ? index * 60 : 0}}ms;"
|
||||
>
|
||||
@@ -93,7 +130,20 @@
|
||||
</view>
|
||||
<view class="avatar avatar--sm {{item.avatarUrl ? 'has-avatar' : ''}}"><image class="avatar__img" src="{{item.avatarUrl || icons.peopleFill}}" mode="{{item.avatarUrl ? 'aspectFill' : 'aspectFit'}}"></image></view>
|
||||
<view class="rank-info">
|
||||
<text class="rank-name">{{item.name}}</text>
|
||||
<view class="rank-name-row">
|
||||
<text class="rank-name">{{item.name}}</text>
|
||||
<!-- 每个用户的勋章:云函数下发 totalDays,浅底行用主题色版。
|
||||
无勋章(未达3天)或旧快照无 totalDays 时不渲染 -->
|
||||
<image
|
||||
wx:if="{{item.badgeIcon}}"
|
||||
class="rank-badge"
|
||||
src="{{item.badgeIcon}}"
|
||||
mode="aspectFit"
|
||||
data-name="{{item.badgeName}}"
|
||||
data-days="{{item.badgeDays}}"
|
||||
bindtap="onBadgeTap"
|
||||
></image>
|
||||
</view>
|
||||
<text class="rank-sessions">{{item.subText}}</text>
|
||||
</view>
|
||||
<text class="rank-dur">{{item.durationText}}</text>
|
||||
@@ -106,7 +156,19 @@
|
||||
<view class="rank-num my-bar__num">{{myEntry.rank}}</view>
|
||||
<view class="avatar avatar--sm my-bar__avatar {{myEntry.avatarUrl ? 'has-avatar' : ''}}"><image class="avatar__img" src="{{myEntry.avatarUrl || icons.peopleFill}}" mode="{{myEntry.avatarUrl ? 'aspectFill' : 'aspectFit'}}"></image></view>
|
||||
<view class="rank-info">
|
||||
<text class="rank-name">我 ({{myEntry.name}})</text>
|
||||
<view class="rank-name-row">
|
||||
<text class="rank-name">我 ({{myEntry.name}})</text>
|
||||
<!-- 我的勋章:主题渐变底用白版 -->
|
||||
<image
|
||||
wx:if="{{myEntry.badgeIconWhite}}"
|
||||
class="rank-badge"
|
||||
src="{{myEntry.badgeIconWhite}}"
|
||||
mode="aspectFit"
|
||||
data-name="{{myEntry.badgeName}}"
|
||||
data-days="{{myEntry.badgeDays}}"
|
||||
bindtap="onBadgeTap"
|
||||
></image>
|
||||
</view>
|
||||
<text class="rank-sessions">{{myEntry.subText}}</text>
|
||||
</view>
|
||||
<text class="rank-dur">{{myEntry.durationText}}</text>
|
||||
|
||||
@@ -194,16 +194,42 @@
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
line-height: 1.3;
|
||||
/* 用 name 的 margin-top 直接控制与上方头像/角标的间距:它是 flex 子元素,
|
||||
margin 必定生效不折叠,不依赖 avatar margin-bottom 的 collapse 行为
|
||||
(WebView/Skyline 下不一致,曾导致角标压住昵称)。 */
|
||||
margin-top: 30rpx;
|
||||
/* 关键对齐修复:行盒高度设为与勋章等高(30rpx)。这样 flex 的 align-items:center
|
||||
对齐的是"昵称盒中心"与"勋章盒中心"两个等高盒,而非 line-height:1 下偏矮、
|
||||
且中文 glyph 视觉重心偏下的行盒,图标不会再飘在昵称上方。 */
|
||||
line-height: 30rpx;
|
||||
}
|
||||
|
||||
.podium-name--first {
|
||||
font-size: 28rpx;
|
||||
font-weight: 600;
|
||||
line-height: 30rpx; /* 与首名勋章统一为 30rpx,前三名勋章等大且和昵称盒等高对齐 */
|
||||
}
|
||||
|
||||
/* 领奖台名字 + 勋章横排(居中)。名字保留自身 max-width/省略,勋章固定不挤压 */
|
||||
.podium-name-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 6rpx;
|
||||
max-width: 220rpx;
|
||||
/* 原间距 margin-top:30rpx 从 .podium-name 移到此处:避免在 flex 子项上用
|
||||
cross 轴 margin 干扰昵称与勋章的居中(那是之前图标"偏高"的隐藏元凶)。 */
|
||||
margin-top: 30rpx;
|
||||
}
|
||||
|
||||
.podium-badge {
|
||||
width: 30rpx;
|
||||
height: 30rpx;
|
||||
flex-shrink: 0;
|
||||
/* 不再用 margin-top 盲推:昵称行盒已设为与勋章等高(30rpx),flex align-items:center
|
||||
直接对齐两盒中心,图标与昵称视觉对齐。若个别冠类勋章因图形重心仍有 ±1~2rpx
|
||||
偏差,再单独给该图加 transform: translateY(2rpx) 即可,不要回退到 margin 推法。 */
|
||||
}
|
||||
|
||||
.podium-badge--first {
|
||||
width: 30rpx;
|
||||
height: 30rpx;
|
||||
}
|
||||
|
||||
/* session count printed on the podium base. Pinned a fixed offset above the
|
||||
@@ -243,7 +269,8 @@
|
||||
font-size: 24rpx;
|
||||
font-weight: 600;
|
||||
color: var(--text-secondary);
|
||||
margin-top: 2rpx;
|
||||
/* line-height 收紧后行盒缩短约 8rpx,此处补偿保持与名字的视觉间距 */
|
||||
margin-top: 10rpx;
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
@@ -277,6 +304,30 @@
|
||||
box-shadow: 0 6rpx 18rpx rgba(212, 107, 8, 0.22), inset 0 2rpx 4rpx rgba(255, 255, 255, 0.45);
|
||||
}
|
||||
|
||||
/* 虚拟领奖台:空位占位(名单不足 3 名时,空缺名次渲染成"虚位以待") */
|
||||
.podium-avatar--empty {
|
||||
opacity: 1;
|
||||
border: 4rpx dashed rgba(var(--primary-rgb), 0.35);
|
||||
box-shadow: none;
|
||||
background: rgba(var(--primary-rgb), 0.04);
|
||||
}
|
||||
|
||||
.podium-avatar__img--empty {
|
||||
opacity: 0.26;
|
||||
filter: grayscale(1);
|
||||
}
|
||||
|
||||
.podium-empty-label {
|
||||
font-size: 22rpx;
|
||||
font-weight: 500;
|
||||
color: var(--text-secondary);
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.podium-crown--empty {
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
/* Rank list */
|
||||
.rank-list {
|
||||
padding: 16rpx 24rpx;
|
||||
@@ -340,6 +391,25 @@
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* 昵称 + 最新勋章横排:昵称可省略,勋章固定不挤压 */
|
||||
.rank-name-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6rpx;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.rank-name-row .rank-name {
|
||||
flex: 0 1 auto;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.rank-badge {
|
||||
width: 30rpx;
|
||||
height: 30rpx;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.rank-sessions {
|
||||
font-size: 22rpx;
|
||||
color: var(--text-secondary);
|
||||
|
||||
Reference in New Issue
Block a user