This commit is contained in:
everestmcarthur 2026-08-01 14:22:29 +00:00
parent 46d2fa3dc9
commit db5fd20107
14 changed files with 902 additions and 99 deletions

0
.nojekyll Normal file
View file

411
404.html Normal file
View file

@ -0,0 +1,411 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>revenge-plugins</title>
<meta name="description" content="Plugins for Revenge, the Discord Android client mod.">
<style>
:root {
--bg: #f5f6fa;
--bg-elevated: #ffffff;
--border: #e3e5eb;
--text: #1c1e26;
--text-muted: #61667a;
--accent: #5865f2;
--accent-text: #ffffff;
--chip-bg: #ececf5;
--chip-bg-active: #5865f2;
--chip-text-active: #ffffff;
--badge-new-bg: #e6f6ec;
--badge-new-text: #1a7f4b;
--badge-revived-bg: #eef0ff;
--badge-revived-text: #4752c4;
--badge-rebuilt-bg: #fff3e0;
--badge-rebuilt-text: #b5680a;
--shadow: 0 1px 2px rgba(20, 21, 31, 0.06), 0 8px 24px rgba(20, 21, 31, 0.05);
color-scheme: light;
}
@media (prefers-color-scheme: dark) {
:root {
--bg: #14151c;
--bg-elevated: #1c1e28;
--border: #2a2c38;
--text: #eef0f7;
--text-muted: #9297ab;
--accent: #7b84f7;
--accent-text: #10111a;
--chip-bg: #262838;
--chip-bg-active: #7b84f7;
--chip-text-active: #10111a;
--badge-new-bg: #103324;
--badge-new-text: #5fd493;
--badge-revived-bg: #21243f;
--badge-revived-text: #9ba3ff;
--badge-rebuilt-bg: #3a2a10;
--badge-rebuilt-text: #e6a852;
--shadow: 0 1px 2px rgba(0, 0, 0, 0.3), 0 8px 24px rgba(0, 0, 0, 0.35);
color-scheme: dark;
}
}
:root[data-theme="dark"] {
--bg: #14151c; --bg-elevated: #1c1e28; --border: #2a2c38; --text: #eef0f7; --text-muted: #9297ab;
--accent: #7b84f7; --accent-text: #10111a; --chip-bg: #262838; --chip-bg-active: #7b84f7; --chip-text-active: #10111a;
--badge-new-bg: #103324; --badge-new-text: #5fd493; --badge-revived-bg: #21243f; --badge-revived-text: #9ba3ff;
--badge-rebuilt-bg: #3a2a10; --badge-rebuilt-text: #e6a852;
--shadow: 0 1px 2px rgba(0,0,0,0.3), 0 8px 24px rgba(0,0,0,0.35); color-scheme: dark;
}
:root[data-theme="light"] {
--bg: #f5f6fa; --bg-elevated: #ffffff; --border: #e3e5eb; --text: #1c1e26; --text-muted: #61667a;
--accent: #5865f2; --accent-text: #ffffff; --chip-bg: #ececf5; --chip-bg-active: #5865f2; --chip-text-active: #ffffff;
--badge-new-bg: #e6f6ec; --badge-new-text: #1a7f4b; --badge-revived-bg: #eef0ff; --badge-revived-text: #4752c4;
--badge-rebuilt-bg: #fff3e0; --badge-rebuilt-text: #b5680a;
--shadow: 0 1px 2px rgba(20,21,31,0.06), 0 8px 24px rgba(20,21,31,0.05); color-scheme: light;
}
* { box-sizing: border-box; }
body {
margin: 0;
background: var(--bg);
color: var(--text);
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
}
.wrap { max-width: 980px; margin: 0 auto; padding: 0 20px; }
header.hero {
padding: 56px 0 32px;
border-bottom: 1px solid var(--border);
}
.eyebrow {
display: inline-flex;
align-items: center;
gap: 6px;
font-size: 13px;
font-weight: 600;
color: var(--accent);
letter-spacing: 0.02em;
margin-bottom: 12px;
}
h1 { font-size: 34px; line-height: 1.15; margin: 0 0 10px; letter-spacing: -0.01em; }
.hero p.sub { color: var(--text-muted); font-size: 16px; max-width: 620px; margin: 0 0 20px; line-height: 1.5; }
.hero-links { display: flex; gap: 10px; flex-wrap: wrap; }
.hero-links a {
font-size: 14px;
font-weight: 600;
color: var(--text);
text-decoration: none;
padding: 8px 14px;
border-radius: 8px;
border: 1px solid var(--border);
background: var(--bg-elevated);
}
.hero-links a.primary { background: var(--accent); color: var(--accent-text); border-color: transparent; }
.stats { display: flex; gap: 28px; margin-top: 28px; flex-wrap: wrap; }
.stats .stat-value { font-size: 24px; font-weight: 700; letter-spacing: -0.01em; }
.stats .stat-label { font-size: 12.5px; color: var(--text-muted); font-weight: 600; }
.controls {
position: sticky;
top: 0;
background: var(--bg);
padding: 18px 0;
z-index: 5;
border-bottom: 1px solid transparent;
}
.controls.stuck { border-bottom-color: var(--border); }
.search {
width: 100%;
padding: 12px 14px;
border-radius: 10px;
border: 1px solid var(--border);
background: var(--bg-elevated);
color: var(--text);
font-size: 15px;
margin-bottom: 12px;
}
.search:focus { outline: 2px solid var(--accent); outline-offset: 1px; }
.chips { display: flex; gap: 8px; flex-wrap: wrap; }
.chip {
font-size: 13px;
font-weight: 600;
padding: 7px 13px;
border-radius: 999px;
background: var(--chip-bg);
color: var(--text-muted);
border: none;
cursor: pointer;
}
.chip[aria-pressed="true"] { background: var(--chip-bg-active); color: var(--chip-text-active); }
main { padding: 24px 0 64px; }
.count { color: var(--text-muted); font-size: 13px; margin: 0 0 16px; }
.grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 14px; }
.card {
background: var(--bg-elevated);
border: 1px solid var(--border);
border-radius: 14px;
padding: 18px;
box-shadow: var(--shadow);
display: flex;
flex-direction: column;
}
.card-top { display: flex; align-items: flex-start; justify-content: space-between; gap: 8px; margin-bottom: 6px; }
.card h3 { font-size: 17px; margin: 0; letter-spacing: -0.005em; }
.badge {
font-size: 11px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.03em;
padding: 3px 8px;
border-radius: 999px;
white-space: nowrap;
flex-shrink: 0;
}
.badge.new { background: var(--badge-new-bg); color: var(--badge-new-text); }
.badge.revived { background: var(--badge-revived-bg); color: var(--badge-revived-text); }
.badge.rebuilt { background: var(--badge-rebuilt-bg); color: var(--badge-rebuilt-text); }
.card .category { font-size: 12px; color: var(--accent); font-weight: 600; margin-bottom: 8px; }
.card p.desc { font-size: 14px; color: var(--text-muted); line-height: 1.5; margin: 0 0 10px; flex-grow: 1; }
.card p.note { font-size: 12.5px; color: var(--text-muted); line-height: 1.5; margin: 0 0 14px; padding: 8px 10px; background: var(--bg); border-radius: 8px; border: 1px solid var(--border); }
.card .authors { font-size: 12px; color: var(--text-muted); margin-bottom: 12px; }
.actions { display: flex; gap: 8px; flex-wrap: wrap; }
.actions button, .actions a {
font-size: 13px;
font-weight: 600;
padding: 8px 12px;
border-radius: 8px;
border: 1px solid var(--border);
background: var(--bg);
color: var(--text);
text-decoration: none;
cursor: pointer;
flex: 1;
text-align: center;
min-width: 88px;
}
.actions button.install { background: var(--accent); color: var(--accent-text); border-color: transparent; }
.actions button.install[data-copied="true"] { background: var(--badge-new-text); }
.empty { text-align: center; padding: 60px 20px; color: var(--text-muted); }
footer { border-top: 1px solid var(--border); padding: 24px 0 40px; }
footer p { color: var(--text-muted); font-size: 13px; margin: 0; }
footer a { color: var(--text-muted); }
.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0,0,0,0); }
.toast {
position: fixed;
bottom: 20px;
left: 50%;
transform: translateX(-50%) translateY(0);
background: var(--text);
color: var(--bg);
font-size: 13px;
font-weight: 600;
padding: 10px 16px;
border-radius: 999px;
opacity: 0;
pointer-events: none;
transition: opacity 0.2s ease, transform 0.2s ease;
z-index: 50;
}
.toast.show { opacity: 1; transform: translateX(-50%) translateY(-8px); }
</style>
</head>
<body>
<header class="hero">
<div class="wrap">
<div class="eyebrow">👊 REVENGE PLUGINS</div>
<h1>Plugins for Revenge</h1>
<p class="sub">An actively maintained collection of plugins for Revenge, the Discord Android client mod. Tap Install to copy a plugin's link, then paste it into Revenge's plugin browser.</p>
<div class="hero-links">
<a class="primary" href="https://github.com/everestmcarthur/revenge-plugins">GitHub repo</a>
<a href="https://github.com/revenge-mod/revenge-bundle">About Revenge</a>
<a href="https://github.com/everestmcarthur/revenge-plugins/issues/new">Report an issue</a>
</div>
<div class="stats" id="stats" aria-hidden="true"></div>
</div>
</header>
<div class="wrap">
<div class="controls" id="controls">
<input id="search" class="search" type="search" placeholder="Search plugins…" aria-label="Search plugins">
<div class="chips" id="categoryChips" role="group" aria-label="Filter by category"></div>
</div>
<main>
<p class="count" id="count"></p>
<div class="grid" id="grid"></div>
<div class="empty" id="empty" hidden>No plugins match your search.</div>
</main>
</div>
<footer>
<div class="wrap">
<p>Built with <a href="https://github.com/everestmcarthur/revenge-plugins">revenge-plugins</a> · not affiliated with Discord or the Revenge project · install links point to this site</p>
</div>
</footer>
<div class="toast" id="toast" role="status" aria-live="polite"></div>
<script>
(function () {
var STATUS_LABEL = { new: "New", revived: "Revived", rebuilt: "Rebuilt" };
var state = { plugins: [], query: "", category: "All" };
var grid = document.getElementById("grid");
var empty = document.getElementById("empty");
var count = document.getElementById("count");
var chipsEl = document.getElementById("categoryChips");
var searchEl = document.getElementById("search");
var toastEl = document.getElementById("toast");
var statsEl = document.getElementById("stats");
function renderStats() {
var categories = Array.from(new Set(state.plugins.map(function (p) { return p.category; })));
var revivedCount = state.plugins.filter(function (p) { return p.status !== "new"; }).length;
var stats = [
{ value: state.plugins.length, label: "plugins" },
{ value: categories.length, label: "categories" },
{ value: revivedCount, label: "revived or rebuilt" }
];
statsEl.innerHTML = stats.map(function (s) {
return '<div><div class="stat-value">' + s.value + '</div><div class="stat-label">' + s.label + '</div></div>';
}).join("");
}
function showToast(msg) {
toastEl.textContent = msg;
toastEl.classList.add("show");
clearTimeout(showToast._t);
showToast._t = setTimeout(function () { toastEl.classList.remove("show"); }, 1600);
}
function escapeHtml(str) {
return String(str).replace(/[&<>"']/g, function (c) {
return { "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;" }[c];
});
}
function copyToClipboard(text) {
if (navigator.clipboard && navigator.clipboard.writeText) {
return navigator.clipboard.writeText(text);
}
var ta = document.createElement("textarea");
ta.value = text;
ta.style.position = "fixed";
ta.style.opacity = "0";
document.body.appendChild(ta);
ta.select();
try { document.execCommand("copy"); } catch (e) {}
document.body.removeChild(ta);
return Promise.resolve();
}
function render() {
var q = state.query.trim().toLowerCase();
var filtered = state.plugins.filter(function (p) {
var matchesCategory = state.category === "All" || p.category === state.category;
var matchesQuery = !q ||
p.name.toLowerCase().indexOf(q) !== -1 ||
p.description.toLowerCase().indexOf(q) !== -1 ||
p.category.toLowerCase().indexOf(q) !== -1;
return matchesCategory && matchesQuery;
});
count.textContent = filtered.length + " plugin" + (filtered.length === 1 ? "" : "s");
grid.innerHTML = "";
empty.hidden = filtered.length !== 0;
filtered.forEach(function (p) {
var card = document.createElement("article");
card.className = "card";
card.innerHTML =
'<div class="card-top">' +
'<h3>' + escapeHtml(p.name) + '</h3>' +
'<span class="badge ' + p.status + '">' + (STATUS_LABEL[p.status] || p.status) + '</span>' +
'</div>' +
'<div class="category">' + escapeHtml(p.category) + '</div>' +
'<p class="desc">' + escapeHtml(p.description) + '</p>' +
(p.note ? '<p class="note">' + escapeHtml(p.note) + '</p>' : '') +
(p.authors && p.authors.length ? '<p class="authors">By ' + escapeHtml(p.authors.join(", ")) + '</p>' : '') +
'<div class="actions">' +
'<button class="install" data-url="' + escapeHtml(p.installUrl) + '">Install</button>' +
'<a href="' + escapeHtml(p.sourceUrl) + '" target="_blank" rel="noopener">Source</a>' +
'<a href="' + escapeHtml(p.issueUrl) + '" target="_blank" rel="noopener">Report issue</a>' +
'</div>';
card.querySelector("button.install").addEventListener("click", function (e) {
var btn = e.currentTarget;
copyToClipboard(btn.getAttribute("data-url")).then(function () {
var original = btn.textContent;
btn.textContent = "Copied!";
btn.setAttribute("data-copied", "true");
showToast("Install link copied - paste it into Revenge's plugin browser");
setTimeout(function () {
btn.textContent = original;
btn.removeAttribute("data-copied");
}, 1400);
});
});
grid.appendChild(card);
});
}
function renderChips() {
var categories = ["All"].concat(
Array.from(new Set(state.plugins.map(function (p) { return p.category; }))).sort()
);
chipsEl.innerHTML = "";
categories.forEach(function (cat) {
var chip = document.createElement("button");
chip.className = "chip";
chip.textContent = cat;
chip.setAttribute("aria-pressed", String(cat === state.category));
chip.addEventListener("click", function () {
state.category = cat;
Array.from(chipsEl.children).forEach(function (c) {
c.setAttribute("aria-pressed", String(c === chip));
});
render();
});
chipsEl.appendChild(chip);
});
}
searchEl.addEventListener("input", function (e) {
state.query = e.target.value;
render();
});
var controls = document.getElementById("controls");
window.addEventListener("scroll", function () {
controls.classList.toggle("stuck", window.scrollY > 8);
});
fetch("https://everestmcarthur.github.io/revenge-plugins/plugins-data.json")
.then(function (r) { return r.json(); })
.then(function (data) {
state.plugins = data;
renderStats();
renderChips();
render();
})
.catch(function () {
count.textContent = "";
empty.hidden = false;
empty.textContent = "Couldn't load the plugin list - try refreshing.";
});
})();
</script>
</body>
</html>

