File size: 7,623 Bytes
54e2b8c
 
 
 
 
5ada4ba
54e2b8c
 
 
c780a69
5ada4ba
 
3603cde
5ada4ba
 
c780a69
5ada4ba
 
 
 
c780a69
5ada4ba
3603cde
 
 
54e2b8c
 
 
 
3603cde
7b958aa
5ada4ba
 
18e8518
 
 
 
 
 
 
54e2b8c
 
 
 
 
 
 
 
 
 
5ada4ba
54e2b8c
5ada4ba
 
 
54e2b8c
 
 
c780a69
3603cde
 
54e2b8c
 
c780a69
3603cde
 
54e2b8c
 
3603cde
7b958aa
3603cde
54e2b8c
 
 
 
3603cde
54e2b8c
3603cde
54e2b8c
3603cde
 
54e2b8c
3603cde
54e2b8c
 
 
 
3603cde
 
 
 
 
54e2b8c
 
3603cde
 
 
54e2b8c
 
c780a69
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
<!DOCTYPE html>
<html lang="vi">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
    <title>Sài Gòn Sync - The World's Most Accurate Clock</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <style>
        @import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@700;800&family=Inter:wght@400;600;800&display=swap');
        body { margin: 0; padding: 0; width: 100vw; height: 100vh; overflow: hidden; background-color: #050508; color: #fff; font-family: 'Inter', sans-serif; display: flex; align-items: center; justify-content: center; }
        .bg-glow { position: fixed; width: 60vw; height: 60vw; background: radial-gradient(circle, rgba(99, 102, 241, 0.15) 0%, rgba(0,0,0,0) 70%); top: 50%; left: 50%; transform: translate(-50%, -50%); z-index: 0; }
        .main-container { position: relative; z-index: 10; width: 100%; max-width: 700px; display: flex; flex-direction: column; align-items: center; padding: 20px; }
        .brand-title { font-family: 'JetBrains Mono', monospace; font-size: 10px; letter-spacing: 5px; font-weight: 800; background: linear-gradient(to right, #6366f1, #a5b4fc, #6366f1); -webkit-background-clip: text; -webkit-text-fill-color: transparent; text-transform: uppercase; margin-bottom: 30px; text-align: center; }
        .tz-select { background: rgba(255, 255, 255, 0.05); border: 1px solid rgba(255, 255, 255, 0.1); color: #a5b4fc; padding: 6px 18px; border-radius: 12px; font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: 1px; margin-bottom: 25px; outline: none; cursor: pointer; transition: 0.3s; }
        .clock-wrapper { display: flex; align-items: center; justify-content: center; font-family: 'JetBrains Mono', monospace; font-size: clamp(3.5rem, 18vw, 7.5rem); font-weight: 800; line-height: 1; gap: 4px; margin-bottom: 15px; }
        .digit-column { height: 1.1em; overflow: hidden; position: relative; width: 0.65em; text-align: center; }
        .digit-strip { transition: transform 0.6s cubic-bezier(0.16, 1, 0.3, 1); }
        .digit-val { height: 1.1em; display: flex; align-items: center; justify-content: center; color: #fff; text-shadow: 0 0 30px rgba(99, 102, 241, 0.4); }
        .sep { color: #4f46e5; opacity: 0.8; margin: 0 4px; padding-bottom: 15px; }
        .stats-bar { background: rgba(255, 255, 255, 0.02); backdrop-filter: blur(25px); border: 1px solid rgba(255, 255, 255, 0.05); border-radius: 24px; padding: 15px 40px; display: flex; gap: 40px; margin-top: 40px; }
        .stat-box { display: flex; flex-direction: column; align-items: center; }
        .stat-label { font-size: 7px; text-transform: uppercase; letter-spacing: 2px; color: #4f46e5; margin-bottom: 4px; font-weight: 600; }
        .stat-data { font-family: 'JetBrains Mono', monospace; font-size: 13px; font-weight: 700; }
        #countdown-overlay { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: #000; display: none; z-index: 100; flex-direction: column; align-items: center; justify-content: center; }
        #countdown-num { font-size: 18rem; font-weight: 900; color: #f87171; text-shadow: 0 0 60px rgba(248, 113, 113, 0.6); }
    </style>
</head>
<body onclick="lockScreen()">
    <div class="bg-glow"></div>
    <div id="countdown-overlay"><div class="text-white text-2xl tracking-[15px] mb-10 font-black">HAPPY NEW YEAR</div><div id="countdown-num">10</div></div>

    <div class="main-container">
        <div class="brand-title">Đồng hồ chính xác nhất thế giới</div>
        <select id="timezone-selector" class="tz-select" onchange="changeTimezone()">
            <option value="Asia/Ho_Chi_Minh">🇻🇳 Sài Gòn (GMT+7)</option>
            <option value="Asia/Singapore">🇸🇬 Singapore (GMT+8)</option>
            <option value="Asia/Tokyo">🇯🇵 Tokyo (GMT+9)</option>
            <option value="Europe/London">🇬🇧 London (GMT+0)</option>
            <option value="America/New_York">🇺🇸 New York (GMT-5)</option>
        </select>
        <div class="clock-wrapper">
            <div class="digit-column"><div class="digit-strip" id="h1"></div></div>
            <div class="digit-column"><div class="digit-strip" id="h2"></div></div>
            <div class="sep">:</div>
            <div class="digit-column"><div class="digit-strip" id="m1"></div></div>
            <div class="digit-column"><div class="digit-strip" id="m2"></div></div>
            <div class="sep">:</div>
            <div class="digit-column"><div class="digit-strip" id="s1"></div></div>
            <div class="digit-column"><div class="digit-strip" id="s2"></div></div>
        </div>
        <div id="full-date" class="text-gray-500 text-[11px] tracking-[5px] uppercase font-bold">---</div>
        <div class="stats-bar">
            <div class="stat-box"><span class="stat-label">Network Ping</span><span class="stat-data" id="v-ping">--</span></div>
            <div class="stat-box"><span class="stat-label">Time Offset</span><span class="stat-data" id="v-offset">--</span></div>
            <div class="stat-box"><span class="stat-label">Server IP</span><span class="stat-data" id="v-ip">--</span></div>
        </div>
    </div>

    <script>
        let serverOffset = 0, selectedTimezone = 'Asia/Ho_Chi_Minh', wakeLock = null;
        const API_URL = 'https://tuhbooh-networttools.hf.space';

        function createStrips() {
            ['h1','h2','m1','m2','s1','s2'].forEach(id => {
                const s = document.getElementById(id); s.innerHTML = '';
                for(let i=0; i<=9; i++) { const d = document.createElement('div'); d.className = 'digit-val'; d.innerText = i; s.appendChild(d); }
            });
        }
        function setDigit(id, val) { document.getElementById(id).style.transform = `translateY(-${val * 1.1}em)`; }
        function changeTimezone() { selectedTimezone = document.getElementById('timezone-selector').value; }
        async function lockScreen() { if(navigator.wakeLock) wakeLock = await navigator.wakeLock.request('screen'); }

        async function sync() {
            const start = performance.now();
            try {
                const r = await fetch(`${API_URL}?t=${Date.now()}`);
                const d = await r.json();
                const ping = performance.now() - start;
                serverOffset = (d.ts * 1000 + ping/2) - Date.now();
                document.getElementById('v-ping').innerText = Math.round(ping) + "ms";
                document.getElementById('v-offset').innerText = Math.round(Math.abs(serverOffset)) + "ms";
                document.getElementById('v-ip').innerText = d.ip;
            } catch(e) {}
        }

        function update() {
            const now = new Date(Date.now() + serverOffset);
            const timeStr = now.toLocaleTimeString('en-GB', {timeZone: selectedTimezone, hour12:false, hour:'2-digit', minute:'2-digit', second:'2-digit'});
            const [h, m, s] = timeStr.split(':');
            setDigit('h1', h[0]); setDigit('h2', h[1]); setDigit('m1', m[0]); setDigit('m2', m[1]); setDigit('s1', s[0]); setDigit('s2', s[1]);
            document.getElementById('full-date').innerText = new Intl.DateTimeFormat('vi-VN', {timeZone: selectedTimezone, weekday:'long', day:'numeric', month:'long', year:'numeric'}).format(now);
            requestAnimationFrame(update);
        }

        createStrips(); sync();
        setInterval(sync, 15000); // Sync mỗi 15s để ổn định
        requestAnimationFrame(update);
    </script>
</body>
</html>