diff --git a/miniprogram/assets/icons/book-open.svg b/miniprogram/assets/icons/book-open.svg
new file mode 100644
index 00000000..d833e86b
--- /dev/null
+++ b/miniprogram/assets/icons/book-open.svg
@@ -0,0 +1,4 @@
+
diff --git a/miniprogram/assets/icons/book.svg b/miniprogram/assets/icons/book.svg
new file mode 100644
index 00000000..93579576
--- /dev/null
+++ b/miniprogram/assets/icons/book.svg
@@ -0,0 +1,4 @@
+
diff --git a/miniprogram/assets/icons/home.svg b/miniprogram/assets/icons/home.svg
new file mode 100644
index 00000000..76244091
--- /dev/null
+++ b/miniprogram/assets/icons/home.svg
@@ -0,0 +1,4 @@
+
diff --git a/miniprogram/assets/icons/list.svg b/miniprogram/assets/icons/list.svg
new file mode 100644
index 00000000..688326aa
--- /dev/null
+++ b/miniprogram/assets/icons/list.svg
@@ -0,0 +1,8 @@
+
diff --git a/miniprogram/assets/icons/share.svg b/miniprogram/assets/icons/share.svg
new file mode 100644
index 00000000..93179fc2
--- /dev/null
+++ b/miniprogram/assets/icons/share.svg
@@ -0,0 +1,7 @@
+
diff --git a/miniprogram/assets/icons/sparkles.svg b/miniprogram/assets/icons/sparkles.svg
new file mode 100644
index 00000000..a3b9133c
--- /dev/null
+++ b/miniprogram/assets/icons/sparkles.svg
@@ -0,0 +1,4 @@
+
diff --git a/miniprogram/assets/icons/user.svg b/miniprogram/assets/icons/user.svg
new file mode 100644
index 00000000..8b190427
--- /dev/null
+++ b/miniprogram/assets/icons/user.svg
@@ -0,0 +1,4 @@
+
diff --git a/miniprogram/assets/icons/users.svg b/miniprogram/assets/icons/users.svg
new file mode 100644
index 00000000..4816094b
--- /dev/null
+++ b/miniprogram/assets/icons/users.svg
@@ -0,0 +1,6 @@
+
diff --git a/miniprogram/components/icon/README.md b/miniprogram/components/icon/README.md
new file mode 100644
index 00000000..34e394c8
--- /dev/null
+++ b/miniprogram/components/icon/README.md
@@ -0,0 +1,175 @@
+# Icon 图标组件
+
+SVG 图标组件,参考 lucide-react 实现,用于在小程序中使用矢量图标。
+
+**技术实现**: 使用 Base64 编码的 SVG + image 组件(小程序不支持直接使用 SVG 标签)
+
+---
+
+## 使用方法
+
+### 1. 在页面 JSON 中引入组件
+
+```json
+{
+ "usingComponents": {
+ "icon": "/components/icon/icon"
+ }
+}
+```
+
+### 2. 在 WXML 中使用
+
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+---
+
+## 属性说明
+
+| 属性 | 类型 | 默认值 | 说明 |
+|-----|------|--------|-----|
+| name | String | 'share' | 图标名称 |
+| size | Number | 48 | 图标大小(rpx) |
+| color | String | 'currentColor' | 图标颜色 |
+| customClass | String | '' | 自定义类名 |
+| customStyle | String | '' | 自定义样式 |
+
+---
+
+## 可用图标
+
+| 图标名称 | 说明 | 对应 lucide-react |
+|---------|------|-------------------|
+| `share` | 分享 | `` |
+| `arrow-up-right` | 右上箭头 | `` |
+| `chevron-left` | 左箭头 | `` |
+| `search` | 搜索 | `` |
+| `heart` | 心形 | `` |
+
+---
+
+## 添加新图标
+
+在 `icon.js` 的 `getSvgPath` 方法中添加新图标:
+
+```javascript
+getSvgPath(name) {
+ const svgMap = {
+ 'new-icon': '',
+ // ... 其他图标
+ }
+ return svgMap[name] || ''
+}
+```
+
+**获取 SVG 代码**: 访问 [lucide.dev](https://lucide.dev) 搜索图标,复制 SVG 内容。
+**注意**: 颜色使用 `COLOR` 占位符,组件会自动替换。
+
+---
+
+## 样式定制
+
+### 1. 使用 customClass
+
+```xml
+
+```
+
+```css
+.my-icon-class {
+ opacity: 0.8;
+}
+```
+
+### 2. 使用 customStyle
+
+```xml
+
+```
+
+---
+
+## 技术说明
+
+### 为什么使用 Base64 + image?
+
+1. **矢量图标**:任意缩放不失真
+2. **灵活着色**:通过 `COLOR` 占位符动态改变颜色
+3. **轻量级**:无需加载字体文件或外部图片
+4. **兼容性**:小程序不支持直接使用 SVG 标签,image 组件支持 Base64 SVG
+
+### 为什么不用字体图标?
+
+小程序对字体文件有限制,Base64 编码字体文件会增加包体积,SVG 图标更轻量。
+
+### 与 lucide-react 的对应关系
+
+- **lucide-react**: React 组件库,使用 SVG
+- **本组件**: 小程序自定义组件,也使用 SVG
+- **SVG path 数据**: 完全相同,从 lucide 官网复制
+
+---
+
+## 示例
+
+### 悬浮分享按钮
+
+```xml
+
+```
+
+```css
+.fab-share {
+ position: fixed;
+ right: 32rpx;
+ bottom: calc(120rpx + env(safe-area-inset-bottom));
+ width: 96rpx;
+ height: 96rpx;
+ border-radius: 50%;
+ background: linear-gradient(135deg, #00CED1 0%, #20B2AA 100%);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+```
+
+---
+
+## 扩展图标库
+
+可以继续添加更多 lucide-react 图标:
+
+- `star` - 星星
+- `wallet` - 钱包
+- `gift` - 礼物
+- `info` - 信息
+- `settings` - 设置
+- `user` - 用户
+- `book-open` - 打开的书
+- `eye` - 眼睛
+- `clock` - 时钟
+- `users` - 用户组
+
+---
+
+**图标组件创建完成!** 🎉
diff --git a/miniprogram/components/icon/icon.js b/miniprogram/components/icon/icon.js
new file mode 100644
index 00000000..b2dec23f
--- /dev/null
+++ b/miniprogram/components/icon/icon.js
@@ -0,0 +1,83 @@
+// components/icon/icon.js
+Component({
+ properties: {
+ // 图标名称
+ name: {
+ type: String,
+ value: 'share',
+ observer: 'updateIcon'
+ },
+ // 图标大小(rpx)
+ size: {
+ type: Number,
+ value: 48
+ },
+ // 图标颜色
+ color: {
+ type: String,
+ value: '#ffffff',
+ observer: 'updateIcon'
+ },
+ // 自定义类名
+ customClass: {
+ type: String,
+ value: ''
+ },
+ // 自定义样式
+ customStyle: {
+ type: String,
+ value: ''
+ }
+ },
+
+ data: {
+ svgData: ''
+ },
+
+ lifetimes: {
+ attached() {
+ this.updateIcon()
+ }
+ },
+
+ methods: {
+ // SVG 图标数据映射
+ getSvgPath(name) {
+ const svgMap = {
+ 'share': '',
+
+ 'arrow-up-right': '',
+
+ 'chevron-left': '',
+
+ 'search': '',
+
+ 'heart': ''
+ }
+
+ return svgMap[name] || ''
+ },
+
+ // 更新图标
+ updateIcon() {
+ const { name, color } = this.data
+ let svgString = this.getSvgPath(name)
+
+ if (svgString) {
+ // 替换颜色占位符
+ svgString = svgString.replace(/COLOR/g, color)
+
+ // 转换为 Base64 Data URL
+ const svgData = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svgString)}`
+
+ this.setData({
+ svgData: svgData
+ })
+ } else {
+ this.setData({
+ svgData: ''
+ })
+ }
+ }
+ }
+})
diff --git a/miniprogram/components/icon/icon.json b/miniprogram/components/icon/icon.json
new file mode 100644
index 00000000..a89ef4db
--- /dev/null
+++ b/miniprogram/components/icon/icon.json
@@ -0,0 +1,4 @@
+{
+ "component": true,
+ "usingComponents": {}
+}
diff --git a/miniprogram/components/icon/icon.wxml b/miniprogram/components/icon/icon.wxml
new file mode 100644
index 00000000..b1c29a25
--- /dev/null
+++ b/miniprogram/components/icon/icon.wxml
@@ -0,0 +1,5 @@
+
+
+
+ {{name}}
+
diff --git a/miniprogram/components/icon/icon.wxss b/miniprogram/components/icon/icon.wxss
new file mode 100644
index 00000000..d12d2a0a
--- /dev/null
+++ b/miniprogram/components/icon/icon.wxss
@@ -0,0 +1,18 @@
+/* components/icon/icon.wxss */
+.icon {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ flex-shrink: 0;
+}
+
+.icon-image {
+ display: block;
+ width: 100%;
+ height: 100%;
+}
+
+.icon-text {
+ font-size: 24rpx;
+ color: currentColor;
+}
diff --git a/miniprogram/custom-tab-bar/index.wxml b/miniprogram/custom-tab-bar/index.wxml
index 14ee2dc5..03dce2f9 100644
--- a/miniprogram/custom-tab-bar/index.wxml
+++ b/miniprogram/custom-tab-bar/index.wxml
@@ -5,13 +5,10 @@
-
-
-
-
-
-
-
+
{{list[0].text}}
@@ -19,13 +16,10 @@
-
-
-
-
-
-
-
+
{{list[1].text}}
@@ -33,10 +27,9 @@
-
-
-
-
+
{{list[2].text}}
@@ -44,12 +37,10 @@
-
-
-
-
-
-
+
{{list[3].text}}
diff --git a/miniprogram/custom-tab-bar/index.wxss b/miniprogram/custom-tab-bar/index.wxss
index 5fd321e1..4ab6f933 100644
--- a/miniprogram/custom-tab-bar/index.wxss
+++ b/miniprogram/custom-tab-bar/index.wxss
@@ -68,105 +68,18 @@
line-height: 1;
}
-/* ===== 首页图标 ===== */
-.icon-home {
- position: relative;
- width: 40rpx;
- height: 40rpx;
+/* ===== SVG 图标样式 ===== */
+.tab-icon {
+ width: 48rpx;
+ height: 48rpx;
+ display: block;
+ filter: brightness(0) saturate(100%) invert(60%) sepia(0%) saturate(0%) hue-rotate(0deg) brightness(95%) contrast(85%);
}
-.home-roof {
- position: absolute;
- top: 4rpx;
- left: 50%;
- transform: translateX(-50%);
- width: 0;
- height: 0;
- border-left: 18rpx solid transparent;
- border-right: 18rpx solid transparent;
- border-bottom: 14rpx solid #8e8e93;
+.tab-icon.icon-active {
+ filter: brightness(0) saturate(100%) invert(72%) sepia(54%) saturate(2933%) hue-rotate(134deg) brightness(101%) contrast(101%);
}
-.home-body {
- position: absolute;
- bottom: 4rpx;
- left: 50%;
- transform: translateX(-50%);
- width: 28rpx;
- height: 18rpx;
- background: #8e8e93;
- border-radius: 0 0 4rpx 4rpx;
-}
-
-.icon-active .home-roof {
- border-bottom-color: #00CED1;
-}
-
-.icon-active .home-body {
- background: #00CED1;
-}
-
-/* ===== 目录图标 ===== */
-.icon-list {
- width: 36rpx;
- height: 32rpx;
- display: flex;
- flex-direction: column;
- justify-content: space-between;
-}
-
-.list-line {
- width: 100%;
- height: 6rpx;
- background: #8e8e93;
- border-radius: 3rpx;
-}
-
-.list-line:nth-child(2) {
- width: 75%;
-}
-
-.list-line:nth-child(3) {
- width: 50%;
-}
-
-.icon-active .list-line {
- background: #00CED1;
-}
-
-/* ===== 我的图标 ===== */
-.icon-user {
- position: relative;
- width: 36rpx;
- height: 40rpx;
-}
-
-.user-head {
- position: absolute;
- top: 0;
- left: 50%;
- transform: translateX(-50%);
- width: 16rpx;
- height: 16rpx;
- background: #8e8e93;
- border-radius: 50%;
-}
-
-.user-body {
- position: absolute;
- bottom: 0;
- left: 50%;
- transform: translateX(-50%);
- width: 28rpx;
- height: 18rpx;
- background: #8e8e93;
- border-radius: 14rpx 14rpx 0 0;
-}
-
-.icon-active .user-head,
-.icon-active .user-body {
- background: #00CED1;
-}
/* ===== 找伙伴 - 中间特殊按钮 ===== */
.special-item {
@@ -199,39 +112,10 @@
margin-top: 4rpx;
}
-/* ===== 找伙伴图标 (双人) ===== */
-.icon-users {
- position: relative;
+/* ===== 找伙伴特殊按钮图标 ===== */
+.special-icon {
width: 56rpx;
- height: 44rpx;
-}
-
-.user-circle {
- position: absolute;
- width: 28rpx;
- height: 28rpx;
- border-radius: 50%;
- background: #ffffff;
-}
-
-.user-circle::after {
- content: '';
- position: absolute;
- bottom: -12rpx;
- left: 50%;
- transform: translateX(-50%);
- width: 22rpx;
- height: 14rpx;
- background: #ffffff;
- border-radius: 11rpx 11rpx 0 0;
-}
-
-.user-1 {
- top: 0;
- left: 0;
-}
-
-.user-2 {
- top: 0;
- right: 0;
+ height: 56rpx;
+ display: block;
+ filter: brightness(0) saturate(100%) invert(100%) sepia(0%) saturate(0%) hue-rotate(0deg) brightness(100%) contrast(100%);
}
diff --git a/miniprogram/pages/read/read.json b/miniprogram/pages/read/read.json
index f6abead2..d182eac9 100644
--- a/miniprogram/pages/read/read.json
+++ b/miniprogram/pages/read/read.json
@@ -1,5 +1,7 @@
{
- "usingComponents": {},
+ "usingComponents": {
+ "icon": "/components/icon/icon"
+ },
"enablePullDownRefresh": false,
"backgroundTextStyle": "light",
"backgroundColor": "#000000",
diff --git a/miniprogram/pages/read/read.wxml b/miniprogram/pages/read/read.wxml
index 57a63d3a..d3556d93 100644
--- a/miniprogram/pages/read/read.wxml
+++ b/miniprogram/pages/read/read.wxml
@@ -226,7 +226,6 @@
diff --git a/miniprogram/pages/read/read.wxss b/miniprogram/pages/read/read.wxss
index 8965f884..e87d8c3e 100644
--- a/miniprogram/pages/read/read.wxss
+++ b/miniprogram/pages/read/read.wxss
@@ -923,20 +923,19 @@
.fab-share {
position: fixed;
right: 32rpx;
+ width:70rpx!important;
bottom: calc(120rpx + env(safe-area-inset-bottom));
- width: 112rpx;
- height: 112rpx;
- border-radius: 50%;
+ height: 70rpx;
+ border-radius: 60rpx;
background: linear-gradient(135deg, #00CED1 0%, #20B2AA 100%);
box-shadow: 0 8rpx 32rpx rgba(0, 206, 209, 0.4);
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
padding: 0;
margin: 0;
border: none;
- z-index: 90;
+ z-index: 9999;
+ display:flex;
+ align-items: center;
+ justify-content: center;
transition: transform 0.2s ease, box-shadow 0.2s ease;
}
@@ -949,16 +948,10 @@
box-shadow: 0 4rpx 20rpx rgba(0, 206, 209, 0.5);
}
-.fab-share-icon {
- font-size: 40rpx;
- color: #ffffff;
- line-height: 1;
+.fab-icon {
+ padding:16rpx;
+ width: 50rpx;
+ height: 50rpx;
display: block;
}
-.fab-share-text {
- font-size: 20rpx;
- color: rgba(255, 255, 255, 0.95);
- margin-top: 4rpx;
- font-weight: 500;
-}
diff --git a/miniprogram/project.private.config.json b/miniprogram/project.private.config.json
index 1d26b0b8..8dd8129a 100644
--- a/miniprogram/project.private.config.json
+++ b/miniprogram/project.private.config.json
@@ -23,12 +23,19 @@
"condition": {
"miniprogram": {
"list": [
+ {
+ "name": "阅读",
+ "pathName": "pages/read/read",
+ "query": "id=1.1",
+ "scene": null,
+ "launchMode": "default"
+ },
{
"name": "分销中心",
"pathName": "pages/referral/referral",
"query": "",
- "scene": null,
- "launchMode": "default"
+ "launchMode": "default",
+ "scene": null
},
{
"name": "我的",
diff --git a/miniprogram/分享图标对齐Next说明.md b/miniprogram/分享图标对齐Next说明.md
new file mode 100644
index 00000000..694d6d59
--- /dev/null
+++ b/miniprogram/分享图标对齐Next说明.md
@@ -0,0 +1,346 @@
+# 分享图标对齐 Next.js 说明
+
+**更新日期**: 2026-02-04
+**目标**: 小程序分享图标与 Next.js 保持一致
+**Next.js 使用**: `Share2` 图标(lucide-react)
+
+---
+
+## 🎯 Next.js 实现
+
+### 引入图标
+
+```tsx
+import { Share2 } from "lucide-react"
+```
+
+### 使用场景
+
+在 `components/chapter-content.tsx` 的顶部导航栏:
+
+```tsx
+
+```
+
+**特点**:
+- 圆形按钮(36px × 36px)
+- 深色背景 `#1c1c1e`
+- 图标尺寸 16px × 16px
+- 图标颜色灰色 `text-gray-400`
+- 点击效果:背景变深 `#2c2c2e`
+
+---
+
+## 📱 小程序实现
+
+### Share2 图标 SVG
+
+创建 `/assets/icons/share.svg`:
+
+```svg
+
+```
+
+**说明**: 这是 lucide-react 的 Share2 图标的 SVG 代码,完全一致。
+
+---
+
+### WXML 代码
+
+```xml
+
+
+```
+
+**关键点**:
+- 使用 `` 组件加载 SVG 文件
+- `mode="aspectFit"` 保持图标比例
+- `open-type="share"` 触发微信分享
+
+---
+
+### WXSS 样式
+
+```css
+.fab-share {
+ position: fixed;
+ right: 32rpx;
+ width: 60rpx!important;
+ bottom: calc(120rpx + env(safe-area-inset-bottom));
+ height: 60rpx;
+ border-radius: 60rpx;
+ background: linear-gradient(135deg, #00CED1 0%, #20B2AA 100%);
+ box-shadow: 0 8rpx 32rpx rgba(0, 206, 209, 0.4);
+ padding: 0;
+ margin: 0;
+ border: none;
+ z-index: 9999;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ transition: transform 0.2s ease, box-shadow 0.2s ease;
+}
+
+.fab-share::after {
+ border: none;
+}
+
+.fab-share:active {
+ transform: scale(0.95);
+ box-shadow: 0 4rpx 20rpx rgba(0, 206, 209, 0.5);
+}
+
+.fab-icon {
+ width: 48rpx;
+ height: 48rpx;
+ display: block;
+}
+```
+
+---
+
+## 📊 对比
+
+### 图标
+
+| 平台 | 图标来源 | 图标类型 | 实现方式 |
+|-----|---------|---------|---------|
+| **Next.js** | lucide-react | Share2 | React 组件 |
+| **小程序** | SVG 文件 | Share2 | image 组件 |
+| **一致性** | ✅ | ✅ 完全相同 | ✅ SVG 代码相同 |
+
+---
+
+### 按钮位置
+
+| 平台 | 位置 | 说明 |
+|-----|------|------|
+| **Next.js** | 顶部导航栏右侧 | 与返回按钮对称 |
+| **小程序** | 右下角悬浮 | 更适合移动端交互 |
+
+**差异原因**: 小程序需要悬浮按钮以避免被内容遮挡,且更符合移动端操作习惯。
+
+---
+
+### 视觉风格
+
+| 属性 | Next.js | 小程序 | 说明 |
+|-----|---------|--------|------|
+| **图标** | Share2 | Share2 | ✅ 完全相同 |
+| **按钮形状** | 圆形 | 圆形 | ✅ 一致 |
+| **图标颜色** | 灰色 `#9ca3af` | 白色 `#ffffff` | 小程序背景是品牌色,用白色更清晰 |
+| **按钮背景** | 深灰 `#1c1c1e` | 品牌色渐变 | 小程序更突出分享功能 |
+| **尺寸** | 36px × 36px | 60rpx × 60rpx (~45px) | 小程序略大,更易点击 |
+
+---
+
+## ✅ 核心一致性
+
+### 1. 图标形状 ✅
+
+**Share2 图标** (三个圆点连线):
+- 左上圆点(18, 5)
+- 左中圆点(6, 12)
+- 右下圆点(18, 19)
+- 两条连接线
+
+Next.js 和小程序使用**完全相同的 SVG path**,视觉效果一致。
+
+---
+
+### 2. 语义一致 ✅
+
+**功能**: 分享当前章节内容
+**触发**: 点击分享图标
+**行为**:
+- Next.js: 打开分享弹窗,显示专属链接和分享选项
+- 小程序: 触发微信原生分享(朋友、群聊、朋友圈)
+
+---
+
+## 🔧 技术实现
+
+### 为什么用 SVG 文件?
+
+| 方案 | 优点 | 缺点 | 结论 |
+|-----|------|------|------|
+| **直接 `