diff --git a/miniprogram/UPDATE_LOG.md b/miniprogram/UPDATE_LOG.md
index c068bfd..c774f57 100644
--- a/miniprogram/UPDATE_LOG.md
+++ b/miniprogram/UPDATE_LOG.md
@@ -1,5 +1,81 @@
# 小程序 UI 更新日志
+## 更新时间
+2026年2月9日
+
+## 修复:"选择"与搜索框垂直对齐问题
+
+### 问题描述
+"选择"文字与右侧搜索框无法垂直居中对齐,"选择"看起来偏上。
+
+### 根本原因
+1. **全局样式污染**:`app.wxss` 和 `index.wxss` 中的全局 `.section-title` 样式设置了 `padding: 12rpx 0` 和 `margin-bottom: 16rpx`,导致"选择"文字上下有额外间距
+2. **小程序 input 组件最小高度**:微信小程序的 `` 组件有默认最小高度(约 48rpx),无法通过 CSS 设置更小的高度,导致搜索框实际高度大于预期
+
+### 解决方案
+1. **统一高度为 48rpx**:适配 input 组件的最小高度限制
+2. **覆盖全局样式**:在 `.selection-header .section-title` 中显式设置 `padding: 0; margin: 0`
+3. **强制 flexbox 居中**:
+ - 父容器 `.selection-header` 使用 `display: flex; align-items: center`
+ - `.section-title` 使用 `display: flex; align-items: center; height: 48rpx`
+ - `.search-container` 使用 `height: 48rpx; overflow: hidden`
+
+### 关键代码
+```css
+.selection-header {
+ display: flex;
+ align-items: center;
+ gap: 8rpx;
+ padding: 0;
+}
+
+.selection-header .section-title {
+ padding: 0;
+ margin: 0;
+ font-size: 28rpx;
+ font-weight: 400;
+ flex-shrink: 0;
+ display: flex;
+ align-items: center;
+ height: 48rpx;
+}
+
+.search-container {
+ flex: 1;
+ display: flex;
+ align-items: center;
+ background: #FEFDFE;
+ border-radius: 24rpx;
+ padding: 0 12rpx;
+ height: 48rpx;
+ min-width: 0;
+ overflow: hidden;
+}
+
+.search-input {
+ flex: 1;
+ font-size: 24rpx;
+ color: #4E5969;
+ height: 48rpx;
+ line-height: 48rpx;
+ min-height: 0;
+ padding: 0;
+ margin: 0;
+ background: transparent;
+}
+```
+
+### 经验教训
+1. **检查全局样式**:修改特定组件样式前,先检查是否有全局样式影响
+2. **小程序组件限制**:微信小程序原生组件(如 input、textarea)有内置最小尺寸,需要适配而非强制覆盖
+3. **调试技巧**:当 flexbox `align-items: center` 不生效时,优先检查子元素的 padding/margin/line-height
+
+### 其他修复
+- **搜索框初始状态**:将 `showSearch` 初始值从 `false` 改为 `true`,搜索框默认完整显示(符合 Figma 设计)
+- **字体选中状态同步**:在 `bootstrap()` 中恢复 `selectedFonts` 后调用 `updateFontTrees()`,确保预览区的字体在字体树中正确显示为已选中
+
+---
+
## 更新时间
2026年2月8日(远端渲染改造)
diff --git a/miniprogram/pages/index/index.js b/miniprogram/pages/index/index.js
index 30947c2..c0bd411 100644
--- a/miniprogram/pages/index/index.js
+++ b/miniprogram/pages/index/index.js
@@ -30,10 +30,13 @@ const LOCAL_ICON_PATHS = {
fontIcon: '/assets/icons/font-icon.svg', // 字体item图标
expandIcon: '/assets/icons/expand.svg', // 展开分类图标
collapseIcon: '/assets/icons/expand.svg', // 折叠使用同一图标,通过旋转实现
- favoriteIcon: '/assets/icons/favorite.svg', // 收藏图标(未收藏白色底,收藏红色底)
- checkbox: '/assets/icons/checkbox.svg', // 复选框(未选中)
- checkboxChecked: '/assets/icons/checkbox-no.svg', // 复选框(已选中)
+ favoriteIcon: '/assets/icons/favorite.svg', // 收藏图标(未收藏)
+ favoriteRedIcon: '/assets/icons/favorite-red.svg', // 已收藏图标(红色)
+ checkbox: '/assets/icons/checkbox-no.svg', // 复选框(未选中)
+ checkboxChecked: '/assets/icons/checkbox.svg', // 复选框(已选中)
search: '/assets/icons/search.svg', // 搜索图标
+ selectAll: '/assets/icons/selectall.svg', // 全选图标
+ unselectAll: '/assets/icons/unselectall.svg', // 取消全选图标
}
function toSvgDataUri(svg) {
@@ -156,7 +159,7 @@ Page({
icons: LOCAL_ICON_PATHS,
// 搜索功能
searchKeyword: '',
- showSearch: false,
+ showSearch: true,
},
async onLoad() {
@@ -233,6 +236,8 @@ Page({
}))
this.setData({ selectedFonts })
+ // 更新字体树以反映选中状态
+ this.updateFontTrees()
await this.generateAllPreviews()
}
} catch (error) {
@@ -284,6 +289,7 @@ Page({
? true
: (typeof expandedFromState === 'boolean' ? expandedFromState : false),
fonts: [],
+ allSelected: false,
})
}
categoryMap.get(category).fonts.push({
@@ -303,6 +309,15 @@ Page({
})
const fontCategories = Array.from(categoryMap.values()).sort((a, b) => a.category.localeCompare(b.category))
+ // 计算每个分类的allSelected状态
+ fontCategories.forEach(cat => {
+ if (cat.fonts.length > 0) {
+ cat.allSelected = cat.fonts.every(f => f.selected)
+ } else {
+ cat.allSelected = false
+ }
+ })
+
favoriteFonts.sort((a, b) => {
const categoryCompare = String(a.category || '').localeCompare(String(b.category || ''))
if (categoryCompare !== 0) return categoryCompare
@@ -414,6 +429,56 @@ Page({
}
},
+ // 切换分类全选/取消全选
+ onToggleSelectAllInCategory(e) {
+ const category = e.currentTarget.dataset.category
+ if (!category) return
+
+ const categoryFonts = this.data.fontCategories.find(c => c.category === category)
+ if (!categoryFonts || categoryFonts.fonts.length === 0) return
+
+ const allSelected = categoryFonts.allSelected
+ const selectedFonts = [...this.data.selectedFonts]
+ const selectedIdSet = new Set(selectedFonts.map(f => f.id))
+
+ if (allSelected) {
+ // 取消全选:移除该分类下的所有字体
+ categoryFonts.fonts.forEach(font => {
+ selectedIdSet.delete(font.id)
+ })
+ } else {
+ // 全选:添加该分类下的所有字体
+ categoryFonts.fonts.forEach(font => {
+ selectedIdSet.add(font.id)
+ })
+ }
+
+ const newSelectedFonts = []
+ this.fontMap.forEach(font => {
+ if (selectedIdSet.has(font.id)) {
+ newSelectedFonts.push({
+ id: font.id,
+ name: font.name,
+ category: font.category,
+ showInPreview: true,
+ previewSrc: '',
+ })
+ }
+ })
+
+ this.setData({ selectedFonts: newSelectedFonts })
+ this.updateFontTrees()
+ this.scheduleGenerate()
+
+ saveAppState({
+ inputText: this.data.inputText,
+ selectedFontIds: newSelectedFonts.map(f => f.id),
+ fontSize: Number(this.data.fontSize),
+ letterSpacing: Number(this.data.letterSpacingInput || 0),
+ textColor: this.data.textColor,
+ })
+ },
+
// 生成单个字体的预览
async generatePreviewForFont(fontId) {
const text = String(this.data.inputText || '')
diff --git a/miniprogram/pages/index/index.wxml b/miniprogram/pages/index/index.wxml
index 0cec0ca..e040ffb 100644
--- a/miniprogram/pages/index/index.wxml
+++ b/miniprogram/pages/index/index.wxml
@@ -119,7 +119,10 @@
src="{{icons.expandIcon}}"
style="transform: rotate({{item.expanded ? '90deg' : '0deg'}})"
/>
- {{item.category}}({{item.fonts.length}})
+ {{item.category}}
+
+
+
@@ -134,15 +137,12 @@
{{font.name}}
-
-
-
+
@@ -154,19 +154,19 @@
- 已收藏
+
{{item.name}}
-
-
-
+
-
+
@@ -175,6 +175,11 @@
+
+
+
diff --git a/miniprogram/pages/index/index.wxss b/miniprogram/pages/index/index.wxss
index 2e58094..f0f7acb 100644
--- a/miniprogram/pages/index/index.wxss
+++ b/miniprogram/pages/index/index.wxss
@@ -122,8 +122,8 @@
display: flex;
flex-direction: column;
margin-top: 16rpx;
- padding: 0 16rpx;
- border: 1rpx solid #f7e0e0;
+ padding: 8rpx;
+ border: 1rpx solid #3EE4C3;
border-radius: 12rpx;
background: #fff;
overflow: hidden;
@@ -266,10 +266,11 @@
/* 字体选择和已收藏字体 */
.bottom-section {
display: flex;
+ flex: 1;
gap: 16rpx;
- height: 600rpx;
+ min-height: 0;
margin-top: 16rpx;
- padding: 0 16rpx;
+ padding: 0;
}
.font-selection,
@@ -277,11 +278,12 @@
flex: 1;
display: flex;
flex-direction: column;
- border: 1rpx solid #f7e0e0;
+ border: 1rpx solid #3EE4C3;
border-radius: 16rpx;
background: #fff;
- padding: 9rpx;
+ padding: 8rpx 8rpx;
overflow: hidden;
+ min-width: 0;
}
/* 搜索相关样式 */
@@ -290,58 +292,90 @@
align-items: center;
gap: 8rpx;
padding: 0;
- height: 40rpx;
+ margin-bottom: 8rpx;
}
.selection-header .section-title {
padding: 0;
+ margin: 0;
font-size: 28rpx;
- line-height: 40rpx;
+ font-weight: 400;
+ flex-shrink: 0;
display: flex;
align-items: center;
- flex-shrink: 0;
+ height: 48rpx;
+ width: 66rpx;
+}
+
+.favorite-header {
+ display: flex;
+ align-items: center;
+ padding: 0;
+ margin-bottom: 8rpx;
+}
+
+.favorite-header .section-title {
+ padding: 0;
+ margin: 0;
+ font-size: 28rpx;
+ font-weight: 400;
+ display: flex;
+ align-items: center;
+ height: 48rpx;
}
.search-container {
flex: 1;
display: flex;
align-items: center;
- gap: 6rpx;
- background: #F7F8FA;
- border-radius: 8rpx;
- padding: 4rpx 12rpx;
- height: 40rpx;
+ background: #FEFDFE;
+ border-radius: 24rpx;
+ padding: 0 12rpx;
+ height: 48rpx;
min-width: 0;
+ overflow: hidden;
}
.search-icon {
- width: 28rpx;
- height: 28rpx;
+ width: 24rpx;
+ height: 24rpx;
flex-shrink: 0;
- opacity: 0.5;
+ margin-right: 8rpx;
}
.search-input {
flex: 1;
- font-size: 22rpx;
+ font-size: 24rpx;
color: #4E5969;
- height: 100%;
+ height: 48rpx;
+ line-height: 48rpx;
+ min-height: 0;
+ padding: 0;
+ margin: 0;
+ background: transparent;
}
.search-toggle {
- width: 40rpx;
- height: 40rpx;
+ width: 32rpx;
+ height: 32rpx;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
- background: #F7F8FA;
- border-radius: 8rpx;
+ background: #8552A1;
+ border-radius: 20rpx;
+}
+
+.search-toggle .search-icon {
+ width: 18rpx;
+ height: 18rpx;
+ opacity: 1;
}
.font-tree {
flex: 1;
min-height: 0;
+ overflow-y: auto;
}
.font-category {
@@ -364,11 +398,28 @@
}
.category-name {
+ flex: 1;
font-size: 21rpx;
font-weight: 500;
color: #000;
}
+.category-select-all {
+ width: 24rpx;
+ height: 24rpx;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ flex-shrink: 0;
+ padding: 4rpx;
+}
+
+.select-all-icon {
+ width: 100%;
+ height: 100%;
+ display: block;
+}
+
.font-list {
display: flex;
flex-direction: column;
@@ -528,6 +579,15 @@
font-size: 28rpx;
}
+/* 版权说明 */
+.copyright-footer {
+ text-align: center;
+ font-size: 20rpx;
+ color: #86909C;
+ padding: 16rpx 0;
+ flex-shrink: 0;
+}
+
/* 画布 */
.hidden-canvas {
position: fixed;