From 37ceb8e4244dc788812a7be856cf2e2f4f665482 Mon Sep 17 00:00:00 2001 From: everestmcarthur <280397636+everestmcarthur@users.noreply.github.com> Date: Sat, 1 Aug 2026 11:00:23 -0400 Subject: [PATCH] Move to rp.jarviscli.dev with real per-plugin pages --- .github/ISSUE_TEMPLATE/bug_report.yml | 53 +++++++++++++++++++++ .github/ISSUE_TEMPLATE/config.yml | 5 ++ .github/ISSUE_TEMPLATE/feature_request.yml | 29 ++++++++++++ .github/ISSUE_TEMPLATE/plugin_broken.yml | 55 ++++++++++++++++++++++ README.md | 36 ++++++++++---- build.mjs | 6 ++- scripts/generate-site.mjs | 14 ++++-- site/CNAME | 1 + site/index.html | 42 +++++++++++++---- 9 files changed, 218 insertions(+), 23 deletions(-) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.yml create mode 100644 .github/ISSUE_TEMPLATE/config.yml create mode 100644 .github/ISSUE_TEMPLATE/feature_request.yml create mode 100644 .github/ISSUE_TEMPLATE/plugin_broken.yml create mode 100644 site/CNAME diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 0000000..70c001c --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -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 diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..52ff1d4 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -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. diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 0000000..2d32188 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -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 diff --git a/.github/ISSUE_TEMPLATE/plugin_broken.yml b/.github/ISSUE_TEMPLATE/plugin_broken.yml new file mode 100644 index 0000000..24e0f79 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/plugin_broken.yml @@ -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 diff --git a/README.md b/README.md index 713b749..a7be491 100644 --- a/README.md +++ b/README.md @@ -2,11 +2,17 @@ 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 -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. +Each plugin has two URLs: + +- `rp.jarviscli.dev//` - a real page describing the plugin (features, commands, how it works) +- `rp.jarviscli.dev//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 @@ -14,16 +20,16 @@ A collection of plugins for [Revenge](https://github.com/revenge-mod/revenge-bun | 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/` | -| 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/` | -| 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/` | +| 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://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://rp.jarviscli.dev/pronoun-db/install/` | ### Productivity | Plugin | Status | Description | Install link | | --- | --- | --- | --- | -| Message Snippets | New | Save reusable text and send it with `/snippet `. Manage snippets in-app or with `/snippet-save`, `/snippet-delete`, `/snippet-list`. | `https://everestmcarthur.github.io/revenge-plugins/message-snippets/` | -| 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/` | +| Message Snippets | New | Save reusable text and send it with `/snippet `. 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://rp.jarviscli.dev/reminders/install/` | "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 @@ -58,7 +64,19 @@ npm install npm run build ``` -Output is written to `dist//`. +This runs both `build.mjs` (compiles every plugin in `plugins/*` into `dist//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//index.html`). + +## Releasing an update + +1. Edit a plugin under `plugins//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 diff --git a/build.mjs b/build.mjs index 3aaebb1..ceebed9 100644 --- a/build.mjs +++ b/build.mjs @@ -60,9 +60,11 @@ const plugins = [ esbuild({ minify: true }), ]; +// Each plugin's actual install target (manifest.json + index.js) lives at //install/, so that +// // itself is free to be a real, bookmarkable HTML page describing the plugin (see generate-site.mjs). for (const plug of await readdir("./plugins")) { const manifest = JSON.parse(await readFile(`./plugins/${plug}/manifest.json`)); - const outPath = `./dist/${plug}/index.js`; + const outPath = `./dist/${plug}/install/index.js`; try { const bundle = await rollup({ @@ -90,7 +92,7 @@ for (const plug of await readdir("./plugins")) { const toHash = await readFile(outPath); manifest.hash = createHash("sha256").update(toHash).digest("hex"); 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}!`); } catch (e) { diff --git a/scripts/generate-site.mjs b/scripts/generate-site.mjs index 19efaed..2ccbf68 100644 --- a/scripts/generate-site.mjs +++ b/scripts/generate-site.mjs @@ -1,6 +1,6 @@ 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 meta = JSON.parse(await readFile("./site/meta.json", "utf8")); @@ -12,7 +12,7 @@ for (const id of await readdir("./dist")) { let manifest; try { - manifest = JSON.parse(await readFile(`${dir}/manifest.json`, "utf8")); + manifest = JSON.parse(await readFile(`${dir}/install/manifest.json`, "utf8")); } catch { continue; // not a plugin output directory } @@ -33,7 +33,8 @@ for (const id of await readdir("./dist")) { features: info.features ?? [], commands: info.commands ?? [], limitations: info.limitations ?? "", - installUrl: `${PAGES_BASE}/${id}/`, + pageUrl: `${PAGES_BASE}/${id}/`, + installUrl: `${PAGES_BASE}/${id}/install/`, sourceUrl: `${REPO_BASE}/tree/main/plugins/${id}`, 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 copyFile("./site/index.html", "./dist/index.html"); await copyFile("./site/index.html", "./dist/404.html"); +await copyFile("./site/CNAME", "./dist/CNAME"); + +// Each plugin gets its own real, bookmarkable page at // (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).`); diff --git a/site/CNAME b/site/CNAME new file mode 100644 index 0000000..54455a4 --- /dev/null +++ b/site/CNAME @@ -0,0 +1 @@ +rp.jarviscli.dev diff --git a/site/index.html b/site/index.html index 2702a32..d3dce5e 100644 --- a/site/index.html +++ b/site/index.html @@ -96,6 +96,12 @@ from { transform: translate3d(0,0,0) scale(1); } 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; } .mark { display: inline-flex; @@ -294,6 +300,7 @@
+
@@ -471,7 +478,7 @@ '
View details →
'; card.addEventListener("click", function () { - location.hash = "#/plugin/" + p.id; + navigateToPlugin(p.id); }); grid.appendChild(card); @@ -508,6 +515,13 @@ 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 ---------- */ function renderDetail(p) { @@ -571,7 +585,7 @@ actions.appendChild(issueLink); document.getElementById("backLink").addEventListener("click", function () { - history.pushState(null, "", location.pathname + location.search); + history.pushState(null, "", "/"); showGrid(); }); } @@ -597,16 +611,26 @@ document.title = "revenge-plugins"; } - function routeFromHash() { - var match = location.hash.match(/^#\/plugin\/([\w-]+)/); - if (match) { + /** + * Each plugin has a real static page at // (a copy of this same file), so a direct visit or + * 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]); } else { showGrid(); } } - window.addEventListener("hashchange", routeFromHash); + window.addEventListener("popstate", routeFromLocation); /* ---------- Command palette ---------- */ @@ -659,7 +683,7 @@ var plugin = paletteMatches[i]; if (!plugin) return; closePalette(); - location.hash = "#/plugin/" + plugin.id; + navigateToPlugin(plugin.id); } paletteInput.addEventListener("input", function (e) { renderPalette(e.target.value); }); @@ -692,14 +716,14 @@ /* ---------- 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 (data) { state.plugins = data; renderStats(); renderChips(); render(); - routeFromHash(); + routeFromLocation(); }) .catch(function () { count.textContent = "";