Compare commits

...

2 Commits

Author SHA1 Message Date
ysm
624621d60e 2026年 03月 27日 星期五 18:11:26 CST 2026-03-27 18:11:26 +08:00
ysm
5f6c7531e3 添加静音按钮,默认静音,设置保存到本地存储,图标灰度显示
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-27 18:11:02 +08:00
3 changed files with 65 additions and 10 deletions

BIN
public/tick1.mp3 Executable file

Binary file not shown.

View File

@ -185,11 +185,20 @@
} }
} }
/* Settings button */ /* Top buttons group */
.settings-button { .top-buttons {
position: absolute; position: absolute;
top: 20px; top: 20px;
left: 20px; left: 20px;
display: flex;
flex-direction: row;
gap: 8px;
z-index: 1000;
}
/* Settings button */
.settings-button {
position: static;
width: 40px; width: 40px;
height: 40px; height: 40px;
padding: 8px; padding: 8px;
@ -209,6 +218,26 @@
background-color: rgba(255, 255, 255, 0.15); background-color: rgba(255, 255, 255, 0.15);
} }
.mute-button {
width: 40px;
height: 40px;
padding: 8px;
font-size: 20px;
background-color: rgba(255, 255, 255, 0.05);
border: none;
border-radius: 8px;
cursor: pointer;
transition: all 0.2s ease;
display: flex;
align-items: center;
justify-content: center;
filter: grayscale(100%);
}
.mute-button:hover {
background-color: rgba(255, 255, 255, 0.15);
}
/* Settings overlay */ /* Settings overlay */
.settings-overlay { .settings-overlay {
position: fixed; position: fixed;

View File

@ -1,4 +1,4 @@
import { useState, useEffect } from 'react' import { useState, useEffect, useRef } from 'react'
import { FlipClock } from './components/FlipClock' import { FlipClock } from './components/FlipClock'
import { RollClock } from './components/RollClock' import { RollClock } from './components/RollClock'
import './App.css' import './App.css'
@ -109,6 +109,11 @@ function App() {
return saved === 'up' ? 'up' : 'down' return saved === 'up' ? 'up' : 'down'
}) })
const [showSettings, setShowSettings] = useState(false) const [showSettings, setShowSettings] = useState(false)
const [isMuted, setIsMuted] = useState(() => {
const saved = localStorage.getItem('clock-isMuted')
return saved === null ? true : saved === 'true'
})
const isMutedRef = useRef(isMuted)
const [showDate, setShowDate] = useState(() => { const [showDate, setShowDate] = useState(() => {
// 从 localStorage 读取,默认显示日期 (true) // 从 localStorage 读取,默认显示日期 (true)
const saved = localStorage.getItem('clock-showDate') const saved = localStorage.getItem('clock-showDate')
@ -147,6 +152,13 @@ function App() {
localStorage.setItem('clock-showDate', String(newValue)) localStorage.setItem('clock-showDate', String(newValue))
} }
const toggleMute = () => {
const newValue = !isMuted
setIsMuted(newValue)
isMutedRef.current = newValue
localStorage.setItem('clock-isMuted', String(newValue))
}
// 切换显示时区时保存到 localStorage // 切换显示时区时保存到 localStorage
const toggleShowTimezone = () => { const toggleShowTimezone = () => {
const newValue = !showTimezone const newValue = !showTimezone
@ -155,8 +167,13 @@ function App() {
} }
useEffect(() => { useEffect(() => {
const audio = new Audio('/tick1.mp3')
const timer = setInterval(() => { const timer = setInterval(() => {
setTime(new Date()) setTime(new Date())
if (!isMutedRef.current) {
audio.currentTime = 0
audio.play().catch(() => {})
}
}, 1000) }, 1000)
return () => clearInterval(timer) return () => clearInterval(timer)
}, []) }, [])
@ -226,13 +243,22 @@ function App() {
return ( return (
<div className="app"> <div className="app">
<button <div className="top-buttons">
className="settings-button" <button
onClick={() => setShowSettings(true)} className="settings-button"
aria-label="设置" onClick={() => setShowSettings(true)}
> aria-label="设置"
>
</button>
</button>
<button
className="mute-button"
onClick={toggleMute}
aria-label={isMuted ? '取消静音' : '静音'}
>
{isMuted ? '🔇' : '🔊'}
</button>
</div>
{showSettings && ( {showSettings && (
<div className="settings-overlay" onClick={() => setShowSettings(false)}> <div className="settings-overlay" onClick={() => setShowSettings(false)}>