feat(HeaderBarAPI): ability to add buttons to ChannelToolbar (#551)
This commit is contained in:
parent
4d504f0d26
commit
9d94430dfc
4 changed files with 69 additions and 10 deletions
|
|
@ -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<any>;
|
||||
priority?: number;
|
||||
location?: HeaderBarButtonLocation;
|
||||
}
|
||||
|
||||
interface HeaderBarButton {
|
||||
|
|
@ -26,8 +29,10 @@ interface HeaderBarButton {
|
|||
}
|
||||
|
||||
export const buttons = new Map<string, HeaderBarButton>();
|
||||
export const channelToolbarButtons = new Map<string, HeaderBarButton>();
|
||||
|
||||
const listeners = new Set<() => void>();
|
||||
const channelToolbarListeners = new Set<() => void>();
|
||||
|
||||
export interface HeaderBarButtonProps {
|
||||
icon: ComponentType<any>;
|
||||
|
|
@ -41,13 +46,15 @@ export interface HeaderBarButtonProps {
|
|||
disabled?: boolean;
|
||||
showBadge?: boolean;
|
||||
badgePosition?: "top" | "bottom";
|
||||
iconSize?: number;
|
||||
ref?: RefObject<any>;
|
||||
}
|
||||
|
||||
export const HeaderBarButton = findComponentByCodeLazy(".HEADER_BAR_BADGE_TOP:", '.iconBadge,"top"') as ComponentType<HeaderBarButtonProps>;
|
||||
|
||||
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 }]) => (
|
||||
<ErrorBoundary noop key={id} onError={e => logger.error(`Failed to render channel toolbar ${id}`, e.error)}>
|
||||
<Button />
|
||||
</ErrorBoundary>
|
||||
));
|
||||
}
|
||||
|
||||
export function _addButtons() {
|
||||
return [<HeaderBarButtons key="vc-header-bar-buttons" />];
|
||||
}
|
||||
|
||||
export function _addChannelToolbarButtons(toolbar: ReactNode[]) {
|
||||
toolbar.push(<ChannelToolbarButtons key="vc-channel-toolbar-buttons" />);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ export { Plugins as plugins };
|
|||
|
||||
import { traceFunction } from "../debug/Tracer";
|
||||
import { addAudioProcessor, removeAudioProcessor } from "./AudioPlayer";
|
||||
import { addHeaderBarButton, removeHeaderBarButton } from "./HeaderBar";
|
||||
import { addChannelToolbarButton, addHeaderBarButton, removeChannelToolbarButton, removeHeaderBarButton } from "./HeaderBar";
|
||||
|
||||
const logger = new Logger("PluginManager", "#a6d189");
|
||||
|
||||
|
|
@ -253,7 +253,13 @@ export const startPlugin = traceFunction("startPlugin", function startPlugin(p:
|
|||
|
||||
// Custom
|
||||
if (renderNicknameIcon) addNicknameIcon(name, renderNicknameIcon);
|
||||
if (headerBarButton) addHeaderBarButton(name, headerBarButton.render, headerBarButton.priority);
|
||||
if (headerBarButton) {
|
||||
if (headerBarButton.location === "channeltoolbar") {
|
||||
addChannelToolbarButton(name, headerBarButton.render, headerBarButton.priority);
|
||||
} else {
|
||||
addHeaderBarButton(name, headerBarButton.render, headerBarButton.priority);
|
||||
}
|
||||
}
|
||||
if (audioProcessor) addAudioProcessor(name, audioProcessor);
|
||||
|
||||
return true;
|
||||
|
|
@ -321,7 +327,13 @@ export const stopPlugin = traceFunction("stopPlugin", function stopPlugin(p: Plu
|
|||
|
||||
// Custom
|
||||
if (renderNicknameIcon) removeNicknameIcon(name);
|
||||
if (headerBarButton) removeHeaderBarButton(name);
|
||||
if (headerBarButton) {
|
||||
if (headerBarButton.location === "channeltoolbar") {
|
||||
removeChannelToolbarButton(name);
|
||||
} else {
|
||||
removeHeaderBarButton(name);
|
||||
}
|
||||
}
|
||||
if (audioProcessor) removeAudioProcessor(name);
|
||||
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -131,7 +131,7 @@ export const ContextMenu = $ContextMenu;
|
|||
export const ChatButtons = $ChatButtons;
|
||||
|
||||
/**
|
||||
* An API allowing you to add buttons to the header bar.
|
||||
* An API allowing you to add buttons to the header bar or channel toolbar.
|
||||
*/
|
||||
export const HeaderBar = $HeaderBar;
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import definePlugin from "@utils/types";
|
|||
|
||||
export default definePlugin({
|
||||
name: "HeaderBarAPI",
|
||||
description: "API to add buttons to the header bar.",
|
||||
description: "API to add buttons to the header bar and channel toolbar.",
|
||||
authors: [EquicordDevs.Prism],
|
||||
|
||||
patches: [
|
||||
|
|
@ -19,6 +19,13 @@ export default definePlugin({
|
|||
match: /(?<=\i\.Fragment,\{children:\[.{1,500}className:\i\}\))(?=\])/,
|
||||
replace: ",...Vencord.Api.HeaderBar._addButtons()"
|
||||
}
|
||||
},
|
||||
{
|
||||
find: "Missing channel in Channel.renderHeaderToolbar",
|
||||
replacement: {
|
||||
match: /(?<=renderHeaderToolbar",\(\)=>\{.{1,200}let (\i)=\[\];)/,
|
||||
replace: "Vencord.Api.HeaderBar._addChannelToolbarButtons($1);"
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue