feat: Add Plugin Button Registration API documentation and Plugin System implementation summary
- Introduced PLUGIN_BUTTON_API.md detailing button registration, UI locations, and usage examples. - Added PLUGIN_SYSTEM_IMPLEMENTATION.md summarizing implemented features, usage examples, and API details for the plugin system.
This commit is contained in:
23
PLUGINS.md
23
PLUGINS.md
@@ -70,7 +70,7 @@ Plugins run with access to your Matrix client and can:
|
||||
|
||||
## Developing Plugins
|
||||
|
||||
Want to create your own plugin? Check out the [Plugin Development Guide](./cinny/src/app/features/settings/plugins/PLUGIN_DEVELOPMENT.md).
|
||||
Want to create your own plugin? Check out the [Plugin API Reference](docs/PLUGIN_API.md).
|
||||
|
||||
### Quick Start
|
||||
|
||||
@@ -101,19 +101,19 @@ Plugins have access to:
|
||||
- **Matrix Client**: Full matrix-js-sdk client instance
|
||||
- **React**: For building UI components
|
||||
- **Commands**: Register custom slash commands
|
||||
- **UI Hooks**: Inject UI elements
|
||||
- **Settings**: Add custom settings sections
|
||||
- **Utilities**: Notifications and helpers
|
||||
- **UI Buttons**: Inject buttons into 11 locations across the app (nav lists, toolbars, headers, sidebar)
|
||||
- **UI Renderers**: Custom message and content renderers
|
||||
- **Settings**: Add custom settings sections per plugin
|
||||
- **Themes**: Register custom themes that appear in the theme selector
|
||||
- **Matrix Events**: Hook into raw Matrix events
|
||||
- **Timers**: Background intervals and timeouts, auto-cleaned on unload
|
||||
- **Notifications**: System notifications
|
||||
|
||||
See the [Plugin Development Guide](./cinny/src/app/features/settings/plugins/PLUGIN_DEVELOPMENT.md) for complete API documentation.
|
||||
See the [Plugin API Reference](docs/PLUGIN_API.md) and [Button Registration API](docs/PLUGIN_BUTTON_API.md) for complete documentation.
|
||||
|
||||
## Example Plugins
|
||||
|
||||
Check out the `example-plugin/` directory for a simple example demonstrating:
|
||||
- Matrix client access
|
||||
- Event listeners
|
||||
- Custom commands
|
||||
- Notifications
|
||||
Check out the `example-plugin/` directory for a simple example, or the `plugins/example-showcase-plugin/` for a full demonstration of all 11 UI button locations.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
@@ -147,7 +147,8 @@ Submit your plugins there to make them available in the marketplace!
|
||||
|
||||
## Support
|
||||
|
||||
- **Documentation**: [Plugin Development Guide](./cinny/src/app/features/settings/plugins/PLUGIN_DEVELOPMENT.md)
|
||||
- **Plugin API Reference**: [docs/PLUGIN_API.md](docs/PLUGIN_API.md)
|
||||
- **Button API Reference**: [docs/PLUGIN_BUTTON_API.md](docs/PLUGIN_BUTTON_API.md)
|
||||
- **Issues**: https://github.com/Paarrot/cinny-desktop/issues
|
||||
- **Community**: Join our Matrix room for plugin development help
|
||||
|
||||
|
||||
47
README.md
47
README.md
@@ -29,3 +29,50 @@ To build the app locally, run:
|
||||
|
||||
To start local dev server, run:
|
||||
* `npm run dev`
|
||||
|
||||
## Plugin System
|
||||
|
||||
Paarrot includes a plugin system for extending and customising the app with JavaScript modules.
|
||||
|
||||
### Installing Plugins
|
||||
|
||||
1. Drop a plugin folder into your plugins directory:
|
||||
- **Windows**: `%APPDATA%\paarrot\plugins\<plugin-name>\`
|
||||
- **Linux**: `~/.config/Paarrot/plugins/<plugin-name>/`
|
||||
- **macOS**: `~/Library/Application Support/Paarrot/plugins/<plugin-name>/`
|
||||
2. Enable it in **Settings → Plugins → Installed**
|
||||
|
||||
### What Plugins Can Do
|
||||
|
||||
- Register custom slash commands
|
||||
- Intercept and modify messages
|
||||
- Inject buttons into 11 UI locations (nav lists, toolbars, headers, sidebar, menus)
|
||||
- Register custom themes
|
||||
- Hook into raw Matrix events
|
||||
- Run background tasks
|
||||
- Show system notifications
|
||||
|
||||
### Plugin Locations (UI Buttons)
|
||||
|
||||
Plugins can inject buttons as **nav list rows** or **icon buttons** across the app:
|
||||
|
||||
| Location | Style | Where |
|
||||
|---|---|---|
|
||||
| `channel-list` | Nav row | Space channel list |
|
||||
| `home-section` | Nav row | Home panel, above room list |
|
||||
| `direct-messages` | Nav row | DMs panel, below "Create Chat" |
|
||||
| `sidebar-actions` | Icon | Left sidebar — above Explore and above Search |
|
||||
| `text-composer-toolbar` | Icon | Message composer toolbar |
|
||||
| `composer-actions` | Icon | Beside the `+` attach button |
|
||||
| `room-header` | Icon | Room header bar |
|
||||
| `room-menu` | Icon | Room ⋮ dropdown |
|
||||
| `message-actions` | Icon | Message hover bar |
|
||||
| `user-menu` | Icon | Right-click on user avatar |
|
||||
| `search-notification-section` | Icon | Notifications page header |
|
||||
|
||||
### Documentation
|
||||
|
||||
- [Plugin System Overview](PLUGINS.md)
|
||||
- [Full Plugin API Reference](docs/PLUGIN_API.md)
|
||||
- [Button Registration API](docs/PLUGIN_BUTTON_API.md)
|
||||
- [Example Plugins](plugins/)
|
||||
|
||||
2
cinny
2
cinny
Submodule cinny updated: 9a463facce...64e252da94
@@ -9,7 +9,8 @@ Complete reference for developing plugins for Paarrot/Cinny Desktop.
|
||||
- [Plugin Context API](#plugin-context-api)
|
||||
- [Commands](#commands)
|
||||
- [Message Interceptors](#message-interceptors)
|
||||
- [Custom Renderers](#custom-renderers)
|
||||
- [UI: Button Registration](#ui-button-registration)
|
||||
- [UI: Custom Renderers](#custom-renderers)
|
||||
- [Settings](#settings)
|
||||
- [Themes](#themes)
|
||||
- [Matrix Events](#matrix-events)
|
||||
@@ -322,6 +323,8 @@ ctx.ui.registerRenderer("image", (data, defaultRenderer) => {
|
||||
|
||||
```typescript
|
||||
interface UIAPI {
|
||||
registerButton(button: UIButtonDefinition): void;
|
||||
unregisterButton(id: string): void;
|
||||
registerRenderer(
|
||||
type: string,
|
||||
renderer: (data: any, defaultRenderer?: () => ReactNode) => ReactNode
|
||||
@@ -336,6 +339,97 @@ type CustomRenderer = (
|
||||
|
||||
---
|
||||
|
||||
### UI: Button Registration
|
||||
|
||||
Inject buttons into various parts of the Paarrot UI. Buttons render in two visual styles depending on location — **nav list rows** (icon + label, full width) or **icon buttons** (compact, toolbar-style).
|
||||
|
||||
See [PLUGIN_BUTTON_API.md](PLUGIN_BUTTON_API.md) for the complete reference including positioning and grouping examples.
|
||||
|
||||
#### Register a Button
|
||||
|
||||
```javascript
|
||||
ctx.ui.registerButton({
|
||||
id: 'my-button',
|
||||
location: 'text-composer-toolbar',
|
||||
label: 'My Tool',
|
||||
icon: '🔧',
|
||||
onClick: () => ctx.log('clicked!')
|
||||
});
|
||||
```
|
||||
|
||||
#### UI Locations — Nav List Rows
|
||||
|
||||
| Location | Where it appears |
|
||||
|---|---|
|
||||
| `channel-list` | Space channel list, below Lobby and Message Search |
|
||||
| `home-section` | Home panel, inside the Rooms category above the room list |
|
||||
| `direct-messages` | DMs panel, below "Create Chat" and above the CHATS dropdown |
|
||||
|
||||
#### UI Locations — Icon Buttons
|
||||
|
||||
| Location | Where it appears |
|
||||
|---|---|
|
||||
| `text-composer-toolbar` | Message composer toolbar (alongside emoji, sticker buttons) |
|
||||
| `composer-actions` | Left side of the composer, beside the `+` attach button |
|
||||
| `room-header` | Top room header bar, before the ⋮ menu |
|
||||
| `room-menu` | Room ⋮ dropdown menu |
|
||||
| `message-actions` | Message hover action bar |
|
||||
| `user-menu` | Right-click popup on the user avatar |
|
||||
| `search-notification-section` | Notifications page header (right side) |
|
||||
| `sidebar-actions` | Left sidebar — above Explore Servers icon, and above Search icon in the sticky bottom section |
|
||||
|
||||
#### Positioning
|
||||
|
||||
```javascript
|
||||
ctx.ui.registerButton({
|
||||
id: 'my-button',
|
||||
location: 'text-composer-toolbar',
|
||||
label: 'My Tool',
|
||||
icon: '🔧',
|
||||
position: {
|
||||
after: 'emoji-picker-button',
|
||||
group: 'my-tools',
|
||||
order: 1
|
||||
},
|
||||
onClick: () => ctx.log('clicked!')
|
||||
});
|
||||
```
|
||||
|
||||
#### Unregister
|
||||
|
||||
```javascript
|
||||
ctx.ui.unregisterButton('my-button');
|
||||
// All buttons are automatically unregistered on plugin unload
|
||||
```
|
||||
|
||||
#### API Reference
|
||||
|
||||
```typescript
|
||||
type UILocation =
|
||||
| 'channel-list' | 'direct-messages' | 'home-section'
|
||||
| 'text-composer-toolbar' | 'composer-actions'
|
||||
| 'room-header' | 'room-menu' | 'message-actions'
|
||||
| 'user-menu' | 'search-notification-section' | 'sidebar-actions';
|
||||
|
||||
interface UIButtonDefinition {
|
||||
id: string;
|
||||
location: UILocation;
|
||||
label: string;
|
||||
icon?: string;
|
||||
position?: UIButtonPosition;
|
||||
onClick?: () => void | Promise<void>;
|
||||
}
|
||||
|
||||
interface UIButtonPosition {
|
||||
before?: string;
|
||||
after?: string;
|
||||
group?: string;
|
||||
order?: number;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Settings
|
||||
|
||||
Define settings that users can configure in the UI.
|
||||
432
docs/PLUGIN_BUTTON_API.md
Normal file
432
docs/PLUGIN_BUTTON_API.md
Normal file
@@ -0,0 +1,432 @@
|
||||
# Plugin Button Registration API
|
||||
|
||||
An easy way to register plugin buttons in various UI locations with positioning and grouping support.
|
||||
|
||||
## Example Plugins
|
||||
|
||||
- **[example-button-plugin/](example-button-plugin/)** - Simple examples showing basic usage patterns
|
||||
- **[example-showcase-plugin/](example-showcase-plugin/)** - Complete demonstration of ALL 11 locations ⭐
|
||||
|
||||
## UI Locations
|
||||
|
||||
Buttons render in two visual styles depending on location — **nav list rows** (icon + label, full width) or **icon buttons** (compact, toolbar/header style).
|
||||
|
||||
### Nav List Rows
|
||||
|
||||
These render as full-width list entries matching the style of built-in items like "Create Room" and "Message Search":
|
||||
|
||||
| Location | Where it appears |
|
||||
|---|---|
|
||||
| `channel-list` | Space channel list, below Lobby and Message Search |
|
||||
| `home-section` | Home panel, inside the Rooms category above the room list |
|
||||
| `direct-messages` | Direct Messages panel, below "Create Chat" and above the CHATS dropdown |
|
||||
|
||||
### Icon Buttons
|
||||
|
||||
These render as compact icon buttons inline with other toolbar/header controls:
|
||||
|
||||
| Location | Where it appears |
|
||||
|---|---|
|
||||
| `text-composer-toolbar` | Message composer toolbar (alongside emoji, sticker buttons) |
|
||||
| `composer-actions` | Left side of the composer, beside the `+` attach button |
|
||||
| `room-header` | Top room header bar, before the ⋮ menu button |
|
||||
| `room-menu` | Room ⋮ dropdown menu |
|
||||
| `message-actions` | Message hover action bar |
|
||||
| `user-menu` | Right-click popup on the user avatar |
|
||||
| `search-notification-section` | Notifications page header (right side) |
|
||||
| `sidebar-actions` | Left sidebar — appears in **two** places: above the Explore Servers icon, and above the Search icon in the sticky bottom section |
|
||||
|
||||
> 💡 **Tip:** Install the [example-showcase-plugin](example-showcase-plugin/) to see exactly where each location appears in the UI!
|
||||
|
||||
## Basic Usage
|
||||
|
||||
### Simple Button
|
||||
|
||||
```javascript
|
||||
module.exports = {
|
||||
name: 'my-plugin',
|
||||
version: '1.0.0',
|
||||
|
||||
onLoad: (context) => {
|
||||
context.ui.registerButton({
|
||||
id: 'my-button',
|
||||
location: 'text-composer-toolbar',
|
||||
label: 'My Action',
|
||||
icon: '🎨',
|
||||
onClick: () => {
|
||||
context.log('Button clicked!');
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
onUnload: () => {
|
||||
// Buttons are automatically cleaned up on plugin unload
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
## Positioning
|
||||
|
||||
### Before/After Positioning
|
||||
|
||||
Place your button before or after existing buttons:
|
||||
|
||||
```javascript
|
||||
context.ui.registerButton({
|
||||
id: 'my-button',
|
||||
location: 'text-composer-toolbar',
|
||||
label: 'My Action',
|
||||
icon: '✨',
|
||||
position: {
|
||||
before: 'emoji-picker-button', // Place before emoji picker
|
||||
// OR
|
||||
after: 'sticker-button' // Place after sticker button
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### Grouping Buttons
|
||||
|
||||
Group related buttons together:
|
||||
|
||||
```javascript
|
||||
context.ui.registerButton({
|
||||
id: 'action-1',
|
||||
location: 'text-composer-toolbar',
|
||||
label: 'Action 1',
|
||||
icon: '1️⃣',
|
||||
position: {
|
||||
group: 'my-plugin-tools',
|
||||
order: 1 // Lower numbers appear first
|
||||
}
|
||||
});
|
||||
|
||||
context.ui.registerButton({
|
||||
id: 'action-2',
|
||||
location: 'text-composer-toolbar',
|
||||
label: 'Action 2',
|
||||
icon: '2️⃣',
|
||||
position: {
|
||||
group: 'my-plugin-tools',
|
||||
order: 2
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### Combined Positioning and Grouping
|
||||
|
||||
Place a group before/after other elements:
|
||||
|
||||
```javascript
|
||||
context.ui.registerButton({
|
||||
id: 'tool-1',
|
||||
location: 'text-composer-toolbar',
|
||||
label: 'Tool 1',
|
||||
icon: '🔧',
|
||||
position: {
|
||||
group: 'my-tools',
|
||||
after: 'emoji-picker-button',
|
||||
order: 1
|
||||
}
|
||||
});
|
||||
|
||||
context.ui.registerButton({
|
||||
id: 'tool-2',
|
||||
location: 'text-composer-toolbar',
|
||||
label: 'Tool 2',
|
||||
icon: '🔨',
|
||||
position: {
|
||||
group: 'my-tools',
|
||||
order: 2
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
## Complete Example
|
||||
|
||||
```javascript
|
||||
module.exports = {
|
||||
name: 'custom-tools',
|
||||
version: '1.0.0',
|
||||
|
||||
onLoad: (context) => {
|
||||
// Nav list row — appears below "Create Chat" in the DMs panel
|
||||
context.ui.registerButton({
|
||||
id: 'dm-favorites',
|
||||
location: 'direct-messages',
|
||||
label: 'Favourites',
|
||||
icon: '⭐',
|
||||
onClick: () => context.log('Favourites clicked!')
|
||||
});
|
||||
|
||||
// Nav list row — appears in the space channel list
|
||||
context.ui.registerButton({
|
||||
id: 'quick-access',
|
||||
location: 'channel-list',
|
||||
label: 'Quick Access',
|
||||
icon: '⚡',
|
||||
onClick: () => context.log('Quick access clicked!')
|
||||
});
|
||||
|
||||
// Icon button — appears in the message composer toolbar
|
||||
context.ui.registerButton({
|
||||
id: 'format-bold',
|
||||
location: 'text-composer-toolbar',
|
||||
label: 'Bold',
|
||||
icon: '𝐁',
|
||||
position: {
|
||||
group: 'custom-formatting',
|
||||
order: 1
|
||||
},
|
||||
onClick: () => context.log('Bold clicked!')
|
||||
});
|
||||
|
||||
// Icon button — appears in the room header
|
||||
context.ui.registerButton({
|
||||
id: 'special-search',
|
||||
location: 'room-header',
|
||||
label: 'Special Search',
|
||||
icon: '🔍',
|
||||
position: { after: 'search-button' },
|
||||
onClick: () => context.log('Special search clicked!')
|
||||
});
|
||||
|
||||
// Sidebar icon — appears above Explore and above Search
|
||||
context.ui.registerButton({
|
||||
id: 'plugin-panel',
|
||||
location: 'sidebar-actions',
|
||||
label: 'Plugin Panel',
|
||||
icon: '🧩',
|
||||
onClick: () => context.log('Plugin panel clicked!')
|
||||
});
|
||||
},
|
||||
|
||||
onUnload: () => {
|
||||
// All registered buttons are automatically cleaned up
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
## Unregistering Buttons
|
||||
|
||||
Buttons are automatically unregistered when the plugin is unloaded. To manually unregister:
|
||||
|
||||
```javascript
|
||||
context.ui.unregisterButton('my-button-id');
|
||||
```
|
||||
|
||||
## TypeScript Types
|
||||
|
||||
```typescript
|
||||
import type { UIButtonDefinition, UIButtonPosition, UILocation } from '@paarrot/plugin-manager';
|
||||
|
||||
const button: UIButtonDefinition = {
|
||||
id: 'my-button',
|
||||
location: 'text-composer-toolbar',
|
||||
label: 'My Action',
|
||||
icon: '🎨',
|
||||
position: {
|
||||
group: 'my-tools',
|
||||
after: 'emoji-picker',
|
||||
order: 1
|
||||
},
|
||||
onClick: () => console.log('Clicked!')
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
## Basic Usage
|
||||
|
||||
### Simple Button
|
||||
|
||||
```javascript
|
||||
module.exports = {
|
||||
name: 'my-plugin',
|
||||
version: '1.0.0',
|
||||
|
||||
onLoad: (context) => {
|
||||
context.ui.registerButton({
|
||||
id: 'my-button',
|
||||
location: 'text-composer-toolbar',
|
||||
label: 'My Action',
|
||||
icon: '🎨',
|
||||
onClick: () => {
|
||||
context.log('Button clicked!');
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
onUnload: () => {
|
||||
// Buttons are automatically cleaned up on plugin unload
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
## Positioning
|
||||
|
||||
### Before/After Positioning
|
||||
|
||||
Place your button before or after existing buttons:
|
||||
|
||||
```javascript
|
||||
context.ui.registerButton({
|
||||
id: 'my-button',
|
||||
location: 'text-composer-toolbar',
|
||||
label: 'My Action',
|
||||
icon: '✨',
|
||||
position: {
|
||||
before: 'emoji-picker-button', // Place before emoji picker
|
||||
// OR
|
||||
after: 'sticker-button' // Place after sticker button
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### Grouping Buttons
|
||||
|
||||
Group related buttons together:
|
||||
|
||||
```javascript
|
||||
context.ui.registerButton({
|
||||
id: 'action-1',
|
||||
location: 'text-composer-toolbar',
|
||||
label: 'Action 1',
|
||||
icon: '1️⃣',
|
||||
position: {
|
||||
group: 'my-plugin-tools',
|
||||
order: 1 // Lower numbers appear first
|
||||
}
|
||||
});
|
||||
|
||||
context.ui.registerButton({
|
||||
id: 'action-2',
|
||||
location: 'text-composer-toolbar',
|
||||
label: 'Action 2',
|
||||
icon: '2️⃣',
|
||||
position: {
|
||||
group: 'my-plugin-tools',
|
||||
order: 2
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### Combined Positioning and Grouping
|
||||
|
||||
Place a group before/after other elements:
|
||||
|
||||
```javascript
|
||||
context.ui.registerButton({
|
||||
id: 'tool-1',
|
||||
location: 'text-composer-toolbar',
|
||||
label: 'Tool 1',
|
||||
icon: '🔧',
|
||||
position: {
|
||||
group: 'my-tools',
|
||||
after: 'emoji-picker-button',
|
||||
order: 1
|
||||
}
|
||||
});
|
||||
|
||||
context.ui.registerButton({
|
||||
id: 'tool-2',
|
||||
location: 'text-composer-toolbar',
|
||||
label: 'Tool 2',
|
||||
icon: '🔨',
|
||||
position: {
|
||||
group: 'my-tools',
|
||||
order: 2
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
## Complete Example
|
||||
|
||||
```javascript
|
||||
module.exports = {
|
||||
name: 'custom-tools',
|
||||
version: '1.0.0',
|
||||
|
||||
onLoad: (context) => {
|
||||
// Nav list row — appears below "Create Chat" in the DMs panel
|
||||
context.ui.registerButton({
|
||||
id: 'dm-favorites',
|
||||
location: 'direct-messages',
|
||||
label: 'Favourites',
|
||||
icon: '⭐',
|
||||
onClick: () => context.log('Favourites clicked!')
|
||||
});
|
||||
|
||||
// Nav list row — appears in the space channel list
|
||||
context.ui.registerButton({
|
||||
id: 'quick-access',
|
||||
location: 'channel-list',
|
||||
label: 'Quick Access',
|
||||
icon: '⚡',
|
||||
onClick: () => context.log('Quick access clicked!')
|
||||
});
|
||||
|
||||
// Icon button — appears in the message composer toolbar
|
||||
context.ui.registerButton({
|
||||
id: 'format-bold',
|
||||
location: 'text-composer-toolbar',
|
||||
label: 'Bold',
|
||||
icon: '𝐁',
|
||||
position: {
|
||||
group: 'custom-formatting',
|
||||
order: 1
|
||||
},
|
||||
onClick: () => context.log('Bold clicked!')
|
||||
});
|
||||
|
||||
// Icon button — appears in the room header
|
||||
context.ui.registerButton({
|
||||
id: 'special-search',
|
||||
location: 'room-header',
|
||||
label: 'Special Search',
|
||||
icon: '🔍',
|
||||
position: { after: 'search-button' },
|
||||
onClick: () => context.log('Special search clicked!')
|
||||
});
|
||||
|
||||
// Sidebar icon — appears above Explore and above Search
|
||||
context.ui.registerButton({
|
||||
id: 'plugin-panel',
|
||||
location: 'sidebar-actions',
|
||||
label: 'Plugin Panel',
|
||||
icon: '🧩',
|
||||
onClick: () => context.log('Plugin panel clicked!')
|
||||
});
|
||||
},
|
||||
|
||||
onUnload: () => {
|
||||
// All registered buttons are automatically cleaned up
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
## Unregistering Buttons
|
||||
|
||||
Buttons are automatically unregistered when the plugin is unloaded. To manually unregister:
|
||||
|
||||
```javascript
|
||||
context.ui.unregisterButton('my-button-id');
|
||||
```
|
||||
|
||||
## TypeScript Types
|
||||
|
||||
```typescript
|
||||
import type { UIButtonDefinition, UIButtonPosition, UILocation } from '@paarrot/plugin-manager';
|
||||
|
||||
const button: UIButtonDefinition = {
|
||||
id: 'my-button',
|
||||
location: 'text-composer-toolbar',
|
||||
label: 'My Action',
|
||||
icon: '🎨',
|
||||
position: {
|
||||
group: 'my-tools',
|
||||
after: 'emoji-picker',
|
||||
order: 1
|
||||
},
|
||||
onClick: () => console.log('Clicked!')
|
||||
};
|
||||
```
|
||||
@@ -16,11 +16,17 @@ All requested features have been implemented! 🎉
|
||||
- Full MessageContext with content, roomId, metadata
|
||||
- Async support for interceptors
|
||||
|
||||
### 3. ✅ Custom Renderers
|
||||
- **Register**: `ctx.ui.registerRenderer("message", (msg, defaultRenderer) => { /* render */ })`
|
||||
- **Unregister**: `ctx.ui.unregisterRenderer("message")`
|
||||
- Fallback to default renderer support
|
||||
- Discord-mod-tier customization enabled
|
||||
### 3. ✅ Custom Renderers & Button Registration
|
||||
- **Register renderer**: `ctx.ui.registerRenderer("message", (msg, defaultRenderer) => { /* render */ })`
|
||||
- **Unregister renderer**: `ctx.ui.unregisterRenderer("message")`
|
||||
- **Register button**: `ctx.ui.registerButton({ id, location, label, icon, onClick })`
|
||||
- **Unregister button**: `ctx.ui.unregisterButton(id)`
|
||||
- 11 UI locations across nav lists, toolbars, headers, sidebar, and menus
|
||||
- Nav list rows (icon + label) for `channel-list`, `home-section`, `direct-messages`
|
||||
- Icon buttons for all other locations
|
||||
- Positioning and grouping support (`before`, `after`, `group`, `order`)
|
||||
- Auto-cleanup on plugin unload
|
||||
- See [PLUGIN_BUTTON_API.md](PLUGIN_BUTTON_API.md) for full reference
|
||||
|
||||
### 4. ✅ Settings UI Per Plugin
|
||||
- **Define schema**: `ctx.settings.define({ theme: { type: "select", options: [...] } })`
|
||||
@@ -162,6 +168,8 @@ interface PluginContext {
|
||||
};
|
||||
|
||||
ui: {
|
||||
registerButton: (button: UIButtonDefinition) => void;
|
||||
unregisterButton: (id: string) => void;
|
||||
registerRenderer: (type: string, renderer: CustomRenderer) => void;
|
||||
unregisterRenderer: (type: string) => void;
|
||||
};
|
||||
Reference in New Issue
Block a user