JSFiddle - React, Tailwind, and code Playground

by arian_

HTML

<div class="character-container">
    <div id="speech-bubble">
        <span class="message" id="message-default" style="display: initial;">
            Hello! It's-a me, Mario!<br>
            I will tell you when your Mii™ was created if you give me its data below!<br>
            Cons include... you'll find out! Wahoo!<br>
        </span>
        <span class="message" id="message-invalid">Mamma Mia, that is not valid Mii™ data!</span>
        <span class="message" id="message-version-1">
            Wii data detected!<br>
            CreateID Hex: <span id="createid-result-v1"></span><br>
            Flags: <span id="createid-flags-v1"></span><br>
            MAC Address: <span id="createid-base-v1"></span><br>
            Created On(?): <span id="createid-date-v1"></span>
        </span>
        <span class="message" id="message-version-3">
            3DS/Wii U data detected!<br>
            CreateID: <span id="createid-result-v3"></span><br>
            <!--Flags: <span id="createid-flags-v3"></span><br>-->
            <span id="createid-base-v3"></span><br>
            <b>Created On: <span id="createid-date-v3"></span></b>
        </span>
        <span class="message" id="message-version-4">Switch data detected! CreateID (Hex): <span id="createid-result-v4"></span>
            Switch data does not have date information in the CreateID. Therefore, this information is Lost Media. Mamma Mia.
        </span>
        <span class="message" id="message-studio">
            Mamma Mia... Mii Studio data lacks a CreateID field, so you will never ever know when it this Mii™ was made.
        </span>
        <span class="message" id="message-miic">
            Mamma Mia... the <a target="_blank" href="https://mii.nxw.pw/">Mii Creator app</a> doesn't include a date in the CreateID field.
        </span>
        <span class="message" id="message-exception">
            <span id="exception-message"></span>
        </span>
    </div>
    <img id="character-normal"...

CSS

body {
    font-family: Arial, sans-serif;
    text-align: center;
    margin: 50px;
}

.character-container {
    position: relative;
    display: inline-block;
}

#character-normal, #character-sad {
    margin-right: 200px;
    width: 249px;
    height: 290px;
}
#character-sad {
    padding-right: 2px;
}

#speech-bubble {
    position: absolute;
    top: -20px;
    left: 190px;
    width: 300px;
    padding: 10px;
    border: 2px solid black;
    background: white;
    border-radius: 10px;
}

input {
    margin-top: 20px;
    padding: 10px;
    width: 80%;
    max-width: 400px;
}

button {
    margin-top: 10px;
    padding: 10px 20px;
}

.message {
    display: none;
}

JavaScript

const messageElements = document.querySelectorAll('.message');

function showMessage(messageId) {
    messageElements.forEach(el => el.style.display = 'none');
    document.getElementById(messageId).style.display = 'initial';
}

function toggleCharacter(happy) {
    document.getElementById('character-normal').style.display = happy ? 'initial' : 'none';
    document.getElementById('character-sad').style.display = happy ? 'none' : 'initial';
}

// Updated byte conversion utilities
const stripSpaces = str => str.replace(/\s+/g, '');

const hexToUint8Array = hex => 
new Uint8Array(hex.match(/.{1,2}/g).map(byte => parseInt(byte, 16)));

const base64ToUint8Array = base64 => {
    const normalizedBase64 = base64.replace(/-/g, '+').replace(/_/g, '/');
    const paddedBase64 = normalizedBase64.padEnd(normalizedBase64.length + (4 - (normalizedBase64.length % 4)) % 4, '=');
    return Uint8Array.from(atob(paddedBase64), c => c.charCodeAt(0));
};

const uint8ArrayToHex = uint8Array =>
Array.from(uint8Array).map(byte => byte.toString(16).padStart(2, '0')).join('').toUpperCase();

const parseHexOrB64TextStringToUint8Array = text => {
    const cleanedData = stripSpaces(text);
    return /^[0-9a-fA-F]+$/.test(cleanedData) ? hexToUint8Array(cleanedData) : base64ToUint8Array(cleanedData);
};

function formatMacAddress(input) {
    // Convert Uint8Array to hex if needed
    const hexArray = typeof input === "string"
        ? input.match(/.{1,2}/g) // Split string into pairs
        : Array.from(input).map(byte => byte.toString(16).padStart(2, '0')); // Format Uint8Array to hex

    return hexArray.join(':').toUpperCase();
}

// Centralized Mii data table with fixed extraction
const miiDataTable = [
    {
        lengths: [72, 92, 96],
        version: 3,
        extractCreateID: (data) => data.slice(12, 22),
        birthPlatform: (data) => data[3] >> 4 & 7
    },
    {
        lengths: [74, 76],
        version: 1,
        extractCreateID: (data) => data.slice(24, 34),
       ...