commit 7795c1d2cccd21030fe223030a73681105562349 Author: Violet Millie Date: Fri Jan 26 15:08:29 2024 +0000 First commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7ee3b69 --- /dev/null +++ b/.gitignore @@ -0,0 +1,189 @@ +# Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore + +# Logs + +logs +_.log +npm-debug.log_ +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +.pnpm-debug.log* + +# Caches + +.cache + +# Diagnostic reports (https://nodejs.org/api/report.html) + +report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json + +# Runtime data + +pids +_.pid +_.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover + +lib-cov + +# Coverage directory used by tools like istanbul + +coverage +*.lcov + +# nyc test coverage + +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) + +.grunt + +# Bower dependency directory (https://bower.io/) + +bower_components + +# node-waf configuration + +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) + +build/Release + +# Dependency directories + +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) + +web_modules/ + +# TypeScript cache + +*.tsbuildinfo + +# Optional npm cache directory + +.npm + +# Optional eslint cache + +.eslintcache + +# Optional stylelint cache + +.stylelintcache + +# Microbundle cache + +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history + +.node_repl_history + +# Output of 'npm pack' + +*.tgz + +# Yarn Integrity file + +.yarn-integrity + +# dotenv environment variable files + +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# parcel-bundler cache (https://parceljs.org/) + +.parcel-cache + +# Next.js build output + +.next +out + +# Nuxt.js build / generate output + +.nuxt +dist + +# Gatsby files + +# Comment in the public line in if your project uses Gatsby and not Next.js + +# https://nextjs.org/blog/next-9-1#public-directory-support + +# public + +# vuepress build output + +.vuepress/dist + +# vuepress v2.x temp and cache directory + +.temp + +# Docusaurus cache and generated files + +.docusaurus + +# Serverless directories + +.serverless/ + +# FuseBox cache + +.fusebox/ + +# DynamoDB Local files + +.dynamodb/ + +# TernJS port file + +.tern-port + +# Stores VSCode versions used for testing VSCode extensions + +.vscode-test + +# yarn v2 + +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.* + +# IntelliJ based IDEs +.idea + +# Finder (MacOS) folder config +.DS_Store + +# VS Code +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +!.vscode/*.code-snippets + +# Local History for Visual Studio Code +.history/ + +# Built Visual Studio Code Extensions +*.vsix diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..78664b2 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "editor.tabSize": 2 +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..b9ee6c8 --- /dev/null +++ b/README.md @@ -0,0 +1,4 @@ +# akkoma-keybinds + +A Firefox extension adding keybinds to the Akkoma front end. + diff --git a/bun.lockb b/bun.lockb new file mode 100755 index 0000000..54375a0 Binary files /dev/null and b/bun.lockb differ diff --git a/package.json b/package.json new file mode 100644 index 0000000..6eb73cc --- /dev/null +++ b/package.json @@ -0,0 +1,17 @@ +{ + "name": "akkoma-keybinds", + "module": "dist/extension/content.js", + "type": "module", + "scripts": { + "web-ext": "web-ext run -s dist -p default -u social.violetmillie.me", + "run-dev": "rm -rf dist && mkdir dist && cp src/extension/manifest.json dist && bun web-ext & bun build src/extension/typescript/content.ts --outdir dist/ --watch" + }, + "devDependencies": { + "@types/bun": "latest", + "web-ext": "^7.11.0" + }, + "peerDependencies": { + "typescript": "^5.0.0" + } +} + diff --git a/src/extension/manifest.json b/src/extension/manifest.json new file mode 100644 index 0000000..ac705d1 --- /dev/null +++ b/src/extension/manifest.json @@ -0,0 +1,26 @@ +{ + "name": "Akkoma Keybinds", + "description": "Introduces keybind controls to the Akkoma front end", + "version": "0.1", + + "browser_specific_settings": { + "gecko": { + "id": "akkomakeybinds@violetmillie.me", + "strict_min_version": "42.0" + } + }, + + "background": { + "scripts": ["Background.js"] + }, + + "content_scripts": [ + { + "matches": ["https://social.violetmillie.me/*"], + "js": ["Content.js"] + } + ], + + "manifest_version": 2 +} + diff --git a/src/extension/typescript/Content.ts b/src/extension/typescript/Content.ts new file mode 100644 index 0000000..f532cc3 --- /dev/null +++ b/src/extension/typescript/Content.ts @@ -0,0 +1,30 @@ +import KeybindManager from "./KeybindManager"; +import RegisterKeybinds from "./RegisterKeybinds"; + +console.log("Akkoma keybinds loaded!"); + +const manager = new KeybindManager(); + +RegisterKeybinds(manager); + +document.addEventListener("keydown", (ev) => { + const keybind = manager.getBindForKey(ev.key); + + if (!keybind) { + return; + } + + if ( + ev.isComposing || + (ev.target !== document.body && !keybind.allowWhileComposing) + ) { + return; + } + + // const keybind = manager.getBindForKey(ev.key); + + ev.preventDefault(); + + keybind.execute(); +}); + diff --git a/src/extension/typescript/KeybindManager.ts b/src/extension/typescript/KeybindManager.ts new file mode 100644 index 0000000..bac27a5 --- /dev/null +++ b/src/extension/typescript/KeybindManager.ts @@ -0,0 +1,31 @@ +export type Keybind = { + /** A string contaning the key that must be pressed to trigger the keybinding */ + key: string; + + /** The callback function to be called when the keybind is triggered */ + execute: Function; + + /** Whether the keybind can be triggered when composing */ + allowWhileComposing?: boolean; +}; + +export default class KeybindManager { + constructor() {} + + registeredKeybinds: Keybind[] = []; + + getBindForKey(key: string): Keybind | undefined { + return this.registeredKeybinds.find( + (registeredKey) => registeredKey.key === key + ); + } + + registerKeybind(keybind: Keybind) { + if (this.getBindForKey(keybind.key)) { + return; + } + + this.registeredKeybinds.push(keybind); + } +} + diff --git a/src/extension/typescript/RegisterKeybinds.ts b/src/extension/typescript/RegisterKeybinds.ts new file mode 100644 index 0000000..43ea2ca --- /dev/null +++ b/src/extension/typescript/RegisterKeybinds.ts @@ -0,0 +1,8 @@ +import type KeybindManager from "./KeybindManager"; + +import ComposeKeybind from "./keybinds/ComposeKeybind"; + +export default async function (keybindManager: KeybindManager) { + keybindManager.registerKeybind(ComposeKeybind); +} + diff --git a/src/extension/typescript/keybinds/ComposeKeybind.ts b/src/extension/typescript/keybinds/ComposeKeybind.ts new file mode 100644 index 0000000..dc1de16 --- /dev/null +++ b/src/extension/typescript/keybinds/ComposeKeybind.ts @@ -0,0 +1,24 @@ +import type { Keybind } from "../KeybindManager"; + +const keybind: Keybind = { + key: "n", + + execute: function () { + // console.log("Hello"); + const element = document.querySelector( + ".signed-in > div:nth-child(2) > form:nth-child(1) > div:nth-child(1) > div:nth-child(3) > textarea:nth-child(1)" + ); + + if (!element) { + return; + } + + const composeArea = element as HTMLElement; + + composeArea.focus(); + composeArea.textContent = "Hello"; + }, +}; + +export default keybind; + diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..d6d2616 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,23 @@ +{ + "compilerOptions": { + "lib": ["ESNext", "DOM"], + "target": "ESNext", + "module": "ESNext", + "moduleDetection": "force", + "jsx": "react-jsx", + "allowJs": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "noEmit": true, + + /* Linting */ + "skipLibCheck": true, + "strict": true, + "noFallthroughCasesInSwitch": true, + "forceConsistentCasingInFileNames": true + } +} +