From daef09265399a9cb3d3ace2e84dca4d390bb37dc Mon Sep 17 00:00:00 2001 From: LeonspaceX Date: Sat, 6 Dec 2025 13:10:45 +0800 Subject: [PATCH] =?UTF-8?q?=E7=BB=9F=E4=B8=80=E6=B7=B1=E8=89=B2=E6=A8=A1?= =?UTF-8?q?=E5=BC=8F=E6=A0=B7=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.css | 45 +++++++++++ src/App.tsx | 129 +++++++++--------------------- src/components/AdminPage.tsx | 2 - src/components/CommentSection.tsx | 3 +- 4 files changed, 84 insertions(+), 95 deletions(-) diff --git a/src/App.css b/src/App.css index edad5ed..d3ca705 100644 --- a/src/App.css +++ b/src/App.css @@ -25,3 +25,48 @@ .dark ::-webkit-scrollbar-thumb:hover { background: #3a3a3a; } + +/* react-markdown-editor-lite 深色模式适配 */ +body.dark-theme .rc-md-editor { + background-color: #292929; + border-color: #3e3e3e; + color: #e0e0e0; +} + +body.dark-theme .rc-md-editor .rc-md-navigation { + background-color: #333; + border-bottom-color: #3e3e3e; +} + +body.dark-theme .rc-md-editor .rc-md-navigation .button-wrap .button { + color: #e0e0e0; +} + +body.dark-theme .rc-md-editor .rc-md-navigation .button-wrap .button:hover { + background-color: #444; +} + +body.dark-theme .rc-md-editor .editor-container .section { + border-right-color: #3e3e3e; +} + +body.dark-theme .rc-md-editor .editor-container .sec-md .input { + background-color: #292929; + color: #e0e0e0; +} + +body.dark-theme .rc-md-editor .editor-container .sec-html { + background-color: #292929; + color: #e0e0e0; +} + +/* 预览区域的代码块样式适配 */ +body.dark-theme .rc-md-editor .editor-container .sec-html pre { + background-color: #1e1e1e; + border: 1px solid #3e3e3e; +} + +body.dark-theme .rc-md-editor .editor-container .sec-html code { + background-color: #1e1e1e; + color: #ce9178; +} \ No newline at end of file diff --git a/src/App.tsx b/src/App.tsx index 04a455e..db97e69 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,4 +1,4 @@ -// 你好,感谢你愿意看源代码,但是悄悄告诉你,代码其实是AI写的,所以质量很差喵。抱歉呜呜呜😭。 +// 你好,感谢你愿意看源代码,但是悄悄告诉你,代码其实是AI写的所以质量很差喵。抱歉呜呜呜😭。 import React, { useState, useEffect, useRef, useCallback } from 'react'; import { FluentProvider, webLightTheme, webDarkTheme, tokens } from '@fluentui/react-components'; @@ -6,10 +6,11 @@ import { BrowserRouter, Routes, Route } from 'react-router-dom'; import PostCard from './components/PostCard'; import MainLayout from './layouts/MainLayout'; import './App.css'; -import { fetchArticles, getNotice } from './api'; +import { fetchArticles } from './api'; import CreatePost from './components/CreatePost'; import { ToastContainer, toast } from 'react-toastify'; import 'react-toastify/dist/ReactToastify.css'; +import { Toaster } from 'react-hot-toast'; import AboutPage from './components/AboutPage'; import PostState from './components/PostState'; import ReportState from './components/ReportState'; @@ -17,10 +18,22 @@ import AdminPage from './components/AdminPage'; import InitPage from './pages/InitPage'; import NotFound from './pages/NotFound'; import ImageViewer from './components/ImageViewer'; -import NoticeModal from './components/NoticeModal'; function App() { - const [isDarkMode, setIsDarkMode] = React.useState(false); + const [isDarkMode, setIsDarkMode] = React.useState(() => { + const savedTheme = localStorage.getItem('theme'); + return savedTheme === 'dark'; + }); + + useEffect(() => { + localStorage.setItem('theme', isDarkMode ? 'dark' : 'light'); + if (isDarkMode) { + document.body.classList.add('dark-theme'); + } else { + document.body.classList.remove('dark-theme'); + } + }, [isDarkMode]); + const [articles, setArticles] = useState(0); const REFRESH_COOLDOWN_MS = 5000; // 刷新冷却时间 const [imageViewer, setImageViewer] = useState<{ open: boolean; src?: string; alt?: string }>({ open: false }); - const THEME_PREF_KEY = 'ThemePref'; - const userPrefRef = useRef(false); - const [noticeModal, setNoticeModal] = useState<{ open: boolean; type?: 'md' | 'url'; content?: string; version?: number }>({ open: false }); const openImageViewer = (src?: string, alt?: string) => { if (!src) return; @@ -71,16 +81,9 @@ function App() { if (containerRef.current) containerRef.current.scrollTop = 0; }; - const handleToggleTheme = () => { - setIsDarkMode(prev => { - const next = !prev; - try { - localStorage.setItem(THEME_PREF_KEY, next ? 'dark' : 'light'); - userPrefRef.current = true; - } catch {} - return next; - }); - }; + // 移除触摸下拉刷新逻辑 + + // 撤销 Pointer 事件回退,恢复为纯 Touch 逻辑 const onWheel: React.WheelEventHandler = (e) => { const atTop = (containerRef.current?.scrollTop ?? 0) <= 0; @@ -89,65 +92,6 @@ function App() { } }; - useEffect(() => { - const mql = typeof window !== 'undefined' && window.matchMedia ? window.matchMedia('(prefers-color-scheme: dark)') : null; - let handler: ((e: MediaQueryListEvent) => void) | null = null; - try { - const saved = localStorage.getItem(THEME_PREF_KEY); - if (saved === 'dark' || saved === 'light') { - userPrefRef.current = true; - setIsDarkMode(saved === 'dark'); - } else { - if (mql) { - setIsDarkMode(mql.matches); - handler = (e: MediaQueryListEvent) => { - if (!userPrefRef.current) { - setIsDarkMode(e.matches); - } - }; - if ('addEventListener' in mql) { - mql.addEventListener('change', handler); - } else { - // @ts-ignore - mql.addListener(handler); - } - } - } - } catch {} - return () => { - if (mql && handler) { - if ('removeEventListener' in mql) { - mql.removeEventListener('change', handler); - } else { - // @ts-ignore - mql.removeListener(handler); - } - } - }; - }, []); - - // 加载公告并根据版本控制显示 - useEffect(() => { - const loadNotice = async () => { - try { - const data = await getNotice(); - const ver = Number(data.version ?? 0) || 0; - if (ver === 0) return; // 版本为 0 不显示 - let storedVer = 0; - try { - const v = localStorage.getItem('notice_ver'); - storedVer = v ? Number(v) || 0 : 0; - } catch {} - if (!storedVer || ver > storedVer) { - setNoticeModal({ open: true, type: data.type === 'url' ? 'url' : 'md', content: String(data.content ?? ''), version: ver }); - } - } catch { - // 获取失败则不显示公告 - } - }; - loadNotice(); - }, []); - useEffect(() => { const controller = new AbortController(); const signal = controller.signal; @@ -185,7 +129,7 @@ function App() { - }> + setIsDarkMode(!isDarkMode)} />}> + {/* 刷新提示改为 toast,不显示顶部灰字 */} {articles.map((article, index) => { if (articles.length === index + 1 && hasMore) { return ( @@ -246,28 +192,29 @@ function App() { } /> } /> - } /> + setIsDarkMode(!isDarkMode)} />} /> } /> - + + {imageViewer.open && imageViewer.src && ( )} - {noticeModal.open && ( -
- setNoticeModal(prev => ({ ...prev, open: false }))} - onNeverShow={(version) => { - try { localStorage.setItem('notice_ver', String(version)); } catch {} - setNoticeModal(prev => ({ ...prev, open: false })); - }} - /> -
- )}
); } export default App; + + + + diff --git a/src/components/AdminPage.tsx b/src/components/AdminPage.tsx index f3eac06..45ea7b6 100644 --- a/src/components/AdminPage.tsx +++ b/src/components/AdminPage.tsx @@ -2,7 +2,6 @@ import React, { useState, useEffect } from 'react'; import { isAdminLoggedIn } from '../admin_api'; import AdminLogin from './AdminLogin'; import AdminDashboard from './AdminDashboard'; -import { Toaster } from 'react-hot-toast'; interface AdminPageProps { isDarkMode: boolean; @@ -43,7 +42,6 @@ const AdminPage: React.FC = ({ isDarkMode, onToggleTheme }) => { ) : ( )} - ); }; diff --git a/src/components/CommentSection.tsx b/src/components/CommentSection.tsx index 511fb60..d9a0c80 100644 --- a/src/components/CommentSection.tsx +++ b/src/components/CommentSection.tsx @@ -12,7 +12,7 @@ import { import { Dismiss24Regular, ArrowReply24Regular } from '@fluentui/react-icons'; import { getComments, postComment } from '../api'; import type { Comment as CommentType } from '../api'; -import { toast, Toaster } from 'react-hot-toast'; +import { toast } from 'react-hot-toast'; const useStyles = makeStyles({ container: { @@ -225,7 +225,6 @@ const CommentSection: React.FC = ({ postId }) => { {!loading && comments.length === 0 && 暂无评论} {renderComments()} - ); };