Lompat ke isi

Memposting Media Pembelajaran berbasis HTML di Blogger: Perbedaan antara revisi

Dari Wiki Berbudi
←Membuat halaman berisi 'Menyimpan media pembelajaran secara online lebih memudahkan guru saat ingin menampilkannya kepada para peserta didik. Hal tersebut karena dengan menggunakan jaringan internet kita cukup menyimpan file media pembelajaran 1 kali dan menampilkannya berkali-kali di perangkat apa pun. Salah satu jenis media yang digunakan dalam kegiatan ini adalah media hasil generate dari AI, baik itu Canva, Gemini, ChatGPT, dsb. dalam format atau ekstensi *.html. Sebelumnya saya...'
 
Tidak ada ringkasan suntingan
 
Baris 13: Baris 13:


   <!--2. TEMPAT KODE SUMBER (Hanya paste HTML Anda di sini)-->
   <!--2. TEMPAT KODE SUMBER (Hanya paste HTML Anda di sini)-->
   <textarea style="display: none;"><!-- ↓↓↓ PASTE KODE HTML APLIKASI ANDA DI BAWAH BARIS INI ↓↓↓ -->
   <textarea style="display: none;">
  <!-- ↓↓↓ PASTE KODE HTML APLIKASI ANDA DI BAWAH BARIS INI ↓↓↓ -->


