mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
Merge pull request #17576 from overleaf/ii-bs5-alert
[web] Bootstrap 5 notifications GitOrigin-RevId: 4409f1b76923d96f1b8297beb35a383d9aa7ec8c
This commit is contained in:
parent
1a7f6514a4
commit
bd570cc473
8 changed files with 314 additions and 23 deletions
|
@ -9,7 +9,7 @@ import EmailsHeader from './emails/header'
|
|||
import EmailsRow from './emails/row'
|
||||
import AddEmail from './emails/add-email'
|
||||
import Icon from '../../../shared/components/icon'
|
||||
import { Alert } from 'react-bootstrap'
|
||||
import NotificationWrapper from '@/features/ui/components/bootstrap-5/notification-wrapper'
|
||||
import { ExposedSettings } from '../../../../../types/exposed-settings'
|
||||
import { LeaversSurveyAlert } from './leavers-survey-alert'
|
||||
|
||||
|
@ -67,10 +67,14 @@ function EmailsSectionContent() {
|
|||
{isInitializingSuccess && <LeaversSurveyAlert />}
|
||||
{isInitializingSuccess && !hideAddSecondaryEmail && <AddEmail />}
|
||||
{isInitializingError && (
|
||||
<Alert bsStyle="danger" className="text-center">
|
||||
<Icon type="exclamation-triangle" fw />{' '}
|
||||
{t('error_performing_request')}
|
||||
</Alert>
|
||||
<NotificationWrapper
|
||||
type="error"
|
||||
content={t('error_performing_request')}
|
||||
bs3Props={{
|
||||
icon: <Icon type="exclamation-triangle" fw />,
|
||||
className: 'text-center',
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
</>
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
import Notification from '@/shared/components/notification'
|
||||
import { Alert, AlertProps } from 'react-bootstrap'
|
||||
import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
|
||||
import classnames from 'classnames'
|
||||
|
||||
type NotificationWrapperProps = React.ComponentProps<typeof Notification> & {
|
||||
bs3Props?: {
|
||||
icon: React.ReactElement
|
||||
className?: string
|
||||
}
|
||||
}
|
||||
|
||||
function NotificationWrapper(props: NotificationWrapperProps) {
|
||||
const { bs3Props, ...notificationProps } = props
|
||||
|
||||
const alertProps = {
|
||||
// Map `error` to `danger`
|
||||
bsStyle:
|
||||
notificationProps.type === 'error' ? 'danger' : notificationProps.type,
|
||||
className: classnames(notificationProps.className, bs3Props?.className),
|
||||
onDismiss: notificationProps.onDismiss,
|
||||
} as const satisfies AlertProps
|
||||
|
||||
return (
|
||||
<BootstrapVersionSwitcher
|
||||
bs3={
|
||||
<Alert {...alertProps}>
|
||||
{bs3Props?.icon}
|
||||
{bs3Props?.icon && ' '}
|
||||
{notificationProps.content}
|
||||
</Alert>
|
||||
}
|
||||
bs5={
|
||||
<div className="notification-list">
|
||||
<Notification {...notificationProps} />
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export default NotificationWrapper
|
|
@ -4,8 +4,10 @@
|
|||
$font-family-sans-serif: 'Noto Sans', sans-serif;
|
||||
$font-family-serif: 'Merriweather', serif;
|
||||
$font-family-monospace: 'DM Mono', monospace;
|
||||
$font-size-base: $default-font-size;
|
||||
$line-height-base: $default-line-height;
|
||||
|
||||
$font-size-base: 1rem;
|
||||
$font-size-sm: var(--font-size-02);
|
||||
$line-height-base: 1.5;
|
||||
|
||||
// Buttons
|
||||
$btn-font-family: $font-family-sans-serif;
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
// Bootstrap itself because Bootstrap uses them to create the CSS variables it
|
||||
// uses, and in calculations to determine, for example, what color text to use
|
||||
// on a button based on contrast.
|
||||
@import 'abstracts/all';
|
||||
@import 'foundations/all';
|
||||
@import 'abstracts/all';
|
||||
|
||||
// Include remainder of required Bootstrap stylesheets (including any separate color mode stylesheets)
|
||||
@import 'bootstrap-5/scss/variables';
|
||||
|
@ -17,21 +17,25 @@
|
|||
// Include remainder of required parts
|
||||
@import 'bootstrap-5/scss/maps';
|
||||
@import 'bootstrap-5/scss/mixins';
|
||||
@import 'bootstrap-5/scss/root';
|
||||
|
||||
// Include any other optional parts as needed, including components
|
||||
@import 'bootstrap-5/scss/utilities';
|
||||
|
||||
// Layout & components
|
||||
@import 'bootstrap-5/scss/root';
|
||||
@import 'bootstrap-5/scss/reboot';
|
||||
@import 'bootstrap-5/scss/type';
|
||||
@import 'bootstrap-5/scss/images';
|
||||
@import 'bootstrap-5/scss/containers';
|
||||
@import 'bootstrap-5/scss/grid';
|
||||
@import 'bootstrap-5/scss/helpers';
|
||||
@import 'bootstrap-5/scss/buttons';
|
||||
@import 'bootstrap-5/scss/dropdown';
|
||||
@import 'bootstrap-5/scss/modal';
|
||||
@import 'bootstrap-5/scss/utilities/api';
|
||||
@import 'bootstrap-5/scss/spinners';
|
||||
|
||||
// Helpers
|
||||
@import 'bootstrap-5/scss/helpers';
|
||||
|
||||
// Utilities
|
||||
@import 'bootstrap-5/scss/utilities/api';
|
||||
|
||||
// Components custom style
|
||||
@import 'components/all';
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
@import 'button';
|
||||
@import 'dropdown-menu';
|
||||
@import 'split-button';
|
||||
@import 'notifications';
|
||||
|
|
|
@ -0,0 +1,248 @@
|
|||
.notification-body {
|
||||
// will be deprecated once notifications moved to use .notification (see below)
|
||||
flex-grow: 1;
|
||||
width: 90%;
|
||||
@media (min-width: var(--bs-breakpoint-md)) {
|
||||
width: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.notification-action {
|
||||
$line-height-computed: $font-size-base * $line-height-base; // 24px
|
||||
|
||||
// will be deprecated once notifications moved to use .notification (see below)
|
||||
margin-top: calc($line-height-computed / 2); // match paragraph padding
|
||||
order: 1;
|
||||
@media (min-width: var(--bs-breakpoint-md)) {
|
||||
margin-top: 0;
|
||||
order: 0;
|
||||
padding-left: $spacing-05;
|
||||
}
|
||||
}
|
||||
|
||||
.notification-close {
|
||||
// will be deprecated once notifications moved to use .notification (see below)
|
||||
padding-left: $spacing-05;
|
||||
text-align: right;
|
||||
width: 10%;
|
||||
|
||||
button {
|
||||
aspect-ratio: 1;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
float: right;
|
||||
padding: 5.5px;
|
||||
cursor: pointer;
|
||||
background: transparent;
|
||||
border: 0;
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
background-color: rgba(var(--neutral-90), 0.08);
|
||||
color: var(--content-secondary);
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: var(--bs-breakpoint-md)) {
|
||||
width: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.notification {
|
||||
border-radius: $border-radius-base;
|
||||
color: var(--content-primary);
|
||||
display: flex;
|
||||
padding: 0 $spacing-06; // vertical padding added by elements within notification
|
||||
width: 100%;
|
||||
|
||||
a:not(.btn) {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-bottom: $spacing-02;
|
||||
}
|
||||
|
||||
.notification-icon {
|
||||
flex-grow: 0;
|
||||
padding: 18px $spacing-06 0 0;
|
||||
}
|
||||
|
||||
.notification-content-and-cta {
|
||||
// shared container to align cta with text on smaller screens
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
flex-wrap: wrap;
|
||||
|
||||
p:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.notification-content {
|
||||
flex-grow: 1;
|
||||
padding: $spacing-06 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.notification-cta {
|
||||
padding-bottom: $spacing-06;
|
||||
|
||||
a {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
a,
|
||||
button {
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
.notification-disclaimer {
|
||||
color: var(--neutral-60);
|
||||
font-size: $font-size-sm;
|
||||
padding-bottom: $spacing-06;
|
||||
}
|
||||
|
||||
.notification-close-btn {
|
||||
height: $spacing-12;
|
||||
align-items: center;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.notification-close-btn {
|
||||
padding: 0 0 0 $spacing-06;
|
||||
|
||||
button {
|
||||
aspect-ratio: 1;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
float: right;
|
||||
padding: 5.5px;
|
||||
cursor: pointer;
|
||||
background: transparent;
|
||||
border: 0;
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
background-color: rgba(var(--neutral-90), 0.08);
|
||||
color: var(--content-secondary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.notification-type-info {
|
||||
background-color: var(--bg-info-03);
|
||||
border: 1px solid var(--blue-20);
|
||||
.notification-icon {
|
||||
color: var(--blue-50);
|
||||
}
|
||||
}
|
||||
&.notification-type-success {
|
||||
background-color: var(--bg-accent-03);
|
||||
border: 1px solid var(--green-20);
|
||||
.notification-icon {
|
||||
color: var(--green-50);
|
||||
}
|
||||
}
|
||||
&.notification-type-warning {
|
||||
background-color: var(--bg-warning-03);
|
||||
border: 1px solid var(--yellow-20);
|
||||
.notification-icon {
|
||||
color: var(--yellow-40);
|
||||
}
|
||||
}
|
||||
&.notification-type-error {
|
||||
background-color: var(--bg-danger-03);
|
||||
border: 1px solid var(--red-20);
|
||||
.notification-icon {
|
||||
color: var(--red-50);
|
||||
}
|
||||
}
|
||||
&.notification-type-offer {
|
||||
background-color: var(--bg-light-primary);
|
||||
border: 1px solid var(--neutral-20);
|
||||
.notification-icon {
|
||||
color: var(--neutral-50);
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: var(--bs-breakpoint-md)) {
|
||||
&:not(.notification-cta-below-content) {
|
||||
.notification-content-and-cta {
|
||||
flex-wrap: nowrap;
|
||||
}
|
||||
|
||||
.notification-content {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.notification-cta {
|
||||
height: $spacing-12;
|
||||
padding-left: $spacing-06;
|
||||
padding-bottom: 0;
|
||||
align-items: center;
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.notification-with-scroll-margin {
|
||||
scroll-margin: $spacing-06;
|
||||
}
|
||||
|
||||
.notification-list {
|
||||
.notification {
|
||||
margin-bottom: $spacing-07;
|
||||
}
|
||||
}
|
||||
|
||||
// Reconfirmation notification
|
||||
|
||||
.reconfirm-notification {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
.fa-warning {
|
||||
margin-right: $spacing-05;
|
||||
}
|
||||
.btn-reconfirm {
|
||||
float: right;
|
||||
margin-left: $spacing-05;
|
||||
text-transform: capitalize;
|
||||
}
|
||||
}
|
||||
|
||||
.group-invitation-cancel-subscription-notification-buttons {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
// Settings page
|
||||
.affiliations-table {
|
||||
.reconfirm-notification {
|
||||
margin: 0 auto $spacing-05 auto !important;
|
||||
padding: $spacing-07;
|
||||
}
|
||||
|
||||
.reconfirm-row {
|
||||
td {
|
||||
border: 0;
|
||||
|
||||
.alert {
|
||||
border: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
:not(.alert) {
|
||||
.reconfirm-notification {
|
||||
background-color: var(--neutral-10);
|
||||
border-radius: $border-radius-base;
|
||||
.fa-warning {
|
||||
color: var(--yellow-40);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,9 +1,6 @@
|
|||
// This file provides CSS variables for font size and line height, plus Sass variables for base text size for Bootstrap
|
||||
@use 'sass:math';
|
||||
|
||||
$default-font-size: 1rem;
|
||||
$default-line-height: 1.5;
|
||||
|
||||
:root {
|
||||
--font-size-01: 0.75rem; // 12px
|
||||
--font-size-02: 0.875rem; // 14px
|
||||
|
|
|
@ -14,13 +14,6 @@ $is-overleaf-light: false;
|
|||
// TODO Bootstrap 5: Check whether this works with Bootstrap 5, and whether we can replace it
|
||||
@import '../vendor/select/select';
|
||||
|
||||
// Sass and CSS variables from Overleaf foundations
|
||||
@import 'foundations/colors';
|
||||
@import 'foundations/spacing';
|
||||
@import 'foundations/typography';
|
||||
@import 'foundations/border-radius';
|
||||
@import 'foundations/elevation';
|
||||
|
||||
// Boostrap-related
|
||||
|
||||
// Note that files containing Bootstrap or Sass files that interact with
|
||||
|
|
Loading…
Reference in a new issue