Skip to content

Instantly share code, notes, and snippets.

@ekanna
Forked from ianobermiller/index.html
Created July 14, 2021 18:49
Show Gist options
  • Select an option

  • Save ekanna/a45d85dd6794e60b41c21bde497545c5 to your computer and use it in GitHub Desktop.

Select an option

Save ekanna/a45d85dd6794e60b41c21bde497545c5 to your computer and use it in GitHub Desktop.
WiFi QR Code, single HTML file
<!DOCTYPE html>
<html>
<head>
<title>WiFi Login</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- https://news.ycombinator.com/item?id=26923316 -->
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>&#128272;</text></svg>">
<style>
body, textarea {
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
font-size: 16px;
}
main {
margin: 0 auto;
max-width: 400px;
text-align: center;
}
canvas {
height: 200px;
width: 200px;
}
label {
display: block;
margin: 12px;
text-align: left;
}
textarea {
box-sizing: border-box;
font-family: Menlo, Consola, monospace;
font-weight: bold;
margin-top: 4px;
padding: 8px;
width: 100%;
}
textarea:invalid {
border: 2px dashed red;
}
/* https://css-tricks.com/the-cleanest-trick-for-autogrowing-textareas/ */
@supports (display: grid) {
.input {
/* easy way to plop the elements on top of each other and have them both sized based on the tallest one's height */
display: grid;
}
.input::after {
/* Note the weird space! Needed to preventy jumpy behavior */
content: attr(data-replicated-value) " ";
/* This is how textarea text behaves */
white-space: pre-wrap;
/* Hidden from view, clicks, and screen readers */
visibility: hidden;
}
.input > textarea {
/* You could leave this, but after a user resizes, then it ruins the auto sizing */
resize: none;
/* Firefox shows scrollbar on growth, you can hide like this. */
overflow: hidden;
}
.input > textarea,
.input::after {
/* Identical styling required!! */
border: 1px solid black;
border-radius: 4px;
box-sizing: border-box;
margin-top: 4px;
padding: 8px;
font: inherit;
/* Place on top of each other */
grid-area: 1 / 1 / 2 / 2;
}
}
</style>
</head>
<body>
<main>
<h1>WiFi Login</h1>
<p>Scan with your phone to join automatically!</p>
<canvas id="qr"></canvas>
<label>
Network Name
<div class="input">
<textarea
id="ssid"
type="text"
rows="1"
autocapitalize="off"
autocorrect="off"
autofocus="true"></textarea>
</div>
</label>
<label>
Password
<div class="input">
<textarea
id="password"
type="text"
minlength="8"
rows="1"
autocapitalize="off"
autocorrect="off"
title="Must be at least 8 characters."></textarea>
</div>
</label>
</main>
<script src="https://cdnjs.cloudflare.com/ajax/libs/qrious/4.0.2/qrious.min.js"></script>
<script>
(function() {
var qr = new QRious({
element: document.getElementById('qr'),
value: 'https://github.com/neocotic/qrious',
size: 400 // twice the size for extra crispiness
});
var ssidInput = document.getElementById('ssid');
var passwordInput = document.getElementById('password');
// https://github.com/bndw/wifi-card/blob/master/src/components/Card.js
var needsEscape = {'"': true, ';': true, ',': true, ':': true, '\\': true};
function escape(v) {
return v.split('').map(c => needsEscape[c] ? '\\' + c : c).join('');
}
function updateQRCode() {
this.parentNode.dataset.replicatedValue = this.value;
var ssid = escape(ssidInput.value);
var password = escape(passwordInput.value);
qr.value = 'WIFI:T:WPA;S:' + ssid + ';P:' + password + ';;';
}
ssidInput.addEventListener('input', updateQRCode);
passwordInput.addEventListener('input', updateQRCode);
})();
</script>
</body>
</html>
@lutfihakim9992-creator
Copy link
Copy Markdown

