LLM-test/test/clock/minimax-2.0-api.html

263 lines
7.0 KiB
HTML
Raw Normal View History

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>Responsive Analog Clock</title>
<style>
:root {
--size: min(78vmin, 520px);
--border: 8px;
--rim: 10px;
--tick: #c7cbd1;
--face: #ffffff;
--numbers: #111;
--hands-hour: #111;
--hands-minute: #111;
--hands-second: #e63946;
--center: #111;
}
* { box-sizing: border-box; }
html, body {
height: 100%;
}
body {
margin: 0;
display: grid;
place-items: center;
background: #ffffff; /* white background */
font-family: system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, "Apple Color Emoji", "Segoe UI Emoji";
color: #111;
}
.clock {
position: relative;
width: var(--size);
aspect-ratio: 1;
background: var(--face);
border: var(--border) solid #111;
border-radius: 50%;
box-shadow:
0 12px 28px rgba(0,0,0,.08),
0 2px 6px rgba(0,0,0,.05) inset;
overflow: hidden;
}
/* Outer decorative rim */
.clock::before {
content: "";
position: absolute;
inset: calc(var(--border) + var(--rim));
border-radius: 50%;
border: 2px solid #e6e8eb;
}
/* Minute/hour ticks */
.ticks {
position: absolute;
inset: 0;
}
.tick {
position: absolute;
left: 50%;
top: 50%;
width: 2px;
height: 8%;
background: var(--tick);
transform-origin: 50% 50%;
opacity: .9;
}
/* Thicker hour ticks (12) */
.tick.hour {
width: 4px;
height: 12%;
background: #8f95a1;
}
/* Numerals */
.numeral {
position: absolute;
left: 50%;
top: 50%;
color: var(--numbers);
font-weight: 600;
transform-origin: 50% 50%;
user-select: none;
-webkit-user-select: none;
text-shadow: 0 1px 0 rgba(0,0,0,0.05);
}
.numeral span {
display: inline-block;
transform: translate(-50%, -50%);
font-size: clamp(14px, 5.2vmin, 28px);
}
/* Hands */
.hand {
position: absolute;
left: 50%;
top: 50%;
transform-origin: 50% 100%;
transform: translate(-50%, -100%) rotate(0deg);
border-radius: 999px;
box-shadow: 0 1px 2px rgba(0,0,0,.15);
}
.hand.hour {
width: 8px;
height: 26%;
background: var(--hands-hour);
z-index: 3;
}
.hand.minute {
width: 6px;
height: 36%;
background: var(--hands-minute);
z-index: 4;
}
.hand.second {
width: 3px;
height: 42%;
background: var(--hands-second);
z-index: 5;
/* Tail counterweight */
}
.hand.second::after {
content: "";
position: absolute;
left: 50%;
bottom: 0;
transform: translateX(-50%);
width: 3px;
height: 16%;
background: var(--hands-second);
border-radius: 3px;
}
/* Center cap */
.center-cap {
position: absolute;
left: 50%;
top: 50%;
width: 14px;
height: 14px;
transform: translate(-50%, -50%);
background: var(--center);
border-radius: 50%;
z-index: 6;
box-shadow: 0 0 0 3px #fff, 0 1px 3px rgba(0,0,0,.2);
}
/* CSS-animated second hand (smooth sweep) */
.spin {
animation-name: sweep;
animation-duration: 60s;
animation-timing-function: linear;
animation-iteration-count: infinite;
animation-play-state: running;
}
@keyframes sweep {
from { transform: translate(-50%, -100%) rotate(0deg); }
to { transform: translate(-50%, -100%) rotate(360deg); }
}
/* Accessibility: reduce motion users still get a ticking second hand */
@media (prefers-reduced-motion: reduce) {
.spin {
animation-duration: 1s; /* rapid ticks */
}
}
</style>
</head>
<body>
<div class="clock" id="clock">
<div class="ticks" aria-hidden="true"></div>
<div class="numeral" aria-hidden="true"><span>12</span></div>
<div class="numeral" aria-hidden="true"><span>3</span></div>
<div class="numeral" aria-hidden="true"><span>6</span></div>
<div class="numeral" aria-hidden="true"><span>9</span></div>
<div class="hand hour" id="hourHand"></div>
<div class="hand minute" id="minuteHand"></div>
<div class="hand second spin" id="secondHand"></div>
<div class="center-cap" aria-hidden="true"></div>
</div>
<script>
(function () {
const hourHand = document.getElementById('hourHand');
const minuteHand = document.getElementById('minuteHand');
const secondHand = document.getElementById('secondHand');
// Create minute and hour ticks (60 total, 12 hour markers)
const ticksContainer = document.querySelector('.ticks');
for (let i = 0; i < 60; i++) {
const tick = document.createElement('div');
tick.className = 'tick' + (i % 5 === 0 ? ' hour' : '');
tick.style.transform = `translate(-50%, -50%) rotate(${i * 6}deg)`;
ticksContainer.appendChild(tick);
}
// Position numerals
const numerals = document.querySelectorAll('.numeral');
const labels = ['12', '3', '6', '9'];
numerals.forEach((el, i) => {
const angle = i * 90; // 0,90,180,270
el.style.transform = `translate(-50%, -50%) rotate(${angle}deg)`;
el.firstElementChild.textContent = labels[i];
el.firstElementChild.style.left = '50%';
el.firstElementChild.style.top = '50%';
});
// Helpers
const setAngle = (el, deg) => {
el.style.transform = `translate(-50%, -100%) rotate(${deg}deg)`;
};
// Initial set from system time
function updateHands() {
const now = new Date();
const ms = now.getMilliseconds();
const s = now.getSeconds() + ms / 1000;
const m = now.getMinutes() + s / 60;
const h = (now.getHours() % 12) + m / 60;
setAngle(hourHand, h * 30);
setAngle(minuteHand, m * 6);
// Second hand is CSS-animated; align its animation phase to current time.
const delay = -(now.getSeconds() + ms / 1000); // start at exact current second
secondHand.style.animationDelay = `${delay}s`;
}
// Keep minute/hour hands in sync every minute (minimal JS)
updateHands();
let minuteTimer = null;
const scheduleNextMinuteUpdate = () => {
const now = new Date();
const msToNextMinute = (60 - now.getSeconds()) * 1000 - now.getMilliseconds() + 25; // +25ms buffer
clearTimeout(minuteTimer);
minuteTimer = setTimeout(() => {
updateHands();
scheduleNextMinuteUpdate();
}, Math.max(250, msToNextMinute));
};
scheduleNextMinuteUpdate();
// Also re-sync on visibility change (when tab becomes active again)
document.addEventListener('visibilitychange', () => {
if (!document.hidden) updateHands();
});
})();
</script>
</body>
</html>