Move to rp.jarviscli.dev with real per-plugin pages
This commit is contained in:
parent
6af091940f
commit
37ceb8e424
9 changed files with 218 additions and 23 deletions
53
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
53
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
|
|
@ -0,0 +1,53 @@
|
||||||
|
name: Bug report
|
||||||
|
description: Something in a plugin is broken or behaving wrong
|
||||||
|
labels: ["bug"]
|
||||||
|
body:
|
||||||
|
- type: dropdown
|
||||||
|
id: plugin
|
||||||
|
attributes:
|
||||||
|
label: Which plugin?
|
||||||
|
options:
|
||||||
|
- Staff Tags
|
||||||
|
- RoleColorEverywhere
|
||||||
|
- PronounDB
|
||||||
|
- Message Snippets
|
||||||
|
- Reminders
|
||||||
|
- Not sure / something else
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: what-happened
|
||||||
|
attributes:
|
||||||
|
label: What happened?
|
||||||
|
description: What did you expect, and what did you actually get?
|
||||||
|
placeholder: "I tried /snippet welcome and nothing was sent to the channel."
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: repro
|
||||||
|
attributes:
|
||||||
|
label: Steps to reproduce
|
||||||
|
placeholder: |
|
||||||
|
1. Enable the plugin
|
||||||
|
2. Run /snippet welcome
|
||||||
|
3. ...
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
|
|
||||||
|
- type: input
|
||||||
|
id: discord-version
|
||||||
|
attributes:
|
||||||
|
label: Discord app version (Settings → About)
|
||||||
|
placeholder: "e.g. 338.4"
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: logs
|
||||||
|
attributes:
|
||||||
|
label: Anything in the Revenge debugger/logs?
|
||||||
|
description: Settings → General → Debugger, if you have it enabled
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
5
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
5
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
blank_issues_enabled: false
|
||||||
|
contact_links:
|
||||||
|
- name: Core Revenge app issue (not a plugin)
|
||||||
|
url: https://github.com/revenge-mod/revenge-bundle/issues
|
||||||
|
about: If the problem is with Revenge itself rather than one of these plugins, report it there instead.
|
||||||
29
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
Normal file
29
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
name: Feature request / new plugin idea
|
||||||
|
description: Something you want added to an existing plugin, or a new plugin entirely
|
||||||
|
labels: ["enhancement"]
|
||||||
|
body:
|
||||||
|
- type: dropdown
|
||||||
|
id: kind
|
||||||
|
attributes:
|
||||||
|
label: What kind of request is this?
|
||||||
|
options:
|
||||||
|
- New feature for an existing plugin
|
||||||
|
- A brand new plugin idea
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: input
|
||||||
|
id: plugin
|
||||||
|
attributes:
|
||||||
|
label: Which plugin? (leave blank if this is a new plugin idea)
|
||||||
|
placeholder: "e.g. Staff Tags"
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: description
|
||||||
|
attributes:
|
||||||
|
label: What do you want, and why?
|
||||||
|
description: The more concrete, the better - what would you actually do with it?
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
55
.github/ISSUE_TEMPLATE/plugin_broken.yml
vendored
Normal file
55
.github/ISSUE_TEMPLATE/plugin_broken.yml
vendored
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
name: A plugin stopped working after a Discord update
|
||||||
|
description: The most common failure mode here - Discord renamed/removed something a plugin depends on
|
||||||
|
labels: ["bug", "discord-update"]
|
||||||
|
body:
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |
|
||||||
|
Discord's internals change without notice, and plugins in this ecosystem patch those internals
|
||||||
|
directly - this is the single most common way something breaks here. Reports like this are
|
||||||
|
genuinely useful, thank you.
|
||||||
|
|
||||||
|
- type: dropdown
|
||||||
|
id: plugin
|
||||||
|
attributes:
|
||||||
|
label: Which plugin?
|
||||||
|
options:
|
||||||
|
- Staff Tags
|
||||||
|
- RoleColorEverywhere
|
||||||
|
- PronounDB
|
||||||
|
- Message Snippets
|
||||||
|
- Reminders
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: dropdown
|
||||||
|
id: surface
|
||||||
|
attributes:
|
||||||
|
label: What stopped showing up / working?
|
||||||
|
description: Pick whichever's closest - helps narrow down which patch broke
|
||||||
|
options:
|
||||||
|
- Chat messages
|
||||||
|
- Member list
|
||||||
|
- Profile popout
|
||||||
|
- Channel header
|
||||||
|
- Typing indicator
|
||||||
|
- Voice channel
|
||||||
|
- A slash command
|
||||||
|
- Not sure
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
|
|
||||||
|
- type: input
|
||||||
|
id: discord-version
|
||||||
|
attributes:
|
||||||
|
label: Discord app version (Settings → About)
|
||||||
|
placeholder: "e.g. 338.4"
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: worked-before
|
||||||
|
attributes:
|
||||||
|
label: Did this work before, and if so, roughly when did it stop?
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
36
README.md
36
README.md
|
|
@ -2,11 +2,17 @@
|
||||||
|
|
||||||
A collection of plugins for [Revenge](https://github.com/revenge-mod/revenge-bundle), the Discord Android client mod.
|
A collection of plugins for [Revenge](https://github.com/revenge-mod/revenge-bundle), the Discord Android client mod.
|
||||||
|
|
||||||
|
**Browse them at [rp.jarviscli.dev](https://rp.jarviscli.dev)** - searchable, with a full detail page per plugin.
|
||||||
|
|
||||||
## Installing a plugin
|
## Installing a plugin
|
||||||
|
|
||||||
1. Open Discord with Revenge installed, go to **Settings → Plugins**.
|
Each plugin has two URLs:
|
||||||
2. Tap the `+` button and paste the plugin's install link (see below).
|
|
||||||
3. Enable it.
|
- `rp.jarviscli.dev/<plugin>/` - a real page describing the plugin (features, commands, how it works)
|
||||||
|
- `rp.jarviscli.dev/<plugin>/install/` - the actual install link you paste into Revenge
|
||||||
|
|
||||||
|
To install: open Discord with Revenge installed, go to **Settings → Plugins**, tap `+`, and paste the
|
||||||
|
`/install/` link.
|
||||||
|
|
||||||
## Plugins
|
## Plugins
|
||||||
|
|
||||||
|
|
@ -14,16 +20,16 @@ A collection of plugins for [Revenge](https://github.com/revenge-mod/revenge-bun
|
||||||
|
|
||||||
| Plugin | Status | Description | Install link |
|
| Plugin | Status | Description | Install link |
|
||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
| Staff Tags | Rebuilt | OWNER/ADMIN/STAFF/MOD-style tags next to members, computed from real server permissions. Per-tag text, colors, gradients, and visibility. | `https://everestmcarthur.github.io/revenge-plugins/staff-tags/` |
|
| Staff Tags | Rebuilt | OWNER/ADMIN/STAFF/MOD-style tags next to members, computed from real server permissions. Per-tag text, colors, gradients, and visibility. | `https://rp.jarviscli.dev/staff-tags/install/` |
|
||||||
| RoleColorEverywhere | Revived | A member's top role color shown in mentions, the typing indicator, voice channel names, member list role headers, and optionally message text. | `https://everestmcarthur.github.io/revenge-plugins/role-color-everywhere/` |
|
| RoleColorEverywhere | Revived | A member's top role color shown in mentions, the typing indicator, voice channel names, member list role headers, and optionally message text. | `https://rp.jarviscli.dev/role-color-everywhere/install/` |
|
||||||
| PronounDB | Revived | Shows a user's pronouns in their profile, if they've set them at pronoundb.org (nothing to configure in the plugin itself). | `https://everestmcarthur.github.io/revenge-plugins/pronoun-db/` |
|
| PronounDB | Revived | Shows a user's pronouns in their profile, if they've set them at pronoundb.org (nothing to configure in the plugin itself). | `https://rp.jarviscli.dev/pronoun-db/install/` |
|
||||||
|
|
||||||
### Productivity
|
### Productivity
|
||||||
|
|
||||||
| Plugin | Status | Description | Install link |
|
| Plugin | Status | Description | Install link |
|
||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
| Message Snippets | New | Save reusable text and send it with `/snippet <name>`. Manage snippets in-app or with `/snippet-save`, `/snippet-delete`, `/snippet-list`. | `https://everestmcarthur.github.io/revenge-plugins/message-snippets/` |
|
| Message Snippets | New | Save reusable text and send it with `/snippet <name>`. Manage snippets in-app or with `/snippet-save`, `/snippet-delete`, `/snippet-list`. | `https://rp.jarviscli.dev/message-snippets/install/` |
|
||||||
| Reminders | New | `/remind 20m Walk the dog` - fires while Discord is running. Can't wake the app from fully closed (no native notification access from a JS plugin). | `https://everestmcarthur.github.io/revenge-plugins/reminders/` |
|
| Reminders | New | `/remind 20m Walk the dog` - fires while Discord is running. Can't wake the app from fully closed (no native notification access from a JS plugin). | `https://rp.jarviscli.dev/reminders/install/` |
|
||||||
|
|
||||||
"Revived" means the plugin previously existed elsewhere, stopped working after a Discord/API update, and has been rebuilt here.
|
"Revived" means the plugin previously existed elsewhere, stopped working after a Discord/API update, and has been rebuilt here.
|
||||||
"Rebuilt" means it's a from-scratch reimplementation of a previously-broken plugin with expanded features. "New" means
|
"Rebuilt" means it's a from-scratch reimplementation of a previously-broken plugin with expanded features. "New" means
|
||||||
|
|
@ -58,7 +64,19 @@ npm install
|
||||||
npm run build
|
npm run build
|
||||||
```
|
```
|
||||||
|
|
||||||
Output is written to `dist/<plugin>/`.
|
This runs both `build.mjs` (compiles every plugin in `plugins/*` into `dist/<id>/install/`) and
|
||||||
|
`scripts/generate-site.mjs` (builds `dist/plugins-data.json` from those manifests + `site/meta.json`,
|
||||||
|
and writes the website - a homepage at `dist/index.html` and a real page per plugin at `dist/<id>/index.html`).
|
||||||
|
|
||||||
|
## Releasing an update
|
||||||
|
|
||||||
|
1. Edit a plugin under `plugins/<id>/src/`.
|
||||||
|
2. `npm run build` locally and sanity-check the output in `dist/`.
|
||||||
|
3. `git add -A && git commit -m "..." && git push origin main`.
|
||||||
|
4. GitHub Actions rebuilds and redeploys to `rp.jarviscli.dev` automatically (usually under a minute) -
|
||||||
|
check progress at the repo's **Actions** tab.
|
||||||
|
|
||||||
|
There's no manual deploy step - anything merged to `main` goes live.
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -60,9 +60,11 @@ const plugins = [
|
||||||
esbuild({ minify: true }),
|
esbuild({ minify: true }),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// Each plugin's actual install target (manifest.json + index.js) lives at /<id>/install/, so that
|
||||||
|
// /<id>/ itself is free to be a real, bookmarkable HTML page describing the plugin (see generate-site.mjs).
|
||||||
for (const plug of await readdir("./plugins")) {
|
for (const plug of await readdir("./plugins")) {
|
||||||
const manifest = JSON.parse(await readFile(`./plugins/${plug}/manifest.json`));
|
const manifest = JSON.parse(await readFile(`./plugins/${plug}/manifest.json`));
|
||||||
const outPath = `./dist/${plug}/index.js`;
|
const outPath = `./dist/${plug}/install/index.js`;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const bundle = await rollup({
|
const bundle = await rollup({
|
||||||
|
|
@ -90,7 +92,7 @@ for (const plug of await readdir("./plugins")) {
|
||||||
const toHash = await readFile(outPath);
|
const toHash = await readFile(outPath);
|
||||||
manifest.hash = createHash("sha256").update(toHash).digest("hex");
|
manifest.hash = createHash("sha256").update(toHash).digest("hex");
|
||||||
manifest.main = "index.js";
|
manifest.main = "index.js";
|
||||||
await writeFile(`./dist/${plug}/manifest.json`, JSON.stringify(manifest));
|
await writeFile(`./dist/${plug}/install/manifest.json`, JSON.stringify(manifest));
|
||||||
|
|
||||||
console.log(`Successfully built ${manifest.name}!`);
|
console.log(`Successfully built ${manifest.name}!`);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { readFile, writeFile, readdir, copyFile, stat } from "fs/promises";
|
import { readFile, writeFile, readdir, copyFile, stat } from "fs/promises";
|
||||||
|
|
||||||
const PAGES_BASE = "https://everestmcarthur.github.io/revenge-plugins";
|
const PAGES_BASE = "https://rp.jarviscli.dev";
|
||||||
const REPO_BASE = "https://github.com/everestmcarthur/revenge-plugins";
|
const REPO_BASE = "https://github.com/everestmcarthur/revenge-plugins";
|
||||||
|
|
||||||
const meta = JSON.parse(await readFile("./site/meta.json", "utf8"));
|
const meta = JSON.parse(await readFile("./site/meta.json", "utf8"));
|
||||||
|
|
@ -12,7 +12,7 @@ for (const id of await readdir("./dist")) {
|
||||||
|
|
||||||
let manifest;
|
let manifest;
|
||||||
try {
|
try {
|
||||||
manifest = JSON.parse(await readFile(`${dir}/manifest.json`, "utf8"));
|
manifest = JSON.parse(await readFile(`${dir}/install/manifest.json`, "utf8"));
|
||||||
} catch {
|
} catch {
|
||||||
continue; // not a plugin output directory
|
continue; // not a plugin output directory
|
||||||
}
|
}
|
||||||
|
|
@ -33,7 +33,8 @@ for (const id of await readdir("./dist")) {
|
||||||
features: info.features ?? [],
|
features: info.features ?? [],
|
||||||
commands: info.commands ?? [],
|
commands: info.commands ?? [],
|
||||||
limitations: info.limitations ?? "",
|
limitations: info.limitations ?? "",
|
||||||
installUrl: `${PAGES_BASE}/${id}/`,
|
pageUrl: `${PAGES_BASE}/${id}/`,
|
||||||
|
installUrl: `${PAGES_BASE}/${id}/install/`,
|
||||||
sourceUrl: `${REPO_BASE}/tree/main/plugins/${id}`,
|
sourceUrl: `${REPO_BASE}/tree/main/plugins/${id}`,
|
||||||
issueUrl: `${REPO_BASE}/issues/new?title=${encodeURIComponent(`[${manifest.name}] `)}`
|
issueUrl: `${REPO_BASE}/issues/new?title=${encodeURIComponent(`[${manifest.name}] `)}`
|
||||||
});
|
});
|
||||||
|
|
@ -44,5 +45,12 @@ plugins.sort((a, b) => a.category.localeCompare(b.category) || a.name.localeComp
|
||||||
await writeFile("./dist/plugins-data.json", JSON.stringify(plugins, null, 2));
|
await writeFile("./dist/plugins-data.json", JSON.stringify(plugins, null, 2));
|
||||||
await copyFile("./site/index.html", "./dist/index.html");
|
await copyFile("./site/index.html", "./dist/index.html");
|
||||||
await copyFile("./site/index.html", "./dist/404.html");
|
await copyFile("./site/index.html", "./dist/404.html");
|
||||||
|
await copyFile("./site/CNAME", "./dist/CNAME");
|
||||||
|
|
||||||
|
// Each plugin gets its own real, bookmarkable page at /<id>/ (not just a hash route) - it's the
|
||||||
|
// same SPA shell, which reads location.pathname on boot to know which plugin to show directly.
|
||||||
|
for (const p of plugins) {
|
||||||
|
await copyFile("./site/index.html", `./dist/${p.id}/index.html`);
|
||||||
|
}
|
||||||
|
|
||||||
console.log(`Generated site data for ${plugins.length} plugin(s).`);
|
console.log(`Generated site data for ${plugins.length} plugin(s).`);
|
||||||
|
|
|
||||||
1
site/CNAME
Normal file
1
site/CNAME
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
rp.jarviscli.dev
|
||||||
|
|
@ -96,6 +96,12 @@
|
||||||
from { transform: translate3d(0,0,0) scale(1); }
|
from { transform: translate3d(0,0,0) scale(1); }
|
||||||
to { transform: translate3d(-2%, 2%, 0) scale(1.08); }
|
to { transform: translate3d(-2%, 2%, 0) scale(1.08); }
|
||||||
}
|
}
|
||||||
|
.hero-spotlight {
|
||||||
|
position: absolute; inset: 0; z-index: 0; pointer-events: none; opacity: 0;
|
||||||
|
background: radial-gradient(280px circle at var(--sx, 50%) var(--sy, 50%), color-mix(in srgb, var(--accent) 22%, transparent), transparent 70%);
|
||||||
|
transition: opacity 0.25s ease;
|
||||||
|
}
|
||||||
|
.hero:hover .hero-spotlight { opacity: 1; }
|
||||||
.hero-inner { position: relative; z-index: 1; }
|
.hero-inner { position: relative; z-index: 1; }
|
||||||
.mark {
|
.mark {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
|
|
@ -294,6 +300,7 @@
|
||||||
|
|
||||||
<header class="hero" id="hero">
|
<header class="hero" id="hero">
|
||||||
<div class="hero-mesh" aria-hidden="true"></div>
|
<div class="hero-mesh" aria-hidden="true"></div>
|
||||||
|
<div class="hero-spotlight" id="heroSpotlight" aria-hidden="true"></div>
|
||||||
<div class="wrap hero-inner">
|
<div class="wrap hero-inner">
|
||||||
<div class="mark">
|
<div class="mark">
|
||||||
<svg viewBox="0 0 32 32" fill="none"><path d="M9 12l7-5 7 5v9l-7 5-7-5z" stroke="currentColor" stroke-width="2"/><circle cx="16" cy="16" r="3" fill="currentColor"/></svg>
|
<svg viewBox="0 0 32 32" fill="none"><path d="M9 12l7-5 7 5v9l-7 5-7-5z" stroke="currentColor" stroke-width="2"/><circle cx="16" cy="16" r="3" fill="currentColor"/></svg>
|
||||||
|
|
@ -471,7 +478,7 @@
|
||||||
'<div class="cta">View details →</div>';
|
'<div class="cta">View details →</div>';
|
||||||
|
|
||||||
card.addEventListener("click", function () {
|
card.addEventListener("click", function () {
|
||||||
location.hash = "#/plugin/" + p.id;
|
navigateToPlugin(p.id);
|
||||||
});
|
});
|
||||||
|
|
||||||
grid.appendChild(card);
|
grid.appendChild(card);
|
||||||
|
|
@ -508,6 +515,13 @@
|
||||||
controlsEl.classList.toggle("stuck", window.scrollY > 8);
|
controlsEl.classList.toggle("stuck", window.scrollY > 8);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var heroSpotlight = document.getElementById("heroSpotlight");
|
||||||
|
heroEl.addEventListener("mousemove", function (e) {
|
||||||
|
var rect = heroEl.getBoundingClientRect();
|
||||||
|
heroSpotlight.style.setProperty("--sx", (e.clientX - rect.left) + "px");
|
||||||
|
heroSpotlight.style.setProperty("--sy", (e.clientY - rect.top) + "px");
|
||||||
|
});
|
||||||
|
|
||||||
/* ---------- Detail view ---------- */
|
/* ---------- Detail view ---------- */
|
||||||
|
|
||||||
function renderDetail(p) {
|
function renderDetail(p) {
|
||||||
|
|
@ -571,7 +585,7 @@
|
||||||
actions.appendChild(issueLink);
|
actions.appendChild(issueLink);
|
||||||
|
|
||||||
document.getElementById("backLink").addEventListener("click", function () {
|
document.getElementById("backLink").addEventListener("click", function () {
|
||||||
history.pushState(null, "", location.pathname + location.search);
|
history.pushState(null, "", "/");
|
||||||
showGrid();
|
showGrid();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -597,16 +611,26 @@
|
||||||
document.title = "revenge-plugins";
|
document.title = "revenge-plugins";
|
||||||
}
|
}
|
||||||
|
|
||||||
function routeFromHash() {
|
/**
|
||||||
var match = location.hash.match(/^#\/plugin\/([\w-]+)/);
|
* Each plugin has a real static page at /<id>/ (a copy of this same file), so a direct visit or
|
||||||
if (match) {
|
* refresh works without any server-side routing - this just avoids a full reload when navigating
|
||||||
|
* from within an already-loaded page.
|
||||||
|
*/
|
||||||
|
function navigateToPlugin(id) {
|
||||||
|
history.pushState(null, "", "/" + id + "/");
|
||||||
|
showDetail(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
function routeFromLocation() {
|
||||||
|
var match = location.pathname.match(/^\/([\w-]+)\/?$/);
|
||||||
|
if (match && match[1]) {
|
||||||
showDetail(match[1]);
|
showDetail(match[1]);
|
||||||
} else {
|
} else {
|
||||||
showGrid();
|
showGrid();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
window.addEventListener("hashchange", routeFromHash);
|
window.addEventListener("popstate", routeFromLocation);
|
||||||
|
|
||||||
/* ---------- Command palette ---------- */
|
/* ---------- Command palette ---------- */
|
||||||
|
|
||||||
|
|
@ -659,7 +683,7 @@
|
||||||
var plugin = paletteMatches[i];
|
var plugin = paletteMatches[i];
|
||||||
if (!plugin) return;
|
if (!plugin) return;
|
||||||
closePalette();
|
closePalette();
|
||||||
location.hash = "#/plugin/" + plugin.id;
|
navigateToPlugin(plugin.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
paletteInput.addEventListener("input", function (e) { renderPalette(e.target.value); });
|
paletteInput.addEventListener("input", function (e) { renderPalette(e.target.value); });
|
||||||
|
|
@ -692,14 +716,14 @@
|
||||||
|
|
||||||
/* ---------- Boot ---------- */
|
/* ---------- Boot ---------- */
|
||||||
|
|
||||||
fetch("https://everestmcarthur.github.io/revenge-plugins/plugins-data.json")
|
fetch("https://rp.jarviscli.dev/plugins-data.json")
|
||||||
.then(function (r) { return r.json(); })
|
.then(function (r) { return r.json(); })
|
||||||
.then(function (data) {
|
.then(function (data) {
|
||||||
state.plugins = data;
|
state.plugins = data;
|
||||||
renderStats();
|
renderStats();
|
||||||
renderChips();
|
renderChips();
|
||||||
render();
|
render();
|
||||||
routeFromHash();
|
routeFromLocation();
|
||||||
})
|
})
|
||||||
.catch(function () {
|
.catch(function () {
|
||||||
count.textContent = "";
|
count.textContent = "";
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue