HTML:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0"
/>
<title>AlpineJS Stopwatch</title>
<script
src="https://cdnjs.cloudflare.com/ajax/libs/alpinejs/3.10.5/cdn.min.js"
defer
></script>
<style>
body {
font-family: Arial, sans-serif;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
margin: 0;
background-color: #f0f0f0;
}
.stopwatch {
background-color: #ffffff;
border-radius: 10px;
padding: 20px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
text-align: center;
}
.time {
font-size: 48px;
font-weight: bold;
margin-bottom: 20px;
color: #333;
}
button {
font-size: 16px;
padding: 10px 20px;
margin: 0 5px;
border: none;
border-radius: 5px;
cursor: pointer;
transition: background-color 0.3s;
}
.start { background-color: #4CAF50; color: white; }
.pause { background-color: #FFC107; color: black; }
.resume { background-color: #2196F3; color: white; }
.stop { background-color: #F44336; color: white; }
.reset { background-color: #9E9E9E; color: white; }
button:hover { opacity: 0.8; }
</style>
</head>
<body>
<div class="stopwatch" x-data="stopwatch()">
<div
class="time"
x-text="formatTime(elapsedTime)"
></div>
<button
@click="start"
x-show="!isRunning && !isPaused"
class="start"
>
Start
</button>
<button
@click="pause"
x-show="isRunning"
class="pause"
>
Pause
</button>
<button
@click="resume"
x-show="isPaused"
class="resume"
>
Resume
</button>
<button
@click="stop"
x-show="isRunning || isPaused"
class="stop"
>
Stop
</button>
<button
@click="reset"
x-show="isPaused || (!isRunning && !isPaused)"
class="reset"
>
Reset
</button>
</div>
<script>
function stopwatch() {
return {
isRunning: false,
isPaused: false,
startTime: 0,
elapsedTime: 0,
timerInterval: null,
start() {
if (!this.isRunning && !this.isPaused) {
this.isRunning = true;
this.startTime =
Date.now() - this.elapsedTime;
this.timerInterval = setInterval(() => {
this.elapsedTime =
Date.now() - this.startTime;
}, 10);
startRecord();
}
},
pause() {
if (this.isRunning) {
this.isRunning = false;
this.isPaused = true;
clearInterval(this.timerInterval);
}
},
resume() {
if (this.isPaused) {
this.isRunning = true;
this.isPaused = false;
this.startTime =
Date.now() - this.elapsedTime;
this.timerInterval = setInterval(() => {
this.elapsedTime =
Date.now() - this.startTime;
}, 10);
}
},
stop() {
this.isRunning = false;
this.isPaused = false;
clearInterval(this.timerInterval);
S.duration = this.elapsedTime / 1000;
this.elapsedTime = 0;
setTimeout(() => {
logRecord();
}, 1000);
},
reset() {
this.elapsedTime = 0;
reset();
},
formatTime(ms) {
let centiseconds = Math.floor((ms % 1000) / 10);
let seconds = Math.floor((ms / 1000) % 60);
let minutes = Math.floor(
(ms / (1000 * 60)) % 60
);
let hours = Math.floor(
(ms / (1000 * 60 * 60)) % 24
);
return `${hours
.toString()
.padStart(2, "0")}:${minutes
.toString()
.padStart(2, "0")}:${seconds
.toString()
.padStart(2, "0")}.${centiseconds
.toString()
.padStart(2, "0")}`;
},
};
}
</script>
</body>
</html>
JavaScript to generate the table:
function jsonToHtmlTable(jsonString) {
// Parse JSON
const data = JSON.parse(jsonString);
// Function to format date
function formatDate(dateString) {
const date = new Date(dateString);
return date.toLocaleString('en-US', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
fractionalSecondDigits: 3
});
}
// Function to format duration
function formatDuration(durationSeconds) {
const totalSeconds = parseFloat(durationSeconds);
const hours = Math.floor(totalSeconds / 3600);
const minutes = Math.floor((totalSeconds % 3600) / 60);
const seconds = Math.floor(totalSeconds % 60);
const milliseconds = Math.round((totalSeconds % 1) * 1000);
let formattedDuration = '';
if (hours > 0) {
formattedDuration += `${hours}h `;
}
if (minutes > 0 || hours > 0) {
formattedDuration += `${minutes}m `;
}
formattedDuration += `${seconds}.${milliseconds.toString().padStart(3, '0')}s`;
return formattedDuration.trim();
}
// Generate table HTML
let tableHtml = '<table style="border-collapse: collapse; width: 100%; font-family: Arial, sans-serif;"><thead style="background-color: #f2f2f2;"><tr><th style="border: 1px solid #ddd; padding: 12px; text-align: left;">Start Time</th><th style="border: 1px solid #ddd; padding: 12px; text-align: left;">End Time</th><th style="border: 1px solid #ddd; padding: 12px; text-align: left;">Duration</th></tr></thead><tbody>';
data.forEach((item, index) => {
const rowStyle = index % 2 === 0 ? 'background-color: #f9f9f9;' : 'background-color: #ffffff;';
tableHtml += `<tr style="${rowStyle}">`;
tableHtml += `<td style="border: 1px solid #ddd; padding: 12px;">${formatDate(item['Start Time'])}</td>`;
tableHtml += `<td style="border: 1px solid #ddd; padding: 12px;">${formatDate(item['End Time'])}</td>`;
tableHtml += `<td style="border: 1px solid #ddd; padding: 12px;">${formatDuration(item['Duration'])}</td>`;
tableHtml += '</tr>';
});
tableHtml += '</tbody></table>';
return tableHtml;
}
return jsonToHtmlTable(p1);