feat: 插件改为浮窗模式
This commit is contained in:
@@ -0,0 +1,145 @@
|
||||
// Panel Content Script —— 商品页右下角悬浮按钮 + 页内悬浮面板
|
||||
//
|
||||
// 面板 = iframe 加载插件内置 sidepanel.html(扩展页面在 iframe 里仍有 chrome.* 权限,
|
||||
// 采集/生成/导出逻辑零改动);按钮与面板容器渲染在独立 Shadow DOM 中,
|
||||
// 不受商品页全局 CSS 影响,面板悬浮覆盖页面、不挤压原页面布局。
|
||||
import { matchProfile } from '../src/profiles/index';
|
||||
|
||||
/** 面板内 App.tsx → 宿主页的收起消息 */
|
||||
const PANEL_CLOSE_MSG = 'sc-panel-close';
|
||||
|
||||
const STYLES = `
|
||||
:host { all: initial; }
|
||||
|
||||
.fab {
|
||||
position: fixed;
|
||||
right: 24px;
|
||||
bottom: 24px;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
border-radius: 50%;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font: 700 20px/1 -apple-system, 'PingFang SC', 'Microsoft YaHei', sans-serif;
|
||||
color: #fff;
|
||||
background: linear-gradient(135deg, #8b5cf6, #6d28d9);
|
||||
box-shadow: 0 4px 16px rgba(109, 40, 217, 0.45);
|
||||
z-index: 3;
|
||||
transition: transform 0.15s ease;
|
||||
}
|
||||
.fab:hover { transform: scale(1.08); }
|
||||
.fab.hidden { display: none; }
|
||||
|
||||
.panel {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
width: min(880px, 100vw);
|
||||
border-radius: 14px 0 0 14px;
|
||||
overflow: hidden;
|
||||
background: #fff;
|
||||
box-shadow: -8px 0 32px rgba(0, 0, 0, 0.25), 0 0 0 1px rgba(0, 0, 0, 0.06);
|
||||
transform: translateX(100%);
|
||||
transition: transform 0.25s ease;
|
||||
z-index: 2;
|
||||
pointer-events: none;
|
||||
}
|
||||
.panel.open { transform: translateX(0); pointer-events: auto; }
|
||||
|
||||
.panel iframe {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: 0;
|
||||
display: block;
|
||||
background: #fff;
|
||||
}
|
||||
`;
|
||||
|
||||
export default defineContentScript({
|
||||
matches: [
|
||||
// Ozon
|
||||
'https://*.ozon.ru/*',
|
||||
'https://*.ozon.kz/*',
|
||||
'https://*.ozon.by/*',
|
||||
// 1688
|
||||
'https://detail.1688.com/*',
|
||||
// 淘宝 / 天猫
|
||||
'https://item.taobao.com/*',
|
||||
'https://detail.tmall.com/*',
|
||||
],
|
||||
async main(ctx) {
|
||||
const ui = await createShadowRootUi(ctx, {
|
||||
name: 'suite-studio-panel',
|
||||
position: 'overlay',
|
||||
anchor: 'body',
|
||||
alignment: 'bottom-right',
|
||||
zIndex: 2147483646,
|
||||
css: STYLES,
|
||||
isolateEvents: true,
|
||||
onMount(container) {
|
||||
const fab = document.createElement('button');
|
||||
fab.className = 'fab hidden';
|
||||
fab.title = '电商套图工作台';
|
||||
fab.textContent = '套';
|
||||
|
||||
const panel = document.createElement('div');
|
||||
panel.className = 'panel';
|
||||
// iframe 懒加载:首次展开才设 src,避免每个商品页都加载整个面板应用
|
||||
const iframe = document.createElement('iframe');
|
||||
iframe.title = '电商套图工作台';
|
||||
panel.append(iframe);
|
||||
container.append(fab, panel);
|
||||
|
||||
const open = () => {
|
||||
if (!iframe.src) iframe.src = chrome.runtime.getURL('/sidepanel.html');
|
||||
panel.classList.add('open');
|
||||
fab.classList.add('hidden');
|
||||
// 聚焦进面板,键盘操作(Esc 关闭 / 预览翻页)直接可用
|
||||
iframe.focus();
|
||||
};
|
||||
const close = () => {
|
||||
panel.classList.remove('open');
|
||||
if (isProductPage()) fab.classList.remove('hidden');
|
||||
};
|
||||
|
||||
fab.addEventListener('click', open);
|
||||
|
||||
// 面板内 App(✕ / Esc)→ 收起
|
||||
window.addEventListener('message', (e) => {
|
||||
if (e.source === iframe.contentWindow && (e.data as any)?.type === PANEL_CLOSE_MSG) close();
|
||||
});
|
||||
|
||||
// 工具栏图标点击 → 开关面板
|
||||
chrome.runtime.onMessage.addListener((msg: any) => {
|
||||
if (msg?.action === 'toggle-suite-panel') {
|
||||
panel.classList.contains('open') ? close() : open();
|
||||
}
|
||||
});
|
||||
|
||||
// 仅商品详情页显示按钮;站内软导航后重判(WXT 内置事件,自动拦截 pushState/replaceState/popState)
|
||||
const refresh = () => {
|
||||
if (isProductPage()) {
|
||||
if (!panel.classList.contains('open')) fab.classList.remove('hidden');
|
||||
} else {
|
||||
fab.classList.add('hidden');
|
||||
close();
|
||||
}
|
||||
};
|
||||
ctx.addEventListener(window, 'wxt:locationchange', refresh);
|
||||
refresh();
|
||||
|
||||
return { open, close };
|
||||
},
|
||||
});
|
||||
ui.mount();
|
||||
},
|
||||
});
|
||||
|
||||
/** 是否为四站点支持的商品详情页(与采集 profile 一致) */
|
||||
function isProductPage(): boolean {
|
||||
return matchProfile(location.href) !== null;
|
||||
}
|
||||
Reference in New Issue
Block a user