diff --git a/src/locales/de-DE/settings.json b/src/locales/de-DE/settings.json index d9f7b3ddb..87cd2095a 100644 --- a/src/locales/de-DE/settings.json +++ b/src/locales/de-DE/settings.json @@ -67,11 +67,13 @@ "script_menu": "Skriptmenü", "display_right_click_menu": "Rechtsklickmenü anzeigen", "display_right_click_menu_desc": "Skriptmenü im Rechtsklickmenü des Browsers anzeigen", - "expand_count": "Erweiterte Anzahl", - "auto_collapse_when_exceeds": "Automatisch einklappen, wenn diese Anzahl überschritten wird", + "menu_expand_count": "Angezeigte Menüeinträge", + "menu_expand_count_desc": "Anzahl der Menüeinträge, die im Popup je Skript ausgeklappt werden; der Rest wird eingeklappt. Bei 0 erscheinen sie erst, wenn das Skript ausgeklappt wird", "popup_layout": "Popup-Layout", "compact_popup_layout": "Kompaktes Popup-Layout", "compact_popup_layout_desc": "Verringert die Abstände zwischen Bereichen und Skriptzeilen im Popup", + "script_list_expand_count": "Angezeigte Skripte in der Liste", + "script_list_expand_count_desc": "Anzahl der Skripte, die je Popup-Bereich ausgeklappt werden; der Rest wird eingeklappt. Bei 0 werden alle angezeigt", "script_update_check_frequency": "Häufigkeit der Skript-Aktualisierungsprüfung", "script_auto_update_frequency": "Frequenz der automatischen Skript-Update-Prüfung", "control_script_update_behavior": "Skript-Update-Verhalten kontrollieren", diff --git a/src/locales/en-US/settings.json b/src/locales/en-US/settings.json index acff52b63..13bec0644 100644 --- a/src/locales/en-US/settings.json +++ b/src/locales/en-US/settings.json @@ -67,11 +67,13 @@ "script_menu": "Script Menu", "display_right_click_menu": "Show right-click menu", "display_right_click_menu_desc": "Show script menu in browser right-click menu", - "expand_count": "Expand Count", - "auto_collapse_when_exceeds": "Auto collapse when exceeds this number", + "menu_expand_count": "Menu Expand Count", + "menu_expand_count_desc": "Menu items shown under a single script in the popup; the rest are collapsed. 0 shows them only after expanding the script", "popup_layout": "Popup Layout", "compact_popup_layout": "Compact Popup Layout", "compact_popup_layout_desc": "Reduce spacing between popup sections and script rows", + "script_list_expand_count": "Script List Expand Count", + "script_list_expand_count_desc": "Scripts shown in each popup section; the rest are collapsed. 0 shows all of them", "script_update_check_frequency": "Script Update Check Frequency", "script_auto_update_frequency": "Script automatic update check frequency", "control_script_update_behavior": "Control script update behavior", diff --git a/src/locales/ja-JP/settings.json b/src/locales/ja-JP/settings.json index f212a11a1..5f2e5b3e5 100644 --- a/src/locales/ja-JP/settings.json +++ b/src/locales/ja-JP/settings.json @@ -67,11 +67,13 @@ "script_menu": "スクリプトメニュー", "display_right_click_menu": "右クリックメニューを表示", "display_right_click_menu_desc": "ブラウザの右クリックメニューにスクリプトメニューを表示する", - "expand_count": "展開数", - "auto_collapse_when_exceeds": "この数を超えたときに自動的に折りたたむ", + "menu_expand_count": "メニューの展開数", + "menu_expand_count_desc": "ポップアップで 1 つのスクリプトに展開表示するメニュー項目数です。超えた分は折りたたまれ、0 の場合はスクリプトを展開したときのみ表示します", "popup_layout": "ポップアップレイアウト", "compact_popup_layout": "コンパクトなポップアップ", "compact_popup_layout_desc": "ポップアップのセクションとスクリプト行の間隔を狭くします", + "script_list_expand_count": "スクリプト一覧の展開数", + "script_list_expand_count_desc": "ポップアップの各セクションで展開表示するスクリプト数です。超えた分は折りたたまれ、0 の場合はすべて表示します", "script_update_check_frequency": "スクリプト更新の確認頻度", "script_auto_update_frequency": "スクリプトの自動更新確認頻度", "control_script_update_behavior": "スクリプト更新の動作を制御", diff --git a/src/locales/ko-KR/settings.json b/src/locales/ko-KR/settings.json index ab94b9b1c..f1bd00e49 100644 --- a/src/locales/ko-KR/settings.json +++ b/src/locales/ko-KR/settings.json @@ -67,11 +67,13 @@ "script_menu": "스크립트 메뉴", "display_right_click_menu": "우클릭 메뉴에 표시", "display_right_click_menu_desc": "브라우저 우클릭 메뉴에 스크립트 메뉴 표시", - "expand_count": "펼침 개수", - "auto_collapse_when_exceeds": "이 개수를 초과하면 자동으로 접기", + "menu_expand_count": "메뉴 펼침 개수", + "menu_expand_count_desc": "팝업에서 스크립트 하나에 펼쳐 표시할 메뉴 항목 개수이며, 초과분은 접힙니다. 0이면 스크립트를 펼쳤을 때만 표시합니다", "popup_layout": "팝업 레이아웃", "compact_popup_layout": "간격을 줄인 팝업 레이아웃", "compact_popup_layout_desc": "팝업 섹션과 스크립트 행 사이의 간격을 줄입니다", + "script_list_expand_count": "스크립트 목록 펼침 개수", + "script_list_expand_count_desc": "팝업의 각 섹션에서 펼쳐 표시할 스크립트 개수이며, 초과분은 접힙니다. 0이면 모두 표시합니다", "script_update_check_frequency": "스크립트 업데이트 확인 주기", "script_auto_update_frequency": "스크립트 자동 업데이트 확인 주기", "control_script_update_behavior": "스크립트 업데이트 동작 제어", diff --git a/src/locales/pt-BR/settings.json b/src/locales/pt-BR/settings.json index 104625aff..827141920 100644 --- a/src/locales/pt-BR/settings.json +++ b/src/locales/pt-BR/settings.json @@ -67,11 +67,13 @@ "script_menu": "Menu de scripts", "display_right_click_menu": "Exibir no menu de contexto", "display_right_click_menu_desc": "Exibe o menu de scripts no menu de contexto do navegador", - "expand_count": "Limite de itens visíveis", - "auto_collapse_when_exceeds": "Recolher automaticamente quando exceder este número", + "menu_expand_count": "Itens de menu visíveis", + "menu_expand_count_desc": "Quantidade de itens de menu expandidos em cada script no popup; o restante fica recolhido. Com 0, eles só aparecem depois de expandir o script", "popup_layout": "Layout do popup", "compact_popup_layout": "Layout compacto do popup", "compact_popup_layout_desc": "Reduzir o espaçamento entre as seções do popup e as linhas de scripts", + "script_list_expand_count": "Scripts visíveis na lista", + "script_list_expand_count_desc": "Quantidade de scripts expandidos em cada seção do popup; o restante fica recolhido. Com 0, todos são exibidos", "script_update_check_frequency": "Frequência de verificação de atualização de scripts", "script_auto_update_frequency": "Frequência de verificação automática de atualização de scripts", "control_script_update_behavior": "Controlar o comportamento de atualização de scripts", diff --git a/src/locales/ru-RU/settings.json b/src/locales/ru-RU/settings.json index 1cbd5eb2d..e9bfc5fc3 100644 --- a/src/locales/ru-RU/settings.json +++ b/src/locales/ru-RU/settings.json @@ -67,11 +67,13 @@ "script_menu": "Меню скрипта", "display_right_click_menu": "Показать контекстное меню", "display_right_click_menu_desc": "Показать меню скрипта в контекстном меню браузера", - "expand_count": "Количество развернутых", - "auto_collapse_when_exceeds": "Автоматически сворачивать при превышении этого количества", + "menu_expand_count": "Количество пунктов меню", + "menu_expand_count_desc": "Сколько пунктов меню разворачивать у одного скрипта во всплывающем окне; остальные сворачиваются. При 0 они появляются только после разворачивания скрипта", "popup_layout": "Макет всплывающего окна", "compact_popup_layout": "Компактное всплывающее окно", "compact_popup_layout_desc": "Уменьшает отступы между разделами и строками скриптов во всплывающем окне", + "script_list_expand_count": "Количество скриптов в списке", + "script_list_expand_count_desc": "Сколько скриптов разворачивать в каждом разделе всплывающего окна; остальные сворачиваются. При 0 отображаются все", "script_update_check_frequency": "Частота проверки обновления скрипта", "script_auto_update_frequency": "Частота автоматической проверки обновлений скриптов", "control_script_update_behavior": "Управление поведением обновления скриптов", diff --git a/src/locales/tr-TR/settings.json b/src/locales/tr-TR/settings.json index 73a396c8e..e43c8a361 100644 --- a/src/locales/tr-TR/settings.json +++ b/src/locales/tr-TR/settings.json @@ -67,11 +67,13 @@ "script_menu": "Betik Menüsü", "display_right_click_menu": "Sağ tıklama menüsünü göster", "display_right_click_menu_desc": "Tarayıcı sağ tıklama menüsünde betik menüsünü göster", - "expand_count": "Genişletme Sayısı", - "auto_collapse_when_exceeds": "Bu sayıyı aştığında otomatik daralt", + "menu_expand_count": "Gösterilen Menü Öğesi Sayısı", + "menu_expand_count_desc": "Açılır pencerede tek bir betikte genişletilerek gösterilecek menü öğesi sayısıdır; fazlası daraltılır. 0 olduğunda yalnızca betik genişletildiğinde görünür", "popup_layout": "Açılır Pencere Düzeni", "compact_popup_layout": "Kompakt Açılır Pencere Düzeni", "compact_popup_layout_desc": "Açılır penceredeki bölümler ve betik satırları arasındaki boşluğu azaltır", + "script_list_expand_count": "Listede Gösterilen Betik Sayısı", + "script_list_expand_count_desc": "Açılır penceredeki her bölümde genişletilerek gösterilecek betik sayısıdır; fazlası daraltılır. 0 olduğunda tümü gösterilir", "script_update_check_frequency": "Betik Güncelleme Denetimi Sıklığı", "script_auto_update_frequency": "Betik Otomatik Güncelleme Denetimi Sıklığı", "control_script_update_behavior": "Betik güncelleme davranışını kontrol et", diff --git a/src/locales/vi-VN/settings.json b/src/locales/vi-VN/settings.json index bb4f0d8da..ed380f717 100644 --- a/src/locales/vi-VN/settings.json +++ b/src/locales/vi-VN/settings.json @@ -67,11 +67,13 @@ "script_menu": "Menu script", "display_right_click_menu": "Hiển thị menu chuột phải", "display_right_click_menu_desc": "Hiển thị menu script trong menu chuột phải của trình duyệt", - "expand_count": "Số lượng mở rộng", - "auto_collapse_when_exceeds": "Tự động thu gọn khi vượt quá số này", + "menu_expand_count": "Số mục menu hiển thị", + "menu_expand_count_desc": "Số mục menu mở rộng trong mỗi script ở cửa sổ bật lên, phần còn lại sẽ thu gọn; đặt 0 thì chỉ hiển thị sau khi mở rộng script", "popup_layout": "Bố cục cửa sổ bật lên", "compact_popup_layout": "Bố cục cửa sổ bật lên thu gọn", "compact_popup_layout_desc": "Giảm khoảng cách giữa các mục và hàng script trong cửa sổ bật lên", + "script_list_expand_count": "Số script hiển thị trong danh sách", + "script_list_expand_count_desc": "Số script mở rộng trong mỗi mục của cửa sổ bật lên, phần còn lại sẽ thu gọn; đặt 0 thì hiển thị tất cả", "script_update_check_frequency": "Tần suất kiểm tra cập nhật tập lệnh", "script_auto_update_frequency": "Tần suất kiểm tra cập nhật script tự động", "control_script_update_behavior": "Kiểm soát hành vi cập nhật script", diff --git a/src/locales/zh-CN/settings.json b/src/locales/zh-CN/settings.json index 660aa1650..625d943c7 100644 --- a/src/locales/zh-CN/settings.json +++ b/src/locales/zh-CN/settings.json @@ -67,11 +67,13 @@ "script_menu": "脚本菜单", "display_right_click_menu": "显示右键菜单", "display_right_click_menu_desc": "在浏览器右键菜单中显示脚本菜单", - "expand_count": "展开数量", - "auto_collapse_when_exceeds": "超过此数量时自动折叠", + "menu_expand_count": "菜单展开数量", + "menu_expand_count_desc": "弹窗中单个脚本展开显示的菜单项数量,超出部分折叠;填 0 表示展开脚本后才显示菜单", "popup_layout": "弹窗布局", "compact_popup_layout": "紧凑弹窗布局", "compact_popup_layout_desc": "减少弹窗分组与脚本行之间的间距", + "script_list_expand_count": "脚本列表展开数量", + "script_list_expand_count_desc": "弹窗中每个分组展开显示的脚本数量,超出部分折叠;填 0 表示全部显示", "script_update_check_frequency": "脚本更新检查频率", "script_auto_update_frequency": "脚本自动检查更新的频率", "control_script_update_behavior": "控制脚本更新的行为", diff --git a/src/locales/zh-TW/settings.json b/src/locales/zh-TW/settings.json index edbd54d54..19a26817e 100644 --- a/src/locales/zh-TW/settings.json +++ b/src/locales/zh-TW/settings.json @@ -67,11 +67,13 @@ "script_menu": "腳本選單", "display_right_click_menu": "顯示右鍵選單", "display_right_click_menu_desc": "在瀏覽器右鍵選單中顯示腳本選單", - "expand_count": "展開數量", - "auto_collapse_when_exceeds": "超過此數量時自動摺疊", + "menu_expand_count": "選單展開數量", + "menu_expand_count_desc": "彈出視窗中單一腳本展開顯示的選單項目數量,超出部分摺疊;填 0 表示展開腳本後才顯示選單", "popup_layout": "彈出視窗版面", "compact_popup_layout": "緊湊彈出視窗版面", "compact_popup_layout_desc": "縮小彈出視窗區段與腳本列的間距", + "script_list_expand_count": "腳本清單展開數量", + "script_list_expand_count_desc": "彈出視窗中每個區段展開顯示的腳本數量,超出部分摺疊;填 0 表示全部顯示", "script_update_check_frequency": "腳本更新檢查頻率", "script_auto_update_frequency": "腳本自動檢查更新的頻率", "control_script_update_behavior": "控制腳本更新的行為", diff --git a/src/pages/options/routes/Setting/sections/InterfaceSection.test.tsx b/src/pages/options/routes/Setting/sections/InterfaceSection.test.tsx index 5c20a558e..729cfb7c9 100644 --- a/src/pages/options/routes/Setting/sections/InterfaceSection.test.tsx +++ b/src/pages/options/routes/Setting/sections/InterfaceSection.test.tsx @@ -56,3 +56,37 @@ describe("界面分区-popup 布局", () => { expect(set).toHaveBeenCalledWith("popup_compact_layout", false); }); }); + +// 两个展开数量此前共用「展开数量 / 超过此数量时自动折叠」文案,用户误以为它管脚本列表(#1558) +describe("界面分区-展开数量", () => { + const numbers = (key: string) => Promise.resolve(key === "script_list_expand_num" ? 5 : 5); + + it("脚本列表与脚本菜单各有一个数量设置,文案互不混淆", async () => { + get.mockImplementation(numbers); + render( () => {}} />); + + expect(await screen.findByText("脚本列表展开数量")).toBeInTheDocument(); + expect(screen.getByText("菜单展开数量")).toBeInTheDocument(); + expect(screen.queryByText("展开数量")).not.toBeInTheDocument(); + }); + + it("修改脚本列表展开数量应写入 script_list_expand_num", async () => { + get.mockImplementation(numbers); + render( () => {}} />); + + const input = await screen.findByLabelText("脚本列表展开数量"); + fireEvent.change(input, { target: { value: "21" } }); + + expect(set).toHaveBeenCalledWith("script_list_expand_num", 21); + }); + + it("修改菜单展开数量应写入 menu_expand_num", async () => { + get.mockImplementation(numbers); + render( () => {}} />); + + const input = await screen.findByLabelText("菜单展开数量"); + fireEvent.change(input, { target: { value: "3" } }); + + expect(set).toHaveBeenCalledWith("menu_expand_num", 3); + }); +}); diff --git a/src/pages/options/routes/Setting/sections/InterfaceSection.tsx b/src/pages/options/routes/Setting/sections/InterfaceSection.tsx index 0288ff09d..e852a1a24 100644 --- a/src/pages/options/routes/Setting/sections/InterfaceSection.tsx +++ b/src/pages/options/routes/Setting/sections/InterfaceSection.tsx @@ -13,7 +13,8 @@ export function InterfaceSection({ register }: { register: (id: string) => (el: const [bgColor, setBgColor] = useSystemConfig("badge_background_color"); const [textColor, setTextColor] = useSystemConfig("badge_text_color"); const [menuType, setMenuType] = useSystemConfig("script_menu_display_type"); - const [expandNum, setExpandNum] = useSystemConfig("menu_expand_num"); + const [menuExpandNum, setMenuExpandNum] = useSystemConfig("menu_expand_num"); + const [scriptListExpandNum, setScriptListExpandNum] = useSystemConfig("script_list_expand_num"); const [favicon, setFavicon] = useSystemConfig("favicon_service"); const [popupCompactLayout, setPopupCompactLayout] = useSystemConfig("popup_compact_layout"); @@ -56,6 +57,19 @@ export function InterfaceSection({ register }: { register: (id: string) => (el: onCheckedChange={setPopupCompactLayout} /> + + setScriptListExpandNum(Number(e.target.value))} + /> +
{t("settings:script_menu")}
(el: > setMenuType(c ? "all" : "no_browser")} /> - + setExpandNum(Number(e.target.value))} + value={menuExpandNum ?? 5} + onChange={(e) => setMenuExpandNum(Number(e.target.value))} /> diff --git a/src/pages/popup/preload.test.ts b/src/pages/popup/preload.test.ts index 76b26279b..49817abba 100644 --- a/src/pages/popup/preload.test.ts +++ b/src/pages/popup/preload.test.ts @@ -6,6 +6,7 @@ const mocks = vi.hoisted(() => ({ getEnableScript: vi.fn(async () => true), getCheckUpdate: vi.fn(async () => ({ notice: "notice", version: "2.0.0", isRead: false })), getMenuExpandNum: vi.fn(async () => 8), + getScriptListExpandNum: vi.fn(async () => 21), getPopupCompactLayout: vi.fn(async () => true), getProvider: vi.fn(async () => "greasyfork"), getPopupData: vi.fn(), @@ -18,6 +19,7 @@ vi.mock("../store/global", () => ({ getEnableScript: mocks.getEnableScript, getCheckUpdate: mocks.getCheckUpdate, getMenuExpandNum: mocks.getMenuExpandNum, + getScriptListExpandNum: mocks.getScriptListExpandNum, getPopupCompactLayout: mocks.getPopupCompactLayout, }, })); @@ -53,5 +55,6 @@ describe("Popup 数据预加载", () => { expect(mocks.getPopupData).toHaveBeenCalledWith({ tabId: 7, url: "https://example.com/page" }); expect(mocks.getPopupCompactLayout).toHaveBeenCalledOnce(); + expect(mocks.getScriptListExpandNum).toHaveBeenCalledOnce(); }); }); diff --git a/src/pages/popup/preload.ts b/src/pages/popup/preload.ts index f53fae882..bbcfd0650 100644 --- a/src/pages/popup/preload.ts +++ b/src/pages/popup/preload.ts @@ -15,6 +15,7 @@ export type PopupInitialData = { isEnableScript: boolean; checkUpdate: { notice: string; version: string; isRead: boolean }; menuExpandNum: number; + scriptListExpandNum: number; popupCompactLayout: boolean; defaultScriptProvider: ScriptProvider; isBlacklist: boolean; @@ -32,14 +33,16 @@ export const scriptListSorter = (a: ScriptMenu, b: ScriptMenu) => const popupDataQuery = createPreloadableQuery<"popup", PopupInitialData>({ key: (key) => key, load: async (_key, signal) => { - const [tab, isEnableScript, checkUpdate, menuExpandNum, popupCompactLayout, provider] = await Promise.all([ - getCurrentTab(), - systemConfig.getEnableScript(), - systemConfig.getCheckUpdate({ sanitizeHTML }), - systemConfig.getMenuExpandNum(), - systemConfig.getPopupCompactLayout(), - cacheInstance.get("default_script_provider"), - ]); + const [tab, isEnableScript, checkUpdate, menuExpandNum, scriptListExpandNum, popupCompactLayout, provider] = + await Promise.all([ + getCurrentTab(), + systemConfig.getEnableScript(), + systemConfig.getCheckUpdate({ sanitizeHTML }), + systemConfig.getMenuExpandNum(), + systemConfig.getScriptListExpandNum(), + systemConfig.getPopupCompactLayout(), + cacheInstance.get("default_script_provider"), + ]); if (signal.aborted) throw new DOMException("Popup preload aborted", "AbortError"); @@ -58,6 +61,7 @@ const popupDataQuery = createPreloadableQuery<"popup", PopupInitialData>({ isEnableScript, checkUpdate: checkUpdate ?? { notice: "", version: ExtVersion, isRead: false }, menuExpandNum, + scriptListExpandNum, popupCompactLayout, defaultScriptProvider: provider ?? "scriptcat", isBlacklist: popupData.isBlacklist, diff --git a/src/pages/popup/usePopupData.test.ts b/src/pages/popup/usePopupData.test.ts index 42868eb7b..fa78ee63f 100644 --- a/src/pages/popup/usePopupData.test.ts +++ b/src/pages/popup/usePopupData.test.ts @@ -1,4 +1,4 @@ -import { describe, it, expect, vi, beforeEach } from "vitest"; +import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; import { renderHook, act } from "@testing-library/react"; const popupInitialData = vi.hoisted(() => ({ @@ -7,6 +7,7 @@ const popupInitialData = vi.hoisted(() => ({ isEnableScript: true, checkUpdate: { notice: "", version: "1.0.0", isRead: false }, menuExpandNum: 5, + scriptListExpandNum: 5, defaultScriptProvider: "scriptcat" as const, isBlacklist: false, scriptList: [ @@ -19,7 +20,7 @@ const popupInitialData = vi.hoisted(() => ({ updatetime: 0, }, ], - backScriptList: [], + backScriptList: [] as unknown[], })); vi.mock("./preload", () => ({ @@ -98,3 +99,82 @@ describe("usePopupData 预加载数据", () => { expect(result.current.scriptList[0]?.name).toBe("Preloaded script"); }); }); + +describe("usePopupData 脚本列表展开数量", () => { + const snapshot = { scriptList: popupInitialData.scriptList, backScriptList: [], scriptListExpandNum: 5 }; + + const makeScripts = (n: number) => + Array.from({ length: n }, (_, i) => ({ + uuid: `script-${i}`, + name: `Script ${i}`, + enable: true, + menus: [], + runNum: 0, + updatetime: 0, + })); + + afterEach(() => { + Object.assign(popupInitialData, snapshot); + }); + + it("默认只展开 5 条,其余折叠为「显示更多」", () => { + Object.assign(popupInitialData, { scriptList: makeScripts(8), scriptListExpandNum: 5 }); + + const { result } = renderHook(() => usePopupData()); + + expect(result.current.scriptList).toHaveLength(5); + expect(result.current.canExpandCurrent).toBe(true); + expect(result.current.remainingCurrentCount).toBe(3); + }); + + it("调大展开数量后应按设置展开而不是恒为 5", () => { + Object.assign(popupInitialData, { scriptList: makeScripts(8), scriptListExpandNum: 21 }); + + const { result } = renderHook(() => usePopupData()); + + expect(result.current.scriptList).toHaveLength(8); + expect(result.current.canExpandCurrent).toBe(false); + }); + + it("设为 0 表示不折叠,全部脚本直接显示", () => { + Object.assign(popupInitialData, { scriptList: makeScripts(30), scriptListExpandNum: 0 }); + + const { result } = renderHook(() => usePopupData()); + + expect(result.current.scriptList).toHaveLength(30); + expect(result.current.canExpandCurrent).toBe(false); + expect(result.current.remainingCurrentCount).toBe(0); + // 列表全展开时脚本可能很多,搜索框必须仍然可用 + expect(result.current.showSearch).toBe(true); + }); + + it("后台脚本分组同样按该设置截断", () => { + Object.assign(popupInitialData, { + scriptList: [], + backScriptList: makeScripts(9), + scriptListExpandNum: 7, + }); + + const { result } = renderHook(() => usePopupData()); + + expect(result.current.backScriptList).toHaveLength(7); + expect(result.current.canExpandBack).toBe(true); + expect(result.current.remainingBackCount).toBe(2); + }); + + it("搜索框跟随该设置:脚本总数未超过展开数量时不显示", () => { + Object.assign(popupInitialData, { scriptList: makeScripts(8), scriptListExpandNum: 10 }); + + const { result } = renderHook(() => usePopupData()); + + expect(result.current.showSearch).toBe(false); + }); + + it("搜索框跟随该设置:脚本总数超过展开数量时显示", () => { + Object.assign(popupInitialData, { scriptList: makeScripts(11), scriptListExpandNum: 10 }); + + const { result } = renderHook(() => usePopupData()); + + expect(result.current.showSearch).toBe(true); + }); +}); diff --git a/src/pages/popup/usePopupData.ts b/src/pages/popup/usePopupData.ts index 68bf8d018..6037c5a9a 100644 --- a/src/pages/popup/usePopupData.ts +++ b/src/pages/popup/usePopupData.ts @@ -75,8 +75,6 @@ function filterScripts(list: ScriptMenu[], query: string): ScriptMenu[] { return list.filter((s) => s.name.toLowerCase().includes(lower)); } -const EXPAND_LIMIT = 5; - // ========== Hook ========== export function usePopupData() { @@ -98,6 +96,7 @@ export function usePopupData() { const [checkUpdateStatus, setCheckUpdateStatus] = useState(0); // 0=idle, 1=checking, 2=latest const [showAlert, setShowAlert] = useState(false); const [menuExpandNum, setMenuExpandNum] = useState(initialData?.menuExpandNum ?? 5); + const [scriptListExpandNum, setScriptListExpandNum] = useState(initialData?.scriptListExpandNum ?? 5); const [popupCompactLayout, setPopupCompactLayout] = useState(initialData?.popupCompactLayout ?? false); const [defaultScriptProvider, setDefaultScriptProvider] = useState( initialData?.defaultScriptProvider ?? "scriptcat" @@ -139,6 +138,7 @@ export function usePopupData() { setIsEnableScript(initialData.isEnableScript); setCheckUpdate(initialData.checkUpdate); setMenuExpandNum(initialData.menuExpandNum); + setScriptListExpandNum(initialData.scriptListExpandNum); setPopupCompactLayout(initialData.popupCompactLayout); setDefaultScriptProvider(initialData.defaultScriptProvider); setInitialized(true); @@ -361,18 +361,22 @@ export function usePopupData() { const filteredScriptList = filterScripts(scriptList, searchQuery); const filteredBackScriptList = filterScripts(backScriptList, searchQuery); const totalScriptCount = scriptList.length + backScriptList.length; - const showSearch = totalScriptCount > EXPAND_LIMIT; + // 设置项以 0 表示「不折叠」;负值(如导入的异常备份)同样按不折叠处理,避免负数 slice 从尾部截断 + const expandThreshold = scriptListExpandNum > 0 ? scriptListExpandNum : 0; + const expandLimit = expandThreshold || Infinity; + // 不折叠时列表可能很长,搜索框反而更需要,故按阈值而非截断上限判断 + const showSearch = totalScriptCount > expandThreshold; - const displayScriptList = expandedSections.current ? filteredScriptList : filteredScriptList.slice(0, EXPAND_LIMIT); + const displayScriptList = expandedSections.current ? filteredScriptList : filteredScriptList.slice(0, expandLimit); const remainingCurrentCount = filteredScriptList.length - displayScriptList.length; // 超过展示上限即可展开/收起:折叠时显示「显示更多」,展开时显示「收起」 - const canExpandCurrent = filteredScriptList.length > EXPAND_LIMIT; + const canExpandCurrent = filteredScriptList.length > expandLimit; const displayBackScriptList = expandedSections.background ? filteredBackScriptList - : filteredBackScriptList.slice(0, EXPAND_LIMIT); + : filteredBackScriptList.slice(0, expandLimit); const remainingBackCount = filteredBackScriptList.length - displayBackScriptList.length; - const canExpandBack = filteredBackScriptList.length > EXPAND_LIMIT; + const canExpandBack = filteredBackScriptList.length > expandLimit; const backRunningCount = backScriptList.filter((s) => s.runStatus === SCRIPT_RUN_STATUS_RUNNING).length; const enabledScriptCount = scriptList.filter((s) => s.enable).length; diff --git a/src/pkg/backup/config_sections.ts b/src/pkg/backup/config_sections.ts index 72adab166..37ae0f872 100644 --- a/src/pkg/backup/config_sections.ts +++ b/src/pkg/backup/config_sections.ts @@ -8,6 +8,7 @@ export type ConfigSection = { id: SectionId; group: "app" | "agent"; count: numb // 显式认领的 SystemConfig 键;未认领的落入 "other"(兜底,保证不漏键) const APPEARANCE_KEYS = new Set([ "menu_expand_num", + "script_list_expand_num", "script_menu_display_type", "badge_number_type", "badge_background_color", diff --git a/src/pkg/config/config.ts b/src/pkg/config/config.ts index fb50f668e..6a6769ea7 100644 --- a/src/pkg/config/config.ts +++ b/src/pkg/config/config.ts @@ -550,7 +550,7 @@ export class SystemConfig { return 5; } - // 展开菜单数 + // 单个脚本行内展开的菜单项数量,0 表示展开脚本行后才显示菜单 getMenuExpandNum() { return this._get("menu_expand_num", this.defaultMenuExpandNum()); } @@ -559,6 +559,15 @@ export class SystemConfig { this._set("menu_expand_num", val); } + /** popup 每个分组展开显示的脚本数量,0 表示不折叠 */ + getScriptListExpandNum() { + return this._get("script_list_expand_num", 5); + } + + setScriptListExpandNum(val: number) { + this._set("script_list_expand_num", val); + } + getPopupCompactLayout() { return this._get("popup_compact_layout", false); }