<title>App Scan Wi-Fi Sederhana</title> <style> /* --- CSS Styles --- */ :root { --primary-color: #007AFF; --bg-color: #f5f7fa; --card-bg: #ffffff; --text-color: #333; --signal-low: #ff3b30; --signal-med: #ffcc00; --signal-high: #34c759; }
    body {
        font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
        background-color: var(--bg-color);
        color: var(--text-color);
        margin: 0;
        padding: 0;
        display: flex;
        justify-content: center;
        min-height: 100vh;
    }

    .app-container {
        width: 100%;
        max-width: 400px;
        background: var(--card-bg);
        box-shadow: 0 0 20px rgba(0,0,0,0.1);
        display: flex;
        flex-direction: column;
        overflow: hidden;
        position: relative;
    }

    header {
        background: var(--primary-color);
        color: white;
        padding: 20px;
        text-align: center;
        box-shadow: 0 2px 5px rgba(0,0,0,0.1);
        z-index: 10;
    }

    h1 { margin: 0; font-size: 1.2rem; }

    .controls {
        padding: 15px;
        text-align: center;
        border-bottom: 1px solid #eee;
    }

    button#scanBtn {
        background: var(--primary-color);
        color: white;
        border: none;
        padding: 10px 20px;
        border-radius: 20px;
        font-weight: 600;
        cursor: pointer;
        transition: transform 0.1s;
        width: 100%;
    }

    button#scanBtn:active { transform: scale(0.98); }

    .network-list {
        flex: 1;
        overflow-y: auto;
        padding: 10px;
    }

    /* Loading Animation */
    .loader {
        display: none;
        text-align: center;
        padding: 20px;
        color: #888;
    }
    .spinner {
        border: 4px solid #f3f3f3;
        border-top: 4px solid var(--primary-color);
        border-radius: 50%;
        width: 30px;
        height: 30px;
        animation: spin 1s linear infinite;
        margin: 0 auto 10px;
    }
    @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }

    /* Network Item Card */
    .wifi-item {
        display: flex;
        align-items: center;
        justify-content: space-between;
        padding: 15px;
        margin-bottom: 10px;
        background: #fff;
        border: 1px solid #e1e1e1;
        border-radius: 8px;
        cursor: pointer;
        transition: background 0.2s;
    }

    .wifi-item:hover { background: #f9f9f9; border-color: var(--primary-color); }

    .wifi-info { display: flex; align-items: center; gap: 10px; }

    .icon { font-size: 1.5rem; }

    .details h3 { margin: 0; font-size: 1rem; margin-bottom: 4px; }
    .details p { margin: 0; font-size: 0.8rem; color: #666; }

    /* Signal Strength Bar Graphic */
    .signal-bars {
        display: flex;
        align-items: flex-end;
        gap: 2px;
        height: 16px;
    }
    .bar {
        width: 4px;
        background: #ddd;
        border-radius: 2px;
    }
    .bar.active { background: var(--primary-color); }
    
    /* Dynamic colors for signal strength */
    .sig-low .bar:nth-child(1) { background: var(--signal-low); }
    .sig-med .bar:nth-child(1), .sig-med .bar:nth-child(2) { background: var(--signal-med); }
    .sig-high .bar { background: var(--signal-high); }

    /* Modal Styles */
    .modal-overlay {
        position: absolute;
        top: 0; left: 0; right: 0; bottom: 0;
        background: rgba(0,0,0,0.5);
        display: flex;
        align-items: flex-end; /* Slide up effect like mobile */
        justify-content: center;
        opacity: 0;
        pointer-events: none;
        transition: opacity 0.3s;
        z-index: 100;
    }
    
    .modal-overlay.active { opacity: 1; pointer-events: all; }

    .modal-content {
        background: white;
        width: 100%;
        max-width: 400px;
        border-radius: 20px 20px 0 0;
        padding: 20px;
        transform: translateY(100%);
        transition: transform 0.3s;
        box-sizing: border-box;
    }

    .modal-overlay.active .modal-content { transform: translateY(0); }

    .modal-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; }
    .close-modal { background: none; border: none; font-size: 1.5rem; cursor: pointer; }

    .password-input {
        width: 100%;
        padding: 15px;
        border: 1px solid #ccc;
        border-radius: 8px;
        margin-bottom: 15px;
        font-size: 1rem;
        box-sizing: border-box;
    }

    .connect-btn {
        width: 100%;
        padding: 15px;
        background: var(--primary-color);
        color: white;
        border: none;
        border-radius: 8px;
        font-size: 1rem;
        font-weight: bold;
        cursor: pointer;
    }

</style>
<div class="app-container">
    <header>
        <h1>Pengaturan Wi-Fi</h1>
    </header>

    <div class="controls">
        <button id="scanBtn" onclick="startScan()">Scan Jaringan</button>
    </div>

    <div id="loader" class="loader">
        <div class="spinner"></div>
        <p>Mencari jaringan...</p>
    </div>

    <div id="networkList" class="network-list">
        <!-- Daftar kosong di sini -->
        <div style="text-align:center; color:#aaa; margin-top:50px;">
            Tekan tombol Scan untuk mencari Wi-Fi
        </div>
    </div>

    <!-- Pop up Modal -->
    <div id="modal" class="modal-overlay">
        <div class="modal-content">
            <div class="modal-header">
                <h2 id="modalTitle">Nama Jaringan</h2>
                <button class="close-modal" onclick="closeModal()">&times;</button>
            </div>
            <div id="modalBody">
                <p>Terenkripsi (WPA2)</p>
                <input type="password" id="wifiPassword" class="password-input" placeholder="Masukkan password">
                <button class="connect-btn" onclick="connectWifi()">Hubungkan</button>
            </div>
            <div id="modalSuccess" class="hidden" style="text-align: center;">
                <div style="font-size: 3rem;">✅</div>
                <h3>Terhubung!</h3>
                <p>Internet sudah aktif.</p>
                <button class="connect-btn" onclick="closeModal()">Tutup</button>
            </div>
        </div>
    </div>
</div>

<script>
    // --- JavaScript Logic ---

    // 1. Data Dummy (Simulasi)
    const dummyNetworks = [
        { ssid: "Wifi_Kantor_Utama", signal: 90, security: "WPA2", locked: true },
        { ssid: "Wifi_Rumah", signal: 75, security: "WPA2", locked: true },
        { ssid: "Tether_Saya", signal: 60, security: "WPA2", locked: true },
        { ssid: "Internet_Gratis", signal: 45, security: "Terbuka", locked: false },
        { ssid: "Tetangga_Subagjo", signal: 30, security: "WPA2", locked: true },
        { ssid: "Starbucks_Official", signal: 85, security: "WPA2", locked: true },
        { ssid: "HUTAN_LINDUNG", signal: 20, security: "WEP", locked: true }
    ];

    let selectedNetwork = null;

    // 2. Fungsi Memulai Scan
    function startScan() {
        const listContainer = document.getElementById('networkList');
        const loader = document.getElementById('loader');
        const btn = document.getElementById('scanBtn');

        // Reset UI
        listContainer.innerHTML = '';
        btn.disabled = true;
        btn.innerText = "Scanning...";
        loader.style.display = 'block';

        // Simulasi jeda waktu (2 detik) untuk efek scanning
        setTimeout(() => {
            loader.style.display = 'none';
            btn.disabled = false;
            btn.innerText = "Scan Ulang";
            renderList(dummyNetworks);
        }, 2000);
    }

    // 3. Fungsi Render Daftar
    function renderList(networks) {
        const listContainer = document.getElementById('networkList');
        
        // Urutkan berdasarkan sinyal terkuat
        networks.sort((a, b) => b.signal - a.signal);

        networks.forEach((net, index) => {
            // Tentukan kelas kekuatan sinyal untuk CSS
            let signalClass = 'sig-high';
            if (net.signal < 40) signalClass = 'sig-low';
            else if (net.signal < 70) signalClass = 'sig-med';

            // Icon Kunci
            const lockIcon = net.locked ? '🔒' : '🔓';
            
            // HTML每一项
            const itemHtml = `
                <div class="wifi-item" onclick="selectNetwork('${net.ssid}', '${net.security}', ${net.locked})">
                    <div class="wifi-info">
                        <div class="icon">📶</div>
                        <div class="details">
                            <h3>${net.ssid} ${lockIcon}</h3>
                            <p>${net.security}</p>
                        </div>
                    </div>
                    <div class="signal-bars ${signalClass}">
                        <div class="bar" style="height: 30%;"></div>
                        <div class="bar" style="height: 50%;"></div>
                        <div class="bar" style="height: 70%;"></div>
                        <div class="bar" style="height: 100%;"></div>
                    </div>
                </div>
            `;
            listContainer.innerHTML += itemHtml;
        });
    }

    // 4. Fungsi Ketika Network Dipilih
    function selectNetwork(ssid, security, isLocked) {
        selectedNetwork = { ssid, security, isLocked };
        
        const modal = document.getElementById('modal');
        const title = document.getElementById('modalTitle');
        const modalBody = document.getElementById('modalBody');
        const modalSuccess = document.getElementById('modalSuccess');

        // Reset Modal ke state awal
        document.getElementById('wifiPassword').value = '';
        modalBody.style.display = 'block';
        modalSuccess.style.display = 'none';
        
        title.innerText = ssid;

        if (!isLocked) {
            // Kalau terbuka, langsung muncul menu hubung atau koneksi otomatis
            modalBody.querySelector('p').innerText = "Jaringan ini tidak terenkripsi.";
            modalBody.querySelector('button').innerText = "Sambungkan";
        } else {
            modalBody.querySelector('p').innerText = `Keamanan: ${security}`;
            modalBody.querySelector('button').innerText = "Hubungkan";
        }

        modal.classList.add('active');
    }

    // 5. Fungsi Menghubungkan (Simulasi)
    function connectWifi() {
        const passInput = document.getElementById('wifiPassword');
        const modalBody = document.getElementById('modalBody');
        const modalSuccess = document.getElementById('modalSuccess');

        if (selectedNetwork.isLocked && passInput.value.trim() === "") {
            alert("Mohon masukkan password Wi-Fi!");
            return;
        }

        // Simulasi verifikasi (langsung sukses saja untuk contoh ini)
        // Tampilkan UI Sukses
        modalBody.style.display = 'none';
        modalSuccess.style.display = 'block';
    }

    // 6. Fungsi Tutup Modal
    function closeModal() {
        document.getElementById('modal').classList.remove('active');
    }

</script>

@sennoalvinn-afk
Copy link
Copy Markdown

<title>Wifi Scanner Simulasi</title> <style> /* --- CSS Styles --- */ :root { --primary: #00ff88; --bg: #0f172a; --card-bg: #1e293b; --text: #f1f5f9; --text-muted: #94a3b8; }
    * { box-sizing: border-box; margin: 0; padding: 0; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; }

    body {
        background-color: var(--bg);
        color: var(--text);
        padding: 20px;
        display: flex;
        flex-direction: column;
        align-items: center;
    }

    .container {
        max-width: 600px;
        width: 100%;
    }

    header {
        text-align: center;
        margin-bottom: 30px;
    }

    h1 {
        color: var(--primary);
        font-size: 2rem;
        margin-bottom: 10px;
    }

    p.subtitle {
        color: var(--text-muted);
        font-size: 0.9rem;
    }

    /* Search Bar */
    .search-box {
        margin-bottom: 20px;
        position: relative;
    }

    input[type="text"] {
        width: 100%;
        padding: 12px 20px;
        border-radius: 25px;
        border: 1px solid #334155;
        background-color: var(--card-bg);
        color: var(--text);
        font-size: 1rem;
        outline: none;
    }

    input[type="text"]:focus {
        border-color: var(--primary);
        box-shadow: 0 0 8px rgba(0, 255, 136, 0.2);
    }

    /* Network List */
    .network-list {
        display: flex;
        flex-direction: column;
        gap: 15px;
    }

    .card {
        background-color: var(--card-bg);
        padding: 20px;
        border-radius: 15px;
        border: 1px solid #334155;
        transition: transform 0.2s;
        display: flex;
        justify-content: space-between;
        align-items: center;
    }

    .card:hover {
        transform: translateY(-3px);
        border-color: var(--primary);
    }

    .card-left {
        flex: 1;
    }

    .wifi-name {
        font-weight: bold;
        font-size: 1.1rem;
        margin-bottom: 5px;
        display: flex;
        align-items: center;
        gap: 8px;
    }

    .badge {
        font-size: 0.7rem;
        padding: 2px 8px;
        border-radius: 4px;
        background-color: #334155;
        color: var(--text-muted);
    }

    .wifi-details {
        font-size: 0.85rem;
        color: var(--text-muted);
        display: flex;
        gap: 15px;
        margin-bottom: 8px;
    }

    /* Signal Bar */
    .signal-bar-container {
        width: 100px;
        height: 4px;
        background-color: #334155;
        border-radius: 2px;
        overflow: hidden;
    }

    .signal-fill {
        height: 100%;
        border-radius: 2px;
        transition: width 0.5s ease;
    }

    /* Password Section */
    .card-right {
        text-align: right;
    }

    .password-box {
        background-color: #0f172a;
        padding: 8px 12px;
        border-radius: 8px;
        font-family: monospace;
        color: var(--primary);
        margin-bottom: 5px;
        cursor: pointer;
        display: inline-block;
        font-size: 0.9rem;
    }

    .password-box:active {
        transform: scale(0.95);
    }

    .btn-copy {
        background: none;
        border: none;
        color: var(--text-muted);
        font-size: 0.75rem;
        cursor: pointer;
        text-decoration: underline;
    }

    .btn-copy:hover {
        color: var(--text);
    }

    .empty-state {
        text-align: center;
        padding: 20px;
        color: var(--text-muted);
    }
    
    /* Lock Icon for Protected */
    .locked { color: #fbbf24; }
</style>
<div class="container">
    <header>
        <h1>Wi-Fi Detector</h1>
        <p class="subtitle">Menampilkan jaringan terdekat (Data Simulasi)</p>
    </header>

    <div class="search-box">
        <input type="text" id="searchInput" placeholder="Cari nama wifi..." onkeyup="filterWifi()">
    </div>

    <div id="networkContainer" class="network-list">
        <!-- Menu akan dihasilkan oleh Javascript -->
    </div>
</div>

<script>
    /* --- JavaScript Logic --- */

    // 1. Data Dummy (Simulasi)
    const wifiData = [
        { ssid: "Wifi_Kantor_01", password: "KantorBes2024!", signal: 95, type: "WPA2" },
        { ssid: "RonaldHome_5G", password: "ronald123", signal: 88, type: "WPA2" },
        { ssid: "IndieCoffee_Shop", password: "kopi勾苓!9", signal: 40, type: "WPA2" },
        { ssid: "TPLINK_8832", password: "password", signal: 30, type: "Open" },
        { ssid: "师范附属小学", password: "sekolah123", signal: 65, type: "WPA2" },
        { ssid: "Starbucks_Free", password: "Netsuke_B", signal: 20, type: "WPA2" },
        { ssid: "DevNetwork_X", password: "codingaja", signal: 92, type: "WPA3" }
    ];

    const container = document.getElementById('networkContainer');
    const searchInput = document.getElementById('searchInput');

    // 2. Fungsi untuk menentukan warna sinyal
    function getSignalColor(level) {
        if (level > 75) return '#00ff88'; // Hijau (Kuat)
        if (level > 40) return '#fbbf24'; // Kuning (Sedang)
        return '#ef4444'; // Merah (Lemah)
    }

    // 3. Fungsi Render Data ke HTML
    function renderList(data) {
        container.innerHTML = ''; // Clear current list

        if (data.length === 0) {
            container.innerHTML = '<div class="empty-state">Jaringan tidak ditemukan</div>';
            return;
        }

        data.forEach(wifi => {
            const signalColor = getSignalColor(wifi.signal);
            const isLocked = wifi.type !== 'Open' ? '🔒' : '🔓';
            
            const html = `
                <div class="card">
                    <div class="card-left">
                        <div class="wifi-name">
                            ${isLocked} ${wifi.ssid}
                            <span class="badge">${wifi.type}</span>
                        </div>
                        <div class="wifi-details">
                            <span>Sinyal: ${wifi.signal}%</span>
                        </div>
                        <div class="signal-bar-container">
                            <div class="signal-fill" style="width: ${wifi.signal}%; background-color: ${signalColor}"></div>
                        </div>
                    </div>
                    <div class="card-right">
                        <div class="password-box" onclick="copyPassword('${wifi.password}')">
                            ${wifi.password}
                        </div>
                        <br>
                        <button class="btn-copy" onclick="copyPassword('${wifi.password}')">Klik Sandi untuk Salin</button>
                    </div>
                </div>
            `;
            container.innerHTML += html;
        });
    }

    // 4. Fungsi Filter (Cari)
    function filterWifi() {
        const query = searchInput.value.toLowerCase();
        const filtered = wifiData.filter(wifi => wifi.ssid.toLowerCase().includes(query));
        renderList(filtered);
    }

    // 5. Fungsi Copy ke Clipboard
    function copyPassword(pass) {
        navigator.clipboard.writeText(pass).then(() => {
            //alert("Sandi '" + pass + "' telah disalin!"); // Alert bisa diganti toast notification
            const originalText = event.target.innerText;
            
            // Feedback visual sederhana
            if(event.target.tagName === 'DIV') {
                event.target.innerText = "Tersalin!";
                setTimeout(() => {
                    event.target.innerText = pass;
                }, 1000);
            } else if (event.target.tagName === 'BUTTON') {
                let btn = event.target;
                btn.innerText = "Tersalin!";
                btn.style.color = "#00ff88";
                setTimeout(() => {
                    btn.innerText = "Klik Sandi untuk Salin";
                    btn.style.color = "#94a3b8";
                }, 1000);
            }
        });
    }

    // Initial Render
    renderList(wifiData);

</script>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment