Greasy Fork

Greasy Fork is available in English.

增强版推特搜索助手-Twitter Search Assistant Enhanced

增强版推特搜索助手 - 右上角定位、浅色系UI、复合搜索、智能替换当前筛选

当前为 2025-11-05 提交的版本,查看 最新版本

// ==UserScript==
// @name         增强版推特搜索助手-Twitter Search Assistant Enhanced
// @namespace    example.twitter.enhanced
// @version      0.5
// @description  增强版推特搜索助手 - 右上角定位、浅色系UI、复合搜索、智能替换当前筛选
// @match        https://twitter.com/*
// @match        https://x.com/*
// @grant        none
// @license MIT
// ==/UserScript==

(function () {
  'use strict';

  // 定义搜索预设
  const presets = {
    "📷 图片": "filter:images -filter:retweets -filter:replies",
    "🎬 视频": "filter:videos -filter:retweets -filter:replies",
    "🔥 高热度": "min_faves:200 -filter:retweets",
    "🈶 日语": "lang:ja -filter:retweets -filter:replies",
    "🌎 英语": "lang:en -filter:retweets -filter:replies",
    "💬 感想": "感想 OR 評価 lang:ja -filter:retweets -filter:replies",
    "⏰ 近期": "since:2024-07-25 -filter:retweets",
    "📊 热门": "min_faves:500 -filter:retweets"
  };

  // 主面板HTML
  const panel = document.createElement('div');
  panel.id = 'tw-search-assistant';
  panel.innerHTML = `
    <div class="panel-header">
      <span>搜索助手</span>
      <button class="toggle-mode" title="切换单选/多选模式">🔄</button>
    </div>
    <div class="mode-indicator">单选模式</div>
    <input id="tw-keyword" type="text" placeholder="输入关键词(可从地址栏自动获取)">
    <div class="preset-grid"></div>
    <div class="action-buttons">
      <button class="btn-clear">清空</button>
      <button class="btn-apply">应用搜索</button>
    </div>
  `;

  // 浅色系样式
  const style = document.createElement('style');
  style.textContent = `
    #tw-search-assistant {
      position: fixed;
      top: 60px;
      right: 320px;
      z-index: 10000;
      width: 280px;
      background: #ffffff;
      border: 1px solid #e1e8ed;
      border-radius: 12px;
      box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
      font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Arial, sans-serif;
      font-size: 13px;
      color: #0f1419;
      transition: all 0.3s ease;
      opacity: 0;
      transform: translateY(-10px);
    }
    
    #tw-search-assistant.show {
      opacity: 1;
      transform: translateY(0);
    }
    
    #tw-search-assistant:hover {
      box-shadow: 0 8px 30px rgba(0, 0, 0, 0.12);
    }
    
    .panel-header {
      display: flex;
      justify-content: space-between;
      align-items: center;
      padding: 12px 16px 8px;
      border-bottom: 1px solid #eff3f4;
      font-weight: 600;
    }
    
    .toggle-mode {
      background: none;
      border: none;
      cursor: pointer;
      font-size: 14px;
      padding: 2px 4px;
      border-radius: 4px;
      transition: background 0.2s;
    }
    
    .toggle-mode:hover {
      background: #f7f9fa;
    }
    
    .mode-indicator {
      padding: 4px 16px;
      font-size: 11px;
      color: #536471;
      background: #f7f9fa;
      margin: 0 16px 8px;
      border-radius: 6px;
      text-align: center;
    }
    
    #tw-keyword {
      width: calc(100% - 32px);
      margin: 0 16px 12px;
      padding: 8px 12px;
      border: 1px solid #eff3f4;
      border-radius: 8px;
      font-size: 14px;
      outline: none;
      transition: border-color 0.2s;
    }
    
    #tw-keyword:focus {
      border-color: #1da1f2;
      box-shadow: 0 0 0 3px rgba(29, 161, 242, 0.1);
    }
    
    .preset-grid {
      display: grid;
      grid-template-columns: 1fr 1fr;
      gap: 6px;
      padding: 0 16px 12px;
    }
    
    .preset-btn {
      padding: 8px 12px;
      background: #f7f9fa;
      border: 1px solid #eff3f4;
      border-radius: 8px;
      color: #0f1419;
      cursor: pointer;
      font-size: 12px;
      transition: all 0.2s;
      display: flex;
      align-items: center;
      gap: 4px;
    }
    
    .preset-btn:hover {
      background: #e8f5fe;
      border-color: #cfe5f7;
    }
    
    .preset-btn.selected {
      background: #e8f5fe;
      color: #1da1f2;
      border-color: #1da1f2;
    }
    
    .preset-btn.selected::after {
      content: '✓';
      margin-left: auto;
      font-size: 11px;
      font-weight: bold;
    }
    
    .action-buttons {
      display: flex;
      gap: 8px;
      padding: 0 16px 16px;
    }
    
    .btn-clear, .btn-apply {
      flex: 1;
      padding: 8px;
      border: none;
      border-radius: 8px;
      font-size: 13px;
      cursor: pointer;
      transition: all 0.2s;
      font-weight: 500;
    }
    
    .btn-clear {
      background: #f7f9fa;
      color: #536471;
      border: 1px solid #eff3f4;
    }
    
    .btn-clear:hover {
      background: #e1e8ed;
    }
    
    .btn-apply {
      background: #1da1f2;
      color: white;
    }
    
    .btn-apply:hover {
      background: #1a91da;
    }
    
    /* 响应式调整 */
    @media (max-width: 1280px) {
      #tw-search-assistant {
        right: 280px;
      }
    }
  `;
  document.head.appendChild(style);
  document.body.appendChild(panel);

  // 状态管理
  let isMultiSelectMode = false;
  let selectedPresets = new Set();

  // 初始化按钮
  function initButtons() {
    const grid = document.querySelector('.preset-grid');
    Object.keys(presets).forEach(name => {
      const btn = document.createElement('button');
      btn.className = 'preset-btn';
      btn.textContent = name;
      btn.onclick = () => handlePresetClick(btn, presets[name]);
      grid.appendChild(btn);
    });
  }

  // 处理预设点击
  function handlePresetClick(btn, filter) {
    if (isMultiSelectMode) {
      if (selectedPresets.has(filter)) {
        selectedPresets.delete(filter);
        btn.classList.remove('selected');
      } else {
        selectedPresets.add(filter);
        btn.classList.add('selected');
      }
    } else {
      // 单选模式:自动执行搜索
      applySearch(filter);
    }
  }

  // 应用搜索
  function applySearch(additionalFilter = null) {
    const kw = document.getElementById('tw-keyword').value.trim();
    let currentUrl = window.location.href;
    
    // 获取当前搜索参数
    let currentQuery = '';
    if (currentUrl.includes('/search?q=')) {
      const match = currentUrl.match(/\/search\?q=([^&]+)/);
      if (match) {
        currentQuery = decodeURIComponent(match[1]);
      }
    }
    
    // 构建新搜索
    let newQuery = kw || currentQuery;
    
    if (additionalFilter) {
      if (isMultiSelectMode && selectedPresets.size > 0) {
        // 复合搜索
        const filters = Array.from(selectedPresets).join(' ');
        newQuery = newQuery ? `${newQuery} ${filters}` : filters;
      } else {
        // 单个筛选
        newQuery = newQuery ? `${newQuery} ${additionalFilter}` : additionalFilter;
      }
    }
    
    if (newQuery) {
      const searchUrl = `https://twitter.com/search?q=${encodeURIComponent(newQuery)}&src=typed_query&f=top`;
      window.location.href = searchUrl;
    }
  }

  // 清空选择
  function clearSelection() {
    selectedPresets.clear();
    document.querySelectorAll('.preset-btn.selected').forEach(btn => {
      btn.classList.remove('selected');
    });
  }

  // 切换模式
  function toggleMode() {
    isMultiSelectMode = !isMultiSelectMode;
    document.querySelector('.mode-indicator').textContent = isMultiSelectMode ? '多选模式' : '单选模式';
    clearSelection();
  }

  // 自动获取当前搜索词
  function autoFillKeyword() {
    const currentUrl = window.location.href;
    if (currentUrl.includes('/search?q=')) {
      const match = currentUrl.match(/\/search\?q=([^&]+)/);
      if (match) {
        const keyword = decodeURIComponent(match[1]).split(' ')[0]; // 只取关键词部分
        document.getElementById('tw-keyword').value = keyword;
      }
    }
  }

  // 绑定事件
  document.querySelector('.toggle-mode').onclick = toggleMode;
  document.querySelector('.btn-clear').onclick = clearSelection;
  document.querySelector('.btn-apply').onclick = () => applySearch();

  // 初始化
  initButtons();
  autoFillKeyword();
  
  // 显示面板(延迟显示效果)
  setTimeout(() => {
    panel.classList.add('show');
  }, 100);

})();