diff --git a/plugins/message-snippets/src/commands.ts b/plugins/message-snippets/src/commands.ts index 7856dcf..13f795d 100644 --- a/plugins/message-snippets/src/commands.ts +++ b/plugins/message-snippets/src/commands.ts @@ -1,16 +1,22 @@ import { registerCommand } from "@vendetta/commands"; +import { findByProps } from "@vendetta/metro"; import { showToast } from "@vendetta/ui/toasts"; import { getSnippets, saveSnippet, deleteSnippet } from "./lib/snippets"; // Discord slash-command option type for a plain string argument. const STRING = 3; +// Returning a CommandResult object from `execute` and relying on the framework to auto-send it +// turned out to be unreliable in practice - real-world plugins (e.g. InfoCommands) route around it +// by sending the message themselves, so this does the same instead of relying on the return value. +const MessageActions = findByProps("sendMessage", "sendBotMessage"); + export default function loadCommands(): (() => void)[] { const unregisterSend = registerCommand({ name: "snippet", description: "Send a saved text snippet", options: [{ name: "name", description: "Snippet name", type: STRING, required: true }], - execute: (args) => { + execute: (args, ctx) => { const name = args.find((a) => a.name === "name")?.value; const text = name ? getSnippets()[name] : undefined; @@ -19,7 +25,12 @@ export default function loadCommands(): (() => void)[] { return; } - return { content: text }; + if (!MessageActions?.sendMessage) { + showToast("Couldn't send the snippet - message action not found", undefined); + return; + } + + MessageActions.sendMessage(ctx.channel.id, { content: text }); } }); diff --git a/plugins/message-snippets/src/ui/Settings.tsx b/plugins/message-snippets/src/ui/Settings.tsx index 9b5fa56..f1da953 100644 --- a/plugins/message-snippets/src/ui/Settings.tsx +++ b/plugins/message-snippets/src/ui/Settings.tsx @@ -2,6 +2,7 @@ import { React, ReactNative } from "@vendetta/metro/common"; import { useProxy } from "@vendetta/storage"; import { storage } from "@vendetta/plugin"; import { Forms } from "@vendetta/ui/components"; +import { showToast } from "@vendetta/ui/toasts"; import SettingsScaffold from "@shared/ui/SettingsScaffold"; import ListSection from "@shared/ui/ListSection"; import PrimaryButton from "@shared/ui/PrimaryButton"; @@ -25,6 +26,7 @@ function NewSnippetForm() { style={{ marginTop: 8 }} onPress={() => { saveSnippet(name.trim(), text); + showToast(`Saved snippet "${name.trim()}"`, undefined); setName(""); setText(""); }} @@ -51,7 +53,10 @@ export default function Settings() { key: name, label: name, subLabel: `${snippets[name].slice(0, 60)}${snippets[name].length > 60 ? "…" : ""} • Tap to delete`, - onPress: () => deleteSnippet(name) + onPress: () => { + deleteSnippet(name); + showToast(`Deleted snippet "${name}"`, undefined); + } }))} /> diff --git a/plugins/reminders/src/ui/Settings.tsx b/plugins/reminders/src/ui/Settings.tsx index 8a23bc6..f9897ec 100644 --- a/plugins/reminders/src/ui/Settings.tsx +++ b/plugins/reminders/src/ui/Settings.tsx @@ -1,6 +1,7 @@ import { React } from "@vendetta/metro/common"; import { useProxy } from "@vendetta/storage"; import { storage } from "@vendetta/plugin"; +import { showToast } from "@vendetta/ui/toasts"; import SettingsScaffold from "@shared/ui/SettingsScaffold"; import ListSection from "@shared/ui/ListSection"; import NoteBox from "@shared/ui/NoteBox"; @@ -33,7 +34,10 @@ export default function Settings() { key: r.id, label: r.text, subLabel: `${formatRemaining(r.dueAt)} • Tap to cancel`, - onPress: () => removeReminder(r.id) + onPress: () => { + removeReminder(r.id); + showToast("Reminder cancelled", undefined); + } }))} /> diff --git a/scripts/generate-site.mjs b/scripts/generate-site.mjs index cb419fe..19efaed 100644 --- a/scripts/generate-site.mjs +++ b/scripts/generate-site.mjs @@ -26,7 +26,13 @@ for (const id of await readdir("./dist")) { authors: (manifest.authors ?? []).map((a) => a.name), category: info.category ?? "Other", status: info.status ?? "new", + accent: info.accent ?? "#5865f2", + tagline: info.tagline ?? manifest.description, note: info.note ?? "", + howItWorks: info.howItWorks ?? "", + features: info.features ?? [], + commands: info.commands ?? [], + limitations: info.limitations ?? "", installUrl: `${PAGES_BASE}/${id}/`, sourceUrl: `${REPO_BASE}/tree/main/plugins/${id}`, issueUrl: `${REPO_BASE}/issues/new?title=${encodeURIComponent(`[${manifest.name}] `)}` diff --git a/shared/ui/ListSection.tsx b/shared/ui/ListSection.tsx index 13f0ceb..872984e 100644 --- a/shared/ui/ListSection.tsx +++ b/shared/ui/ListSection.tsx @@ -1,7 +1,8 @@ -import { React } from "@vendetta/metro/common"; +import { React, ReactNative } from "@vendetta/metro/common"; import { Forms } from "@vendetta/ui/components"; import NoteBox from "./NoteBox"; +const { Text } = ReactNative; const { FormSection, FormRow } = Forms; export interface ListItem { @@ -11,7 +12,11 @@ export interface ListItem { onPress?: () => void; } -/** A titled section listing tap-able rows, with a friendly note shown in place of an empty list. */ +/** + * A titled section listing tap-able rows, with a friendly note shown in place of an empty list. + * Always pairs onPress with a visible trailing indicator - rows without one have been unreliable + * about actually registering taps in testing. + */ export default function ListSection({ title, items, emptyText }: { title: string; items: ListItem[]; emptyText: string }) { return ( @@ -19,7 +24,13 @@ export default function ListSection({ title, items, emptyText }: { title: string {emptyText} ) : ( items.map((item) => ( - + ×} + /> )) )} diff --git a/site/index.html b/site/index.html index 8eca61a..2702a32 100644 --- a/site/index.html +++ b/site/index.html @@ -5,16 +5,18 @@ revenge-plugins + -
-
-
👊 REVENGE PLUGINS
-

Plugins for Revenge

-

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.

+
+ +
+
+ + Revenge Plugins +
+

Discord, your way.

+

A hand-built collection of plugins for Revenge, the Discord Android client mod - rebuilt from scratch where the old ecosystem broke, and net-new where nothing existed yet.

-
+
- +
+ + ⌘K +
@@ -248,6 +326,8 @@
+
+