Unverified Commit de5fbb72 authored by Lemon-miaow's avatar Lemon-miaow
Browse files

fix(panel): LuckPerms 页在手机上玩家栏按内容收高、列表在卡内滚动,选中玩家的面板落在首屏

parent 7b284340
Loading
Loading
Loading
Loading
+21 −0
Changes for panel/e2e/mobile.spec.ts: 21 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ for (const [account, path] of [
  ["linked", "/account"],
  ["owner", "/servers"],
  ["owner", "/admin/users"],
  ["owner", "/servers/survival/luckperms"],
] as const) {
  test(`${path} fits a 375px screen for ${account}`, async ({ page, signIn }) => {
    await signIn(account);
@@ -29,3 +30,23 @@ for (const [account, path] of [
    await expectFitsScreen(page);
  });
}

test("the LuckPerms player list leaves the rest of the page on the first screen", async ({ page, signIn }) => {
  await signIn("owner");
  await page.goto("/servers/survival/luckperms");
  const list = page.getByRole("button", { name: "mock_player", exact: true }).locator("..");
  await expect(list).toBeVisible();

  // Twelve players online: the list scrolls inside its card, so the prompt
  // under it shows without scrolling the page.
  await expect(page.getByText(t("servers:luckperms_select_player_prompt"))).toBeInViewport({ ratio: 1 });
  const { scrollHeight, clientHeight } = await list.evaluate((el) => ({
    scrollHeight: el.scrollHeight,
    clientHeight: el.clientHeight,
  }));
  expect(scrollHeight).toBeGreaterThan(clientHeight);

  // The last one is still a tap away.
  await page.getByRole("button", { name: "Herobrine", exact: true }).click();
  await expect(page.getByRole("textbox", { name: t("servers:luckperms_player_lookup") })).toHaveValue("Herobrine");
});
+16 −0
Changes for panel/e2e/smoke.spec.ts: 16 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -73,3 +73,19 @@ test("a player's pages load on demand and never pull in the admin pages", async
  await expect.poll(() => fetched.some((p) => ACCOUNT_PAGE.test(p))).toBe(true);
  expect(fetched.filter((p) => ADMIN_PAGE.test(p))).toEqual([]);
});

test("on a wide screen the LuckPerms player list runs down its column", async ({ page, signIn }) => {
  await signIn("owner");
  await page.goto("/servers/survival/luckperms");
  const list = page.getByRole("button", { name: "mock_player", exact: true }).locator("..");
  await expect(list).toBeVisible();

  const listBox = (await list.boundingBox())!;
  const cardBox = (await list.locator("..").boundingBox())!;
  expect(cardBox.height).toBeGreaterThanOrEqual(500);
  expect(Math.abs(listBox.y + listBox.height - (cardBox.y + cardBox.height))).toBeLessThanOrEqual(2);

  // A taller screen grows the card to its cap, whatever the roster holds.
  await page.setViewportSize({ width: 1280, height: 1000 });
  await expect.poll(async () => (await list.locator("..").boundingBox())!.height).toBe(700);
});
+6 −4
Changes for panel/src/pages/ServerLuckPerms.tsx: 6 added lines, 4 removed lines.
Original line number Diff line number Diff line
@@ -397,8 +397,10 @@ export function ServerLuckPerms() {
        />
      ) : (
        <div className="grid grid-cols-1 lg:grid-cols-4 gap-6 items-start">
          {/* Left Directory Sidebar: Single card for Search + Online Players */}
          <Card className="lg:col-span-1 flex flex-col h-[calc(100vh-14rem)] lg:min-h-[500px] max-h-[700px] border-border bg-card/60 backdrop-blur-sm overflow-hidden">
          {/* Left Directory Sidebar: Single card for Search + Online Players. On a
              wide screen it fills the column; on a phone it fits its content and the
              list scrolls inside it, so the player's panel below is on the first screen. */}
          <Card className="lg:col-span-1 flex flex-col lg:h-[calc(100vh-14rem)] lg:min-h-[500px] lg:max-h-[700px] border-border bg-card/60 backdrop-blur-sm overflow-hidden">
            <CardHeader className="p-4 pb-2 border-b border-border/50 shrink-0">
              <CardTitle className="text-xs font-bold uppercase tracking-wider text-muted-foreground flex items-center gap-2">
                <Users className="h-4 w-4 text-primary" />
@@ -424,7 +426,7 @@ export function ServerLuckPerms() {
                {t("access_online_title")}
              </span>
            </div>
            <CardContent className="p-2 overflow-y-auto flex-1 space-y-0.5 min-h-0">
            <CardContent className="p-2 overflow-y-auto max-h-52 lg:max-h-none flex-1 space-y-0.5 min-h-0">
              {playersLoading && onlinePlayers.length === 0 ? (
                <div className="flex justify-center py-6">
                  <Loader2 className="h-5 w-5 animate-spin text-primary" />
@@ -463,7 +465,7 @@ export function ServerLuckPerms() {
          {/* Right Main Panel */}
          <div className="lg:col-span-3 space-y-6">
            {!selectedPlayer ? (
              <Card className="flex flex-col items-center justify-center py-24 text-center border-dashed border-border bg-card/20 min-h-[500px]">
              <Card className="flex flex-col items-center justify-center py-8 lg:py-24 text-center border-dashed border-border bg-card/20 lg:min-h-[500px]">
                <Shield className="h-14 w-14 text-muted-foreground/15 mb-4 animate-pulse" />
                <p className="text-sm text-muted-foreground font-medium max-w-xs leading-normal">
                  {t("luckperms_select_player_prompt")}