diff --git a/package-lock.json b/package-lock.json
index 18e9afbb0..847894bbe 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -37,6 +37,7 @@
"@openedx-plugins/course-app-xpert_unit_summary": "file:plugins/course-apps/xpert_unit_summary",
"@openedx/frontend-build": "^14.3.3",
"@openedx/frontend-plugin-framework": "^1.6.0",
+ "@openedx/frontend-slot-footer": "^1.2.0",
"@openedx/paragon": "^22.16.0",
"@redux-devtools/extension": "^3.3.0",
"@reduxjs/toolkit": "1.9.7",
@@ -4241,6 +4242,20 @@
"@babel/runtime": "^7.9.2"
}
},
+ "node_modules/@openedx/frontend-slot-footer": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/@openedx/frontend-slot-footer/-/frontend-slot-footer-1.2.0.tgz",
+ "integrity": "sha512-bJuqgdiAlPRj1QuUOJWtNqGTCTcdsk4vHeOM3jRkxtWycq+j1JpGnnZEWAmjoRv9dDKr39vt2buNrmvj0sCTbA==",
+ "license": "AGPL-3.0",
+ "dependencies": {
+ "@openedx/frontend-plugin-framework": "^1.5.0"
+ },
+ "peerDependencies": {
+ "@edx/frontend-component-footer": "*",
+ "react": "^17.0.0 || ^18.0.0",
+ "react-dom": "^17.0.0 || ^18.0.0"
+ }
+ },
"node_modules/@openedx/paragon": {
"version": "22.17.0",
"resolved": "https://registry.npmjs.org/@openedx/paragon/-/paragon-22.17.0.tgz",
diff --git a/package.json b/package.json
index 1043e4711..785df3bc4 100644
--- a/package.json
+++ b/package.json
@@ -60,6 +60,7 @@
"@openedx-plugins/course-app-wiki": "file:plugins/course-apps/wiki",
"@openedx-plugins/course-app-xpert_unit_summary": "file:plugins/course-apps/xpert_unit_summary",
"@openedx/frontend-build": "^14.3.3",
+ "@openedx/frontend-slot-footer": "^1.2.0",
"@openedx/frontend-plugin-framework": "^1.6.0",
"@openedx/paragon": "^22.16.0",
"@redux-devtools/extension": "^3.3.0",
diff --git a/src/CourseAuthoringPage.jsx b/src/CourseAuthoringPage.jsx
index e187522c0..9a594ff6c 100644
--- a/src/CourseAuthoringPage.jsx
+++ b/src/CourseAuthoringPage.jsx
@@ -5,7 +5,7 @@ import { useDispatch, useSelector } from 'react-redux';
import {
useLocation,
} from 'react-router-dom';
-import { StudioFooter } from '@edx/frontend-component-footer';
+import { StudioFooterSlot } from '@openedx/frontend-slot-footer';
import Header from './header';
import { fetchCourseDetail, fetchWaffleFlags } from './data/thunks';
import { useModel } from './generic/model-store';
@@ -66,7 +66,7 @@ const CourseAuthoringPage = ({ courseId, children }) => {
)
)}
{children}
- {!inProgress && !isEditor && }
+ {!inProgress && !isEditor && }
);
};
diff --git a/src/accessibility-page/AccessibilityPage.jsx b/src/accessibility-page/AccessibilityPage.jsx
index d3dd1c99a..d7cc8959f 100644
--- a/src/accessibility-page/AccessibilityPage.jsx
+++ b/src/accessibility-page/AccessibilityPage.jsx
@@ -2,7 +2,7 @@ import React from 'react';
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import { Helmet } from 'react-helmet';
import { Container } from '@openedx/paragon';
-import { StudioFooter } from '@edx/frontend-component-footer';
+import { StudioFooterSlot } from '@openedx/frontend-slot-footer';
import Header from '../header';
import messages from './messages';
@@ -29,7 +29,7 @@ const AccessibilityPage = ({
-
+
>
);
};
diff --git a/src/course-rerun/index.jsx b/src/course-rerun/index.jsx
index 1bfeed4f9..425d8163c 100644
--- a/src/course-rerun/index.jsx
+++ b/src/course-rerun/index.jsx
@@ -7,7 +7,8 @@ import {
ActionRow,
Button,
} from '@openedx/paragon';
-import { StudioFooter } from '@edx/frontend-component-footer';
+import { StudioFooterSlot } from '@openedx/frontend-slot-footer';
+
import { useNavigate, useParams } from 'react-router-dom';
import Header from '../header';
@@ -88,7 +89,7 @@ const CourseRerun = () => {
isQueryPending={savingStatus === RequestStatus.PENDING}
/>
-
+
>
);
};
diff --git a/src/library-authoring/LibraryAuthoringPage.tsx b/src/library-authoring/LibraryAuthoringPage.tsx
index 7871fd99b..10741d118 100644
--- a/src/library-authoring/LibraryAuthoringPage.tsx
+++ b/src/library-authoring/LibraryAuthoringPage.tsx
@@ -1,7 +1,7 @@
import { useCallback, useEffect, useState } from 'react';
import { Helmet } from 'react-helmet';
import classNames from 'classnames';
-import { StudioFooter } from '@edx/frontend-component-footer';
+import { StudioFooterSlot } from '@openedx/frontend-slot-footer';
import { useIntl } from '@edx/frontend-platform/i18n';
import {
ActionRow,
@@ -286,7 +286,7 @@ const LibraryAuthoringPage = ({ returnToLibrarySelection }: LibraryAuthoringPage
- {!componentPickerMode && }
+ {!componentPickerMode && }
{!!sidebarComponentInfo?.type && (
diff --git a/src/library-authoring/collections/LibraryCollectionPage.tsx b/src/library-authoring/collections/LibraryCollectionPage.tsx
index 306a64ab5..4bff6751a 100644
--- a/src/library-authoring/collections/LibraryCollectionPage.tsx
+++ b/src/library-authoring/collections/LibraryCollectionPage.tsx
@@ -1,5 +1,5 @@
import { useEffect } from 'react';
-import { StudioFooter } from '@edx/frontend-component-footer';
+import { StudioFooterSlot } from '@openedx/frontend-slot-footer';
import { useIntl } from '@edx/frontend-platform/i18n';
import {
ActionRow,
@@ -220,7 +220,7 @@ const LibraryCollectionPage = () => {
- {!componentPickerMode && }
+ {!componentPickerMode && }
{!!sidebarComponentInfo?.type && (
diff --git a/src/library-authoring/create-library/CreateLibrary.tsx b/src/library-authoring/create-library/CreateLibrary.tsx
index 7939a2b4f..009069430 100644
--- a/src/library-authoring/create-library/CreateLibrary.tsx
+++ b/src/library-authoring/create-library/CreateLibrary.tsx
@@ -1,4 +1,4 @@
-import { StudioFooter } from '@edx/frontend-component-footer';
+import { StudioFooterSlot } from '@openedx/frontend-slot-footer';
import { useIntl } from '@edx/frontend-platform/i18n';
import {
Container,
@@ -162,7 +162,7 @@ const CreateLibrary = () => {
{isError && (
)}
-
+
>
);
};
diff --git a/src/plugin-slots/README.md b/src/plugin-slots/README.md
index a7a3c3c21..c017435bd 100644
--- a/src/plugin-slots/README.md
+++ b/src/plugin-slots/README.md
@@ -9,3 +9,6 @@
## Course Unit page
* [`course_unit_header_actions_slot`](./CourseUnitHeaderActionsSlot/)
+
+## Footer Slot
+* [`studio_footer_slot`](./StudioFooterSlot/)
diff --git a/src/plugin-slots/StudioFooterSlot/README.md b/src/plugin-slots/StudioFooterSlot/README.md
new file mode 100644
index 000000000..f45d46947
--- /dev/null
+++ b/src/plugin-slots/StudioFooterSlot/README.md
@@ -0,0 +1,50 @@
+# Studio Footer Slot
+
+### Slot ID: `studio_footer_slot`
+
+## Description
+
+This slot is used to replace/modify/hide the footer.
+
+The implementation of the `StudioFooterSlot` component lives in [the `frontend-slot-footer` repository](https://github.com/openedx/frontend-slot-footer/).
+
+## Example
+
+The following `env.config.jsx` will replace the default footer.
+
+
+
+with a simple custom footer
+
+
+
+```jsx
+import { DIRECT_PLUGIN, PLUGIN_OPERATIONS } from '@openedx/frontend-plugin-framework';
+
+const config = {
+ pluginSlots: {
+ studio_footer_slot: {
+ plugins: [
+ {
+ // Hide the default footer
+ op: PLUGIN_OPERATIONS.Hide,
+ widgetId: 'default_contents',
+ },
+ {
+ // Insert a custom footer
+ op: PLUGIN_OPERATIONS.Insert,
+ widget: {
+ id: 'custom_footer',
+ type: DIRECT_PLUGIN,
+ RenderWidget: () => (
+
🦶
+ ),
+ },
+ },
+ ]
+ }
+ },
+}
+
+export default config;
+```
\ No newline at end of file
diff --git a/src/plugin-slots/StudioFooterSlot/images/custom_footer.png b/src/plugin-slots/StudioFooterSlot/images/custom_footer.png
new file mode 100644
index 000000000..ccae66ecd
Binary files /dev/null and b/src/plugin-slots/StudioFooterSlot/images/custom_footer.png differ
diff --git a/src/plugin-slots/StudioFooterSlot/images/default_studio_footer.png b/src/plugin-slots/StudioFooterSlot/images/default_studio_footer.png
new file mode 100644
index 000000000..d7b71698a
Binary files /dev/null and b/src/plugin-slots/StudioFooterSlot/images/default_studio_footer.png differ
diff --git a/src/studio-home/StudioHome.tsx b/src/studio-home/StudioHome.tsx
index 9b8bc20a3..0e3380bef 100644
--- a/src/studio-home/StudioHome.tsx
+++ b/src/studio-home/StudioHome.tsx
@@ -9,7 +9,7 @@ import {
} from '@openedx/paragon';
import { Add as AddIcon, Error } from '@openedx/paragon/icons';
import { useIntl } from '@edx/frontend-platform/i18n';
-import { StudioFooter } from '@edx/frontend-component-footer';
+import { StudioFooterSlot } from '@openedx/frontend-slot-footer';
import { getConfig } from '@edx/frontend-platform';
import { useLocation, useNavigate } from 'react-router-dom';
@@ -188,7 +188,7 @@ const StudioHome = () => {
isQueryPending={anyQueryIsPending}
/>
-
+
>
);
};
diff --git a/src/taxonomy/TaxonomyLayout.tsx b/src/taxonomy/TaxonomyLayout.tsx
index 63c41b9ed..68827aad9 100644
--- a/src/taxonomy/TaxonomyLayout.tsx
+++ b/src/taxonomy/TaxonomyLayout.tsx
@@ -1,5 +1,5 @@
import { useMemo, useState } from 'react';
-import { StudioFooter } from '@edx/frontend-component-footer';
+import { StudioFooterSlot } from '@openedx/frontend-slot-footer';
import { Outlet, ScrollRestoration } from 'react-router-dom';
import { Toast } from '@openedx/paragon';
@@ -28,7 +28,7 @@ export const TaxonomyLayout = () => {
/>
)}
-
+
{toastMessage && (