@nauedu/frontend-component-header 18.2.1 → 20.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (196) hide show
  1. package/README.rst +6 -0
  2. package/dist/Header.js +13 -9
  3. package/dist/Header.js.map +1 -1
  4. package/dist/Header.test.jsx +3 -0
  5. package/dist/Icons.js +1 -1
  6. package/dist/LanguageSelector/data/api.js +13 -5
  7. package/dist/LanguageSelector/data/api.js.map +1 -1
  8. package/dist/LanguageSelector/index.js +12 -4
  9. package/dist/LanguageSelector/index.js.map +1 -1
  10. package/dist/Logo.js +10 -23
  11. package/dist/Logo.js.map +1 -1
  12. package/dist/Menu/Menu.js +11 -11
  13. package/dist/Menu/Menu.js.map +1 -1
  14. package/dist/Menu/menu.scss +6 -6
  15. package/dist/__snapshots__/Header.test.jsx.snap +2 -0
  16. package/dist/desktop-header/DesktopHeader.js +172 -0
  17. package/dist/desktop-header/DesktopHeader.js.map +1 -0
  18. package/dist/desktop-header/DesktopHeaderMainOrSecondaryMenu.js +51 -0
  19. package/dist/desktop-header/DesktopHeaderMainOrSecondaryMenu.js.map +1 -0
  20. package/dist/desktop-header/DesktopHeaderUserMenu.js +49 -0
  21. package/dist/desktop-header/DesktopHeaderUserMenu.js.map +1 -0
  22. package/dist/desktop-header/DesktopLoggedOutItems.js +22 -0
  23. package/dist/desktop-header/DesktopLoggedOutItems.js.map +1 -0
  24. package/dist/desktop-header/DesktopUserMenuToggle.js +25 -0
  25. package/dist/desktop-header/DesktopUserMenuToggle.js.map +1 -0
  26. package/dist/frontend-platform.d.ts +41 -0
  27. package/dist/index.scss +27 -15
  28. package/dist/learning-header/AnonymousUserMenu.js +11 -8
  29. package/dist/learning-header/AnonymousUserMenu.js.map +1 -1
  30. package/dist/learning-header/AuthenticatedUserDropdown.js +32 -24
  31. package/dist/learning-header/AuthenticatedUserDropdown.js.map +1 -1
  32. package/dist/learning-header/LearningHeader.js +10 -11
  33. package/dist/learning-header/LearningHeader.js.map +1 -1
  34. package/dist/learning-header/LearningHeaderCourseInfo.js +24 -0
  35. package/dist/learning-header/LearningHeaderCourseInfo.js.map +1 -0
  36. package/dist/learning-header/LearningHeaderHelpLink.js +13 -0
  37. package/dist/learning-header/LearningHeaderHelpLink.js.map +1 -0
  38. package/dist/learning-header/LearningHeaderUserMenuItems.js +20 -0
  39. package/dist/learning-header/LearningHeaderUserMenuItems.js.map +1 -0
  40. package/dist/learning-header/LearningLoggedOutButtons.js +24 -0
  41. package/dist/learning-header/LearningLoggedOutButtons.js.map +1 -0
  42. package/dist/learning-header/LearningUserMenuToggle.js +26 -0
  43. package/dist/learning-header/LearningUserMenuToggle.js.map +1 -0
  44. package/dist/learning-header/data/api.js +12 -4
  45. package/dist/learning-header/data/api.js.map +1 -1
  46. package/dist/learning-header/data/api.test.js +92 -95
  47. package/dist/learning-header/data/api.test.js.map +1 -1
  48. package/dist/learning-header/messages.js +5 -0
  49. package/dist/learning-header/messages.js.map +1 -1
  50. package/dist/mobile-header/MobileHeader.js +197 -0
  51. package/dist/mobile-header/MobileHeader.js.map +1 -0
  52. package/dist/mobile-header/MobileHeaderMainMenu.js +46 -0
  53. package/dist/mobile-header/MobileHeaderMainMenu.js.map +1 -0
  54. package/dist/mobile-header/MobileHeaderUserMenu.js +38 -0
  55. package/dist/mobile-header/MobileHeaderUserMenu.js.map +1 -0
  56. package/dist/mobile-header/MobileLoggedOutItems.js +27 -0
  57. package/dist/mobile-header/MobileLoggedOutItems.js.map +1 -0
  58. package/dist/mobile-header/MobileUserMenuToggle.js +19 -0
  59. package/dist/mobile-header/MobileUserMenuToggle.js.map +1 -0
  60. package/dist/plugin-slots/CourseInfoSlot/README.md +128 -0
  61. package/dist/plugin-slots/CourseInfoSlot/images/add_custom_components_before_and_after_course_info.png +0 -0
  62. package/dist/plugin-slots/CourseInfoSlot/images/replace_course_info_with_custom_component.png +0 -0
  63. package/dist/plugin-slots/CourseInfoSlot/images/replace_course_title.png +0 -0
  64. package/dist/plugin-slots/CourseInfoSlot/index.js +32 -0
  65. package/dist/plugin-slots/CourseInfoSlot/index.js.map +1 -0
  66. package/dist/plugin-slots/DesktopHeaderSlot/README.md +44 -0
  67. package/dist/plugin-slots/DesktopHeaderSlot/images/desktop_header_custom_component.png +0 -0
  68. package/dist/plugin-slots/DesktopHeaderSlot/index.js +16 -0
  69. package/dist/plugin-slots/DesktopHeaderSlot/index.js.map +1 -0
  70. package/dist/plugin-slots/DesktopLoggedOutItemsSlot/README.md +137 -0
  71. package/dist/plugin-slots/DesktopLoggedOutItemsSlot/images/desktop_logged_out_items_custom_component.png +0 -0
  72. package/dist/plugin-slots/DesktopLoggedOutItemsSlot/images/desktop_logged_out_items_custom_components_before_after.png +0 -0
  73. package/dist/plugin-slots/DesktopLoggedOutItemsSlot/images/desktop_logged_out_items_modify_items.png +0 -0
  74. package/dist/plugin-slots/DesktopLoggedOutItemsSlot/index.js +20 -0
  75. package/dist/plugin-slots/DesktopLoggedOutItemsSlot/index.js.map +1 -0
  76. package/dist/plugin-slots/DesktopMainMenuSlot/README.md +137 -0
  77. package/dist/plugin-slots/DesktopMainMenuSlot/images/desktop_main_menu_custom_component.png +0 -0
  78. package/dist/plugin-slots/DesktopMainMenuSlot/images/desktop_main_menu_custom_components_before_after.png +0 -0
  79. package/dist/plugin-slots/DesktopMainMenuSlot/images/desktop_main_menu_modify_items.png +0 -0
  80. package/dist/plugin-slots/DesktopMainMenuSlot/index.js +20 -0
  81. package/dist/plugin-slots/DesktopMainMenuSlot/index.js.map +1 -0
  82. package/dist/plugin-slots/DesktopSecondaryMenuSlot/README.md +132 -0
  83. package/dist/plugin-slots/DesktopSecondaryMenuSlot/images/desktop_secondary_menu_custom_component.png +0 -0
  84. package/dist/plugin-slots/DesktopSecondaryMenuSlot/images/desktop_secondary_menu_custom_components_before_after.png +0 -0
  85. package/dist/plugin-slots/DesktopSecondaryMenuSlot/images/desktop_secondary_menu_modify_items.png +0 -0
  86. package/dist/plugin-slots/DesktopSecondaryMenuSlot/index.js +20 -0
  87. package/dist/plugin-slots/DesktopSecondaryMenuSlot/index.js.map +1 -0
  88. package/dist/plugin-slots/DesktopUserMenuSlot/README.md +144 -0
  89. package/dist/plugin-slots/DesktopUserMenuSlot/images/desktop_user_menu_custom_component.png +0 -0
  90. package/dist/plugin-slots/DesktopUserMenuSlot/images/desktop_user_menu_custom_components_before_after.png +0 -0
  91. package/dist/plugin-slots/DesktopUserMenuSlot/images/desktop_user_menu_modify_items.png +0 -0
  92. package/dist/plugin-slots/DesktopUserMenuSlot/index.js +20 -0
  93. package/dist/plugin-slots/DesktopUserMenuSlot/index.js.map +1 -0
  94. package/dist/plugin-slots/DesktopUserMenuToggleSlot/README.md +74 -0
  95. package/dist/plugin-slots/DesktopUserMenuToggleSlot/images/desktop_user_menu_custom_component.png +0 -0
  96. package/dist/plugin-slots/DesktopUserMenuToggleSlot/images/desktop_user_menu_modified_toggle.png +0 -0
  97. package/dist/plugin-slots/DesktopUserMenuToggleSlot/index.js +19 -0
  98. package/dist/plugin-slots/DesktopUserMenuToggleSlot/index.js.map +1 -0
  99. package/dist/plugin-slots/LearningHelpSlot/README.md +44 -0
  100. package/dist/plugin-slots/LearningHelpSlot/images/learning_help_custom_component.png +0 -0
  101. package/dist/plugin-slots/LearningHelpSlot/index.js +11 -0
  102. package/dist/plugin-slots/LearningHelpSlot/index.js.map +1 -0
  103. package/dist/plugin-slots/LearningLoggedOutItemsSlot/README.md +135 -0
  104. package/dist/plugin-slots/LearningLoggedOutItemsSlot/images/learning_logged_out_items_custom_component.png +0 -0
  105. package/dist/plugin-slots/LearningLoggedOutItemsSlot/images/learning_logged_out_items_custom_components_before_after.png +0 -0
  106. package/dist/plugin-slots/LearningLoggedOutItemsSlot/images/learning_logged_out_items_modified_items.png +0 -0
  107. package/dist/plugin-slots/LearningLoggedOutItemsSlot/index.js +18 -0
  108. package/dist/plugin-slots/LearningLoggedOutItemsSlot/index.js.map +1 -0
  109. package/dist/plugin-slots/LearningUserMenuSlot/README.md +133 -0
  110. package/dist/plugin-slots/LearningUserMenuSlot/images/learning_user_menu_custom_component.png +0 -0
  111. package/dist/plugin-slots/LearningUserMenuSlot/images/learning_user_menu_custom_components_before_after.png +0 -0
  112. package/dist/plugin-slots/LearningUserMenuSlot/images/learning_user_menu_modified_items.png +0 -0
  113. package/dist/plugin-slots/LearningUserMenuSlot/index.js +18 -0
  114. package/dist/plugin-slots/LearningUserMenuSlot/index.js.map +1 -0
  115. package/dist/plugin-slots/LearningUserMenuToggleSlot/README.md +74 -0
  116. package/dist/plugin-slots/LearningUserMenuToggleSlot/images/learning_user_menu_toggle_custom_component.png +0 -0
  117. package/dist/plugin-slots/LearningUserMenuToggleSlot/images/learning_user_menu_toggle_modified_items.png +0 -0
  118. package/dist/plugin-slots/LearningUserMenuToggleSlot/index.js +19 -0
  119. package/dist/plugin-slots/LearningUserMenuToggleSlot/index.js.map +1 -0
  120. package/dist/plugin-slots/LogoSlot/README.md +72 -0
  121. package/dist/plugin-slots/LogoSlot/index.js +27 -0
  122. package/dist/plugin-slots/LogoSlot/index.js.map +1 -0
  123. package/dist/plugin-slots/MobileHeaderSlot/README.md +44 -0
  124. package/dist/plugin-slots/MobileHeaderSlot/images/mobile_header_custom_component.png +0 -0
  125. package/dist/plugin-slots/MobileHeaderSlot/index.js +16 -0
  126. package/dist/plugin-slots/MobileHeaderSlot/index.js.map +1 -0
  127. package/dist/plugin-slots/MobileLoggedOutItemsSlot/README.md +136 -0
  128. package/dist/plugin-slots/MobileLoggedOutItemsSlot/images/mobile_logged_out_items_custom_component.png +0 -0
  129. package/dist/plugin-slots/MobileLoggedOutItemsSlot/images/mobile_logged_out_items_custom_components_before_after.png +0 -0
  130. package/dist/plugin-slots/MobileLoggedOutItemsSlot/images/mobile_logged_out_items_modify_items.png +0 -0
  131. package/dist/plugin-slots/MobileLoggedOutItemsSlot/index.js +20 -0
  132. package/dist/plugin-slots/MobileLoggedOutItemsSlot/index.js.map +1 -0
  133. package/dist/plugin-slots/MobileMainMenuSlot/README.md +136 -0
  134. package/dist/plugin-slots/MobileMainMenuSlot/images/mobile_main_menu_custom_component.png +0 -0
  135. package/dist/plugin-slots/MobileMainMenuSlot/images/mobile_main_menu_custom_components_before_after.png +0 -0
  136. package/dist/plugin-slots/MobileMainMenuSlot/images/mobile_main_menu_modify_items.png +0 -0
  137. package/dist/plugin-slots/MobileMainMenuSlot/index.js +20 -0
  138. package/dist/plugin-slots/MobileMainMenuSlot/index.js.map +1 -0
  139. package/dist/plugin-slots/MobileUserMenuSlot/README.md +144 -0
  140. package/dist/plugin-slots/MobileUserMenuSlot/images/mobile_user_menu_custom_component.png +0 -0
  141. package/dist/plugin-slots/MobileUserMenuSlot/images/mobile_user_menu_custom_components_before_after.png +0 -0
  142. package/dist/plugin-slots/MobileUserMenuSlot/images/mobile_user_menu_modify_items.png +0 -0
  143. package/dist/plugin-slots/MobileUserMenuSlot/index.js +20 -0
  144. package/dist/plugin-slots/MobileUserMenuSlot/index.js.map +1 -0
  145. package/dist/plugin-slots/MobileUserMenuToggleSlot/README.md +74 -0
  146. package/dist/plugin-slots/MobileUserMenuToggleSlot/images/mobile_user_menu_toggle_custom_component.png +0 -0
  147. package/dist/plugin-slots/MobileUserMenuToggleSlot/images/mobile_user_menu_toggle_modified_items.png +0 -0
  148. package/dist/plugin-slots/MobileUserMenuToggleSlot/index.js +19 -0
  149. package/dist/plugin-slots/MobileUserMenuToggleSlot/index.js.map +1 -0
  150. package/dist/plugin-slots/README.md +26 -0
  151. package/dist/setupTest.js +0 -2
  152. package/dist/studio-header/BrandNav.test.tsx +40 -0
  153. package/dist/studio-header/BrandNav.tsx +25 -0
  154. package/dist/studio-header/CourseLockUp.test.tsx +59 -0
  155. package/dist/studio-header/CourseLockUp.tsx +56 -0
  156. package/dist/studio-header/HeaderBody.test.tsx +102 -0
  157. package/dist/studio-header/HeaderBody.tsx +196 -0
  158. package/dist/studio-header/MobileHeader.tsx +74 -0
  159. package/dist/studio-header/MobileMenu.test.tsx +81 -0
  160. package/dist/studio-header/MobileMenu.tsx +50 -0
  161. package/dist/studio-header/NavDropdownMenu.test.tsx +67 -0
  162. package/dist/studio-header/NavDropdownMenu.tsx +42 -0
  163. package/dist/studio-header/StudioHeader.scss +8 -8
  164. package/dist/studio-header/StudioHeader.test.tsx +220 -0
  165. package/dist/studio-header/StudioHeader.tsx +84 -0
  166. package/dist/studio-header/UserMenu.tsx +69 -0
  167. package/dist/studio-header/{index.js → index.ts} +1 -1
  168. package/dist/studio-header/{messages.js → messages.ts} +15 -14
  169. package/dist/studio-header/utils.ts +37 -0
  170. package/dist/test-utils.js +12 -4
  171. package/dist/test-utils.js.map +1 -1
  172. package/package.json +28 -30
  173. package/dist/DesktopHeader.js +0 -242
  174. package/dist/DesktopHeader.js.map +0 -1
  175. package/dist/MobileHeader.js +0 -244
  176. package/dist/MobileHeader.js.map +0 -1
  177. package/dist/studio-header/BrandNav.js +0 -21
  178. package/dist/studio-header/BrandNav.js.map +0 -1
  179. package/dist/studio-header/CourseLockUp.js +0 -45
  180. package/dist/studio-header/CourseLockUp.js.map +0 -1
  181. package/dist/studio-header/HeaderBody.js +0 -131
  182. package/dist/studio-header/HeaderBody.js.map +0 -1
  183. package/dist/studio-header/MobileHeader.js +0 -79
  184. package/dist/studio-header/MobileHeader.js.map +0 -1
  185. package/dist/studio-header/MobileMenu.js +0 -45
  186. package/dist/studio-header/MobileMenu.js.map +0 -1
  187. package/dist/studio-header/NavDropdownMenu.js +0 -30
  188. package/dist/studio-header/NavDropdownMenu.js.map +0 -1
  189. package/dist/studio-header/StudioHeader.js +0 -72
  190. package/dist/studio-header/StudioHeader.js.map +0 -1
  191. package/dist/studio-header/UserMenu.js +0 -55
  192. package/dist/studio-header/UserMenu.js.map +0 -1
  193. package/dist/studio-header/index.js.map +0 -1
  194. package/dist/studio-header/messages.js.map +0 -1
  195. package/dist/studio-header/utils.js +0 -29
  196. package/dist/studio-header/utils.js.map +0 -1
