fix: 移除遗留fmfuncs目录创建 + 清理init_service无用导入 + 文件管理器SVG图标 + 示例插件MD3改造

- init_service: 删除_load_fmfuncs方法和fmfuncs目录创建(已迁移到sdk/)
- init_service: 清理未使用的importlib.util和sys导入
- 文件管理器: 全部emoji替换为MD3 SVG矢量图标(文件夹/文件类型/右键菜单)
- 示例插件: dashboard.html改为MD3风格 CSS变量自动适配日夜主题
- 面包屑: 加底色+模糊+左右外边距
- CSS: .btn::after加pointer-events:none
- 插件开发指南: 更新2.6节MD3主题同步和完善的CSS变量/组件类参考表

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
qinglong
2026-06-12 19:00:19 +08:00
parent 9b997d8bda
commit 9de094ea54
16 changed files with 283 additions and 308 deletions
+78 -26
View File
@@ -154,8 +154,12 @@ async function loadPluginPage(pluginName) {
var scripts = [];
clean = clean.replace(/<script\b[^>]*>([\s\S]*?)<\/script>/gi, function(m,code){ scripts.push(code.trim()); return ''; });
// Scope plugin styles: replace body selector with .plugin-page-root to avoid
// styling the main page's <body> element
styles = styles.replace(/body\s*\{/gi, '.plugin-page-root{').replace(/body\b/gi, '.plugin-page-root');
content.style.padding = '0';
content.innerHTML = '<style>'+styles+'</style>'+clean;
content.innerHTML = '<div class="plugin-page-root"><style>'+styles+'</style>'+clean+'</div>';
scripts.forEach(function(code){
try { var s=document.createElement('script'); s.textContent=code; document.head.appendChild(s); document.head.removeChild(s); }
@@ -172,51 +176,99 @@ async function loadPluginPage(pluginName) {
}
// ═══ Global file/dir picker (in-page iframe modal) ═══
// ═══ Global file/dir picker (in-page overlay, no iframe) ═══
window.pickPath = function(mode, callback) {
var id = 'picker_' + Date.now();
var url = './static/pages/files.html?picker=1&mode=' + (mode || 'dir') + '&cb=' + id;
// Create modal overlay
var overlay = document.createElement('div');
overlay.id = 'fm-picker-overlay';
overlay.style.cssText = 'position:fixed;inset:0;z-index:500;background:rgba(0,0,0,.5);display:flex;align-items:center;justify-content:center';
overlay.onclick = function(e) { if (e.target === overlay) closePicker(); };
var box = document.createElement('div');
box.style.cssText = 'background:var(--md-sys-color-surface-container-high);border-radius:var(--shape-lg);width:720px;height:520px;max-width:95vw;max-height:85vh;display:flex;flex-direction:column;overflow:hidden;box-shadow:var(--md-sys-elevation-5)';
// Header
// Header with close button
var header = document.createElement('div');
header.style.cssText = 'display:flex;justify-content:space-between;align-items:center;padding:12px 16px;border-bottom:1px solid var(--outline);flex-shrink:0';
header.innerHTML = '<span style="font-weight:500;color:var(--primary)">📂 选择' + (mode==='file'?'文件':'目录') + '</span>' +
'<button class="btn btn-sm btn-outlined" onclick="closePicker()" style="font-size:16px;line-height:1">✕</button>';
var headerTitle = document.createElement('span');
headerTitle.style.cssText = 'font-weight:500;color:var(--primary)';
headerTitle.textContent = '📂 选择' + (mode==='file'?'文件':'目录');
header.appendChild(headerTitle);
var closeBtn = document.createElement('span');
closeBtn.style.cssText = 'cursor:pointer;font-size:20px;line-height:1;padding:4px 8px;border-radius:4px;color:var(--text-dim)';
closeBtn.textContent = '✕';
closeBtn.onclick = function(){ closePicker(); };
header.appendChild(closeBtn);
box.appendChild(header);
// Iframe
var iframe = document.createElement('iframe');
iframe.src = url;
iframe.style.cssText = 'flex:1;border:none;width:100%';
box.appendChild(iframe);
// Content area — load file manager via fetch
var contentArea = document.createElement('div');
contentArea.style.cssText = 'flex:1;overflow:hidden;display:flex;flex-direction:column';
box.appendChild(contentArea);
overlay.appendChild(box);
document.body.appendChild(overlay);
function closePicker() {
window.removeEventListener('message', handler);
if (overlay.parentNode) overlay.parentNode.removeChild(overlay);
}
window._closePicker = closePicker;
// Close on backdrop click
overlay.addEventListener('click', function(e){ if(e.target===overlay) closePicker(); });
// Listen for pick result from iframe
window.addEventListener('message', function handler(e) {
try {
var d = JSON.parse(e.data);
if (d.action === 'fm-picked' && d.callback_id === id) {
closePicker();
if (d.path && callback) callback(d.path);
function closePicker() {
if(overlay.parentNode) overlay.parentNode.removeChild(overlay);
}
// Load file manager HTML into content area
fetch('./static/pages/files.html?t=' + Date.now())
.then(function(r){ return r.text(); })
.then(function(html){
// Strip meta and CSS link (already available in main page)
html = html.replace(/<meta[^>]*>/gi, '').replace(/<link[^>]*>/gi, '');
// Extract inline scripts
var scripts = [];
var clean = html.replace(/<script\b[^>]*>([\s\S]*?)<\/script>/gi, function(m,code){ scripts.push(code.trim()); return ''; });
contentArea.innerHTML = clean;
// Execute scripts
scripts.forEach(function(code){
try { var s=document.createElement('script'); s.textContent=code; document.head.appendChild(s); document.head.removeChild(s); }
catch(ex){}
});
// Load files.js if not already loaded
// Fix container height for overlay
var fmContainer = contentArea.querySelector('.fm-container');
if(fmContainer) fmContainer.style.height = '100%';
function doInit(){
window.FilesModule._apiBase = '';
window.FilesModule.currentPath = '';
window.FilesModule.pickerMode = mode || 'dir';
window.FilesModule.pickerCallback = id;
window.FilesModule._scope = contentArea;
window.FilesModule._getEl = function(sel){ return contentArea.querySelector(sel); };
// Override _pickResult to close overlay instead of alert
window.FilesModule._pickResult = function(path){
closePicker();
if(callback) callback(path || window.FilesModule.currentPath || '/');
};
if(window.FilesModule.destroy) window.FilesModule.destroy();
if(window.FilesModule.init) window.FilesModule.init();
}
} catch(ex) {}
});
// Override picker actions to close overlay and call callback
window._fmPick = function(){
var p = window.FilesModule && window.FilesModule.currentPath || '/';
closePicker();
if(callback) callback(p);
};
window._fmCancel = function(){ closePicker(); };
if(window.FilesModule){ doInit(); }
else {
var s=document.createElement('script');
s.src='./static/pages/files.js?v=0603';
s.onload=doInit;
document.head.appendChild(s);
}
})
.catch(function(e){
contentArea.innerHTML = '<div style="color:var(--error);padding:40px;text-align:center">加载失败: '+e.message+'</div>';
});
};
// ═══ Sidebar toggle ═══