52
404.md
View file

@ -1,52 +0,0 @@
---
permalink: /404.html
---
> **Note:** You accessed a link that returned a 404, probably by clicking one of the plugin links. You're supposed to copy the link address and add it into Revenge.
# revenge-plugins
A small collection of plugins for [Revenge](https://github.com/revenge-mod/revenge-bundle), the Discord Android client mod.
## Installing a plugin
1. Open Discord with Revenge installed, go to **Settings → Plugins**.
2. Tap the `+` button and paste the plugin's install link (see below).
3. Enable it.
| Plugin | Description | Install link |
| --- | --- | --- |
| Staff Tags | Adds OWNER/ADMIN/STAFF/MOD-style tags next to members, based on their actual server permissions. Fully customizable: per-tag text, colors, gradients, and visibility. | `https://everestmcarthur.github.io/revenge-plugins/staff-tags/` |
## About Staff Tags
This is a rebuilt version of the old `staff-tags` plugin, which stopped working after Discord renamed some of the
internal components it depended on (`DisplayName`, `HeaderName`, `getTagProperties`) - when any one of those lookups
came back empty, the entire plugin used to fail to load, taking every tag down with it, everywhere.
This version isolates each patch (chat tags, member list, profile, channel header) so that if Discord changes one of
them again in the future, only that specific surface stops showing tags instead of the whole plugin breaking. It also
adds:
- Per-tag show/hide toggles
- Custom tag text
- Custom solid colors
- Gradient tags (member list & profile only - chat message tags are rendered from data rather than a
patchable element, so they always use a solid color)
- "Use top role color" as a fallback when no custom color is set
Tags are computed from the built-in `computePermissions` API against real permission bits (Administrator, Manage
Server, Manage Messages, Kick/Ban, etc.), the same as the original plugin, not from role names.
## Building locally
```sh
npm install
npm run build
```
Output is written to `dist/<plugin>/`.
## Contributing
Issues and PRs are welcome, especially if a Discord update breaks a lookup a plugin relies on - `findByName` /
`findByProps` targets can and do change without notice.

View file

@ -1,47 +0,0 @@
# revenge-plugins
A small collection of plugins for [Revenge](https://github.com/revenge-mod/revenge-bundle), the Discord Android client mod.
## Installing a plugin
1. Open Discord with Revenge installed, go to **Settings → Plugins**.
2. Tap the `+` button and paste the plugin's install link (see below).
3. Enable it.
| Plugin | Description | Install link |
| --- | --- | --- |
| Staff Tags | Adds OWNER/ADMIN/STAFF/MOD-style tags next to members, based on their actual server permissions. Fully customizable: per-tag text, colors, gradients, and visibility. | `https://everestmcarthur.github.io/revenge-plugins/staff-tags/` |
## About Staff Tags
This is a rebuilt version of the old `staff-tags` plugin, which stopped working after Discord renamed some of the
internal components it depended on (`DisplayName`, `HeaderName`, `getTagProperties`) - when any one of those lookups
came back empty, the entire plugin used to fail to load, taking every tag down with it, everywhere.
This version isolates each patch (chat tags, member list, profile, channel header) so that if Discord changes one of
them again in the future, only that specific surface stops showing tags instead of the whole plugin breaking. It also
adds:
- Per-tag show/hide toggles
- Custom tag text
- Custom solid colors
- Gradient tags (member list & profile only - chat message tags are rendered from data rather than a
patchable element, so they always use a solid color)
- "Use top role color" as a fallback when no custom color is set
Tags are computed from the built-in `computePermissions` API against real permission bits (Administrator, Manage
Server, Manage Messages, Kick/Ban, etc.), the same as the original plugin, not from role names.
## Building locally
```sh
npm install
npm run build
```
Output is written to `dist/<plugin>/`.
## Contributing
Issues and PRs are welcome, especially if a Discord update breaks a lookup a plugin relies on - `findByName` /
`findByProps` targets can and do change without notice.

411
index.html Normal file
View file

@ -0,0 +1,411 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>revenge-plugins</title>
<meta name="description" content="Plugins for Revenge, the Discord Android client mod.">
<style>
:root {
--bg: #f5f6fa;
--bg-elevated: #ffffff;
--border: #e3e5eb;
--text: #1c1e26;
--text-muted: #61667a;
--accent: #5865f2;
--accent-text: #ffffff;
--chip-bg: #ececf5;
--chip-bg-active: #5865f2;
--chip-text-active: #ffffff;
--badge-new-bg: #e6f6ec;
--badge-new-text: #1a7f4b;
--badge-revived-bg: #eef0ff;
--badge-revived-text: #4752c4;
--badge-rebuilt-bg: #fff3e0;
--badge-rebuilt-text: #b5680a;
--shadow: 0 1px 2px rgba(20, 21, 31, 0.06), 0 8px 24px rgba(20, 21, 31, 0.05);
color-scheme: light;
}
@media (prefers-color-scheme: dark) {
:root {
--bg: #14151c;
--bg-elevated: #1c1e28;
--border: #2a2c38;
--text: #eef0f7;
--text-muted: #9297ab;
--accent: #7b84f7;
--accent-text: #10111a;
--chip-bg: #262838;
--chip-bg-active: #7b84f7;
--chip-text-active: #10111a;
--badge-new-bg: #103324;
--badge-new-text: #5fd493;
--badge-revived-bg: #21243f;
--badge-revived-text: #9ba3ff;
--badge-rebuilt-bg: #3a2a10;
--badge-rebuilt-text: #e6a852;
--shadow: 0 1px 2px rgba(0, 0, 0, 0.3), 0 8px 24px rgba(0, 0, 0, 0.35);
color-scheme: dark;
}
}
:root[data-theme="dark"] {
--bg: #14151c; --bg-elevated: #1c1e28; --border: #2a2c38; --text: #eef0f7; --text-muted: #9297ab;
--accent: #7b84f7; --accent-text: #10111a; --chip-bg: #262838; --chip-bg-active: #7b84f7; --chip-text-active: #10111a;
--badge-new-bg: #103324; --badge-new-text: #5fd493; --badge-revived-bg: #21243f; --badge-revived-text: #9ba3ff;
--badge-rebuilt-bg: #3a2a10; --badge-rebuilt-text: #e6a852;
--shadow: 0 1px 2px rgba(0,0,0,0.3), 0 8px 24px rgba(0,0,0,0.35); color-scheme: dark;
}
:root[data-theme="light"] {
--bg: #f5f6fa; --bg-elevated: #ffffff; --border: #e3e5eb; --text: #1c1e26; --text-muted: #61667a;
--accent: #5865f2; --accent-text: #ffffff; --chip-bg: #ececf5; --chip-bg-active: #5865f2; --chip-text-active: #ffffff;
--badge-new-bg: #e6f6ec; --badge-new-text: #1a7f4b; --badge-revived-bg: #eef0ff; --badge-revived-text: #4752c4;
--badge-rebuilt-bg: #fff3e0; --badge-rebuilt-text: #b5680a;
--shadow: 0 1px 2px rgba(20,21,31,0.06), 0 8px 24px rgba(20,21,31,0.05); color-scheme: light;
}
* { box-sizing: border-box; }
body {
margin: 0;
background: var(--bg);
color: var(--text);
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
}
.wrap { max-width: 980px; margin: 0 auto; padding: 0 20px; }
header.hero {
padding: 56px 0 32px;
border-bottom: 1px solid var(--border);
}
.eyebrow {
display: inline-flex;
align-items: center;
gap: 6px;
font-size: 13px;
font-weight: 600;
color: var(--accent);
letter-spacing: 0.02em;
margin-bottom: 12px;
}
h1 { font-size: 34px; line-height: 1.15; margin: 0 0 10px; letter-spacing: -0.01em; }
.hero p.sub { color: var(--text-muted); font-size: 16px; max-width: 620px; margin: 0 0 20px; line-height: 1.5; }
.hero-links { display: flex; gap: 10px; flex-wrap: wrap; }
.hero-links a {
font-size: 14px;
font-weight: 600;
color: var(--text);
text-decoration: none;
padding: 8px 14px;
border-radius: 8px;
border: 1px solid var(--border);
background: var(--bg-elevated);
}
.hero-links a.primary { background: var(--accent); color: var(--accent-text); border-color: transparent; }
.stats { display: flex; gap: 28px; margin-top: 28px; flex-wrap: wrap; }
.stats .stat-value { font-size: 24px; font-weight: 700; letter-spacing: -0.01em; }
.stats .stat-label { font-size: 12.5px; color: var(--text-muted); font-weight: 600; }
.controls {
position: sticky;
top: 0;
background: var(--bg);
padding: 18px 0;
z-index: 5;
border-bottom: 1px solid transparent;
}
.controls.stuck { border-bottom-color: var(--border); }
.search {
width: 100%;
padding: 12px 14px;
border-radius: 10px;
border: 1px solid var(--border);
background: var(--bg-elevated);
color: var(--text);
font-size: 15px;
margin-bottom: 12px;
}
.search:focus { outline: 2px solid var(--accent); outline-offset: 1px; }
.chips { display: flex; gap: 8px; flex-wrap: wrap; }
.chip {
font-size: 13px;
font-weight: 600;
padding: 7px 13px;
border-radius: 999px;
background: var(--chip-bg);
color: var(--text-muted);
border: none;
cursor: pointer;
}
.chip[aria-pressed="true"] { background: var(--chip-bg-active); color: var(--chip-text-active); }
main { padding: 24px 0 64px; }
.count { color: var(--text-muted); font-size: 13px; margin: 0 0 16px; }
.grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 14px; }
.card {
background: var(--bg-elevated);
border: 1px solid var(--border);
border-radius: 14px;
padding: 18px;
box-shadow: var(--shadow);
display: flex;
flex-direction: column;
}
.card-top { display: flex; align-items: flex-start; justify-content: space-between; gap: 8px; margin-bottom: 6px; }
.card h3 { font-size: 17px; margin: 0; letter-spacing: -0.005em; }
.badge {
font-size: 11px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.03em;
padding: 3px 8px;
border-radius: 999px;
white-space: nowrap;
flex-shrink: 0;
}
.badge.new { background: var(--badge-new-bg); color: var(--badge-new-text); }
.badge.revived { background: var(--badge-revived-bg); color: var(--badge-revived-text); }
.badge.rebuilt { background: var(--badge-rebuilt-bg); color: var(--badge-rebuilt-text); }
.card .category { font-size: 12px; color: var(--accent); font-weight: 600; margin-bottom: 8px; }
.card p.desc { font-size: 14px; color: var(--text-muted); line-height: 1.5; margin: 0 0 10px; flex-grow: 1; }
.card p.note { font-size: 12.5px; color: var(--text-muted); line-height: 1.5; margin: 0 0 14px; padding: 8px 10px; background: var(--bg); border-radius: 8px; border: 1px solid var(--border); }
.card .authors { font-size: 12px; color: var(--text-muted); margin-bottom: 12px; }
.actions { display: flex; gap: 8px; flex-wrap: wrap; }
.actions button, .actions a {
font-size: 13px;
font-weight: 600;
padding: 8px 12px;
border-radius: 8px;
border: 1px solid var(--border);
background: var(--bg);
color: var(--text);
text-decoration: none;
cursor: pointer;
flex: 1;
text-align: center;
min-width: 88px;
}
.actions button.install { background: var(--accent); color: var(--accent-text); border-color: transparent; }
.actions button.install[data-copied="true"] { background: var(--badge-new-text); }
.empty { text-align: center; padding: 60px 20px; color: var(--text-muted); }
footer { border-top: 1px solid var(--border); padding: 24px 0 40px; }
footer p { color: var(--text-muted); font-size: 13px; margin: 0; }
footer a { color: var(--text-muted); }
.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0,0,0,0); }
.toast {
position: fixed;
bottom: 20px;
left: 50%;
transform: translateX(-50%) translateY(0);
background: var(--text);
color: var(--bg);
font-size: 13px;
font-weight: 600;
padding: 10px 16px;
border-radius: 999px;
opacity: 0;
pointer-events: none;
transition: opacity 0.2s ease, transform 0.2s ease;
z-index: 50;
}
.toast.show { opacity: 1; transform: translateX(-50%) translateY(-8px); }
</style>
</head>
<body>
<header class="hero">
<div class="wrap">
<div class="eyebrow">👊 REVENGE PLUGINS</div>
<h1>Plugins for Revenge</h1>
<p class="sub">An actively maintained collection of plugins for Revenge, the Discord Android client mod. Tap Install to copy a plugin's link, then paste it into Revenge's plugin browser.</p>
<div class="hero-links">
<a class="primary" href="https://github.com/everestmcarthur/revenge-plugins">GitHub repo</a>
<a href="https://github.com/revenge-mod/revenge-bundle">About Revenge</a>
<a href="https://github.com/everestmcarthur/revenge-plugins/issues/new">Report an issue</a>
</div>
<div class="stats" id="stats" aria-hidden="true"></div>
</div>
</header>
<div class="wrap">
<div class="controls" id="controls">
<input id="search" class="search" type="search" placeholder="Search plugins…" aria-label="Search plugins">
<div class="chips" id="categoryChips" role="group" aria-label="Filter by category"></div>
</div>
<main>
<p class="count" id="count"></p>
<div class="grid" id="grid"></div>
<div class="empty" id="empty" hidden>No plugins match your search.</div>
</main>
</div>
<footer>
<div class="wrap">
<p>Built with <a href="https://github.com/everestmcarthur/revenge-plugins">revenge-plugins</a> · not affiliated with Discord or the Revenge project · install links point to this site</p>
</div>
</footer>
<div class="toast" id="toast" role="status" aria-live="polite"></div>
<script>
(function () {
var STATUS_LABEL = { new: "New", revived: "Revived", rebuilt: "Rebuilt" };
var state = { plugins: [], query: "", category: "All" };
var grid = document.getElementById("grid");
var empty = document.getElementById("empty");
var count = document.getElementById("count");
var chipsEl = document.getElementById("categoryChips");
var searchEl = document.getElementById("search");
var toastEl = document.getElementById("toast");
var statsEl = document.getElementById("stats");
function renderStats() {
var categories = Array.from(new Set(state.plugins.map(function (p) { return p.category; })));
var revivedCount = state.plugins.filter(function (p) { return p.status !== "new"; }).length;
var stats = [
{ value: state.plugins.length, label: "plugins" },
{ value: categories.length, label: "categories" },
{ value: revivedCount, label: "revived or rebuilt" }
];
statsEl.innerHTML = stats.map(function (s) {
return '<div><div class="stat-value">' + s.value + '</div><div class="stat-label">' + s.label + '</div></div>';
}).join("");
}
function showToast(msg) {
toastEl.textContent = msg;
toastEl.classList.add("show");
clearTimeout(showToast._t);
showToast._t = setTimeout(function () { toastEl.classList.remove("show"); }, 1600);
}
function escapeHtml(str) {
return String(str).replace(/[&<>"']/g, function (c) {
return { "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;" }[c];
});
}
function copyToClipboard(text) {
if (navigator.clipboard && navigator.clipboard.writeText) {
return navigator.clipboard.writeText(text);
}
var ta = document.createElement("textarea");
ta.value = text;
ta.style.position = "fixed";
ta.style.opacity = "0";
document.body.appendChild(ta);
ta.select();
try { document.execCommand("copy"); } catch (e) {}
document.body.removeChild(ta);
return Promise.resolve();
}
function render() {
var q = state.query.trim().toLowerCase();
var filtered = state.plugins.filter(function (p) {
var matchesCategory = state.category === "All" || p.category === state.category;
var matchesQuery = !q ||
p.name.toLowerCase().indexOf(q) !== -1 ||
p.description.toLowerCase().indexOf(q) !== -1 ||
p.category.toLowerCase().indexOf(q) !== -1;
return matchesCategory && matchesQuery;
});
count.textContent = filtered.length + " plugin" + (filtered.length === 1 ? "" : "s");
grid.innerHTML = "";
empty.hidden = filtered.length !== 0;
filtered.forEach(function (p) {
var card = document.createElement("article");
card.className = "card";
card.innerHTML =
'<div class="card-top">' +
'<h3>' + escapeHtml(p.name) + '</h3>' +
'<span class="badge ' + p.status + '">' + (STATUS_LABEL[p.status] || p.status) + '</span>' +
'</div>' +
'<div class="category">' + escapeHtml(p.category) + '</div>' +
'<p class="desc">' + escapeHtml(p.description) + '</p>' +
(p.note ? '<p class="note">' + escapeHtml(p.note) + '</p>' : '') +
(p.authors && p.authors.length ? '<p class="authors">By ' + escapeHtml(p.authors.join(", ")) + '</p>' : '') +
'<div class="actions">' +
'<button class="install" data-url="' + escapeHtml(p.installUrl) + '">Install</button>' +
'<a href="' + escapeHtml(p.sourceUrl) + '" target="_blank" rel="noopener">Source</a>' +
'<a href="' + escapeHtml(p.issueUrl) + '" target="_blank" rel="noopener">Report issue</a>' +
'</div>';
card.querySelector("button.install").addEventListener("click", function (e) {
var btn = e.currentTarget;
copyToClipboard(btn.getAttribute("data-url")).then(function () {
var original = btn.textContent;
btn.textContent = "Copied!";
btn.setAttribute("data-copied", "true");
showToast("Install link copied - paste it into Revenge's plugin browser");
setTimeout(function () {
btn.textContent = original;
btn.removeAttribute("data-copied");
}, 1400);
});
});
grid.appendChild(card);
});
}
function renderChips() {
var categories = ["All"].concat(
Array.from(new Set(state.plugins.map(function (p) { return p.category; }))).sort()
);
chipsEl.innerHTML = "";
categories.forEach(function (cat) {
var chip = document.createElement("button");
chip.className = "chip";
chip.textContent = cat;
chip.setAttribute("aria-pressed", String(cat === state.category));
chip.addEventListener("click", function () {
state.category = cat;
Array.from(chipsEl.children).forEach(function (c) {
c.setAttribute("aria-pressed", String(c === chip));
});
render();
});
chipsEl.appendChild(chip);
});
}
searchEl.addEventListener("input", function (e) {
state.query = e.target.value;
render();
});
var controls = document.getElementById("controls");
window.addEventListener("scroll", function () {
controls.classList.toggle("stuck", window.scrollY > 8);
});
fetch("https://everestmcarthur.github.io/revenge-plugins/plugins-data.json")
.then(function (r) { return r.json(); })
.then(function (data) {
state.plugins = data;
renderStats();
renderChips();
render();
})
.catch(function () {
count.textContent = "";
empty.hidden = false;
empty.textContent = "Couldn't load the plugin list - try refreshing.";
});
})();
</script>
</body>
</html>

