Compare commits

..

No commits in common. "2a40d05cacae607694826521a9f7ba8f901758d6" and "4518e2e57e84adb0d6dd07d6ac64865c62079eea" have entirely different histories.

13 changed files with 143 additions and 617 deletions

View File

@ -5,7 +5,6 @@
## 项目概述
一个精简的 React + TypeScript + Vite 入门项目。
主要功能是在页面上显示数码风格的时钟。
- **Node 版本**: v24.14.0(在 `.nvmrc` 中指定)
- **包管理器**: npm
@ -67,8 +66,3 @@ src/
## 构建输出
生产构建输出到 `dist/` 目录ESLint 会忽略该目录)。
## 本地存储
本地存储使用localStorage用于保存用户设置。

4
dev.sh
View File

@ -1,4 +0,0 @@
#!/bin/bash
source ~/.nvm/nvm.sh
nvm use
npm run dev

View File

@ -1,11 +0,0 @@
# 翻页
这里是关于翻页的设计文档
翻页样式是模拟常见于机场的用于显示航班信息的老式机械翻页机。
基本样式就是上下两个方块,分别显示数字的上半部分和下半部分。
每次翻页时,上半部分会沿着上半部分的下边缘向下翻转,显示出后面背景的下一个数字的上半部分。然后,下半部分会沿着下半部分的上边缘向下翻转,显示出后面背景的下一个数字的下半部分。

View File

@ -1,4 +0,0 @@
#!/bin/bash
source ~/.nvm/nvm.sh
nvm use

View File

