Skip to content

Plugins

WARNING

These steps are based off the upcoming v4.0.0 release of Schooltape. If you are planning on contributing, please base your changes off the v4.0.0 branch.

Breaking changes may occur before the release.

IMPORTANT

For CSS only modifications, see snippets

First, you will need these things:

  • name: The name of your plugin (e.g. My New Plugin)
  • nameCamelCase: The name of your plugin in camelCase (e.g. myNewPlugin)
  • description: A brief description of what your plugin does, without a period at the end (e.g. Adds a new button to the top bar)
  • targets (optional): An array of CSS selectors which Schooltape will wait for to load into the DOM before injecting the plugin (e.g. [".timetable"])

Throughout this guide, you will see these between <angle brackets>. Replace them with the appropriate values.

Creating a Plugin

INFO

For a real life example, see this commit!

Boilerplate

  1. Append your plugin nameCamelCase to the union type PluginId in src/utils/constants.ts
ts
export type PluginId =
  | "subheader"
  | "scrollSegments"
  // ...
  | "<nameCamelCase>"; 
  1. Append your plugin information to the PLUGIN_INFO object in src/utils/constants.ts
ts
export const PLUGIN_INFO: Record<Types.PluginId, Types.PluginInfo> = {
  subheader: {
    name: "Subheader Revamp",
    description: "Adds a clock and current period info to the subheader",
  },
  scrollSegments: {
    name: "Scroll Segments",
    description: "Segments the Schoolbox page into scrollable sections",
  },
  // ...
  <nameCamelCase>: { 
    name: "<name>", 
    description: "<description>", 
  }, 
};
  1. Append your plugin settings to the plugins record in src/utils/storage.ts
ts
export const plugins: Record<Types.PluginId, WxtStorageItem<Types.PluginGeneric, any>> = {
  subheader: storage.defineItem<Types.PluginGeneric>("local:plugin-subheader", {
    fallback: {
      toggle: true,
    },
  }),
  scrollSegments: storage.defineItem<Types.PluginGeneric>("local:plugin-scrollSegments", {
    fallback: {
      toggle: true,
    },
  }),
  // ...
  <nameCamelCase>: storage.defineItem<Types.PluginGeneric>("local:plugin-<nameCamelCase>", { 
    fallback: { 
      // here you can define the default settings for your plugin
      toggle: true, 
    }, 
  }), 
};
  1. Import your plugin in src/entrypoints/plugins.content.ts
ts
// @ts-ignore
import subheader from "./plugins/subheader";
import scrollSegments from "./plugins/scrollSegments";
// ...
import <nameCamelCase> from "./plugins/<nameCamelCase>"; 

export default defineContentScript({
  matches: ["<all_urls>"],
  runAt: "document_start",
  excludeMatches: EXCLUDE_MATCHES,
  async main() {
    subheader();
    scrollSegments();
    // ...
    <nameCamelCase>(); 
  },
});
  1. Create your plugin function in src/entrypoints/plugins with the name of your plugin in camelCase
    • If you are planning to include CSS, HTML, or Svelte alongside your TypeScript:
      1. Create a new folder in src/entrypoints/plugins with the name of your plugin in camelCase (e.g. myNewPlugin).
      2. Inside this folder, you can create a index.ts file for your TypeScript, and any other files you need (e.g. styles.css)
    • If you are only planning to include TypeScript:
      1. Create a new file in src/entrypoints/plugins with the name of your plugin in camelCase (e.g. myNewPlugin.ts)

Now, in your TypeScript file, copy the following boilerplate:

ts
export default function init() { 
  defineStPlugin( 
    "<nameCamelCase>", 
    () => { 
      // Your code here
    }, 
    [<targets>], 
  ); 
} 

Code!

Now that you have dealt with all that boilerplate, you can start actually building your plugin!

Released under the GPL-3.0 license.