@@ -0,0 +1,136 @@
1
+ # Mobile Main Menu Slot
2
+
3
+ ### Slot ID: `org.openedx.frontend.layout.header_mobile_main_menu.v1`
4
+
5
+ ### Slot ID Aliases
6
+ * `mobile_main_menu_slot`
7
+
8
+ ## Description
9
+
10
+ This slot is used to replace/modify/hide the mobile main menu.
11
+
12
+ ## Examples
13
+
14
+ ### Modify Items
15
+
16
+ The following `env.config.jsx` will modify the items in the mobile main menu.
17
+
18
+ ![Screenshot of modified items](./images/mobile_main_menu_modify_items.png)
19
+
20
+ ```jsx
21
+ import { PLUGIN_OPERATIONS } from '@openedx/frontend-plugin-framework';
22
+
23
+ const modifyMainMenu = ( widget ) => {
24
+ widget.content.menu = [
25
+ {
26
+ type: 'item',
27
+ href: 'https://openedx.org/',
28
+ content: 'openedx.org',
29
+ },
30
+ {
31
+ type: 'item',
32
+ href: 'https://docs.openedx.org/en/latest/',
33
+ content: 'Documentation',
34
+ },
35
+ {
36
+ type: 'item',
37
+ href: 'https://discuss.openedx.org/',
38
+ content: 'Forums',
39
+ }
40
+ ];
41
+ return widget;
42
+ };
43
+
44
+ const config = {
45
+ pluginSlots: {
46
+ 'org.openedx.frontend.layout.header_mobile_main_menu.v1': {
47
+ keepDefault: true,
48
+ plugins: [
49
+ {
50
+ op: PLUGIN_OPERATIONS.Modify,
51
+ widgetId: 'default_contents',
52
+ fn: modifyMainMenu,
53
+ },
54
+ ]
55
+ },
56
+ },
57
+ }
58
+
59
+ export default config;
60
+ ```
61
+
62
+ ### Replace Menu with Custom Component
63
+
64
+ The following `env.config.jsx` will replace the mobile main menu entirely (in this case with a centered 🗺️ `h1`)
65
+
66
+ ![Screenshot of custom component](./images/mobile_main_menu_custom_component.png)
67
+
68
+ ```jsx
69
+ import { DIRECT_PLUGIN, PLUGIN_OPERATIONS } from '@openedx/frontend-plugin-framework';
70
+
71
+ const config = {
72
+ pluginSlots: {
73
+ 'org.openedx.frontend.layout.header_mobile_main_menu.v1': {
74
+ keepDefault: false,
75
+ plugins: [
76
+ {
77
+ op: PLUGIN_OPERATIONS.Insert,
78
+ widget: {
79
+ id: 'custom_main_menu_component',
80
+ type: DIRECT_PLUGIN,
81
+ RenderWidget: () => (
82
+ <h1 style={{textAlign: 'center'}}>🗺️</h1>
83
+ ),
84
+ },
85
+ },
86
+ ]
87
+ },
88
+ },
89
+ }
90
+
91
+ export default config;
92
+ ```
93
+
94
+ ### Add Custom Components before and after Menu
95
+
96
+ The following `env.config.jsx` will place custom components before and after the mobile main menu (in this case centered `h1`s with 🌞 and 🌚).
97
+
98
+ ![Screenshot of custom components before and after](./images/mobile_main_menu_custom_components_before_after.png)
99
+
100
+ ```jsx
101
+ import { DIRECT_PLUGIN, PLUGIN_OPERATIONS } from '@openedx/frontend-plugin-framework';
102
+
103
+ const config = {
104
+ pluginSlots: {
105
+ 'org.openedx.frontend.layout.header_mobile_main_menu.v1': {
106
+ keepDefault: true,
107
+ plugins: [
108
+ {
109
+ op: PLUGIN_OPERATIONS.Insert,
110
+ widget: {
111
+ id: 'custom_before_main_menu_component',
112
+ type: DIRECT_PLUGIN,
113
+ priority: 10,
114
+ RenderWidget: () => (
115
+ <h1 style={{textAlign: 'center'}}>🌞</h1>
116
+ ),
117
+ },
118
+ },
119
+ {
120
+ op: PLUGIN_OPERATIONS.Insert,
121
+ widget: {
122
+ id: 'custom_after_main_menu_component',
123
+ type: DIRECT_PLUGIN,
124
+ priority: 90,
125
+ RenderWidget: () => (
126
+ <h1 style={{textAlign: 'center'}}>🌚</h1>
127
+ ),
128
+ },
129
+ },
130
+ ]
131
+ },
132
+ },
133
+ }
134
+
135
+ export default config;
136
+ ```
@@ -0,0 +1,20 @@
1
+ import React from 'react';
2
+ import { PluginSlot } from '@openedx/frontend-plugin-framework';
3
+ import MobileHeaderMainMenu, { mobileHeaderMainMenuDataShape } from '../../mobile-header/MobileHeaderMainMenu';
4
+ var MobileMainMenuSlot = function MobileMainMenuSlot(_ref) {
5
+ var menu = _ref.menu;
6
+ return /*#__PURE__*/React.createElement(PluginSlot, {
7
+ id: "org.openedx.frontend.layout.header_mobile_main_menu.v1",
8
+ idAliases: ['mobile_main_menu_slot'],
9
+ slotOptions: {
10
+ mergeProps: true
11
+ }
12
+ }, /*#__PURE__*/React.createElement(MobileHeaderMainMenu, {
13
+ menu: menu
14
+ }));
15
+ };
16
+ MobileMainMenuSlot.propTypes = {
17
+ menu: mobileHeaderMainMenuDataShape
18
+ };
19
+ export default MobileMainMenuSlot;
20
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":["React","PluginSlot","MobileHeaderMainMenu","mobileHeaderMainMenuDataShape","MobileMainMenuSlot","_ref","menu","createElement","id","idAliases","slotOptions","mergeProps","propTypes"],"sources":["../../../src/plugin-slots/MobileMainMenuSlot/index.jsx"],"sourcesContent":["import React from 'react';\nimport { PluginSlot } from '@openedx/frontend-plugin-framework';\nimport MobileHeaderMainMenu, { mobileHeaderMainMenuDataShape } from '../../mobile-header/MobileHeaderMainMenu';\n\nconst MobileMainMenuSlot = ({\n menu,\n}) => (\n <PluginSlot\n id=\"org.openedx.frontend.layout.header_mobile_main_menu.v1\"\n idAliases={['mobile_main_menu_slot']}\n slotOptions={{\n mergeProps: true,\n }}\n >\n <MobileHeaderMainMenu menu={menu} />\n </PluginSlot>\n);\n\nMobileMainMenuSlot.propTypes = {\n menu: mobileHeaderMainMenuDataShape,\n};\n\nexport default MobileMainMenuSlot;\n"],"mappings":"AAAA,OAAOA,KAAK,MAAM,OAAO;AACzB,SAASC,UAAU,QAAQ,oCAAoC;AAC/D,OAAOC,oBAAoB,IAAIC,6BAA6B,QAAQ,0CAA0C;AAE9G,IAAMC,kBAAkB,GAAG,SAArBA,kBAAkBA,CAAAC,IAAA;EAAA,IACtBC,IAAI,GAAAD,IAAA,CAAJC,IAAI;EAAA,oBAEJN,KAAA,CAAAO,aAAA,CAACN,UAAU;IACTO,EAAE,EAAC,wDAAwD;IAC3DC,SAAS,EAAE,CAAC,uBAAuB,CAAE;IACrCC,WAAW,EAAE;MACXC,UAAU,EAAE;IACd;EAAE,gBAEFX,KAAA,CAAAO,aAAA,CAACL,oBAAoB;IAACI,IAAI,EAAEA;EAAK,CAAE,CACzB,CAAC;AAAA,CACd;AAEDF,kBAAkB,CAACQ,SAAS,GAAG;EAC7BN,IAAI,EAAEH;AACR,CAAC;AAED,eAAeC,kBAAkB","ignoreList":[]}
@@ -0,0 +1,144 @@
1
+ # Mobile User Menu Slot
2
+
3
+ ### Slot ID: `org.openedx.frontend.layout.header_mobile_user_menu.v1`
4
+
5
+ ### Slot ID Aliases
6
+ * `mobile_user_menu_slot`
7
+
8
+ ## Description
9
+
10
+ This slot is used to replace/modify/hide the mobile user menu.
11
+
12
+ ## Examples
13
+
14
+ ### Modify Items
15
+
16
+ The following `env.config.jsx` will modify the items in the mobile user menu.
17
+
18
+ ![Screenshot of modified items](./images/mobile_user_menu_modify_items.png)
19
+
20
+ ```jsx
21
+ import { PLUGIN_OPERATIONS } from '@openedx/frontend-plugin-framework';
22
+
23
+ const modifyUserMenu = ( widget ) => {
24
+ widget.content.menu = [
25
+ {
26
+ items: [
27
+ {
28
+ type: 'item',
29
+ href: 'https://openedx.org/',
30
+ content: 'openedx.org',
31
+ },
32
+ {
33
+ type: 'item',
34
+ href: 'https://docs.openedx.org/en/latest/',
35
+ content: 'Documentation',
36
+ },
37
+ ]
38
+ },
39
+ {
40
+ items: [
41
+ {
42
+ type: 'item',
43
+ href: 'https://discuss.openedx.org/',
44
+ content: 'Forums',
45
+ }
46
+ ]
47
+ }
48
+ ];
49
+ return widget;
50
+ };
51
+
52
+ const config = {
53
+ pluginSlots: {
54
+ 'org.openedx.frontend.layout.header_mobile_user_menu.v1': {
55
+ keepDefault: true,
56
+ plugins: [
57
+ {
58
+ op: PLUGIN_OPERATIONS.Modify,
59
+ widgetId: 'default_contents',
60
+ fn: modifyUserMenu,
61
+ },
62
+ ]
63
+ },
64
+ },
65
+ }
66
+
67
+ export default config;
68
+ ```
69
+
70
+ ### Replace Menu with Custom Component
71
+
72
+ The following `env.config.jsx` will replace the mobile main user entirely (in this case with a centered 🗺️ `h1`)
73
+
74
+ ![Screenshot of custom component](./images/mobile_user_menu_custom_component.png)
75
+
76
+ ```jsx
77
+ import { DIRECT_PLUGIN, PLUGIN_OPERATIONS } from '@openedx/frontend-plugin-framework';
78
+
79
+ const config = {
80
+ pluginSlots: {
81
+ 'org.openedx.frontend.layout.header_mobile_user_menu.v1': {
82
+ keepDefault: false,
83
+ plugins: [
84
+ {
85
+ op: PLUGIN_OPERATIONS.Insert,
86
+ widget: {
87
+ id: 'custom_user_menu_component',
88
+ type: DIRECT_PLUGIN,
89
+ RenderWidget: () => (
90
+ <h1 style={{textAlign: 'center'}}>🗺️</h1>
91
+ ),
92
+ },
93
+ },
94
+ ]
95
+ },
96
+ },
97
+ }
98
+
99
+ export default config;
100
+ ```
101
+
102
+ ### Add Custom Components before and after Menu
103
+
104
+ The following `env.config.jsx` will place custom components before and after the mobile user menu (in this case centered `h1`s with 🌞 and 🌚).
105
+
106
+ ![Screenshot of custom components before and after](./images/mobile_user_menu_custom_components_before_after.png)
107
+
108
+ ```jsx
109
+ import { DIRECT_PLUGIN, PLUGIN_OPERATIONS } from '@openedx/frontend-plugin-framework';
110
+
111
+ const config = {
112
+ pluginSlots: {
113
+ 'org.openedx.frontend.layout.header_mobile_user_menu.v1': {
114
+ keepDefault: true,
115
+ plugins: [
116
+ {
117
+ op: PLUGIN_OPERATIONS.Insert,
118
+ widget: {
119
+ id: 'custom_before_user_menu_component',
120
+ type: DIRECT_PLUGIN,
121
+ priority: 10,
122
+ RenderWidget: () => (
123
+ <h1 style={{textAlign: 'center'}}>🌞</h1>
124
+ ),
125
+ },
126
+ },
127
+ {
128
+ op: PLUGIN_OPERATIONS.Insert,
129
+ widget: {
130
+ id: 'custom_after_user_menu_component',
131
+ type: DIRECT_PLUGIN,
132
+ priority: 90,
133
+ RenderWidget: () => (
134
+ <h1 style={{textAlign: 'center'}}>🌚</h1>
135
+ ),
136
+ },
137
+ },
138
+ ]
139
+ },
140
+ },
141
+ }
142
+
143
+ export default config;
144
+ ```
@@ -0,0 +1,20 @@
1
+ import React from 'react';
2
+ import { PluginSlot } from '@openedx/frontend-plugin-framework';
3
+ import MobileHeaderUserMenu, { mobileHeaderUserMenuDataShape } from '../../mobile-header/MobileHeaderUserMenu';
4
+ var MobileUserMenuSlot = function MobileUserMenuSlot(_ref) {
5
+ var menu = _ref.menu;
6
+ return /*#__PURE__*/React.createElement(PluginSlot, {
7
+ id: "org.openedx.frontend.layout.header_mobile_user_menu.v1",
8
+ idAliases: ['mobile_user_menu_slot'],
9
+ slotOptions: {
10
+ mergeProps: true
11
+ }
12
+ }, /*#__PURE__*/React.createElement(MobileHeaderUserMenu, {
13
+ menu: menu
14
+ }));
15
+ };
16
+ MobileUserMenuSlot.propTypes = {
17
+ menu: mobileHeaderUserMenuDataShape
18
+ };
19
+ export default MobileUserMenuSlot;
20
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":["React","PluginSlot","MobileHeaderUserMenu","mobileHeaderUserMenuDataShape","MobileUserMenuSlot","_ref","menu","createElement","id","idAliases","slotOptions","mergeProps","propTypes"],"sources":["../../../src/plugin-slots/MobileUserMenuSlot/index.jsx"],"sourcesContent":["import React from 'react';\nimport { PluginSlot } from '@openedx/frontend-plugin-framework';\nimport MobileHeaderUserMenu, { mobileHeaderUserMenuDataShape } from '../../mobile-header/MobileHeaderUserMenu';\n\nconst MobileUserMenuSlot = ({\n menu,\n}) => (\n <PluginSlot\n id=\"org.openedx.frontend.layout.header_mobile_user_menu.v1\"\n idAliases={['mobile_user_menu_slot']}\n slotOptions={{\n mergeProps: true,\n }}\n >\n <MobileHeaderUserMenu menu={menu} />\n </PluginSlot>\n);\n\nMobileUserMenuSlot.propTypes = {\n menu: mobileHeaderUserMenuDataShape,\n};\n\nexport default MobileUserMenuSlot;\n"],"mappings":"AAAA,OAAOA,KAAK,MAAM,OAAO;AACzB,SAASC,UAAU,QAAQ,oCAAoC;AAC/D,OAAOC,oBAAoB,IAAIC,6BAA6B,QAAQ,0CAA0C;AAE9G,IAAMC,kBAAkB,GAAG,SAArBA,kBAAkBA,CAAAC,IAAA;EAAA,IACtBC,IAAI,GAAAD,IAAA,CAAJC,IAAI;EAAA,oBAEJN,KAAA,CAAAO,aAAA,CAACN,UAAU;IACTO,EAAE,EAAC,wDAAwD;IAC3DC,SAAS,EAAE,CAAC,uBAAuB,CAAE;IACrCC,WAAW,EAAE;MACXC,UAAU,EAAE;IACd;EAAE,gBAEFX,KAAA,CAAAO,aAAA,CAACL,oBAAoB;IAACI,IAAI,EAAEA;EAAK,CAAE,CACzB,CAAC;AAAA,CACd;AAEDF,kBAAkB,CAACQ,SAAS,GAAG;EAC7BN,IAAI,EAAEH;AACR,CAAC;AAED,eAAeC,kBAAkB","ignoreList":[]}
@@ -0,0 +1,74 @@
1
+ # Mobile User Menu Toggle Slot
2
+
3
+ ### Slot ID: `org.openedx.frontend.layout.header_mobile_user_menu_trigger.v1`
4
+
5
+ ## Description
6
+
7
+ This slot is used to replace/modify/hide the contents of the user menu toggle button on mobile screens.
8
+
9
+ ## Examples
10
+
11
+ ### Modify Avatar
12
+
13
+ The following `env.config.jsx` will modify the icon for the user menu toggle button on mobile.
14
+
15
+ ![Screenshot of modified items](./images/mobile_user_menu_toggle_modified_items.png)
16
+
17
+ ```jsx
18
+ import { PLUGIN_OPERATIONS } from '@openedx/frontend-plugin-framework';
19
+
20
+ const modifyUserMenuToggle = ( widget ) => {
21
+ // Shows a dummy image with the resolution marker '30x30'.
22
+ widget.content.avatar = "https://dummyimage.com/30x30"
23
+ return widget;
24
+ };
25
+
26
+ const config = {
27
+ pluginSlots: {
28
+ 'org.openedx.frontend.layout.header_mobile_user_menu_trigger.v1': {
29
+ keepDefault: true,
30
+ plugins: [
31
+ {
32
+ op: PLUGIN_OPERATIONS.Modify,
33
+ widgetId: 'default_contents',
34
+ fn: modifyUserMenuToggle,
35
+ },
36
+ ]
37
+ },
38
+ },
39
+ }
40
+
41
+ export default config;
42
+ ```
43
+
44
+ ### Replace Menu toggle contents with Custom Component
45
+
46
+ The following `env.config.jsx` will replace the contents of the user menu toggle button's contents entirely (in this case with an emoji).
47
+
48
+ ![Screenshot of replaced with custom component](./images/mobile_user_menu_toggle_custom_component.png)
49
+
50
+ ```jsx
51
+ import { DIRECT_PLUGIN, PLUGIN_OPERATIONS } from '@openedx/frontend-plugin-framework';
52
+
53
+ const config = {
54
+ pluginSlots: {
55
+ 'org.openedx.frontend.layout.header_mobile_user_menu_trigger.v1': {
56
+ keepDefault: false,
57
+ plugins: [
58
+ {
59
+ op: PLUGIN_OPERATIONS.Insert,
60
+ widget: {
61
+ id: 'custom_mobile_user_menu_toggle',
62
+ type: DIRECT_PLUGIN,
63
+ RenderWidget: () => (
64
+ <span>🦊</span>
65
+ ),
66
+ },
67
+ },
68
+ ]
69
+ },
70
+ },
71
+ }
72
+
73
+ export default config;
74
+ ```
@@ -0,0 +1,19 @@
1
+ import React from 'react';
2
+ import { PluginSlot } from '@openedx/frontend-plugin-framework';
3
+ import MobileUserMenuToggle, { MobileUserMenuTogglePropTypes } from '../../mobile-header/MobileUserMenuToggle';
4
+ var MobileUserMenuToggleSlot = function MobileUserMenuToggleSlot(_ref) {
5
+ var avatar = _ref.avatar,
6
+ label = _ref.label;
7
+ return /*#__PURE__*/React.createElement(PluginSlot, {
8
+ id: "org.openedx.frontend.layout.header_mobile_user_menu_trigger.v1",
9
+ slotOptions: {
10
+ mergeProps: true
11
+ }
12
+ }, /*#__PURE__*/React.createElement(MobileUserMenuToggle, {
13
+ avatar: avatar,
14
+ label: label
15
+ }));
16
+ };
17
+ MobileUserMenuToggleSlot.propTypes = MobileUserMenuTogglePropTypes;
18
+ export default MobileUserMenuToggleSlot;
19
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":["React","PluginSlot","MobileUserMenuToggle","MobileUserMenuTogglePropTypes","MobileUserMenuToggleSlot","_ref","avatar","label","createElement","id","slotOptions","mergeProps","propTypes"],"sources":["../../../src/plugin-slots/MobileUserMenuToggleSlot/index.jsx"],"sourcesContent":["import React from 'react';\nimport { PluginSlot } from '@openedx/frontend-plugin-framework';\nimport MobileUserMenuToggle, {\n MobileUserMenuTogglePropTypes,\n} from '../../mobile-header/MobileUserMenuToggle';\n\nconst MobileUserMenuToggleSlot = ({\n avatar,\n label,\n}) => (\n <PluginSlot\n id=\"org.openedx.frontend.layout.header_mobile_user_menu_trigger.v1\"\n slotOptions={{\n mergeProps: true,\n }}\n >\n <MobileUserMenuToggle avatar={avatar} label={label} />\n </PluginSlot>\n);\n\nMobileUserMenuToggleSlot.propTypes = MobileUserMenuTogglePropTypes;\n\nexport default MobileUserMenuToggleSlot;\n"],"mappings":"AAAA,OAAOA,KAAK,MAAM,OAAO;AACzB,SAASC,UAAU,QAAQ,oCAAoC;AAC/D,OAAOC,oBAAoB,IACzBC,6BAA6B,QACxB,0CAA0C;AAEjD,IAAMC,wBAAwB,GAAG,SAA3BA,wBAAwBA,CAAAC,IAAA;EAAA,IAC5BC,MAAM,GAAAD,IAAA,CAANC,MAAM;IACNC,KAAK,GAAAF,IAAA,CAALE,KAAK;EAAA,oBAELP,KAAA,CAAAQ,aAAA,CAACP,UAAU;IACTQ,EAAE,EAAC,gEAAgE;IACnEC,WAAW,EAAE;MACXC,UAAU,EAAE;IACd;EAAE,gBAEFX,KAAA,CAAAQ,aAAA,CAACN,oBAAoB;IAACI,MAAM,EAAEA,MAAO;IAACC,KAAK,EAAEA;EAAM,CAAE,CAC3C,CAAC;AAAA,CACd;AAEDH,wBAAwB,CAACQ,SAAS,GAAGT,6BAA6B;AAElE,eAAeC,wBAAwB","ignoreList":[]}
@@ -0,0 +1,26 @@
1
+ # `frontend-component-header` Plugin Slots
2
+
3
+ ### Shared
4
+ * [`org.openedx.frontend.layout.header_logo.v1`](./LogoSlot/)
5
+
6
+ ### Desktop Header
7
+ * [`org.openedx.frontend.layout.header_desktop.v1`](./DesktopHeaderSlot/)
8
+ * [`org.openedx.frontend.layout.header_desktop_logged_out_items.v1`](./DesktopLoggedOutItemsSlot/)
9
+ * [`org.openedx.frontend.layout.header_desktop_main_menu.v1`](./DesktopMainMenuSlot/)
10
+ * [`org.openedx.frontend.layout.header_desktop_secondary_menu.v1`](./DesktopSecondaryMenuSlot/)
11
+ * [`org.openedx.frontend.layout.header_desktop_user_menu.v1`](./DesktopUserMenuSlot/)
12
+ * [`org.openedx.frontend.layout.header_desktop_user_menu_toggle.v1`](./DesktopUserMenuToggleSlot/)
13
+
14
+ ### Learning Header
15
+ * [`org.openedx.frontend.layout.header_learning_course_info.v1`](./CourseInfoSlot/)
16
+ * [`org.openedx.frontend.layout.header_learning_help.v1`](./LearningHelpSlot/)
17
+ * [`org.openedx.frontend.layout.header_learning_logged_out_items.v1`](./LearningLoggedOutItemsSlot/)
18
+ * [`org.openedx.frontend.layout.header_learning_user_menu.v1`](./LearningUserMenuSlot/)
19
+ * [`org.openedx.frontend.layout.header_learning_user_menu.v1`](./LearningUserMenuSlot/)
20
+
21
+ ### Mobile Header
22
+ * [`org.openedx.frontend.layout.header_mobile.v1`](./MobileHeaderSlot/)
23
+ * [`org.openedx.frontend.layout.header_mobile_logged_out_items.v1`](./MobileLoggedOutItemsSlot/)
24
+ * [`org.openedx.frontend.layout.header_mobile_main_menu.v1`](./MobileMainMenuSlot/)
25
+ * [`org.openedx.frontend.layout.header_mobile_user_menu.v1`](./MobileUserMenuSlot/)
26
+ * [`org.openedx.frontend.layout.header_mobile_user_menu_trigger.v1`](./MobileUserMenuToggleSlot/)
package/dist/setupTest.js CHANGED
@@ -4,8 +4,6 @@ import React from 'react';
4
4
  import PropTypes from 'prop-types';
