From cb436904ea9aa357c70d9d5e2fde6796818a0ef0 Mon Sep 17 00:00:00 2001 From: Bot Date: Thu, 16 Apr 2026 16:59:01 +0800 Subject: [PATCH] feat: integrate custom branding, time-based themes, and LXGW font directly into frontend --- src/App.tsx | 3 +-- src/components/Header.tsx | 3 --- src/index.css | 24 ++++++++++++++++++++++++ src/lib/custom-config.ts | 38 ++++++++++++++++++++++++++++++++++++++ src/main.tsx | 3 +++ src/vite-env.d.ts | 13 +++++++++++++ 6 files changed, 79 insertions(+), 5 deletions(-) create mode 100644 src/lib/custom-config.ts diff --git a/src/App.tsx b/src/App.tsx index 02b2a74..e6e46c4 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -44,8 +44,7 @@ const MainApp: React.FC = () => { // 检测是否强制指定了主题颜色 const forceTheme = - // @ts-expect-error ForceTheme is a global variable - (window.ForceTheme as string) !== "" ? window.ForceTheme : undefined; + window.ForceTheme as string !== "" ? window.ForceTheme : undefined; useEffect(() => { if (forceTheme === "dark" || forceTheme === "light") { diff --git a/src/components/Header.tsx b/src/components/Header.tsx index a2acea7..399acc5 100644 --- a/src/components/Header.tsx +++ b/src/components/Header.tsx @@ -70,10 +70,8 @@ function Header() { const siteName = settingData?.data?.config?.site_name; - // @ts-expect-error CustomLogo is a global variable const customLogo = window.CustomLogo || "/apple-touch-icon.png"; - // @ts-expect-error CustomDesc is a global variable const customDesc = window.CustomDesc || t("nezha"); const customMobileBackgroundImage = @@ -208,7 +206,6 @@ type links = { }; function Links() { - // @ts-expect-error CustomLinks is a global variable const customLinks = window.CustomLinks as string; const links: links[] | null = customLinks ? JSON.parse(customLinks) : null; diff --git a/src/index.css b/src/index.css index 10603cc..a7c066a 100644 --- a/src/index.css +++ b/src/index.css @@ -1,4 +1,5 @@ @import "tailwindcss"; +@import url("https://cdn.jsdelivr.net/npm/lxgw-wenkai-screen-webfont@1.7.0/style.css"); @plugin "tailwindcss-animate"; @@ -189,6 +190,7 @@ @layer base { * { @apply border-border; + font-family: 'LXGW WenKai Screen', sans-serif !important; } html { @apply scroll-smooth; @@ -199,6 +201,9 @@ font-synthesis-weight: none; text-rendering: optimizeLegibility; } + h1, h2, h3, h4, h5, h6 { + font-family: 'LXGW WenKai Screen', sans-serif !important; + } } @layer base { @@ -381,3 +386,22 @@ filter: blur(2px); } } + +/* Custom background overlays */ +.bg-cover::after { + content: ''; + position: absolute; + inset: 0; + pointer-events: none; + transition: backdrop-filter 0.3s ease, background 0.3s ease; +} + +.dark .bg-cover::after { + backdrop-filter: blur(8px); + background: rgba(0, 0, 0, .6); +} + +.light .bg-cover::after { + backdrop-filter: blur(0); + background: rgba(255, 255, 255, .3); +} diff --git a/src/lib/custom-config.ts b/src/lib/custom-config.ts new file mode 100644 index 0000000..b836867 --- /dev/null +++ b/src/lib/custom-config.ts @@ -0,0 +1,38 @@ +import { DateTime } from "luxon"; + +export function initCustomConfig() { + try { + const hour = DateTime.now().hour; + const isNight = hour >= 18 || hour < 6; + + // Use default values if window variables are not already set (e.g. by backend custom_code) + // although the goal is to hardcode these for "consistency". + + window.CustomBackgroundImage = isNight + ? 'https://loohui.com/wp-content/uploads/images/background.jpg' + : 'https://loohui.com/wp-content/uploads/images/background_day.jpg'; + + window.CustomMobileBackgroundImage = window.CustomBackgroundImage; + window.ForceTheme = isNight ? 'dark' : 'light'; + + /* LOGO / 副标题 / 链接 */ + window.CustomLogo = 'https://loohui.com/wp-content/uploads/images/pet.png'; + window.CustomDesc = '树树皆秋色,山山唯落晖'; + window.CustomLinks = JSON.stringify([ + { "link": "https://loohui.com/", "name": "返回Blog", "blank": false } + ]); + + // Handle internal redirects if needed + document.addEventListener('click', (e: MouseEvent) => { + const target = e.target as HTMLElement; + const a = target.closest('a'); + if (a && a.href === 'https://loohui.com/') { + e.preventDefault(); + window.location.href = a.href; + } + }); + + } catch (e) { + console.error('[Nezha custom_config] crash:', e); + } +} diff --git a/src/main.tsx b/src/main.tsx index d991d8c..be346ca 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -12,9 +12,12 @@ import { SortProvider } from "./context/sort-provider"; import { StatusProvider } from "./context/status-provider"; import { TooltipProvider } from "./context/tooltip-provider"; import { WebSocketProvider } from "./context/websocket-provider"; +import { initCustomConfig } from "./lib/custom-config"; import "./i18n"; import "./index.css"; +initCustomConfig(); + const queryClient = new QueryClient(); const rootElement = document.getElementById("root"); diff --git a/src/vite-env.d.ts b/src/vite-env.d.ts index 11f02fe..95342df 100644 --- a/src/vite-env.d.ts +++ b/src/vite-env.d.ts @@ -1 +1,14 @@ /// + +interface Window { + CustomBackgroundImage: string; + CustomMobileBackgroundImage: string; + ForceTheme: string; + CustomLogo: string; + CustomDesc: string; + CustomLinks: string; + ForceShowServices: boolean; + ForceCardInline: boolean; + ForceShowMap: boolean; + ForcePeakCutEnabled: boolean; +}