From a309aba988419cd6d453dc5c99f29fca3836d510 Mon Sep 17 00:00:00 2001
From: 22 <60903333+nini22P@users.noreply.github.com>
Date: Wed, 1 Apr 2026 08:27:37 +0800
Subject: [PATCH 1/2] feat: add a feature that only works on March 32nd
---
.../components/AprilFools/AprilFools.tsx | 30 +++++++++++++++++++
app/[locale]/layout.tsx | 2 ++
package-lock.json | 24 ---------------
3 files changed, 32 insertions(+), 24 deletions(-)
create mode 100644 app/[locale]/components/AprilFools/AprilFools.tsx
diff --git a/app/[locale]/components/AprilFools/AprilFools.tsx b/app/[locale]/components/AprilFools/AprilFools.tsx
new file mode 100644
index 0000000..39e6f80
--- /dev/null
+++ b/app/[locale]/components/AprilFools/AprilFools.tsx
@@ -0,0 +1,30 @@
+'use client'
+
+import { useEffect } from 'react'
+import { usePathname } from 'next/navigation'
+
+const AprilFools = () => {
+ const pathname = usePathname()
+
+ useEffect(() => {
+ const now = new Date()
+ if (now.getMonth() !== 3 || now.getDate() !== 1) return
+
+ if (document.title.includes('WebGAL'))
+ document.title = document.title.replace(/WebGAL/g, 'WebG@L')
+
+ const walker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT)
+ const textNodes: Text[] = []
+ let node: Node | null
+ while ((node = walker.nextNode())) textNodes.push(node as Text)
+ textNodes.forEach(node => {
+ if (node.textContent?.includes('WebGAL'))
+ node.textContent = node.textContent.replace(/WebGAL/g, 'WebG@L')
+ })
+ }, [pathname])
+
+ return null
+}
+
+export default AprilFools
+
diff --git a/app/[locale]/layout.tsx b/app/[locale]/layout.tsx
index e9aeab1..a93d777 100644
--- a/app/[locale]/layout.tsx
+++ b/app/[locale]/layout.tsx
@@ -5,6 +5,7 @@ import { i18n } from '../../i18n'
import Footer from './components/Footer/Footer'
import Navbar from './components/Navbar/Navbar'
import { GoogleAnalytics } from '@next/third-parties/google'
+import AprilFools from './components/AprilFools/AprilFools'
const notoSansSC = Noto_Sans_SC({
subsets: ['latin'],
@@ -29,6 +30,7 @@ export default async function LangLayout({ children, params: { locale } }
+
{children}
diff --git a/package-lock.json b/package-lock.json
index dd61959..1db6c57 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -2417,7 +2417,6 @@
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
- "dev": true,
"hasInstallScript": true,
"optional": true,
"os": [
@@ -2930,12 +2929,6 @@
"node": ">= 4"
}
},
- "node_modules/immutable": {
- "version": "4.3.0",
- "license": "MIT",
- "optional": true,
- "peer": true
- },
"node_modules/import-fresh": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
@@ -5556,23 +5549,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/sass": {
- "version": "1.63.6",
- "license": "MIT",
- "optional": true,
- "peer": true,
- "dependencies": {
- "chokidar": ">=3.0.0 <4.0.0",
- "immutable": "^4.0.0",
- "source-map-js": ">=0.6.2 <2.0.0"
- },
- "bin": {
- "sass": "sass.js"
- },
- "engines": {
- "node": ">=14.0.0"
- }
- },
"node_modules/scheduler": {
"version": "0.23.0",
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz",
From e7db943ba3f49fbb081a42225bdf6650858d8c4b Mon Sep 17 00:00:00 2001
From: 22 <60903333+nini22P@users.noreply.github.com>
Date: Wed, 1 Apr 2026 08:40:02 +0800
Subject: [PATCH 2/2] improve text replacement logic
---
.../components/AprilFools/AprilFools.tsx | 25 +++++++++++++------
1 file changed, 18 insertions(+), 7 deletions(-)
diff --git a/app/[locale]/components/AprilFools/AprilFools.tsx b/app/[locale]/components/AprilFools/AprilFools.tsx
index 39e6f80..11b2544 100644
--- a/app/[locale]/components/AprilFools/AprilFools.tsx
+++ b/app/[locale]/components/AprilFools/AprilFools.tsx
@@ -3,6 +3,15 @@
import { useEffect } from 'react'
import { usePathname } from 'next/navigation'
+function replaceInNode(root: Node) {
+ const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT)
+ let node: Node | null
+ while ((node = walker.nextNode())) {
+ if (node.textContent?.includes('WebGAL'))
+ node.textContent = node.textContent.replace(/WebGAL/g, 'WebG@L')
+ }
+}
+
const AprilFools = () => {
const pathname = usePathname()
@@ -13,14 +22,16 @@ const AprilFools = () => {
if (document.title.includes('WebGAL'))
document.title = document.title.replace(/WebGAL/g, 'WebG@L')
- const walker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT)
- const textNodes: Text[] = []
- let node: Node | null
- while ((node = walker.nextNode())) textNodes.push(node as Text)
- textNodes.forEach(node => {
- if (node.textContent?.includes('WebGAL'))
- node.textContent = node.textContent.replace(/WebGAL/g, 'WebG@L')
+ replaceInNode(document.body)
+
+ const observer = new MutationObserver((mutations) => {
+ mutations.forEach(({ addedNodes }) =>
+ addedNodes.forEach(node => replaceInNode(node))
+ )
})
+ observer.observe(document.body, { childList: true, subtree: true })
+
+ return () => observer.disconnect()
}, [pathname])
return null