feat: Kinetic Dark 设计语言 + Lucide 图标迁移 + 首页轻量个性化

- 建立 Lucide 子集 iconfont(49 字形),全站 emoji 替换为 fc-icon 组件
- 重塑 Design Token(冷中性近黑底 + Volt 荧光绿 #B6F24E),消除硬编码颜色
- 首页登录后个性化:我的计划 / 我的收藏 / 今日推荐(纯前端复用现有 API)
- 后端 DEFAULT_EMOJI→Lucide 名,PALETTE 对齐 Kinetic Dark 语义色板
- 修复 person-standing 缺失字形;14 个官方组合 seed emoji 全部映射到现有字形
This commit is contained in:
2026-07-22 21:38:56 +08:00
parent ca0af6f7d2
commit b94eb706ff
64 changed files with 1572 additions and 173 deletions

View File

@@ -1,17 +1,28 @@
// 头像组件:纯 emoji 圆形头像(无二进制图片)。
// props: avatar(emoji 字符串), size(rpx, 默认 120), bg(背景色, 默认 gold-soft)
const { iconName } = require('../../utils/icon-name');
// 头像组件:圆形 Lucide 图标头像(无二进制图片)。
// props: avatar(lucide 图标名 或 历史 emoji), size(rpx, 默认 120), bg(背景色)
Component({
properties: {
avatar: { type: String, value: '💪' },
avatar: { type: String, value: 'user' },
size: { type: Number, value: 120 },
bg: { type: String, value: 'rgba(217,179,108,0.12)' }
bg: { type: String, value: 'rgba(182,242,78,0.12)' }
},
data: {
fontSize: 60
glyph: 'user',
iconSize: 60
},
observers: {
size: function (size) {
this.setData({ fontSize: Math.round(size * 0.5) });
avatar(v) {
this.setData({ glyph: iconName(v, 'user') });
},
size(s) {
this.setData({ iconSize: Math.round(s * 0.5) });
}
},
lifetimes: {
attached() {
this.setData({ glyph: iconName(this.data.avatar, 'user'), iconSize: Math.round(this.data.size * 0.5) });
}
}
});

View File

@@ -1,4 +1,6 @@
{
"component": true,
"usingComponents": {}
"usingComponents": {
"fc-icon": "/components/fc-icon/index"
}
}

View File

@@ -1,5 +1,5 @@
<view
class="avatar"
style="width: {{size}}rpx; height: {{size}}rpx; background: {{bg}}; font-size: {{fontSize}}rpx;">
{{avatar || '💪'}}
style="width: {{size}}rpx; height: {{size}}rpx; background: {{bg}};">
<fc-icon name="{{glyph}}" size="{{iconSize}}" color="var(--accent)" />
</view>

View File

@@ -4,10 +4,10 @@ Component({
},
data: {
items: [
{ key: 'home', label: '首页', emoji: '🏠', page: '/pages/index/index' },
{ key: 'category', label: '分类', emoji: '📚', page: '/pages/category/category' },
{ key: 'plans', label: '计划', emoji: '📋', page: '/pages/my-plans/my-plans' },
{ key: 'mine', label: '我的', emoji: '👤', page: '/pages/profile/profile' }
{ key: 'home', label: '首页', icon: 'home', page: '/pages/index/index' },
{ key: 'category', label: '分类', icon: 'layout-grid', page: '/pages/category/category' },
{ key: 'plans', label: '计划', icon: 'clipboard-list', page: '/pages/my-plans/my-plans' },
{ key: 'mine', label: '我的', icon: 'user', page: '/pages/profile/profile' }
]
},
methods: {

View File

@@ -1,4 +1,6 @@
{
"component": true,
"usingComponents": {}
"usingComponents": {
"fc-icon": "/components/fc-icon/index"
}
}

View File

@@ -5,7 +5,7 @@
class="bn__item {{active === item.key ? 'bn__item--active' : ''}}"
data-page="{{item.page}}"
bindtap="onTap">
<text class="bn__emoji">{{item.emoji}}</text>
<fc-icon name="{{item.icon}}" size="40" color="{{active === item.key ? 'var(--accent)' : 'var(--text-3)'}}" />
<text class="bn__label">{{item.label}}</text>
</view>
</view>

View File

@@ -27,6 +27,6 @@
background: linear-gradient(90deg, var(--gold), var(--gold-2));
}
.bn__item--active { color: var(--gold); }
.bn__emoji { font-size: 40rpx; line-height: 1; }
.bn__emoji { line-height: 1; }
.bn__label { font-size: 22rpx; margin-top: 6rpx; }
.bn__item--active .bn__label { color: var(--gold-2); }

View File

@@ -1,4 +1,6 @@
{
"component": true,
"usingComponents": {}
"usingComponents": {
"fc-icon": "/components/fc-icon/index"
}
}

View File

@@ -7,7 +7,7 @@
mode="aspectFill"
lazy-load="true"
binderror="onImgError" />
<view wx:else class="ex-card__ph">🏋️</view>
<view wx:else class="ex-card__ph"><fc-icon name="dumbbell" size="64" color="var(--text-3)" /></view>
<view wx:if="{{exercise.typeLabel}}" class="ex-card__type">{{exercise.typeLabel}}</view>
<view wx:if="{{score > 0}}" class="ex-card__score">匹配 {{score}}</view>
</view>

View File

@@ -21,11 +21,11 @@
.ex-card__type {
position: absolute; left: 12rpx; top: 12rpx;
font-size: 20rpx; color: var(--text-2);
background: rgba(0,0,0,0.45); padding: 4rpx 14rpx; border-radius: 999rpx;
background: var(--scrim); padding: 4rpx 14rpx; border-radius: 999rpx;
}
.ex-card__score {
position: absolute; right: 12rpx; top: 12rpx;
font-size: 20rpx; color: #0E1110; font-weight: 700;
font-size: 20rpx; color: var(--accent-on); font-weight: 700;
background: var(--gold); padding: 4rpx 14rpx; border-radius: 999rpx;
}
.ex-card__body { padding: 16rpx 18rpx 20rpx; }

View File

@@ -0,0 +1,23 @@
const iconMap = require('../../utils/icon-map');
Component({
properties: {
// Lucide 图标名,如 search / dumbbell / heart
name: { type: String, value: '' },
// 字号rpx
size: { type: Number, value: 20 },
// 颜色默认跟随当前文字色currentColor 在 iconfont 下用具体色)
color: { type: String, value: '' },
},
data: { glyph: '' },
observers: {
name(n) {
this.setData({ glyph: (iconMap[n] || '') });
},
},
lifetimes: {
attached() {
this.setData({ glyph: (iconMap[this.data.name] || '') });
},
},
});

View File

@@ -0,0 +1,4 @@
{
"component": true,
"usingComponents": {}
}

View File

@@ -0,0 +1 @@
<text class="fc-icon" style="font-size:{{size}}rpx;{{color ? 'color:' + color + ';' : ''}}">{{glyph}}</text>

View File

@@ -0,0 +1,10 @@
.fc-icon {
font-family: "fc-icon";
font-style: normal;
font-weight: normal;
font-variant: normal;
text-transform: none;
line-height: 1;
-webkit-font-smoothing: antialiased;
display: inline-block;
}

View File

@@ -9,7 +9,7 @@
}
.gif-loading__dot {
width: 18rpx; height: 18rpx; border-radius: 999rpx;
background: var(--gold, #c9a24b);
background: var(--accent);
animation: gif-pulse 1s ease-in-out infinite;
}
.gif-loading__txt {

View File

@@ -1,5 +1,5 @@
.navbar {
background: linear-gradient(180deg, rgba(22,32,27,0.96) 0%, rgba(14,17,16,0.55) 100%);
background: linear-gradient(180deg, var(--bar-bg) 0%, var(--float-bg) 100%);
position: sticky;
top: 0;
z-index: 50;