feat(files): 行尾悬停露出常用操作图标,面包屑带登记目录类型
学 MP 文件管理:鼠标悬停或键盘焦点所在行在行尾浮出 2–3 个图标按钮(未入库视频 / 目录:整理、识别、刮削;已入库:打开作品、刷新元数据、重命名;其余:重命名、移动到),带 tooltip 与 aria-label,被状态阻止的灰显写原因;浮出时让出修改时间列;焦点行可 Tab 进入、Esc 回列表;窄屏仍只用 ⋯ 菜单。 面包屑前加「下载目录 / 媒体库」说明段。顺带修正 Shift+F10 菜单定位按行键找行时被 CSS.escape 改坏的问题。 Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Cxwgnn2pbzQ7rXv3rq7fei
This commit is contained in:
1 parent
d98899a5f8
commit
67f05895d3
6 files changed
+165
-39
No files matched your search
@@ -2,6 +2,7 @@ import { describe, expect, it } from "vitest";
|
||||
import { resolveFilesMock } from "~/api/files.ts";
|
||||
import {
|
||||
applyIdentifyCompleted,
|
||||
breadcrumbItems,
|
||||
clickSelect,
|
||||
collapseCrumbs,
|
||||
cueTime,
|
||||
@@ -10,6 +11,7 @@ import {
|
||||
entryStatusView,
|
||||
entrySubline,
|
||||
formatEpisodes,
|
||||
hoverOpLabel,
|
||||
hoverOps,
|
||||
initialLocation,
|
||||
menuModel,
|
||||
@@ -220,10 +222,45 @@ describe("v2 菜单与副行", () => {
|
||||
expect(m && !("separator" in m) ? m.disabled : null).toMatch(/H&R/);
|
||||
});
|
||||
|
||||
it("hover 主操作按状态", () => {
|
||||
expect(hoverOps(video)).toEqual(["organize", "identify"]);
|
||||
expect(hoverOps(registered)).toEqual(["rename", "openMedia"]);
|
||||
it("悬停常用操作按文件 / 目录类型选 2–3 个,都在菜单里能找到", () => {
|
||||
expect(hoverOps(video)).toEqual(["organize", "identify", "writeNfo"]);
|
||||
expect(hoverOps({ ...base, type: "dir" as const, fileKind: null })).toEqual(["organize", "identify", "writeNfo"]);
|
||||
expect(hoverOps(registered)).toEqual(["openMedia", "scrape", "rename"]);
|
||||
// 未完成的视频不能整理:退为识别 / 重命名 / 移动
|
||||
expect(hoverOps({ ...video, status: "temp" as const })).toEqual(["identify", "rename", "move"]);
|
||||
expect(hoverOps({ ...base, fileKind: "nfo" as const })).toEqual(["rename", "move"]);
|
||||
expect(hoverOps({ ...base, fileKind: "subtitle" as const })).toEqual(["rename", "move"]);
|
||||
for (const e of [video, registered, { ...base, fileKind: "nfo" as const }]) {
|
||||
const ops = hoverOps(e);
|
||||
expect(ops.length).toBeGreaterThanOrEqual(2);
|
||||
expect(ops.length).toBeLessThanOrEqual(3);
|
||||
const menu = menuModel([e], lib).flatMap((x) => ("separator" in x ? [] : [x.key]));
|
||||
for (const op of ops) expect(menu).toContain(op);
|
||||
}
|
||||
});
|
||||
|
||||
it("悬停图标的 tooltip / aria-label 文字去掉菜单里的省略号", () => {
|
||||
expect(hoverOpLabel("organize")).toBe("整理");
|
||||
expect(hoverOpLabel("writeNfo")).toBe("刮削");
|
||||
expect(hoverOpLabel("move")).toBe("移动到");
|
||||
expect(hoverOpLabel("scrape")).toBe("刷新元数据");
|
||||
expect(hoverOpLabel("openMedia")).toBe("打开作品");
|
||||
});
|
||||
|
||||
it("面包屑:登记目录类型 > 登记目录 > 各级子目录,每段带可跳转的相对路径", () => {
|
||||
expect(breadcrumbItems({ name: "qBittorrent · 下载", kind: "download" }, "")).toEqual({
|
||||
group: "下载目录",
|
||||
crumbs: [{ label: "qBittorrent · 下载", path: "" }],
|
||||
});
|
||||
expect(breadcrumbItems({ name: "剧集库", kind: "library" }, "亚洲剧集/繁花 (2023)/Season 1/")).toEqual({
|
||||
group: "媒体库",
|
||||
crumbs: [
|
||||
{ label: "剧集库", path: "" },
|
||||
{ label: "亚洲剧集", path: "亚洲剧集" },
|
||||
{ label: "繁花 (2023)", path: "亚洲剧集/繁花 (2023)" },
|
||||
{ label: "Season 1", path: "亚洲剧集/繁花 (2023)/Season 1" },
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it("副行:已登记作品、待识别解析、目录计数", () => {
|
||||
|
||||
Reference in new issue
Block a user