Browse Source

update Banner component (#973)

mikkio-j 3 years ago
parent
commit
62bbd99f54

+ 63 - 0
src/shared/components/Banner/Banner.style.ts

@@ -0,0 +1,63 @@
+import styled from '@emotion/styled'
+
+import { Button, Text } from '@/shared/components'
+import { colors, sizes } from '@/shared/theme'
+
+import { BannerVariant } from './Banner'
+
+type BannerProps = {
+  variant: BannerVariant
+}
+
+export const BannerHeader = styled.div`
+  width: 100%;
+  height: ${sizes(8)};
+  display: flex;
+  align-items: center;
+`
+
+export const BannerIconContainer = styled.div`
+  display: flex;
+  justify-content: center;
+  align-content: center;
+  width: ${sizes(6)};
+  height: ${sizes(6)};
+  margin-right: ${sizes(2)};
+`
+
+export const BannerTitle = styled(Text)`
+  display: flex;
+  align-items: center;
+  word-break: break-word;
+`
+
+export const BannerButtonsContainer = styled.div`
+  display: flex;
+  margin-left: auto;
+`
+
+export const BannerActionButton = styled(Button)`
+  display: flex;
+  align-items: center;
+  padding: ${sizes(2)};
+  min-width: auto;
+`
+
+export const BannerDescription = styled(Text)`
+  margin-top: ${sizes(2)};
+  line-height: ${sizes(5)};
+  color: ${colors.gray[300]};
+  word-break: break-word;
+`
+
+export const BannerWrapper = styled.div<BannerProps>`
+  position: relative;
+  padding: ${sizes(4)};
+  box-shadow: ${({ variant }) => variant === 'primary' && `inset 0 0 0 1px ${colors.gray[700]}`};
+  width: 100%;
+  background-color: ${({ variant }) =>
+    variant === 'tertiary' ? colors.gray[700] : variant === 'secondary' ? colors.blue[500] : colors.transparent};
+  ${BannerDescription} {
+    color: ${({ variant }) => variant === 'secondary' && colors.blue[200]};
+  }
+`

+ 67 - 0
src/shared/components/Banner/Banner.tsx

@@ -0,0 +1,67 @@
+import React, { ReactNode } from 'react'
+
+import { IconButton } from '@/shared/components'
+import { SvgAlertError, SvgAlertInfo, SvgAlertSuccess, SvgAlertWarning, SvgGlyphClose } from '@/shared/icons'
+
+import {
+  BannerActionButton,
+  BannerButtonsContainer,
+  BannerDescription,
+  BannerHeader,
+  BannerIconContainer,
+  BannerTitle,
+  BannerWrapper,
+} from './Banner.style'
+
+export type BannerVariant = 'primary' | 'secondary' | 'tertiary'
+
+type BannerIconType = 'success' | 'error' | 'info' | 'warning'
+
+const ICON_TYPE_TO_ICON: Record<BannerIconType, ReactNode> = {
+  info: <SvgAlertInfo />,
+  success: <SvgAlertSuccess />,
+  error: <SvgAlertError />,
+  warning: <SvgAlertWarning />,
+}
+
+export type BannerProps = {
+  title?: string
+  description?: string
+  className?: string
+  variant?: BannerVariant
+  icon?: BannerIconType
+  onExitClick: (event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void
+  actionText?: string
+  onActionClick?: (event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void
+}
+
+export const Banner: React.FC<BannerProps> = ({
+  title,
+  description,
+  className,
+  variant = 'primary',
+  icon,
+  actionText,
+  onExitClick,
+  onActionClick,
+}) => {
+  return (
+    <BannerWrapper className={className} variant={variant}>
+      <BannerHeader>
+        {icon && <BannerIconContainer>{ICON_TYPE_TO_ICON[icon]}</BannerIconContainer>}
+        <BannerTitle variant="subtitle2">{title}</BannerTitle>
+        <BannerButtonsContainer>
+          {actionText && (
+            <BannerActionButton variant="tertiary" onClick={onActionClick}>
+              {actionText}
+            </BannerActionButton>
+          )}
+          <IconButton aria-label="close dialog" onClick={onExitClick} variant="tertiary" size="small">
+            <SvgGlyphClose />
+          </IconButton>
+        </BannerButtonsContainer>
+      </BannerHeader>
+      {description && <BannerDescription variant="body2">{description}</BannerDescription>}
+    </BannerWrapper>
+  )
+}

+ 1 - 0
src/shared/components/Banner/index.ts

@@ -0,0 +1 @@
+export * from './Banner'

+ 9 - 0
src/shared/components/DismissibleMessage/DismissibleMessage.stories.tsx

@@ -21,6 +21,15 @@ export default {
       defaultValue:
         'This mean you can only access one on the device you used to create it. Clearing your browser history will delete all your drafts.',
     },
+    variant: {
+      control: { type: 'select', options: ['primary', 'secondary', 'tertiary'] },
+      defaultValue: 'primary',
+    },
+    actionText: { defaultValue: 'Action' },
+    icon: {
+      control: { type: 'select', options: [null, 'error', 'success', 'info', 'warning'] },
+      defaultValue: null,
+    },
   },
   decorators: [(Story) => <Story />],
 } as Meta

+ 0 - 38
src/shared/components/DismissibleMessage/DismissibleMessage.style.ts

@@ -1,38 +0,0 @@
-import styled from '@emotion/styled'
-
-import { SvgGlyphInfo } from '@/shared/icons'
-import { colors, sizes } from '@/shared/theme'
-
-import { IconButton } from '../IconButton'
-import { Text } from '../Text'
-
-export const MessageWrapper = styled.div`
-  position: relative;
-  padding: ${sizes(4)};
-  border: 1px solid ${colors.gray[700]};
-  width: 100%;
-  max-width: 450px;
-`
-
-export const MessageButton = styled(IconButton)`
-  position: absolute;
-  top: ${sizes(2)};
-  right: ${sizes(2)};
-`
-
-export const StyledSvgGlyphInfo = styled(SvgGlyphInfo)`
-  margin-right: ${sizes(2)};
-`
-
-export const MessageTitle = styled(Text)`
-  display: flex;
-  align-items: center;
-  word-break: break-word;
-`
-
-export const MessageDescription = styled(Text)`
-  margin-top: ${sizes(2)};
-  line-height: ${sizes(5)};
-  color: ${colors.gray[300]};
-  word-break: break-word;
-`

+ 8 - 33
src/shared/components/DismissibleMessage/DismissibleMessage.tsx

@@ -1,47 +1,22 @@
-import React, { useEffect, useState } from 'react'
+import React from 'react'
 
 import { usePersonalDataStore } from '@/providers'
-import { SvgGlyphClose } from '@/shared/icons'
 
-import {
-  MessageButton,
-  MessageDescription,
-  MessageTitle,
-  MessageWrapper,
-  StyledSvgGlyphInfo,
-} from './DismissibleMessage.style'
+import { Banner, BannerProps } from '../Banner'
 
 export type DismissibleMessageProps = {
-  title?: string
-  description?: string
   id: string
-  className?: string
-}
+} & Omit<BannerProps, 'onExitClick'>
 
