From bd570cc4732bc7812d2d483561d8e0bcd459915f Mon Sep 17 00:00:00 2001
From: ilkin-overleaf <100852799+ilkin-overleaf@users.noreply.github.com>
Date: Mon, 15 Apr 2024 11:21:52 +0300
Subject: [PATCH] Merge pull request #17576 from overleaf/ii-bs5-alert
[web] Bootstrap 5 notifications
GitOrigin-RevId: 4409f1b76923d96f1b8297beb35a383d9aa7ec8c
---
.../settings/components/emails-section.tsx | 14 +-
.../bootstrap-5/notification-wrapper.tsx | 42 +++
.../abstracts/variable-overrides.scss | 6 +-
.../stylesheets/bootstrap-5/bootstrap.scss | 16 +-
.../bootstrap-5/components/all.scss | 1 +
.../bootstrap-5/components/notifications.scss | 248 ++++++++++++++++++
.../bootstrap-5/foundations/typography.scss | 3 -
.../stylesheets/bootstrap-5/main-style.scss | 7 -
8 files changed, 314 insertions(+), 23 deletions(-)
create mode 100644 services/web/frontend/js/features/ui/components/bootstrap-5/notification-wrapper.tsx
create mode 100644 services/web/frontend/stylesheets/bootstrap-5/components/notifications.scss
diff --git a/services/web/frontend/js/features/settings/components/emails-section.tsx b/services/web/frontend/js/features/settings/components/emails-section.tsx
index 0e640d8634..63e1845126 100644
--- a/services/web/frontend/js/features/settings/components/emails-section.tsx
+++ b/services/web/frontend/js/features/settings/components/emails-section.tsx
@@ -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 && }
{isInitializingSuccess && !hideAddSecondaryEmail && }
{isInitializingError && (
-
- {' '}
- {t('error_performing_request')}
-
+ ,
+ className: 'text-center',
+ }}
+ />
)}
>
>
diff --git a/services/web/frontend/js/features/ui/components/bootstrap-5/notification-wrapper.tsx b/services/web/frontend/js/features/ui/components/bootstrap-5/notification-wrapper.tsx
new file mode 100644
index 0000000000..aec9db8982
--- /dev/null
+++ b/services/web/frontend/js/features/ui/components/bootstrap-5/notification-wrapper.tsx
@@ -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 & {
+ 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 (
+
+ {bs3Props?.icon}
+ {bs3Props?.icon && ' '}
+ {notificationProps.content}
+
+ }
+ bs5={
+
+
+
+ }
+ />
+ )
+}
+
+export default NotificationWrapper
diff --git a/services/web/frontend/stylesheets/bootstrap-5/abstracts/variable-overrides.scss b/services/web/frontend/stylesheets/bootstrap-5/abstracts/variable-overrides.scss
index 9f460e2025..106d521f23 100644
--- a/services/web/frontend/stylesheets/bootstrap-5/abstracts/variable-overrides.scss
+++ b/services/web/frontend/stylesheets/bootstrap-5/abstracts/variable-overrides.scss
@@ -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;
diff --git a/services/web/frontend/stylesheets/bootstrap-5/bootstrap.scss b/services/web/frontend/stylesheets/bootstrap-5/bootstrap.scss
index 354d9b891c..16a2b46ff7 100644
--- a/services/web/frontend/stylesheets/bootstrap-5/bootstrap.scss
+++ b/services/web/frontend/stylesheets/bootstrap-5/bootstrap.scss
@@ -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';
diff --git a/services/web/frontend/stylesheets/bootstrap-5/components/all.scss b/services/web/frontend/stylesheets/bootstrap-5/components/all.scss
index 09ed41b29a..684cfac373 100644
--- a/services/web/frontend/stylesheets/bootstrap-5/components/all.scss
+++ b/services/web/frontend/stylesheets/bootstrap-5/components/all.scss
@@ -1,3 +1,4 @@
@import 'button';
@import 'dropdown-menu';
@import 'split-button';
+@import 'notifications';
diff --git a/services/web/frontend/stylesheets/bootstrap-5/components/notifications.scss b/services/web/frontend/stylesheets/bootstrap-5/components/notifications.scss
new file mode 100644
index 0000000000..0b18779748
--- /dev/null
+++ b/services/web/frontend/stylesheets/bootstrap-5/components/notifications.scss
@@ -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);
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/services/web/frontend/stylesheets/bootstrap-5/foundations/typography.scss b/services/web/frontend/stylesheets/bootstrap-5/foundations/typography.scss
index 42540c1b5a..b78ef8ab70 100644
--- a/services/web/frontend/stylesheets/bootstrap-5/foundations/typography.scss
+++ b/services/web/frontend/stylesheets/bootstrap-5/foundations/typography.scss
@@ -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
diff --git a/services/web/frontend/stylesheets/bootstrap-5/main-style.scss b/services/web/frontend/stylesheets/bootstrap-5/main-style.scss
index bbbdee6a99..92b2539412 100644
--- a/services/web/frontend/stylesheets/bootstrap-5/main-style.scss
+++ b/services/web/frontend/stylesheets/bootstrap-5/main-style.scss
@@ -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