-
-
+
+
+
+ {period && (
+
+ {period}
+
+ )}
+
+
+ {dateInfo.dateString} {dateInfo.weekday}
+
+
+ {/* Hours */}
+
+
+
+
-
- :
-
+
+ :
+
- {/* Minutes */}
-
-
-
-
+ {/* Minutes */}
+
+
+
+
-
- :
-
+
+ :
+
- {/* Seconds */}
-
-
-
+ {/* Seconds */}
+
+
+
+
diff --git a/src/components/FlipDigit.css b/src/components/FlipDigit.css
index b5c850a..1f60955 100644
--- a/src/components/FlipDigit.css
+++ b/src/components/FlipDigit.css
@@ -3,6 +3,7 @@
border-radius: 4px;
background-color: #1a1a1a;
overflow: hidden;
+ perspective: 1000px;
}
.flip-digit-bg-top {
diff --git a/src/components/FlipDigit.tsx b/src/components/FlipDigit.tsx
index a540459..9f2ab23 100644
--- a/src/components/FlipDigit.tsx
+++ b/src/components/FlipDigit.tsx
@@ -33,11 +33,14 @@ export function FlipDigit({ value, size }: FlipDigitProps) {
// Finish animation
const finishAnimation = () => {
- setTopRotation(0);
- setBottomRotation(-90);
- setFlipBottomValue(null);
setIsAnimating(false);
- animating.current = false;
+
+ requestAnimationFrame(() => {
+ setTopRotation(0);
+ setBottomRotation(-90);
+ setFlipBottomValue(null);
+ animating.current = false;
+ });
};
// Start bottom animation after top completes
@@ -64,7 +67,6 @@ 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);
@@ -73,13 +75,23 @@ export function FlipDigit({ value, size }: FlipDigitProps) {
// Update bgTop immediately (revealed when top flips away)
setBgTopValue(value);
- // Reset rotation states
+ // First, ensure transition is disabled before resetting rotation
+ setIsAnimating(false);
+
+ // Reset rotation states instantly (without transition)
setTopRotation(0);
setBottomRotation(-90);
- // Start top animation after a brief delay to ensure state is set
+ // Wait for browser to apply the reset (without transition)
requestAnimationFrame(() => {
- setTopRotation(90);
+ // 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);
+ });
});
// After top animation completes, start bottom animation
@@ -111,12 +123,12 @@ export function FlipDigit({ value, size }: FlipDigitProps) {
const topFlipStyle = {
height: `${halfHeight}px`,
- transform: `perspective(1000px) rotateX(${topRotation}deg)`,
+ transform: `rotateX(${topRotation}deg)`,
};
const bottomFlipStyle = {
height: `${halfHeight}px`,
- transform: `perspective(1000px) rotateX(${bottomRotation}deg)`,
+ transform: `rotateX(${bottomRotation}deg)`,
};
const centerLineStyle = {
diff --git a/src/components/RollClock.css b/src/components/RollClock.css
index 31ba25b..7773d26 100644
--- a/src/components/RollClock.css
+++ b/src/components/RollClock.css
@@ -10,8 +10,7 @@
flex-direction: column;
align-items: flex-end;
justify-content: center;
- gap: 4px;
- margin-right: 4px;
+ margin-right: 8px;
}
.roll-clock-period {
@@ -32,6 +31,7 @@
border-radius: 4px;
cursor: pointer;
transition: all 0.2s ease;
+ white-space: nowrap;
}
.roll-format-toggle:hover {
@@ -45,6 +45,34 @@
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;
@@ -52,6 +80,15 @@
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;
diff --git a/src/components/RollClock.tsx b/src/components/RollClock.tsx
index 855a38f..e7a4005 100644
--- a/src/components/RollClock.tsx
+++ b/src/components/RollClock.tsx
@@ -2,29 +2,30 @@ 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 }: RollClockProps) {
+export function RollClock({ time, size, dateInfo, period }: RollClockProps) {
// Roll direction: 'down' = roll down, 'up' = roll up
const [direction, setDirection] = useState<'down' | 'up'>('down');
const [is24Hour, setIs24Hour] = useState(true);
- // Parse time and convert if needed
+ // Parse time - it's already in 12h format when period is provided
const [hoursStr, minutes, seconds] = time.split(':');
- let hours = parseInt(hoursStr, 10);
- let period: string | undefined;
+ const displayHours = hoursStr;
- 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;
+ const periodSize = size * 0.20;
+ const dateSize = size * 0.20;
// Toggle direction
const toggleDirection = () => {
@@ -34,14 +35,6 @@ export function RollClock({ time, size }: RollClockProps) {
return (
- {!is24Hour && period && (
-
- {period}
-
- )}
-
- {/* Hours */}
-
-
-
+
+
+
+ {!is24Hour && period && (
+
+ {period}
+
+ )}
+
+
+ {dateInfo.dateString} {dateInfo.weekday}
+
+
+ {/* Hours */}
+
+
+
+
-
- :
-
+
+ :
+
- {/* Minutes */}
-
-
-
-
+ {/* Minutes */}
+
+
+
+
-
- :
-
+
+ :
+
- {/* Seconds */}
-
-
-
+ {/* Seconds */}
+
+
+
+