From d0a8778015753a5f76cb683738f9d7f4f004452f Mon Sep 17 00:00:00 2001 From: "kshitij.sobti" Date: Fri, 21 Mar 2025 17:31:29 +0530 Subject: [PATCH] feat: Add slots to add tab links for courses Adds new slot that allow adding new links to course tabs. --- src/course-tabs/CourseTabLink.tsx | 20 +++++++ src/course-tabs/CourseTabLinksList.tsx | 25 +++++++++ ...avigation.jsx => CourseTabsNavigation.tsx} | 51 +++++++----------- src/plugin-slots/CourseTabLinksSlot/README.md | 51 ++++++++++++++++++ .../CourseTabLinksSlot/course-tabs-custom.png | Bin 0 -> 13454 bytes src/plugin-slots/CourseTabLinksSlot/index.tsx | 21 ++++++++ 6 files changed, 137 insertions(+), 31 deletions(-) create mode 100644 src/course-tabs/CourseTabLink.tsx create mode 100644 src/course-tabs/CourseTabLinksList.tsx rename src/course-tabs/{CourseTabsNavigation.jsx => CourseTabsNavigation.tsx} (58%) create mode 100644 src/plugin-slots/CourseTabLinksSlot/README.md create mode 100644 src/plugin-slots/CourseTabLinksSlot/course-tabs-custom.png create mode 100644 src/plugin-slots/CourseTabLinksSlot/index.tsx diff --git a/src/course-tabs/CourseTabLink.tsx b/src/course-tabs/CourseTabLink.tsx new file mode 100644 index 00000000..16ccdce4 --- /dev/null +++ b/src/course-tabs/CourseTabLink.tsx @@ -0,0 +1,20 @@ +import classNames from 'classnames'; +import React from 'react'; + +interface CourseTabLinkProps { + slug: string; + activeTabSlug?: string; + url: string; + title: string; +} + +export const CourseTabLink = ({ + slug, activeTabSlug, url, title, +}: CourseTabLinkProps) => ( + + {title} + +); diff --git a/src/course-tabs/CourseTabLinksList.tsx b/src/course-tabs/CourseTabLinksList.tsx new file mode 100644 index 00000000..894debcd --- /dev/null +++ b/src/course-tabs/CourseTabLinksList.tsx @@ -0,0 +1,25 @@ +import { CourseTabLink } from '@src/course-tabs/CourseTabLink'; +import React from 'react'; + +interface CourseTabLinkListProps { + tabs: Array<{ + title: string; + slug: string; + url: string; + }>, + activeTabSlug?: string; +} + +export const CourseTabLinksList = ({ tabs, activeTabSlug }: CourseTabLinkListProps) => ( + <> + {tabs.map(({ url, title, slug }) => ( + + ))} + +); diff --git a/src/course-tabs/CourseTabsNavigation.jsx b/src/course-tabs/CourseTabsNavigation.tsx similarity index 58% rename from src/course-tabs/CourseTabsNavigation.jsx rename to src/course-tabs/CourseTabsNavigation.tsx index 9c2a12ef..87a1b92c 100644 --- a/src/course-tabs/CourseTabsNavigation.jsx +++ b/src/course-tabs/CourseTabsNavigation.tsx @@ -1,16 +1,28 @@ import React from 'react'; -import PropTypes from 'prop-types'; -import { useIntl } from '@edx/frontend-platform/i18n'; import classNames from 'classnames'; - -import messages from './messages'; -import Tabs from '../generic/tabs/Tabs'; +import { useIntl } from '@edx/frontend-platform/i18n'; +import { CourseTabLinksSlot } from '../plugin-slots/CourseTabLinksSlot'; import { CoursewareSearch, CoursewareSearchToggle } from '../course-home/courseware-search'; import { useCoursewareSearchState } from '../course-home/courseware-search/hooks'; +import Tabs from '../generic/tabs/Tabs'; +import messages from './messages'; + +interface CourseTabsNavigationProps { + activeTabSlug?: string; + className?: string | null; + tabs: Array<{ + title: string; + slug: string; + url: string; + }>; +} + const CourseTabsNavigation = ({ - activeTabSlug, className, tabs, -}) => { + activeTabSlug = undefined, + className = null, + tabs, +}:CourseTabsNavigationProps) => { const intl = useIntl(); const { show } = useCoursewareSearchState(); @@ -23,15 +35,7 @@ const CourseTabsNavigation = ({ className="nav-underline-tabs" aria-label={intl.formatMessage(messages.courseMaterial)} > - {tabs.map(({ url, title, slug }) => ( - - {title} - - ))} +
@@ -44,19 +48,4 @@ const CourseTabsNavigation = ({ ); }; -CourseTabsNavigation.propTypes = { - activeTabSlug: PropTypes.string, - className: PropTypes.string, - tabs: PropTypes.arrayOf(PropTypes.shape({ - title: PropTypes.string.isRequired, - slug: PropTypes.string.isRequired, - url: PropTypes.string.isRequired, - })).isRequired, -}; - -CourseTabsNavigation.defaultProps = { - activeTabSlug: undefined, - className: null, -}; - export default CourseTabsNavigation; diff --git a/src/plugin-slots/CourseTabLinksSlot/README.md b/src/plugin-slots/CourseTabLinksSlot/README.md new file mode 100644 index 00000000..653086e2 --- /dev/null +++ b/src/plugin-slots/CourseTabLinksSlot/README.md @@ -0,0 +1,51 @@ +# Course Tab Links Slot + +### Slot ID: `org.openedx.frontend.learning.course_tab_links.v1` + +### Props: +* `activeTabSlug`: The slug of the currently active tab. + +## Description + +This slot is used to replace/modify/hide the course tabs. + +## Example + +### Added link to Course Tabs +![Added "Custom Tab" to course tabs](./course-tabs-custom.png) + +The following `env.config.jsx` will add a new course tab call "Custom Tab". + +```js +import { DIRECT_PLUGIN, PLUGIN_OPERATIONS } from '@openedx/frontend-plugin-framework'; + +import { CourseTabLink } from '@src/course-tabs/CourseTabLink'; + + +const config = { + pluginSlots: { + "org.openedx.frontend.learning.course_tab_links.v1": { + keepDefault: true, + plugins: [ + { + op: PLUGIN_OPERATIONS.Insert, + widget: { + id: 'custom_tab', + type: DIRECT_PLUGIN, + RenderWidget: ({ activeTabSlug })=> ( + + ), + }, + }, + ], + }, + }, +} + +export default config; +``` diff --git a/src/plugin-slots/CourseTabLinksSlot/course-tabs-custom.png b/src/plugin-slots/CourseTabLinksSlot/course-tabs-custom.png new file mode 100644 index 0000000000000000000000000000000000000000..6c9a4d68acda64b89af66fbcf79eb6d62550d64e GIT binary patch literal 13454 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 literal 0 HcmV?d00001 diff --git a/src/plugin-slots/CourseTabLinksSlot/index.tsx b/src/plugin-slots/CourseTabLinksSlot/index.tsx new file mode 100644 index 00000000..2515399e --- /dev/null +++ b/src/plugin-slots/CourseTabLinksSlot/index.tsx @@ -0,0 +1,21 @@ +import { PluginSlot } from '@openedx/frontend-plugin-framework'; +import { CourseTabLinksList } from '@src/course-tabs/CourseTabLinksList'; +import React from 'react'; + +type CourseTabList = Array<{ + title: string; + slug: string; + url: string; +}>; + +export const CourseTabLinksSlot = ({ tabs, activeTabSlug }: { + tabs: CourseTabList, + activeTabSlug?: string +}) => ( + + + +);