@ -8,11 +8,26 @@
.app {
display: flex;
flex-direction: column;
align-items: stretch;
align-items: center;
justify-content: center;
min-height: 100vh;
width: 100%;
padding-top: 40px;
box-sizing: border-box;
gap: 40px;
}
.clock-container {
display: flex;
justify-content: center;
align-items: center;
}
/* Digital clock style (default) */
.digital-clock {
font-family: 'DSEG7', monospace;
font-size: 15vw;
font-weight: bold;
color: #fff;
text-shadow: 0 0 20px rgba(255, 255, 255, 0.5);
letter-spacing: 0.1em;
}
/* Style selector */
@ -23,113 +38,6 @@
padding: 8px;
background-color: rgba(255, 255, 255, 0.05);
border-radius: 12px;
z-index: 10;
flex-shrink: 0;
margin-bottom: 60px;
align-self: center;
}
.clock-wrapper {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
gap: 0;
width: 100%;
padding: 0 20px;
box-sizing: border-box;
}
.digital-clock-outer {
display: flex;
flex-direction: row;
align-items: center;
gap: 0;
}
.digital-clock-side-panel {
display: flex;
flex-direction: column;
align-items: flex-end;
justify-content: center;
margin-right: 8px;
}
.digital-clock-wrapper {
position: relative;
display: flex;
flex-direction: column;
align-items: stretch;
}
.digital-clock-header {
display: flex;
flex-direction: row;
align-items: baseline;
justify-content: space-between;
margin-bottom: 4px;
}
.digital-clock-header-left {
display: flex;
flex-direction: row;
align-items: baseline;
}
.digital-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;
}
.digital-clock-date {
font-family: Arial, sans-serif;
font-weight: 600;
color: #fff;
text-shadow: 0 0 10px rgba(255, 255, 255, 0.5);
line-height: 1;
white-space: nowrap;
}
.format-toggle-side {
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;
white-space: nowrap;
}
.format-toggle-side:hover {
color: #fff;
background-color: rgba(255, 255, 255, 0.15);
}
.clock-container {
display: flex;
justify-content: center;
align-items: center;
flex: 1;
max-width: 100vw;
overflow: hidden;
box-sizing: border-box;
}
.digital-clock {
font-family: 'DSEG7', monospace;
font-weight: bold;
color: #fff;
text-shadow: 0 0 20px rgba(255, 255, 255, 0.5);
letter-spacing: 0.05em;
white-space: nowrap;
max-width: 100%;
overflow: hidden;
}
.style-button {
@ -156,6 +64,10 @@
/* Responsive adjustments */
@media (max-width: 768px) {
.digital-clock {
font-size: 12vw;
}
.style-selector {
gap: 8px;
}

View File

@ -5,65 +5,10 @@ import './App.css'
type ClockStyle = 'digital' | 'flip' | 'roll'
interface DateInfo {
dateString: string
weekday: string
}
function formatDate(date: Date): DateInfo {
const year = date.getFullYear()
const month = String(date.getMonth() + 1).padStart(2, '0')
const day = String(date.getDate()).padStart(2, '0')
const weekdays = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六']
const weekday = weekdays[date.getDay()]
return {
dateString: `${year}-${month}-${day}`,
weekday
}
}
function DigitalClock({ time, size, period, is24Hour, onToggleFormat, dateInfo }: { time: string; size: number; period?: string; is24Hour: boolean; onToggleFormat: () => void; dateInfo: DateInfo }) {
const fontSize = Math.floor(size * 0.95)
const periodSize = Math.floor(size * 0.20)
const dateSize = Math.floor(size * 0.20)
function DigitalClock({ time }: { time: string }) {
return (
<div className="digital-clock-outer">
<div className="digital-clock-side-panel">
<button
className="format-toggle-side"
onClick={onToggleFormat}
>
{is24Hour ? '24H' : '12H'}
</button>
</div>
<div className="digital-clock-wrapper">
<div className="digital-clock-header">
<div className="digital-clock-header-left">
{!is24Hour && period && (
<span
className="digital-clock-period"
style={{ fontSize: `${periodSize}px` }}
>
{period}
</span>
)}
</div>
<span
className="digital-clock-date"
style={{ fontSize: `${dateSize}px` }}
>
{dateInfo.dateString} {dateInfo.weekday}
</span>
</div>
<div
className="digital-clock"
style={{ fontSize: `${fontSize}px`, lineHeight: '1' }}
>
{time}
</div>
</div>
<div className="digital-clock">
{time}
</div>
)
}
@ -71,8 +16,6 @@ function DigitalClock({ time, size, period, is24Hour, onToggleFormat, dateInfo }
function App() {
const [time, setTime] = useState(new Date())
const [clockStyle, setClockStyle] = useState<ClockStyle>('digital')
const [clockSize, setClockSize] = useState(120)
const [is24Hour, setIs24Hour] = useState(true)
useEffect(() => {
const timer = setInterval(() => {
@ -81,67 +24,26 @@ function App() {
return () => clearInterval(timer)
}, [])
// Responsive clock size - fit within screen width
useEffect(() => {
const updateSize = () => {
const width = window.innerWidth
// More conservative for small screens
const margin = width < 480 ? 40 : 60
const availableWidth = width - margin
// Use larger divisor for small screens to prevent overflow
const divisor = width < 480 ? 7 : 6
const newSize = Math.floor(availableWidth / divisor)
setClockSize(Math.min(newSize, 200))
}
updateSize()
window.addEventListener('resize', updateSize)
return () => window.removeEventListener('resize', updateSize)
}, [])
// Format time based on 12/24 hour setting
const formatTime = () => {
let hours = time.getHours()
const minutes = String(time.getMinutes()).padStart(2, '0')
const seconds = String(time.getSeconds()).padStart(2, '0')
let period: string | undefined
if (!is24Hour) {
period = hours >= 12 ? 'PM' : 'AM'
hours = hours % 12 || 12
}
return {
timeString: `${String(hours).padStart(2, '0')}:${minutes}:${seconds}`,
period
}
}
const { timeString, period } = formatTime()
const dateInfo = formatDate(time)
const timeString = `${String(time.getHours()).padStart(2, '0')}:${String(time.getMinutes()).padStart(2, '0')}:${String(time.getSeconds()).padStart(2, '0')}`
const renderClock = () => {
switch (clockStyle) {
case 'flip':
return <FlipClock time={timeString} size={clockSize} dateInfo={dateInfo} period={period} />
return <FlipClock time={timeString} size={120} />
case 'roll':
return <RollClock time={timeString} size={clockSize} dateInfo={dateInfo} period={period} />
return <RollClock time={timeString} size={120} />
case 'digital':
default:
return (
<DigitalClock
time={timeString}
size={clockSize}
period={period}
is24Hour={is24Hour}
onToggleFormat={() => setIs24Hour(!is24Hour)}
dateInfo={dateInfo}
/>
)
return <DigitalClock time={timeString} />
}
}
return (
<div className="app">
<div className="clock-container">
{renderClock()}
</div>
<div className="style-selector">
<button
className={`style-button ${clockStyle === 'digital' ? 'active' : ''}`}
@ -162,12 +64,6 @@ function App() {
</button>
</div>
<div className="clock-wrapper">
<div className="clock-container">
{renderClock()}
</div>
</div>
</div>
)
}

View File

@ -1,72 +1,3 @@
.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;
margin-right: 8px;
}
.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;
white-space: nowrap;
}
.flip-format-toggle:hover {
color: #fff;
background-color: rgba(255, 255, 255, 0.15);
}
.flip-clock-main {
display: flex;
flex-direction: column;
align-items: stretch;
}
.flip-clock-header {
display: flex;
flex-direction: row;
align-items: baseline;
justify-content: space-between;
margin-bottom: 4px;
}
.flip-clock-header-left {
display: flex;
flex-direction: row;
align-items: baseline;
}
.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-clock-container {
display: flex;
flex-direction: row;
@ -74,15 +5,6 @@
justify-content: center;
}
.flip-clock-date {
font-family: Arial, sans-serif;
font-weight: 600;
color: #fff;
text-shadow: 0 0 10px rgba(255, 255, 255, 0.5);
line-height: 1;
white-space: nowrap;
}
.flip-clock-digit-group {
display: flex;
flex-direction: row;

View File

@ -1,97 +1,52 @@
import { useState } from 'react';
import { FlipDigit } from './FlipDigit';
import './FlipClock.css';
interface DateInfo {
dateString: string;
weekday: string;
}
interface FlipClockProps {
time: string; // "HH:MM:SS" format
size: number;
dateInfo: DateInfo;
period?: string;
}
export function FlipClock({ time, size, dateInfo, period }: FlipClockProps) {
const [is24Hour, setIs24Hour] = useState(true);
// Parse time - it's already in 12h format when period is provided
const [hoursStr, minutes, seconds] = time.split(':');
const displayHours = hoursStr;
const periodSize = size * 0.20;
const dateSize = size * 0.20;
export function FlipClock({ time, size }: FlipClockProps) {
const [hours, minutes, seconds] = time.split(':');
return (
<div className="flip-clock-outer">
<div className="flip-clock-side-panel">
<button
className="flip-format-toggle"
onClick={() => setIs24Hour(!is24Hour)}
>
{is24Hour ? '24H' : '12H'}
</button>
<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>
<div className="flip-clock-main">
<div className="flip-clock-header">
<div className="flip-clock-header-left">
{period && (
<span
className="flip-clock-period"
style={{ fontSize: `${periodSize}px` }}
>
{period}
</span>
)}
</div>
<span
className="flip-clock-date"
style={{ fontSize: `${dateSize}px` }}
>
{dateInfo.dateString} {dateInfo.weekday}
</span>
</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} />
</div>
</div>
{/* 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>
);

View File

@ -3,7 +3,6 @@
border-radius: 4px;
background-color: #1a1a1a;
overflow: hidden;
perspective: 1000px;
}
.flip-digit-bg-top {
@ -70,8 +69,7 @@
border-top-left-radius: 4px;
border-top-right-radius: 4px;
backface-visibility: hidden;
z-index: 11;
/* 旋转轴在底部边缘(卡片中线位置) */
z-index: 10;
transform-origin: center bottom;
}
@ -89,7 +87,6 @@
border-bottom-right-radius: 4px;
backface-visibility: hidden;
z-index: 10;
/* 旋转轴在顶部边缘(卡片中线位置) */
transform-origin: center top;
}

View File

@ -33,28 +33,23 @@ export function FlipDigit({ value, size }: FlipDigitProps) {
// Finish animation
const finishAnimation = () => {
setTopRotation(0);
setBottomRotation(-90);
setFlipBottomValue(null);
setIsAnimating(false);
requestAnimationFrame(() => {
setTopRotation(0);
setBottomRotation(-90);
setFlipBottomValue(null);
animating.current = false;
});
animating.current = false;
};
// Start bottom animation after top completes
const startBottomAnimation = (targetValue: number) => {
// 上半片翻转完成后,更新上半翻转片的值为新值
// 这样当 finishAnimation 重置 rotation 时,上半翻转片显示正确的值
setFlipTopValue(targetValue);
// 第二阶段:下半片从-90°向下翻转90°到0°
// Animate bottom flap from -90deg to 0deg
requestAnimationFrame(() => {
setBottomRotation(0);
});
// 下半片翻转完成后,背景下半更新为新值
// After bottom animation completes, update bgBottom and finish
setTimeout(() => {
setBgBottomValue(targetValue);
setTimeout(() => {
@ -67,6 +62,7 @@ export function FlipDigit({ value, size }: FlipDigitProps) {
useEffect(() => {
if (value !== bgTopValue && !animating.current) {
animating.current = true;
setIsAnimating(true);
// Save current value as flip top value
setFlipTopValue(bgTopValue);
@ -75,23 +71,13 @@ export function FlipDigit({ value, size }: FlipDigitProps) {
// Update bgTop immediately (revealed when top flips away)
setBgTopValue(value);
// First, ensure transition is disabled before resetting rotation
setIsAnimating(false);
// Reset rotation states instantly (without transition)
// Reset rotation states
setTopRotation(0);
setBottomRotation(-90);
// Wait for browser to apply the reset (without transition)
// Start top animation after a brief delay to ensure state is set
requestAnimationFrame(() => {
// Now enable transition for the actual animation
setIsAnimating(true);
// Wait one more frame to ensure transition is enabled
requestAnimationFrame(() => {
// Start top animation: flip from 0° to 90°
setTopRotation(90);
});
setTopRotation(90);
});
// After top animation completes, start bottom animation
@ -123,12 +109,14 @@ export function FlipDigit({ value, size }: FlipDigitProps) {
const topFlipStyle = {
height: `${halfHeight}px`,
transform: `rotateX(${topRotation}deg)`,
transform: `perspective(1000px) translateY(${halfHeight * 0.5}px) rotateX(${topRotation}deg) translateY(${-halfHeight * 0.5}px)`,
opacity: topRotation > 60 ? 0 : 1,
};
const bottomFlipStyle = {
height: `${halfHeight}px`,
transform: `rotateX(${bottomRotation}deg)`,
transform: `perspective(1000px) translateY(${-halfHeight * 0.5}px) rotateX(${bottomRotation}deg) translateY(${halfHeight * 0.5}px)`,
opacity: bottomRotation > -60 ? 1 : 0,
};
const centerLineStyle = {
@ -157,7 +145,7 @@ export function FlipDigit({ value, size }: FlipDigitProps) {
style={{
...halfHeightStyle,
...topFlipStyle,
transition: isAnimating ? 'transform 300ms ease-in' : 'none',
transition: isAnimating ? 'transform 300ms ease-in, opacity 300ms ease-in' : 'none',
}}
>
<span className="flip-digit-text flip-digit-top-text" style={topTextStyle}>
@ -172,7 +160,7 @@ export function FlipDigit({ value, size }: FlipDigitProps) {
style={{
...halfHeightStyle,
...bottomFlipStyle,
transition: isAnimating ? 'transform 300ms ease-out' : 'none',
transition: isAnimating ? 'transform 300ms ease-out, opacity 300ms ease-out' : 'none',
}}
>
<span className="flip-digit-text flip-digit-bottom-text" style={bottomTextStyle}>

View File

@ -1,78 +1,9 @@
.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;
margin-right: 8px;
}
.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;
white-space: nowrap;
}
.roll-format-toggle:hover {
color: #fff;
background-color: rgba(255, 255, 255, 0.15);
}
.roll-clock-wrapper {
display: flex;
flex-direction: row;
align-items: center;
}
.roll-clock-main {
display: flex;
flex-direction: column;
align-items: stretch;
}
.roll-clock-header {
display: flex;
flex-direction: row;
align-items: baseline;
justify-content: space-between;
margin-bottom: 4px;
}
.roll-clock-header-left {
display: flex;
flex-direction: row;
align-items: baseline;
}
.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-clock-container {
display: flex;
flex-direction: row;
@ -80,15 +11,6 @@
justify-content: center;
}
.roll-clock-date {
font-family: Arial, sans-serif;
font-weight: 600;
color: #fff;
text-shadow: 0 0 10px rgba(255, 255, 255, 0.5);
line-height: 1;
white-space: nowrap;
}
.roll-clock-digit-group {
display: flex;
flex-direction: row;

View File

@ -2,30 +2,17 @@ import { useState } from 'react';
import { RollDigit } from './RollDigit';
import './RollClock.css';
interface DateInfo {
dateString: string;
weekday: string;
}
interface RollClockProps {
time: string; // "HH:MM:SS" format
size: number;
dateInfo: DateInfo;
period?: string;
}
export function RollClock({ time, size, dateInfo, period }: 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);
// Parse time - it's already in 12h format when period is provided
const [hoursStr, minutes, seconds] = time.split(':');
const displayHours = hoursStr;
const [hours, minutes, seconds] = time.split(':');
const buttonSize = size * 0.25;
const periodSize = size * 0.20;
const dateSize = size * 0.20;
// Toggle direction
const toggleDirection = () => {
@ -33,95 +20,65 @@ export function RollClock({ time, size, dateInfo, period }: RollClockProps) {
};
return (
<div className="roll-clock-outer">
<div className="roll-clock-side-panel">
<button
className="roll-format-toggle"
onClick={() => setIs24Hour(!is24Hour)}
>
{is24Hour ? '24H' : '12H'}
</button>
</div>
<div className="roll-clock-wrapper">
<div className="roll-clock-main">
<div className="roll-clock-header">
<div className="roll-clock-header-left">
{!is24Hour && period && (
<span
className="roll-clock-period"
style={{ fontSize: `${periodSize}px` }}
>
{period}
</span>
)}
</div>
<span
className="roll-clock-date"
style={{ fontSize: `${dateSize}px` }}
>
{dateInfo.dateString} {dateInfo.weekday}
</span>
</div>
<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>
<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>
<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>
{/* Direction toggle button */}
<button
className="roll-clock-button"
<span
className="roll-clock-separator"
style={{
width: `${buttonSize}px`,
height: `${buttonSize}px`,
borderRadius: `${buttonSize / 2}px`,
marginLeft: '8px',
fontSize: `${size * 0.5}px`,
marginTop: `${-size * 0.08}px`
}}
onClick={toggleDirection}
>
<span
className="roll-clock-button-text"
style={{ fontSize: `${buttonSize * 0.6}px` }}
>
{direction === 'down' ? '↓' : '↑'}
</span>
</button>
:
</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}
>
<span
className="roll-clock-button-text"
style={{ fontSize: `${buttonSize * 0.6}px` }}
>
{direction === 'down' ? '↓' : '↑'}
</span>
</button>
</div>
);
}

View File

@ -51,9 +51,11 @@
}
#root {
width: 100%;
width: 1126px;
max-width: 100%;
margin: 0 auto;
text-align: center;
border-inline: 1px solid var(--border);
min-height: 100svh;
display: flex;
flex-direction: column;