@@ -113,7 +113,7 @@ export function DownloadSection({
113113 const [ loading , setLoading ] = useState ( true ) ;
114114 const [ search , setSearch ] = useState ( "" ) ;
115115 const [ sortBy , setSortBy ] = useState < "semantic" | "releaseDate" | "downloadCount" > ( "semantic" ) ;
116- const [ sortOrder , setSortOrder ] = useState ( "desc" ) ;
116+ const [ sortOrder , setSortOrder ] = useState < "asc" | "desc" > ( "desc" ) ;
117117 const [ tags , setTags ] = useState < string [ ] > ( [ ] ) ;
118118 const [ selectedTag , setSelectedTag ] = useState < string | null > ( null ) ;
119119 const [ currentPage , setCurrentPage ] = useState ( 1 ) ;
@@ -260,8 +260,10 @@ export function DownloadSection({
260260 // Filter out prereleases if not needed
261261 const filteredData = showPrereleases ? data : data . filter ( release => ! release . prerelease ) ;
262262
263- // 修复:正确识别最新版本
264- const latestRelease = filteredData . find ( release => ! release . prerelease ) ?. id || null ;
263+ // 修复:正确识别最新版本(按发布时间排序取最新正式版)
264+ const latestRelease = filteredData
265+ . filter ( release => ! release . prerelease )
266+ . sort ( ( a , b ) => new Date ( b . published_at ) . getTime ( ) - new Date ( a . published_at ) . getTime ( ) ) [ 0 ] ?. id || null ;
265267
266268 const parsedReleases : ParsedRelease [ ] = filteredData . map ( ( release ) => {
267269 const mcVersionMatch = release . tag_name . match ( / ^ ( \d + \. \d + \. \d + ) / ) ;
@@ -329,82 +331,53 @@ export function DownloadSection({
329331 }
330332 }
331333
332- const compareVersionStrings = ( v1 : string , v2 : string ) => {
334+ // 🌟 核心修复:完整语义化版本比较(支持正式版 > 预发布版,解决2.0排在1.x前面的问题)
335+ const compareSemanticVersions = ( v1 : string , v2 : string ) : number => {
336+ // 解析版本:分离 主版本号 + 预发布后缀(如 v9-2.0 → [9,2,0], 无后缀;v9-b2 → [9], 后缀 b2)
333337 const parseVersion = ( version : string ) => {
334- const match = version . match ( / ^ E n d l e s s P i x e l - ( \d + \. \d + \. \d + ) - v ( \d + ) - ( .* ) $ / i) ;
335-
336- if ( ! match ) {
337- return {
338- mcVersion : "0.0.0" ,
339- modVersion : 0 ,
340- buildType : "" ,
341- buildNum : 0 ,
342- fullVersion : version
343- } ;
344- }
345-
346- const [ , mcVersion , modVersionStr , buildInfo ] = match ;
347- const modVersion = parseInt ( modVersionStr , 10 ) ;
348-
349- let buildType = "release" ;
350- let buildNum = 0 ;
351-
352- const betaMatch = buildInfo . match ( / ^ b ( \d + ) $ / i) ;
353- if ( betaMatch ) {
354- buildType = "beta" ;
355- buildNum = parseInt ( betaMatch [ 1 ] , 10 ) ;
356- } else {
357- const releaseMatch = buildInfo . match ( / ^ ( \d + (?: \. \d + ) * ) $ / ) ;
358- if ( releaseMatch ) {
359- const versionParts = releaseMatch [ 1 ] . split ( "." ) . map ( Number ) ;
360- buildNum = versionParts [ 0 ] * 1000 + ( versionParts [ 1 ] || 0 ) * 10 + ( versionParts [ 2 ] || 0 ) ;
361- }
362- }
363-
364- return {
365- mcVersion,
366- modVersion,
367- buildType,
368- buildNum,
369- fullVersion : version
370- } ;
338+ // 匹配预发布后缀(-b/-beta/-rc 等开头)
339+ const preReleaseMatch = version . match ( / - ( [ a - z A - Z ] + .* ) $ / ) ;
340+ const preRelease = preReleaseMatch ? preReleaseMatch [ 1 ] : '' ;
341+ // 提取主版本号的数字部分(忽略前缀,只取数字序列)
342+ const mainParts = ( preRelease ? version . replace ( / - [ a - z A - Z ] + .* $ / , '' ) : version )
343+ . match ( / \d + / g) ?. map ( Number ) || [ ] ;
344+ return { mainParts, preRelease } ;
371345 } ;
372346
373- const v1Info = parseVersion ( v1 ) ;
374- const v2Info = parseVersion ( v2 ) ;
375-
376- if ( v1Info . mcVersion !== v2Info . mcVersion ) {
377- const mcParts1 = v1Info . mcVersion . split ( "." ) . map ( Number ) ;
378- const mcParts2 = v2Info . mcVersion . split ( "." ) . map ( Number ) ;
347+ const { mainParts : p1 , preRelease : pr1 } = parseVersion ( v1 ) ;
348+ const { mainParts : p2 , preRelease : pr2 } = parseVersion ( v2 ) ;
379349
380- for ( let i = 0 ; i < 3 ; i ++ ) {
381- if ( mcParts1 [ i ] !== mcParts2 [ i ] ) {
382- return mcParts2 [ i ] - mcParts1 [ i ] ;
383- }
384- }
385- }
386-
387- if ( v1Info . modVersion !== v2Info . modVersion ) {
388- return v2Info . modVersion - v1Info . modVersion ;
350+ // 1. 先比较主版本号(核心逻辑)
351+ const maxLen = Math . max ( p1 . length , p2 . length ) ;
352+ for ( let i = 0 ; i < maxLen ; i ++ ) {
353+ const num1 = p1 [ i ] || 0 ;
354+ const num2 = p2 [ i ] || 0 ;
355+ if ( num1 > num2 ) return 1 ;
356+ if ( num1 < num2 ) return - 1 ;
389357 }
390358
391- if ( v1Info . buildType !== v2Info . buildType ) {
392- if ( v1Info . buildType === "release" ) return - 1 ;
393- if ( v2Info . buildType === "release" ) return 1 ;
394- }
359+ // 2. 主版本号相同 → 正式版 > 预发布版
360+ if ( ! pr1 && pr2 ) return 1 ; // v1是正式版,v2是预发布版 → v1大
361+ if ( pr1 && ! pr2 ) return - 1 ; // v1是预发布版,v2是正式版 → v2大
395362
396- if ( v1Info . buildNum !== v2Info . buildNum ) {
397- return v2Info . buildNum - v1Info . buildNum ;
363+ // 3. 都是预发布版 → 比较后缀(如 b2 > b1)
364+ if ( pr1 && pr2 ) {
365+ // 提取后缀里的数字(b2 → 2, b10 →10)
366+ const getPreNum = ( pr : string ) => Number ( pr . match ( / \d + / ) ?. [ 0 ] || 0 ) ;
367+ return getPreNum ( pr1 ) - getPreNum ( pr2 ) ;
398368 }
399369
400- return v1Info . fullVersion . localeCompare ( v2Info . fullVersion ) ;
370+ // 版本完全相同
371+ return 0 ;
401372 } ;
402373
374+ // 修复语义化排序逻辑
403375 const semanticCompare = ( a : ParsedRelease , b : ParsedRelease ) => {
404376 if ( a . isLatest && ! b . isLatest ) return - 1 ;
405377 if ( ! a . isLatest && b . isLatest ) return 1 ;
406378
407- return compareVersionStrings ( a . version , b . version ) ; // 修复:使用version而不是name
379+ // 使用修复后的语义化比较函数
380+ return compareSemanticVersions ( a . version , b . version ) ;
408381 } ;
409382
410383 const filteredReleases = releases
@@ -416,7 +389,8 @@ export function DownloadSection({
416389 . filter ( ( release ) => ( selectedTag ? release . tags ?. includes ( selectedTag ) : true ) )
417390 . sort ( ( a , b ) => {
418391 if ( sortBy === "semantic" ) {
419- return sortOrder === "asc" ? - semanticCompare ( a , b ) : semanticCompare ( a , b ) ;
392+ // 排序方向:desc → 新版本在前,asc → 旧版本在前
393+ return sortOrder === "asc" ? semanticCompare ( a , b ) : - semanticCompare ( a , b ) ;
420394 }
421395
422396 const compare = ( key : "releaseDate" | "downloadCount" ) => {
@@ -776,14 +750,36 @@ export function DownloadSection({
776750
777751 { /* Footer Note */ }
778752 < div className = "text-center text-sm text-slate-500 dark:text-slate-400 mt-8 p-4 bg-slate-50 dark:bg-slate-800/30 rounded-lg border border-slate-200 dark:border-slate-700" >
779- < p >
780- 加速下载由
781- < a href = "https://gh-proxy.com/ " target = "_blank" rel = "noopener noreferrer" className = "text-blue-500 hover:text-blue-600 dark:text-blue-400 dark:hover:text-blue-300 underline" > gh-proxy.com </ a >
782- < a href = "https://gh.imixc.top/ " target = "_blank" rel = "noopener noreferrer" className = "text-blue-500 hover:text-blue-600 dark:text-blue-400 dark:hover:text-blue-300 underline" > gh.imixc.top </ a >
783- < a href = "https://gh.jasonzeng.dev/ " target = "_blank" rel = "noopener noreferrer" className = "text-blue-500 hover:text-blue-600 dark:text-blue-400 dark:hover:text-blue-300 underline" > gh.jasonzeng.dev</ a >
784- 提供。
785- 如遇下载问题,请尝试不同的镜像链接。
753+ < p className = "mb-3" >
754+ 加速下载服务由以下镜像站点提供:
786755 </ p >
756+
757+ < div className = "flex flex-wrap gap-2" >
758+ < a
759+ href = "https://gh-proxy.com/"
760+ target = "_blank"
761+ rel = "noopener noreferrer"
762+ className = "px-4 py-2 bg-blue-500 text-white hover:bg-blue-600 dark:bg-blue-600 dark:hover:bg-blue-700 rounded-md transition-colors duration-200"
763+ >
764+ gh-proxy.com
765+ </ a >
766+ < a
767+ href = "https://gh.imixc.top/"
768+ target = "_blank"
769+ rel = "noopener noreferrer"
770+ className = "px-4 py-2 bg-blue-500 text-white hover:bg-blue-600 dark:bg-blue-600 dark:hover:bg-blue-700 rounded-md transition-colors duration-200"
771+ >
772+ gh.imixc.top
773+ </ a >
774+ < a
775+ href = "https://gh.jasonzeng.dev/"
776+ target = "_blank"
777+ rel = "noopener noreferrer"
778+ className = "px-4 py-2 bg-blue-500 text-white hover:bg-blue-600 dark:bg-blue-600 dark:hover:bg-blue-700 rounded-md transition-colors duration-200"
779+ >
780+ gh.jasonzeng.dev
781+ </ a >
782+ </ div >
787783 </ div >
788784 </ div >
789785 ) ;
@@ -810,6 +806,11 @@ function ReleaseCard({ release, isExpanded, onToggleExpand }: ReleaseCardProps)
810806 return "bg-blue-100 text-blue-800 border-blue-300 dark:bg-blue-900/30 dark:text-blue-300" ;
811807 }
812808
809+ // 🌟 修复:镜像链接拼接(去掉多余空格,和官网格式一致)
810+ const getMirrorUrl = ( host : string , originalUrl : string ) => {
811+ return `${ host } /${ originalUrl } ` ;
812+ } ;
813+
813814 return (
814815 < Card className = { `
815816 relative overflow-hidden transition-all duration-300 hover:shadow-lg
@@ -874,32 +875,32 @@ function ReleaseCard({ release, isExpanded, onToggleExpand }: ReleaseCardProps)
874875 const mirrors = [
875876 {
876877 name : "Cloudflare 主站(全球加速)" ,
877- url : ` https://gh-proxy.com/ ${ file . downloadUrl } ` ,
878+ url : getMirrorUrl ( " https://gh-proxy.org" , file . downloadUrl ) ,
878879 tag : "Cloudflare" ,
879880 } ,
880881 {
881882 name : "Fastly CDN" ,
882- url : ` https://cdn.gh-proxy.com/ ${ file . downloadUrl } ` ,
883+ url : getMirrorUrl ( " https://cdn.gh-proxy.org" , file . downloadUrl ) ,
883884 tag : "Fastly" ,
884885 } ,
885886 {
886887 name : "Edgeone 全球加速" ,
887- url : ` https://edgeone.gh-proxy.com/ ${ file . downloadUrl } ` ,
888+ url : getMirrorUrl ( " https://edgeone.gh-proxy.org" , file . downloadUrl ) ,
888889 tag : "Edgeone" ,
889890 } ,
890891 {
891892 name : "Jasonzeng 文件代理加速" ,
892- url : ` https://gh.xmly.dev/ ${ file . downloadUrl } ` ,
893+ url : getMirrorUrl ( " https://gh.xmly.dev" , file . downloadUrl ) ,
893894 tag : "Jasonzeng" ,
894895 } ,
895896 {
896897 name : "Imixc 国内高速下载" ,
897- url : ` https://gh.imixc.top/ ${ file . downloadUrl } ` ,
898+ url : getMirrorUrl ( " https://gh.imixc.top" , file . downloadUrl ) ,
898899 tag : "Imixc" ,
899900 } ,
900901 {
901902 name : "香港 国内线路优化,secbit.ai&Sharon CDN赞助" ,
902- url : ` https://hk.gh-proxy.com/ ${ file . downloadUrl } ` ,
903+ url : getMirrorUrl ( " https://hk.gh-proxy.org" , file . downloadUrl ) ,
903904 tag : "香港" ,
904905 tip : "大文件下载不建议使用!" ,
905906 } ,
@@ -995,7 +996,7 @@ function ReleaseCard({ release, isExpanded, onToggleExpand }: ReleaseCardProps)
995996 </ Button >
996997
997998 { showChangelog && (
998- < div className = "mt-4 p-4 bg-slate-50 dark:bg-slate-800/50 rounded-xl border border-slate-200 dark:border-slate-700 prose prose-sm max-w-none dark:prose-invert wrap-break-word" >
999+ < div className = "mt-4 p-4 bg-slate-50 dark:bg-slate-800/50 rounded-xl border border-slate-200 dark:border-slate-700 prose prose-sm max-w-none dark:prose-invert wrap-break-word overflow-auto max-h-60 " >
9991000 < ReactMarkdown
10001001 rehypePlugins = { [ rehypeRaw ] }
10011002 remarkPlugins = { [ remarkGfm ] }
0 commit comments