Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 81 additions & 0 deletions extensions/diffkit-redirect/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# DiffKit Extension

Standalone browser extension for redirecting only selected GitHub URLs to DiffKit.

## What it does

- Redirects matching GitHub URLs at page start
- Lets you keep the extension globally enabled or disabled
- Shows one toggle per redirect rule in the popup
- Uses a configurable list of rules instead of redirecting every GitHub page
- Supports both exact URL redirects and regex-based route schemas
- Supports custom route remaps like GitHub PR changes pages to DiffKit review pages

## Default rule

The extension ships with these enabled rules:

- `https://github.com/`
- `https://diff-kit.com/`
- `https://github.com/pulls/*`
- `https://diff-kit.com/pulls`
- `https://github.com/issues/*`
- `https://diff-kit.com/issues`
- `https://github.com/:owner/:repo/pull/:number`
- `https://diff-kit.com/:owner/:repo/pull/:number`
- `https://github.com/:owner/:repo/pull/:number/changes`
- `https://diff-kit.com/:owner/:repo/review/:number`
- `https://github.com/:owner/:repo/issues/:number`
- `https://diff-kit.com/:owner/:repo/issues/:number`

## Rule format

```json
[
{
"id": "github-pull-details",
"label": "Pull request details",
"description": "Redirect GitHub pull request detail pages to DiffKit.",
"enabled": true,
"match": {
"urlRegex": "^https://github\\.com/([^/?#]+)/([^/?#]+)/pull/(\\d+)/?$",
"excludeUrlRegexes": []
},
"redirect": {
"replacement": "https://diff-kit.com/$1/$2/pull/$3"
}
}
]
```

For an exact URL redirect, use:

```json
{
"id": "one-off",
"label": "Specific PR page",
"description": "Single URL redirect",
"enabled": true,
"match": {
"exactUrl": "https://github.com/org/repo/pull/123"
},
"redirect": {
"url": "https://diff-kit.com/org/repo/pull/123"
}
}
```

## Install locally

1. Open `chrome://extensions`
2. Enable Developer mode
3. Click Load unpacked
4. Select `extensions/diffkit-redirect`

## Scope

This version is intentionally limited to `github.com` in `manifest.json`. If you later want redirects from other source hosts, add those hosts to the extension matches and permissions.

## Popup behavior

The popup keeps all default rules enabled unless you turn specific ones off. Use the master switch to pause all redirects without losing your per-rule selections.
22 changes: 22 additions & 0 deletions extensions/diffkit-redirect/content.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
(async function runRedirect() {
const shared = globalThis.DiffKitRedirect;
if (!shared) {
return;
}

try {
const config = await shared.getConfig();
if (!config.enabled) {
return;
}

const redirect = shared.findRedirect(window.location.href, config.rules);
if (!redirect) {
return;
}

window.location.replace(redirect.targetUrl);
} catch (error) {
console.error("DiffKit: failed to evaluate redirect.", error);
}
})();
Binary file added extensions/diffkit-redirect/icons/icon-128.png
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 extensions/diffkit-redirect/icons/icon-16.png
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 extensions/diffkit-redirect/icons/icon-32.png
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 extensions/diffkit-redirect/icons/icon-48.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 12 additions & 0 deletions extensions/diffkit-redirect/icons/logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
30 changes: 30 additions & 0 deletions extensions/diffkit-redirect/manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"manifest_version": 3,
"name": "DiffKit",
"version": "0.1.0",
"description": "Redirect selected GitHub URLs to matching DiffKit routes.",
"icons": {
"16": "icons/icon-16.png",
"32": "icons/icon-32.png",
"48": "icons/icon-48.png",
"128": "icons/icon-128.png"
},
"permissions": ["storage"],
"host_permissions": ["https://github.com/*"],
"action": {
"default_title": "DiffKit",
"default_popup": "popup.html",
"default_icon": {
"16": "icons/icon-16.png",
"32": "icons/icon-32.png"
}
},
"options_page": "options.html",
"content_scripts": [
{
"matches": ["https://github.com/*"],
"js": ["shared.js", "content.js"],
"run_at": "document_start"
}
]
}
74 changes: 74 additions & 0 deletions extensions/diffkit-redirect/options.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>DiffKit Options</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<main class="options-layout">
<section class="options-panel">
<div class="options-header">
<div>
<p class="eyebrow">DiffKit</p>
<h1>Redirect rules</h1>
</div>

