| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354 |
- class PugePanel {
- constructor() {
- this.loadedCSS = new Set();
- this.init();
- }
- // 初始化方法
- init() {
- this.removeExistingStartBox();
- this.createPanel();
- this.createTriggerButton();
- }
- // 加载CSS,避免重复加载
- loadCSS(url) {
- if (this.loadedCSS.has(url)) return;
-
- this.loadedCSS.add(url);
- const link = document.createElement('link');
- link.rel = 'stylesheet';
- link.type = 'text/css';
- link.href = url;
- (document.head || document.documentElement).appendChild(link);
- }
- // 移除已存在的start-box
- removeExistingStartBox() {
- const existingBox = document.querySelector('.start-box');
- if (existingBox) {
- existingBox.remove();
- }
- }
- // 创建关闭按钮
- createCloseButton() {
- const closeBtn = document.createElement('div');
- closeBtn.className = 'puge-close-btn';
- closeBtn.innerHTML = '×';
- closeBtn.setAttribute('aria-label', '关闭面板');
-
- // 添加关闭按钮事件
- closeBtn.addEventListener('click', () => this.togglePanel(false));
- closeBtn.addEventListener('mouseenter', () => {
- closeBtn.style.color = '#ff4444';
- });
- closeBtn.addEventListener('mouseleave', () => {
- closeBtn.style.color = '#666';
- });
-
- return closeBtn;
- }
- // 创建标题栏
- createTitleBar() {
- const titleBar = document.createElement('div');
- titleBar.className = 'puge-title-bar';
-
- const titleText = document.createElement('span');
- titleText.className = 'puge-title';
- titleText.textContent = '功能面板';
-
- titleBar.appendChild(titleText);
- titleBar.appendChild(this.createCloseButton());
-
- return titleBar;
- }
- // 创建内容区域
- createContentArea() {
- const contentArea = document.createElement('div');
- contentArea.className = 'puge-box puge-content-area';
-
- // 根据屏幕方向设置高度
- const isLandscape = window.innerWidth > window.innerHeight;
- if (isLandscape) {
- contentArea.style.maxHeight = '60%';
- } else {
- contentArea.style.height = 'calc(100% - 40px)';
- }
-
- return contentArea;
- }
- // 创建主面板
- createPanel() {
- setTimeout(() => {
- if (document.querySelector('.start-box')) return;
-
- const panel = document.createElement('div');
- panel.className = 'start-box owo puge-panel';
- panel.setAttribute('aria-hidden', 'true');
-
- // 设置面板样式
- const isLandscape = window.innerWidth > window.innerHeight;
- Object.assign(panel.style, {
- display: 'none',
- zIndex: '9665',
- position: 'fixed',
- right: '0',
- bottom: '0',
- boxShadow: '1px 1px 9px rgba(204, 204, 204, 0.5)',
- backgroundColor: 'rgba(255, 255, 255, 0.95)',
- backdropFilter: 'blur(10px)',
- transition: 'opacity 0.3s ease, transform 0.3s ease'
- });
-
- if (isLandscape) {
- panel.style.width = '320px';
- panel.style.maxHeight = '60%';
- } else {
- panel.style.width = '100%';
- panel.style.height = '100%';
- }
- const contentArea = this.createContentArea()
- // 组装面板
- panel.appendChild(this.createTitleBar());
- panel.appendChild(contentArea);
-
- setTimeout(() => {
- document.body.appendChild(panel);
- // 触发创建回调
- if (window.pugeCreated) {
- window.pugeCreated(contentArea);
- window.pugeCreated = null;
- }
- }, 1000);
-
-
- }, 1000);
- }
- // 星星图标SVG
- get starIconSVG() {
- return `<svg class="puge-star-icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" width="40" height="40">
- <path d="M622.7968 89.7024l60.1088 124.1088c15.9744 36.0448 52.0192 60.1088 92.16 66.048l134.144 20.0704c100.1472 14.0288 138.1376 136.192 68.096 208.2816l-98.0992 94.1056c-28.0576 28.0576-42.0864 68.096-36.0448 106.0864l22.016 134.144c15.9744 100.1472-86.1184 174.1824-176.2304 128.2048l-120.1152-62.0544c-36.0448-18.0224-76.0832-18.0224-112.128 0L334.4384 972.8c-90.112 46.08-192.2048-28.0576-176.2304-128.2048l22.016-134.144c7.9872-40.0384-6.0416-80.0768-36.0448-106.0864L46.08 508.2112c-72.0896-72.0896-32.0512-192.2048 68.096-208.2816l134.144-20.0704c40.0384-6.0416 74.1376-30.0032 92.16-66.048l60.1088-124.1088c50.0736-90.112 176.2304-90.112 222.208 0" fill="#FED44A"></path>
- <path d="M404.5824 89.7024l-60.1088 124.1088c-15.9744 36.0448-52.0192 60.1088-92.16 66.048l-134.144 20.0704c-62.0544 10.0352-102.0928 60.1088-104.1408 112.128 18.0224-98.0992 220.2624-22.016 312.4224-14.0288 94.1056 10.0352 120.1152-74.1376 120.1152-74.1376s20.0704-100.1472 44.032-226.304c18.0224-102.0928 86.1184-58.0608 110.1824-40.0384C544.768-0.4096 444.6208 11.6736 404.5824 89.7024" fill="#FFDE73"></path>
- <path d="M574.7712 784.5888c-74.1376-50.0736-140.1856 0-140.1856 0S362.496 848.6912 278.4256 928.768c-86.1184 80.0768-118.1696-33.9968-118.1696-33.9968 18.0224 72.0896 102.0928 116.1216 174.1824 76.0832l122.1632-62.0544c36.0448-18.0224 76.0832-18.0224 112.128 0L690.8928 972.8c56.1152 30.0032 118.1696 11.9808 152.1664-32.0512 2.048-7.9872 3.9936-14.0288 7.9872-20.0704-67.9936 66.1504-200.192-86.016-276.2752-136.0896" fill="#FEC54A"></path>
- <path d="M466.6368 103.7312c15.9744 3.9936 26.0096 18.0224 22.016 36.0448l-28.0576 126.1568c-3.9936 15.9744-18.0224 26.0096-36.0448 22.016-15.9744-3.9936-26.0096-18.0224-22.016-36.0448l28.0576-128.2048c3.9936-15.9744 20.0704-23.9616 36.0448-19.968" fill="#FFF2CA"></path>
- <path d="M375.3984 530.8416c-29.2864 0-53.0432-18.7392-53.0432-41.984 0-23.1424 23.7568-41.984 53.0432-41.984s53.0432 18.7392 53.0432 41.984c0 23.1424-23.7568 41.984-53.0432 41.984z m260.9152 0c-29.2864 0-53.0432-18.7392-53.0432-41.984 0-23.1424 23.7568-41.984 53.0432-41.984s53.0432 18.7392 53.0432 41.984c0 23.1424-23.7568 41.984-53.0432 41.984z m-190.464 74.6496c-2.56-3.6864-3.3792-8.192-2.56-12.4928 0.9216-4.3008 3.584-8.0896 7.2704-10.4448 7.8848-5.12 18.432-3.072 23.8592 4.608 12.288 17.7152 26.2144 25.8048 43.1104 25.8048s30.8224-8.0896 43.1104-25.8048c5.4272-7.68 15.9744-9.728 23.8592-4.608 3.7888 2.3552 6.4512 6.144 7.2704 10.4448 0.9216 4.3008 0 8.9088-2.56 12.4928-18.3296 26.5216-42.7008 40.6528-71.7824 40.6528-28.8768-0.1024-53.248-14.1312-71.5776-40.6528z" fill="#92410E"></path>
- </svg>`;
- }
- // 创建触发按钮
- createTriggerButton() {
- if (document.querySelector('.puge-menu')) return;
-
- const triggerBtn = document.createElement('div');
- triggerBtn.className = 'puge-menu puge-trigger-btn';
- triggerBtn.setAttribute('aria-label', '打开功能面板');
- triggerBtn.setAttribute('role', 'button');
- triggerBtn.tabIndex = 0;
-
- Object.assign(triggerBtn.style, {
- position: 'fixed',
- width: '40px',
- height: '40px',
- right: '10px',
- bottom: '120px',
- zIndex: '9666',
- cursor: 'pointer',
- transition: 'transform 0.3s ease'
- });
-
- triggerBtn.innerHTML = this.starIconSVG;
-
- // 添加点击事件
- triggerBtn.addEventListener('click', () => this.togglePanel(true));
- triggerBtn.addEventListener('keydown', (e) => {
- if (e.key === 'Enter' || e.key === ' ') {
- e.preventDefault();
- this.togglePanel(true);
- }
- });
-
- // 添加悬停效果
- triggerBtn.addEventListener('mouseenter', () => {
- triggerBtn.style.transform = 'scale(1.1)';
- });
- triggerBtn.addEventListener('mouseleave', () => {
- triggerBtn.style.transform = 'scale(1)';
- });
-
- setTimeout(() => {
- document.body.appendChild(triggerBtn);
- }, 1000);
- }
- // 切换面板显示/隐藏
- togglePanel(show) {
- const panel = document.querySelector('.start-box');
- const triggerBtn = document.querySelector('.puge-menu');
-
- if (!panel) return;
-
- const shouldShow = show ?? panel.style.display === 'none';
-
- if (shouldShow) {
- panel.style.display = 'block';
- panel.setAttribute('aria-hidden', 'false');
- panel.style.opacity = '0';
- panel.style.transform = 'translateY(20px)';
-
- // 动画显示
- requestAnimationFrame(() => {
- panel.style.opacity = '1';
- panel.style.transform = 'translateY(0)';
- });
-
- if (triggerBtn) {
- triggerBtn.style.display = 'none';
- }
-
- // 触发回调
- if (window.pugeCreated) {
- window.pugeCreated(panel.querySelector('.puge-content-area'));
- window.pugeCreated = null;
- }
- } else {
- panel.style.opacity = '0';
- panel.style.transform = 'translateY(20px)';
-
- setTimeout(() => {
- panel.style.display = 'none';
- panel.setAttribute('aria-hidden', 'true');
-
- if (triggerBtn) {
- triggerBtn.style.display = 'block';
- triggerBtn.style.opacity = '0';
- triggerBtn.style.transform = 'scale(0.8)';
-
- requestAnimationFrame(() => {
- triggerBtn.style.opacity = '1';
- triggerBtn.style.transform = 'scale(1)';
- });
- }
- }, 300);
- }
- }
- // 全局方法挂载
- static mountGlobalMethods() {
- window.owostart = () => {
- const instance = window.pugePanelInstance;
- if (instance) instance.togglePanel();
- };
-
- window.loadingDialog = () => {
- // 保留原接口,空实现
- return;
- };
-
- window.alertDialog = (text) => {
- if (window.logBox && window.logBox.add) {
- window.logBox.add(text);
- } else {
- console.log('Alert:', text);
- }
- };
- }
- }
- // 创建样式(可以移到CSS文件中)
- function addStyles() {
- const style = document.createElement('style');
- style.textContent = `
- .puge-title-bar {
- position: relative;
- height: 40px;
- line-height: 40px;
- background: linear-gradient(135deg, #f5f5f5 0%, #e8e8e8 100%);
- border-bottom: 1px solid #e0e0e0;
- padding: 0 15px;
- font-weight: 600;
- font-size: 16px;
- color: #333;
- user-select: none;
- display: flex;
- justify-content: space-between;
- align-items: center;
- }
-
- .puge-title {
- font-size: 16px;
- color: #333;
- }
-
- .puge-close-btn {
- width: 30px;
- height: 40px;
- line-height: 40px;
- text-align: center;
- font-size: 24px;
- color: #666;
- cursor: pointer;
- transition: color 0.3s ease, transform 0.2s ease;
- border-radius: 4px;
- }
-
- .puge-close-btn:hover {
- color: #ff4444;
- transform: scale(1.1);
- }
-
- .puge-close-btn:active {
- transform: scale(0.95);
- }
-
- .puge-box {
- padding: 0 10px;
- overflow: auto;
- box-sizing: border-box;
- background-color: #fff;
- }
-
- .puge-trigger-btn {
- display: flex;
- align-items: center;
- justify-content: center;
- transition: all 0.3s ease !important;
- }
-
- .puge-star-icon {
- display: block;
- filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.1));
- }
- .puge-login-box, .puge-box.puge-content-area {
- position: relative;
- padding-bottom: 10px;
- }
- @media (prefers-reduced-motion: reduce) {
- .puge-panel,
- .puge-trigger-btn,
- .puge-close-btn {
- transition: none !important;
- }
- }
- `;
- (document.head || document.documentElement).appendChild(style);
- }
- // 初始化
- (function() {
- // 防止重复初始化
- if (window.pugePanelInstance) return;
-
- // 添加样式
- addStyles();
-
- // 创建实例
- window.pugePanelInstance = new PugePanel();
-
- // 挂载全局方法
- PugePanel.mountGlobalMethods();
- })();
|