diff --git a/package.json b/package.json
index ee8ac82..2f0fbce 100644
--- a/package.json
+++ b/package.json
@@ -14,6 +14,7 @@
"snapshot": "fedx-scripts jest --updateSnapshot",
"start": "fedx-scripts webpack-dev-server --progress",
"test": "fedx-scripts jest --coverage",
+ "test:dev": "fedx-scripts jest --watchAll",
"types": "tsc --noEmit"
},
"files": [
@@ -70,3 +71,4 @@
"react-router-dom": "^6.14.2"
}
}
+
diff --git a/src/desktop-header/DesktopHeader.jsx b/src/desktop-header/DesktopHeader.jsx
index 9982950..973b86f 100644
--- a/src/desktop-header/DesktopHeader.jsx
+++ b/src/desktop-header/DesktopHeader.jsx
@@ -4,8 +4,9 @@ import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import { getConfig } from '@edx/frontend-platform';
// Local Components
+import DesktopUserMenuToggleSlot
+ from '../plugin-slots/DesktopUserMenuToggleSlot';
import { Menu, MenuTrigger, MenuContent } from '../Menu';
-import Avatar from '../Avatar';
import LogoSlot from '../plugin-slots/LogoSlot';
import DesktopLoggedOutItemsSlot from '../plugin-slots/DesktopLoggedOutItemsSlot';
import { desktopLoggedOutItemsDataShape } from './DesktopLoggedOutItems';
@@ -19,7 +20,6 @@ import { desktopUserMenuDataShape } from './DesktopHeaderUserMenu';
import messages from '../Header.messages';
// Assets
-import { CaretIcon } from '../Icons';
class DesktopHeader extends React.Component {
constructor(props) { // eslint-disable-line @typescript-eslint/no-useless-constructor
@@ -51,8 +51,7 @@ class DesktopHeader extends React.Component {
aria-label={intl.formatMessage(messages['header.label.account.menu.for'], { username })}
className="btn btn-outline-primary d-inline-flex align-items-center pl-2 pr-3"
>
-
- {username}
+
@@ -123,15 +122,15 @@ export const desktopHeaderDataShape = {
DesktopHeader.propTypes = {
mainMenu: desktopHeaderDataShape.mainMenu,
- secondaryMenu: desktopHeaderDataShape.secondaryMenumainMenu,
- userMenu: desktopHeaderDataShape.userMenumainMenu,
- loggedOutItems: desktopHeaderDataShape.loggedOutItemsmainMenu,
- logo: desktopHeaderDataShape.logomainMenu,
- logoAltText: desktopHeaderDataShape.logoAltTextmainMenu,
- logoDestination: desktopHeaderDataShape.logoDestinationmainMenu,
- avatar: desktopHeaderDataShape.avatarmainMenu,
- username: desktopHeaderDataShape.usernamemainMenu,
- loggedIn: desktopHeaderDataShape.loggedInmainMenu,
+ secondaryMenu: desktopHeaderDataShape.secondaryMenu,
+ userMenu: desktopHeaderDataShape.userMenu,
+ loggedOutItems: desktopHeaderDataShape.loggedOutItems,
+ logo: desktopHeaderDataShape.logo,
+ logoAltText: desktopHeaderDataShape.logoAltText,
+ logoDestination: desktopHeaderDataShape.logoDestination,
+ avatar: desktopHeaderDataShape.avatar,
+ username: desktopHeaderDataShape.username,
+ loggedIn: desktopHeaderDataShape.loggedIn,
// i18n
intl: intlShape.isRequired,
diff --git a/src/desktop-header/DesktopUserMenuToggle.jsx b/src/desktop-header/DesktopUserMenuToggle.jsx
new file mode 100644
index 0000000..f905714
--- /dev/null
+++ b/src/desktop-header/DesktopUserMenuToggle.jsx
@@ -0,0 +1,20 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { CaretIcon } from '../Icons';
+import Avatar from '../Avatar';
+
+const DesktopUserMenuToggle = ({ avatar, label }) => (
+ <>
+
+ {label}
+ >
+);
+
+export const DesktopUserMenuTogglePropTypes = {
+ avatar: PropTypes.string,
+ label: PropTypes.string,
+};
+
+DesktopUserMenuToggle.propTypes = DesktopUserMenuTogglePropTypes;
+
+export default DesktopUserMenuToggle;
diff --git a/src/learning-header/AuthenticatedUserDropdown.jsx b/src/learning-header/AuthenticatedUserDropdown.jsx
index 9336796..e270662 100644
--- a/src/learning-header/AuthenticatedUserDropdown.jsx
+++ b/src/learning-header/AuthenticatedUserDropdown.jsx
@@ -1,12 +1,12 @@
import React from 'react';
import PropTypes from 'prop-types';
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faUserCircle } from '@fortawesome/free-solid-svg-icons';
import { getConfig } from '@edx/frontend-platform';
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import { Dropdown } from '@openedx/paragon';
+import LearningUserMenuToggleSlot from '../plugin-slots/LearningUserMenuToggleSlot';
import LearningUserMenuSlot from '../plugin-slots/LearningUserMenuSlot';
import messages from './messages';
@@ -38,10 +38,7 @@ const AuthenticatedUserDropdown = ({ intl, username }) => {
return (
-
-
- {username}
-
+
diff --git a/src/learning-header/LearningUserMenuToggle.jsx b/src/learning-header/LearningUserMenuToggle.jsx
new file mode 100644
index 0000000..9f9d623
--- /dev/null
+++ b/src/learning-header/LearningUserMenuToggle.jsx
@@ -0,0 +1,28 @@
+import React from 'react';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import PropTypes from 'prop-types';
+
+const LearningUserMenuToggle = ({
+ label,
+ icon,
+}) => (
+ <>
+
+
+ {label}
+
+ >
+);
+
+export const LearningUserMenuTogglePropTypes = {
+ label: PropTypes.string.isRequired,
+ // Full shape available by examining @fortawesome/fontawesome-common-types/index.d.ts.
+ icon: PropTypes.shape({
+ prefix: PropTypes.string.isRequired,
+ iconName: PropTypes.string.isRequired,
+ }).isRequired,
+};
+
+LearningUserMenuToggle.propTypes = LearningUserMenuTogglePropTypes;
+
+export default LearningUserMenuToggle;
diff --git a/src/mobile-header/MobileHeader.jsx b/src/mobile-header/MobileHeader.jsx
index 70d808e..788d17e 100644
--- a/src/mobile-header/MobileHeader.jsx
+++ b/src/mobile-header/MobileHeader.jsx
@@ -4,8 +4,8 @@ import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import { getConfig } from '@edx/frontend-platform';
// Local Components
+import MobileUserMenuToggleSlot from '../plugin-slots/MobileUserMenuToggleSlot';
import { Menu, MenuTrigger, MenuContent } from '../Menu';
-import Avatar from '../Avatar';
import LogoSlot from '../plugin-slots/LogoSlot';
import MobileLoggedOutItemsSlot from '../plugin-slots/MobileLoggedOutItemsSlot';
import { mobileHeaderLoggedOutItemsDataShape } from './MobileLoggedOutItems';
@@ -40,14 +40,17 @@ class MobileHeader extends React.Component {
return ;
}
+ renderUserMenuToggle() {
+ const { avatar, username } = this.props;
+ return ;
+ }
+
render() {
const {
logo,
logoAltText,
logoDestination,
loggedIn,
- avatar,
- username,
stickyOnMobile,
intl,
mainMenu,
@@ -98,7 +101,7 @@ class MobileHeader extends React.Component {
aria-label={intl.formatMessage(messages['header.label.account.menu'])}
title={intl.formatMessage(messages['header.label.account.menu'])}
>
-
+ {this.renderUserMenuToggle()}
{loggedIn ? this.renderUserMenuItems() : this.renderLoggedOutItems()}
diff --git a/src/mobile-header/MobileUserMenuToggle.jsx b/src/mobile-header/MobileUserMenuToggle.jsx
new file mode 100644
index 0000000..7f2eeb9
--- /dev/null
+++ b/src/mobile-header/MobileUserMenuToggle.jsx
@@ -0,0 +1,14 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import Avatar from '../Avatar';
+
+const MobileUserMenuToggle = ({ avatar, username }) => ;
+
+export const MobileUserMenuTogglePropTypes = {
+ avatar: PropTypes.string,
+ username: PropTypes.string,
+};
+
+MobileUserMenuToggle.propTypes = MobileUserMenuTogglePropTypes;
+
+export default MobileUserMenuToggle;
diff --git a/src/plugin-slots/DesktopHeaderSlot/README.md b/src/plugin-slots/DesktopHeaderSlot/README.md
index 890e51b..631d2ba 100644
--- a/src/plugin-slots/DesktopHeaderSlot/README.md
+++ b/src/plugin-slots/DesktopHeaderSlot/README.md
@@ -41,4 +41,4 @@ const config = {
}
export default config;
-```
\ No newline at end of file
+```
diff --git a/src/plugin-slots/DesktopUserMenuToggleSlot/README.md b/src/plugin-slots/DesktopUserMenuToggleSlot/README.md
new file mode 100644
index 0000000..4e8c6a4
--- /dev/null
+++ b/src/plugin-slots/DesktopUserMenuToggleSlot/README.md
@@ -0,0 +1,74 @@
+# Desktop User Menu Toggle Slot
+
+### Slot ID: `org.openedx.frontend.layout.header_desktop_user_menu_toggle.v1`
+
+## Description
+
+This slot is used to replace/modify/hide the contents of the user menu toggle button on desktop sized screens.
+
+## Examples
+
+### Modify Label Text
+
+The following `env.config.jsx` will modify the label text to be something more generic:
+
+
+
+```jsx
+import { PLUGIN_OPERATIONS } from '@openedx/frontend-plugin-framework';
+import { faHouse } from '@fortawesome/free-solid-svg-icons';
+
+const modifyUserMenuToggle = ( widget ) => {
+ widget.content.label = "My Profile";
+ return widget;
+};
+
+const config = {
+ pluginSlots: {
+ 'org.openedx.frontend.layout.header_desktop_user_menu_toggle.v1': {
+ keepDefault: true,
+ plugins: [
+ {
+ op: PLUGIN_OPERATIONS.Modify,
+ widgetId: 'default_contents',
+ fn: modifyUserMenuToggle,
+ },
+ ]
+ },
+ },
+}
+
+export default config;
+```
+
+### Replace Menu toggle contents with Custom Component
+
+The following `env.config.jsx` will replace the contents of the learning user menu toggle button entirely (in this case with an emoji)
+
+
+
+```jsx
+import { DIRECT_PLUGIN, PLUGIN_OPERATIONS } from '@openedx/frontend-plugin-framework';
+
+const config = {
+ pluginSlots: {
+ 'org.openedx.frontend.layout.header_desktop_user_menu_toggle.v1': {
+ keepDefault: false,
+ plugins: [
+ {
+ op: PLUGIN_OPERATIONS.Insert,
+ widget: {
+ id: 'custom_desktop_user_menu_toggle',
+ type: DIRECT_PLUGIN,
+ RenderWidget: () => (
+ 🦊
+ ),
+ },
+ },
+ ]
+ },
+ },
+}
+
+export default config;
+```
diff --git a/src/plugin-slots/DesktopUserMenuToggleSlot/images/desktop_user_menu_custom_component.png b/src/plugin-slots/DesktopUserMenuToggleSlot/images/desktop_user_menu_custom_component.png
new file mode 100644
index 0000000..c16bf45
Binary files /dev/null and b/src/plugin-slots/DesktopUserMenuToggleSlot/images/desktop_user_menu_custom_component.png differ
diff --git a/src/plugin-slots/DesktopUserMenuToggleSlot/images/desktop_user_menu_modified_toggle.png b/src/plugin-slots/DesktopUserMenuToggleSlot/images/desktop_user_menu_modified_toggle.png
new file mode 100644
index 0000000..d5eefff
Binary files /dev/null and b/src/plugin-slots/DesktopUserMenuToggleSlot/images/desktop_user_menu_modified_toggle.png differ
diff --git a/src/plugin-slots/DesktopUserMenuToggleSlot/index.jsx b/src/plugin-slots/DesktopUserMenuToggleSlot/index.jsx
new file mode 100644
index 0000000..d9af0f2
--- /dev/null
+++ b/src/plugin-slots/DesktopUserMenuToggleSlot/index.jsx
@@ -0,0 +1,21 @@
+import React from 'react';
+import { PluginSlot } from '@openedx/frontend-plugin-framework';
+import DesktopUserMenuToggle, { DesktopUserMenuTogglePropTypes } from '../../desktop-header/DesktopUserMenuToggle';
+
+const DesktopUserMenuToggleSlot = ({
+ avatar,
+ label,
+}) => (
+
+);
+
+DesktopUserMenuToggleSlot.propTypes = DesktopUserMenuTogglePropTypes;
+
+export default DesktopUserMenuToggleSlot;
diff --git a/src/plugin-slots/LearningUserMenuToggleSlot/README.md b/src/plugin-slots/LearningUserMenuToggleSlot/README.md
new file mode 100644
index 0000000..7e9b158
--- /dev/null
+++ b/src/plugin-slots/LearningUserMenuToggleSlot/README.md
@@ -0,0 +1,74 @@
+# Learning User Menu Toggle Slot
+
+### Slot ID: `org.openedx.frontend.layout.header_learning_user_menu_toggle.v1`
+
+## Description
+
+This slot is used to replace/modify/hide the contents of the learning user menu toggle button.
+
+## Examples
+
+### Modify Icon
+
+The following `env.config.jsx` will modify the icon for the learning user menu toggle button. **Note:** The icon is only shown on mobile screens.
+
+
+
+```jsx
+import { PLUGIN_OPERATIONS } from '@openedx/frontend-plugin-framework';
+import { faHouse } from '@fortawesome/free-solid-svg-icons';
+
+const modifyUserMenuToggle = ( widget ) => {
+ widget.content.icon = faHouse;
+ return widget;
+};
+
+const config = {
+ pluginSlots: {
+ 'org.openedx.frontend.layout.header_learning_user_menu_toggle.v1': {
+ keepDefault: true,
+ plugins: [
+ {
+ op: PLUGIN_OPERATIONS.Modify,
+ widgetId: 'default_contents',
+ fn: modifyUserMenuToggle,
+ },
+ ]
+ },
+ },
+}
+
+export default config;
+```
+
+### Replace Menu toggle contents with Custom Component
+
+The following `env.config.jsx` will replace the contents of the learning user menu toggle button's contents entirely (in this case with an emoji)
+
+
+
+```jsx
+import { DIRECT_PLUGIN, PLUGIN_OPERATIONS } from '@openedx/frontend-plugin-framework';
+
+const config = {
+ pluginSlots: {
+ 'org.openedx.frontend.layout.header_learning_user_menu_toggle.v1': {
+ keepDefault: false,
+ plugins: [
+ {
+ op: PLUGIN_OPERATIONS.Insert,
+ widget: {
+ id: 'custom_learning_user_menu_toggle',
+ type: DIRECT_PLUGIN,
+ RenderWidget: () => (
+ 🦊
+ ),
+ },
+ },
+ ]
+ },
+ },
+}
+
+export default config;
+```
diff --git a/src/plugin-slots/LearningUserMenuToggleSlot/images/learning_user_menu_toggle_custom_component.png b/src/plugin-slots/LearningUserMenuToggleSlot/images/learning_user_menu_toggle_custom_component.png
new file mode 100644
index 0000000..950f9bd
Binary files /dev/null and b/src/plugin-slots/LearningUserMenuToggleSlot/images/learning_user_menu_toggle_custom_component.png differ
diff --git a/src/plugin-slots/LearningUserMenuToggleSlot/images/learning_user_menu_toggle_modified_items.png b/src/plugin-slots/LearningUserMenuToggleSlot/images/learning_user_menu_toggle_modified_items.png
new file mode 100644
index 0000000..40ee175
Binary files /dev/null and b/src/plugin-slots/LearningUserMenuToggleSlot/images/learning_user_menu_toggle_modified_items.png differ
diff --git a/src/plugin-slots/LearningUserMenuToggleSlot/index.jsx b/src/plugin-slots/LearningUserMenuToggleSlot/index.jsx
new file mode 100644
index 0000000..636989a
--- /dev/null
+++ b/src/plugin-slots/LearningUserMenuToggleSlot/index.jsx
@@ -0,0 +1,22 @@
+import React from 'react';
+import { PluginSlot } from '@openedx/frontend-plugin-framework';
+import LearningUserMenuToggle, {
+ LearningUserMenuTogglePropTypes,
+} from '../../learning-header/LearningUserMenuToggle';
+
+const LearningUserMenuToggleSlot = ({
+ label, icon,
+}) => (
+
+);
+
+LearningUserMenuToggleSlot.propTypes = LearningUserMenuTogglePropTypes;
+
+export default LearningUserMenuToggleSlot;
diff --git a/src/plugin-slots/MobileUserMenuToggleSlot/README.md b/src/plugin-slots/MobileUserMenuToggleSlot/README.md
new file mode 100644
index 0000000..717be40
--- /dev/null
+++ b/src/plugin-slots/MobileUserMenuToggleSlot/README.md
@@ -0,0 +1,74 @@
+# Mobile User Menu Toggle Slot
+
+### Slot ID: `org.openedx.frontend.layout.header_mobile_user_menu_trigger.v1`
+
+## Description
+
+This slot is used to replace/modify/hide the contents of the user menu toggle button on mobile screens.
+
+## Examples
+
+### Modify Avatar
+
+The following `env.config.jsx` will modify the icon for the user menu toggle button on mobile.
+
+
+
+```jsx
+import { PLUGIN_OPERATIONS } from '@openedx/frontend-plugin-framework';
+
+const modifyUserMenuToggle = ( widget ) => {
+ // Shows a dummy image with the resolution marker '30x30'.
+ widget.content.avatar = "https://dummyimage.com/30x30"
+ return widget;
+};
+
+const config = {
+ pluginSlots: {
+ 'org.openedx.frontend.layout.header_mobile_user_menu_trigger.v1': {
+ keepDefault: true,
+ plugins: [
+ {
+ op: PLUGIN_OPERATIONS.Modify,
+ widgetId: 'default_contents',
+ fn: modifyUserMenuToggle,
+ },
+ ]
+ },
+ },
+}
+
+export default config;
+```
+
+### Replace Menu toggle contents with Custom Component
+
+The following `env.config.jsx` will replace the contents of the user menu toggle button's contents entirely (in this case with an emoji).
+
+
+
+```jsx
+import { DIRECT_PLUGIN, PLUGIN_OPERATIONS } from '@openedx/frontend-plugin-framework';
+
+const config = {
+ pluginSlots: {
+ 'org.openedx.frontend.layout.header_mobile_user_menu_trigger.v1': {
+ keepDefault: false,
+ plugins: [
+ {
+ op: PLUGIN_OPERATIONS.Insert,
+ widget: {
+ id: 'custom_mobile_user_menu_toggle',
+ type: DIRECT_PLUGIN,
+ RenderWidget: () => (
+ 🦊
+ ),
+ },
+ },
+ ]
+ },
+ },
+}
+
+export default config;
+```
diff --git a/src/plugin-slots/MobileUserMenuToggleSlot/images/mobile_user_menu_toggle_custom_component.png b/src/plugin-slots/MobileUserMenuToggleSlot/images/mobile_user_menu_toggle_custom_component.png
new file mode 100644
index 0000000..86a26fb
Binary files /dev/null and b/src/plugin-slots/MobileUserMenuToggleSlot/images/mobile_user_menu_toggle_custom_component.png differ
diff --git a/src/plugin-slots/MobileUserMenuToggleSlot/images/mobile_user_menu_toggle_modified_items.png b/src/plugin-slots/MobileUserMenuToggleSlot/images/mobile_user_menu_toggle_modified_items.png
new file mode 100644
index 0000000..476ddd7
Binary files /dev/null and b/src/plugin-slots/MobileUserMenuToggleSlot/images/mobile_user_menu_toggle_modified_items.png differ
diff --git a/src/plugin-slots/MobileUserMenuToggleSlot/index.jsx b/src/plugin-slots/MobileUserMenuToggleSlot/index.jsx
new file mode 100644
index 0000000..cb574ce
--- /dev/null
+++ b/src/plugin-slots/MobileUserMenuToggleSlot/index.jsx
@@ -0,0 +1,23 @@
+import React from 'react';
+import { PluginSlot } from '@openedx/frontend-plugin-framework';
+import MobileUserMenuToggle, {
+ MobileUserMenuTogglePropTypes,
+} from '../../mobile-header/MobileUserMenuToggle';
+
+const MobileUserMenuToggleSlot = ({
+ avatar,
+ label,
+}) => (
+
+);
+
+MobileUserMenuToggleSlot.propTypes = MobileUserMenuTogglePropTypes;
+
+export default MobileUserMenuToggleSlot;
diff --git a/src/plugin-slots/README.md b/src/plugin-slots/README.md
index 2cf12ce..21e158f 100644
--- a/src/plugin-slots/README.md
+++ b/src/plugin-slots/README.md
@@ -9,15 +9,18 @@
* [`org.openedx.frontend.layout.header_desktop_main_menu.v1`](./DesktopMainMenuSlot/)
* [`org.openedx.frontend.layout.header_desktop_secondary_menu.v1`](./DesktopSecondaryMenuSlot/)
* [`org.openedx.frontend.layout.header_desktop_user_menu.v1`](./DesktopUserMenuSlot/)
+* [`org.openedx.frontend.layout.header_desktop_user_menu_toggle.v1`](./DesktopUserMenuToggleSlot/)
### Learning Header
* [`org.openedx.frontend.layout.header_learning_course_info.v1`](./CourseInfoSlot/)
* [`org.openedx.frontend.layout.header_learning_help.v1`](./LearningHelpSlot/)
* [`org.openedx.frontend.layout.header_learning_logged_out_items.v1`](./LearningLoggedOutItemsSlot/)
* [`org.openedx.frontend.layout.header_learning_user_menu.v1`](./LearningUserMenuSlot/)
+* [`org.openedx.frontend.layout.header_learning_user_menu.v1`](./LearningUserMenuSlot/)
### Mobile Header
* [`org.openedx.frontend.layout.header_mobile.v1`](./MobileHeaderSlot/)
* [`org.openedx.frontend.layout.header_mobile_logged_out_items.v1`](./MobileLoggedOutItemsSlot/)
* [`org.openedx.frontend.layout.header_mobile_main_menu.v1`](./MobileMainMenuSlot/)
* [`org.openedx.frontend.layout.header_mobile_user_menu.v1`](./MobileUserMenuSlot/)
+* [`org.openedx.frontend.layout.header_mobile_user_menu_trigger.v1`](./MobileUserMenuToggleSlot/)