fix(panel): LuckPerms 页在手机上玩家栏按内容收高、列表在卡内滚动,选中玩家的面板落在首屏
This commit is contained in:
3 files changed
+43
-4
No files matched your search
@@ -20,6 +20,7 @@ for (const [account, path] of [
|
|||||||
["linked", "/account"],
|
["linked", "/account"],
|
||||||
["owner", "/servers"],
|
["owner", "/servers"],
|
||||||
["owner", "/admin/users"],
|
["owner", "/admin/users"],
|
||||||
|
["owner", "/servers/survival/luckperms"],
|
||||||
] as const) {
|
] as const) {
|
||||||
test(`${path} fits a 375px screen for ${account}`, async ({ page, signIn }) => {
|
test(`${path} fits a 375px screen for ${account}`, async ({ page, signIn }) => {
|
||||||
await signIn(account);
|
await signIn(account);
|
||||||
@@ -29,3 +30,23 @@ for (const [account, path] of [
|
|||||||
await expectFitsScreen(page);
|
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");
|
||||||
|
});
|
||||||
@@ -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);
|
await expect.poll(() => fetched.some((p) => ACCOUNT_PAGE.test(p))).toBe(true);
|
||||||
expect(fetched.filter((p) => ADMIN_PAGE.test(p))).toEqual([]);
|
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);
|
||||||
|
});
|
||||||
@@ -397,8 +397,10 @@ export function ServerLuckPerms() {
|
|||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<div className="grid grid-cols-1 lg:grid-cols-4 gap-6 items-start">
|
<div className="grid grid-cols-1 lg:grid-cols-4 gap-6 items-start">
|
||||||
{/* Left Directory Sidebar: Single card for Search + Online Players */}
|
{/* Left Directory Sidebar: Single card for Search + Online Players. On a
|
||||||
<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">
|
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">
|
<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">
|
<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" />
|
<Users className="h-4 w-4 text-primary" />
|
||||||
@@ -424,7 +426,7 @@ export function ServerLuckPerms() {
|
|||||||
{t("access_online_title")}
|
{t("access_online_title")}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</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 ? (
|
{playersLoading && onlinePlayers.length === 0 ? (
|
||||||
<div className="flex justify-center py-6">
|
<div className="flex justify-center py-6">
|
||||||
<Loader2 className="h-5 w-5 animate-spin text-primary" />
|
<Loader2 className="h-5 w-5 animate-spin text-primary" />
|
||||||
@@ -463,7 +465,7 @@ export function ServerLuckPerms() {
|
|||||||
{/* Right Main Panel */}
|
{/* Right Main Panel */}
|
||||||
<div className="lg:col-span-3 space-y-6">
|
<div className="lg:col-span-3 space-y-6">
|
||||||
{!selectedPlayer ? (
|
{!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" />
|
<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">
|
<p className="text-sm text-muted-foreground font-medium max-w-xs leading-normal">
|
||||||
{t("luckperms_select_player_prompt")}
|
{t("luckperms_select_player_prompt")}
|
||||||
|
|||||||
Reference in new issue
Block a user