373373 }
374374 .chk-link : hover { color : var (--text ); border-color : var (--border-h ); background : rgba (255 , 255 , 255 , .04 ); }
375375
376+ .source-toggle {
377+ display : flex;
378+ align-items : center;
379+ gap : 6px ;
380+ margin-top : 12px ;
381+ padding-top : 12px ;
382+ border-top : 1px solid var (--border );
383+ }
384+ .source-label {
385+ font-size : 0.74rem ;
386+ color : var (--text-muted );
387+ margin-right : 4px ;
388+ white-space : nowrap;
389+ }
390+ .source-btns {
391+ display : flex;
392+ gap : 2px ;
393+ background : rgba (10 , 20 , 34 , 0.7 );
394+ border : 1px solid var (--border );
395+ border-radius : 7px ;
396+ padding : 2px ;
397+ }
398+ .source-btn {
399+ padding : 3px 10px ;
400+ border-radius : 5px ;
401+ border : none;
402+ background : transparent;
403+ color : var (--text-muted );
404+ font-size : 0.72rem ;
405+ font-weight : 500 ;
406+ cursor : pointer;
407+ transition : background .15s , color .15s ;
408+ font-family : inherit;
409+ }
410+ .source-btn .active { background : var (--border-h ); color : var (--text ); }
411+ .source-btn : hover : not (.active ) { color : var (--text ); }
412+
376413 /* ─── SUBSCRIBE ──────────────────────────────────────────── */
377414 .subscribe-section {
378415 position : relative; z-index : 1 ;
@@ -584,6 +621,13 @@ <h3 data-i18n="subscribe-cn">Mainland China · Feishu</h3>
584621 < span data-i18n ="checksums "> SHA256 Checksums</ span >
585622 </ a >
586623 </ div >
624+ < div class ="source-toggle ">
625+ < span class ="source-label " data-i18n ="source-label "> Download source:</ span >
626+ < div class ="source-btns " id ="source-btns ">
627+ < button class ="source-btn " data-source ="github "> GitHub</ button >
628+ < button class ="source-btn " data-source ="cdn "> Sipeed CDN</ button >
629+ </ div >
630+ </ div >
587631 </ div >
588632 </ div >
589633
@@ -623,6 +667,7 @@ <h3 data-i18n="subscribe-cn">Mainland China · Feishu</h3>
623667 'sipeed-visit' : 'Visit Sipeed' ,
624668 'btn-repo' : 'PicoClaw Repo' ,
625669 'btn-docs' : 'Documentation' ,
670+ 'source-label' : 'Download source:' ,
626671 'subscribe-title' : 'Stay Connected' ,
627672 'subscribe-desc' : 'Subscribe for news and product updates.' ,
628673 'subscribe-global' : 'Global · Google Form' ,
@@ -650,6 +695,7 @@ <h3 data-i18n="subscribe-cn">Mainland China · Feishu</h3>
650695 'sipeed-visit' : '访问 Sipeed' ,
651696 'btn-repo' : 'PicoClaw 仓库' ,
652697 'btn-docs' : '文档' ,
698+ 'source-label' : '下载源:' ,
653699 'subscribe-title' : '保持联系' ,
654700 'subscribe-desc' : '订阅最新动态和产品更新。' ,
655701 'subscribe-global' : '全球用户 · Google 表单' ,
@@ -689,6 +735,7 @@ <h3 data-i18n="subscribe-cn">Mainland China · Feishu</h3>
689735
690736 function switchLang ( lang ) {
691737 currentLang = lang ;
738+ currentSource = lang === 'zh' ? 'cdn' : 'github' ;
692739 localStorage . setItem ( 'lang' , lang ) ;
693740 applyStaticLang ( ) ;
694741 if ( platformData ) buildCards ( platformData ) ;
@@ -741,8 +788,15 @@ <h3 data-i18n="subscribe-cn">Mainland China · Feishu</h3>
741788 ] ;
742789
743790 // ── Constants ─────────────────────────────────────────────────
744- const BASE_DL = 'https://github.com/sipeed/picoclaw/releases/latest/download/' ;
745- const RELEASES_URL = 'https://github.com/sipeed/picoclaw/releases/latest' ;
791+ const BASE_DL_GITHUB = 'https://github.com/sipeed/picoclaw/releases/latest/download/' ;
792+ const BASE_DL_CDN = 'https://picoclaw.sipeed.com/latest/' ;
793+ const RELEASES_URL = 'https://github.com/sipeed/picoclaw/releases/latest' ;
794+
795+ let currentSource = currentLang === 'zh' ? 'cdn' : 'github' ;
796+
797+ function getBaseDL ( ) {
798+ return currentSource === 'cdn' ? BASE_DL_CDN : BASE_DL_GITHUB ;
799+ }
746800 const ICON_CDN = 'https://cdn.simpleicons.org/' ;
747801
748802 const INLINE_ICONS = {
@@ -800,11 +854,10 @@ <h3 data-i18n="subscribe-cn">Mainland China · Feishu</h3>
800854 } ) ;
801855 }
802856
803- function openModal ( p ) {
804- document . getElementById ( 'modal-title-text' ) . textContent = p . name ;
805- document . getElementById ( 'modal-icon' ) . src = iconUrl ( p . icon , p . color ) ;
806- document . getElementById ( 'modal-icon' ) . alt = p . name ;
857+ let currentModalPlatform = null ;
807858
859+ function renderArchList ( p ) {
860+ const base = getBaseDL ( ) ;
808861 const list = document . getElementById ( 'arch-list' ) ;
809862 list . innerHTML = '' ;
810863
@@ -814,9 +867,9 @@ <h3 data-i18n="subscribe-cn">Mainland China · Feishu</h3>
814867 el = document . createElement ( 'div' ) ;
815868 el . className = 'arch-item arch-item--multi' ;
816869 const fmtBtns = [
817- `<a class="fmt-btn" href="${ BASE_DL + arch . file } " target="_blank" rel="noopener noreferrer">.tar.gz</a>` ,
818- `<a class="fmt-btn" href="${ BASE_DL + arch . packages . deb } " target="_blank" rel="noopener noreferrer">.deb</a>` ,
819- `<a class="fmt-btn" href="${ BASE_DL + arch . packages . rpm } " target="_blank" rel="noopener noreferrer">.rpm</a>` ,
870+ `<a class="fmt-btn" href="${ base + arch . file } " target="_blank" rel="noopener noreferrer">.tar.gz</a>` ,
871+ `<a class="fmt-btn" href="${ base + arch . packages . deb } " target="_blank" rel="noopener noreferrer">.deb</a>` ,
872+ `<a class="fmt-btn" href="${ base + arch . packages . rpm } " target="_blank" rel="noopener noreferrer">.rpm</a>` ,
820873 ] . join ( '' ) ;
821874 el . innerHTML = `
822875 <div class="arch-left">
@@ -827,7 +880,7 @@ <h3 data-i18n="subscribe-cn">Mainland China · Feishu</h3>
827880 } else {
828881 el = document . createElement ( 'a' ) ;
829882 el . className = 'arch-item' ;
830- el . href = BASE_DL + arch . file ;
883+ el . href = base + arch . file ;
831884 el . target = '_blank' ;
832885 el . rel = 'noopener noreferrer' ;
833886 el . innerHTML = `
@@ -839,11 +892,27 @@ <h3 data-i18n="subscribe-cn">Mainland China · Feishu</h3>
839892 }
840893 list . appendChild ( el ) ;
841894 } ) ;
895+ }
896+
897+ function updateSourceBtns ( ) {
898+ document . querySelectorAll ( '#source-btns .source-btn' ) . forEach ( btn => {
899+ btn . classList . toggle ( 'active' , btn . dataset . source === currentSource ) ;
900+ } ) ;
901+ }
902+
903+ function openModal ( p ) {
904+ currentModalPlatform = p ;
905+ document . getElementById ( 'modal-title-text' ) . textContent = p . name ;
906+ document . getElementById ( 'modal-icon' ) . src = iconUrl ( p . icon , p . color ) ;
907+ document . getElementById ( 'modal-icon' ) . alt = p . name ;
908+
909+ renderArchList ( p ) ;
910+ updateSourceBtns ( ) ;
842911
843912 document . getElementById ( 'backdrop' ) . classList . add ( 'open' ) ;
844913 document . body . style . overflow = 'hidden' ;
845914 requestAnimationFrame ( ( ) => {
846- const first = list . querySelector ( '.arch-item' ) ;
915+ const first = document . getElementById ( 'arch- list' ) . querySelector ( '.arch-item' ) ;
847916 if ( first ) first . focus ( ) ;
848917 } ) ;
849918 }
@@ -859,6 +928,14 @@ <h3 data-i18n="subscribe-cn">Mainland China · Feishu</h3>
859928 document . getElementById ( 'close-btn' ) . addEventListener ( 'click' , closeModal ) ;
860929 document . addEventListener ( 'keydown' , e => { if ( e . key === 'Escape' ) closeModal ( ) ; } ) ;
861930
931+ document . getElementById ( 'source-btns' ) . addEventListener ( 'click' , e => {
932+ const btn = e . target . closest ( '.source-btn' ) ;
933+ if ( ! btn ) return ;
934+ currentSource = btn . dataset . source ;
935+ updateSourceBtns ( ) ;
936+ if ( currentModalPlatform ) renderArchList ( currentModalPlatform ) ;
937+ } ) ;
938+
862939 applyStaticLang ( ) ;
863940 document . getElementById ( 'checksums-link' ) . href = RELEASES_URL ;
864941 buildCards ( PLATFORMS ) ;
0 commit comments