Redesign notifications

This commit is contained in:
viktorstrate
2021-07-18 15:04:06 +02:00
parent de685f28f5
commit 5fb6b432af
10 changed files with 97 additions and 95 deletions

View File

@@ -117,10 +117,6 @@ const LoginForm = () => {
)
}
// background-image: radial-gradient(0% 100%, #FF8246 0%, #D6264D 100%);
// border: 2px solid rgba(255,51,0,0.29);
// border-radius: 6px;
type LoginInputs = {
username: string
password: string

View File

@@ -1,7 +1,6 @@
import { gql } from '@apollo/client'
import { saveTokenCookie } from '../../helpers/authentication'
import styled from 'styled-components'
// import { Container as SemanticContainer } from 'semantic-ui-react'
export const checkInitialSetupQuery = gql`
query CheckInitialSetup {

View File

@@ -15,6 +15,7 @@ import urlJoin from 'url-join'
import { clearTokenCookie } from './helpers/authentication'
import { MessageState } from './components/messages/Messages'
import { Message } from './components/messages/SubscriptionsHook'
import { NotificationType } from './__generated__/globalTypes'
export const GRAPHQL_ENDPOINT = process.env.REACT_APP_API_ENDPOINT
? urlJoin(process.env.REACT_APP_API_ENDPOINT as string, '/graphql')
@@ -103,9 +104,9 @@ const linkError = onError(({ graphQLErrors, networkError }) => {
}
if (errorMessages.length > 0) {
const newMessages = errorMessages.map(msg => ({
const newMessages: Message[] = errorMessages.map(msg => ({
key: Math.random().toString(26),
type: 'message',
type: NotificationType.Message,
props: {
negative: true,
...msg,

View File

@@ -0,0 +1,33 @@
import React from 'react'
import { forwardRef } from 'react'
import { ReactComponent as DismissIcon } from './icons/dismissIcon.svg'
export type MessageProps = {
header: string
content?: string
children?: React.ReactNode
onDismiss?(): void
}
const Message = forwardRef(
(
{ onDismiss, header, children, content }: MessageProps,
ref: React.ForwardedRef<HTMLDivElement>
) => {
return (
<div
ref={ref}
className="bg-white shadow-md border rounded p-2 h-[84px] relative"
>
<button onClick={onDismiss} className="absolute top-3 right-2">
<DismissIcon className="w-[10px] h-[10px] text-gray-700" />
</button>
<h1 className="font-semibold text-sm">{header}</h1>
<div className="text-sm">{content}</div>
{children}
</div>
)
}
)
export default Message

View File

@@ -1,36 +0,0 @@
import React from 'react'
import PropTypes from 'prop-types'
import styled from 'styled-components'
import { Message, Progress } from 'semantic-ui-react'
const StyledProgress = styled(Progress)`
position: absolute !important;
bottom: 0;
left: 0;
width: 100%;
`
const MessageProgress = ({ header, content, percent = 0, ...props }) => {
return (
<Message floating {...props}>
<Message.Content>
<Message.Header>{header}</Message.Header>
{content}
<StyledProgress
percent={percent}
size="tiny"
attached="bottom"
indicating
/>
</Message.Content>
</Message>
)
}
MessageProgress.propTypes = {
header: PropTypes.string,
content: PropTypes.any,
percent: PropTypes.number,
}
export default MessageProgress

View File

@@ -0,0 +1,30 @@
import React, { forwardRef } from 'react'
import MessagePlain, { MessageProps } from './Message'
type MessageProgressProps = MessageProps & {
percent?: number
}
const MessageProgress = forwardRef(
(
{ header, content, percent = 0, ...props }: MessageProgressProps,
ref: React.ForwardedRef<HTMLDivElement>
) => {
let color = '#dc2625'
if (percent > 33) color = '#fbbf24'
if (percent > 66) color = '#56e263'
return (
<MessagePlain header={header} content={content} {...props} ref={ref}>
<div className="absolute bottom-0 left-0 right-0 h-[3px] rounded-b overflow-hidden">
<div
className="h-full transition-all duration-200"
style={{ width: `${percent}%`, backgroundColor: color }}
></div>
</div>
</MessagePlain>
)
}
)
export default MessageProgress

View File

@@ -1,10 +1,11 @@
import React, { useState } from 'react'
import { animated, useTransition } from 'react-spring'
import { Message } from 'semantic-ui-react'
import styled from 'styled-components'
import { authToken } from '../../helpers/authentication'
import MessageProgress from './MessageProgress'
import SubscriptionsHook from './SubscriptionsHook'
import MessagePlain from './Message'
import SubscriptionsHook, { Message } from './SubscriptionsHook'
import { NotificationType } from '../../__generated__/globalTypes'
const Container = styled.div`
position: fixed;
@@ -17,7 +18,14 @@ const Container = styled.div`
}
`
export const MessageState = {
type MessageStateType = {
set: React.Dispatch<React.SetStateAction<Message[]>>
get: Message[]
add(message: Message): void
removeKey(key: string): void
}
export const MessageState: MessageStateType = {
set: fn => {
console.warn('set function is not defined yet, called with', fn)
},
@@ -39,37 +47,30 @@ export const MessageState = {
}
const Messages = () => {
const [messages, setMessages] = useState([])
const [messages, setMessages] = useState<Message[]>([])
MessageState.set = setMessages
MessageState.get = messages
const [refMap] = useState(() => new WeakMap())
const getMessageElement = (message, ref) => {
const dismissMessage = message => {
const getMessageElement = (message: Message): React.FunctionComponent => {
const dismissMessage = (message: Message) => {
message.onDismiss && message.onDismiss()
setMessages(messages => messages.filter(msg => msg.key != message.key))
}
const RefDiv = props => <div {...props} ref={x => x && ref(x)} />
switch (message.type.toLowerCase()) {
case 'message':
switch (message.type) {
case NotificationType.Message:
return props => (
<Message
as={RefDiv}
<MessagePlain
onDismiss={() => {
dismissMessage(message)
}}
floating
{...message.props}
{...props}
/>
)
case 'progress':
case NotificationType.Progress:
return props => (
<MessageProgress
as={RefDiv}
onDismiss={() => {
dismissMessage(message)
}}
@@ -77,36 +78,19 @@ const Messages = () => {
{...props}
/>
)
default:
throw new Error(`Invalid message type: ${message.type}`)
}
}
let refHooks = new Map()
messages.forEach(message => {
let resolveFunc = null
const waitPromise = new Promise(resolve => {
resolveFunc = resolve
})
refHooks.set(message.key, {
done: resolveFunc,
promise: waitPromise,
})
})
const transitions = useTransition(messages.slice().reverse(), x => x.key, {
from: {
opacity: 0,
height: '0px',
},
enter: item => async next => {
const refPromise = refHooks.get(item.key).promise
await refPromise
await next({
opacity: 1,
height: `${refMap.get(item).offsetHeight + 10}px`,
})
enter: {
opacity: 1,
height: `100px`,
},
leave: { opacity: 0, height: '0px' },
})
@@ -114,15 +98,7 @@ const Messages = () => {
return (
<Container>
{transitions.map(({ item, props: style, key }) => {
const getRef = ref => {
refMap.set(item, ref)
if (refHooks.has(item.key)) {
refHooks.get(item.key).done()
}
}
const MessageElement = getMessageElement(item, getRef)
style.padding = 0
const MessageElement = getMessageElement(item)
return (
<animated.div key={key} style={style}>

View File

@@ -26,6 +26,7 @@ export interface Message {
key: string
type: NotificationType
timeout?: number
onDismiss?: () => void
props: {
header: string
content: string

View File

@@ -0,0 +1 @@
<svg viewBox="0 0 20 20"><g stroke="currentColor" stroke-width="3.5" fill="none" fill-rule="evenodd"><path d="m1.515 1.515 16.97 16.97M18.485 1.515l-16.97 16.97"/></g></svg>

After

Width:  |  Height:  |  Size: 173 B

View File

@@ -12,6 +12,7 @@ import {
sidebarDownloadQuery_media_downloads,
} from './__generated__/sidebarDownloadQuery'
import { SidebarSection, SidebarSectionTitle } from './SidebarComponents'
import { NotificationType } from '../../__generated__/globalTypes'
export const SIDEBAR_DOWNLOAD_QUERY = gql`
query sidebarDownloadQuery($mediaId: ID!) {
@@ -111,12 +112,12 @@ const downloadMediaShowProgress =
const notifyKey = Math.random().toString(26)
MessageState.add({
key: notifyKey,
type: 'progress',
type: NotificationType.Progress,
onDismiss,
props: {
header: 'Downloading photo',
content: `Starting download`,
progress: 0,
percent: 0,
},
})
@@ -133,7 +134,7 @@ const downloadMediaShowProgress =
MessageState.add({
key: notifyKey,
type: 'progress',
type: NotificationType.Progress,
onDismiss,
props: {
header: 'Downloading photo',
@@ -151,7 +152,7 @@ const downloadMediaShowProgress =
MessageState.add({
key: notifyKey,
type: 'progress',
type: NotificationType.Progress,
props: {
header: 'Downloading photo completed',
content: `The photo has been downloaded`,