mirror of
https://github.com/BetterSEQTA/BetterSEQTA-Plus.git
synced 2026-06-05 19:24:39 +00:00
5.2 KiB
5.2 KiB
BetterSEQTA+ Plugin System
Overview
The BetterSEQTA+ plugin system is designed to provide a clean, type-safe, and developer-friendly way to extend the functionality of BetterSEQTA+. While initially focused on built-in plugins, the architecture is designed to potentially support external plugins in the future.
Core Concepts
Plugin Structure
Each plugin is a simple object that contains metadata and a run function:
const examplePlugin = {
id: 'example',
name: 'Example Plugin',
description: 'Does something cool',
version: '1.0.0',
settings: {
enabled: { type: 'boolean', default: true },
color: { type: 'string', default: '#ff0000' }
},
run: (api) => {
// Plugin logic here
}
};
Plugin API
Plugins receive a powerful API object that provides access to:
- Settings: Type-safe settings management with direct property access
- SEQTA Integration: React component mounting and state management
- Storage: Persistent storage capabilities
- Events: Communication system
Settings System
Settings are defined with TypeScript types for safety and accessed like regular properties:
// In your plugin
api.settings.myOption = true;
const value = api.settings.myOption;
// Watch for changes
api.settings.onChange('myOption', (newValue) => {
console.log('Option changed:', newValue);
});
SEQTA Integration
Plugins can interact with SEQTA's React components:
// Listen for component mounting
api.seqta.onMount('.timetable-view', (element) => {
// Access the DOM element directly
console.log('Timetable mounted:', element);
// If you need React access, use getFiber
const fiber = api.seqta.getFiber('.timetable-view');
fiber.setState(prevState => ({
...prevState,
someValue: true
}));
});
// Get specific component
const fiber = api.seqta.getFiber('.timetable-cell');
const props = await fiber.getProps();
// Listen for page changes
api.seqta.onPageChange((page) => {
if (page === 'timetable') {
// Handle timetable page
}
});
Implementation Status
Phase 1: Core Infrastructure ✅
- Create basic plugin type definitions
- Implement plugin manager
- Set up basic API structure
- Create plugin loading system
Phase 2: Settings System ✅
- Design settings storage structure
- Implement settings proxy system
- Add settings change notifications
- Create settings validation
Phase 3: SEQTA Integration ✅
- Implement component mount detection
- Create ReactFiber wrapper
- Add page change detection
- Create component state utilities
Phase 4: Plugin API Features ✅
- Storage system
- Event system
- Error handling
- Plugin lifecycle hooks
Phase 5: Migration & Testing 🚧
- Convert existing features to plugins
- Create plugin testing utilities
- Add plugin documentation
- Create example plugins
Phase 6: Future Enhancements 📝
- Plugin dependencies system
- Plugin hot-reloading
- External plugin support
- Plugin marketplace infrastructure
Plugin Example
const timetablePlugin = {
id: 'timetable',
name: 'Timetable Enhancer',
description: 'Adds extra features to the timetable view',
version: '1.0.0',
settings: {
showWeekends: {
type: 'boolean',
default: false,
description: 'Show weekend days in the timetable'
},
theme: {
type: 'select',
options: ['light', 'dark', 'auto'],
default: 'auto',
description: 'Timetable theme'
}
},
run: async (api) => {
// Listen for timetable mount
api.seqta.onMount('.timetable-view', (element) => {
// Get React access since we need to modify state
const fiber = api.seqta.getFiber('.timetable-view');
// Apply settings
if (api.settings.showWeekends) {
fiber.setState(prevState => ({
...prevState,
showWeekends: true
}));
}
});
// Watch for settings changes
api.settings.onChange('theme', async (newTheme) => {
const timetable = api.seqta.getFiber('.timetable-view');
if (newTheme !== 'auto') {
await timetable.setProp('theme', newTheme);
}
});
}
};
Directory Structure
src/
plugins/
core/
types.ts # Core type definitions
createAPI.ts # API implementation
manager.ts # Plugin manager
built-in/ # Built-in plugins
timetable/
assessments/
etc...
API Type Definitions
interface BSAPI<TSettings> {
seqta: {
onMount: (selector: string, callback: (fiber: ReactFiber) => void) => void;
getFiber: (selector: string) => ReactFiber;
getCurrentPage: () => string;
onPageChange: (callback: (page: string) => void) => void;
};
settings: TSettings & {
onChange: <K extends keyof TSettings>(
key: K,
callback: (value: TSettings[K]) => void
) => void;
};
storage: {
get: (key: string) => Promise<any>;
set: (key: string, value: any) => Promise<void>;
};
events: {
on: (event: string, callback: (...args: any[]) => void) => void;
emit: (event: string, ...args: any[]) => void;
};
}