MediaWiki:Common.js:修订间差异
添加虾仁AI浮窗助手组件 |
v3.1 修正 Minerva 抽屉挂载点 |
||
| (未显示2个用户的3个中间版本) | |||
| 第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; | ||
| 第321行: | 第363行: | ||
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'); | ||
| 第358行: | 第401行: | ||
'<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>' + | ||
| 第388行: | 第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(); } | |||
}); | }); | ||
}); | }); | ||