MediaWiki:Common.js:修订间差异
添加虾仁AI浮窗助手组件 |
v3.1 修正 Minerva 抽屉挂载点 |
||
| (未显示4个用户的10个中间版本) | |||
| 第1行: | 第1行: | ||
/* 虾仁维基 - 自定义侧边栏导航 | /* 虾仁维基 - 自定义侧边栏导航 v3.0 */ | ||
/* | /* 优化:古风主题统一、健壮初始化、精致样式、移动端(Minerva)适配 */ | ||
/* 最后更新: 2026-07-30 */ | /* 最后更新: 2026-07-30 */ | ||
| 第16行: | 第16行: | ||
return; | return; | ||
} | } | ||
var skin = mw.config.get('skin'); | |||
var isMobile = (skin === 'minerva' || skin === 'minerva-vec'); | |||
mw.loader.using('mediawiki.api').then(function () { | mw.loader.using('mediawiki.api').then(function () { | ||
waitForPanel(function ($panel) { | if (isMobile) { | ||
waitForMobileDrawer(function ($host) { | |||
buildNav($host, true); | |||
}); | |||
} else { | |||
waitForPanel(function ($panel) { | |||
buildNav($panel, false); | |||
}); | |||
} | |||
}).catch(function (e) { | }).catch(function (e) { | ||
console.error('[虾仁导航] 依赖加载失败,降级构建', e); | console.error('[虾仁导航] 依赖加载失败,降级构建', e); | ||
waitForPanel(function ($panel) { | if (isMobile) { | ||
waitForMobileDrawer(function ($host) { | |||
buildNav($host, true); | |||
}); | |||
} else { | |||
waitForPanel(function ($panel) { | |||
buildNav($panel, false); | |||
}); | |||
} | |||
}); | }); | ||
} | } | ||
| 第41行: | 第55行: | ||
} | } | ||
function buildNav($panel) { | /* | ||
* Minerva 抽屉真实结构: | |||
* <nav class="navigation-drawer toggle-list"> | |||
* <input id="main-menu-input" class="toggle-list__checkbox"> <- checkbox hack 开关 | |||
* <label for="main-menu-input"> <- 汉堡按钮 | |||
* <div id="mw-mf-page-left" class="menu"> <- 抽屉内容, 由 #main-menu-input:checked ~ 控制显隐 | |||
* 必须挂到 #mw-mf-page-left 内部; 若挂到外层 <nav>, 内容会插在 checkbox 之前, | |||
* 脱离 checkbox hack 的兄弟选择器控制, 变成常驻页头, 破坏 header 布局。 | |||
*/ | |||
function waitForMobileDrawer(cb) { | |||
var tries = 0; | |||
function tryFind() { | |||
var $host = $('#mw-mf-page-left'); | |||
if (!$host.length) $host = $('.navigation-drawer .menu'); | |||
if (!$host.length) $host = $('.navigation-drawer #p-navigation').parent(); | |||
if ($host.length) return cb($host.first()); | |||
if (++tries > 60) return; | |||
setTimeout(tryFind, 100); | |||
} | |||
tryFind(); | |||
} | |||
function buildNav($panel, isMobile) { | |||
var html = ''; | var html = ''; | ||
| 第96行: | 第132行: | ||
html += '<div class="xn-single"><a href="' + url('共创入口') + '">共创入口</a></div>'; | html += '<div class="xn-single"><a href="' + url('共创入口') + '">共创入口</a></div>'; | ||
$panel.html(html); | if (isMobile) { | ||
var $box = $('<section class="xn-mobile"></section>'); | |||
$box.html(html); | |||
$panel.prepend($box); | |||
} else { | |||
$panel.html(html); | |||
} | |||
restoreCollapse(); | restoreCollapse(); | ||
bindEvents(); | bindEvents(); | ||
| 第229行: | 第271行: | ||
function highlightCurrent() { | function highlightCurrent() { | ||
var currentTitle = mw.config.get('wgPageName'); | var currentTitle = mw.config.get('wgPageName'); | ||
$(' | $('.xn-link a').each(function () { | ||
var href = $(this).attr('href'); | var href = $(this).attr('href'); | ||
if (!href) return; | if (!href) return; | ||
| 第309行: | 第351行: | ||
})(jQuery, mediaWiki); | })(jQuery, mediaWiki); | ||
/* ===== 虾仁AI 浮窗助手(2026-07- | /* ===== 虾仁AI 浮窗助手(2026-07-30 v2) ===== */ | ||
(function () { | (function () { | ||
if (window.__xrAiInited) return; | if (window.__xrAiInited) return; | ||
window.__xrAiInited = true; | window.__xrAiInited = true; | ||
function xrAvatar(size) { | |||
return '<svg viewBox="0 0 48 48" width="' + size + '" height="' + size + '" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><ellipse cx="24" cy="14.5" rx="18" ry="5.5" fill="#caa53d"/><ellipse cx="24" cy="14.5" rx="18" ry="5.5" fill="none" stroke="#a8842a" stroke-width="0.8"/><path d="M13 14.5 Q24 2.5 35 14.5 Z" fill="#d9b84a"/><path d="M13 14.5 Q24 2.5 35 14.5 Z" fill="none" stroke="#a8842a" stroke-width="0.8"/><circle cx="12.5" cy="25" r="6.5" fill="#2c2c2c"/><circle cx="35.5" cy="25" r="6.5" fill="#2c2c2c"/><circle cx="24" cy="29" r="15" fill="#fdfdfd" stroke="#e9e2d2" stroke-width="0.8"/><ellipse cx="18" cy="28" rx="4.5" ry="5.6" fill="#2c2c2c"/><ellipse cx="30" cy="28" rx="4.5" ry="5.6" fill="#2c2c2c"/><circle cx="18" cy="28" r="1.9" fill="#fff"/><circle cx="30" cy="28" r="1.9" fill="#fff"/><ellipse cx="24" cy="33" rx="2.1" ry="1.5" fill="#2c2c2c"/><path d="M20.5 36 Q24 38.5 27.5 36" stroke="#2c2c2c" stroke-width="1.3" fill="none" stroke-linecap="round"/><circle cx="15" cy="33" r="2" fill="#c41e3a" opacity="0.18"/><circle cx="33" cy="33" r="2" fill="#c41e3a" opacity="0.18"/></svg>'; | |||
} | |||
function init() { | function init() { | ||
var API = '/ai_proxy.php'; | var API = '/ai_proxy.php'; | ||
var TITLE = '虾仁AI'; | var TITLE = '虾仁AI'; | ||
var AUDIT_TEMPLATE = '作品名:\n1. 视觉识别(主角是否为草帽熊猫头或明显变体):\n2. 听觉识别(是否使用虾仁系列标志性AI配音):\n3. 主角身份(是否虾仁人格内核的投射,名字可不同):\n4. 完整性(有无完整结局):\n5. 深度(有无情感内核/名场面):\n6. 原创性(虾仁原生或深度改编):\n7. 自述与作品链接:\n'; | |||
var css = document.createElement('style'); | var css = document.createElement('style'); | ||
css.textContent = [ | css.textContent = [ | ||
'#xr-ai-fab{position:fixed;right:22px;bottom:22px;z-index:99999;width:56px;height:56px;border-radius:50%;border:none;cursor:pointer;background:linear-gradient(135deg,#c41e3a,#9b182d);color:#fff;font-size:26px;box-shadow:0 6px 20px rgba(155,24,45,.4);transition:transform .2s ease,box-shadow .2s ease;font-family:"Noto Serif SC","Songti SC",serif}', | '#xr-ai-fab{position:fixed;right:22px;bottom:22px;z-index:99999;width:56px;height:56px;border-radius:50%;border:none;display:flex;align-items:center;justify-content:center;cursor:pointer;background:linear-gradient(135deg,#c41e3a,#9b182d);color:#fff;font-size:26px;box-shadow:0 6px 20px rgba(155,24,45,.4);transition:transform .2s ease,box-shadow .2s ease;font-family:"Noto Serif SC","Songti SC",serif}', | ||
'#xr-ai-fab:hover{transform:scale(1.08);box-shadow:0 8px 26px rgba(155,24,45,.55)}', | '#xr-ai-fab:hover{transform:scale(1.08);box-shadow:0 8px 26px rgba(155,24,45,.55)}', | ||
'#xr-ai-panel{position:fixed;right:22px;bottom:90px;z-index:99999;width:360px;max-width:calc(100vw - 32px);height:520px;max-height:calc(100vh - 120px);display:none;flex-direction:column;overflow:hidden;background:#fbf6ec;border:1px solid #e7d8bf;border-radius:14px;box-shadow:0 12px 40px rgba(80,40,30,.25);font-family:"Noto Serif SC","Source Han Serif SC","Songti SC","STSong","SimSun",serif;color:#3a2418}', | '#xr-ai-panel{position:fixed;right:22px;bottom:90px;z-index:99999;width:360px;max-width:calc(100vw - 32px);height:520px;max-height:calc(100vh - 120px);display:none;flex-direction:column;overflow:hidden;background:#fbf6ec;border:1px solid #e7d8bf;border-radius:14px;box-shadow:0 12px 40px rgba(80,40,30,.25);font-family:"Noto Serif SC","Source Han Serif SC","Songti SC","STSong","SimSun",serif;color:#3a2418}', | ||
'#xr-ai-panel.xr-show{display:flex}', | '#xr-ai-panel.xr-show{display:flex}', | ||
'.xr-ai-head{display:flex;align-items:center;justify-content:space-between;padding:12px 14px;background:linear-gradient(135deg,#c41e3a,#9b182d);color:#fff}', | '.xr-ai-head{display:flex;align-items:center;justify-content:space-between;padding:12px 14px;background:linear-gradient(135deg,#c41e3a,#9b182d);color:#fff}', | ||
'.xr-ai-title{font-weight:700;font-size:16px;letter-spacing:.05em}', | '.xr-ai-title{font-weight:700;font-size:16px;letter-spacing:.05em;display:flex;align-items:center;gap:6px}', | ||
'.xr-ai-close{background:none;border:none;color:#fff;font-size:20px;cursor:pointer;line-height:1}', | '.xr-ai-close{background:none;border:none;color:#fff;font-size:20px;cursor:pointer;line-height:1}', | ||
'.xr-ai-tabs{display:flex;border-bottom:1px solid #ecdfc8;background:#f3e9d6}', | '.xr-ai-tabs{display:flex;border-bottom:1px solid #ecdfc8;background:#f3e9d6}', | ||
| 第345行: | 第392行: | ||
var fab = document.createElement('button'); | var fab = document.createElement('button'); | ||
fab.id = 'xr-ai-fab'; fab.innerHTML = | fab.id = 'xr-ai-fab'; fab.innerHTML = xrAvatar(38); fab.title = TITLE; fab.setAttribute('aria-label', TITLE); | ||
var panel = document.createElement('div'); | var panel = document.createElement('div'); | ||
panel.id = 'xr-ai-panel'; | panel.id = 'xr-ai-panel'; | ||
panel.innerHTML = | panel.innerHTML = | ||
'<div class="xr-ai-head"><span class="xr-ai-title"> | '<div class="xr-ai-head"><span class="xr-ai-title">' + xrAvatar(22) + ' ' + TITLE + '</span>' + | ||
'<button class="xr-ai-close" title="收起">×</button></div>' + | '<button class="xr-ai-close" title="收起">×</button></div>' + | ||
'<div class="xr-ai-tabs">' + | '<div class="xr-ai-tabs">' + | ||
'<button class="xr-ai-tab xr-active" data-mode="general">闲聊</button>' + | '<button class="xr-ai-tab xr-active" data-mode="general">闲聊</button>' + | ||
'<button class="xr-ai-tab" data-mode="wiki">问虾仁宇宙</button></div>' + | '<button class="xr-ai-tab" data-mode="wiki">问虾仁宇宙</button>' + | ||
'<button class="xr-ai-tab" data-mode="audit">作品审核</button></div>' + | |||
'<div class="xr-ai-hint">内容由 AI 生成,仅供参考</div>' + | '<div class="xr-ai-hint">内容由 AI 生成,仅供参考</div>' + | ||
'<div class="xr-ai-msgs"></div>' + | '<div class="xr-ai-msgs"></div>' + | ||
| 第384行: | 第432行: | ||
t.classList.add('xr-active'); | t.classList.add('xr-active'); | ||
mode = t.getAttribute('data-mode'); | mode = t.getAttribute('data-mode'); | ||
if (mode === 'audit' && !inputEl.value.trim()) { inputEl.value = AUDIT_TEMPLATE; inputEl.focus(); } | |||
}); | }); | ||
}); | }); | ||
| 第457行: | 第506行: | ||
}); | }); | ||
addBubble('xr-ai', ' | addBubble('xr-ai', '你好,我是虾仁AI,可以陪你闲聊,也能帮你查「虾仁宇宙」的资料。选个模式开始吧~'); | ||
} | } | ||