Ukrainian flag(ctrl+shift+U)

💙💛Ukrainian flag,fluttering effect. Ctrl+Shift+U control ON/OFF.

目前為 2025-12-29 提交的版本,檢視 最新版本

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         Ukrainian flag(ctrl+shift+U)
// @namespace    tampermonkey.net
// @version      12.3
// @description  💙💛Ukrainian flag,fluttering effect. Ctrl+Shift+U control ON/OFF.
// @author       邢智轩(from China)
// @match        *://*/*
// @icon         https://www.tampermonkey.net/favicon.ico
// @run-at       document-start
// @grant        none
// @license MIT
// ==/UserScript==

(function() {
    'use strict';

    let isTerminated = false; // 用於追蹤使用者是否手動關閉

    // 1. 核心注入函數
    function injectBadge() {
        if (document.getElementById('ua-waving-badge-root')) return;

        const host = document.createElement('div');
        host.id = 'ua-waving-badge-root';
        host.style.cssText = `
            position: fixed !important;
            bottom: 30px !important;
            left: 30px !important;
            z-index: 2147483647 !important;
            pointer-events: none !important;
            display: block !important;
            transition: opacity 0.4s ease, transform 0.4s ease !important;
            opacity: 0;
            transform: translateY(20px);
        `;
        document.documentElement.appendChild(host);

        const shadow = host.attachShadow({mode: 'closed'});

        // SVG 資源
        const tridentSvg = `<svg viewBox="0 0 200 300"><path d="M100 0 L85 45 L40 45 Q20 45 20 80 L20 180 Q20 220 50 220 L65 220 L65 190 L50 190 Q40 190 40 175 L40 90 L75 90 L80 180 Q82 250 100 250 Q118 250 120 180 L125 90 L160 90 L160 175 Q160 190 150 190 L135 190 L135 220 L150 220 Q180 220 180 180 L180 80 Q180 45 160 45 L115 45 Z M100 260 L90 300 L110 300 Z" fill="#FFD700"/></svg>`;
        const shieldSvg = `<svg viewBox="0 0 100 120"><path d="M10 10 Q50 0 90 10 L90 60 Q90 95 50 115 Q10 95 10 60 Z" fill="#0057B7" stroke="#FFD700" stroke-width="4"/><path d="M50 25 V85 M35 35 Q35 75 50 75 Q65 75 65 35 M42 35 V60 M58 35 V60" fill="none" stroke="#FFD700" stroke-width="8" stroke-linecap="round"/></svg>`;

        shadow.innerHTML = `
        <style>
            .flag-container {
                position: relative;
                width: 120px;
                height: 70px;
                background: linear-gradient(to bottom, #0057B7 50%, #FFD700 50%);
                border-radius: 4px;
                overflow: hidden;
                box-shadow: 0 10px 25px rgba(0,0,0,0.5);
                animation: wave 3s infinite ease-in-out;
                transform-origin: left center;
                display: flex;
                align-items: center;
                justify-content: space-around;
                padding: 0 10px;
            }
            .icon { width: 35px; height: auto; filter: drop-shadow(0 2px 4px rgba(0,0,0,0.6)); z-index: 2; }
            @keyframes wave {
                0%, 100% { transform: skewY(0deg) scale(1); }
                25% { transform: skewY(2.5deg) scale(1.02); }
                50% { transform: skewY(-2.5deg) scale(1); }
                75% { transform: skewY(1.5deg) scale(0.98); }
            }
            .flag-container::after {
                content: "";
                position: absolute;
                top: 0; left: -100%;
                width: 100%; height: 100%;
                background: linear-gradient(90deg, transparent, rgba(255,255,255,0.2), transparent);
                animation: shine 4s infinite linear;
            }
            @keyframes shine { 0% { left: -100%; } 20% { left: 100%; } 100% { left: 100%; } }
        </style>
        <div class="flag-container">
            <div class="icon">${tridentSvg}</div>
            <div class="icon">${shieldSvg}</div>
        </div>`;

        // 入場動畫
        requestAnimationFrame(() => {
            host.style.opacity = '1';
            host.style.transform = 'translateY(0)';
        });
    }

    // 2. 快捷鍵切換邏輯 (Ctrl + Shift + U)
    window.addEventListener('keydown', function(e) {
        if (e.ctrlKey && e.shiftKey && e.code === 'KeyU') {
            const root = document.getElementById('ua-waving-badge-root');
            if (root) {
                // 執行關閉
                root.style.opacity = '0';
                root.style.transform = 'translateY(20px)';
                setTimeout(() => {
                    root.remove();
                    isTerminated = true;
                }, 400);
            } else {
                // 執行開啟
                isTerminated = false;
                injectBadge();
            }
        }
    }, true);

    // 3. 強制置頂與自癒校驗 (每 1.5 秒一次)
    function enforce() {
        if (isTerminated) return;

        const root = document.getElementById('ua-waving-badge-root');
        if (!root || !document.documentElement.contains(root)) {
            injectBadge();
        } else {
            // 層級檢查
            if (root.parentElement !== document.documentElement) {
                document.documentElement.appendChild(root);
            }
            if (root.style.zIndex !== '2147483647') {
                root.style.setProperty('z-index', '2147483647', 'important');
            }
        }
    }

    // 初始啟動
    injectBadge();
    setInterval(enforce, 1500);
    const observer = new MutationObserver(enforce);
    observer.observe(document.documentElement, { childList: true, subtree: true });

})();