Skip to content

Commit

Permalink
feat: add cardgrid component and docs
Browse files Browse the repository at this point in the history
  • Loading branch information
becomevocal committed Jul 15, 2024
1 parent e8d6302 commit 321b35c
Show file tree
Hide file tree
Showing 9 changed files with 407 additions and 1 deletion.
4 changes: 3 additions & 1 deletion packages/examples-site/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { AlertsManager, createAlertsManager } from "@bigcommerce/big-design";
import PageCRUDList from "./pages/CRUDListPage/CRUDListPage";
import PageCRUDAddEdit from "./pages/CRUDAddEditPage/CRUDAddEditPage";
import PageAnchorNav from "./pages/AnchorNavPage/AnchorNavPage";
import CardGridPage from "./pages/CardGridPage";

export const alertsManager = createAlertsManager();

Expand All @@ -28,7 +29,8 @@ const RouteFC = () => {
{ path: "/page-crud-list", element: <PageCRUDList /> },
{ path: "/page-crud-add", element: <PageCRUDAddEdit /> },
{ path: "/page-crud-edit/:sku", element: <PageCRUDAddEdit /> },
{ path: "/page-anchor-nav", element: <PageAnchorNav />}
{ path: "/page-anchor-nav", element: <PageAnchorNav />},
{ path: "/cardgrid", element: <CardGridPage />}
]);
return routes;
};
Expand Down
243 changes: 243 additions & 0 deletions packages/examples-site/src/pages/CardGridPage/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,243 @@
import React, { FunctionComponent } from "react";
import { Flex, FlexItem, Text, HR, Table } from "@bigcommerce/big-design";
import {
CardGrid,
Page,
AdvancedPanel as Panel,
} from "bigcommerce-design-patterns";
import { useNavigate } from "react-router";
import { theme } from "@bigcommerce/big-design-theme";

import { CopyBlock, nord as codecolor } from "react-code-blocks";

const CardGridPage: FunctionComponent = () => {
const navigate = useNavigate();

const copyBlockProps = {
language: "jsx",
showLineNumbers: true,
startingLineNumber: 1,
wrapLines: true,
theme: codecolor,
customStyle: {
width: "100%",
minHeight: "45px",
},
};

return (
<Page
headerTitle="Card Grids"
headerBackButtonLabel="Back to patterns"
onHeaderBackButtonClick={() => navigate("/")}
pageDescription={
<Text color="secondary60">
Card grids are used to showcase relevant resources or actions in a condensed,
organized manner.
</Text>
}
>
<Flex flexDirection="column" flexGap={theme.spacing.xLarge}>
<Panel headerTitle="Example: Content">
<Flex flexDirection="column" flexGap={theme.spacing.medium}>
<FlexItem>
<CardGrid
items={[
{
name: "Helpful resource one",
description:
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean euismod bibendum laoreet. ",
href: "https://developer.bigcommerce.com",
},
{
name: "Helpful resource two",
description:
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean euismod bibendum laoreet. ",
href: "https://developer.bigcommerce.com",
},
]}
/>
</FlexItem>
<FlexItem>
<HR />
</FlexItem>
<FlexItem>
<CopyBlock
{...copyBlockProps}
text={`import { CardGrid } from "bigcommerce-design-patterns";
<CardGrid items={[
{
name: "Helpful resource one",
description:
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean euismod bibendum laoreet. ",
href: "https://developer.bigcommerce.com",
},
{
name: "Helpful resource two",
description:
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean euismod bibendum laoreet. ",
href: "https://developer.bigcommerce.com",
},
]} />`}
/>
</FlexItem>
</Flex>
</Panel>

<Panel headerTitle="Example: Actions">
<Flex flexDirection="column" flexGap={theme.spacing.medium}>
<FlexItem>
<CardGrid
items={[
{
name: "Grid Item 1",
description:
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean euismod bibendum laoreet. Proin gravida dolor sit amet.",
button: {
variant: "primary",
text: "Connect",
},
icon: (
<img
src="https://storage.googleapis.com/bigcommerce-developers/images/bigc-dev/bigc-inverted-black.svg"
height="45"
width="45"
/>
),
format: "action",
},
{
name: "Grid Item 2",
description:
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean euismod bibendum laoreet. Proin gravida dolor sit amet.",
button: {
variant: "primary",
text: "Connect",
},
icon: (
<img
src="https://storage.googleapis.com/bigcommerce-developers/images/bigc-dev/bigc-inverted-black.svg"
height="45"
width="45"
/>
),
format: "action",
},
]}
/>
</FlexItem>
<FlexItem>
<HR />
</FlexItem>
<FlexItem>
<CopyBlock
{...copyBlockProps}
text={`import { CardGrid } from "bigcommerce-design-patterns";
<CardGrid items={[
{
name: "Grid Item 1",
description:
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean euismod bibendum laoreet.",
button: {
variant: "primary",
text: "Connect",
},
icon: (
<img
src="https://storage.googleapis.com/bigcommerce-developers/logos/bigcommerce-dx.svg"
height="45"
width="45"
/>
),
format: "action",
},
{
name: "Grid Item 2",
description:
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean euismod bibendum laoreet.",
button: {
variant: "primary",
text: "Connect",
},
icon: (
<img
src="https://storage.googleapis.com/bigcommerce-developers/logos/bigcommerce-dx.svg"
height="45"
width="45"
/>
),
format: "action",
},
]} />`}
/>
</FlexItem>
</Flex>
</Panel>
<Panel headerTitle="Example: Skeleton">
<Flex flexDirection="column" flexGap={theme.spacing.medium}>
<FlexItem>
<CardGrid />
</FlexItem>
<FlexItem>
<HR />
</FlexItem>
<FlexItem>
<CopyBlock
{...copyBlockProps}
text={`import { CardGrid } from "bigcommerce-design-patterns";
<CardGrid />`}
/>
</FlexItem>
</Flex>
</Panel>

<Panel headerTitle="Props" contentsPadding={false}>
<Table
columns={[
{
header: "Prop Name",
hash: "propName",
render: ({ propName }) => propName,
},
{
header: "Type",
hash: "type",
render: ({ type }) => type,
},
{
header: "Default",
hash: "default",
render: ({ default: defaultValue }) => defaultValue.toString(),
},
{
header: "Description",
hash: "description",
render: ({ description }) => description,
},
{
header: "Required",
hash: "required",
render: ({ required }) => (required ? "Yes" : "No"),
},
]}
items={[
{
propName: "items",
type: "array",
default: "-",
description: "Array of entries for content or actions. See above for examples for each. If you don't include the items prop, a loading skeleton will render.",
required: false,
},
]}
stickyHeader
/>
</Panel>
</Flex>
</Page>
);
};

