为翻页和滚动时钟独立添加12/24小时制切换

- FlipClock组件独立实现12/24H切换功能
- RollClock组件独立实现12/24H切换功能
- 分别使用独立的CSS样式(flip-format-toggle/roll-format-toggle)
- 各组件状态独立,互不干扰

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
ysm 2026-03-24 00:17:32 +08:00
parent 0f0809b1c0
commit d2a9a94d3b
6 changed files with 234 additions and 115 deletions

View File

@ -57,7 +57,7 @@
}
.digital-clock-period {
font-family: system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
font-family: Arial, sans-serif;
font-weight: 600;
color: #fff;
text-shadow: 0 0 10px rgba(255, 255, 255, 0.5);
@ -81,24 +81,6 @@
background-color: rgba(255, 255, 255, 0.15);
}
.format-toggle {
padding: 6px 12px;
font-size: 12px;
font-weight: 500;
color: #888;
background-color: rgba(255, 255, 255, 0.05);
border: none;
border-radius: 6px;
cursor: pointer;
transition: all 0.2s ease;
flex-shrink: 0;
}
.format-toggle:hover {
color: #fff;
background-color: rgba(255, 255, 255, 0.15);
}
.clock-container {
display: flex;
justify-content: center;
@ -109,12 +91,6 @@
box-sizing: border-box;
}
.digital-clock-wrapper {
position: relative;
display: inline-flex;
align-items: flex-start;
}
.digital-clock {
font-family: 'DSEG7', monospace;
font-weight: bold;

View File

@ -6,7 +6,6 @@ import './App.css'
type ClockStyle = 'digital' | 'flip' | 'roll'
function DigitalClock({ time, size, period, is24Hour, onToggleFormat }: { time: string; size: number; period?: string; is24Hour: boolean; onToggleFormat: () => void }) {
// Match visual height with flip/roll clocks
const fontSize = Math.floor(size * 0.95)
const periodSize = Math.floor(size * 0.25)

View File

@ -1,3 +1,44 @@
.flip-clock-outer {
display: flex;
flex-direction: row;
align-items: center;
gap: 0;
}
.flip-clock-side-panel {
display: flex;
flex-direction: column;
align-items: flex-end;
justify-content: center;
gap: 4px;
margin-right: 4px;
}
.flip-clock-period {
font-family: Arial, sans-serif;
font-weight: 600;
color: #fff;
text-shadow: 0 0 10px rgba(255, 255, 255, 0.5);
line-height: 1;
}
.flip-format-toggle {
padding: 4px 8px;
font-size: 12px;
font-weight: 500;
color: #888;
background-color: rgba(255, 255, 255, 0.05);
border: none;
border-radius: 4px;
cursor: pointer;
transition: all 0.2s ease;
}
.flip-format-toggle:hover {
color: #fff;
background-color: rgba(255, 255, 255, 0.15);
}
.flip-clock-container {
display: flex;
flex-direction: row;

View File

@ -1,3 +1,4 @@
import { useState } from 'react';
import { FlipDigit } from './FlipDigit';
import './FlipClock.css';
@ -7,46 +8,77 @@ interface FlipClockProps {
}
export function FlipClock({ time, size }: FlipClockProps) {
const [hours, minutes, seconds] = time.split(':');
const [is24Hour, setIs24Hour] = useState(true);
// Parse time and convert if needed
const [hoursStr, minutes, seconds] = time.split(':');
let hours = parseInt(hoursStr, 10);
let period: string | undefined;
if (!is24Hour) {
period = hours >= 12 ? 'PM' : 'AM';
hours = hours % 12 || 12;
}
const displayHours = String(hours).padStart(2, '0');
const periodSize = size * 0.25;
return (
<div className="flip-clock-container">
{/* Hours */}
<div className="flip-clock-digit-group">
<FlipDigit value={parseInt(hours[0], 10)} size={size} />
<FlipDigit value={parseInt(hours[1], 10)} size={size} />
<div className="flip-clock-outer">
<div className="flip-clock-side-panel">
{!is24Hour && period && (
<span
className="flip-clock-period"
style={{ fontSize: `${periodSize}px` }}
>
{period}
</span>
)}
<button
className="flip-format-toggle"
onClick={() => setIs24Hour(!is24Hour)}
>
{is24Hour ? '24H' : '12H'}
</button>
</div>
<div className="flip-clock-container">
{/* Hours */}
<div className="flip-clock-digit-group">
<FlipDigit value={parseInt(displayHours[0], 10)} size={size} />
<FlipDigit value={parseInt(displayHours[1], 10)} size={size} />
</div>
<span
className="flip-clock-separator"
style={{
fontSize: `${size * 0.5}px`,
marginTop: `${-size * 0.08}px`
}}
>
:
</span>
<span
className="flip-clock-separator"
style={{
fontSize: `${size * 0.5}px`,
marginTop: `${-size * 0.08}px`
}}
>
:
</span>
{/* Minutes */}
<div className="flip-clock-digit-group">
<FlipDigit value={parseInt(minutes[0], 10)} size={size} />
<FlipDigit value={parseInt(minutes[1], 10)} size={size} />
</div>
{/* Minutes */}
<div className="flip-clock-digit-group">
<FlipDigit value={parseInt(minutes[0], 10)} size={size} />
<FlipDigit value={parseInt(minutes[1], 10)} size={size} />
</div>
<span
className="flip-clock-separator"
style={{
fontSize: `${size * 0.5}px`,
marginTop: `${-size * 0.08}px`
}}
>
:
</span>
<span
className="flip-clock-separator"
style={{
fontSize: `${size * 0.5}px`,
marginTop: `${-size * 0.08}px`
}}
>
:
</span>
{/* Seconds */}
<div className="flip-clock-digit-group">
<FlipDigit value={parseInt(seconds[0], 10)} size={size} />
<FlipDigit value={parseInt(seconds[1], 10)} size={size} />
{/* Seconds */}
<div className="flip-clock-digit-group">
<FlipDigit value={parseInt(seconds[0], 10)} size={size} />
<FlipDigit value={parseInt(seconds[1], 10)} size={size} />
</div>
</div>
</div>
);

View File

@ -1,3 +1,44 @@
.roll-clock-outer {
display: flex;
flex-direction: row;
align-items: center;
gap: 0;
}
.roll-clock-side-panel {
display: flex;
flex-direction: column;
align-items: flex-end;
justify-content: center;
gap: 4px;
margin-right: 4px;
}
.roll-clock-period {
font-family: Arial, sans-serif;
font-weight: 600;
color: #fff;
text-shadow: 0 0 10px rgba(255, 255, 255, 0.5);
line-height: 1;
}
.roll-format-toggle {
padding: 4px 8px;
font-size: 12px;
font-weight: 500;
color: #888;
background-color: rgba(255, 255, 255, 0.05);
border: none;
border-radius: 4px;
cursor: pointer;
transition: all 0.2s ease;
}
.roll-format-toggle:hover {
color: #fff;
background-color: rgba(255, 255, 255, 0.15);
}
.roll-clock-wrapper {
display: flex;
flex-direction: row;

View File

@ -10,9 +10,21 @@ interface RollClockProps {
export function RollClock({ time, size }: RollClockProps) {
// Roll direction: 'down' = roll down, 'up' = roll up
const [direction, setDirection] = useState<'down' | 'up'>('down');
const [is24Hour, setIs24Hour] = useState(true);
const [hours, minutes, seconds] = time.split(':');
// Parse time and convert if needed
const [hoursStr, minutes, seconds] = time.split(':');
let hours = parseInt(hoursStr, 10);
let period: string | undefined;
if (!is24Hour) {
period = hours >= 12 ? 'PM' : 'AM';
hours = hours % 12 || 12;
}
const displayHours = String(hours).padStart(2, '0');
const buttonSize = size * 0.25;
const periodSize = size * 0.25;
// Toggle direction
const toggleDirection = () => {
@ -20,65 +32,83 @@ export function RollClock({ time, size }: RollClockProps) {
};
return (
<div className="roll-clock-wrapper">
<div className="roll-clock-container">
{/* Hours */}
<div className="roll-clock-digit-group">
<RollDigit value={parseInt(hours[0], 10)} size={size} direction={direction} />
<RollDigit value={parseInt(hours[1], 10)} size={size} direction={direction} />
</div>
<span
className="roll-clock-separator"
style={{
fontSize: `${size * 0.5}px`,
marginTop: `${-size * 0.08}px`
}}
<div className="roll-clock-outer">
<div className="roll-clock-side-panel">
{!is24Hour && period && (
<span
className="roll-clock-period"
style={{ fontSize: `${periodSize}px` }}
>
{period}
</span>
)}
<button
className="roll-format-toggle"
onClick={() => setIs24Hour(!is24Hour)}
>
:
</span>
{/* Minutes */}
<div className="roll-clock-digit-group">
<RollDigit value={parseInt(minutes[0], 10)} size={size} direction={direction} />
<RollDigit value={parseInt(minutes[1], 10)} size={size} direction={direction} />
</div>
<span
className="roll-clock-separator"
style={{
fontSize: `${size * 0.5}px`,
marginTop: `${-size * 0.08}px`
}}
>
:
</span>
{/* Seconds */}
<div className="roll-clock-digit-group">
<RollDigit value={parseInt(seconds[0], 10)} size={size} direction={direction} />
<RollDigit value={parseInt(seconds[1], 10)} size={size} direction={direction} />
</div>
{is24Hour ? '24H' : '12H'}
</button>
</div>
<div className="roll-clock-wrapper">
<div className="roll-clock-container">
{/* Hours */}
<div className="roll-clock-digit-group">
<RollDigit value={parseInt(displayHours[0], 10)} size={size} direction={direction} />
<RollDigit value={parseInt(displayHours[1], 10)} size={size} direction={direction} />
</div>
{/* Direction toggle button */}
<button
className="roll-clock-button"
style={{
width: `${buttonSize}px`,
height: `${buttonSize}px`,
borderRadius: `${buttonSize / 2}px`,
marginLeft: '8px',
}}
onClick={toggleDirection}
>
<span
className="roll-clock-button-text"
style={{ fontSize: `${buttonSize * 0.6}px` }}
<span
className="roll-clock-separator"
style={{
fontSize: `${size * 0.5}px`,
marginTop: `${-size * 0.08}px`
}}
>
:
</span>
{/* Minutes */}
<div className="roll-clock-digit-group">
<RollDigit value={parseInt(minutes[0], 10)} size={size} direction={direction} />
<RollDigit value={parseInt(minutes[1], 10)} size={size} direction={direction} />
</div>
<span
className="roll-clock-separator"
style={{
fontSize: `${size * 0.5}px`,
marginTop: `${-size * 0.08}px`
}}
>
:
</span>
{/* Seconds */}
<div className="roll-clock-digit-group">
<RollDigit value={parseInt(seconds[0], 10)} size={size} direction={direction} />
<RollDigit value={parseInt(seconds[1], 10)} size={size} direction={direction} />
</div>
</div>
{/* Direction toggle button */}
<button
className="roll-clock-button"
style={{
width: `${buttonSize}px`,
height: `${buttonSize}px`,
borderRadius: `${buttonSize / 2}px`,
marginLeft: '8px',
}}
onClick={toggleDirection}
>
{direction === 'down' ? '↓' : '↑'}
</span>
</button>
<span
className="roll-clock-button-text"
style={{ fontSize: `${buttonSize * 0.6}px` }}
>
{direction === 'down' ? '↓' : '↑'}
</span>
</button>
</div>
</div>
);
}