const $uuidQty = $('#uuid-qty');
const $uuidUpper = $('#uuid-upper');
const $uuidHyphens = $('#uuid-hyphens');
const $uuidGenerateBtn = $('#uuid-generate-btn');
const $uuidOutput = $('#uuid-output');
const $uuidCopyBtn = $('#uuid-copy-btn');
const $uuidVersionV4 = $('#uuid-version-v4');
const $uuidVersionV7 = $('#uuid-version-v7');
const $uuidV7Timestamp = $('#uuid-v7-timestamp');
const $uuidV7TimestampValue = $('#uuid-v7-timestamp-value');
let uuidVersion = 'v4';
const uuidv7 = () => {
const now = Date.now();
const bytes = new Uint8Array(16);
window.crypto.getRandomValues(bytes);
bytes[0] = (now / 2 ** 40) & 0xff;
bytes[1] = (now / 2 ** 32) & 0xff;
bytes[2] = (now / 2 ** 24) & 0xff;
bytes[3] = (now / 2 ** 16) & 0xff;
bytes[4] = (now / 2 ** 8) & 0xff;
bytes[5] = now & 0xff;
bytes[6] = (bytes[6] & 0x0f) | 0x70;
bytes[8] = (bytes[8] & 0x3f) | 0x80;
const hex = [...bytes].map((b, i) =>
[4, 6, 8, 10].includes(i) ? '-' + b.toString(16).padStart(2, '0') : b.toString(16).padStart(2, '0')
).join('');
return { id: hex, timestampMs: now };
};
const updateVersionUI = () => {
const isV4 = uuidVersion === 'v4';
$uuidVersionV4
.toggleClass('bg-blue-600 text-white shadow-sm', isV4)
.toggleClass('text-gray-500 hover:text-gray-300', !isV4);
$uuidVersionV7
.toggleClass('bg-blue-600 text-white shadow-sm', !isV4)
.toggleClass('text-gray-500 hover:text-gray-300', isV4);
$uuidV7Timestamp.toggleClass('hidden', isV4);
};
$uuidVersionV4.on('click', () => { uuidVersion = 'v4'; updateVersionUI(); });
$uuidVersionV7.on('click', () => { uuidVersion = 'v7'; updateVersionUI(); });
window.generateUuids = () => {
let qty = parseInt($uuidQty.val(), 10);
if (isNaN(qty) || qty < 1) qty = 1;
if (qty > 1000) qty = 1000;
const isUpper = $uuidUpper.is(':checked');
const removeHyphens = $uuidHyphens.is(':checked');
let results = [];
let firstTimestampMs = null;
for(let i=0; i<qty; i++) {
let id, timestampMs;
if (uuidVersion === 'v7') {
({ id, timestampMs } = uuidv7());
if (firstTimestampMs === null) firstTimestampMs = timestampMs;
} else {
id = window.crypto.randomUUID();
}
if (removeHyphens) id = id.replaceAll('-', '');
if (isUpper) id = id.toUpperCase();
results.push(id);
}
$uuidOutput.val(results.join('\n'));
if (uuidVersion === 'v7' && firstTimestampMs !== null) {
$uuidV7TimestampValue.text(new Date(firstTimestampMs).toISOString());
}
};
$uuidGenerateBtn.on('click', window.generateUuids);
updateVersionUI();
$uuidCopyBtn.on('click', () => {
const txt = $uuidOutput.val();
if(txt) {
navigator.clipboard.writeText(txt);
const origBtnText = $uuidCopyBtn.html();
$uuidCopyBtn.html('<svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path></svg> Copied!');
setTimeout(() => {
$uuidCopyBtn.html(origBtnText);
}, 2000);
}
});