From e85f687c6b03fcf0a2ce4bbe6deb74d2d0b17eaf Mon Sep 17 00:00:00 2001 From: "Apple\\Apple" Date: Mon, 26 May 2025 23:06:55 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20feat:=20add=20notice=20modal=20comp?= =?UTF-8?q?onent=20with=20empty=20state=20support?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit introduces the following changes: - Create a reusable NoticeModal component to handle system announcements - Extract notice functionality from Home and HeaderBar components - Add loading and empty states using Semi UI illustrations - Implement "close for today" feature with localStorage - Support both light and dark mode for empty state illustrations - Add proper error handling and loading states - Improve code reusability and maintainability Breaking changes: None Related components: HeaderBar.js, Home/index.js, NoticeModal.js --- web/src/components/HeaderBar.js | 17 ++++++ web/src/components/NoticeModal.js | 94 +++++++++++++++++++++++++++++++ web/src/i18n/locales/en.json | 4 +- web/src/pages/Home/index.js | 60 ++++---------------- 4 files changed, 125 insertions(+), 50 deletions(-) create mode 100644 web/src/components/NoticeModal.js diff --git a/web/src/components/HeaderBar.js b/web/src/components/HeaderBar.js index d2c437a2..e872e1e3 100644 --- a/web/src/components/HeaderBar.js +++ b/web/src/components/HeaderBar.js @@ -6,6 +6,7 @@ import { useTranslation } from 'react-i18next'; import { API, getLogo, getSystemName, showSuccess } from '../helpers'; import fireworks from 'react-fireworks'; import { CN, GB } from 'country-flag-icons/react/3x2'; +import NoticeModal from './NoticeModal'; import { IconClose, @@ -18,6 +19,7 @@ import { IconUserSetting, IconCreditCard, IconKey, + IconBell, } from '@douyinfe/semi-icons'; import { Avatar, @@ -41,6 +43,7 @@ const HeaderBar = () => { const [currentLang, setCurrentLang] = useState(i18n.language); const [mobileMenuOpen, setMobileMenuOpen] = useState(false); const location = useLocation(); + const [noticeVisible, setNoticeVisible] = useState(false); const systemName = getSystemName(); const logo = getLogo(); @@ -357,6 +360,11 @@ const HeaderBar = () => { return (
+ setNoticeVisible(false)} + isMobile={styleState.isMobile} + />
@@ -456,6 +464,15 @@ const HeaderBar = () => { )} + + +
+ )} + size={isMobile ? 'full-width' : 'large'} + > + {renderContent()} + + ); +}; + +export default NoticeModal; \ No newline at end of file diff --git a/web/src/i18n/locales/en.json b/web/src/i18n/locales/en.json index 0be5fcbe..e64452f8 100644 --- a/web/src/i18n/locales/en.json +++ b/web/src/i18n/locales/en.json @@ -1529,5 +1529,7 @@ "系统公告": "System Notice", "今日关闭": "Close Today", "关闭公告": "Close Notice", - "搜索条件": "Search Conditions" + "搜索条件": "Search Conditions", + "加载中...": "Loading...", + "暂无公告": "No Notice" } \ No newline at end of file diff --git a/web/src/pages/Home/index.js b/web/src/pages/Home/index.js index e88b0716..f676fe69 100644 --- a/web/src/pages/Home/index.js +++ b/web/src/pages/Home/index.js @@ -1,5 +1,5 @@ import React, { useContext, useEffect, useState } from 'react'; -import { Button, Typography, Tag, Modal } from '@douyinfe/semi-ui'; +import { Button, Typography, Tag } from '@douyinfe/semi-ui'; import { API, showError, isMobile } from '../../helpers'; import { StatusContext } from '../../context/Status'; import { marked } from 'marked'; @@ -7,6 +7,7 @@ import { useTranslation } from 'react-i18next'; import { IconGithubLogo } from '@douyinfe/semi-icons'; import exampleImage from '../../images/example.png'; import { Link } from 'react-router-dom'; +import NoticeModal from '../../components/NoticeModal'; import { Moonshot, OpenAI, XAI, Zhipu, Volcengine, Cohere, Claude, Gemini, Suno, Minimax, Wenxin, Spark, Qingyan, DeepSeek, Qwen, Midjourney, Grok, AzureAI, Hunyuan, Xinference } from '@lobehub/icons'; const { Text } = Typography; @@ -17,38 +18,16 @@ const Home = () => { const [homePageContentLoaded, setHomePageContentLoaded] = useState(false); const [homePageContent, setHomePageContent] = useState(''); const [noticeVisible, setNoticeVisible] = useState(false); - const [noticeContent, setNoticeContent] = useState(''); const isDemoSiteMode = statusState?.status?.demo_site_enabled || false; - const handleCloseNotice = () => { - setNoticeVisible(false); - }; - - const handleCloseTodayNotice = () => { + useEffect(() => { + const lastCloseDate = localStorage.getItem('notice_close_date'); const today = new Date().toDateString(); - localStorage.setItem('notice_close_date', today); - setNoticeVisible(false); - }; - - const displayNotice = async () => { - const res = await API.get('/api/notice'); - const { success, message, data } = res.data; - if (success) { - if (data !== '') { - const htmlNotice = marked.parse(data); - setNoticeContent(htmlNotice); - const lastCloseDate = localStorage.getItem('notice_close_date'); - const today = new Date().toDateString(); - - if (lastCloseDate !== today) { - setNoticeVisible(true); - } - } - } else { - showError(message); + if (lastCloseDate !== today) { + setNoticeVisible(true); } - }; + }, []); const displayHomePageContent = async () => { setHomePageContent(localStorage.getItem('home_page_content') || ''); @@ -81,33 +60,16 @@ const Home = () => { }; useEffect(() => { - displayNotice().then(); displayHomePageContent().then(); }, []); return (
- - - -
- )} - size={isMobile() ? 'full-width' : 'large'} - > -
- + onClose={() => setNoticeVisible(false)} + isMobile={isMobile()} + /> {homePageContentLoaded && homePageContent === '' ? (
{/* Banner 部分 */}