Skip to content

Commit

Permalink
feat: Card ribbon (#52)
Browse files Browse the repository at this point in the history
* feat: Card ribbon

* fix: Circular dependency problem

* build: Card folder structure

* chore: Updated stories, comments

* refactor: Moved Pancake theme out of types to avoid circular dependencies
  • Loading branch information
hachiojidev authored Nov 12, 2020
1 parent 5d5db86 commit 257a49c
Show file tree
Hide file tree
Showing 11 changed files with 194 additions and 72 deletions.
13 changes: 13 additions & 0 deletions src/components/Card/Card.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import React from "react";
import StyledCard from "./StyledCard";
import { CardProps } from "./types";

const Card: React.FC<CardProps> = ({ ribbon, children, ...props }) => {
return (
<StyledCard {...props}>
{ribbon}
{children}
</StyledCard>
);
};
export default Card;
58 changes: 58 additions & 0 deletions src/components/Card/CardRibbon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import React from "react";
import styled, { DefaultTheme } from "styled-components";
import { CardRibbonProps } from "./types";

interface StyledCardRibbonProps extends CardRibbonProps {
theme: DefaultTheme;
}

const StyledCardRibbon = styled.div<Partial<StyledCardRibbonProps>>`
background-color: ${({ variantColor = "secondary", theme }) => theme.colors[variantColor]};
color: white;
margin: 0;
padding: 0;
padding: 8px 0;
position: absolute;
right: 0;
top: 0;
text-align: center;
transform: translateX(30%) translateY(0%) rotate(45deg);
transform-origin: top left;
width: 112px;
&:before,
&:after {
background-color: ${({ variantColor = "secondary", theme }) => theme.colors[variantColor]};
content: "";
height: 100%;
margin: 0 -1px; /* Removes tiny gap */
position: absolute;
top: 0;
width: 100%;
}
&:before {
right: 100%;
}
&:after {
left: 100%;
}
& > div {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
width: 112px;
}
`;

const CardRibbon: React.FC<CardRibbonProps> = ({ variantColor, text }) => {
return (
<StyledCardRibbon variantColor={variantColor}>
<div title={text}>{text}</div>
</StyledCardRibbon>
);
};

export default CardRibbon;
44 changes: 44 additions & 0 deletions src/components/Card/StyledCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import styled, { DefaultTheme } from "styled-components";
import { CardProps } from "./types";

interface StyledCardProps extends CardProps {
theme: DefaultTheme;
}

/**
* Priority: Warning --> Success --> Active
*/
const getBoxShadow = ({ isActive, isSuccess, isWarning, theme }: StyledCardProps) => {
if (isWarning) {
return theme.card.boxShadowWarning;
}

if (isSuccess) {
return theme.card.boxShadowSuccess;
}

if (isActive) {
return theme.card.boxShadowActive;
}

return theme.card.boxShadow;
};

const StyledCard = styled.div<StyledCardProps>`
background-color: ${({ theme }) => theme.card.background};
border: ${({ theme }) => theme.card.boxShadow};
border-radius: 32px;
box-shadow: ${getBoxShadow};
color: ${({ theme }) => theme.colors.text};
overflow: hidden;
padding: 24px;
position: relative;
`;

StyledCard.defaultProps = {
isActive: false,
isSuccess: false,
isWarning: false,
};

export default StyledCard;
30 changes: 29 additions & 1 deletion src/components/Card/index.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import React from "react";
import styled from "styled-components";
/* eslint-disable import/no-unresolved */
import { Meta } from "@storybook/react/types-6-0";
import Card from "./index";
import CardRibbon from "./CardRibbon";
import Card from "./Card";

const Row = styled.div`
margin-bottom: 32px;
Expand Down Expand Up @@ -36,3 +37,30 @@ export const Default: React.FC = () => {
</div>
);
};

export const Ribbon: React.FC = () => {
return (
<div style={{ padding: "32px", width: "500px" }}>
<Row>
<Card ribbon={<CardRibbon text="Ribbon" />}>
<div style={{ height: "200px" }}>Card with Ribbon</div>
</Card>
</Row>
<Row>
<Card ribbon={<CardRibbon variantColor="textDisabled" text="Ribbon with Long Text" />}>
<div style={{ height: "150px" }}>Ribbons will truncate when text is too long</div>
</Card>
</Row>
<Row>
<Card ribbon={<CardRibbon variantColor="success" text="Success" />}>
<div style={{ height: "200px" }}>Card</div>
</Card>
</Row>
<Row>
<Card ribbon={<CardRibbon variantColor="failure" text="Failure" />}>
<div style={{ height: "200px" }}>Any Color in the theme</div>
</Card>
</Row>
</div>
);
};
47 changes: 2 additions & 45 deletions src/components/Card/index.tsx
Original file line number Diff line number Diff line change
@@ -1,45 +1,2 @@
import styled, { DefaultTheme } from "styled-components";

interface CardProps {
isActive?: boolean;
isSuccess?: boolean;
isWarning?: boolean;
theme: DefaultTheme;
}

/**
* Priority: Warning --> Success --> Active
*/
const getBoxShadow = ({ isActive, isSuccess, isWarning, theme }: CardProps) => {
if (isWarning) {
return theme.card.boxShadowWarning;
}

if (isSuccess) {
return theme.card.boxShadowSuccess;
}

if (isActive) {
return theme.card.boxShadowActive;
}

return theme.card.boxShadow;
};

const Card = styled.div<CardProps>`
background-color: ${({ theme }) => theme.card.background};
border: ${({ theme }) => theme.card.boxShadow};
border-radius: 32px;
box-shadow: ${getBoxShadow};
color: ${({ theme }) => theme.colors.text};
padding: 24px;
margin: 2px;
`;

Card.defaultProps = {
isActive: false,
isSuccess: false,
isWarning: false,
};

export default Card;
export { default as Card } from "./Card";
export { default as CardRibbon } from "./CardRibbon";
9 changes: 8 additions & 1 deletion src/components/Card/theme.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
import { shadows } from "../../theme/base";
import { CardTheme } from "./types";

export type CardTheme = {
background: string;
boxShadow: string;
boxShadowActive: string;
boxShadowSuccess: string;
boxShadowWarning: string;
};

export const light: CardTheme = {
background: "#FFFFFF",
Expand Down
14 changes: 14 additions & 0 deletions src/components/Card/types.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,21 @@
import { Colors } from "../../theme/types";

export interface CardRibbonProps {
variantColor?: keyof Colors;
text: string;
}

export type CardTheme = {
background: string;
boxShadow: string;
boxShadowActive: string;
boxShadowSuccess: string;
boxShadowWarning: string;
};

export interface CardProps {
isActive?: boolean;
isSuccess?: boolean;
isWarning?: boolean;
ribbon?: React.ReactNode;
}
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
export { default as Button } from "./components/Button";
export { default as ButtonMenu } from "./components/ButtonMenu";
export { default as ButtonMenuItem } from "./components/ButtonMenu/ButtonMenuItem";
export { default as Card } from "./components/Card";
export { default as Checkbox } from "./components/Checkbox";
export { default as Heading } from "./components/Heading";
export * from "./components/Card";
export * from "./components/Layouts";
export * from "./components/Svg";
export { default as Tag } from "./components/Tag";
Expand Down
2 changes: 1 addition & 1 deletion src/styled.d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import "styled-components";
import { PancakeTheme } from "./theme/types";
import { PancakeTheme } from "./theme";

declare module "styled-components" {
/* eslint-disable @typescript-eslint/no-empty-interface */
Expand Down
24 changes: 24 additions & 0 deletions src/theme/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,27 @@
import { ButtonTheme } from "../components/Button/types";
import { CardTheme } from "../components/Card/types";
import { TagTheme } from "../components/Tag/types";
import { ToggleTheme } from "../components/Toggle/types";
import { NavTheme } from "../widgets/Nav/types";
import { Colors, Breakpoints, MediaQueries, Spacing, Shadows, Radii, ZIndices } from "./types";

export interface PancakeTheme {
siteWidth: number;
isDark: boolean;
colors: Colors;
button: ButtonTheme;
card: CardTheme;
tag: TagTheme;
nav: NavTheme;
toggle: ToggleTheme;
breakpoints: Breakpoints;
mediaQueries: MediaQueries;
spacing: Spacing;
shadows: Shadows;
radii: Radii;
zIndices: ZIndices;
}

export { default as dark } from "./dark";
export { default as light } from "./light";

Expand Down
23 changes: 0 additions & 23 deletions src/theme/types.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,3 @@
import { ButtonTheme } from "../components/Button/types";
import { CardTheme } from "../components/Card/types";
import { TagTheme } from "../components/Tag/types";
import { ToggleTheme } from "../components/Toggle/types";
import { NavTheme } from "../widgets/Nav/types";

export type Breakpoints = string[];

export type MediaQueries = {
Expand Down Expand Up @@ -54,20 +48,3 @@ export type ZIndices = {
dropdown: number;
modal: number;
};

export interface PancakeTheme {
siteWidth: number;
isDark: boolean;
colors: Colors;
button: ButtonTheme;
card: CardTheme;
tag: TagTheme;
nav: NavTheme;
toggle: ToggleTheme;
breakpoints: Breakpoints;
mediaQueries: MediaQueries;
spacing: Spacing;
shadows: Shadows;
radii: Radii;
zIndices: ZIndices;
}

0 comments on commit 257a49c

Please sign in to comment.