@lmy54321/design-system 1.1.4 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,196 @@
1
+ import { useState } from "react";
2
+ import { motion } from "motion/react";
3
+ import { Switch } from "@lmy54321/design-system";
4
+ import { Btn } from "@lmy54321/design-system";
5
+ import { Tag } from "@lmy54321/design-system";
6
+ import { Dialog } from "@lmy54321/design-system";
7
+ import { IconFont } from "@lmy54321/design-system";
8
+ import { BottomNavigationBar } from "@lmy54321/design-system";
9
+ import type { TabId } from "@lmy54321/design-system";
10
+ import { ImageWithFallback } from "@lmy54321/design-system";
11
+ import { DraggablePanel, DRAWER_STATES } from "@lmy54321/design-system";
12
+
13
+ /* ── 四个入口模块数据 ── */
14
+ const entryModules = [
15
+ {
16
+ value: "12",
17
+ desc: "足迹城市",
18
+ image: "/images/city-footprint.png",
19
+ rotate: "-8deg",
20
+ },
21
+ {
22
+ value: "3,280",
23
+ desc: "行程公里",
24
+ image: "/images/km-journey.png",
25
+ rotate: "6deg",
26
+ },
27
+ {
28
+ value: "48",
29
+ desc: "收藏地点",
30
+ image: "/images/fav-places.png",
31
+ rotate: "-5deg",
32
+ },
33
+ {
34
+ value: "26",
35
+ desc: "评价数",
36
+ image: "/images/reviews-count.png",
37
+ rotate: "7deg",
38
+ },
39
+ ];
40
+
41
+ const menuItems = [
42
+ { icon: "bookmark", label: "我的收藏", badge: "48" },
43
+ { icon: "history", label: "历史记录", badge: "" },
44
+ { icon: "download", label: "离线地图", badge: "2" },
45
+ { icon: "map-setting", label: "地图设置", badge: "" },
46
+ { icon: "help-circle", label: "帮助与反馈", badge: "" },
47
+ ];
48
+
49
+ interface MePageProps {
50
+ activeTab: TabId;
51
+ onTabChange: (id: TabId) => void;
52
+ }
53
+
54
+ export function MePage({ activeTab, onTabChange }: MePageProps) {
55
+ const [darkMode, setDarkMode] = useState(false);
56
+ const [notifications, setNotifications] = useState(true);
57
+ const [showLogout, setShowLogout] = useState(false);
58
+
59
+ const meContent = (
60
+ <div className="pb-[80px]">
61
+ {/* User Profile Card */}
62
+ <div className="px-[16px] pt-[8px] pb-[16px]">
63
+ <div className="flex items-center gap-[14px] p-[16px] rounded-[24px] bg-card-muted">
64
+ <div className="size-[56px] rounded-full bg-primary/15 flex items-center justify-center shrink-0">
65
+ <IconFont name="user" size="28px" className="text-primary" />
66
+ </div>
67
+ <div className="flex-1 min-w-0">
68
+ <div className="flex items-center gap-[8px]">
69
+ <span className="text-[18px] font-medium text-foreground leading-[24px]">探索者</span>
70
+ <Tag label="VIP" size="sm" className="bg-[#FFB800]/15 text-[#FFB800] border-transparent" />
71
+ </div>
72
+ <p className="text-[12px] text-muted-foreground leading-[16px] mt-[2px]">用脚步丈量世界</p>
73
+ </div>
74
+ <Btn size="small" variant="secondary" label="编辑" icon={null} />
75
+ </div>
76
+ </div>
77
+
78
+ {/* Entry Modules — 1×4 横向小卡片 */}
79
+ <div className="px-[16px] mb-[20px]">
80
+ <div className="flex gap-[8px]">
81
+ {entryModules.map((mod, i) => (
82
+ <motion.div
83
+ key={mod.desc}
84
+ className="relative flex-1 min-w-0 rounded-[16px] overflow-hidden bg-black/[0.04] p-[10px] pb-[20px] cursor-pointer active:scale-[0.97] transition-transform"
85
+ initial={{ opacity: 0, y: 10 }}
86
+ animate={{ opacity: 1, y: 0 }}
87
+ transition={{ delay: 0.05 * i, duration: 0.3, type: "spring" }}
88
+ >
89
+ <div className="relative z-[1]">
90
+ <div className="text-[20px] font-semibold leading-[26px] tracking-tight text-foreground">
91
+ {mod.value}
92
+ </div>
93
+ <div className="text-[10px] text-muted-foreground leading-[14px] mt-[2px]">
94
+ {mod.desc}
95
+ </div>
96
+ </div>
97
+ <div className="absolute right-[-2px] bottom-[-2px] size-[36px] z-0">
98
+ <div
99
+ className="size-full rounded-[8px] overflow-hidden"
100
+ style={{ transform: `rotate(${mod.rotate})` }}
101
+ >
102
+ <ImageWithFallback
103
+ src={mod.image}
104
+ alt={mod.desc}
105
+ className="size-full object-cover"
106
+ />
107
+ </div>
108
+ </div>
109
+ </motion.div>
110
+ ))}
111
+ </div>
112
+ </div>
113
+
114
+ {/* Menu List */}
115
+ <div className="px-[16px] mb-[20px]">
116
+ <div className="rounded-[20px] bg-card-muted overflow-hidden">
117
+ {menuItems.map((item, index) => (
118
+ <div key={item.label}>
119
+ <div className="flex items-center gap-[12px] px-[16px] py-[14px] active:bg-black/[0.03] cursor-pointer transition-colors">
120
+ <IconFont name={item.icon} size="20px" className="text-foreground shrink-0" />
121
+ <span className="flex-1 text-[14px] text-foreground leading-[20px]">{item.label}</span>
122
+ {item.badge && (
123
+ <Tag label={item.badge} size="sm" className="bg-black/[0.04] text-muted-foreground border-transparent" />
124
+ )}
125
+ <IconFont name="chevron-right" size="16px" className="text-muted-foreground" />
126
+ </div>
127
+ {index < menuItems.length - 1 && (
128
+ <div className="mx-[16px] h-px bg-black/[0.04]" />
129
+ )}
130
+ </div>
131
+ ))}
132
+ </div>
133
+ </div>
134
+
135
+ {/* Settings */}
136
+ <div className="px-[16px] mb-[20px]">
137
+ <span className="text-[14px] font-medium text-muted-foreground mb-[8px] block">设置</span>
138
+ <div className="rounded-[20px] bg-card-muted overflow-hidden">
139
+ <div className="flex items-center gap-[12px] px-[16px] py-[14px]">
140
+ <IconFont name="notification" size="20px" className="text-foreground" />
141
+ <span className="flex-1 text-[14px] text-foreground leading-[20px]">消息通知</span>
142
+ <Switch checked={notifications} onCheckedChange={setNotifications} />
143
+ </div>
144
+ <div className="mx-[16px] h-px bg-black/[0.04]" />
145
+ <div className="flex items-center gap-[12px] px-[16px] py-[14px]">
146
+ <IconFont name="mode-dark" size="20px" className="text-foreground" />
147
+ <span className="flex-1 text-[14px] text-foreground leading-[20px]">深色模式</span>
148
+ <Switch checked={darkMode} onCheckedChange={setDarkMode} />
149
+ </div>
150
+ </div>
151
+ </div>
152
+
153
+ {/* Logout */}
154
+ <div className="px-[16px] pb-[16px]">
155
+ <Btn
156
+ variant="secondary"
157
+ label="退出登录"
158
+ icon={null}
159
+ onClick={() => setShowLogout(true)}
160
+ className="w-full"
161
+ />
162
+ </div>
163
+ </div>
164
+ );
165
+
166
+ return (
167
+ <div className="relative w-full h-[100dvh] bg-background" style={{ fontFamily: "var(--font-family-sans)" }}>
168
+ {/* Logout Dialog */}
169
+ <Dialog
170
+ open={showLogout}
171
+ onOpenChange={setShowLogout}
172
+ variant="warning"
173
+ title="退出登录"
174
+ description="确定要退出当前账号吗?"
175
+ mainActionText="退出"
176
+ secondaryActionText="取消"
177
+ onMainAction={() => setShowLogout(false)}
178
+ onSecondaryAction={() => setShowLogout(false)}
179
+ />
180
+
181
+ <DraggablePanel
182
+ state={DRAWER_STATES.FULL}
183
+ fullScreenContent={meContent}
184
+ topToolbar={{ mode: "center-title", title: "我的", showBack: false, rightActionCount: 1 }}
185
+ showTopToolbarInStates={[DRAWER_STATES.FULL]}
186
+ >
187
+ {null}
188
+ </DraggablePanel>
189
+
190
+ {/* Bottom Navigation */}
191
+ <div className="absolute bottom-[16px] left-1/2 -translate-x-1/2 z-[1000]">
192
+ <BottomNavigationBar activeTab={activeTab} onTabChange={onTabChange} />
193
+ </div>
194
+ </div>
195
+ );
196
+ }