feat: 项目 logo + 侧栏拖动排序 + 合并修复(主检出干净时 in-place)

- 项目 logo:仓库内文件(logo/icon/favicon 等多路径)→git remote 头像→自定义(URL/相对路径)→
  首字母徽章兜底;GET /api/projects/:id/logo(文件流/302),配置面板加 Logo 输入
- 侧栏项目拖动排序:projects.sort_order + POST /api/projects/reorder,乐观更新
- 合并修复:默认分支正被主检出占用时,若工作区干净则直接在主检出 in-place 合并
  (用户手动合并的等价操作,安全);脏工作区拒绝并提示提交/暂存或仅通过
- schema: projects.logo / sort_order(ensureColumn 平滑迁移)

测试 75/75(merge 用例改为干净→成功/脏→拒绝)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
wangjia
2026-06-13 03:45:24 +08:00
parent 740d2c2637
commit bb6186902a
12 changed files with 290 additions and 31 deletions
+23 -2
View File
@@ -119,10 +119,10 @@ body::before {
/* ── 项目列表 ─────────────────────────────────────────────── */
.project-list { list-style: none; flex: 1; }
.project-list li {
padding: 9px 16px 9px 14px;
padding: 8px 16px 8px 12px;
border-left: 2px solid transparent;
cursor: pointer;
display: flex; flex-direction: column; gap: 1px;
display: flex; align-items: center; gap: 9px;
}
.project-list li:hover { background: var(--panel); }
.project-list li.active {
@@ -130,8 +130,25 @@ body::before {
border-left-color: var(--green);
}
.project-list li.active .p-name { color: var(--green); }
.project-list li.dragging { opacity: .4; }
.project-list li.drop-over { box-shadow: inset 0 2px 0 var(--green); }
.p-meta { display: flex; flex-direction: column; gap: 1px; min-width: 0; flex: 1; }
.p-name { font-weight: 600; font-size: 13px; }
.p-path { font-size: 10.5px; color: var(--faint); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* 项目 logo:图片优先,加载失败 onerror 移除自身 → 露出首字母徽章 */
.p-logo-wrap { position: relative; flex: none; width: 26px; height: 26px; }
.p-logo-fb {
position: absolute; inset: 0; display: grid; place-items: center;
font-size: 13px; font-weight: 700; border-radius: 5px; color: #0a0d0b;
background: hsl(var(--h, 140) 45% 60%);
}
.p-logo {
position: absolute; inset: 0; width: 100%; height: 100%;
object-fit: cover; border-radius: 5px; background: var(--bg-deep);
opacity: 0;
}
.p-logo.ok { opacity: 1; }
.p-empty { padding: 14px 16px; color: var(--faint); font-size: 12px; }
.side-foot {
@@ -770,3 +787,7 @@ li.ev-updated { --ev: var(--muted); }
/* 配置面板内的同步行 */
.cfg-sync-row { margin-top: 10px; padding-top: 10px; border-top: 1px dashed var(--line-soft); align-items: center; gap: 10px; }
/* 配置面板:可伸展输入(logo) */
.config-panel label.grow { flex: 1; display: flex; flex-direction: column; gap: 4px; }
.config-panel label.grow input { width: 100%; }