@@ -27,6 +27,8 @@ import {
2727 RefreshCw ,
2828 Eye ,
2929 ChevronRight ,
30+ ChevronDown ,
31+ Mail ,
3032 Settings as SettingsIcon ,
3133} from "lucide-react" ;
3234import { useLocale , useTranslation } from "@/lib/i18n" ;
@@ -719,17 +721,33 @@ function ReaderPreferencesPanel() {
719721}
720722/* ── About Panel ── */
721723/* ═══════════════════════════════════════════
722- About Panel — 品牌展示卡 + 技术栈
724+ About Panel — 品牌展示卡 + 技术栈 + 社区与支持
723725 ═══════════════════════════════════════════ */
724726function AboutPanel ( ) {
725727 const t = useTranslation ( ) ;
728+ const feedbackEmail = "nowenlab@qq.com" ;
729+ const feedbackQqGroupNumber = "1093473044" ;
730+ const feedbackMailto = `mailto:${ feedbackEmail } ?subject=${ encodeURIComponent ( "[NowenReader 反馈]" ) } ` ;
731+ const releaseUrl = "https://github.com/cropflre/nowen-reader/releases" ;
732+ const noteAssetRevision = "9b18e950cff87fde86f2812759277931c313b125" ;
733+ const noteAssetBase = `https://raw.githubusercontent.com/cropflre/nowen-note/${ noteAssetRevision } /frontend/src/assets` ;
734+ const communityQr = `${ noteAssetBase } /community/nowen-lab-wechat.jpg` ;
735+ const qqGroupQr = `${ noteAssetBase } /feedback/qq-group.jpg` ;
736+ const wechatSponsorQr = `${ noteAssetBase } /sponsor/weixin.jpg` ;
737+ const alipaySponsorQr = `${ noteAssetBase } /sponsor/zhifubao.png` ;
738+ const [ showSponsor , setShowSponsor ] = useState ( false ) ;
726739 const [ versionInfo , setVersionInfo ] = useState < { version : string ; uptime : string ; runtime ?: { go : string ; os : string ; arch : string ; cpus : number ; goroutines : number ; memoryMB : number } } | null > ( null ) ;
727740
728741 useEffect ( ( ) => {
729742 fetch ( apiPath ( "/api/health" ) )
730- . then ( ( res ) => res . json ( ) )
743+ . then ( ( res ) => {
744+ if ( ! res . ok ) throw new Error ( `health request failed: ${ res . status } ` ) ;
745+ return res . json ( ) ;
746+ } )
731747 . then ( ( data ) => setVersionInfo ( data ) )
732- . catch ( ( ) => { } ) ;
748+ . catch ( ( error ) => {
749+ console . error ( "[AboutPanel] Failed to load version info:" , error ) ;
750+ } ) ;
733751 } , [ ] ) ;
734752
735753 const techStack = [
@@ -747,7 +765,6 @@ function AboutPanel() {
747765 { /* Brand Card */ }
748766 < div className = "overflow-hidden rounded-lg border border-border bg-card p-6 sm:p-8" >
749767 < div className = "flex flex-col items-center gap-4 text-center" >
750- { /* Logo */ }
751768 < div className = "flex h-16 w-16 items-center justify-center rounded-lg bg-accent" >
752769 < BookOpen className = "h-8 w-8 text-white" />
753770 </ div >
@@ -758,7 +775,7 @@ function AboutPanel() {
758775 </ p >
759776 </ div >
760777 < div className = "flex items-center gap-2 flex-wrap justify-center" >
761- < span className = "inline-flex items-center gap-1.5 rounded-full bg-accent/10 px-3 py-1 text-xs font-medium text-accent" >
778+ < span className = "inline-flex items-center gap-1.5 rounded-full bg-accent/10 px-3 py-1 text-xs font-medium text-accent" title = "当前版本" >
762779 < Sparkles className = "h-3 w-3" />
763780 { formatAppVersion ( versionInfo ?. version ) }
764781 </ span >
@@ -805,8 +822,138 @@ function AboutPanel() {
805822 </ div >
806823 </ div >
807824
825+ { /* Nowen 开源实验室 */ }
826+ < div className = "flex flex-col gap-4 rounded-lg border border-border bg-card p-5 sm:flex-row sm:items-center sm:justify-between" >
827+ < div className = "flex min-w-0 items-start gap-3" >
828+ < span className = "flex h-9 w-9 shrink-0 items-center justify-center rounded-lg bg-accent/10 text-accent" >
829+ < Globe className = "h-4 w-4" />
830+ </ span >
831+ < div className = "min-w-0" >
832+ < div className = "text-sm font-medium text-foreground" > Nowen 开源实验室</ div >
833+ < div className = "mt-0.5 text-xs leading-relaxed text-muted" > 扫码关注公众号,获取 Nowen 最新动态。</ div >
834+ </ div >
835+ </ div >
836+ < img
837+ src = { communityQr }
838+ alt = "Nowen 开源实验室公众号二维码"
839+ className = "h-28 w-28 self-center rounded-lg bg-white object-contain p-1 sm:self-auto"
840+ loading = "lazy"
841+ draggable = { false }
842+ />
843+ </ div >
844+
845+ { /* 更新日志 */ }
846+ < a
847+ href = { releaseUrl }
848+ target = "_blank"
849+ rel = "noopener noreferrer"
850+ className = "flex min-h-20 items-center justify-between gap-4 rounded-lg border border-border bg-card p-5 text-left transition-colors hover:border-accent/30 hover:bg-card-hover/50"
851+ >
852+ < div className = "flex min-w-0 items-center gap-3" >
853+ < span className = "flex h-9 w-9 shrink-0 items-center justify-center rounded-lg bg-accent/10 text-accent" >
854+ < Sparkles className = "h-4 w-4" />
855+ </ span >
856+ < div className = "min-w-0" >
857+ < div className = "text-sm font-medium text-foreground" > 更新日志</ div >
858+ < div className = "mt-0.5 text-xs text-muted" > 查看本版新功能与历次修复</ div >
859+ </ div >
860+ </ div >
861+ < span className = "inline-flex shrink-0 items-center gap-1 text-xs text-muted transition-colors group-hover:text-accent" >
862+ 查看更新
863+ < ExternalLink className = "h-3 w-3" />
864+ </ span >
865+ </ a >
866+
867+ { /* 意见与 Bug 反馈 */ }
868+ < a
869+ href = { feedbackMailto }
870+ className = "flex min-h-20 items-center justify-between gap-4 rounded-lg border border-border bg-card p-5 text-left transition-colors hover:border-accent/30 hover:bg-card-hover/50"
871+ >
872+ < div className = "flex min-w-0 items-center gap-3" >
873+ < span className = "flex h-9 w-9 shrink-0 items-center justify-center rounded-lg bg-sky-500/10 text-sky-500" >
874+ < Mail className = "h-4 w-4" />
875+ </ span >
876+ < div className = "min-w-0" >
877+ < div className = "text-sm font-medium text-foreground" > 意见与 Bug 反馈</ div >
878+ < div className = "mt-0.5 text-xs leading-relaxed text-muted" > 遇到问题或有功能建议,欢迎通过邮件联系我们。</ div >
879+ < div className = "mt-1 text-[11px] text-muted/70" > { feedbackEmail } </ div >
880+ </ div >
881+ </ div >
882+ < span className = "shrink-0 text-xs text-muted" > 发送邮件</ span >
883+ </ a >
884+
885+ { /* 加入 QQ 群反馈 */ }
886+ < div className = "flex flex-col gap-4 rounded-lg border border-border bg-card p-5 sm:flex-row sm:items-center sm:justify-between" >
887+ < div className = "flex min-w-0 items-start gap-3" >
888+ < span className = "flex h-9 w-9 shrink-0 items-center justify-center rounded-lg bg-sky-500/10 text-sky-500" >
889+ < Users className = "h-4 w-4" />
890+ </ span >
891+ < div className = "min-w-0" >
892+ < div className = "text-sm font-medium text-foreground" > 加入 QQ 群反馈</ div >
893+ < div className = "mt-0.5 text-xs leading-relaxed text-muted" > 扫码加入 nowen 开发群,也可搜索群号加入。</ div >
894+ < div className = "mt-1 text-xs font-medium text-foreground" > QQ群:{ feedbackQqGroupNumber } </ div >
895+ </ div >
896+ </ div >
897+ < img
898+ src = { qqGroupQr }
899+ alt = { `Nowen 开发群 QQ 群 ${ feedbackQqGroupNumber } 二维码` }
900+ className = "h-28 w-28 self-center rounded-lg bg-white object-contain p-1 sm:self-auto"
901+ loading = "lazy"
902+ draggable = { false }
903+ />
904+ </ div >
905+
906+ { /* 支持作者 */ }
907+ < div className = "overflow-hidden rounded-lg border border-border bg-card" >
908+ < button
909+ type = "button"
910+ onClick = { ( ) => setShowSponsor ( ( current ) => ! current ) }
911+ aria-expanded = { showSponsor }
912+ aria-controls = "about-sponsor-codes"
913+ className = "flex min-h-20 w-full items-center justify-between gap-4 p-5 text-left transition-colors hover:bg-card-hover/50"
914+ >
915+ < div className = "flex min-w-0 items-center gap-3" >
916+ < span className = "flex h-9 w-9 shrink-0 items-center justify-center rounded-lg bg-rose-500/10 text-rose-500" >
917+ < Heart className = "h-4 w-4" />
918+ </ span >
919+ < div className = "min-w-0" >
920+ < div className = "text-sm font-medium text-foreground" > 支持作者</ div >
921+ < div className = "mt-0.5 text-xs leading-relaxed text-muted" > 如果这个项目对你有帮助,欢迎请作者喝杯咖啡 ☕</ div >
922+ </ div >
923+ </ div >
924+ < span className = "inline-flex shrink-0 items-center gap-1 text-xs text-muted" >
925+ { showSponsor ? "收起赞赏码" : "展开赞赏码" }
926+ < ChevronDown className = { `h-3.5 w-3.5 transition-transform ${ showSponsor ? "rotate-180" : "" } ` } />
927+ </ span >
928+ </ button >
929+ { showSponsor && (
930+ < div id = "about-sponsor-codes" className = "grid gap-4 border-t border-border/30 bg-background/30 p-5 sm:grid-cols-2" >
931+ < div className = "flex flex-col items-center gap-2 rounded-lg border border-border/50 bg-card p-3" >
932+ < img
933+ src = { wechatSponsorQr }
934+ alt = "微信赞赏码"
935+ className = "h-40 w-40 rounded-lg bg-white object-contain p-1"
936+ loading = "lazy"
937+ draggable = { false }
938+ />
939+ < span className = "text-xs font-medium text-foreground" > 微信赞赏</ span >
940+ </ div >
941+ < div className = "flex flex-col items-center gap-2 rounded-lg border border-border/50 bg-card p-3" >
942+ < img
943+ src = { alipaySponsorQr }
944+ alt = "支付宝赞赏码"
945+ className = "h-40 w-40 rounded-lg bg-white object-contain p-1"
946+ loading = "lazy"
947+ draggable = { false }
948+ />
949+ < span className = "text-xs font-medium text-foreground" > 支付宝赞赏</ span >
950+ </ div >
951+ </ div >
952+ ) }
953+ </ div >
954+
808955 { /* Links */ }
809- < div className = "flex items-center justify-center gap-4" >
956+ < div className = "flex flex-wrap items-center justify-center gap-4" >
810957 < a
811958 href = "https://github.com/cropflre/nowen-reader"
812959 target = "_blank"
@@ -835,4 +982,4 @@ function AboutPanel() {
835982 </ p >
836983 </ div >
837984 ) ;
838- }
985+ }
0 commit comments