View file

@ -0,0 +1 @@
(function(m,c,u,v,t,f,E){"use strict";function o(){return v.storage.snippets??={},v.storage.snippets}function g(e,r){o()[e.trim()]=r}function y(e){delete o()[e]}const d=3;function b(){const e=c.registerCommand({name:"snippet",description:"Send a saved text snippet",options:[{name:"name",description:"Snippet name",type:d,required:!0}],execute:function(n){const a=n.find(function(p){return p.name==="name"})?.value,s=a?o()[a]:void 0;if(!s){u.showToast(`No snippet named "${a}"`,void 0);return}return{content:s}}}),r=c.registerCommand({name:"snippet-save",description:"Save a text snippet",options:[{name:"name",description:"Snippet name",type:d,required:!0},{name:"text",description:"Snippet content",type:d,required:!0}],execute:function(n){const a=n.find(function(p){return p.name==="name"})?.value,s=n.find(function(p){return p.name==="text"})?.value;!a||!s||(g(a,s),u.showToast(`Saved snippet "${a}"`,void 0))}}),i=c.registerCommand({name:"snippet-delete",description:"Delete a saved text snippet",options:[{name:"name",description:"Snippet name",type:d,required:!0}],execute:function(n){const a=n.find(function(s){return s.name==="name"})?.value;a&&(y(a),u.showToast(`Deleted snippet "${a}"`,void 0))}}),l=c.registerCommand({name:"snippet-list",description:"List your saved snippet names",options:[],execute:function(){const n=Object.keys(o());u.showToast(n.length?n.join(", "):"No snippets saved yet",void 0)}});return[e,r,i,l]}const{ScrollView:w,View:T,TouchableOpacity:C}=t.ReactNative,{FormSection:h,FormRow:F,FormInput:S,FormText:R}=E.Forms;function $(){const[e,r]=t.React.useState(""),[i,l]=t.React.useState(""),n=!!e.trim()&&!!i.trim();return t.React.createElement(T,{style:{paddingHorizontal:16,paddingBottom:12}},t.React.createElement(S,{title:"Name",placeholder:"e.g. rules",value:e,onChange:r}),t.React.createElement(S,{title:"Text",placeholder:"What /snippet should send",value:i,onChange:l,multiline:!0}),t.React.createElement(C,{disabled:!n,onPress:function(){g(e.trim(),i),r(""),l("")},style:{marginTop:8,backgroundColor:"#5865F2",borderRadius:8,padding:10,alignItems:"center",opacity:n?1:.5}},t.React.createElement(R,{style:{color:"white"}},"Save snippet")))}function N(){f.useProxy(v.storage);const e=o();f.useProxy(e);const r=Object.keys(e);return t.React.createElement(w,{style:{flex:1}},t.React.createElement(h,{title:"Add a snippet"},t.React.createElement($,null)),t.React.createElement(h,{title:"Saved snippets"},r.length===0&&t.React.createElement(R,{style:{marginHorizontal:16,marginVertical:8}},"None yet. Add one above, then send it anywhere with /snippet name."),r.map(function(i){return t.React.createElement(F,{key:i,label:i,subLabel:`${e[i].slice(0,60)}${e[i].length>60?"\u2026":""} \u2022 Tap to delete`,onPress:function(){return y(i)}})})))}let x=[];var P={onLoad:function(){x=b()},onUnload:function(){return x.forEach(function(e){return e()})},settings:N};return m.default=P,Object.defineProperty(m,"__esModule",{value:!0}),m})({},vendetta.commands,vendetta.ui.toasts,vendetta.plugin,vendetta.metro.common,vendetta.storage,vendetta.ui.components);

