# Example Plugin Template **Published version:** [docs.betterseqta.org/example-plugin/](https://docs.betterseqta.org/example-plugin/) This is a complete, working example of a simple BetterSEQTA+ plugin. You can copy this code and modify it to create your own plugin! ## What This Example Does This plugin adds a friendly welcome message to the SEQTA homepage and lets users customize the message through settings. ## Complete Plugin Code Create a new file in `src/plugins/built-in/my-first-plugin/index.ts`: ```typescript import type { Plugin } from "@/plugins/core/types"; import { BasePlugin } from "@/plugins/core/settings"; import { defineSettings, booleanSetting, stringSetting } from "@/plugins/core/settingsHelpers"; import { Setting } from "@/plugins/core/settingsHelpers"; // Define the plugin settings const settings = defineSettings({ enabled: booleanSetting({ default: true, title: "Show Welcome Message", description: "Display a welcome message on the SEQTA homepage" }), customMessage: stringSetting({ default: "Welcome to SEQTA! 🎉", title: "Custom Message", description: "The message to display on the homepage", maxLength: 100 }), showEmoji: booleanSetting({ default: true, title: "Show Emoji", description: "Include emojis in the welcome message" }) }); // Create settings class class MyFirstPluginSettings extends BasePlugin { @Setting(settings.enabled) enabled!: boolean; @Setting(settings.customMessage) customMessage!: string; @Setting(settings.showEmoji) showEmoji!: boolean; } // Create settings instance const settingsInstance = new MyFirstPluginSettings(); // Define the plugin const myFirstPlugin: Plugin = { id: "my-first-plugin", name: "My First Plugin", description: "Adds a customizable welcome message to the SEQTA homepage", version: "1.0.0", // Link our settings settings: settingsInstance.settings, // Mark as beta (optional) beta: true, // Add some CSS styles (optional) styles: ` .my-plugin-welcome { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 20px; border-radius: 12px; margin: 20px; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); text-align: center; font-size: 18px; animation: slideIn 0.5s ease-out; } @keyframes slideIn { from { opacity: 0; transform: translateY(-20px); } to { opacity: 1; transform: translateY(0); } } .my-plugin-welcome .close-btn { float: right; background: rgba(255, 255, 255, 0.2); border: none; color: white; padding: 5px 10px; border-radius: 20px; cursor: pointer; font-size: 12px; } .my-plugin-welcome .close-btn:hover { background: rgba(255, 255, 255, 0.3); } `, // Main plugin function run: async (api) => { console.log("[My First Plugin] Starting up! 🚀"); // Wait for settings to load await api.settings.loaded; let welcomeElement: HTMLElement | null = null; // Function to create the welcome message const createWelcomeMessage = () => { // Only show if enabled in settings if (!api.settings.enabled) { return; } // Remove existing message if it exists if (welcomeElement) { welcomeElement.remove(); } // Create the message element welcomeElement = document.createElement("div"); welcomeElement.className = "my-plugin-welcome"; // Build the message content let message = api.settings.customMessage; if (!api.settings.showEmoji) { // Remove emojis if disabled message = message.replace(/[\u{1F600}-\u{1F64F}]|[\u{1F300}-\u{1F5FF}]|[\u{1F680}-\u{1F6FF}]|[\u{1F1E0}-\u{1F1FF}]|[\u{2600}-\u{26FF}]|[\u{2700}-\u{27BF}]/gu, ''); } welcomeElement.innerHTML = `
${message}
Powered by My First Plugin `; return welcomeElement; }; // Function to add message to homepage const addToHomepage = () => { api.seqta.onMount(".home-page, .dashboard, [class*='home']", (homePage) => { console.log("[My First Plugin] Found homepage, adding welcome message"); const message = createWelcomeMessage(); if (message) { // Add to the top of the homepage homePage.insertBefore(message, homePage.firstChild); } }); }; // Add message when plugin starts addToHomepage(); // Re-add message when user navigates to homepage api.seqta.onPageChange((page) => { console.log("[My First Plugin] Page changed to:", page); if (page.includes("home") || page.includes("dashboard")) { // Small delay to let the page load setTimeout(addToHomepage, 500); } }); // Listen for settings changes and update the message api.settings.onChange("enabled", (enabled) => { console.log("[My First Plugin] Enabled setting changed:", enabled); if (enabled) { addToHomepage(); } else if (welcomeElement) { welcomeElement.remove(); welcomeElement = null; } }); api.settings.onChange("customMessage", (newMessage) => { console.log("[My First Plugin] Message changed:", newMessage); if (welcomeElement && api.settings.enabled) { // Update existing message addToHomepage(); } }); api.settings.onChange("showEmoji", (showEmoji) => { console.log("[My First Plugin] Show emoji changed:", showEmoji); if (welcomeElement && api.settings.enabled) { // Update existing message addToHomepage(); } }); // Return cleanup function (called when plugin is disabled) return () => { console.log("[My First Plugin] Cleaning up..."); if (welcomeElement) { welcomeElement.remove(); welcomeElement = null; } }; } }; export default myFirstPlugin; ``` ## How to Use This Example ### Step 1: Create the Plugin File 1. Create a new folder: `src/plugins/built-in/my-first-plugin/` 2. Create `index.ts` in that folder 3. Copy the code above into `index.ts` ### Step 2: Register the Plugin Add this to `src/plugins/index.ts`: ```typescript // Add this import at the top import myFirstPlugin from "./built-in/my-first-plugin"; // Add this line where other plugins are registered pluginManager.registerPlugin(myFirstPlugin); ``` ### Step 3: Test It 1. Run `npm run dev` 2. Reload your extension in Chrome 3. Visit a SEQTA page 4. You should see your welcome message! 5. Open BetterSEQTA+ settings to customize it ## Key Concepts Explained ### 1. Plugin Structure ```typescript const myPlugin: Plugin = { id: "unique-id", // Must be unique across all plugins name: "Display Name", // Shown in settings description: "What it does", // Shown in settings version: "1.0.0", // Plugin version settings: settingsObject, // User-configurable options styles: "/* CSS here */", // Optional CSS styles run: async (api) => { // Main plugin code // Your code here } }; ``` ### 2. Settings System ```typescript // Define what settings your plugin has const settings = defineSettings({ myOption: booleanSetting({ default: true, title: "My Option", description: "What this option does" }) }); // Use in your plugin if (api.settings.myOption) { // Do something } ``` ### 3. SEQTA Integration ```typescript // Wait for elements to appear api.seqta.onMount(".some-selector", (element) => { // Modify the element }); // Detect page changes api.seqta.onPageChange((page) => { if (page === "home") { // User navigated to homepage } }); ``` ### 4. Cleanup Always return a cleanup function to remove your changes when the plugin is disabled: ```typescript run: async (api) => { // Add your features return () => { // Remove your features }; } ``` ## Customization Ideas Want to modify this example? Here are some ideas: 1. **Change the styling**: Modify the CSS to use different colors, animations, or layouts 2. **Add more settings**: Number settings, select dropdowns, hotkeys 3. **Different trigger**: Show on different pages, or based on time of day 4. **Add interactions**: Buttons that do things when clicked 5. **Store data**: Use `api.storage` to remember user preferences 6. **Communicate with other plugins**: Use `api.events` to send/receive events ## Next Steps Once you've got this working: 1. **Experiment**: Try changing things and see what happens 2. **Read other plugins**: Look at the built-in plugins for inspiration 3. **Check the API docs**: Learn about all available API functions 4. **Share your creation**: Show it off in Discord! ## Need Help? - 💬 Ask in our [Discord server](https://discord.gg/YzmbnCDkat) - 📚 Read the [plugin documentation](https://docs.betterseqta.org/plugins/) - 🐛 Check the [troubleshooting guide](https://docs.betterseqta.org/troubleshooting/) - 📝 Open an issue on GitHub Happy coding! 🎉