<label class="toggle-row">
<span>Enabled</span>
<input id="enabled-toggle" type="checkbox">
</label>
</div>

<p class="muted">
Add only the GitHub routes DiffKit currently supports. A rule can
match a single exact URL or a regex pattern over the full URL.
</p>

<textarea
id="rules-editor"
class="rules-editor"
spellcheck="false"
></textarea>

<div class="panel-actions">
<button id="save-button" type="button">Save rules</button>
<button id="reset-button" type="button" class="secondary">
Reset defaults
</button>
</div>

<p id="save-status" class="status-copy"></p>
</section>

<aside class="help-panel">
<h2>Rule shape</h2>
<pre class="code-block">{
"id": "github-pull-details",
"label": "Pull request details",
"description": "Redirect GitHub pull request detail pages to DiffKit.",
"enabled": true,
"match": {
"urlRegex": "^https://github\\.com/([^/?#]+)/([^/?#]+)/pull/(\\d+)/?$",
"excludeUrlRegexes": []
},
"redirect": {
"replacement": "https://diff-kit.com/$1/$2/pull/$3"
}
}</pre>

<p class="muted">
<code>label</code>
is optional but recommended so the popup can show a clean toggle name.
For one-off routes, use <code>match.exactUrl</code> and
<code>redirect.url</code>
instead.
</p>
</aside>
</main>

<script src="shared.js"></script>
<script src="options.js"></script>
</body>
</html>
58 changes: 58 additions & 0 deletions extensions/diffkit-redirect/options.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
(async function initOptions() {
const shared = globalThis.DiffKitRedirect;
const enabledToggle = document.getElementById("enabled-toggle");
const rulesEditor = document.getElementById("rules-editor");
const saveButton = document.getElementById("save-button");
const resetButton = document.getElementById("reset-button");
const saveStatus = document.getElementById("save-status");

function setStatus(message, tone) {
saveStatus.textContent = message;
saveStatus.dataset.tone = tone || "";
}

async function loadConfig() {
const config = await shared.getConfig();
enabledToggle.checked = config.enabled;
rulesEditor.value = JSON.stringify(config.rules, null, 2);

if (config.validationErrors.length > 0) {
setStatus(config.validationErrors.join(" "), "error");
return;
}

setStatus("", "");
}

async function saveConfig() {
let parsedRules;
try {
parsedRules = JSON.parse(rulesEditor.value);
} catch {
setStatus("Rules must be valid JSON.", "error");
return;
}

const result = await shared.saveConfig({
enabled: enabledToggle.checked,
rules: parsedRules,
});

if (!result.ok) {
setStatus(result.errors.join(" "), "error");
return;
}

setStatus("Rules saved.", "success");
await loadConfig();
}

saveButton.addEventListener("click", saveConfig);

resetButton.addEventListener("click", () => {
rulesEditor.value = JSON.stringify(shared.getDefaultRules(), null, 2);
setStatus("Defaults restored in the editor. Save to apply them.", "");
});

await loadConfig();
})();
41 changes: 41 additions & 0 deletions extensions/diffkit-redirect/popup.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>DiffKit</title>
<link rel="stylesheet" href="styles.css">
</head>
<body class="popup-body">
<main class="popup-shell">
<section class="popup-card">
<div class="brand-row">
<div class="brand-lockup">
<img class="brand-logo" src="icons/logo.svg" alt="DiffKit">
<div>
<p class="eyebrow">DiffKit</p>
<h1>GitHub redirects</h1>
</div>
</div>
<label class="switch" aria-label="Toggle redirects">
<input id="enabled-toggle" type="checkbox">
<span class="switch-track"></span>
</label>
</div>

<p class="lede">
Choose which GitHub routes should jump into DiffKit automatically.
</p>

<div id="rule-list" class="rule-list" role="list"></div>

<div class="status-row">
<p id="status-copy" class="status-copy">Loading…</p>
</div>
</section>
</main>

<script src="shared.js"></script>
<script src="popup.js"></script>
</body>
</html>
Loading
Loading