feat(start): 背景按时段选图(6-24 随机 No.1~5,0-6 用 Night),标题改 CCStart

- StartPage 背景改为纯本地时间:白天从 No.1~No.5 随机取一张并固定整页生命周期,夜间(0-6点)用 Night
- 登录页 h2 与 index.html 标签页标题由 Sign in 改为 CCStart
- 起始页背景图压成 WebP(限宽 2560,质量 ~82),单图从 2.5~4.7MB 降到 113~375KB,适配 3Mbps 带宽
- 删除旧 dark.png/light.jpg
- 部署文档补充前端单独重发流程与 WSL 实际路径

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
cc 2026-06-22 22:18:47 +08:00
parent e4383cf4b5
commit 5b60185f94
12 changed files with 42 additions and 22 deletions

View File

@ -4,7 +4,7 @@
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" /> <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Sign in</title> <title>CCStart</title>
</head> </head>
<body> <body>
<div id="root"></div> <div id="root"></div>

Binary file not shown.

After

Width:  |  Height:  |  Size: 113 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 234 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 265 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 366 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 158 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 331 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 844 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 MiB

View File

@ -40,7 +40,7 @@ export function LoginForm({ onSignIn }: LoginFormProps) {
className="flex w-full max-w-md flex-col justify-center px-8 py-14 sm:px-12 lg:px-16" className="flex w-full max-w-md flex-col justify-center px-8 py-14 sm:px-12 lg:px-16"
> >
<motion.div variants={fadeUp} className="mb-10"> <motion.div variants={fadeUp} className="mb-10">
<h2 className="font-display text-3xl font-medium text-text">Sign in</h2> <h2 className="font-display text-3xl font-medium text-text">CCStart</h2>
<p className="mt-2 text-sm text-muted">Enter your details to continue.</p> <p className="mt-2 text-sm text-muted">Enter your details to continue.</p>
</motion.div> </motion.div>

View File

@ -7,8 +7,8 @@ import { SearchBar } from './start/SearchBar'
import { CategoryDock } from './start/CategoryDock' import { CategoryDock } from './start/CategoryDock'
import { WeatherFx } from './start/WeatherFx' import { WeatherFx } from './start/WeatherFx'
// 背景图:放 src/assets/startpage/ 下。按昼夜选 light / dark // 背景图:放 src/assets/startpage/ 下。6:0024:00 从 No.1~No.5 里随机取一张
// 缺这两张时回退到目录里排序第一张,再无则用渐变。说明见该目录 README。 // 0:006:00 用 Night。缺图时互相回退,再无则用渐变。说明见该目录 README。
const bgFiles = import.meta.glob<string>('../assets/startpage/*.{jpg,jpeg,png,webp}', { const bgFiles = import.meta.glob<string>('../assets/startpage/*.{jpg,jpeg,png,webp}', {
eager: true, eager: true,
query: '?url', query: '?url',
@ -19,24 +19,16 @@ function bgByName(name: string): string | undefined {
return Object.entries(bgFiles).find(([p]) => p.toLowerCase().includes(`/${name}.`))?.[1] return Object.entries(bgFiles).find(([p]) => p.toLowerCase().includes(`/${name}.`))?.[1]
} }
const lightBg = bgByName('light') // 白天候选No.1~No.5按编号排序夜间Night。
const darkBg = bgByName('dark') const dayBgs = Object.entries(bgFiles)
const anyBg = Object.entries(bgFiles) .filter(([p]) => /\/no\.\d+\./i.test(p))
.sort(([a], [b]) => a.localeCompare(b)) .sort(([a], [b]) => a.localeCompare(b))
.map(([, url]) => url)[0] .map(([, url]) => url)
const nightBg = bgByName('night')
// 和风图标码中能区分昼夜的子集(晴/多云/阵雨)。其余码无昼夜之分。 // 昼夜判断纯按本地时间0:006:00 为夜。
const NIGHT_ICONS = new Set(['150', '151', '152', '153', '350', '351', '456', '457']) function isNight(): boolean {
const DAY_ICONS = new Set(['100', '101', '102', '103', '300', '301', '400', '401']) return new Date().getHours() < 6
// 昼夜判断图标码优先判断不了的码用本地时间兜底18:0006:00 为夜)。
function isNight(icon?: string): boolean {
if (icon) {
if (NIGHT_ICONS.has(icon)) return true
if (DAY_ICONS.has(icon)) return false
}
const h = new Date().getHours()
return h < 6 || h >= 18
} }
// 动态效果类型:只做雨/雪两类,其余静态。 // 动态效果类型:只做雨/雪两类,其余静态。
@ -64,14 +56,18 @@ export function StartPage() {
const icon = wx.data && wx.data.ok ? wx.data.icon : undefined const icon = wx.data && wx.data.ok ? wx.data.icon : undefined
// 白天随机选一张,整页生命周期内固定,避免每分钟一拍时背景乱跳。
const [dayIdx] = useState(() => Math.floor(Math.random() * Math.max(dayBgs.length, 1)))
// 开发预览(仅 DEV?bg=light|dark 强制背景;?fx=rain|snow|thunder|none 强制动效。 // 开发预览(仅 DEV?bg=light|dark 强制背景;?fx=rain|snow|thunder|none 强制动效。
// 例http://localhost:5173/?bg=dark&fx=snow // 例http://localhost:5173/?bg=dark&fx=snow
const ov = import.meta.env.DEV ? new URLSearchParams(window.location.search) : null const ov = import.meta.env.DEV ? new URLSearchParams(window.location.search) : null
const ovBg = ov?.get('bg') const ovBg = ov?.get('bg')
const ovFx = ov?.get('fx') const ovFx = ov?.get('fx')
const night = ovBg ? ovBg === 'dark' : isNight(icon) const night = ovBg ? ovBg === 'dark' : isNight()
const bg = (night ? darkBg : lightBg) ?? lightBg ?? darkBg ?? anyBg const dayBg = dayBgs[dayIdx] ?? dayBgs[0]
const bg = (night ? nightBg : dayBg) ?? dayBg ?? nightBg
let kind = fxKind(icon) let kind = fxKind(icon)
let thunder = isThunder(icon) let thunder = isThunder(icon)

View File

@ -230,3 +230,27 @@ ssh root@8.130.143.54 "tail -f /opt/internet-project/server.log"
**Redeploy after code changes:** **Redeploy after code changes:**
Re-run Tasks 14. For frontend-only changes, skip Task 2. Re-run Tasks 14. For frontend-only changes, skip Task 2.
**Frontend-only redeploy (verified 2026-06-22):**
The active WSL checkout is at `/home/cc/InternetProject` (not the `/mnt/f/...`
path in the original tasks above). Since the Rust process serves `static/` from
disk, a frontend-only change needs **no server restart** — just rebuild and
replace the static files:
```bash
cd /home/cc/InternetProject/Client
npm run build
# clear stale hashed assets so old bundles don't accumulate
ssh root@8.130.143.54 "rm -rf /opt/internet-project/static/assets && mkdir -p /opt/internet-project/static"
scp -r dist/* root@8.130.143.54:/opt/internet-project/static/
# verify live
curl -s http://8.130.143.54:8548/ | grep -o '<title>[^<]*</title>'
curl -s -o /dev/null -w '%{http_code}\n' http://8.130.143.54:8548/api/client/health
```
**Restart the Rust binary (backend changes):**
A helper exists on the server: `/opt/internet-project/restart_rust.sh`. The
previous binary is kept as `RustServer.bak` for rollback.
> Startpage backgrounds: large PNG/JPG source images are pre-compressed to WebP
> (max width 2560, quality ~82) before building — keeps each background under
> ~400 KB for the 3 Mbps server link.