Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 | 4104x 6544x 332x 8083x 8083x 1489x 6586x 4196x 332x 7780x 332x 1769x 1769x 1769x 6627x 1769x 7816x 7816x 1242x 7041x | import React from "react";
import { AmountBadge } from "~app/components/amount-badge";
import { PageWrapper } from "~app/components/page-wrapper";
import { suspendedFallback } from "~app/components/suspense-wrapper";
import { NavigationContext } from "~app/contexts/navigation-context";
import { Icon } from "~components/icons";
import type { IconName } from "~components/icons";
import { Link } from "~components/link";
import { Text } from "~components/text";
import { cn } from "~components/utils";
import type { ViewReactNode } from "~components/view";
import { View } from "~components/view";
import type { FileRouteTypes } from "~web/entry/routeTree.gen";
type ShowProps = {
useShow?: () => boolean;
};
type MenuElement = {
iconName: IconName;
text: string;
pathname: FileRouteTypes["to"];
useBadgeAmount?: () => number;
} & ShowProps;
const useZero = () => 0;
const useTrue = () => true;
const WithShow = suspendedFallback<React.PropsWithChildren<ShowProps>>(
({ useShow = useTrue, children }) => {
const show = useShow();
if (!show) {
return null;
}
return <>{children}</>;
},
() => null,
);
const MenuItemComponent: React.FC<MenuElement & { selected: boolean }> = ({
iconName,
pathname,
text,
useBadgeAmount = useZero,
useShow,
selected,
}) => (
<WithShow useShow={useShow}>
<Link
key={pathname}
to={pathname}
className="flex flex-1 flex-col items-center justify-center"
color={selected ? "primary" : "foreground"}
>
<AmountBadge useAmount={useBadgeAmount}>
<Icon name={iconName} className="size-6" />
</AmountBadge>
<Text className={cn("text-sm/8", selected ? "text-primary" : undefined)}>
{text}
</Text>
</Link>
</WithShow>
);
type Props = {
children?: ViewReactNode;
elements: (MenuElement & {
ItemWrapper?: React.FC<React.PropsWithChildren>;
PageWrapper?: React.FC<React.PropsWithChildren>;
})[];
};
export const Page: React.FC<Props> = ({ children, elements }) => {
const { usePathname } = React.use(NavigationContext);
const pathname = usePathname();
const Wrapper = elements.find(
(element) => element.pathname === pathname,
)?.PageWrapper;
return (
<>
<PageWrapper wrapper={Wrapper}>{children}</PageWrapper>
<View
className="bg-content1 fixed bottom-0 left-0 z-20 w-full flex-row p-2 shadow-lg"
testID="sticky-menu"
>
<View className="mx-auto max-w-screen-sm flex-1 flex-row">
{elements.map(({ ItemWrapper, ...props }) => {
const element = (
<MenuItemComponent
key={props.pathname}
{...props}
selected={pathname.startsWith(props.pathname)}
/>
);
if (ItemWrapper) {
return <ItemWrapper key={props.pathname}>{element}</ItemWrapper>;
}
return element;
})}
</View>
</View>
</>
);
};
|