Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/locales/de-DE/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@
"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",
"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_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",
Expand Down
3 changes: 3 additions & 0 deletions src/locales/en-US/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@
"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",
"popup_layout": "Popup Layout",
"compact_popup_layout": "Compact Popup Layout",
"compact_popup_layout_desc": "Reduce spacing between popup sections and script rows",
"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",
Expand Down
3 changes: 3 additions & 0 deletions src/locales/ja-JP/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@
"display_right_click_menu_desc": "ブラウザの右クリックメニューにスクリプトメニューを表示する",
"expand_count": "展開数",
"auto_collapse_when_exceeds": "この数を超えたときに自動的に折りたたむ",
"popup_layout": "ポップアップレイアウト",
"compact_popup_layout": "コンパクトなポップアップ",
"compact_popup_layout_desc": "ポップアップのセクションとスクリプト行の間隔を狭くします",
"script_update_check_frequency": "スクリプト更新の確認頻度",
"script_auto_update_frequency": "スクリプトの自動更新確認頻度",
"control_script_update_behavior": "スクリプト更新の動作を制御",
Expand Down
3 changes: 3 additions & 0 deletions src/locales/ru-RU/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@
"display_right_click_menu_desc": "Показать меню скрипта в контекстном меню браузера",
"expand_count": "Количество развернутых",
"auto_collapse_when_exceeds": "Автоматически сворачивать при превышении этого количества",
"popup_layout": "Макет всплывающего окна",
"compact_popup_layout": "Компактное всплывающее окно",
"compact_popup_layout_desc": "Уменьшает отступы между разделами и строками скриптов во всплывающем окне",
"script_update_check_frequency": "Частота проверки обновления скрипта",
"script_auto_update_frequency": "Частота автоматической проверки обновлений скриптов",
"control_script_update_behavior": "Управление поведением обновления скриптов",
Expand Down
3 changes: 3 additions & 0 deletions src/locales/tr-TR/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@
"display_right_click_menu_desc": "Tarayıcının sağ tıklama menüsünde betik menüsünü göster",
"expand_count": "Genişletme Sayısı",
"auto_collapse_when_exceeds": "Bu sayı aşıldığında otomatik daralt",
"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_update_check_frequency": "Betik Güncelleme Kontrol Sıklığı",
"script_auto_update_frequency": "Betik otomatik güncelleme kontrol sıklığı",
"control_script_update_behavior": "Betik güncelleme davranışını kontrol edin",
Expand Down
3 changes: 3 additions & 0 deletions src/locales/vi-VN/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@
"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",
"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_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",
Expand Down
3 changes: 3 additions & 0 deletions src/locales/zh-CN/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@
"display_right_click_menu_desc": "在浏览器右键菜单中显示脚本菜单",
"expand_count": "展开数量",
"auto_collapse_when_exceeds": "超过此数量时自动折叠",
"popup_layout": "弹窗布局",
"compact_popup_layout": "紧凑弹窗布局",
"compact_popup_layout_desc": "减少弹窗分组与脚本行之间的间距",
"script_update_check_frequency": "脚本更新检查频率",
"script_auto_update_frequency": "脚本自动检查更新的频率",
"control_script_update_behavior": "控制脚本更新的行为",
Expand Down
3 changes: 3 additions & 0 deletions src/locales/zh-TW/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@
"display_right_click_menu_desc": "在瀏覽器右鍵選單中顯示腳本選單",
"expand_count": "展開數量",
"auto_collapse_when_exceeds": "超過此數量時自動摺疊",
"popup_layout": "彈出視窗版面",
"compact_popup_layout": "緊湊彈出視窗版面",
"compact_popup_layout_desc": "縮小彈出視窗區段與腳本列的間距",
"script_update_check_frequency": "腳本更新檢查頻率",
"script_auto_update_frequency": "腳本自動檢查更新的頻率",
"control_script_update_behavior": "控制腳本更新的行為",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { describe, it, expect, vi, beforeAll, afterEach } from "vitest";
import { render, screen, cleanup } from "@testing-library/react";
import { render, screen, cleanup, fireEvent } from "@testing-library/react";

const { get, set } = vi.hoisted(() => ({ get: vi.fn(), set: vi.fn() }));
vi.mock("@App/pages/store/global", async () => {
Expand Down Expand Up @@ -35,3 +35,17 @@ describe("界面分区-图标服务", () => {
expect(screen.getAllByText("扩展图标徽标")).toHaveLength(1);
});
});

