bit-twiddler 0.2.0

Cross-platform developer toolbox: bit manipulation, hashing, YAML/JSON/SQL, QR, Markdown, cron, and 40+ more tools — Tauri v2, no Node.js
  // --- UUID Generator Logic ---
  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);

    // Timestamp (48 bits, big-endian milliseconds since epoch)
    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;
    // Version (4 bits = 0x7)
    bytes[6] = (bytes[6] & 0x0f) | 0x70;
    // Variant (2 bits = 0b10)
    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);
    }
  });