Skip to content

Commit

Permalink
Remove chakra components from layout header
Browse files Browse the repository at this point in the history
  • Loading branch information
JunichiSugiura committed Jan 13, 2025
1 parent 7818d89 commit f941f1f
Show file tree
Hide file tree
Showing 3 changed files with 132 additions and 177 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { Meta, StoryObj } from "@storybook/react";
import { Banner } from "./Banner";
import { EthereumIcon, TransferDuoIcon } from "@cartridge/ui-next";

const meta: Meta<typeof Banner> = {
component: Banner,
Expand All @@ -10,28 +11,41 @@ const meta: Meta<typeof Banner> = {
values: [{ name: "dark", value: "#161a17" }],
},
},
args: {
variant: "compressed",
title: "Welcome to Keychain",
description: "Secure your digital assets",
},
} satisfies Meta<typeof Banner>;

export default meta;

type Story = StoryObj<typeof meta>;

export const Expanded: Story = {
parameters: {
args: {
variant: "expanded",
},
};

export const Compressed: Story = {};

export const IconComponentProp: Story = {
args: {
title: "Welcome to Keychain",
description: "Secure your digital assets",
Icon: TransferDuoIcon,
},
};

export const Compressed: Story = {
parameters: {
variant: "compressed",
export const IconElementProp: Story = {
args: {
icon: <EthereumIcon />,
},
};

export const VeryLongTitle: Story = {
args: {
title: "Welcome to Keychain",
description: "Secure your digital assets",
title: "This is a very long title that should be truncated",
description:
"This is a very long description that should be wrapped and demonstrate how text behaves when it extends beyond multiple lines. It's important to test how the UI handles lengthy content to ensure proper wrapping, readability, and overall visual appeal. How does this much longer description look in the component?",
},
};
243 changes: 99 additions & 144 deletions packages/keychain/src/components/layout/container/header/Banner.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,5 @@
import {
VStack,
Circle,
Text,
Center,
Flex,
Image,
Square,
HStack,
} from "@chakra-ui/react";
import { useControllerTheme } from "@/hooks/theme";
import { TOP_BAR_HEIGHT } from "./TopBar";
import { IconProps } from "@cartridge/ui-next";
import { cn, IconProps } from "@cartridge/ui-next";

export type BannerProps = {
Icon?: React.ComponentType<IconProps>;
Expand All @@ -29,149 +18,115 @@ export function Banner({
description,
variant = "compressed",
}: BannerProps) {
const theme = useControllerTheme();

switch (variant) {
case "expanded":
return (
<VStack w="full" pb={6}>
<VStack
h={136}
w="full"
className="bg-[image:var(--theme-cover-url)]"
bgSize="cover"
bgPos="center"
position="relative"
mb={10}
_before={{
content: '""',
position: "absolute",
top: 0,
left: 0,
right: 0,
bottom: 0,
background: `linear-gradient(180deg, rgba(0, 0, 0, 0) 0%, var(--chakra-colors-solid-bg) 100%)`,
pointerEvents: "none",
}}
>
<Center position="absolute" bottom={-ICON_OFFSET / 4} left={4}>
<HStack w="full" gap={4} align="center">
<Flex
position="relative"
h={`${ICON_SIZE}px`}
w={`${ICON_SIZE}px`}
minW={`${ICON_SIZE}px`}
>
<Flex
position="absolute"
inset={0}
borderWidth={4}
borderColor="solid.bg"
borderRadius="lg"
/>
<Flex
bg="darkGray.700"
borderRadius="lg"
h="100%"
w="100%"
justify="center"
alignItems="center"
overflow="hidden"
>
{Icon ? (
<Circle size="100%" bg="solid.primary">
<Icon size="lg" />
</Circle>
) : icon ? (
<Circle size="100%" bg="solid.primary">
{icon}
</Circle>
) : (
<Image
src={theme.icon}
w="100%"
h="100%"
alt="Controller Icon"
objectFit="cover"
/>
)}
</Flex>
</Flex>

<VStack align="flex-start" spacing={1}>
<Text fontSize="lg" fontWeight="semibold">
{title}
</Text>

{description && (
<Text fontSize="sm" color="text.secondary">
{description}
</Text>
)}
</VStack>
</HStack>
</Center>
</VStack>
</VStack>
<div className="flex flex-col w-full h-[136px] bg-[image:var(--theme-cover-url)] bg-cover bg-center relative mb-16 before:content-[''] before:absolute before:inset-0 before:bg-gradient-to-b before:from-transparent before:to-[var(--chakra-colors-solid-bg)] before:pointer-events-none">
<div className="p-4 flex items-center gap-4 absolute -bottom-10 left-1">
<HeaderIcon variant={variant} Icon={Icon} icon={icon} />
<Headline
variant={variant}
title={title}
description={description}
/>
</div>
</div>
);
case "compressed":
default:
return (
<VStack w="full">
<HStack
h={TOP_BAR_HEIGHT / 4}
w="full"
className="bg-[image:var(--theme-cover-url)]"
bgSize="cover"
bgPos="center"
pb={6}
/>
<div className="flex flex-col">
<div className="w-full bg-[image:var(--theme-cover-url)] bg-cover bg-center h-14 pb-6" />
<div className="p-4 flex items-center gap-4">
<HeaderIcon variant={variant} Icon={Icon} icon={icon} />
<Headline
variant={variant}
title={title}
description={description}
/>
</div>
</div>
);
}
}

<HStack w="full" p={4} gap={4} minW={0}>
{Icon ? (
<Square size="44px" bg="solid.primary" borderRadius="md">
<Icon size="lg" />
</Square>
) : icon ? (
<Square size="44px" bg="solid.primary" borderRadius="md">
{icon}
</Square>
) : (
<Image
src={theme.icon}
boxSize="44px"
alt="Controller Icon"
borderRadius="md"
/>
)}
function HeaderIcon({
variant,
Icon,
icon,
}: Pick<BannerProps, "variant" | "Icon" | "icon">) {
const theme = useControllerTheme();

<VStack w="full" align="stretch" gap={1} minW={0}>
<Text
w="full"
fontSize="lg"
fontWeight="semibold"
noOfLines={1}
textOverflow="ellipsis"
>
{title}
</Text>
return (
<IconWrapper variant={variant}>
{(() => {
if (Icon) {
return <Icon />;
}

{description && (
<Text
w="full"
fontSize="xs"
color="text.secondary"
overflowWrap="break-word"
>
{description}
</Text>
)}
</VStack>
</HStack>
</VStack>
if (icon) {
return icon;
}

return (
<img
src={theme.icon}

Check warning

Code scanning / CodeQL

Client-side URL redirect Medium

Untrusted URL redirection depends on a
user-provided value
.

Check failure

Code scanning / CodeQL

Client-side cross-site scripting High

Cross-site scripting vulnerability due to
user-provided value
.
className="size-full rounded"
alt="Controller Header Icon"
/>
);
})()}
</IconWrapper>
);
}

function IconWrapper({
variant,
children,
}: {
variant?: BannerVariant;
children: React.ReactNode;
}) {
switch (variant) {
case "expanded":
return (
<div className="rounded size-20 bg-background flex items-center justify-center">
<div className="rounded bg-secondary size-[calc(100%-8px)] flex items-center justify-center">
{children}
</div>
</div>
);
default:
case "compressed":
return (
<div className="rounded size-11 flex items-center justify-center bg-secondary">
{children}
</div>
);
}
}

const ICON_SIZE = 80;
const ICON_OFFSET = 40;
function Headline({
variant,
title,
description,
}: Pick<BannerProps, "variant" | "title" | "description">) {
return (
<div className="flex-1 flex flex-col gap-1">
<div className="text-lg font-semibold line-clamp-1 text-ellipsis">
{title}
</div>

{description && (
<div
className={cn(
"text-muted-foreground break-words",
variant === "compressed" ? "text-xs" : "text-sm",
)}
>
{description}
</div>
)}
</div>
);
}
36 changes: 11 additions & 25 deletions packages/keychain/src/components/layout/container/header/TopBar.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { Spacer, HStack } from "@chakra-ui/react";
import { CloseButton } from "./CloseButton";
import { SettingsButton } from "./SettingsButton";
import { BackButton } from "./BackButton";
Expand Down Expand Up @@ -26,42 +25,29 @@ export function TopBar({
);

return (
<HStack
w="full"
zIndex="overlay"
align="center"
justify="flex-start"
flexShrink={0}
bg="transparent"
position="absolute"
top={0}
h={TOP_BAR_HEIGHT / 4}
p={2}
>
<div className="flex items-center justify-between absolute top-0 left-0 right-0 h-14 p-0.5 z-50">
{onBack ? (
<BackButton onClick={onBack} />
) : (
<CloseButton onClose={onClose} />
)}

<Spacer />
<div className="flex items-center gap-2">
{!hideNetwork && chainId && <Network chainId={chainId} />}

{!hideNetwork && chainId && <Network chainId={chainId} />}

{!hideAccount && (
<>
{/* {!!address && (
{!hideAccount && (
<>
{/* {!!address && (
<>
<EthBalance chainId={chainId} address={address} />
{chainId && <AccountMenu onLogout={onLogout} address={address} />}
</>
)} */}
</>
)}
</>
)}

{showSettings && <SettingsButton onClick={() => openSettings()} />}
</HStack>
{showSettings && <SettingsButton onClick={() => openSettings()} />}
</div>
</div>
);
}

export const TOP_BAR_HEIGHT = 56;

0 comments on commit f941f1f

Please sign in to comment.