Skip to content

Commit

Permalink
add firefox extension
Browse files Browse the repository at this point in the history
  • Loading branch information
pomdtr committed Dec 11, 2023
1 parent 0c7cd8c commit c3266d8
Show file tree
Hide file tree
Showing 34 changed files with 240 additions and 7 deletions.
20 changes: 13 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,19 +45,29 @@ The page will access Tweety on port 9999.

> Note: Browser Friendly urls are not available on Safari, and requires to disable the Shield feature on Brave.
## Chrome Extension
## Browser Extension

Browser extensions for Chrome and Firefox are available in the `extension` folder.

A chrome extension is availaible in the extension folder. To install it:
## Chrome Extension

- Clone the repository
- Go to `chrome://extensions`
- Enable `Developer mode`
- Click on `Load unpacked`
- Select the `extension` folder
- Select the `extension/chrome` folder

By default, the extension will try to connect to `localhost:9999`. You can
customize the origin in the extension options.

## Firefox Extension

- Clone the repository
- Go to `about:debugging
- Click on `This Firefox`
- Click on `Load Temporary Add-on...`
- Select the `extension/firefox/manifest.json` file

## Starting Tweety on Boot

If you have installed Tweety using Homebrew, you can use the following command:
Expand Down Expand Up @@ -114,10 +124,6 @@ custom path.

## FAQ

### Firefox Version?

Firefox should be quite easy to support, the browser integration is minimal. Contributions are welcome!

### Windows Version?

The library used to create the terminal UI (xterm.js) does not support Windows yet.
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
8 changes: 8 additions & 0 deletions extension/firefox/devtools.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<!DOCTYPE html>
<html>

<body>
<script src="devtools.js"></script>
</body>

</html>
8 changes: 8 additions & 0 deletions extension/firefox/devtools.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
chrome.devtools.panels.create(
"Tweety",
"icons/[email protected]",
"panel.html?reload=true",
function (panel) {
// code to execute when the panel is displayed
}
);
1 change: 1 addition & 0 deletions extension/firefox/icons/icon.link
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
https://icon.ray.so/?fileName=extension_icon&icon=terminal&backgroundRadius=128&backgroundStrokeSize=0&backgroundStrokeColor=%23FFFFFF&backgroundRadialGlare=false&backgroundNoiseTexture=false&backgroundNoiseTextureOpacity=25&backgroundStrokeOpacity=100&iconColor=%23FFFFFF&iconSize=352&selectedPresetIndex=11&customSvg=undefined&backgroundFillType=Linear&backgroundStartColor=%23FC466B&backgroundEndColor=%233F5EFB&backgroundAngle=180
1 change: 1 addition & 0 deletions extension/firefox/icons/icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added extension/firefox/icons/[email protected]
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added extension/firefox/icons/[email protected]
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added extension/firefox/icons/[email protected]
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added extension/firefox/icons/[email protected]
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added extension/firefox/icons/[email protected]
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added extension/firefox/icons/[email protected]
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
45 changes: 45 additions & 0 deletions extension/firefox/manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
{
"manifest_version": 3,
"name": "Tweety",
"version": "1.0.0",
"description": "An integrated terminal for your browser",
"icons": {
"16": "./icons/[email protected]",
"32": "./icons/[email protected]",
"48": "./icons/[email protected]",
"128": "./icons/[email protected]",
"256": "./icons/[email protected]"
},
"background": {
"scripts": [
"worker.js"
]
},
"action": {
"default_icon": {
"16": "./icons/[email protected]",
"24": "./icons/[email protected]",
"32": "./icons/[email protected]"
},
"default_title": "Tweety"
},
"devtools_page": "devtools.html",
"permissions": [
"storage",
"contextMenus"
],
"options_ui": {
"page": "./options.html"
},
"omnibox": {
"keyword": "tty"
},
"commands": {
"create_terminal_tab": {
"description": "Create terminal tab"
},
"create_terminal_window": {
"description": "Create terminal window"
}
}
}
22 changes: 22 additions & 0 deletions extension/firefox/options.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<!doctype html>
<html>

<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>Tweety Options</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@picocss/pico@1/css/pico.min.css" />
<script src="options.js" type="module" defer></script>
</head>

<body>
<main class="container">
<form>
<label for="origin">Origin</label>
<input type="text" name="origin" id="origin" placeholder="Tweety Origin" />
</form>
</main>
</body>

</html>
13 changes: 13 additions & 0 deletions extension/firefox/options.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
const { origin = "http://localhost:9999" } = await chrome.storage.local.get(["origin"]);

const textInput = document.getElementById("origin");
textInput.value = origin;
textInput.addEventListener("input", async (event) => {
try {
const url = new URL(event.target.value);
textInput.setAttribute("aria-invalid", "false");
await chrome.storage.local.set({ origin: url.toString() });
} catch (_) {
textInput.setAttribute("aria-invalid", "true")
}
});
28 changes: 28 additions & 0 deletions extension/firefox/panel.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<!doctype html>
<html>

<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>Tweety</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style>
body {
margin: 0px;
width: 100vw;
height: 100vh;
}

iframe {
display: block;
border: 0px;
width: 100%;
height: 100%;
}
</style>
<script type="module" src="panel.js" defer></script>
</head>

<body></body>

</html>
25 changes: 25 additions & 0 deletions extension/firefox/panel.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
const { origin = "http://localhost:9999" } = await chrome.storage.local.get([
"origin",
]);

const url = new URL(origin);
const params = new URLSearchParams(window.location.search);
for (const param of params) {
url.searchParams.set(param[0], param[1]);
}

const iframe = document.createElement("iframe");
iframe.src = url.toString();
document.body.appendChild(iframe);

window.addEventListener("message", (event) => {
if (event.source !== iframe.contentWindow) {
console.error("Message not from iframe");
return;
}
if (event.data !== "close") {
console.error("Message not close");
return;
}
window.close();
});
51 changes: 51 additions & 0 deletions extension/firefox/worker.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
chrome.runtime.onInstalled.addListener(function () {
console.log("onInstalled");
chrome.contextMenus.removeAll();
chrome.contextMenus.create({
id: "create_terminal_window",
title: "Create Terminal Window",
contexts: ["action"],
});
});

chrome.contextMenus.onClicked.addListener(function (info) {
handleCommand(info.menuItemId);
});

chrome.action.onClicked.addListener(function () {
handleCommand("create_terminal_tab");
});

chrome.commands.onCommand.addListener(handleCommand);

async function handleCommand(command) {
const { origin = "http://localhost:9999" } = await chrome.storage.local.get([
"origin",
]);
if (command == "create_terminal_tab") {
chrome.tabs.create({ url: origin });
} else if (command == "create_terminal_window") {
const [width, height] = [800, 600];
const win = await chrome.windows.getCurrent();
if (!win) {
chrome.windows.create({ url: origin, type: "popup", width, height });
}
const left = Math.round(win.left + (win.width - width) / 2);
const top = Math.round(win.top + (win.height - height) / 2);
chrome.windows.create({ url: origin, type: "popup", width, height, left, top });
}
}

chrome.omnibox.onInputChanged.addListener(function (text) {
chrome.omnibox.setDefaultSuggestion({
description: `Open <match>${text}</match> profile`,
});
});


chrome.omnibox.onInputEntered.addListener(async function (text) {
const { origin = "http://localhost:9999" } = await chrome.storage.local.get([
"origin",
]);
chrome.tabs.create({ url: origin + "?profile=" + encodeURIComponent(text) });
});
25 changes: 25 additions & 0 deletions scripts/build-firefox-extension.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#!/usr/bin/env -S deno run -A
import * as path from "https://deno.land/std/path/mod.ts";
import * as fs from "https://deno.land/std/fs/mod.ts";

const __dirname = new URL(".", import.meta.url).pathname;

const chromeDir = path.join(__dirname, "..", "extension", "chrome");
const firefoxDir = path.join(__dirname, "..", "extension", "firefox");

Deno.removeSync(firefoxDir, { recursive: true });
fs.copySync(chromeDir, firefoxDir);

const manifestPath = path.join(firefoxDir, "manifest.json");
let chromeManifest = JSON.parse(Deno.readTextFileSync(manifestPath));

const firefoxManifest = chromeManifest;

firefoxManifest.background = {
scripts: ["worker.js"],
};

firefoxManifest.side_panel = undefined;
firefoxManifest.permissions = ["storage", "contextMenus"];

Deno.writeTextFileSync(manifestPath, JSON.stringify(firefoxManifest, null, 2));

0 comments on commit c3266d8

Please sign in to comment.