feat(manage): unified management page layout (#5758)

This commit is contained in:
Thomas authored and GitHub committed 2026-05-28 10:56:46 +02:00
1 parent 4f2b3cf3ee
commit c252b4f9ac
19 files changed
+293 -244

No files matched your search

@@ -0,0 +1,15 @@
import type { PropsWithChildren } from "react";
import { Affix, Box } from "@mantine/core";
import { MANAGE_ACTION_BUTTON_MIN_WIDTH, MANAGE_AFFIX_POSITION } from "./manage-page.constants";
export const ManageMobilePrimaryAction = ({ children }: PropsWithChildren) => (
<>
<Box visibleFrom="md" miw={MANAGE_ACTION_BUTTON_MIN_WIDTH}>
{children}
</Box>
<Affix hiddenFrom="md" position={MANAGE_AFFIX_POSITION}>
{children}
</Affix>
</>
);
@@ -0,0 +1,44 @@
import type { ReactNode } from "react";
import type { MantineSize } from "@mantine/core";
import { Group, Stack, Title } from "@mantine/core";
import { DynamicBreadcrumb } from "~/components/navigation/dynamic-breadcrumb";
import { ManageContainer } from "./manage-container";
import { MANAGE_FLOATING_ACTION_BOTTOM_OFFSET } from "./manage-page.constants";
interface ManagePageLayoutProps {
title: ReactNode;
primaryAction?: ReactNode;
toolbar?: ReactNode;
footer?: ReactNode;
floatingPrimaryAction?: boolean;
size?: MantineSize;
children: ReactNode;
}
export const ManagePageLayout = ({
title,
primaryAction,
toolbar,
footer,
floatingPrimaryAction,
size,
children,
}: ManagePageLayoutProps) => {
const titleNode = typeof title === "string" ? <Title>{title}</Title> : title;
return (
<ManageContainer size={size}>
<DynamicBreadcrumb />
<Stack pb={floatingPrimaryAction ? { base: MANAGE_FLOATING_ACTION_BOTTOM_OFFSET, md: 0 } : undefined}>
<Group justify="space-between" align="center">
{titleNode}
{primaryAction}
</Group>
{toolbar}
{children}
{footer && <Group justify="end">{footer}</Group>}
</Stack>
</ManageContainer>
);
};
@@ -0,0 +1,5 @@
export const MANAGE_AFFIX_POSITION = { bottom: 20, right: 20 } as const;
export const MANAGE_FLOATING_ACTION_BOTTOM_OFFSET = 48;
export const MANAGE_ACTION_BUTTON_MIN_WIDTH = 160;
@@ -2,13 +2,15 @@ import { forwardRef } from "react";
import type { ButtonProps } from "@mantine/core";
import { Affix, Button, createPolymorphicComponent } from "@mantine/core";
import { MANAGE_ACTION_BUTTON_MIN_WIDTH, MANAGE_AFFIX_POSITION } from "./manage-page.constants";
type MobileAffixButtonProps = Omit<ButtonProps, "visibleFrom" | "hiddenFrom">;
export const MobileAffixButton = createPolymorphicComponent<"button", MobileAffixButtonProps>(
forwardRef<HTMLButtonElement, MobileAffixButtonProps>((props, ref) => (
<>
<Button ref={ref} visibleFrom="md" {...props} />
<Affix hiddenFrom="md" position={{ bottom: 20, right: 20 }}>
<Button ref={ref} visibleFrom="md" miw={MANAGE_ACTION_BUTTON_MIN_WIDTH} {...props} />
<Affix hiddenFrom="md" position={MANAGE_AFFIX_POSITION}>
<Button ref={ref} {...props} />
</Affix>
</>
+1 -1
View File
@@ -20,7 +20,7 @@ export const NoResults = ({ icon: Icon, title, action }: NoResultsProps) => {
<Text fw={500} size="lg">
{title}
</Text>
{!action?.hidden && <Anchor href={action?.href}>{action?.label}</Anchor>}
{action && !action.hidden && <Anchor href={action.href}>{action.label}</Anchor>}
</Stack>
</Card>
);