-export const DismissibleMessage: React.FC<DismissibleMessageProps> = ({ title, description, id, className }) => {
-  const dismissedMessages = usePersonalDataStore((state) => state.dismissedMessages)
+export const DismissibleMessage: React.FC<DismissibleMessageProps> = ({ id, ...dismissedMessageProps }) => {
+  const isDismissedMessage = usePersonalDataStore((state) =>
+    state.dismissedMessages.some((message) => message.id === id)
+  )
   const updateDismissedMessages = usePersonalDataStore((state) => state.actions.updateDismissedMessages)
-  const [isDismissedMessage, setDismissedMessage] = useState<boolean>()
-
-  useEffect(() => {
-    const isDissmised = dismissedMessages.some((channel) => channel.id === id)
-    setDismissedMessage(isDissmised)
-  }, [dismissedMessages, id])
 
   if (isDismissedMessage) {
     return null
   }
 
-  return (
-    <MessageWrapper className={className}>
-      <MessageTitle variant="subtitle2">
-        <StyledSvgGlyphInfo />
-        {title}
-      </MessageTitle>
-      <MessageButton aria-label="close dialog" onClick={() => updateDismissedMessages(id)} variant="tertiary">
-        <SvgGlyphClose />
-      </MessageButton>
-      <MessageDescription variant="body2">{description}</MessageDescription>
-    </MessageWrapper>
-  )
+  return <Banner {...dismissedMessageProps} onExitClick={() => updateDismissedMessages(id)} />
 }

+ 1 - 0
src/shared/components/index.ts

@@ -29,6 +29,7 @@ export * from './Select'
 export * from './TextField'
 export * from './Checkbox'
 export * from './TextArea'
+export * from './Banner'
 export * from './DismissibleMessage'
 export * from './ActionBar'
 export * from './MultiFileSelect'

+ 9 - 0
src/views/studio/MyVideosView/MyVideosView.tsx

@@ -270,9 +270,18 @@ export const MyVideosView = () => {
               <StyledDismissibleMessage
                 id="video-draft-saved-locally-warning"
                 title="Video drafts are saved locally"
+                icon="info"
                 description="You will only be able to access drafts on the device you used to create them. Clearing your browser history will delete all your drafts."
               />
             )}
+            {currentTabName === 'Unlisted' && (
+              <StyledDismissibleMessage
+                id="unlisted-video-link-info"
+                title="Unlisted videos can be seen only with direct link"
+                icon="info"
+                description="You can share a private video with others by sharing a direct link to it. Unlisted video is not going to be searchable on our platform."
+              />
+            )}
             <Grid maxColumns={null} onResize={handleOnResizeGrid}>
               {gridContent}
             </Grid>