diff --git a/src/Containers/TextBubble/TextBubble.stories.tsx b/src/Containers/TextBubble/TextBubble.stories.tsx new file mode 100644 index 000000000..9e0537ceb --- /dev/null +++ b/src/Containers/TextBubble/TextBubble.stories.tsx @@ -0,0 +1,53 @@ +import React from 'react'; +import { Meta, Story } from '@storybook/react'; +import TextBubble, { ITextBubbleProps } from './TextBubble'; +import TypingDots from '../../Text/TypingDots/TypingDots'; +import { Robot } from '@styled-icons/remix-fill/Robot'; + +export default { + title: 'Components/Text Bubble', + component: TextBubble, +} as Meta; + +const Template: Story = (args) => ( + +); + +export const Basic = Template.bind({}); +Basic.args = { + content:

Basic text bubble (other generated)

, + fromBot: true +} + +export const User = Template.bind({}); +User.args = { + content:

Basic text bubble (user generated)

, + fromBot: false +} + +export const NoText = Template.bind({}); +NoText.args = { + content:

, + fromBot: true +} + +export const Typing = Template.bind({}); +Typing.args = { + content: , + fromBot: true, + icon: Robot +} + +export const CustomStyled = Template.bind({}); +CustomStyled.args = { + content:

Text bubble with custom styles

, + fromBot: true, + bubbleStyle: { + backgroundColor: 'yellow', + borderRadius: '15px' + }, + iconStyle: { + borderRadius: '5px' + }, + icon: Robot +} diff --git a/src/Containers/TextBubble/TextBubble.tsx b/src/Containers/TextBubble/TextBubble.tsx new file mode 100644 index 000000000..c4edf515b --- /dev/null +++ b/src/Containers/TextBubble/TextBubble.tsx @@ -0,0 +1,81 @@ +import React from 'react'; +import styled from 'styled-components'; +import { Robot, User } from '@styled-icons/fa-solid/'; + +export interface ITextBubbleProps { + content: React.ReactElement; + fromBot: boolean; + icon: React.ReactElement; + iconSize: number; + iconStyle: React.HTMLAttrs; + bubbleStyle: React.HTMLAttrs; +} + +export const TextBubble = ({content, fromBot, icon, iconSize, iconStyle, bubbleStyle, ...props}: ITextBubbleProps): React.ReactElement => { + if (!icon) + icon = fromBot ? Robot : User; + + if (!iconSize) + iconSize = 25; + + return ( + + { fromBot && + + } + + + { content } + + + { !fromBot && + + } + + ); +} + +const StyledImg = styled.svg<{ imgSize: number }>` + ${({ imgSize }) => ` + width: ${imgSize}px; + height: ${imgSize}px; + `} + margin: 0 10px; + border-radius: 999px; + border-style: solid; + padding: 10px; +` + +const BubbleContainer = styled.div` + display: inline-block; +` + +const Bubble = styled.div<{ fromBot: boolean }>` + display: inline-block; + border: 1.5px solid rgba(0, 0, 0, 0.1); + padding: 0 10px; + + ${({ theme, fromBot }): string => + fromBot + ? ` + border-radius: 20px 20px 20px 5px; + background-color: ${theme.colors["background"]}; + ` + : ` + border-radius: 20px 20px 5px 20px; + background-color: ${theme.colors["primary"]}; + ` + } + + animation: appear 0.5s ease-in 1; + @keyframes appear { + from { + opacity: 0; + } + to { + opacity: 100; + } + } +`; + +export default TextBubble; diff --git a/src/Text/TypingDots/TypingDots.stories.tsx b/src/Text/TypingDots/TypingDots.stories.tsx new file mode 100644 index 000000000..0ce0153e9 --- /dev/null +++ b/src/Text/TypingDots/TypingDots.stories.tsx @@ -0,0 +1,12 @@ +import React from 'react'; +import { Meta, Story } from '@storybook/react'; +import TypingDots, { ITypingDotsProps } from './TypingDots'; + +export default { + title: 'Components/Typing Indicator Dots', + component: TypingDots +} as Meta; + +export const Basic: Story = () => ( + +); diff --git a/src/Text/TypingDots/TypingDots.tsx b/src/Text/TypingDots/TypingDots.tsx new file mode 100644 index 000000000..60fa2ffdf --- /dev/null +++ b/src/Text/TypingDots/TypingDots.tsx @@ -0,0 +1,54 @@ +import React from 'react'; +import styled from 'styled-components'; + +export interface ITypingDotsProps { + num: number; + delayStep: number; +} + +export const TypingDots = ({ num, delayStep, ...props }: ITypingDotsProps): React.ReactElement => { + + let dots = []; + + for (let i = 0; i < num; i ++) { + dots.push(); + } + + return ( + + { dots } + + ); +} + +const DotContainer = styled.div` + margin: 10px; + display: flex; + flex-direction: row; +` + +const Dot = styled.div<{ delay: number }>` + width: 10px; + height: 10px; + border-radius: 50%; + margin: 10px 5px 10px 5px; + ${({ theme }): string => ` + background-color: ${theme.colors.border}; + `} + animation: bounce 0.5s ease-in-out infinite; + animation-delay: ${p => p.delay}s; + + @keyframes bounce { + 10% { + transform: translateY(0); + } + 50% { + transform: translateY(-25%); + } + 90% { + transform: translateY(25%); + } + } +` + +export default TypingDots;