feat: Moves search button into a slot (#644)

Signed-off-by: Farhaan Bukhsh <farhaan@opencraft.com>
This commit is contained in:
Farhaan Bukhsh
2025-10-27 20:21:45 +05:30
committed by GitHub
parent 97063850c6
commit c86165180f
6 changed files with 131 additions and 17 deletions

View File

@@ -24,3 +24,6 @@
* [`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/)
### Studio Header
* [`org.openedx.frontend.layout.studio_header_search_button_slot.v1`](./StudioHeaderSearchButtonSlot/)

View File

@@ -0,0 +1,89 @@
# Studio Header Search Button Slot
### Slot ID: `org.openedx.frontend.layout.studio_header_search_button_slot.v1`
## Description
This slot is used to replace/modify/hide the search button in the studio header.
## Examples
### Replace search with custom component
The following `env.config.jsx` will replace the search button entirely (in this case with a custom emoji icon):
![Search button being replaced](./images/studio_header_search_button_replace.png)
```jsx
import {
DIRECT_PLUGIN,
PLUGIN_OPERATIONS,
} from "@openedx/frontend-plugin-framework";
const config = {
pluginSlots: {
"org.openedx.frontend.layout.studio_header_search_button_slot.v1": {
keepDefault: false,
plugins: [
{
op: PLUGIN_OPERATIONS.Insert,
widget: {
id: "custom_notification_tray",
type: DIRECT_PLUGIN,
RenderWidget: () => <span>🔔</span>,
},
},
],
},
},
};
export default config;
```
### Add custom component before and after search button
The following `env.config.jsx` will insert emoji after and before the search button
![Add custom component before and after search button](./images/studio_header_search_button_before_after.png)
```jsx
import {
DIRECT_PLUGIN,
PLUGIN_OPERATIONS,
} from "@openedx/frontend-plugin-framework";
const config = {
pluginSlots: {
"org.openedx.frontend.layout.studio_header_search_button_slot.v1": {
keepDefault: true,
plugins: [
{
op: PLUGIN_OPERATIONS.Insert,
widget: {
priority: 10,
id: 'custom_notification_tray_before',
type: DIRECT_PLUGIN,
RenderWidget: () => <span>🔔</span>,
},
},
{
op: PLUGIN_OPERATIONS.Insert,
widget: {
priority: 90,
id: 'custom_notification_tray_after',
type: DIRECT_PLUGIN,
RenderWidget: () => <span>🔕</span>,
},
},
],
},
};
export default config;
```
## API
- **Slot ID:** `org.openedx.frontend.layout.studio_header_search_button_slot.v1`
- **Component:** Uses the [PluginSlot](https://github.com/openedx/frontend-plugin-framework#pluginslot) from the Open edX Frontend Plugin Framework for plugin injection.

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View File

@@ -0,0 +1,34 @@
import React from 'react';
import { PluginSlot } from '@openedx/frontend-plugin-framework';
import { Nav, IconButton, Icon } from '@openedx/paragon';
import { Search } from '@openedx/paragon/icons';
import PropTypes from 'prop-types';
import { useIntl } from '@edx/frontend-platform/i18n';
import messages from '../../studio-header/messages';
const StudioHeaderSearchButtonSlot = ({ searchButtonAction }) => {
const intl = useIntl();
return (
<PluginSlot
id="org.openedx.frontend.layout.studio_header_search_button_slot.v1"
>
{searchButtonAction && (
<Nav>
<IconButton
src={Search}
iconAs={Icon}
onClick={searchButtonAction}
aria-label={intl.formatMessage(messages['header.label.search.nav'])}
alt={intl.formatMessage(messages['header.label.search.nav'])}
/>
</Nav>
)}
</PluginSlot>
);
};
StudioHeaderSearchButtonSlot.propTypes = {
searchButtonAction: PropTypes.func,
};
export default StudioHeaderSearchButtonSlot;

View File

@@ -1,22 +1,19 @@
import React, { type ReactNode, type ComponentProps } from 'react';
import { useIntl } from '@edx/frontend-platform/i18n';
import classNames from 'classnames';
import {
ActionRow,
Button,
Container,
Icon,
IconButton,
Nav,
Row,
} from '@openedx/paragon';
import { Close, MenuIcon, Search } from '@openedx/paragon/icons';
import { Close, MenuIcon } from '@openedx/paragon/icons';
import CourseLockUp from './CourseLockUp';
import UserMenu from './UserMenu';
import BrandNav from './BrandNav';
import NavDropdownMenu from './NavDropdownMenu';
import messages from './messages';
import StudioHeaderSearchButtonSlot from '../plugin-slots/StudioHeaderSearchButtonSlot';
export interface HeaderBodyProps {
studioBaseUrl: string;
@@ -65,7 +62,6 @@ const HeaderBody = ({
searchButtonAction,
containerProps = {},
}: HeaderBodyProps) => {
const intl = useIntl();
const renderBrandNav = (
<BrandNav
@@ -141,17 +137,9 @@ const HeaderBody = ({
</>
)}
<ActionRow.Spacer />
{searchButtonAction && (
<Nav>
<IconButton
src={Search}
iconAs={Icon}
onClick={searchButtonAction}
aria-label={intl.formatMessage(messages['header.label.search.nav'])}
alt={intl.formatMessage(messages['header.label.search.nav'])}
/>
</Nav>
)}
<StudioHeaderSearchButtonSlot
searchButtonAction={searchButtonAction}
/>
<Nav>
<UserMenu
{...{