Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add empty state component #179

Merged
merged 3 commits into from
Nov 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 32 additions & 18 deletions apps/www/content/primitives/components/emptystate.mdx
Original file line number Diff line number Diff line change
@@ -1,21 +1,20 @@
---
title: Empty State
description:
description:
---

## Preview

<Preview>
<Flex
style={{
flexDirection: "column",
alignItems: "center",
gap: "8px",
}}
>
<EmptyState>
<Title>No Design Systems</Title>
<Text>You can create a new Design System by clicking the button.</Text>
</EmptyState>
<Flex direction="column" align="center">
<EmptyState
icon={<InfoCircledIcon />}
heading="Looking for new components"
subHeading="Check out new components in @raystack/apsara"
primaryAction={<Button>Primary Action</Button>}
secondaryAction={<Button variant="text">Secondary Action</Button>}
/>

</Flex>
</Preview>

Expand All @@ -24,20 +23,35 @@ description:
Install the component from your command line.

<LiveProvider>
<LiveEditor code={`npm install @raystack/apsara`} border/>
<LiveEditor code={`npm install @raystack/apsara`} border />
</LiveProvider>

## Props

The `Flex` component accepts the following props:

- `icon`: Icon to show in top of empty state
- `heading`: primary heading message
- `subHeading`: secondary heading message
- `primaryAction`: action to show in empty state like button or link
- `secondaryAction`: secondary action to show in empty state like button or link
- `classNames`: Map of className with internal components
- `container`
- `iconContainer`
- `icon`
- `heading`
- `subHeading`

## Anatomy

Import all parts and piece them together.

<LiveProvider>
<LiveEditor code={`
import { EmptyState } from '@raystack/apsara'
import { EmptyState } from '@raystack/apsara/v1'

<EmptyState headerText="Looking for new components" />

<EmptyState style={{ marginTop: 160 }}>
<h3>No Design Systems</h3>
<p>You can create a new Design System by clicking the button.</p>
</EmptyState>
`} border />

</LiveProvider>
6 changes: 5 additions & 1 deletion apps/www/utils/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,11 @@ export const primitivesRoutes = [
slug: "docs/primitives/components/dropdownmenu",
newBadge: true,
},
{ title: "Empty State", slug: "docs/primitives/components/emptystate" },
{
title: "Empty State",
slug: "docs/primitives/components/emptystate",
newBadge: true,
},
{ title: "ErrorState", slug: "docs/primitives/components/errorstate" },
{
title: "Flex",
Expand Down
3 changes: 3 additions & 0 deletions packages/raystack/emptystate/emptystate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ const emptystate = cva(styles.emptystate);
type EmptystateProps = PropsWithChildren<VariantProps<typeof emptystate>> &
HTMLAttributes<HTMLElement>;

/**
* @deprecated Use EmptyState from '@raystack/apsara/v1' instead.
*/
export function EmptyState({ children, className, ...props }: EmptystateProps) {
return (
<div className={emptystate({ className })} {...props}>
Expand Down
53 changes: 53 additions & 0 deletions packages/raystack/v1/components/emptystate/emptystate.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
.emptyState {
padding: var(--rs-space-9) var(--rs-space-5);
width: 100%;
height: 100%;
text-align: center;
}

.iconContainer {
position: relative;
z-index: 2;
}

.icon {
height: 32px;
width: 32px;
padding: var(--rs-space-3);
box-sizing: content-box;
border: 1px solid var(--rs-color-border-base-primary);
background-color: var(--rs-color-background-base-secondary);
border-radius: var(--rs-radius-4);
color: var(--rs-color-text-base-secondary);
box-shadow: 0px 1px 4px 0px rgba(0, 0, 0, 0.08),
0px -3px 0px 0px rgba(0, 0, 0, 0.03) inset;
}

.icon > svg {
fill: currentColor;
height: 100%;
width: 100%;
}

.icon::before {
content: "";
position: absolute;
height: 100%;
width: 100%;
top: -10px;
left: calc(50% - 15px);
border: inherit;
border-radius: inherit;
background-color: inherit;
z-index: -10;
transform: rotate(-42deg);
box-shadow: 0px -1.5px 0px 0px rgba(0, 0, 0, 0.02) inset;
}

.headerText {
max-width: 360px;
}

.subHeaderText {
max-width: 288px;
}
70 changes: 70 additions & 0 deletions packages/raystack/v1/components/emptystate/emptystate.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { cva } from "class-variance-authority";
import styles from "./emptystate.module.css";
const emptystate = cva(styles.emptystate);
import { Flex } from "../flex";
import { Text } from "../text";
import clsx from "clsx";

type classNameKeys =
| "container"
| "iconContainer"
| "icon"
| "heading"
| "subHeading";

interface EmptystateProps {
icon: React.ReactNode;
heading?: React.ReactNode;
subHeading?: React.ReactNode;
primaryAction?: React.ReactNode;
secondaryAction?: React.ReactNode;
classNames?: Partial<Record<classNameKeys, string>>;
}

export const EmptyState = ({
icon,
heading,
subHeading,
primaryAction,
secondaryAction,
classNames,
}: EmptystateProps) => {
return (
<Flex
direction="column"
align="center"
gap="medium"
className={clsx(styles.emptyState, classNames?.container)}
>
<div className={clsx(styles.iconContainer, classNames?.iconContainer)}>
<div className={clsx(styles.icon, classNames?.icon)}>{icon}</div>
</div>

<Flex direction="column" gap="small" align="center">
{heading && (
<Text
size={5}
weight={500}
className={clsx(styles.headerText, classNames?.heading)}
>
{heading}
</Text>
)}

{subHeading && (
<Text
size={4}
weight={400}
className={clsx(styles.subHeaderText, classNames?.subHeading)}
>
{subHeading}
</Text>
)}
</Flex>

{primaryAction}

{secondaryAction}
</Flex>
);
};
1 change: 1 addition & 0 deletions packages/raystack/v1/components/emptystate/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { EmptyState } from "./emptystate";
2 changes: 2 additions & 0 deletions packages/raystack/v1/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ export { ToastContainer, toast } from "./components/toast";
export { DropdownMenu } from "./components/dropdownMenu";
export { Text } from "./components/text";
export { Flex } from "./components/flex";
export { EmptyState } from "./components/emptystate";

export {
ThemeProvider,
ThemeProviderProps,
Expand Down