View file

@ -0,0 +1 @@
{"name":"Message Snippets","description":"Save reusable text and send it with /snippet <name>. Manage snippets from the plugin settings, or with /snippet-save, /snippet-delete, /snippet-list.","authors":[{"name":"everestmcarthur"}],"main":"index.js","hash":"52df1423fc1e2ed548a6b3160bce59ca996baf0f93a497d62787054bd6a3b9de"}

72
plugins-data.json Normal file
View file

@ -0,0 +1,72 @@
[
{
"id": "pronoun-db",
"name": "PronounDB",
"description": "Shows a user's pronouns (from pronoundb.org) in their profile.",
"authors": [
"everestmcarthur"
],
"category": "Identity",
"status": "revived",
"note": "Previously broken because PronounDB shut down the API it used (HTTP 410). Migrated to PronounDB's current v2 API.",
"installUrl": "https://everestmcarthur.github.io/revenge-plugins/pronoun-db/",
"sourceUrl": "https://github.com/everestmcarthur/revenge-plugins/tree/main/plugins/pronoun-db",
"issueUrl": "https://github.com/everestmcarthur/revenge-plugins/issues/new?title=%5BPronounDB%5D%20"
},
{
"id": "role-color-everywhere",
"name": "RoleColorEverywhere",
"description": "Displays a member's top role color in more places: mentions, the typing indicator, voice channel participant names, member list role headers, and optionally message text.",
"authors": [
"everestmcarthur"
],
"category": "Moderation & Appearance",
"status": "revived",
"note": "Previously broken. Ported from the original source and hardened with the same crash-isolation fix as Staff Tags.",
"installUrl": "https://everestmcarthur.github.io/revenge-plugins/role-color-everywhere/",
"sourceUrl": "https://github.com/everestmcarthur/revenge-plugins/tree/main/plugins/role-color-everywhere",
"issueUrl": "https://github.com/everestmcarthur/revenge-plugins/issues/new?title=%5BRoleColorEverywhere%5D%20"
},
{
"id": "staff-tags",
"name": "Staff Tags",
"description": "Adds customizable tags (OWNER, ADMIN, STAFF, MOD, and more) next to members based on their server permissions. Supports per-tag colors, gradients, custom text, and visibility toggles.",
"authors": [
"everestmcarthur"
],
"category": "Moderation & Appearance",
"status": "rebuilt",
"note": "Previously broken. Rebuilt with per-patch crash isolation, plus new customization: per-tag text, colors, gradients, and visibility.",
"installUrl": "https://everestmcarthur.github.io/revenge-plugins/staff-tags/",
"sourceUrl": "https://github.com/everestmcarthur/revenge-plugins/tree/main/plugins/staff-tags",
"issueUrl": "https://github.com/everestmcarthur/revenge-plugins/issues/new?title=%5BStaff%20Tags%5D%20"
},
{
"id": "message-snippets",
"name": "Message Snippets",
"description": "Save reusable text and send it with /snippet <name>. Manage snippets from the plugin settings, or with /snippet-save, /snippet-delete, /snippet-list.",
"authors": [
"everestmcarthur"
],
"category": "Productivity",
"status": "new",
"note": "Didn't exist in the Revenge/Vendetta plugin ecosystem before.",
"installUrl": "https://everestmcarthur.github.io/revenge-plugins/message-snippets/",
"sourceUrl": "https://github.com/everestmcarthur/revenge-plugins/tree/main/plugins/message-snippets",
"issueUrl": "https://github.com/everestmcarthur/revenge-plugins/issues/new?title=%5BMessage%20Snippets%5D%20"
},
{
"id": "reminders",
"name": "Reminders",
"description": "Set quick reminders with /remind <time> <text>, e.g. /remind 20m Walk the dog. Fires while Discord is running in the foreground or background - it can't wake the app up if it's been fully closed.",
"authors": [
"everestmcarthur"
],
"category": "Productivity",
"status": "new",
"note": "Didn't exist in the Revenge/Vendetta plugin ecosystem before. Only fires while Discord is running.",
"installUrl": "https://everestmcarthur.github.io/revenge-plugins/reminders/",
"sourceUrl": "https://github.com/everestmcarthur/revenge-plugins/tree/main/plugins/reminders",
"issueUrl": "https://github.com/everestmcarthur/revenge-plugins/issues/new?title=%5BReminders%5D%20"
}
]

