急速搜索

经验创意 · 44 次浏览
困困君 创建于 11小时7分钟前

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
    <title>快捷网址搜索</title>
    <style>
        html, body {
            margin: 0;
            width: 100%;
            height: 100%;
            overflow: hidden;
            background: transparent;
            font-family: "Microsoft YaHei", "PingFang SC", "Segoe UI", sans-serif;
            user-select: none;
            -webkit-user-select: none;
        }

        * {
            box-sizing: border-box;
        }

        .card {
            width: 100%;
            height: 100%;
            border-radius: 18px;
            background: linear-gradient(145deg, #2b2d36 0%, #1c1d22 100%);
            border: 1px solid rgba(132, 146, 166, 0.15);
            box-shadow: inset 0 1px 1px rgba(255, 255, 255, 0.08), 0 8px 24px rgba(0, 0, 0, 0.5);
            display: flex;
            flex-direction: column;
            position: relative;
            color: #e4e7ed;
        }

        .header {
            padding: 16px 20px 8px;
            display: flex;
            align-items: center;
            cursor: grab;
            font-size: 14px;
            font-weight: bold;
            color: rgba(255, 255, 255, 0.8);
            letter-spacing: 0.5px;
        }
        
        .header:active {
            cursor: grabbing;
        }

        .header-icon {
            width: 16px;
            height: 16px;
            margin-right: 8px;
            fill: currentColor;
            opacity: 0.8;
        }

        .main-content {
            flex: 1;
            display: flex;
            flex-direction: column;
            padding: 0 20px;
            justify-content: center;
            overflow: hidden;
        }

        .engine-tabs {
            display: flex;
            gap: 10px;
            margin-bottom: 18px;
            overflow-x: auto;
            padding-bottom: 6px;
        }

        .engine-tabs::-webkit-scrollbar {
            height: 4px;
        }
        
        .engine-tabs::-webkit-scrollbar-track {
            background: transparent;
        }
        
        .engine-tabs::-webkit-scrollbar-thumb {
            background: rgba(255, 255, 255, 0.1);
            border-radius: 4px;
        }
        
        .engine-tabs::-webkit-scrollbar-thumb:hover {
            background: rgba(255, 255, 255, 0.2);
        }

        .engine-tab {
            padding: 6px 16px;
            font-size: 13px;
            border-radius: 20px;
            background: rgba(255, 255, 255, 0.05);
            color: rgba(255, 255, 255, 0.6);
            cursor: pointer;
            transition: all 0.2s cubic-bezier(0.25, 0.46, 0.45, 0.94);
            border: 1px solid rgba(255, 255, 255, 0.03);
            white-space: nowrap;
        }

        .engine-tab:hover {
            background: rgba(255, 255, 255, 0.1);
            color: rgba(255, 255, 255, 0.95);
        }

        .engine-tab:active {
            transform: scale(0.95);
        }

        .engine-tab.active {
            background: rgba(82, 153, 255, 0.15);
            color: #7ab3ff;
            border-color: rgba(82, 153, 255, 0.3);
            box-shadow: 0 0 12px rgba(82, 153, 255, 0.1);
            font-weight: 600;
        }

        .search-container {
            display: flex;
            align-items: center;
            background: rgba(0, 0, 0, 0.3);
            border: 1px solid rgba(255, 255, 255, 0.08);
            border-radius: 14px;
            padding: 6px 8px 6px 16px;
            transition: all 0.3s ease;
            box-shadow: inset 0 2px 6px rgba(0, 0, 0, 0.2);
        }

        .search-container:focus-within {
            border-color: rgba(122, 179, 255, 0.6);
            background: rgba(0, 0, 0, 0.4);
            box-shadow: inset 0 2px 6px rgba(0, 0, 0, 0.3), 0 0 0 3px rgba(122, 179, 255, 0.15);
        }

        .search-input {
            flex: 1;
            background: transparent;
            border: none;
            outline: none;
            color: #ffffff;
            font-size: 15px;
            font-family: inherit;
            padding: 8px 0;
            caret-color: #7ab3ff;
            user-select: auto;
            -webkit-user-select: auto;
        }

        .search-input::placeholder {
            color: rgba(255, 255, 255, 0.25);
        }

        .search-btn {
            background: rgba(255, 255, 255, 0.08);
            border: 1px solid rgba(255, 255, 255, 0.05);
            border-radius: 10px;
            width: 38px;
            height: 38px;
            display: flex;
            align-items: center;
            justify-content: center;
            cursor: pointer;
            color: rgba(255, 255, 255, 0.8);
            transition: all 0.2s ease;
            margin-left: 10px;
        }

        .search-btn:hover {
            background: #5299ff;
            color: #ffffff;
            border-color: #5299ff;
            box-shadow: 0 4px 12px rgba(82, 153, 255, 0.4);
        }

        .search-btn:active {
            transform: scale(0.92);
        }

        .search-btn svg {
            width: 18px;
            height: 18px;
            fill: currentColor;
            transition: transform 0.2s;
        }
        
        .search-btn:hover svg {
            transform: scale(1.1);
        }

        .resize-handle {
            position: absolute;
            right: 6px;
            bottom: 6px;
            width: 14px;
            height: 14px;
            cursor: nwse-resize;
            background: radial-gradient(circle at 60% 60%, rgba(255,255,255,0.2) 1.5px, transparent 1.5px);
            background-size: 4px 4px;
            border-bottom-right-radius: 12px;
            opacity: 0.4;
            transition: opacity 0.2s;
        }
        
        .resize-handle:hover {
            opacity: 1;
        }
    </style>
</head>
<body>
    <div class="card">
        <div class="header yanm-drag" data-yanm-drag="true">
            <svg class="header-icon" viewBox="0 0 24 24">
                <path d="M15.5,14L20.5,19L19,20.5L14,15.5V14.71L13.73,14.43C12.59,15.41 11.11,16 9.5,16A6.5,6.5 0 0,1 3,9.5A6.5,6.5 0 0,1 9.5,3A6.5,6.5 0 0,1 16,9.5C16,11.11 15.41,12.59 14.43,13.73L14.71,14H15.5M9.5,14C12,14 14,12 14,9.5C14,7 12,5 9.5,5C7,5 5,7 5,9.5C5,12 7,14 9.5,14M12,20V22H2V20H12Z" />
            </svg>
            极速探索
        </div>
        
        <div class="main-content">
            <div class="engine-tabs" id="engineTabs"></div>
            
            <div class="search-container">
                <input type="text" id="searchInput" class="search-input" placeholder="输入你想知道的一切..." autocomplete="off" spellcheck="false" />
                <button id="searchBtn" class="search-btn" title="立即搜索">
                    <svg viewBox="0 0 24 24">
                        <path d="M4,11V13H16L10.5,18.5L11.92,19.92L19.84,12L11.92,4.08L10.5,5.5L16,11H4Z" />
                    </svg>
                </button>
            </div>
        </div>
        
        <div class="resize-handle yanm-resize" data-yanm-resize="true"></div>
    </div>

    <script>
        const engines = [
            { id: 'bing', name: '必应', url: 'https://cn.bing.com/search?q=' },
            { id: 'google', name: 'Google', url: 'https://www.google.com/search?q=' },
            { id: 'baidu', name: '百度', url: 'https://www.baidu.com/s?wd=' },
            { id: 'bilibili', name: 'B站', url: 'https://search.bilibili.com/all?keyword=' },
            { id: 'github', name: 'GitHub', url: 'https://github.com/search?q=' },
            { id: 'zhihu', name: '知乎', url: 'https://www.zhihu.com/search?type=content&q=' }
        ];

        let state = {
            activeEngine: 'bing'
        };

        const STATE_KEY = 'yanm_widget_engine_state';
        const engineTabsEl = document.getElementById('engineTabs');
        const searchInputEl = document.getElementById('searchInput');
        const searchBtnEl = document.getElementById('searchBtn');

        function renderTabs() {
            engineTabsEl.innerHTML = '';
            engines.forEach(engine => {
                const tab = document.createElement('div');
                tab.className = `engine-tab ${state.activeEngine === engine.id ? 'active' : ''}`;
                tab.innerText = engine.name;
                tab.onclick = () => {
                    state.activeEngine = engine.id;
                    renderTabs();
                    saveState();
                    searchInputEl.focus();
                };
                engineTabsEl.appendChild(tab);
            });
        }

        function doSearch() {
            const query = searchInputEl.value.trim();
            if (!query) {
                searchInputEl.focus();
                return;
            }
            const engine = engines.find(e => e.id === state.activeEngine) || engines[0];
            const targetUrl = engine.url + encodeURIComponent(query);
            
            if (window.yanm) {
                window.yanm.invoke('url.open', { url: targetUrl, closeAfterOpen: true }).catch(err => {
                    console.error('Yanm URL open failed:', err);
                });
            } else {
                window.open(targetUrl, '_blank');
            }
            searchInputEl.value = '';
        }

        searchBtnEl.onclick = doSearch;
        searchInputEl.onkeydown = (e) => {
            if (e.key === 'Enter') {
                e.preventDefault();
                doSearch();
            }
        };

        function saveState() {
            const stateStr = JSON.stringify(state);
            localStorage.setItem(STATE_KEY, stateStr);
            if (window.yanm) {
                window.yanm.invoke('state.set', { key: STATE_KEY, value: stateStr }).catch(console.error);
            }
        }

        function applyState(stateStr) {
            if (!stateStr) return;
            try {
                const parsed = JSON.parse(stateStr);
                if (parsed && parsed.activeEngine) {
                    state.activeEngine = parsed.activeEngine;
                    renderTabs();
                }
            } catch (e) {
                console.error('Parse state error:', e);
            }
        }

        function init() {
            renderTabs();
            const localState = localStorage.getItem(STATE_KEY);
            if (localState) {
                applyState(localState);
            }
            
            setTimeout(() => { searchInputEl.focus(); }, 200);

            let attempts = 0;
            const tryConnectHost = () => {
                if (window.yanm) {
                    window.yanm.invoke('state.get', { key: STATE_KEY })
                        .then(res => {
                            if (res) applyState(res);
                        })
                        .catch(err => console.warn('Yanmu state.get failed:', err));
                } else if (attempts < 50) {
                    attempts++;
                    setTimeout(tryConnectHost, 100);
                }
            };
            tryConnectHost();
        }

        init();
    </script>
</body>
</html>


回复内容
暂无回复
回复主贴