5
5
  import '@testing-library/jest-dom';
6
6
  import '@testing-library/jest-dom/extend-expect';
7
- import 'babel-polyfill';
8
- import 'jest-chain';
9
7
  import { getConfig, mergeConfig } from '@edx/frontend-platform';
10
8
  import { configure as configureLogging } from '@edx/frontend-platform/logging';
11
9
  import { configure as configureI18n } from '@edx/frontend-platform/i18n';
@@ -0,0 +1,40 @@
1
+ import React from 'react';
2
+ import { render, screen } from '@testing-library/react';
3
+ import '@testing-library/jest-dom/extend-expect';
4
+ import { MemoryRouter } from 'react-router-dom';
5
+
6
+ import BrandNav from './BrandNav';
7
+
8
+ const studioBaseUrl = 'https://example.com/';
9
+ const logo = 'logo.png';
10
+ const logoAltText = 'Example Logo';
11
+
12
+ const RootWrapper = () => (
13
+ <MemoryRouter>
14
+ <BrandNav
15
+ studioBaseUrl={studioBaseUrl}
16
+ logo={logo}
17
+ logoAltText={logoAltText}
18
+ />
19
+ </MemoryRouter>
20
+ );
21
+
22
+ describe('BrandNav Component', () => {
23
+ afterEach(() => {
24
+ jest.clearAllMocks();
25
+ });
26
+
27
+ it('renders the logo with the correct alt text', () => {
28
+ render(<RootWrapper />);
29
+
30
+ const img = screen.getByAltText(logoAltText);
31
+ expect(img).toHaveAttribute('src', logo);
32
+ });
33
+
34
+ it('displays a link that navigates to studioBaseUrl', () => {
35
+ render(<RootWrapper />);
36
+
37
+ const link = screen.getByRole('link') as HTMLAnchorElement;
38
+ expect(link.href).toBe(studioBaseUrl);
39
+ });
40
+ });
@@ -0,0 +1,25 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { Link } from 'react-router-dom';
4
+
5
+ const BrandNav = ({
6
+ studioBaseUrl,
7
+ logo,
8
+ logoAltText,
9
+ }) => (
10
+ <Link to={studioBaseUrl}>
11
+ <img
12
+ src={logo}
13
+ alt={logoAltText}
14
+ className="d-block logo"
15
+ />
16
+ </Link>
17
+ );
18
+
19
+ BrandNav.propTypes = {
20
+ studioBaseUrl: PropTypes.string.isRequired,
21
+ logo: PropTypes.string.isRequired,
22
+ logoAltText: PropTypes.string.isRequired,
23
+ };
24
+
25
+ export default BrandNav;
@@ -0,0 +1,59 @@
1
+ import React from 'react';
2
+ import { render, screen } from '@testing-library/react';
3
+ import '@testing-library/jest-dom/extend-expect';
4
+ import { IntlProvider } from '@edx/frontend-platform/i18n';
5
+ import { MemoryRouter } from 'react-router-dom';
6
+
7
+ import CourseLockUp from './CourseLockUp';
8
+ import messages from './messages';
9
+
10
+ const mockProps = {
11
+ number: '101',
12
+ org: 'EDX',
13
+ title: 'Course Title',
14
+ outlineLink: 'https://example.com/course-outline',
15
+ };
16
+
17
+ const RootWrapper = (props) => (
18
+ <MemoryRouter>
19
+ <IntlProvider locale="en" messages={{}}>
20
+ <CourseLockUp {...props} />
21
+ </IntlProvider>
22
+ </MemoryRouter>
23
+ );
24
+
25
+ describe('CourseLockUp Component', () => {
26
+ afterEach(() => {
27
+ jest.clearAllMocks();
28
+ });
29
+
30
+ it('renders course org, number, and title', () => {
31
+ render(<RootWrapper {...mockProps} />);
32
+
33
+ const courseOrgNumber = screen.getByTestId('course-org-number');
34
+ const courseTitle = screen.getByTestId('course-title');
35
+
36
+ expect(courseOrgNumber).toBeInTheDocument();
37
+ expect(courseOrgNumber).toHaveTextContent(`${mockProps.org} ${mockProps.number}`);
38
+ expect(courseTitle).toBeInTheDocument();
39
+ expect(courseTitle).toHaveTextContent(mockProps.title);
40
+ });
41
+
42
+ it('renders the link with correct aria-label', () => {
43
+ render(<RootWrapper {...mockProps} />);
44
+
45
+ const link = screen.getByTestId('course-lock-up-block');
46
+ expect(link).toHaveAttribute(
47
+ 'aria-label',
48
+ messages['header.label.courseOutline'].defaultMessage,
49
+ );
50
+ });
51
+
52
+ it('navigates to an absolute URL when clicked', () => {
53
+ render(<RootWrapper {...mockProps} />);
54
+
55
+ // FIXME: don't use testId - https://testing-library.com/docs/queries/about#priority
56
+ const link = screen.getByTestId('course-lock-up-block') as HTMLAnchorElement;
57
+ expect(link.href).toBe(mockProps.outlineLink);
58
+ });
59
+ });
@@ -0,0 +1,56 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
4
+ import {
5
+ OverlayTrigger,
6
+ Tooltip,
7
+ } from '@openedx/paragon';
8
+ import { Link } from 'react-router-dom';
9
+
10
+ import messages from './messages';
11
+
12
+ const CourseLockUp = ({
13
+ outlineLink,
14
+ org,
15
+ number,
16
+ title,
17
+ // injected
18
+ intl,
19
+ }) => (
20
+ <OverlayTrigger
21
+ placement="bottom"
22
+ overlay={(
23
+ <Tooltip id="course-lock-up">
24
+ {title}
25
+ </Tooltip>
26
+ )}
27
+ >
28
+ <Link
29
+ className="course-title-lockup mr-2"
30
+ to={outlineLink}
31
+ aria-label={intl.formatMessage(messages['header.label.courseOutline'])}
32
+ data-testid="course-lock-up-block"
33
+ >
34
+ <span className="d-block small m-0 text-gray-800" data-testid="course-org-number">{org} {number}</span>
35
+ <span className="d-block m-0 font-weight-bold text-gray-800" data-testid="course-title">{title}</span>
36
+ </Link>
37
+ </OverlayTrigger>
38
+ );
39
+
40
+ CourseLockUp.propTypes = {
41
+ number: PropTypes.string,
42
+ org: PropTypes.string,
43
+ title: PropTypes.string,
44
+ outlineLink: PropTypes.string,
45
+ // injected
46
+ intl: intlShape.isRequired,
47
+ };
48
+
49
+ CourseLockUp.defaultProps = {
50
+ number: null,
51
+ org: null,
52
+ title: null,
53
+ outlineLink: null,
54
+ };
55
+
56
+ export default injectIntl(CourseLockUp);