1
pronoun-db/index.js Normal file
View file

@ -0,0 +1 @@
(function(u,g,f,P,d,o){"use strict";const m={he:"he/him",she:"she/her",they:"they/them",it:"it/its",any:"any",other:"other",ask:"ask",avoid:"avoid, use name"};function w(e){if(e?.length)return e.map(function(t){return m[t]??t}).join(" / ")}const i=new Map,r=new Map;let s=new Set,l;function h(e,t){r.get(e)?.forEach(function(n){return n(t)}),r.delete(e)}async function R(){const e=[...s];if(s=new Set,!!e.length)try{const t=await(await d.safeFetch(`https://pronoundb.org/api/v2/lookup?platform=discord&ids=${e.join(",")}`,{headers:{Accept:"application/json"}})).json();for(const n of e){const a=w(t?.[n]?.sets?.en);i.set(n,a??null),h(n,a)}}catch{for(const t of e)i.set(t,null),h(t,void 0)}}function S(e){return i.get(e)??void 0}function j(e,t){return i.has(e)?(t(i.get(e)??void 0),function(){}):(r.has(e)||r.set(e,new Set),r.get(e).add(t),s.add(e),clearTimeout(l),l=setTimeout(R,150),function(){return r.get(e)?.delete(t)})}const{Text:A}=o.ReactNative,p=f.findByName("UserProfileSection",!1);function E({userId:e}){const[t,n]=o.React.useState(function(){return S(e)});return o.React.useEffect(function(){return j(e,n)},[e]),!t||!p?null:o.React.createElement(p,{title:"Pronouns"},o.React.createElement(A,{style:{fontSize:16}},t))}const y=f.find(function(e){return e?.type?.name==="UserProfile"});function I(){return y?P.after("type",y,function(e,t){try{const n=d.findInReactTree(t,function(c){return Array.isArray(c?.props?.children)&&c.props.children.some(function(T){return T?.type?.name==="UserProfileBio"})})?.props?.children;if(!Array.isArray(n))return;const a=n.find(function(c){return typeof c?.props?.displayProfile?.userId=="string"})?.props?.displayProfile?.userId;if(!a)return;n.unshift(React.createElement(E,{userId:a}))}catch{}}):function(){}}let v=function(){};var $={onLoad:function(){try{v=I()}catch(e){g.logger.error(`[PronounDB] Failed to apply the profile patch: ${e}`)}},onUnload:function(){return v()}};return u.default=$,Object.defineProperty(u,"__esModule",{value:!0}),u})({},vendetta,vendetta.metro,vendetta.patcher,vendetta.utils,vendetta.metro.common);

