mirror of
https://github.com/BetterSEQTA/BetterSEQTA-Plus.git
synced 2026-06-06 03:34:40 +00:00
300 lines
9.0 KiB
Markdown
300 lines
9.0 KiB
Markdown
# Creating Plugins for BetterSEQTA+
|
|
|
|
**Published version:** [docs.betterseqta.org/plugins/](https://docs.betterseqta.org/plugins/) · [Plugin development](https://docs.betterseqta.org/plugin-development/) · [Plugin API](https://docs.betterseqta.org/plugin-api/)
|
|
|
|
Hey there! 👋 So you want to create a plugin for BetterSEQTA+? That's awesome! This guide will walk you through everything you need to know, from the very basics to more advanced features. Don't worry if you're new to this - we'll explain everything step by step.
|
|
|
|
## What is a Plugin?
|
|
|
|
In BetterSEQTA+, a plugin is like a mini-app that adds new features to SEQTA. Think of it as a piece of LEGO that you can snap onto SEQTA to make it do new things. For example, you could create a plugin that:
|
|
|
|
- Changes how SEQTA looks
|
|
- Adds new buttons or features
|
|
- Shows extra information on your timetable
|
|
- Collects notifications in a better way
|
|
- Really, anything you can imagine!
|
|
|
|
## Your First Plugin
|
|
|
|
Let's create a super simple plugin together. We'll make one that adds a friendly message to the SEQTA homepage. Here's what we'll need:
|
|
|
|
```typescript
|
|
import type { Plugin } from "@/plugins/core/types";
|
|
|
|
const myFirstPlugin: Plugin = {
|
|
// Every plugin needs these basic details
|
|
id: "my-first-plugin",
|
|
name: "My First Plugin",
|
|
description: "Adds a friendly message to SEQTA",
|
|
version: "1.0.0",
|
|
|
|
// This tells BetterSEQTA+ that users can turn our plugin on/off
|
|
disableToggle: true,
|
|
|
|
// Optional: Mark your plugin as beta to show a "Beta" tag in settings
|
|
beta: true,
|
|
|
|
// This is where the magic happens!
|
|
run: async (api) => {
|
|
// Wait for the homepage to load
|
|
api.seqta.onMount(".home-page", (homePage) => {
|
|
// Create our message
|
|
const message = document.createElement("div");
|
|
message.textContent = "Hello from my first plugin! 🎉";
|
|
message.style.padding = "20px";
|
|
message.style.backgroundColor = "#e9f5ff";
|
|
message.style.borderRadius = "8px";
|
|
message.style.margin = "20px";
|
|
|
|
// Add it to the page
|
|
homePage.prepend(message);
|
|
});
|
|
|
|
// Return a cleanup function that removes our message when the plugin is disabled
|
|
return () => {
|
|
const message = document.querySelector(".home-page > div");
|
|
message?.remove();
|
|
};
|
|
},
|
|
};
|
|
|
|
export default myFirstPlugin;
|
|
```
|
|
|
|
Let's break down what's happening here:
|
|
|
|
1. First, we import the `Plugin` type that tells TypeScript what a plugin should look like
|
|
2. We create our plugin object with some basic information:
|
|
- `id`: A unique name for your plugin (use lowercase and dashes)
|
|
- `name`: A friendly name that users will see
|
|
- `description`: Explain what your plugin does
|
|
- `version`: Your plugin's version number
|
|
3. We set `disableToggle: true` so users can turn our plugin on/off in settings
|
|
4. We set `beta: true` to mark the plugin as beta
|
|
5. The `run` function is where we put our plugin's code
|
|
6. We use `api.seqta.onMount` to wait for the homepage to load
|
|
7. We create and style a message element
|
|
8. We return a cleanup function that removes our changes when the plugin is disabled
|
|
|
|
## The Plugin API
|
|
|
|
When your plugin runs, it gets access to a powerful API that lets you do all sorts of things. Let's look at what you can do:
|
|
|
|
### SEQTA API (`api.seqta`)
|
|
|
|
This helps you interact with SEQTA's pages:
|
|
|
|
```typescript
|
|
// Wait for an element to appear on the page
|
|
api.seqta.onMount(".some-class", (element) => {
|
|
// Do something with the element
|
|
});
|
|
|
|
// Know when the user changes pages
|
|
api.seqta.onPageChange((page) => {
|
|
console.log("User went to:", page);
|
|
});
|
|
|
|
// Get the current page
|
|
const currentPage = api.seqta.getCurrentPage();
|
|
```
|
|
|
|
### Settings API (`api.settings`)
|
|
|
|
Want to let users customize your plugin? Use settings!
|
|
|
|
```typescript
|
|
import { BasePlugin } from "@/plugins/core/settings";
|
|
import {
|
|
booleanSetting,
|
|
defineSettings,
|
|
Setting,
|
|
} from "@/plugins/core/settingsHelpers";
|
|
|
|
// Define your settings
|
|
const settings = defineSettings({
|
|
showMessage: booleanSetting({
|
|
default: true,
|
|
title: "Show Welcome Message",
|
|
description: "Show a friendly message on the homepage",
|
|
}),
|
|
});
|
|
|
|
// Create a class for your plugin
|
|
class MyPluginClass extends BasePlugin<typeof settings> {
|
|
@Setting(settings.showMessage)
|
|
showMessage!: boolean;
|
|
}
|
|
|
|
// Create your plugin
|
|
const settingsInstance = new MyPluginClass();
|
|
|
|
const myPlugin: Plugin<typeof settings> = {
|
|
// ... other plugin details ...
|
|
settings: settingsInstance.settings,
|
|
|
|
run: async (api) => {
|
|
// Use the setting
|
|
if (api.settings.showMessage) {
|
|
// Show the message
|
|
}
|
|
|
|
// Listen for setting changes
|
|
api.settings.onChange("showMessage", (newValue) => {
|
|
if (newValue) {
|
|
// Show the message
|
|
} else {
|
|
// Hide the message
|
|
}
|
|
});
|
|
},
|
|
};
|
|
```
|
|
|
|
### Storage API (`api.storage`)
|
|
|
|
Need to save some data? The storage API has got you covered:
|
|
|
|
```typescript
|
|
// Save some data
|
|
await api.storage.set("lastVisit", new Date().toISOString());
|
|
|
|
// Get it back later
|
|
const lastVisit = await api.storage.get("lastVisit");
|
|
|
|
// Listen for changes
|
|
api.storage.onChange("lastVisit", (newValue) => {
|
|
console.log("Last visit updated:", newValue);
|
|
});
|
|
```
|
|
|
|
### Events API (`api.events`)
|
|
|
|
Want your plugin to be able to interface with other plugins? Then use events!
|
|
|
|
```typescript
|
|
// Listen for an event
|
|
api.events.on("myCustomEvent", (data) => {
|
|
console.log("Got event:", data);
|
|
});
|
|
|
|
// Send an event
|
|
api.events.emit("myCustomEvent", { some: "data" });
|
|
```
|
|
|
|
## Adding Styles
|
|
|
|
Want to make your plugin look pretty? You can add CSS styles:
|
|
|
|
```typescript
|
|
const myPlugin: Plugin = {
|
|
// ... other plugin details ...
|
|
|
|
// Add your CSS here
|
|
styles: `
|
|
.my-plugin-message {
|
|
background: linear-gradient(135deg, #6e8efb, #a777e3);
|
|
color: white;
|
|
padding: 20px;
|
|
border-radius: 12px;
|
|
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
|
margin: 20px;
|
|
animation: slide-in 0.3s ease-out;
|
|
}
|
|
|
|
@keyframes slide-in {
|
|
from { transform: translateY(-20px); opacity: 0; }
|
|
to { transform: translateY(0); opacity: 1; }
|
|
}
|
|
`,
|
|
|
|
run: async (api) => {
|
|
// Your plugin code here
|
|
},
|
|
};
|
|
```
|
|
|
|
## Best Practices
|
|
|
|
Here are some tips to make your plugin awesome:
|
|
|
|
1. **Always Clean Up**: When your plugin is disabled, clean up any changes you made:
|
|
|
|
```typescript
|
|
run: async (api) => {
|
|
// Add stuff to the page
|
|
const element = document.createElement("div");
|
|
document.body.appendChild(element);
|
|
|
|
// Return a cleanup function
|
|
return () => {
|
|
element.remove();
|
|
};
|
|
};
|
|
```
|
|
|
|
2. **Use TypeScript**: It helps catch errors before they happen and makes your code easier to understand.
|
|
|
|
3. **Test Your Plugin**: Make sure it works in different situations:
|
|
|
|
- When SEQTA is loading
|
|
- When the user switches pages
|
|
- When the plugin is enabled/disabled
|
|
- When settings are changed
|
|
|
|
4. **Keep It Fast**: Don't slow down SEQTA:
|
|
|
|
- Use `onMount` instead of intervals or timeouts
|
|
- Clean up event listeners when they're not needed
|
|
- Don't do heavy calculations on the main thread
|
|
|
|
5. **Make It User-Friendly**:
|
|
- Add clear settings with good descriptions
|
|
- Use `disableToggle: true` so users can turn it off if needed
|
|
- Add helpful error messages if something goes wrong
|
|
- Use `beta: true` for experimental features to let users know they're trying something new
|
|
|
|
## Plugin Metadata Options
|
|
|
|
Your plugin object supports several optional flags to customize how it appears and behaves:
|
|
|
|
```typescript
|
|
const myPlugin: Plugin = {
|
|
id: "my-plugin",
|
|
name: "My Plugin",
|
|
description: "What my plugin does",
|
|
version: "1.0.0",
|
|
|
|
// Optional flags:
|
|
disableToggle: true, // Show enable/disable toggle in settings
|
|
defaultEnabled: false, // Start disabled by default (requires disableToggle: true)
|
|
beta: true, // Show "Beta" tag in settings UI
|
|
|
|
// Your plugin code...
|
|
run: async (api) => { /* ... */ },
|
|
};
|
|
```
|
|
|
|
- **`disableToggle`**: When `true`, users can enable/disable your plugin in settings
|
|
- **`defaultEnabled`**: When `false`, your plugin starts disabled (only works with `disableToggle: true`)
|
|
- **`beta`**: When `true`, shows an orange "Beta" tag next to your plugin name in settings
|
|
|
|
## Examples
|
|
|
|
Want to see more examples? Check out our built-in plugins:
|
|
|
|
- [themes](../../src/plugins/built-in/themes/index.ts): Shows how to change SEQTA's appearance
|
|
- [notificationCollector](../../src/plugins/built-in/notificationCollector/index.ts): Shows how to work with SEQTA's notifications
|
|
- [timetable](../../src/plugins/built-in/timetable/index.ts): Shows how to modify SEQTA's timetable view
|
|
- [assessmentsAverage](../../src/plugins/built-in/assessmentsAverage/index.ts): Shows how to add new features to existing pages
|
|
|
|
## Need Help?
|
|
|
|
Got stuck? No worries! Here's where you can get help:
|
|
|
|
- Join our [Discord server](https://discord.gg/YzmbnCDkat)
|
|
- Check out the built-in plugins in the `src/plugins/built-in` folder
|
|
- Open an issue on our [GitHub page](https://github.com/betterseqta/betterseqta-plus/issues)
|
|
|
|
Happy coding and feel free to check out the [plugin API](https://docs.betterseqta.org/plugin-api/) on the documentation site.
|