@@ -3,6 +3,9 @@ import { useTranslation } from 'react-i18next';
33import { experienceAdapter } from '../../services/experience-adapter' ;
44import { ExperienceRecord } from '../../services/experienceStorage' ;
55import RealmHelpTooltip from './RealmHelpTooltip' ;
6+ import ShareModal from '../ShareModal' ;
7+ import { learningPaths } from '../ProblemList/data/learningPaths' ;
8+ import { useCompletionStatus } from '../ProblemList/hooks/useCompletionStatus' ;
69import './ExperienceBar.css' ;
710
811interface ExperienceBarProps {
@@ -39,8 +42,8 @@ const REALMS: RealmInfo[] = [
3942 { name : '飞升仙界' , nameEn : 'Ascension' , translationKey : 'ascension' , color : '#fde68a' , icon : '✨' , bgGradient : 'linear-gradient(135deg, #0f1419 0%, #1a2332 50%, #0d1117 100%)' } ,
4043] ;
4144
42- const ExperienceBar : React . FC < ExperienceBarProps > = ( {
43- currentLang,
45+ const ExperienceBar : React . FC < ExperienceBarProps > = ( {
46+ currentLang,
4447 refreshTrigger,
4548 completedProblems = 0 ,
4649 totalProblems = 100
@@ -56,8 +59,11 @@ const ExperienceBar: React.FC<ExperienceBarProps> = ({
5659 const [ expGainAmount , setExpGainAmount ] = useState ( 0 ) ;
5760 const [ showHelpTooltip , setShowHelpTooltip ] = useState ( false ) ;
5861 const [ helpIconRect , setHelpIconRect ] = useState < DOMRect | null > ( null ) ;
62+ const [ showShareModal , setShowShareModal ] = useState ( false ) ;
5963 const helpIconRef = useRef < HTMLDivElement > ( null ) ;
6064
65+ const { getStatsForProblems } = useCompletionStatus ( ) ;
66+
6167 const loadExperience = useCallback ( async ( ) => {
6268 try {
6369 const exp = await experienceAdapter . getTotalExperience ( ) ;
@@ -111,6 +117,22 @@ const ExperienceBar: React.FC<ExperienceBarProps> = ({
111117 // 计算题目完成百分比
112118 const problemPercentage = totalProblems > 0 ? Math . round ( ( completedProblems / totalProblems ) * 100 ) : 0 ;
113119
120+ // 准备路径进度数据
121+ const getPathProgress = useCallback ( ( ) => {
122+ return learningPaths . map ( path => {
123+ const stats = getStatsForProblems ( [ ] ) ;
124+ return {
125+ id : path . id ,
126+ name : path . name ,
127+ nameEn : path . nameEn ,
128+ icon : path . icon ,
129+ color : path . color ,
130+ completed : 0 ,
131+ total : 10
132+ } ;
133+ } ) ;
134+ } , [ getStatsForProblems ] ) ;
135+
114136 return (
115137 < div className = "experience-bar-container" >
116138 < div className = "experience-bar-content" >
@@ -149,6 +171,22 @@ const ExperienceBar: React.FC<ExperienceBarProps> = ({
149171
150172 { /* 进度区域 */ }
151173 < div className = "progress-section" >
174+ { /* 分享按钮 */ }
175+ < button
176+ className = "share-button"
177+ onClick = { ( ) => setShowShareModal ( true ) }
178+ aria-label = { t ( 'share.shareProgress' , '分享进度' ) }
179+ >
180+ < svg viewBox = "0 0 24 24" fill = "none" stroke = "currentColor" strokeWidth = "2" >
181+ < circle cx = "18" cy = "5" r = "3" />
182+ < circle cx = "6" cy = "12" r = "3" />
183+ < circle cx = "18" cy = "19" r = "3" />
184+ < line x1 = "8.59" y1 = "13.51" x2 = "15.42" y2 = "17.49" />
185+ < line x1 = "15.41" y1 = "6.51" x2 = "8.59" y2 = "10.49" />
186+ </ svg >
187+ < span > { t ( 'share.share' , '分享' ) } </ span >
188+ </ button >
189+
152190 { /* 题目完成进度 */ }
153191 < div className = "problem-progress" >
154192 < div className = "problem-progress-info" >
@@ -160,17 +198,17 @@ const ExperienceBar: React.FC<ExperienceBarProps> = ({
160198 < span className = "problem-percentage" > { problemPercentage } %</ span >
161199 </ div >
162200 < div className = "problem-progress-track" >
163- < div
201+ < div
164202 className = "problem-progress-fill"
165203 style = { { width : `${ problemPercentage } %` } }
166204 />
167205 </ div >
168206 </ div >
169-
207+
170208 { /* 经验条 */ }
171209 < div className = "exp-bar-wrapper" >
172210 < div className = "exp-bar-track" >
173- < div
211+ < div
174212 className = "exp-bar-fill"
175213 style = { { width : `${ levelProgress } %` } }
176214 />
@@ -179,8 +217,8 @@ const ExperienceBar: React.FC<ExperienceBarProps> = ({
179217 < div className = "exp-bar-text" >
180218 < span className = "exp-current" > { experience . totalExp . toLocaleString ( ) } { t ( 'experience.exp' ) } </ span >
181219 < span className = "exp-next" >
182- { nextRealm
183- ? t ( 'experience.toNextRealm' , {
220+ { nextRealm
221+ ? t ( 'experience.toNextRealm' , {
184222 realm : t ( `realms.${ nextRealm . translationKey } ` ) ,
185223 exp : expToNextRealm . toLocaleString ( )
186224 } )
@@ -191,13 +229,32 @@ const ExperienceBar: React.FC<ExperienceBarProps> = ({
191229 </ div >
192230 </ div >
193231 </ div >
194-
232+
195233 { /* 经验值获取动画 */ }
196234 { showExpGain && (
197235 < div className = "exp-gain-popup" >
198236 +{ expGainAmount . toLocaleString ( ) } { t ( 'experience.exp' ) }
199237 </ div >
200238 ) }
239+
240+ { /* 分享弹窗 */ }
241+ < ShareModal
242+ isOpen = { showShareModal }
243+ onClose = { ( ) => setShowShareModal ( false ) }
244+ currentLang = { currentLang }
245+ totalExp = { experience . totalExp }
246+ currentRealm = { {
247+ name : currentRealm . name ,
248+ nameEn : currentRealm . nameEn ,
249+ icon : currentRealm . icon ,
250+ color : currentRealm . color
251+ } }
252+ realmProgress = { realmProgress }
253+ expToNextRealm = { expToNextRealm }
254+ completedProblems = { completedProblems }
255+ totalProblems = { totalProblems }
256+ pathProgress = { getPathProgress ( ) }
257+ />
201258 </ div >
202259 ) ;
203260} ;
0 commit comments