Skip to content

Commit

Permalink
feat(manager-react-component): add manager tile component
Browse files Browse the repository at this point in the history
It's a duplicated of dashboard tile but with a Compound components pattern

Signed-off-by: Thibault Barske <[email protected]>
  • Loading branch information
tibs245 committed Jan 23, 2025
1 parent c8ff2f5 commit a5fd7a7
Show file tree
Hide file tree
Showing 4 changed files with 215 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import React from 'react';

export type TileBlockProps = React.PropsWithChildren<{
label?: string;
}>;

export const ManagerTileItem = ({ children }: React.PropsWithChildren) => {
return <dl className="flex flex-col gap-y-[8px] my-0">{children}</dl>;
};

const ManagerTileItemLabel = ({ children }: React.PropsWithChildren) => {
return (
<dt className="tile-block-title m-0 text-[--ods-color-heading] text-[16px] leading-[16px] font-semibold">
{children}
</dt>
);
};

const ManagerTileItemDescription = ({ children }: React.PropsWithChildren) => {
return (
<dt className="tile-block-title m-0 text-[--ods-color-heading] text-[16px] leading-[16px] font-semibold">
{children}
</dt>
);
};

ManagerTileItem.Label = ManagerTileItemLabel;
ManagerTileItem.Description = ManagerTileItemDescription;
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import React from 'react';
import { OdsDivider, OdsCard } from '@ovhcloud/ods-components/react';
import { ODS_CARD_COLOR } from '@ovhcloud/ods-components';
import { ManagerTileItem } from './manager-tile-item.component';

export type ManagerTileProps = React.ComponentProps<typeof OdsCard>;

export const ManagerTile = ({
className,
children,
...props
}: ManagerTileProps) => {
return (
<OdsCard
className={`w-full flex-col p-[1rem] ${className}`}
color={ODS_CARD_COLOR.neutral}
{...props}
>
<div className="flex flex-col w-full">{children}</div>
</OdsCard>
);
};

type ManagerTileTitleProps = React.PropsWithChildren;
const ManagerTileTitle = ({ children }: ManagerTileTitleProps) => {
return (
<h4 className="dashboard-tile-title m-0 text-[--ods-color-heading] text-[20px] leading-[28px] font-bold">
{children}
</h4>
);
};

const ManagerTileDivider = () => <OdsDivider spacing="24" />;

ManagerTile.Title = ManagerTileTitle;
ManagerTile.Item = ManagerTileItem;
ManagerTile.Divider = ManagerTileDivider;
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import React, { useId } from 'react';
import { Meta } from '@storybook/react';
import { OdsSkeleton } from '@ovhcloud/ods-components/react';
import { ManagerTile } from './manager-tile.component';
import ActionMenu from '../../navigation/menus/action/action.component';

const actionItems = [
{
id: 1,
href: 'https://ovhcloud.com',
label: 'Action 1',
},
{
id: 2,
onClick: () => window.open('https://ovhcloud.com', '_blank', 'noopener'),
label: 'Action 2',
},
];

export const CompleteExample = () => {
const id = useId();
return (
<ManagerTile>
<ManagerTile.Title>Complete example</ManagerTile.Title>
<ManagerTile.Divider />
<ManagerTile.Item>
<ManagerTile.Item.Label>Component Example</ManagerTile.Item.Label>
<ManagerTile.Item.Description>
<span>Test</span>
</ManagerTile.Item.Description>
</ManagerTile.Item>
<ManagerTile.Divider />
<ManagerTile.Item>
<ManagerTile.Item.Label>Loading</ManagerTile.Item.Label>
<ManagerTile.Item.Description>
<OdsSkeleton />
</ManagerTile.Item.Description>
</ManagerTile.Item>
<ManagerTile.Divider />
<ManagerTile.Item>
<ManagerTile.Item.Label>Text Directly</ManagerTile.Item.Label>
<ManagerTile.Item.Description>
Text example
</ManagerTile.Item.Description>
</ManagerTile.Item>
<ManagerTile.Divider />
<ManagerTile.Item>
<ManagerTile.Item.Label>Menu Example</ManagerTile.Item.Label>
<ManagerTile.Item.Description>
<span>
<div className="flex">
<div className="mr-auto">Test value</div>
<ActionMenu isCompact items={actionItems} id={id} />
</div>
</span>
</ManagerTile.Item.Description>
</ManagerTile.Item>
<ManagerTile.Divider />
<ManagerTile.Item>
<ManagerTile.Item.Label>Component Example</ManagerTile.Item.Label>
<ManagerTile.Item.Description>
<span>Test</span>
</ManagerTile.Item.Description>
</ManagerTile.Item>
</ManagerTile>
);
};

export const SimpleExampleWithTitle = () => (
<ManagerTile>
<ManagerTile.Title>Sample example with title</ManagerTile.Title>
<ManagerTile.Divider />
<ManagerTile.Item>
<ManagerTile.Item.Label>Component Example</ManagerTile.Item.Label>
<ManagerTile.Item.Description>Test</ManagerTile.Item.Description>
</ManagerTile.Item>
<ManagerTile.Divider />
<ManagerTile.Item>
<ManagerTile.Item.Label>Loading</ManagerTile.Item.Label>
<ManagerTile.Item.Description>
<OdsSkeleton />
</ManagerTile.Item.Description>
</ManagerTile.Item>
</ManagerTile>
);

export const NoTitle = () => (
<ManagerTile>
<ManagerTile.Item>
<ManagerTile.Item.Label>Component Example</ManagerTile.Item.Label>
<ManagerTile.Item.Description>Test</ManagerTile.Item.Description>
</ManagerTile.Item>
<ManagerTile.Divider />
<ManagerTile.Item>
<ManagerTile.Item.Label>Loading</ManagerTile.Item.Label>
<ManagerTile.Item.Description>
<OdsSkeleton />
</ManagerTile.Item.Description>
</ManagerTile.Item>
</ManagerTile>
);

const meta: Meta = {
title: 'Content/Manager Tile',
component: ManagerTile,
argTypes: {},
args: {},
};

export default meta;
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { waitFor, screen } from '@testing-library/react';

const testItem = {
id: 'id',
label: 'label',
value: 'value',
};

describe.skip('Dashboard Tile component', () => {
it('renders correctly', async () => {
await waitFor(() => {
expect(screen.getByText('Title')).toBeInTheDocument();
expect(screen.getByText(testItem.value)).toBeInTheDocument();
expect(screen.getByText(testItem.label)).toBeInTheDocument();
expect(screen.queryByText(testItem.id)).not.toBeInTheDocument();
});
});

it('renders correctly without items', async () => {
await waitFor(() => {
expect(screen.getByText('Title 2')).toBeInTheDocument();
});
});

it('renders correctly without title', async () => {
await waitFor(() => {
expect(screen.getByText(testItem.value)).toBeInTheDocument();
expect(screen.getByText(testItem.label)).toBeInTheDocument();
expect(screen.queryByText(testItem.id)).not.toBeInTheDocument();
});
});

it('renders correctly without label', async () => {
await waitFor(() => {
expect(screen.getByText(testItem.value)).toBeInTheDocument();
expect(screen.queryByText(testItem.label)).not.toBeInTheDocument();
expect(screen.queryByText(testItem.id)).not.toBeInTheDocument();
});
});
});

0 comments on commit a5fd7a7

Please sign in to comment.