mirror of
https://github.com/yaklang/yaklang-chrome-extension.git
synced 2026-09-26 21:21:53 +08:00
fix popup options.html context
This commit is contained in:
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 36 KiB |
@@ -39,18 +39,20 @@
|
|||||||
"tabs"
|
"tabs"
|
||||||
],
|
],
|
||||||
"host_permissions": [
|
"host_permissions": [
|
||||||
"<all_urls>",
|
"<all_urls>"
|
||||||
"*://mitm/*"
|
|
||||||
],
|
],
|
||||||
|
|
||||||
"web_accessible_resources": [
|
"web_accessible_resources": [
|
||||||
{
|
{
|
||||||
"resources": [
|
"resources": [
|
||||||
"types/*.js",
|
"images/*",
|
||||||
"proxy/*.js",
|
"proxy/*"
|
||||||
"socket.js",
|
],
|
||||||
"proxy.js",
|
"matches": ["<all_urls>"]
|
||||||
"proxy/content.js"
|
},
|
||||||
|
{
|
||||||
|
"resources": [
|
||||||
|
"/images/yak.svg"
|
||||||
],
|
],
|
||||||
"matches": ["<all_urls>"]
|
"matches": ["<all_urls>"]
|
||||||
}
|
}
|
||||||
|
|||||||
+81
-18
@@ -9,6 +9,9 @@ const ProxyActionType = {
|
|||||||
UPDATE_PROXY_CONFIG: 'UPDATE_PROXY_CONFIG'
|
UPDATE_PROXY_CONFIG: 'UPDATE_PROXY_CONFIG'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 在文件顶部添加常量声明
|
||||||
|
const YAK_ICON_URL = chrome.runtime.getURL('/images/yak.svg');
|
||||||
|
|
||||||
// 添加一个通用的消息发送函数
|
// 添加一个通用的消息发送函数
|
||||||
async function sendMessageWithRetry(message, maxRetries = 3) {
|
async function sendMessageWithRetry(message, maxRetries = 3) {
|
||||||
for (let i = 0; i < maxRetries; i++) {
|
for (let i = 0; i < maxRetries; i++) {
|
||||||
@@ -139,26 +142,39 @@ async function updatePanel() {
|
|||||||
|
|
||||||
// 修改这里的判断逻辑
|
// 修改这里的判断逻辑
|
||||||
let html = `
|
let html = `
|
||||||
<div class="proxy-item ${currentProxy.proxy === '' ? 'active' : ''}" data-id="direct">
|
<div class="proxy-item ${!currentProxy.enable && currentProxy.proxy === '' ? 'active' : ''}"
|
||||||
<span style="color: ${currentProxy.proxy === '' ? '#ff6b00' : '#666'}">🔴</span>
|
data-id="direct"
|
||||||
|
title="直接连接">
|
||||||
|
<span style="color: ${!currentProxy.enable && currentProxy.proxy === '' ? '#ff6b00' : '#666'}">🟢</span>
|
||||||
<span>[直接连接]</span>
|
<span>[直接连接]</span>
|
||||||
|
<img src="${YAK_ICON_URL}" class="watermark-icon" alt="" />
|
||||||
</div>
|
</div>
|
||||||
<div class="proxy-item ${currentProxy.proxy === 'system' ? 'active' : ''}" data-id="system">
|
<div class="proxy-item ${currentProxy.proxy === 'system' ? 'active' : ''}"
|
||||||
|
data-id="system"
|
||||||
|
title="系统代理">
|
||||||
<span style="color: ${currentProxy.proxy === 'system' ? '#ff6b00' : '#666'}">⚙️</span>
|
<span style="color: ${currentProxy.proxy === 'system' ? '#ff6b00' : '#666'}">⚙️</span>
|
||||||
<span>[系统代理]</span>
|
<span>[系统代理]</span>
|
||||||
|
<img src="${YAK_ICON_URL}" class="watermark-icon" alt="" />
|
||||||
</div>
|
</div>
|
||||||
|
<div class="divider"></div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
// 添加自定义代理配置
|
// 修改自定义代理配置的判断逻辑
|
||||||
configs.forEach(config => {
|
configs.forEach(config => {
|
||||||
if (config.id !== 'direct' && config.id !== 'system') {
|
if (config.id !== 'direct' && config.id !== 'system') {
|
||||||
// 检查当前代理是否与配置匹配
|
const proxyUrl = `${config.scheme}://${config.host}:${config.port}`;
|
||||||
const isActive = currentProxy.enable &&
|
const isActive = currentProxy.enable && currentProxy.proxy === proxyUrl && config.enabled;
|
||||||
currentProxy.proxy === `${config.scheme}://${config.host}:${config.port}`;
|
|
||||||
|
// 添加 title 属性显示详细信息
|
||||||
|
const tooltipText = `${config.scheme.toUpperCase()} ${config.host}:${config.port}`;
|
||||||
|
|
||||||
html += `
|
html += `
|
||||||
<div class="proxy-item ${isActive ? 'active' : ''}" data-id="${config.id}">
|
<div class="proxy-item ${isActive ? 'active' : ''}"
|
||||||
|
data-id="${config.id}"
|
||||||
|
title="${tooltipText}">
|
||||||
<span style="color: ${isActive ? '#ff6b00' : '#666'}">🌐</span>
|
<span style="color: ${isActive ? '#ff6b00' : '#666'}">🌐</span>
|
||||||
<span>${config.name}</span>
|
<span>${config.name}</span>
|
||||||
|
<img src="${YAK_ICON_URL}" class="watermark-icon" alt="" />
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
@@ -247,7 +263,7 @@ function createFloatingPanel() {
|
|||||||
position: fixed;
|
position: fixed;
|
||||||
top: 20px;
|
top: 20px;
|
||||||
right: 0;
|
right: 0;
|
||||||
width: 200px;
|
width: 180px;
|
||||||
background: white;
|
background: white;
|
||||||
border-radius: 8px 0 0 8px;
|
border-radius: 8px 0 0 8px;
|
||||||
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
||||||
@@ -299,21 +315,41 @@ function createFloatingPanel() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.panel-content {
|
.panel-content {
|
||||||
padding: 12px;
|
padding: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.proxy-item {
|
.proxy-item {
|
||||||
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 8px 12px;
|
padding: 4px 10px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: all 0.2s;
|
transition: all 0.2s;
|
||||||
color: #666;
|
color: #666;
|
||||||
border-left: 3px solid transparent;
|
border-left: 3px solid transparent;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.proxy-item:hover {
|
.proxy-item > span {
|
||||||
background: #f5f5f5;
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.watermark-icon {
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
opacity: 0.3;
|
||||||
|
pointer-events: none;
|
||||||
|
display: none;
|
||||||
|
object-fit: contain;
|
||||||
|
object-position: right center;
|
||||||
|
padding: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.proxy-item.active .watermark-icon {
|
||||||
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.proxy-item.active {
|
.proxy-item.active {
|
||||||
@@ -333,6 +369,10 @@ function createFloatingPanel() {
|
|||||||
transition: color 0.2s;
|
transition: color 0.2s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.proxy-item:hover {
|
||||||
|
background: #f5f5f5;
|
||||||
|
}
|
||||||
|
|
||||||
.proxy-item:hover span:first-child {
|
.proxy-item:hover span:first-child {
|
||||||
color: #ff6b00;
|
color: #ff6b00;
|
||||||
}
|
}
|
||||||
@@ -340,7 +380,7 @@ function createFloatingPanel() {
|
|||||||
.add-proxy {
|
.add-proxy {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 8px 12px;
|
padding: 4px 10px;
|
||||||
color: #1890ff;
|
color: #1890ff;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
border-top: 1px solid #eee;
|
border-top: 1px solid #eee;
|
||||||
@@ -352,7 +392,7 @@ function createFloatingPanel() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.settings {
|
.settings {
|
||||||
padding: 8px 12px;
|
padding: 4px 10px;
|
||||||
color: #666;
|
color: #666;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
border-top: 1px solid #eee;
|
border-top: 1px solid #eee;
|
||||||
@@ -362,6 +402,25 @@ function createFloatingPanel() {
|
|||||||
.settings:hover {
|
.settings:hover {
|
||||||
background: #f5f5f5;
|
background: #f5f5f5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.panel-header .header-content {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 0 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.yak-icon {
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
object-fit: contain;
|
||||||
|
}
|
||||||
|
|
||||||
|
.divider {
|
||||||
|
height: 1px;
|
||||||
|
background-color: #eee;
|
||||||
|
margin: 4px 0;
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
// 创建面板内容
|
// 创建面板内容
|
||||||
@@ -370,20 +429,24 @@ function createFloatingPanel() {
|
|||||||
panel.innerHTML = `
|
panel.innerHTML = `
|
||||||
<div class="collapse-trigger"></div>
|
<div class="collapse-trigger"></div>
|
||||||
<div class="panel-header">
|
<div class="panel-header">
|
||||||
<span>代理设置</span>
|
<div class="header-content">
|
||||||
|
<img src="${YAK_ICON_URL}" class="yak-icon" alt="Yak" />
|
||||||
|
<span>代理设置</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-content">
|
<div class="panel-content">
|
||||||
<div class="proxy-item active">
|
<div class="proxy-item active">
|
||||||
<span>🔴</span>
|
<span>🟢</span>
|
||||||
<span>[直接连接]</span>
|
<span>[直接连接]</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="proxy-item">
|
<div class="proxy-item">
|
||||||
<span>⚙️</span>
|
<span>⚙️</span>
|
||||||
<span>[系统代理]</span>
|
<span>[系统代理]</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="divider"></div>
|
||||||
<div class="add-proxy">
|
<div class="add-proxy">
|
||||||
<span>➕</span>
|
<span>➕</span>
|
||||||
<span>添加代理...</span>
|
<span>[添加代理...]</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="settings">
|
<div class="settings">
|
||||||
<span>👨💻</span>
|
<span>👨💻</span>
|
||||||
|
|||||||
@@ -200,4 +200,36 @@ body {
|
|||||||
|
|
||||||
.ant-menu-item .menu-icon {
|
.ant-menu-item .menu-icon {
|
||||||
transition: color 0.3s ease;
|
transition: color 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.proxy-switch-container {
|
||||||
|
position: relative;
|
||||||
|
width: 180px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-watermark {
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
opacity: 0.03;
|
||||||
|
pointer-events: none;
|
||||||
|
object-fit: contain;
|
||||||
|
object-position: right bottom;
|
||||||
|
z-index: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 确保菜单项在水印上层 */
|
||||||
|
.ant-menu-item {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
background: transparent !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 确保分割线在水印上层 */
|
||||||
|
.ant-menu-item-divider {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
}
|
}
|
||||||
@@ -6,6 +6,9 @@ import "./index.css";
|
|||||||
import type { MenuProps } from 'antd';
|
import type { MenuProps } from 'antd';
|
||||||
import type { ProxyConfig } from '@/types/proxy';
|
import type { ProxyConfig } from '@/types/proxy';
|
||||||
|
|
||||||
|
// 添加 YAK 图标 URL 常量
|
||||||
|
const YAK_ICON_URL = chrome.runtime.getURL('/images/yak.svg');
|
||||||
|
|
||||||
// 固定的代理模式
|
// 固定的代理模式
|
||||||
const FIXED_MODES = [
|
const FIXED_MODES = [
|
||||||
{
|
{
|
||||||
@@ -48,18 +51,21 @@ interface ProxySwitchProps {
|
|||||||
onProxyChange: (config: ProxyConfig) => void;
|
onProxyChange: (config: ProxyConfig) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ProxySwitch: React.FC<ProxySwitchProps> = ({
|
export const ProxySwitch: React.FC<ProxySwitchProps> = () => {
|
||||||
proxyConfigs,
|
const [initialized, setInitialized] = useState<boolean>(false);
|
||||||
currentProxy,
|
const [currentMode, setCurrentMode] = useState<string>('');
|
||||||
onProxyChange,
|
|
||||||
}) => {
|
|
||||||
const [currentMode, setCurrentMode] = useState<string>('direct');
|
|
||||||
const [customProxies, setCustomProxies] = useState<CustomProxy[]>([]);
|
const [customProxies, setCustomProxies] = useState<CustomProxy[]>([]);
|
||||||
const [isLoading, setIsLoading] = useState<boolean>(false);
|
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
loadProxyStatus();
|
const init = async () => {
|
||||||
loadCustomProxies();
|
await Promise.all([
|
||||||
|
loadProxyStatus(),
|
||||||
|
loadCustomProxies()
|
||||||
|
]);
|
||||||
|
setInitialized(true);
|
||||||
|
};
|
||||||
|
init();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const loadProxyStatus = async () => {
|
const loadProxyStatus = async () => {
|
||||||
@@ -68,55 +74,154 @@ export const ProxySwitch: React.FC<ProxySwitchProps> = ({
|
|||||||
action: ProxyActionType.GET_PROXY_STATUS
|
action: ProxyActionType.GET_PROXY_STATUS
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (!response) {
|
||||||
|
console.log('No response from background script');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (response.success) {
|
if (response.success) {
|
||||||
const activeMode = response.data.mode;
|
const activeMode = response.data.mode;
|
||||||
setCurrentMode(activeMode);
|
|
||||||
|
|
||||||
if (FIXED_MODES.some(mode => mode.key === activeMode)) {
|
if (FIXED_MODES.some(mode => mode.key === activeMode)) {
|
||||||
setCurrentMode(activeMode);
|
setCurrentMode(activeMode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error loading proxy status:', error);
|
console.error('Error loading proxy status:', error);
|
||||||
|
setCurrentMode('direct');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const loadCustomProxies = async () => {
|
const loadCustomProxies = async () => {
|
||||||
try {
|
try {
|
||||||
const response = await chrome.runtime.sendMessage({
|
// 首先检查当前是否在 options 页面的上下文中
|
||||||
action: ProxyActionType.GET_PROXY_CONFIGS
|
const currentUrl = window.location.href;
|
||||||
});
|
const isInOptionsContext = currentUrl.includes('chrome-extension://') && currentUrl.includes('options.html');
|
||||||
|
|
||||||
if (response.success && response.data) {
|
|
||||||
const proxies = response.data
|
|
||||||
.filter((proxy: ProxyConfig) => !FIXED_MODES.some(mode => mode.key === proxy.id))
|
|
||||||
.map((proxy: ProxyConfig): CustomProxy => ({
|
|
||||||
key: proxy.id,
|
|
||||||
name: proxy.name,
|
|
||||||
color: '#1890ff',
|
|
||||||
config: proxy,
|
|
||||||
enabled: proxy.enabled
|
|
||||||
}));
|
|
||||||
setCustomProxies(proxies);
|
|
||||||
|
|
||||||
const enabledProxy = proxies.find((proxy: ProxyConfig) => proxy.enabled);
|
if (isInOptionsContext) {
|
||||||
if (enabledProxy) {
|
// 如果在 options 页面上下文中,直接使用消息通信
|
||||||
setCurrentMode(enabledProxy.key);
|
const response = await chrome.runtime.sendMessage({
|
||||||
|
action: ProxyActionType.GET_PROXY_CONFIGS
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response?.success && response.data) {
|
||||||
|
const proxies = response.data
|
||||||
|
.filter((proxy: ProxyConfig) => !FIXED_MODES.some(mode => mode.key === proxy.id))
|
||||||
|
.map((proxy: ProxyConfig): CustomProxy => ({
|
||||||
|
key: proxy.id,
|
||||||
|
name: proxy.name,
|
||||||
|
color: '#1890ff',
|
||||||
|
config: proxy,
|
||||||
|
enabled: proxy.enabled
|
||||||
|
}));
|
||||||
|
setCustomProxies(proxies);
|
||||||
|
|
||||||
|
const enabledProxy = response.data.find((proxy: ProxyConfig) => proxy.enabled);
|
||||||
|
if (enabledProxy) {
|
||||||
|
setCurrentMode(enabledProxy.id);
|
||||||
|
} else {
|
||||||
|
setCurrentMode('direct');
|
||||||
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 如果不在 options 页面上下文中,使用 IndexedDB
|
||||||
|
const DB_NAME = 'yaklang_extension';
|
||||||
|
const STORE_NAME = 'proxy_configs';
|
||||||
|
|
||||||
|
// 打开数据库
|
||||||
|
const db = await new Promise<IDBDatabase>((resolve, reject) => {
|
||||||
|
const request = indexedDB.open(DB_NAME, 1);
|
||||||
|
request.onerror = () => reject(request.error);
|
||||||
|
request.onsuccess = () => resolve(request.result);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 从数据库读取代理配置
|
||||||
|
const configs = await new Promise<ProxyConfig[]>((resolve, reject) => {
|
||||||
|
try {
|
||||||
|
const transaction = db.transaction([STORE_NAME], 'readonly');
|
||||||
|
const store = transaction.objectStore(STORE_NAME);
|
||||||
|
const request = store.getAll();
|
||||||
|
|
||||||
|
request.onerror = () => reject(request.error);
|
||||||
|
request.onsuccess = () => resolve(request.result || []);
|
||||||
|
} catch (error) {
|
||||||
|
reject(error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 处理代理配置
|
||||||
|
const proxies = configs
|
||||||
|
.filter((proxy: ProxyConfig) => !FIXED_MODES.some(mode => mode.key === proxy.id))
|
||||||
|
.map((proxy: ProxyConfig): CustomProxy => ({
|
||||||
|
key: proxy.id,
|
||||||
|
name: proxy.name,
|
||||||
|
color: '#1890ff',
|
||||||
|
config: proxy,
|
||||||
|
enabled: proxy.enabled
|
||||||
|
}));
|
||||||
|
setCustomProxies(proxies);
|
||||||
|
|
||||||
|
const enabledProxy = configs.find((proxy: ProxyConfig) => proxy.enabled);
|
||||||
|
if (enabledProxy) {
|
||||||
|
setCurrentMode(enabledProxy.id);
|
||||||
|
} else {
|
||||||
|
setCurrentMode('direct');
|
||||||
|
}
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error loading custom proxies:', error);
|
console.error('Error loading custom proxies:', error);
|
||||||
|
setCustomProxies([]);
|
||||||
|
setCurrentMode('direct');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleApplyConfig = async (mode: string) => {
|
const handleModeChange = async (mode: string) => {
|
||||||
|
if (mode === 'setting') {
|
||||||
|
await chrome.runtime.openOptionsPage?.();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mode === 'add') {
|
||||||
|
try {
|
||||||
|
const [activeTab] = await chrome.tabs.query({
|
||||||
|
active: true,
|
||||||
|
currentWindow: true
|
||||||
|
});
|
||||||
|
const optionsUrl = chrome.runtime.getURL('/proxy/options.html');
|
||||||
|
|
||||||
|
if (activeTab?.url === optionsUrl) {
|
||||||
|
chrome.tabs.sendMessage(activeTab.id!, {
|
||||||
|
action: 'TRIGGER_ADD_PROXY'
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
const tab = await chrome.tabs.create({
|
||||||
|
url: optionsUrl
|
||||||
|
});
|
||||||
|
|
||||||
|
const listener = (tabId: number, changeInfo: chrome.tabs.TabChangeInfo) => {
|
||||||
|
if (tabId === tab.id && changeInfo.status === 'complete') {
|
||||||
|
chrome.tabs.onUpdated.removeListener(listener);
|
||||||
|
chrome.tabs.sendMessage(tab.id!, {
|
||||||
|
action: 'TRIGGER_ADD_PROXY'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
chrome.tabs.onUpdated.addListener(listener);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to get current tab:', error);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
const fixedMode = FIXED_MODES.find(fixed => fixed.key === mode);
|
const fixedMode = FIXED_MODES.find(fixed => fixed.key === mode);
|
||||||
const customProxy = customProxies.find(proxy => proxy.key === mode);
|
const customProxy = customProxies.find(proxy => proxy.key === mode);
|
||||||
|
|
||||||
const config = fixedMode?.config || customProxy?.config;
|
const config = fixedMode?.config || customProxy?.config;
|
||||||
|
|
||||||
if (!config) {
|
if (!config) {
|
||||||
console.error('No config found for mode:', mode);
|
console.error('No config found for mode:', mode);
|
||||||
return;
|
return;
|
||||||
@@ -149,63 +254,13 @@ export const ProxySwitch: React.FC<ProxySwitchProps> = ({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleModeChange = async (mode: string) => {
|
|
||||||
if (mode === 'setting') {
|
|
||||||
await chrome.runtime.openOptionsPage?.();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mode === 'add') {
|
|
||||||
try {
|
|
||||||
// 获取当前活动标签页
|
|
||||||
const [activeTab] = await chrome.tabs.query({
|
|
||||||
active: true,
|
|
||||||
currentWindow: true
|
|
||||||
});
|
|
||||||
const optionsUrl = chrome.runtime.getURL('/proxy/options.html');
|
|
||||||
|
|
||||||
if (activeTab?.url === optionsUrl) {
|
|
||||||
// 如果当前就在 options 页面,直接发消息触发添加代理
|
|
||||||
chrome.tabs.sendMessage(activeTab.id!, {
|
|
||||||
action: 'TRIGGER_ADD_PROXY'
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
// 如果不在 options 页面,创建新的
|
|
||||||
const tab = await chrome.tabs.create({
|
|
||||||
url: optionsUrl
|
|
||||||
});
|
|
||||||
|
|
||||||
// 等待页面加载完成
|
|
||||||
const listener = (tabId: number, changeInfo: chrome.tabs.TabChangeInfo) => {
|
|
||||||
if (tabId === tab.id && changeInfo.status === 'complete') {
|
|
||||||
chrome.tabs.onUpdated.removeListener(listener);
|
|
||||||
chrome.tabs.sendMessage(tab.id!, {
|
|
||||||
action: 'TRIGGER_ADD_PROXY'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
chrome.tabs.onUpdated.addListener(listener);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Failed to get current tab:', error);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
await handleApplyConfig(mode);
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Failed to change proxy mode:', error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const menuItems: MenuProps['items'] = [
|
const menuItems: MenuProps['items'] = [
|
||||||
...FIXED_MODES.map(mode => ({
|
...FIXED_MODES.map(mode => ({
|
||||||
key: mode.key,
|
key: mode.key,
|
||||||
icon: <span className="menu-icon" style={{ color: mode.color }}>{mode.icon}</span>,
|
icon: <span className="menu-icon" style={{ color: mode.color }}>{mode.icon}</span>,
|
||||||
label: mode.name,
|
label: mode.name,
|
||||||
className: `${currentMode === mode.key ? 'menu-item-selected' : ''} ${isLoading ? 'menu-item-loading' : ''}`
|
className: `${currentMode === mode.key ? 'menu-item-selected' : ''} ${isLoading ? 'menu-item-loading' : ''}`,
|
||||||
|
title: mode.name.replace(/[\[\]]/g, '')
|
||||||
})),
|
})),
|
||||||
{ type: 'divider' },
|
{ type: 'divider' },
|
||||||
...customProxies.map(proxy => ({
|
...customProxies.map(proxy => ({
|
||||||
@@ -215,7 +270,8 @@ export const ProxySwitch: React.FC<ProxySwitchProps> = ({
|
|||||||
color: currentMode === proxy.key ? 'var(--yakit-primary)' : 'inherit',
|
color: currentMode === proxy.key ? 'var(--yakit-primary)' : 'inherit',
|
||||||
opacity: isLoading ? 0.7 : 1
|
opacity: isLoading ? 0.7 : 1
|
||||||
}}>{proxy.name}</span>,
|
}}>{proxy.name}</span>,
|
||||||
className: `${currentMode === proxy.key ? 'menu-item-selected' : ''} ${isLoading ? 'menu-item-loading' : ''}`
|
className: `${currentMode === proxy.key ? 'menu-item-selected' : ''} ${isLoading ? 'menu-item-loading' : ''}`,
|
||||||
|
title: `${proxy.config.scheme.toUpperCase()} ${proxy.config.host}:${proxy.config.port}`
|
||||||
})),
|
})),
|
||||||
{
|
{
|
||||||
key: 'add',
|
key: 'add',
|
||||||
@@ -231,13 +287,37 @@ export const ProxySwitch: React.FC<ProxySwitchProps> = ({
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
return (
|
return initialized ? (
|
||||||
<Menu
|
<div className="proxy-switch-container" style={{ position: 'relative' }}>
|
||||||
items={menuItems}
|
<img
|
||||||
selectedKeys={[currentMode]}
|
src={YAK_ICON_URL}
|
||||||
onClick={({ key }) => !isLoading && handleModeChange(key)}
|
className="panel-watermark"
|
||||||
style={{ width: 180 }}
|
alt=""
|
||||||
className={isLoading ? 'menu-loading' : ''}
|
style={{
|
||||||
/>
|
position: 'absolute',
|
||||||
|
right: 0,
|
||||||
|
bottom: 0,
|
||||||
|
width: '100%',
|
||||||
|
height: '100%',
|
||||||
|
opacity: 0.1,
|
||||||
|
backgroundColor: '#fff7e6',
|
||||||
|
pointerEvents: 'none',
|
||||||
|
objectFit: 'contain',
|
||||||
|
objectPosition: 'right bottom',
|
||||||
|
zIndex: 0
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Menu
|
||||||
|
items={menuItems}
|
||||||
|
selectedKeys={[currentMode]}
|
||||||
|
onClick={({ key }) => !isLoading && handleModeChange(key)}
|
||||||
|
style={{ width: 180, position: 'relative', zIndex: 1, background: 'transparent' }}
|
||||||
|
className={isLoading ? 'menu-loading' : ''}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div style={{ width: 180, height: 100, display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
|
||||||
|
<span>加载中...</span>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
Reference in New Issue
Block a user