aboutsummaryrefslogtreecommitdiffstats
path: root/packages/renderer/src/components/banner/NotificationBanner.tsx
blob: 70fe693e6bd3520a3fcf5b6f82e718e479aa39e4 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
/*
 * Copyright (C)  2022 Kristóf Marussy <kristof@marussy.com>
 *
 * This file is part of Sophie.
 *
 * Sophie is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, version 3.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 *
 * SPDX-License-Identifier: AGPL-3.0-only
 */

import Alert, { AlertColor } from '@mui/material/Alert';
import Box from '@mui/material/Box';
import Typography from '@mui/material/Typography';
import { styled } from '@mui/material/styles';
import React, { ReactNode } from 'react';
import { useTranslation } from 'react-i18next';

const NotificationBannerRoot = styled(Alert)(({ theme }) => ({
  padding: `7px ${theme.spacing(1)} 6px ${theme.spacing(2)}`,
  // Match the height of the location bar.
  minHeight: 53,
  borderRadius: 0,
  borderBottom: `1px solid ${theme.palette.divider}`,
  '.MuiAlert-message': {
    flexGrow: 1,
    paddingTop: 0,
    paddingBottom: 4,
    display: 'flex',
    flexWrap: 'wrap',
    justifyContent: 'center',
  },
  '.MuiAlert-action': {
    paddingLeft: 0,
    paddingRight: theme.spacing(1),
  },
}));

const NotificationBannerText = styled(Typography)(({ theme }) => ({
  fontSize: 'inherit',
  paddingTop: theme.spacing(1),
  paddingRight: theme.spacing(2),
  flexGrow: 9999,
}));

const NotificationBannerButtons = styled(Box, {
  shouldForwardProp: (prop) => prop !== 'hasCloseButton',
})<{ hasCloseButton: boolean }>(({ theme, hasCloseButton }) => ({
  fontSize: 'inherit',
  paddingTop: theme.spacing(0.5),
  paddingRight: hasCloseButton ? theme.spacing(0.5) : 0,
  display: 'flex',
  flexWrap: 'wrap',
  flexGrow: 1,
  gap: theme.spacing(1),
  '.MuiButton-root': {
    flexGrow: 1,
  },
}));

export default function NotificationBanner({
  severity,
  icon,
  onClose,
  buttons,
  children,
}: {
  severity?: AlertColor;
  icon?: ReactNode;
  onClose?: () => void;
  buttons?: ReactNode;
  children?: ReactNode;
}): JSX.Element {
  const { t } = useTranslation();

  return (
    /* eslint-disable react/jsx-props-no-spreading -- Conditionally set the onClose prop. */
    <NotificationBannerRoot
      severity={severity ?? 'success'}
      icon={icon ?? false}
      {...(onClose === undefined ? {} : { onClose })}
      closeText={t<string>('banner.close')}
    >
      {/* eslint-enable react/jsx-props-no-spreading */}
      <NotificationBannerText>{children}</NotificationBannerText>
      {buttons && (
        <NotificationBannerButtons hasCloseButton={onClose !== undefined}>
          {buttons}
        </NotificationBannerButtons>
      )}
    </NotificationBannerRoot>
  );
}

NotificationBanner.defaultProps = {
  severity: 'success',
  icon: false,
  onClose: undefined,
  buttons: undefined,
  children: undefined,
};