feat: 文件管理器 + Windows兼容 + SVG主题适配 (v0.6.0)
新增: - services/web_panel/routes/files.py — 全功能文件管理后端API (11个端点) - pages/files.html + files.js — 文件管理前端 (浏览/编辑/上传/删除/右键菜单) - 插件Picker API: window.open+postMessage唤出文件选择器 - 符号链接目录双层面包屑 (逻辑路径+物理路径) - 文件系统全访问+跨平台 (Linux/Windows/macOS) - permission_rules.yaml新增4个filemanager.*权限 修复: - SVG fill=currentColor 日夜模式自适应 - 特殊目录容错 (/dev/fd损坏符号链接/proc) - 面包屑每层级独立可点击+可编辑路径跳转 - ..行返回上级+data-is-dir补全 - rmlint→lstat回退 损坏符号链接不炸页面 文档: - 插件开发指南新增第八章(文件管理器集成) - 开发踩坑记录新增4条(特殊目录/双面包屑/SVG颜色/Windows) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -64,6 +64,7 @@
|
||||
|
||||
/* ── Reset ── */
|
||||
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
|
||||
svg{fill:currentColor}
|
||||
body{
|
||||
background:var(--bg);color:var(--text);
|
||||
font-family:"Google Sans",system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;
|
||||
@@ -189,7 +190,7 @@ h3{font-size:1rem;font-weight:500;letter-spacing:.15px}
|
||||
.nav-item:hover{background:rgba(208,188,255,.08);color:var(--text)}
|
||||
.nav-item.active{background:var(--primary-container);color:var(--md-sys-color-on-primary-container)}
|
||||
.nav-item .nav-icon{width:24px;height:24px;flex-shrink:0;display:flex;align-items:center;justify-content:center}
|
||||
.nav-item svg{width:20px;height:20px;flex-shrink:0}
|
||||
.nav-item svg{width:20px;height:20px;flex-shrink:0;fill:currentColor}
|
||||
.nav-item .nav-label{overflow:hidden;text-overflow:ellipsis}
|
||||
.toggle-sidebar{
|
||||
margin-top:auto;padding:16px;text-align:center;cursor:pointer;
|
||||
@@ -426,3 +427,56 @@ h3{font-size:1rem;font-weight:500;letter-spacing:.15px}
|
||||
|
||||
/* ── Menu reveal animation for login error ── */
|
||||
.err-msg{transition:opacity .3s}
|
||||
|
||||
/* ═══════════════════════════════════════════
|
||||
File Manager
|
||||
═══════════════════════════════════════════ */
|
||||
.fm-container{display:flex;flex-direction:column;height:calc(100vh - var(--topbar-h) - 48px);gap:12px}
|
||||
.fm-toolbar{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:8px}
|
||||
.fm-path-bar{flex:1;min-width:0;display:flex;flex-direction:column;gap:4px}
|
||||
.fm-path-input{width:100%;padding:8px 12px;background:var(--md-sys-color-surface-container-lowest);border:1px solid var(--outline);border-radius:var(--shape-xs);color:var(--text);font-family:"JetBrains Mono",monospace;font-size:12px;outline:none;transition:border-color .2s}
|
||||
.fm-path-input:focus{border-color:var(--primary);box-shadow:0 0 0 2px rgba(208,188,255,.15)}
|
||||
.fm-breadcrumb{display:flex;align-items:center;flex-wrap:wrap;gap:4px;overflow-x:auto;scrollbar-width:none;flex:1;min-width:0}
|
||||
.fm-breadcrumb::-webkit-scrollbar{display:none}
|
||||
.fm-crumb{white-space:nowrap;padding:4px 10px;border-radius:var(--shape-full);cursor:pointer;font-size:.82rem;color:var(--text-dim);transition:.15s}
|
||||
.fm-crumb:hover{background:rgba(208,188,255,.1);color:var(--primary)}
|
||||
.fm-crumb-sep{color:var(--outline);font-size:.7rem;flex-shrink:0}
|
||||
.fm-resolved-crumbs{display:flex;align-items:center;gap:4px;font-size:.75rem;opacity:.8;flex-basis:100%}
|
||||
.fm-actions{display:flex;gap:6px;flex-shrink:0;align-items:center}
|
||||
.fm-toggle{display:flex;align-items:center;gap:4px;font-size:.75rem;color:var(--text-dim);cursor:pointer}
|
||||
.fm-toggle input{margin:0}
|
||||
.fm-list{flex:1;overflow-y:auto;scrollbar-width:thin;scrollbar-color:var(--outline) transparent}
|
||||
.fm-row{display:grid;grid-template-columns:32px 1fr 100px 140px;align-items:center;padding:10px 12px;cursor:pointer;border-radius:var(--shape-xs);transition:background .12s;gap:8px;font-size:.88rem}
|
||||
.fm-row:hover{background:rgba(208,188,255,.06)}
|
||||
.fm-row.fm-dir{font-weight:500}
|
||||
.fm-row.fm-parent{border-bottom:1px solid var(--outline);margin-bottom:2px;font-weight:600}
|
||||
.fm-icon{font-size:1.2rem;text-align:center}
|
||||
.fm-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
||||
.fm-size{text-align:right;color:var(--text-dim);font-size:.8rem;font-variant-numeric:tabular-nums}
|
||||
.fm-date{text-align:right;color:var(--text-dim);font-size:.78rem}
|
||||
|
||||
/* Editor overlay */
|
||||
.fm-editor-overlay{position:fixed;inset:0;z-index:200;display:flex;flex-direction:column;background:var(--md-sys-color-surface-container-high)}
|
||||
.fm-editor-header{display:flex;justify-content:space-between;align-items:center;padding:12px 20px;border-bottom:1px solid var(--outline);background:var(--bg-card)}
|
||||
.fm-editor-header span{font-weight:500;color:var(--primary)}
|
||||
.fm-editor-header div{display:flex;gap:8px}
|
||||
.fm-editor-overlay textarea{flex:1;padding:16px 20px;background:var(--md-sys-color-surface-container-lowest);color:var(--text);border:none;outline:none;resize:none;font-family:"JetBrains Mono","Fira Code",monospace;font-size:13px;line-height:1.6;tab-size:4}
|
||||
|
||||
/* Dialog overlay */
|
||||
.fm-dialog-overlay{position:fixed;inset:0;z-index:300;display:flex;align-items:center;justify-content:center;background:rgba(0,0,0,.5)}
|
||||
.fm-dialog{background:var(--md-sys-color-surface-container-high);border-radius:var(--shape-md);padding:24px;min-width:320px;max-width:450px;box-shadow:var(--md-sys-elevation-4)}
|
||||
|
||||
/* Context menu */
|
||||
.fm-context{position:fixed;z-index:250;background:var(--md-sys-color-surface-container-high);border-radius:var(--shape-xs);box-shadow:var(--md-sys-elevation-3);min-width:160px;padding:4px 0;overflow:hidden}
|
||||
.fm-context-item{padding:8px 16px;cursor:pointer;font-size:.82rem;color:var(--text);transition:background .12s}
|
||||
.fm-context-item:hover{background:rgba(208,188,255,.1)}
|
||||
.fm-context-item.danger{color:var(--error)}
|
||||
.fm-context-item.danger:hover{background:rgba(242,184,181,.1)}
|
||||
.fm-context-sep{height:1px;background:var(--outline);margin:4px 0}
|
||||
|
||||
/* Responsive */
|
||||
@media(max-width:768px){
|
||||
.fm-row{grid-template-columns:28px 1fr 70px}
|
||||
.fm-date{display:none}
|
||||
.fm-actions{flex-wrap:wrap}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user