<!DOCTYPE html>
<html lang="id">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
    <title>Visualisasi Pecahan, Desimal & Persen</title>
    <link href="https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;600;800&family=Space+Mono:wght@700&display=swap" rel="stylesheet">
    <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet">
    <style>
        :root {
            --primary: #0284C7; /* Light Blue 600 */
            --primary-light: #38BDF8; /* Light Blue 400 */
            --secondary: #059669; /* Emerald 600 */
            --secondary-light: #34D399; /* Emerald 400 */
            --accent: #D97706; /* Amber 600 */
            --accent-light: #FBBF24; /* Amber 400 */
            --danger: #EF4444;
            --dark-bg: #0F172A; /* Slate 900 */
            --panel-bg: rgba(30, 41, 59, 0.7); /* Slate 800 */
            --glass-border: rgba(255, 255, 255, 0.1);
            --text-main: #F8FAFC;
            --text-muted: #94A3B8;
        }
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            font-family: 'Outfit', sans-serif;
            touch-action: manipulation;
        }
        body {
            background: linear-gradient(135deg, var(--dark-bg), #082F49);
            color: var(--text-main);
            height: 100vh;
            display: flex;
            flex-direction: column;
            overflow: hidden;
        }
        /* Header */
        header {
            background: rgba(15, 23, 42, 0.8);
            backdrop-filter: blur(10px);
            border-bottom: 1px solid var(--glass-border);
            padding: 10px 20px;
            display: flex;
            align-items: center;
            justify-content: center;
            gap: 12px;
            z-index: 10;
            height: 50px;
        }
        header h1 {
            font-size: 1.1rem;
            font-weight: 800;
            background: linear-gradient(to right, #7DD3FC, #6EE7B7);
            -webkit-background-clip: text;
            -webkit-text-fill-color: transparent;
            text-transform: uppercase;
            letter-spacing: 1px;
        }
        header i {
            color: #7DD3FC;
            font-size: 1.3rem;
        }
        /* Main Container */
        .main-container {
            flex: 1;
            display: flex;
            flex-direction: column;
            padding: 12px;
            gap: 12px;
            height: calc(100vh - 50px);
        }
        /* Visual Panel */
        .visual-panel {
            flex: 1.3;
            background: var(--panel-bg);
            border: 1px solid var(--glass-border);
            border-radius: 20px;
            position: relative;
            overflow: hidden;
            display: flex;
            box-shadow: 0 10px 30px rgba(0,0,0,0.3);
            background-image: radial-gradient(circle at 50% 50%, rgba(2, 132, 199, 0.1) 0%, transparent 70%),
                              repeating-linear-gradient(45deg, rgba(255,255,255,0.02) 0px, rgba(255,255,255,0.02) 20px, transparent 20px, transparent 40px);
        }
        .visual-content {
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: space-evenly;
            width: 100%;
            height: 100%;
            padding: 10px;
        }
        .grid-container {
            position: relative;
            width: 200px;
            height: 200px;
        }
        .grid-bg-glow {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            width: 150%;
            height: 150%;
            background: radial-gradient(circle at center, rgba(52, 211, 153, 0.25) 0%, transparent 65%);
            pointer-events: none;
            transition: opacity 0.2s;
            opacity: 0;
        }
        .grid-100 {
            position: absolute;
            top: 0; left: 0; right: 0; bottom: 0;
            display: grid;
            grid-template-columns: repeat(10, 1fr);
            grid-template-rows: repeat(10, 1fr);
            gap: 2px;
        }
        .grid-cell {
            background: rgba(255,255,255,0.05);
            border-radius: 3px;
        }
        .value-cards {
            display: flex;
            gap: 10px;
            width: 100%;
            justify-content: center;
            padding: 0 5px;
        }
        .value-card {
            background: rgba(15, 23, 42, 0.6);
            backdrop-filter: blur(10px);
            border: 1px solid var(--glass-border);
            border-radius: 12px;
            padding: 10px 5px;
            flex: 1;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            box-shadow: 0 4px 15px rgba(0,0,0,0.2);
            transition: transform 0.2s, border-color 0.2s;
        }
        .card-label {
            font-size: 0.65rem;
            text-transform: uppercase;
            letter-spacing: 1px;
            color: var(--text-muted);
            margin-bottom: 5px;
        }
        .card-value {
            font-family: 'Space Mono', monospace;
            font-size: 1.3rem;
            font-weight: 700;
        }
        .frac-display {
            display: flex;
            flex-direction: column;
            align-items: center;
            font-family: 'Space Mono', monospace;
            font-weight: 700;
            font-size: 1.2rem;
            line-height: 1;
            color: var(--primary-light);
        }
        .frac-line {
            width: 100%;
            min-width: 20px;
            height: 2px;
            background: currentColor;
            margin: 3px 0;
            border-radius: 2px;
        }
        /* Control Panel */
        .control-panel {
            flex: 0.7;
            display: flex;
            flex-direction: column;
            background: var(--panel-bg);
            border: 1px solid var(--glass-border);
            border-radius: 20px;
            padding: 12px;
        }
        .tabs {
            display: flex;
            background: rgba(0,0,0,0.2);
            border-radius: 10px;
            padding: 4px;
            margin-bottom: 12px;
        }
        .tab-btn {
            flex: 1;
            padding: 8px;
            background: transparent;
            border: none;
            color: var(--text-muted);
            font-family: 'Outfit', sans-serif;
            font-weight: 600;
            font-size: 0.9rem;
            cursor: pointer;
            border-radius: 8px;
            transition: all 0.3s;
            display: flex;
            justify-content: center;
            align-items: center;
            gap: 6px;
        }
        .tab-btn.active {
            background: var(--primary);
            color: white;
            box-shadow: 0 2px 10px rgba(2, 132, 199, 0.4);
        }
        .mode-container {
            flex: 1;
            display: flex;
            flex-direction: column;
            gap: 10px;
        }
        .slider-group {
            background: rgba(255,255,255,0.05);
            border: 1px solid var(--glass-border);
            border-radius: 10px;
            padding: 10px 12px;
        }
        .slider-header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 10px;
        }
        .slider-label {
            font-size: 0.85rem;
            font-weight: 600;
            color: var(--text-muted);
            display: flex;
            align-items: center;
            gap: 6px;
        }
        .slider-val-display {
            font-family: 'Space Mono', monospace;
            font-weight: 700;
            font-size: 1rem;
            color: white;
            background: rgba(0,0,0,0.3);
            padding: 2px 8px;
            border-radius: 6px;
            border: 1px solid var(--glass-border);
        }
        input[type="range"] {
            width: 100%;
            -webkit-appearance: none;
            height: 6px;
            background: rgba(255,255,255,0.1);
            border-radius: 3px;
            outline: none;
        }
        input[type="range"]::-webkit-slider-thumb {
            -webkit-appearance: none;
            width: 22px;
            height: 22px;
            border-radius: 50%;
            background: white;
            cursor: pointer;
            box-shadow: 0 0 10px rgba(0,0,0,0.5);
            transition: transform 0.1s;
        }
       
        input[type="range"]::-webkit-slider-thumb:active {
            transform: scale(1.2);
            background: var(--secondary-light);
        }
        .quick-presets {
            margin-top: 2px;
        }
        .preset-grid {
            display: grid;
            grid-template-columns: repeat(3, 1fr);
            gap: 8px;
        }
        .preset-btn {
            background: rgba(255,255,255,0.05);
            border: 1px solid rgba(255,255,255,0.1);
            color: white;
            font-family: 'Space Mono', monospace;
            font-size: 0.95rem;
            font-weight: 700;
            padding: 8px 0;
            border-radius: 8px;
            cursor: pointer;
            transition: all 0.2s;
        }
        .preset-btn:active {
            background: var(--primary);
            transform: scale(0.95);
        }
        .btn {
            padding: 10px;
            border: none;
            border-radius: 10px;
            font-size: 0.9rem;
            font-weight: 700;
            cursor: pointer;
            transition: all 0.2s;
            text-transform: uppercase;
            letter-spacing: 0.5px;
            display: flex;
            align-items: center;
            justify-content: center;
            gap: 8px;
            width: 100%;
        }
        .btn-action {
            background: linear-gradient(135deg, var(--primary), #0369A1);
            color: white;
            margin-top: auto;
            box-shadow: 0 4px 15px rgba(2, 132, 199, 0.4);
        }
        .btn-action:active { transform: translateY(2px); }
        /* Kuis Mode Styles */
        .kuis-info {
            text-align: center;
            font-size: 0.9rem;
            line-height: 1.4;
            padding: 0 5px;
        }
        .kuis-display-box {
            background: rgba(0,0,0,0.3);
            border: 1px dashed var(--glass-border);
            border-radius: 12px;
            padding: 10px;
            display: flex;
            justify-content: center;
            align-items: center;
            min-height: 70px;
            margin: 5px 0;
        }
        .kuis-text-val {
            font-family: 'Space Mono', monospace;
            font-size: 1.8rem;
            font-weight: 700;
            color: var(--accent-light);
        }
        .input-group {
            display: flex;
            align-items: center;
            background: rgba(0,0,0,0.4);
            border: 1px solid var(--glass-border);
            border-radius: 10px;
            padding: 5px 15px;
        }
        .input-group input {
            flex: 1;
            background: transparent;
            border: none;
            color: white;
            font-family: 'Space Mono', monospace;
            font-size: 1.4rem;
            font-weight: bold;
            text-align: center;
            padding: 6px;
            outline: none;
            width: 100%;
        }
        .input-group .unit {
            font-size: 1.3rem;
            font-weight: bold;
            color: var(--text-muted);
        }
        .action-area {
            display: flex;
            gap: 10px;
        }
        .btn-check {
            background: linear-gradient(135deg, var(--secondary), #047857);
            color: white;
            flex: 1.5;
            box-shadow: 0 4px 15px rgba(5, 150, 105, 0.4);
        }
       
        .btn-new {
            background: rgba(255,255,255,0.1);
            color: white;
            border: 1px solid var(--glass-border);
            flex: 1;
        }
        /* Modals & Overlays */
        .overlay {
            position: fixed;
            top: 0; left: 0; right: 0; bottom: 0;
            background: rgba(0,0,0,0.8);
            backdrop-filter: blur(5px);
            display: flex;
            justify-content: center;
            align-items: center;
            z-index: 1000;
            opacity: 0;
            pointer-events: none;
            transition: opacity 0.3s;
        }
        .overlay.show {
            opacity: 1;
            pointer-events: all;
        }
        .modal-card {
            background: var(--dark-bg);
            border: 1px solid var(--glass-border);
            border-radius: 20px;
            width: 90%;
            max-width: 450px;
            max-height: 85vh;
            display: flex;
            flex-direction: column;
            overflow: hidden;
            transform: translateY(20px);
            transition: transform 0.3s;
            box-shadow: 0 15px 40px rgba(0,0,0,0.5);
        }
        .overlay.show .modal-card {
            transform: translateY(0);
        }
        .modal-header {
            background: rgba(255,255,255,0.05);
            padding: 15px 20px;
            display: flex;
            justify-content: space-between;
            align-items: center;
            border-bottom: 1px solid var(--glass-border);
        }
        .modal-header h2 {
            font-size: 1.1rem;
            color: var(--accent-light);
            display: flex;
            align-items: center;
            gap: 10px;
        }
        .btn-close-icon {
            background: none;
            border: none;
            color: var(--text-muted);
            font-size: 1.4rem;
            cursor: pointer;
            transition: color 0.2s;
            padding: 5px;
        }
        .btn-close-icon:hover { color: white; }
        .modal-body {
            padding: 15px;
            overflow-y: auto;
            display: flex;
            flex-direction: column;
            gap: 12px;
        }
        .step-card {
            background: rgba(255,255,255,0.03);
            border: 1px solid rgba(255,255,255,0.05);
            border-radius: 12px;
            padding: 15px;
        }
        .step-title {
            font-weight: 700;
            color: var(--primary-light);
            margin-bottom: 5px;
            font-size: 0.95rem;
        }
        .step-desc {
            font-size: 0.85rem;
            color: var(--text-muted);
            margin-bottom: 10px;
            line-height: 1.4;
        }
        .step-math {
            font-family: 'Space Mono', monospace;
            font-size: 0.9rem;
            line-height: 1.6;
            background: rgba(0,0,0,0.3);
            padding: 12px;
            border-radius: 8px;
            color: white;
        }
        .highlight {
            color: var(--secondary-light);
            font-weight: bold;
        }
        /* Status Modal */
        .status-card {
            background: var(--panel-bg);
            border: 1px solid var(--glass-border);
            padding: 25px;
            border-radius: 20px;
            text-align: center;
            transform: scale(0.8);
            transition: transform 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
            max-width: 80%;
            box-shadow: 0 20px 50px rgba(0,0,0,0.5);
        }
        .overlay.show .status-card { transform: scale(1); }
        .status-icon {
            font-size: 3rem;
            margin-bottom: 10px;
        }
        .status-title {
            font-size: 1.4rem;
            font-weight: 800;
            margin-bottom: 5px;
        }
        .status-desc {
            font-size: 0.9rem;
            color: var(--text-muted);
            margin-bottom: 15px;
            line-height: 1.4;
        }
        .correct-theme .status-icon, .correct-theme .status-title { color: var(--secondary-light); }
        .wrong-theme .status-icon, .wrong-theme .status-title { color: var(--danger); }
        @media (min-width: 768px) {
            .main-container {
                flex-direction: row;
                padding: 20px;
                gap: 20px;
            }
            .visual-panel {
                flex: 1.5;
            }
            .control-panel {
                flex: 1;
                padding: 20px;
                gap: 15px;
            }
            .grid-container {
                width: 280px;
                height: 280px;
            }
            .value-card {
                padding: 15px;
                max-width: 140px;
            }
            .card-value {
                font-size: 1.8rem;
            }
            .frac-display {
                font-size: 1.6rem;
            }
            .btn {
                padding: 12px;
                font-size: 1rem;
            }
        }
    </style>
</head>
<body>
    <header>
        <i class="fas fa-chart-pie"></i>
        <h1>Pecahan, Desimal & Persen</h1>
    </header>
    <div class="main-container">
        <!-- Visual Panel -->
        <div class="visual-panel">
            <div class="visual-content">
                <div class="grid-container">
                    <div class="grid-bg-glow" id="gridGlow"></div>
                    <div class="grid-100" id="grid100">
                        <!-- Generated via JS -->
                    </div>
                </div>
               
                <div class="value-cards">
                    <div class="value-card" id="cardPecahan">
                        <div class="card-label">Pecahan</div>
                        <div class="frac-display">
                            <div class="frac-num">1</div>
                            <div class="frac-line"></div>
                            <div class="frac-den">4</div>
                        </div>
                    </div>
                    <div class="value-card" id="cardDesimal">
                        <div class="card-label">Desimal</div>
                        <div class="card-value" style="color: var(--primary-light);" id="dispDes">0.25</div>
                    </div>
                    <div class="value-card" id="cardPersen">
                        <div class="card-label">Persen</div>
                        <div class="card-value" style="color: var(--accent-light);" id="dispPct">25%</div>
                    </div>
                </div>
            </div>
        </div>
        <!-- Control Panel -->
        <div class="control-panel">
            <div class="tabs">
                <button class="tab-btn active" id="tabEksplorasi" onclick="setMode('eksplorasi')"><i class="fas fa-search"></i> Eksplorasi</button>
                <button class="tab-btn" id="tabKuis" onclick="setMode('kuis')"><i class="fas fa-gamepad"></i> Tantangan</button>
            </div>
            <!-- Mode Eksplorasi -->
            <div id="modeEksplorasi" class="mode-container">
                <div class="slider-group">
                    <div class="slider-header">
                        <span class="slider-label"><i class="fas fa-sliders-h"></i> Atur Persentase</span>
                        <span class="slider-val-display" id="sliderValDisplay">25%</span>
                    </div>
                    <input type="range" id="mainSlider" min="0" max="100" step="0.5" value="25">
                </div>
               
                <div class="quick-presets">
                    <div class="slider-label" style="margin-bottom:8px;"><i class="fas fa-bolt"></i> Tombol Cepat</div>
                    <div class="preset-grid">
                        <button class="preset-btn" onclick="setPreset(50)">1/2</button>
                        <button class="preset-btn" onclick="setPreset(25)">1/4</button>
                        <button class="preset-btn" onclick="setPreset(75)">3/4</button>
                        <button class="preset-btn" onclick="setPreset(20)">1/5</button>
                        <button class="preset-btn" onclick="setPreset(10)">1/10</button>
                        <button class="preset-btn" onclick="setPreset(12.5)">1/8</button>
                    </div>
                </div>
                <button class="btn btn-action" onclick="showExplanation()">
                    <i class="fas fa-lightbulb"></i> Cara Mengubah
                </button>
            </div>
            <!-- Mode Kuis -->
            <div id="modeKuis" class="mode-container" style="display:none;">
                <div class="kuis-info" id="kuisQuestion">
                    Ubah bentuk di bawah menjadi <b>Persen</b>:
                </div>
               
                <div class="kuis-display-box" id="kuisDisplayBox">
                    <!-- Placeholder -->
                </div>
                <div class="input-group">
                    <input type="number" id="inputKuis" placeholder="Ketikan jawaban..." step="any">
                    <span class="unit" id="kuisUnit">%</span>
                </div>
                <div class="action-area" style="margin-top: auto;">
                    <button class="btn btn-new" onclick="randomKuis()">
                        <i class="fas fa-random"></i> Lewati
                    </button>
                    <button class="btn btn-check" onclick="cekKuis()">
                        <i class="fas fa-check"></i> Cek Jawaban
                    </button>
                </div>
            </div>
        </div>
    </div>
    <!-- Explanation Overlay -->
    <div id="explanationOverlay" class="overlay">
        <div class="modal-card">
            <div class="modal-header">
                <h2><i class="fas fa-lightbulb"></i> Cara Mengubah Bentuk</h2>
                <button class="btn-close-icon" onclick="closeExplanation()"><i class="fas fa-times"></i></button>
            </div>
            <div class="modal-body">
                <div class="step-card">
                    <div class="step-title">1. Pecahan ke Desimal</div>
                    <div class="step-desc">Ubah penyebut menjadi 10, 100, atau 1000. Atau bagikan langsung pembilang dengan penyebut.</div>
                    <div class="step-math">
                        <span class="highlight">1/4</span> = 1 ÷ 4 = <span class="highlight">0.25</span><br>
                        <span class="highlight">2/5</span> = (2×2) / (5×2) = 4/10 = <span class="highlight">0.4</span>
                    </div>
                </div>
                <div class="step-card">
                    <div class="step-title">2. Desimal ke Persen</div>
                    <div class="step-desc">Kalikan nilai desimal dengan 100 (geser koma ke kanan 2 kali) dan beri simbol %.</div>
                    <div class="step-math">
                        <span class="highlight">0.25</span> × 100 = <span class="highlight">25%</span><br>
                        <span class="highlight">0.4</span> × 100 = <span class="highlight">40%</span>
                    </div>
                </div>
                <div class="step-card">
                    <div class="step-title">3. Persen ke Pecahan</div>
                    <div class="step-desc">Tulis angka persen sebagai pembilang, dan 100 sebagai penyebut. Lalu sederhanakan.</div>
                    <div class="step-math">
                        <span class="highlight">25%</span> = 25/100 = <span class="highlight">1/4</span>
                    </div>
                </div>
            </div>
        </div>
    </div>
    <!-- Status Overlay -->
    <div id="statusOverlay" class="overlay">
        <div class="status-card">
            <div class="status-icon" id="statusIcon"><i class="fas fa-check-circle"></i></div>
            <div class="status-title" id="statusTitle">Tepat Sekali!</div>
            <div class="status-desc" id="statusDesc">Jawabanmu sudah benar.</div>
            <button class="btn btn-action" style="width: 100%; justify-content: center; margin-top: 10px;" onclick="closeStatus()">Lanjut</button>
        </div>
    </div>
    <script>
        // Init Grid
        const grid = document.getElementById('grid100');
        for (let i = 0; i < 100; i++) {
            const cell = document.createElement('div');
            cell.className = 'grid-cell';
            grid.appendChild(cell);
        }
        // Logic Helpers
        function gcd(a, b) {
            return b ? gcd(b, a % b) : a;
        }
        function getSimplifiedFraction(percent) {
            let n = Math.round(percent * 10);
            let d = 1000;
            let divisor = gcd(n, d);
            return { n: n / divisor, d: d / divisor };
        }
        // Update Visuals Core Function
        function updateVisuals(percent) {
            // 1. Update Grid
            const cells = grid.children;
            for (let i = 0; i < 100; i++) {
                if (percent >= i + 1) {
                    cells[i].style.background = 'var(--secondary-light)';
                    cells[i].style.boxShadow = '0 0 4px rgba(52, 211, 153, 0.4)';
                } else if (percent > i) {
                    let fill = (percent - i) * 100;
                    cells[i].style.background = `linear-gradient(to right, var(--secondary-light) ${fill}%, rgba(255,255,255,0.05) ${fill}%)`;
                    cells[i].style.boxShadow = 'none';
                } else {
                    cells[i].style.background = 'rgba(255,255,255,0.05)';
                    cells[i].style.boxShadow = 'none';
                }
            }
            document.getElementById('gridGlow').style.opacity = (percent / 100) * 0.8;
            // 2. Format displays
            let displayPercent = percent % 1 === 0 ? percent : percent.toFixed(1);
            let decimalVal = percent / 100;
            document.getElementById('dispDes').innerText = decimalVal.toString();
            document.getElementById('dispPct').innerText = displayPercent + '%';
            const cardPecahan = document.getElementById('cardPecahan');
            if (percent === 0) {
                cardPecahan.innerHTML = `<div class="card-label">Pecahan</div><div class="card-value" style="color: var(--primary-light);">0</div>`;
            } else if (percent === 100) {
                cardPecahan.innerHTML = `<div class="card-label">Pecahan</div><div class="card-value" style="color: var(--primary-light);">1</div>`;
            } else {
                let frac = getSimplifiedFraction(percent);
                cardPecahan.innerHTML = `
                    <div class="card-label">Pecahan</div>
                    <div class="frac-display">
                        <div class="frac-num">${frac.n}</div>
                        <div class="frac-line"></div>
                        <div class="frac-den">${frac.d}</div>
                    </div>
                `;
            }
        }
        // Event Listeners for Mode Eksplorasi
        const mainSlider = document.getElementById('mainSlider');
        const sliderValDisplay = document.getElementById('sliderValDisplay');
        mainSlider.addEventListener('input', (e) => {
            let val = parseFloat(e.target.value);
            let dispVal = val % 1 === 0 ? val : val.toFixed(1);
            sliderValDisplay.innerText = dispVal + '%';
            updateVisuals(val);
        });
        function setPreset(val) {
            mainSlider.value = val;
            let dispVal = val % 1 === 0 ? val : val.toFixed(1);
            sliderValDisplay.innerText = dispVal + '%';
            updateVisuals(val);
        }
        // Init initial visual
        updateVisuals(25);
        // UI Tabs
        const tabEksplorasi = document.getElementById('tabEksplorasi');
        const tabKuis = document.getElementById('tabKuis');
        const modeEksplorasi = document.getElementById('modeEksplorasi');
        const modeKuis = document.getElementById('modeKuis');
        function setMode(mode) {
            if (mode === 'eksplorasi') {
                tabEksplorasi.classList.add('active');
                tabKuis.classList.remove('active');
                modeEksplorasi.style.display = 'flex';
                modeKuis.style.display = 'none';
               
                // restore visual to slider
                let val = parseFloat(mainSlider.value);
                updateVisuals(val);
            } else {
                tabEksplorasi.classList.remove('active');
                tabKuis.classList.add('active');
                modeEksplorasi.style.display = 'none';
                modeKuis.style.display = 'flex';
                randomKuis();
            }
        }
        // Modals
        function showExplanation() {
            document.getElementById('explanationOverlay').classList.add('show');
        }
        function closeExplanation() {
            document.getElementById('explanationOverlay').classList.remove('show');
        }
        // Kuis Logic
        const kuisTypes = [
            { from: 'Pecahan', to: 'Persen', unit: '%' },
            { from: 'Pecahan', to: 'Desimal', unit: '' },
            { from: 'Desimal', to: 'Persen', unit: '%' },
            { from: 'Persen', to: 'Desimal', unit: '' }
        ];
        const kuisValues = [
            { frac: {n:1, d:2}, dec: '0.5', pct: '50' },
            { frac: {n:1, d:4}, dec: '0.25', pct: '25' },
            { frac: {n:3, d:4}, dec: '0.75', pct: '75' },
            { frac: {n:1, d:5}, dec: '0.2', pct: '20' },
            { frac: {n:2, d:5}, dec: '0.4', pct: '40' },
            { frac: {n:3, d:5}, dec: '0.6', pct: '60' },
            { frac: {n:4, d:5}, dec: '0.8', pct: '80' },
            { frac: {n:1, d:10}, dec: '0.1', pct: '10' },
            { frac: {n:3, d:10}, dec: '0.3', pct: '30' },
            { frac: {n:7, d:10}, dec: '0.7', pct: '70' },
            { frac: {n:9, d:10}, dec: '0.9', pct: '90' },
            { frac: {n:1, d:8}, dec: '0.125', pct: '12.5' },
            { frac: {n:3, d:8}, dec: '0.375', pct: '37.5' },
            { frac: {n:1, d:20}, dec: '0.05', pct: '5' },
            { frac: {n:3, d:20}, dec: '0.15', pct: '15' }
        ];
        let currentKuisAnswer = 0;
        let currentKuisPctVal = 0;
        function randomKuis() {
            // Update visual to empty or interrogative
            updateVisuals(0);
            document.getElementById('gridGlow').style.opacity = 0;
            const typeObj = kuisTypes[Math.floor(Math.random() * kuisTypes.length)];
            const valObj = kuisValues[Math.floor(Math.random() * kuisValues.length)];
           
            let fromText = '';
            let targetAnswer = 0;
           
            if (typeObj.from === 'Pecahan') {
                fromText = `<div class="frac-display" style="font-size: 2.2rem; color: var(--text-main);">
                    <div class="frac-num">${valObj.frac.n}</div>
                    <div class="frac-line"></div>
                    <div class="frac-den">${valObj.frac.d}</div>
                </div>`;
            } else if (typeObj.from === 'Desimal') {
                fromText = `<div class="kuis-text-val">${valObj.dec}</div>`;
            } else if (typeObj.from === 'Persen') {
                fromText = `<div class="kuis-text-val">${valObj.pct}%</div>`;
            }
           
            if (typeObj.to === 'Persen') targetAnswer = parseFloat(valObj.pct);
            else if (typeObj.to === 'Desimal') targetAnswer = parseFloat(valObj.dec);
           
            document.getElementById('kuisQuestion').innerHTML = `Ubah bentuk ${typeObj.from.toLowerCase()} di bawah menjadi <b>${typeObj.to}</b>:`;
            document.getElementById('kuisDisplayBox').innerHTML = fromText;
            document.getElementById('kuisUnit').innerText = typeObj.unit;
            document.getElementById('inputKuis').value = '';
            document.getElementById('inputKuis').focus();
           
            currentKuisAnswer = targetAnswer;
            currentKuisPctVal = parseFloat(valObj.pct);
        }
        function cekKuis() {
            const userValStr = document.getElementById('inputKuis').value.replace(',', '.');
            const userVal = parseFloat(userValStr);
            if (isNaN(userVal)) return;
           
            if (Math.abs(userVal - currentKuisAnswer) < 0.001) {
                let formattedAns = currentKuisAnswer + document.getElementById('kuisUnit').innerText;
                showStatus(true, "Tepat Sekali!", `Jawabanmu benar: ${formattedAns}`);
                updateVisuals(currentKuisPctVal); // Show visual feedback
            } else {
                showStatus(false, "Coba Lagi!", "Jawabanmu belum tepat. Ingat kembali caranya atau gunakan mode Eksplorasi.");
            }
        }
        function showStatus(isCorrect, title, desc) {
            const overlay = document.getElementById('statusOverlay');
            const icon = document.getElementById('statusIcon');
            const titleEl = document.getElementById('statusTitle');
            const descEl = document.getElementById('statusDesc');
           
            overlay.className = 'overlay show';
            const card = overlay.querySelector('.status-card');
           
            if (isCorrect) {
                card.className = 'status-card correct-theme';
                icon.innerHTML = '<i class="fas fa-check-circle"></i>';
            } else {
                card.className = 'status-card wrong-theme';
                icon.innerHTML = '<i class="fas fa-times-circle"></i>';
            }
           
            titleEl.innerText = title;
            descEl.innerText = desc;
        }
        function closeStatus() {
            document.getElementById('statusOverlay').classList.remove('show');
            if (document.querySelector('.status-card').classList.contains('correct-theme')) {
                randomKuis();
            } else {
                document.getElementById('inputKuis').focus();
            }
        }
        // Enter key to check
        document.getElementById('inputKuis').addEventListener('keypress', function (e) {
            if (e.key === 'Enter') {
                cekKuis();
            }
        });
    </script>
</body>
</html>




Baris 1.072: Baris 77:
<!--==========================================================-->
<!--==========================================================-->
</syntaxhighlight>
</syntaxhighlight>
== Langkah Implementasi ==
# Copy kode HTML di atas
# Buka blogger.com dan masuk ke mode editor kode HTML untuk penulisannya
# Paste potongan kode di atas
# Ambil kode HTML dari AI yang anda gunakan seperti Gemini, Canva.com/ai, ChatGPT, dsb.
# Kembali ke blogger.com
# Paste di baris ke 13
# Simpan / Terbitkan

Revisi terkini sejak 13 Mei 2026 04.00

Menyimpan media pembelajaran secara online lebih memudahkan guru saat ingin menampilkannya kepada para peserta didik. Hal tersebut karena dengan menggunakan jaringan internet kita cukup menyimpan file media pembelajaran 1 kali dan menampilkannya berkali-kali di perangkat apa pun.

Salah satu jenis media yang digunakan dalam kegiatan ini adalah media hasil generate dari AI, baik itu Canva, Gemini, ChatGPT, dsb. dalam format atau ekstensi *.html.

Sebelumnya saya menggunakan CMS custom dari hasil vibe coding dan menambahkan fitur pengelolaan media pembelajaran dan generator perangkat pembelajaran di inibudi.or.id. Namun, sehubungan ada yang bertanya terkait pemanfaatan Blogger gratis untuk menyimpan file HTML. Berikut hasil eksperimen saya yang berhasil menyisipkan kode HTML media pembelajaran ke dalam blogger.

<!--==========================================================-->
<!--WIDGET APLIKASI HTML BLOGGER (AUTO-FULLSCREEN)-->
<!--==========================================================-->
<div class="aplikasi-html-blogger" style="margin: 20px 0px; position: relative;">
  
  <!--1. IFRAME UTAMA-->
  <iframe allow="fullscreen" style="background-color: white; border-radius: 12px; border: 2px solid #e2e8f0; box-shadow: 0 4px 12px rgba(0,0,0,0.1); height: 750px; width: 100%;"></iframe>

  <!--2. TEMPAT KODE SUMBER (Hanya paste HTML Anda di sini)-->
  <textarea style="display: none;">
  <!-- ↓↓↓ PASTE KODE HTML APLIKASI ANDA DI BAWAH BARIS INI ↓↓↓ -->



<!-- ↑↑↑ PASTE KODE HTML APLIKASI ANDA DI ATAS BARIS INI ↑↑↑ -->

  </textarea>
</div>

<!--3. MESIN INJEKTOR PINTAR (Sistem Otomatis)-->
<script>
  document.querySelectorAll('.aplikasi-html-blogger').forEach(function(wadah) {
    var iframe = wadah.querySelector('iframe');
    var textarea = wadah.querySelector('textarea');
    
    if (iframe && textarea && !iframe.getAttribute('data-tersuntik')) {
      
      // Script dan UI Tombol Fullscreen Otomatis (Ikon SVG)
      var btnSVGEnter = '<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M8 3H5a2 2 0 0 0-2 2v3m18 0V5a2 2 0 0 0-2-2h-3m0 18h3a2 2 0 0 0 2-2v-3M3 16v3a2 2 0 0 0 2 2h3"></path></svg>';
      var btnSVGExit = '<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M8 3v3a2 2 0 0 1-2 2H3m18 0h-3a2 2 0 0 1-2-2V3m0 18v-3a2 2 0 0 1 2-2h3M3 16h3a2 2 0 0 1 2 2v3"></path></svg>';
      
      var autoFsScript = `
        <style>
          .btn-fs-blogger { position: fixed; bottom: 20px; right: 20px; z-index: 99999; background: #0ea5e9; color: white; border: none; border-radius: 50%; width: 50px; height: 50px; cursor: pointer; box-shadow: 0 4px 10px rgba(0,0,0,0.2); display: flex; justify-content: center; align-items: center; transition: all 0.2s; }
          .btn-fs-blogger:hover { background: #0284c7; transform: scale(1.1); }
        </style>
        <button id="btn-fs-otomatis" class="btn-fs-blogger" title="Layar Penuh">${btnSVGEnter}</button>
        <script>
          document.getElementById('btn-fs-otomatis').addEventListener('click', function() {
            var doc = window.document;
            var docEl = doc.documentElement;
            var requestFullScreen = docEl.requestFullscreen || docEl.mozRequestFullScreen || docEl.webkitRequestFullScreen || docEl.msRequestFullscreen;
            var cancelFullScreen = doc.exitFullscreen || doc.mozCancelFullScreen || doc.webkitExitFullscreen || doc.msExitFullscreen;
            
            if(!doc.fullscreenElement && !doc.mozFullScreenElement && !doc.webkitFullscreenElement && !doc.msFullscreenElement) {
              requestFullScreen.call(docEl).catch(function(err){ console.log("Fullscreen Error: ", err); });
              this.innerHTML = '${btnSVGExit}';
            } else {
              cancelFullScreen.call(doc);
              this.innerHTML = '${btnSVGEnter}';
            }
          });
        <\/script>
      `;

      // Gabungkan kode sumber HTML dengan tombol otomatis sebelum tag penutup </body>
      var sourceHTML = textarea.value;
      if (sourceHTML.includes('</body>')) {
        sourceHTML = sourceHTML.replace('</body>', autoFsScript + '</body>');
      } else {
        sourceHTML += autoFsScript;
      }

      // Delay 100ms untuk mencegah error MutationObserver dari Ekstensi Browser
      setTimeout(function() {
        iframe.srcdoc = sourceHTML;
        iframe.setAttribute('data-tersuntik', 'true');
      }, 100);
    }
  });
</script>
<!--==========================================================-->

Langkah Implementasi

  1. Copy kode HTML di atas
  2. Buka blogger.com dan masuk ke mode editor kode HTML untuk penulisannya
  3. Paste potongan kode di atas
  4. Ambil kode HTML dari AI yang anda gunakan seperti Gemini, Canva.com/ai, ChatGPT, dsb.
  5. Kembali ke blogger.com
  6. Paste di baris ke 13
  7. Simpan / Terbitkan