describe("界面分区-popup 布局", () => {
it("应显示紧凑布局开关并保存切换结果", async () => {
get.mockImplementation((key: string) => Promise.resolve(key === "popup_compact_layout"));
render(<InterfaceSection register={() => () => {}} />);

await screen.findByText("紧凑弹窗布局");
const compactSwitch = screen.getByRole("switch", { name: "紧凑弹窗布局" });
expect(compactSwitch).toBeChecked();

fireEvent.click(compactSwitch);
expect(set).toHaveBeenCalledWith("popup_compact_layout", false);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export function InterfaceSection({ register }: { register: (id: string) => (el:
const [menuType, setMenuType] = useSystemConfig("script_menu_display_type");
const [expandNum, setExpandNum] = useSystemConfig("menu_expand_num");
const [favicon, setFavicon] = useSystemConfig("favicon_service");
const [popupCompactLayout, setPopupCompactLayout] = useSystemConfig("popup_compact_layout");

return (
<SettingCard id="interface" title={t("settings:interface_settings")} register={register}>
Expand Down Expand Up @@ -47,6 +48,14 @@ export function InterfaceSection({ register }: { register: (id: string) => (el:
className="h-8 w-12 rounded border border-border bg-transparent"
/>
</SettingRow>
<div className="text-[13px] font-semibold text-foreground pt-1">{t("settings:popup_layout")}</div>
<SettingRow label={t("settings:compact_popup_layout")} description={t("settings:compact_popup_layout_desc")}>
<Switch
aria-label={t("settings:compact_popup_layout")}
checked={popupCompactLayout ?? false}
onCheckedChange={setPopupCompactLayout}
/>
</SettingRow>
<div className="text-[13px] font-semibold text-foreground pt-1">{t("settings:script_menu")}</div>
<SettingRow
label={t("settings:display_right_click_menu")}
Expand Down
19 changes: 19 additions & 0 deletions src/pages/popup/App.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ function makeData(overrides: Record<string, any> = {}) {
checkUpdateStatus: 0,
showAlert: false,
menuExpandNum: 5,
popupCompactLayout: false,
defaultScriptProvider: "scriptcat",
currentUrl: "https://example.com",
handleToggleScript: vi.fn(),
Expand Down Expand Up @@ -103,6 +104,24 @@ describe("Popup 页头品牌标识", () => {
});
});

describe("Popup 紧凑布局", () => {
it("启用后应缩小分组标题与脚本行间距", () => {
const script = makeScriptMenu();
mockData = makeData({
popupCompactLayout: true,
scriptList: [script],
allScripts: [script],
fullScriptCount: 1,
enabledScriptCount: 1,
});

render(<App />);

expect(screen.getByText(new RegExp(t("popup:current_page_scripts"))).closest("button")).toHaveClass("h-8", "px-3");
expect(screen.getByText("Script A").closest("button")?.parentElement).toHaveClass("h-9", "px-3", "gap-2");
});
});

describe("Popup 脚本列表展开/收起", () => {
it("当前页脚本超过展示上限且已展开时,应显示「收起」按钮并可再次折叠", () => {
const handleToggleExpand = vi.fn();
Expand Down
36 changes: 29 additions & 7 deletions src/pages/popup/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ export default function App() {
title={t("popup:current_page_scripts")}
enabledCount={data.enabledScriptCount}
totalCount={data.fullScriptCount}
compact={data.popupCompactLayout}
>
{data.scriptList.map((script) => (
<ScriptRow
Expand All @@ -156,6 +157,7 @@ export default function App() {
host={data.host}
isPageScript
menuExpandNum={data.menuExpandNum}
compact={data.popupCompactLayout}
onToggle={data.handleToggleScript}
onDelete={data.handleDeleteScript}
onOpenEditor={data.handleOpenEditor}
Expand All @@ -180,13 +182,15 @@ export default function App() {
enabledCount={data.enabledBackScriptCount}
totalCount={data.fullBackScriptCount}
runningSummary={data.backRunningCount > 0 ? `${data.backRunningCount} ${t("script:running")}` : undefined}
compact={data.popupCompactLayout}
>
{data.backScriptList.map((script) => (
<ScriptRow
key={script.uuid}
script={script}
isPageScript={false}
menuExpandNum={data.menuExpandNum}
compact={data.popupCompactLayout}
onToggle={data.handleToggleScript}
onDelete={data.handleDeleteScript}
onOpenEditor={data.handleOpenEditor}
Expand Down Expand Up @@ -383,14 +387,20 @@ interface SectionProps {
enabledCount: number;
totalCount: number;
runningSummary?: string;
compact?: boolean;
children: React.ReactNode;
}

function Section({ id, title, enabledCount, totalCount, runningSummary, children }: SectionProps) {
function Section({ id, title, enabledCount, totalCount, runningSummary, compact = false, children }: SectionProps) {
return (
<AccordionPrimitive.Item value={id}>
<AccordionPrimitive.Header className="flex">
<AccordionPrimitive.Trigger className="flex flex-1 items-center gap-1.5 h-9 px-4 text-left group focus:outline-none focus-visible:ring-2 focus-visible:ring-ring/50 hover:bg-accent transition-colors">
<AccordionPrimitive.Trigger
className={cn(
"flex flex-1 items-center gap-1.5 text-left group focus:outline-none focus-visible:ring-2 focus-visible:ring-ring/50 hover:bg-accent transition-colors",
compact ? "h-8 px-3" : "h-9 px-4"
)}
>
<ChevronDown className="w-3.5 h-3.5 text-muted-foreground transition-transform duration-200 group-data-[state=closed]:-rotate-90" />
<span className="text-xs font-semibold text-fg-secondary">{`${title} (${enabledCount}/${totalCount})`}</span>
<div className="flex-1" />
Expand Down Expand Up @@ -437,6 +447,7 @@ interface ScriptRowProps {
host?: string;
isPageScript?: boolean;
menuExpandNum?: number;
compact?: boolean;
onToggle: (uuid: string, enable: boolean) => void;
onDelete: (uuid: string) => void;
onOpenEditor: (uuid: string) => void;
Expand All @@ -452,6 +463,7 @@ function ScriptRow({
host,
isPageScript = true,
menuExpandNum = 5,
compact = false,
onToggle,
onDelete,
onOpenEditor,
Expand Down Expand Up @@ -484,12 +496,22 @@ function ScriptRow({

return (
<CollapsiblePrimitive.Root open={isActive} onOpenChange={setIsActive}>
<div className="flex items-center gap-2.5 h-11 px-4 hover:bg-accent transition-colors">
<CollapsiblePrimitive.Trigger className="flex flex-1 items-center gap-2.5 min-w-0 text-left focus:outline-none focus-visible:ring-2 focus-visible:ring-ring/50">
<div
className={cn(
"flex items-center hover:bg-accent transition-colors",
compact ? "h-9 px-3 gap-2" : "h-11 px-4 gap-2.5"
)}
>
<CollapsiblePrimitive.Trigger
className={cn(
"flex flex-1 min-w-0 text-left focus:outline-none focus-visible:ring-2 focus-visible:ring-ring/50",
compact ? "gap-2" : "gap-2.5"
)}
>
<ScriptIcon
name={script.name}
iconUrl={script.icon}
size={20}
size={compact ? 16 : 20}
className={script.enable ? undefined : "opacity-40"}
/>
<span
Expand All @@ -505,7 +527,7 @@ function ScriptRow({

{/* 折叠区域:操作按钮(点击展开) */}
<CollapsiblePrimitive.Content className="overflow-hidden data-[state=closed]:animate-collapsible-up data-[state=open]:animate-collapsible-down">
<div className="flex flex-col gap-0.5 pl-11 pr-4 pt-1 pb-2">
<div className={cn("flex flex-col gap-0.5", compact ? "pl-9 pr-3 pt-0.5 pb-1" : "pl-11 pr-4 pt-1 pb-2")}>
{/* 运行/停止(仅后台脚本) */}
{!isPageScript && onRun && onStop && (
<>
Expand Down Expand Up @@ -553,7 +575,7 @@ function ScriptRow({

{/* 始终可见区域:GM 菜单、用户配置(与旧版一致,不在折叠内) */}
{(visibleMenus.length > 0 || script.hasUserConfig) && (
<div className="flex flex-col gap-0.5 pl-11 pr-4 pb-1">
<div className={cn("flex flex-col gap-0.5", compact ? "pl-9 pr-3 pb-0.5" : "pl-11 pr-4 pb-1")}>
{visibleMenus.map((menuItem) =>
menuItem.options?.inputType ? (
<InputMenuItem
Expand Down
3 changes: 3 additions & 0 deletions src/pages/popup/preload.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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),
getPopupCompactLayout: vi.fn(async () => true),
getProvider: vi.fn(async () => "greasyfork"),
getPopupData: vi.fn(),
}));
Expand All @@ -17,6 +18,7 @@ vi.mock("../store/global", () => ({
getEnableScript: mocks.getEnableScript,
getCheckUpdate: mocks.getCheckUpdate,
getMenuExpandNum: mocks.getMenuExpandNum,
getPopupCompactLayout: mocks.getPopupCompactLayout,
},
}));
vi.mock("../store/features/script", () => ({ popupClient: { getPopupData: mocks.getPopupData } }));
Expand Down Expand Up @@ -50,5 +52,6 @@ describe("Popup 数据预加载", () => {
await vi.waitFor(() => expect(mocks.getPopupData).toHaveBeenCalled());

expect(mocks.getPopupData).toHaveBeenCalledWith({ tabId: 7, url: "https://example.com/page" });
expect(mocks.getPopupCompactLayout).toHaveBeenCalledOnce();
});
});
5 changes: 4 additions & 1 deletion src/pages/popup/preload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export type PopupInitialData = {
isEnableScript: boolean;
checkUpdate: { notice: string; version: string; isRead: boolean };
menuExpandNum: number;
popupCompactLayout: boolean;
defaultScriptProvider: ScriptProvider;
isBlacklist: boolean;
scriptList: ScriptMenu[];
Expand All @@ -31,11 +32,12 @@ export const scriptListSorter = (a: ScriptMenu, b: ScriptMenu) =>
const popupDataQuery = createPreloadableQuery<"popup", PopupInitialData>({
key: (key) => key,
load: async (_key, signal) => {
const [tab, isEnableScript, checkUpdate, menuExpandNum, provider] = await Promise.all([
const [tab, isEnableScript, checkUpdate, menuExpandNum, popupCompactLayout, provider] = await Promise.all([
getCurrentTab(),
systemConfig.getEnableScript(),
systemConfig.getCheckUpdate({ sanitizeHTML }),
systemConfig.getMenuExpandNum(),
systemConfig.getPopupCompactLayout(),
cacheInstance.get<ScriptProvider>("default_script_provider"),
]);

Expand All @@ -56,6 +58,7 @@ const popupDataQuery = createPreloadableQuery<"popup", PopupInitialData>({
isEnableScript,
checkUpdate: checkUpdate ?? { notice: "", version: ExtVersion, isRead: false },
menuExpandNum,
popupCompactLayout,
defaultScriptProvider: provider ?? "scriptcat",
isBlacklist: popupData.isBlacklist,
scriptList: popupData.scriptList.sort(scriptListSorter),
Expand Down
3 changes: 3 additions & 0 deletions src/pages/popup/usePopupData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,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 [popupCompactLayout, setPopupCompactLayout] = useState(initialData?.popupCompactLayout ?? false);
const [defaultScriptProvider, setDefaultScriptProvider] = useState<ScriptProvider>(
initialData?.defaultScriptProvider ?? "scriptcat"
);
Expand Down Expand Up @@ -138,6 +139,7 @@ export function usePopupData() {
setIsEnableScript(initialData.isEnableScript);
setCheckUpdate(initialData.checkUpdate);
setMenuExpandNum(initialData.menuExpandNum);
setPopupCompactLayout(initialData.popupCompactLayout);
setDefaultScriptProvider(initialData.defaultScriptProvider);
setInitialized(true);
}
Expand Down Expand Up @@ -423,6 +425,7 @@ export function usePopupData() {
checkUpdateStatus,
showAlert,
menuExpandNum,
popupCompactLayout,
handleSearch,
handleToggleExpand,
};
Expand Down
13 changes: 13 additions & 0 deletions src/pkg/config/config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,19 @@ describe("SystemConfig 双 storage 与懒迁移", () => {
expect(localData["system_enable_eslint"]).toBeUndefined();
});

it("popup 紧凑布局应默认关闭并写入 sync storage", async () => {
await expect(config.getPopupCompactLayout()).resolves.toBe(false);

config.setPopupCompactLayout(true);

await expect(config.getPopupCompactLayout()).resolves.toBe(true);
const syncData = await chrome.storage.sync.get("system_popup_compact_layout");
expect(syncData["system_popup_compact_layout"]).toBe(true);

const localData = await chrome.storage.local.get("system_popup_compact_layout");
expect(localData["system_popup_compact_layout"]).toBeUndefined();
});

it("编辑器偏好应返回默认值并写入 sync storage", async () => {
await expect(config.getEditorPreferences()).resolves.toEqual({
version: 1,
Expand Down
8 changes: 8 additions & 0 deletions src/pkg/config/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -507,6 +507,14 @@ export class SystemConfig {
this._set("menu_expand_num", val);
}

getPopupCompactLayout() {
return this._get<boolean>("popup_compact_layout", false);
}

setPopupCompactLayout(val: boolean) {
this._set("popup_compact_layout", val);
}

async getLanguage() {
if (globalThis.localStorage) {
const cachedLanguage = localStorage.getItem("language");
Expand Down
Loading