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:
       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.',
         '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 />],
   decorators: [(Story) => <Story />],
 } as Meta
 } 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 { 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 = {
 export type DismissibleMessageProps = {
-  title?: string
-  description?: string
   id: 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 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) {
   if (isDismissedMessage) {
     return null
     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 './TextField'
 export * from './Checkbox'
 export * from './Checkbox'
 export * from './TextArea'
 export * from './TextArea'
+export * from './Banner'
 export * from './DismissibleMessage'
 export * from './DismissibleMessage'
 export * from './ActionBar'
 export * from './ActionBar'
 export * from './MultiFileSelect'
 export * from './MultiFileSelect'

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

@@ -270,9 +270,18 @@ export const MyVideosView = () => {
               <StyledDismissibleMessage
               <StyledDismissibleMessage
                 id="video-draft-saved-locally-warning"
                 id="video-draft-saved-locally-warning"
                 title="Video drafts are saved locally"
                 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."
                 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}>
             <Grid maxColumns={null} onResize={handleOnResizeGrid}>
               {gridContent}
               {gridContent}
             </Grid>
             </Grid>