From 9d94430dfc5ea3ad60b60fe5171077884f02abfa Mon Sep 17 00:00:00 2001 From: prism Date: Wed, 10 Dec 2025 14:35:29 +0100 Subject: [PATCH] feat(HeaderBarAPI): ability to add buttons to ChannelToolbar (#551) --- src/api/HeaderBar.tsx | 50 ++++++++++++++++++++++++--- src/api/PluginManager.ts | 18 ++++++++-- src/api/index.ts | 2 +- src/equicordplugins/_api/headerBar.ts | 9 ++++- 4 files changed, 69 insertions(+), 10 deletions(-) diff --git a/src/api/HeaderBar.tsx b/src/api/HeaderBar.tsx index db5c66186..41027c50c 100644 --- a/src/api/HeaderBar.tsx +++ b/src/api/HeaderBar.tsx @@ -14,10 +14,13 @@ const logger = new Logger("HeaderBarAPI"); export type HeaderBarButtonFactory = () => JSX.Element | null; +export type HeaderBarButtonLocation = "headerbar" | "channeltoolbar"; + export interface HeaderBarButtonData { render: HeaderBarButtonFactory; icon: ComponentType; priority?: number; + location?: HeaderBarButtonLocation; } interface HeaderBarButton { @@ -26,8 +29,10 @@ interface HeaderBarButton { } export const buttons = new Map(); +export const channelToolbarButtons = new Map(); const listeners = new Set<() => void>(); +const channelToolbarListeners = new Set<() => void>(); export interface HeaderBarButtonProps { icon: ComponentType; @@ -41,13 +46,15 @@ export interface HeaderBarButtonProps { disabled?: boolean; showBadge?: boolean; badgePosition?: "top" | "bottom"; + iconSize?: number; ref?: RefObject; } export const HeaderBarButton = findComponentByCodeLazy(".HEADER_BAR_BADGE_TOP:", '.iconBadge,"top"') as ComponentType; +export const ChannelToolbarButton = HeaderBarButton; + /** - * Add a button to the header bar. * @param id Unique identifier for the button. * @param render Function that renders the button component. * @param priority Higher priority = more to the right. Default is 0. @@ -57,15 +64,26 @@ export function addHeaderBarButton(id: string, render: HeaderBarButtonFactory, p listeners.forEach(l => l()); } -/** - * Remove a button from the header bar. - * @param id The identifier of the button to remove. - */ export function removeHeaderBarButton(id: string) { buttons.delete(id); listeners.forEach(l => l()); } +/** + * @param id Unique identifier for the button. + * @param render Function that renders the button component. + * @param priority Higher priority = more to the right. Default is 0. + */ +export function addChannelToolbarButton(id: string, render: HeaderBarButtonFactory, priority = 0) { + channelToolbarButtons.set(id, { render, priority }); + channelToolbarListeners.forEach(l => l()); +} + +export function removeChannelToolbarButton(id: string) { + channelToolbarButtons.delete(id); + channelToolbarListeners.forEach(l => l()); +} + function HeaderBarButtons() { const [, forceUpdate] = useState(0); @@ -84,6 +102,28 @@ function HeaderBarButtons() { )); } +function ChannelToolbarButtons() { + const [, forceUpdate] = useState(0); + + useEffect(() => { + const listener = () => forceUpdate(n => n + 1); + channelToolbarListeners.add(listener); + return () => { channelToolbarListeners.delete(listener); }; + }, []); + + const sorted = Array.from(channelToolbarButtons).sort(([, a], [, b]) => a.priority - b.priority); + + return sorted.map(([id, { render: Button }]) => ( + logger.error(`Failed to render channel toolbar ${id}`, e.error)}> +