export default CardGridPage;
3 changes: 3 additions & 0 deletions packages/examples-site/src/pages/Home/Home.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ const PageHome: FunctionComponent = () => {
<li>
<Link to={"/info-illustration"}>Info Illustrations</Link>
</li>
<li>
<Link to={"/cardgrid"}>Card Grid</Link>
</li>
</ul>
</Page>
);
Expand Down
1 change: 1 addition & 0 deletions packages/patterns/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"@bigcommerce/big-design-icons": "^0.24.0",
"@bigcommerce/big-design-theme": "^0.19.2",
"react": "^18.0.0",
"react-loading-skeleton": "^3.4.0",
"styled-components": "^5.3.11"
},
"devDependencies": {
Expand Down
115 changes: 115 additions & 0 deletions packages/patterns/src/components/CardGrid/CardGrid.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import Skeleton from "react-loading-skeleton";
import "react-loading-skeleton/dist/skeleton.css";
import {
Box,
Button,
Grid,
Text,
Flex,
FlexItem,
} from "@bigcommerce/big-design";
import { ChevronRightIcon } from "@bigcommerce/big-design-icons";
import { StyledLinkBox, StyledLink } from "./styled";

export type CardGridItem = {
button?: {
variant: "primary" | "secondary" | "subtle" | "danger";
text: string;
};
name?: string;
description?: string;
format?: string;
href?: string;
icon?: React.ReactNode;
};

function CardGridItem({
button,
name,
description,
format = "content",
href,
icon,
}: CardGridItem) {
if (format === "action") {
return (
<Box border="box" borderRadius="normal" padding="medium">
<Flex flexGap="16px" flexDirection="row">
<FlexItem>
{icon ? icon : <Skeleton width={45} height={45} />}
</FlexItem>
<FlexItem flexGrow={1}>
<Text bold>{name ?? <Skeleton width={150} />}</Text>
</FlexItem>
<FlexItem>
{button ? (
<Button
variant="secondary"
onClick={() => {
alert(`${name} clicked`);
}}
>
{button.text}
</Button>
) : (
<Skeleton height={36} width={100} />
)}
</FlexItem>
</Flex>

<Text marginTop="medium">{description ?? <Skeleton count={2} />}</Text>
</Box>
);
}

// Default format is "content"
const itemContent = (
<>
<Flex flexGap="16px" flexDirection="row">
<FlexItem flexGrow={1}>
<Text bold>{name ?? <Skeleton width={150} />}</Text>
</FlexItem>
<FlexItem>
{name ? <ChevronRightIcon /> : <Skeleton width={24} />}
</FlexItem>
</Flex>

<Text marginTop="medium">{description ?? <Skeleton count={2} />}</Text>
</>
);
return href ? (
<StyledLink target="_blank" href={href}>
<StyledLinkBox border="box" borderRadius="normal" padding="medium">
{itemContent}
</StyledLinkBox>
</StyledLink>
) : (
<Box border="box" borderRadius="normal" padding="medium">
{itemContent}
</Box>
);
}

export function CardGrid({
items,
format,
}: {
items?: CardGridItem[];
format?: "content" | "action";
}) {
return (
<Grid
gridColumns={{ mobile: "repeat(1, 1fr)", tablet: "repeat(2, 1fr)" }}
gridGap="16px"
>
{items ? (
items.map((item) => <CardGridItem format={format} {...item} />)
) : (
<>
<CardGridItem format={format} />
<CardGridItem format={format} />
</>
)}
</Grid>
);
}
1 change: 1 addition & 0 deletions packages/patterns/src/components/CardGrid/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { CardGrid, type CardGridItem } from './CardGrid';
Loading

0 comments on commit 321b35c

Please sign in to comment.