1
pronoun-db/manifest.json Normal file
View file

@ -0,0 +1 @@
{"name":"PronounDB","description":"Shows a user's pronouns (from pronoundb.org) in their profile.","authors":[{"name":"everestmcarthur"}],"main":"index.js","vendetta":{"icon":"ic_group"},"hash":"ac7d15900334016be2f13c94a4331eba31d7bb8bebdb46a1dcae5e259cb12558"}

1
reminders/index.js Normal file
View file

@ -0,0 +1 @@
(function(a,v,d,c,p,w,s,y){"use strict";const R={s:1e3,sec:1e3,secs:1e3,second:1e3,seconds:1e3,m:6e4,min:6e4,mins:6e4,minute:6e4,minutes:6e4,h:36e5,hr:36e5,hrs:36e5,hour:36e5,hours:36e5,d:864e5,day:864e5,days:864e5,w:6048e5,week:6048e5,weeks:6048e5};function $(t){const e=t.trim().toLowerCase().match(/^(\d+(?:\.\d+)?)\s*([a-z]+)$/);if(!e)return;const n=Number(e[1]),r=R[e[2]];if(!(!r||!Number.isFinite(n)||n<=0))return Math.round(n*r)}function o(){return c.storage.reminders??=[],c.storage.reminders}function x(t,e){o().push({id:`${Date.now()}-${Math.random().toString(36).slice(2,8)}`,dueAt:Date.now()+e,text:t})}function m(t){const e=o(),n=e.findIndex(function(r){return r.id===t});n!==-1&&e.splice(n,1)}function b(t){try{p.showConfirmationAlert({title:"\u23F0 Reminder",content:t.text,confirmText:"Got it"})}catch{d.showToast(`\u23F0 ${t.text}`,void 0)}}let i;function k(){l(),i=setInterval(function(){const t=Date.now(),e=o().filter(function(n){return n.dueAt<=t});e.length&&e.forEach(function(n){b(n),m(n.id)})},15e3)}function l(){i&&clearInterval(i),i=void 0}const f=3;function E(){return[v.registerCommand({name:"remind",description:"Set a reminder, e.g. /remind 20m Walk the dog",options:[{name:"in",description:"e.g. 10m, 2h, 1d",type:f,required:!0},{name:"text",description:"What to remind you about",type:f,required:!0}],execute:function(t){const e=t.find(function(u){return u.name==="in"})?.value,n=t.find(function(u){return u.name==="text"})?.value,r=e?$(e):void 0;if(!r||!n){d.showToast(`Couldn't parse "${e}" - try something like 10m, 2h, or 1d`,void 0);return}x(n,r),d.showToast(`Reminder set for ${e} from now`,void 0)}})]}const{ScrollView:S,View:F}=w.ReactNative,{FormSection:D,FormRow:M,FormText:h}=y.Forms;function T(t){const e=t-Date.now();if(e<=0)return"due now";const n=Math.round(e/6e4);if(n<60)return`in ${n}m`;const r=Math.round(n/60);return r<24?`in ${r}h`:`in ${Math.round(r/24)}d`}function P(){s.useProxy(c.storage);const t=o();return s.useProxy(t),React.createElement(S,{style:{flex:1}},React.createElement(D,{title:"Pending reminders"},t.length===0&&React.createElement(h,{style:{marginHorizontal:16,marginVertical:8}},'None yet. Set one from any chat with /remind, e.g. "/remind 20m Walk the dog".'),t.map(function(e){return React.createElement(M,{key:e.id,label:e.text,subLabel:`${T(e.dueAt)} \u2022 Tap to cancel`,onPress:function(){return m(e.id)}})})),React.createElement(F,{style:{paddingHorizontal:16,paddingVertical:8}},React.createElement(h,null,"Reminders fire while Discord is open (foreground or background) - they can't wake the app up from fully closed, since that needs a native OS-level notification this plugin doesn't have access to.")))}let g=[];var A={onLoad:function(){g=E(),k()},onUnload:function(){g.forEach(function(t){return t()}),l()},settings:P};return a.default=A,Object.defineProperty(a,"__esModule",{value:!0}),a})({},vendetta.commands,vendetta.ui.toasts,vendetta.plugin,vendetta.ui.alerts,vendetta.metro.common,vendetta.storage,vendetta.ui.components);

1
reminders/manifest.json Normal file
View file

@ -0,0 +1 @@
{"name":"Reminders","description":"Set quick reminders with /remind <time> <text>, e.g. /remind 20m Walk the dog. Fires while Discord is running in the foreground or background - it can't wake the app up if it's been fully closed.","authors":[{"name":"everestmcarthur"}],"main":"index.js","hash":"930b9e9471744c812a5e0c2477f28a463d97a5cc7467987b4044fe77069d6f40"}

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1 @@
{"name":"RoleColorEverywhere","description":"Displays a member's top role color in more places: mentions, the typing indicator, voice channel participant names, member list role headers, and optionally message text.","authors":[{"name":"everestmcarthur"}],"main":"index.js","vendetta":{"icon":"ic_theme_24px"},"hash":"05ccf2fccc961caa8c38535146fff17e0eaf988abb98c7661dc5f20390bfc1b0"}