diff --git a/frontend/public/assets/reward.png b/frontend/public/assets/reward.png new file mode 100644 index 0000000..dafae02 Binary files /dev/null and b/frontend/public/assets/reward.png differ diff --git a/frontend/public/assets/wexin.png b/frontend/public/assets/wexin.png new file mode 100644 index 0000000..b72f4c5 Binary files /dev/null and b/frontend/public/assets/wexin.png differ diff --git a/frontend/src/components/icons/DiscordIcon.tsx b/frontend/src/components/icons/DiscordIcon.tsx new file mode 100644 index 0000000..b21e16d --- /dev/null +++ b/frontend/src/components/icons/DiscordIcon.tsx @@ -0,0 +1,20 @@ +import React from 'react'; + +export const DiscordIcon: React.FC> = (props) => { + return ( + + Discord + + + ); +}; + +export default DiscordIcon; diff --git a/frontend/src/components/icons/GitHubIcon.tsx b/frontend/src/components/icons/GitHubIcon.tsx new file mode 100644 index 0000000..afc9eb5 --- /dev/null +++ b/frontend/src/components/icons/GitHubIcon.tsx @@ -0,0 +1,21 @@ +import React from 'react'; + +export const GitHubIcon: React.FC> = (props) => { + return ( + + GitHub + + + ); +}; + + +export default GitHubIcon; diff --git a/frontend/src/components/icons/SponsorIcon.tsx b/frontend/src/components/icons/SponsorIcon.tsx new file mode 100644 index 0000000..0facfe0 --- /dev/null +++ b/frontend/src/components/icons/SponsorIcon.tsx @@ -0,0 +1,20 @@ +import React from 'react'; + +export const SponsorIcon: React.FC> = (props) => { + return ( + + Sponsor + + + ); +}; + +export default SponsorIcon; diff --git a/frontend/src/components/icons/WeChatIcon.tsx b/frontend/src/components/icons/WeChatIcon.tsx new file mode 100644 index 0000000..7e51a0b --- /dev/null +++ b/frontend/src/components/icons/WeChatIcon.tsx @@ -0,0 +1,20 @@ +import React from 'react'; + +export const WeChatIcon: React.FC> = (props) => { + return ( + + WeChat + + + ); +}; + +export default WeChatIcon; diff --git a/frontend/src/components/icons/discord.svg b/frontend/src/components/icons/discord.svg new file mode 100644 index 0000000..9d7796b --- /dev/null +++ b/frontend/src/components/icons/discord.svg @@ -0,0 +1 @@ +Discord \ No newline at end of file diff --git a/frontend/src/components/icons/github.svg b/frontend/src/components/icons/github.svg new file mode 100644 index 0000000..538ec5b --- /dev/null +++ b/frontend/src/components/icons/github.svg @@ -0,0 +1 @@ +GitHub \ No newline at end of file diff --git a/frontend/src/components/icons/sponsor.svg b/frontend/src/components/icons/sponsor.svg new file mode 100644 index 0000000..a0c0e1c --- /dev/null +++ b/frontend/src/components/icons/sponsor.svg @@ -0,0 +1 @@ +GitHub Sponsors \ No newline at end of file diff --git a/frontend/src/components/icons/wechat.svg b/frontend/src/components/icons/wechat.svg new file mode 100644 index 0000000..c3eb6c4 --- /dev/null +++ b/frontend/src/components/icons/wechat.svg @@ -0,0 +1 @@ +WeChat \ No newline at end of file diff --git a/frontend/src/components/layout/Header.tsx b/frontend/src/components/layout/Header.tsx index 52758c7..0e4b03a 100644 --- a/frontend/src/components/layout/Header.tsx +++ b/frontend/src/components/layout/Header.tsx @@ -1,15 +1,23 @@ -import React from 'react'; +import React, { useState } from 'react'; import { useTranslation } from 'react-i18next'; import { useAuth } from '@/contexts/AuthContext'; import ThemeSwitch from '@/components/ui/ThemeSwitch'; +import GitHubIcon from '@/components/icons/GitHubIcon'; +import SponsorIcon from '@/components/icons/SponsorIcon'; +import WeChatIcon from '@/components/icons/WeChatIcon'; +import DiscordIcon from '@/components/icons/DiscordIcon'; +import SponsorDialog from '@/components/ui/SponsorDialog'; +import WeChatDialog from '@/components/ui/WeChatDialog'; interface HeaderProps { onToggleSidebar: () => void; } const Header: React.FC = ({ onToggleSidebar }) => { - const { t } = useTranslation(); + const { t, i18n } = useTranslation(); const { auth } = useAuth(); + const [sponsorDialogOpen, setSponsorDialogOpen] = useState(false); + const [wechatDialogOpen, setWechatDialogOpen] = useState(false); return (
@@ -33,9 +41,46 @@ const Header: React.FC = ({ onToggleSidebar }) => { {/* Theme Switch and Version */}
{import.meta.env.PACKAGE_VERSION} + + + + {i18n.language === 'zh' ? ( + + ) : ( + + + + )} +
+ +
); }; diff --git a/frontend/src/components/ui/SponsorDialog.tsx b/frontend/src/components/ui/SponsorDialog.tsx new file mode 100644 index 0000000..9aaebd2 --- /dev/null +++ b/frontend/src/components/ui/SponsorDialog.tsx @@ -0,0 +1,60 @@ +import React from 'react'; +import { useTranslation } from 'react-i18next'; +import { X } from 'lucide-react'; + +interface SponsorDialogProps { + open: boolean; + onOpenChange: (open: boolean) => void; +} + +const SponsorDialog: React.FC = ({ open, onOpenChange }) => { + const { i18n, t } = useTranslation(); + + if (!open) return null; + + return ( +
+
+
+ {/* Close button (X) in the top-right corner */} + + +

+ {t('sponsor.title')} +

+ +
+ {i18n.language === 'zh' ? ( + {t('sponsor.rewardAlt')} + ) : ( +
+

{t('sponsor.supportMessage')}

+ + {t('sponsor.supportButton')} + +
+ )} +
+
+
+
+ ); +}; + +export default SponsorDialog; diff --git a/frontend/src/components/ui/WeChatDialog.tsx b/frontend/src/components/ui/WeChatDialog.tsx new file mode 100644 index 0000000..5bcb2f0 --- /dev/null +++ b/frontend/src/components/ui/WeChatDialog.tsx @@ -0,0 +1,49 @@ +import React from 'react'; +import { useTranslation } from 'react-i18next'; +import { X } from 'lucide-react'; + +interface WeChatDialogProps { + open: boolean; + onOpenChange: (open: boolean) => void; +} + +const WeChatDialog: React.FC = ({ open, onOpenChange }) => { + const { t } = useTranslation(); + + if (!open) return null; + + return ( +
+
+
+ {/* Close button (X) in the top-right corner */} + + +

+ {t('wechat.title')} +

+ +
+ {t('wechat.qrCodeAlt')} +

+ {t('wechat.scanMessage')} +

+
+
+
+
+ ); +}; + +export default WeChatDialog; diff --git a/frontend/src/locales/en.json b/frontend/src/locales/en.json index c6818eb..e9c41ad 100644 --- a/frontend/src/locales/en.json +++ b/frontend/src/locales/en.json @@ -26,6 +26,24 @@ "viewProfile": "View profile", "userCenter": "User Center" }, + "sponsor": { + "label": "Sponsor", + "title": "Support the Project", + "rewardAlt": "Reward QR Code", + "supportMessage": "Support the development of MCP Hub by buying me a coffee!", + "supportButton": "Support on Ko-fi" + }, + "wechat": { + "label": "WeChat", + "title": "Connect via WeChat", + "qrCodeAlt": "WeChat QR Code", + "scanMessage": "Scan this QR code to connect with us on WeChat" + }, + "discord": { + "label": "Discord", + "title": "Join our Discord server", + "community": "Join our growing community on Discord for support, discussions, and updates!" + }, "theme": { "title": "Theme", "light": "Light", diff --git a/frontend/src/locales/zh.json b/frontend/src/locales/zh.json index e6b3f4a..e89105c 100644 --- a/frontend/src/locales/zh.json +++ b/frontend/src/locales/zh.json @@ -26,6 +26,24 @@ "viewProfile": "查看个人中心", "userCenter": "个人中心" }, + "sponsor": { + "label": "赞助", + "title": "支持项目", + "rewardAlt": "赞赏码", + "supportMessage": "通过捐赠支持 MCP Hub 的开发!", + "supportButton": "在 Ko-fi 上支持" + }, + "wechat": { + "label": "微信", + "title": "微信联系", + "qrCodeAlt": "微信二维码", + "scanMessage": "扫描二维码添加微信" + }, + "discord": { + "label": "Discord", + "title": "加入我们的 Discord 服务器", + "community": "加入我们不断壮大的 Discord 社区,获取支持、参与讨论并了解最新动态!" + }, "theme": { "title": "主题", "light": "浅色",