diff --git a/src/desktop-header/DesktopHeader.jsx b/src/desktop-header/DesktopHeader.jsx index 5828ae6da..2c318ac8b 100644 --- a/src/desktop-header/DesktopHeader.jsx +++ b/src/desktop-header/DesktopHeader.jsx @@ -18,6 +18,7 @@ import { desktopUserMenuDataShape } from './DesktopHeaderUserMenu'; // i18n import messages from '../Header.messages'; +import NotificationTraySlot from '../plugin-slots/NotificationSlot'; // Assets @@ -39,6 +40,8 @@ const DesktopHeader = ({ const renderSecondaryMenu = () => ; + const renderNotificationTray = () => ; + const renderUserMenu = () => ( + {renderNotificationTray()} {renderSecondaryMenu()} {renderUserMenu()} diff --git a/src/learning-header/LearningHeader.jsx b/src/learning-header/LearningHeader.jsx index 349690bb2..a99258f2f 100644 --- a/src/learning-header/LearningHeader.jsx +++ b/src/learning-header/LearningHeader.jsx @@ -11,6 +11,7 @@ import CourseInfoSlot from '../plugin-slots/CourseInfoSlot'; import { courseInfoDataShape } from './LearningHeaderCourseInfo'; import messages from './messages'; import LearningHelpSlot from '../plugin-slots/LearningHelpSlot'; +import NotificationTraySlot from '../plugin-slots/NotificationSlot'; const LearningHeader = ({ courseOrg, @@ -38,12 +39,13 @@ const LearningHeader = ({ {showUserDropdown && authenticatedUser && ( - <> - - - + <> + + + + )} {showUserDropdown && !authenticatedUser && ( diff --git a/src/mobile-header/MobileHeader.jsx b/src/mobile-header/MobileHeader.jsx index 6d48efd07..1a9bb8d58 100644 --- a/src/mobile-header/MobileHeader.jsx +++ b/src/mobile-header/MobileHeader.jsx @@ -13,6 +13,7 @@ import MobileMainMenuSlot from '../plugin-slots/MobileMainMenuSlot'; import { mobileHeaderMainMenuDataShape } from './MobileHeaderMainMenu'; import MobileUserMenuSlot from '../plugin-slots/MobileUserMenuSlot'; import { mobileHeaderUserMenuDataShape } from './MobileHeaderUserMenu'; +import NotificationTraySlot from '../plugin-slots/NotificationSlot'; // i18n import messages from '../Header.messages'; @@ -43,6 +44,8 @@ const MobileHeader = ({ const renderUserMenuToggle = () => ; + const renderNotificationTray = () => ; + const logoProps = { src: logo, alt: logoAltText, href: logoDestination }; const stickyClassName = stickyOnMobile ? 'sticky-top' : ''; const logoClasses = getConfig().AUTHN_MINIMAL_HEADER ? 'justify-content-left pl-3' : 'justify-content-center'; @@ -87,6 +90,7 @@ const MobileHeader = ({ aria-label={intl.formatMessage(messages['header.label.account.menu'])} title={intl.formatMessage(messages['header.label.account.menu'])} > + {renderNotificationTray()} {renderUserMenuToggle()} diff --git a/src/plugin-slots/NotificationSlot/README.md b/src/plugin-slots/NotificationSlot/README.md new file mode 100644 index 000000000..6f5d9ba01 --- /dev/null +++ b/src/plugin-slots/NotificationSlot/README.md @@ -0,0 +1,81 @@ +# Notification Tray Slot + +### Slot ID: `org.openedx.frontend.layout.notification_tray.v1` + +## Description + +This slot is used to replace, modify, or hide the contents of the notification tray in the Open edX header. It allows developers to easily extend or customize the notification tray using the [Open edX Frontend Plugin Framework](https://github.com/openedx/frontend-plugin-framework). + +The slot is kept empty so that it can only be enabled when it is required else +nothing is displayed. + +![Screenshot for frontend-app-learning]('./images/learner_header_notification.png') + +![Screenshot for frontend-app-learner-dashboard]('./images/learner_dashboard_notification.png') + +![Screenshot for frontend-app-authroing]('./images/studio_header_notification.png') + +## Examples + +### Insert Notification Tray with Custom Component + +The following `env.config.jsx` will replace the notification tray's contents entirely (in this case with a custom emoji icon): + +```jsx +import { DIRECT_PLUGIN, PLUGIN_OPERATIONS } from '@openedx/frontend-plugin-framework'; + +const config = { + pluginSlots: { + 'org.openedx.frontend.layout.notification_tray.v1': { + keepDefault: false, + plugins: [ + { + op: PLUGIN_OPERATIONS.Insert, + widget: { + id: 'custom_notification_tray', + type: DIRECT_PLUGIN, + RenderWidget: () => ( + 🔔 Custom Notification + ), + }, + }, + ], + }, + }, +}; + +export default config; +``` + +## Component Usage + +Import the `NotificationTraySlot` component and use it in your layout or header component where you want the notifications tray to appear: + +```jsx +import NotificationTraySlot from './src/plugin-slots/NotificationSlot'; + +function Header() { + return ( +
+ {/* Other header content */} + +
+ ); +} +``` + +## API + +- **Slot ID:** `org.openedx.frontend.layout.notification_tray.v1` +- **Alias:** `notification_tray_plugin` +- **Component:** Uses the [PluginSlot](https://github.com/openedx/frontend-plugin-framework#pluginslot) from the Open edX Frontend Plugin Framework for plugin injection. +- **Props:** This component does not accept any props directly. + +## License + +This component is part of the [open-craft/frontend-component-header](https://github.com/open-craft/frontend-component-header) repository and is made available under its license. + +## Contributing + +If you would like to contribute improvements or additional plugin slots, please open a pull request or issue in the [repository](https://github.com/open-craft/frontend-component-header). + diff --git a/src/plugin-slots/NotificationSlot/images/learner_dashboard_notification.png b/src/plugin-slots/NotificationSlot/images/learner_dashboard_notification.png new file mode 100644 index 000000000..8baecbf61 Binary files /dev/null and b/src/plugin-slots/NotificationSlot/images/learner_dashboard_notification.png differ diff --git a/src/plugin-slots/NotificationSlot/images/learner_header_notification.png b/src/plugin-slots/NotificationSlot/images/learner_header_notification.png new file mode 100644 index 000000000..de14cfcf1 Binary files /dev/null and b/src/plugin-slots/NotificationSlot/images/learner_header_notification.png differ diff --git a/src/plugin-slots/NotificationSlot/images/studio_header_notification.png b/src/plugin-slots/NotificationSlot/images/studio_header_notification.png new file mode 100644 index 000000000..981b0e965 Binary files /dev/null and b/src/plugin-slots/NotificationSlot/images/studio_header_notification.png differ diff --git a/src/plugin-slots/NotificationSlot/index.jsx b/src/plugin-slots/NotificationSlot/index.jsx new file mode 100644 index 000000000..cde77e22a --- /dev/null +++ b/src/plugin-slots/NotificationSlot/index.jsx @@ -0,0 +1,11 @@ +import React from 'react'; +import { PluginSlot } from '@openedx/frontend-plugin-framework'; + +const NotificationTraySlot = () => ( + +); + +export default NotificationTraySlot; diff --git a/src/plugin-slots/README.md b/src/plugin-slots/README.md index 21e158f68..24f3484e0 100644 --- a/src/plugin-slots/README.md +++ b/src/plugin-slots/README.md @@ -2,6 +2,7 @@ ### Shared * [`org.openedx.frontend.layout.header_logo.v1`](./LogoSlot/) +* [`org.openedx.frontend.layout.notification_tray.v1`](./NotificationSlot/) ### Desktop Header * [`org.openedx.frontend.layout.header_desktop.v1`](./DesktopHeaderSlot/) diff --git a/src/studio-header/HeaderBody.tsx b/src/studio-header/HeaderBody.tsx index 598aec381..df450f99b 100644 --- a/src/studio-header/HeaderBody.tsx +++ b/src/studio-header/HeaderBody.tsx @@ -18,6 +18,7 @@ import UserMenu from './UserMenu'; import BrandNav from './BrandNav'; import NavDropdownMenu from './NavDropdownMenu'; import messages from './messages'; +import NotificationTraySlot from '../plugin-slots/NotificationSlot'; const HeaderBody = ({ logo, @@ -57,7 +58,7 @@ const HeaderBody = ({ return ( @@ -116,6 +117,9 @@ const HeaderBody = ({ )} + {searchButtonAction && (