Merge remote-tracking branch 'upstream/dev' into dev
This commit is contained in:
commit
002b733f0f
10 changed files with 132 additions and 94 deletions
|
|
@ -9,7 +9,6 @@ code_review:
|
||||||
include_drafts: false
|
include_drafts: false
|
||||||
|
|
||||||
ignore_patterns:
|
ignore_patterns:
|
||||||
- "pnpm-lock.yaml"
|
|
||||||
- "pnpm-workspace.yaml"
|
- "pnpm-workspace.yaml"
|
||||||
- "dist/**"
|
- "dist/**"
|
||||||
- "browser/**"
|
- "browser/**"
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ If a plugin breaks ANY of these, reject the entire PR. These are non-negotiable:
|
||||||
|
|
||||||
1. **No simple slash-command plugins** (e.g. `/cat`). Should be a [user-installable Discord app](https://discord.com/developers/docs/change-log#userinstallable-apps-preview) instead.
|
1. **No simple slash-command plugins** (e.g. `/cat`). Should be a [user-installable Discord app](https://discord.com/developers/docs/change-log#userinstallable-apps-preview) instead.
|
||||||
2. **No simple text replacement plugins.** The built-in TextReplace plugin already covers this.
|
2. **No simple text replacement plugins.** The built-in TextReplace plugin already covers this.
|
||||||
3. **No raw DOM manipulation.** Always use patches and React.
|
3. **No raw DOM manipulation / MutationObserver.** Always use patches and React.
|
||||||
4. **No FakeDeafen or FakeMute.**
|
4. **No FakeDeafen or FakeMute.**
|
||||||
5. **No StereoMic-related plugins.**
|
5. **No StereoMic-related plugins.**
|
||||||
6. **No UI-only hide/redesign plugins.** Use CSS for that. (Negotiable in rare cases.)
|
6. **No UI-only hide/redesign plugins.** Use CSS for that. (Negotiable in rare cases.)
|
||||||
|
|
@ -37,26 +37,13 @@ export default definePlugin({
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
**Settings** must use `definePluginSettings` from `@api/Settings`. Reject inline `options` objects.
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
// GOOD
|
|
||||||
const settings = definePluginSettings({
|
|
||||||
myOption: { type: OptionType.BOOLEAN, description: "Enables the feature.", default: true }
|
|
||||||
});
|
|
||||||
export default definePlugin({ settings, /* ... */ });
|
|
||||||
|
|
||||||
// BAD
|
|
||||||
export default definePlugin({ options: { myOption: { /* ... */ } } });
|
|
||||||
```
|
|
||||||
|
|
||||||
**Prefer declarative APIs** over manual registration:
|
**Prefer declarative APIs** over manual registration:
|
||||||
|
|
||||||
- `flux: { EVENT_NAME(data) {} }` not manual FluxDispatcher subscribe
|
- `flux: { EVENT_NAME(data) {} }` not manual FluxDispatcher subscribe
|
||||||
- `contextMenus: { "nav-id": fn }` not manual addContextMenuPatch
|
- `contextMenus: { "nav-id": fn }` not manual addContextMenuPatch
|
||||||
- `chatBarButton: { render, icon }` not addChatBarButton
|
- `chatBarButton: { render, icon }` not addChatBarButton
|
||||||
- `messagePopoverButton: { render, icon }` not addMessagePopoverButton
|
- `messagePopoverButton: { render, icon }` not addMessagePopoverButton
|
||||||
- `managedStyle` for CSS not manual enableStyle/disableStyle
|
- `managedStyle` for CSS not manual enableStyle/disableStyle in start/stop
|
||||||
|
|
||||||
**Reject deprecated fields:** `renderChatBarButton`, `renderMessagePopoverButton`, `options`
|
**Reject deprecated fields:** `renderChatBarButton`, `renderMessagePopoverButton`, `options`
|
||||||
|
|
||||||
|
|
@ -68,34 +55,33 @@ export default definePlugin({ options: { myOption: { /* ... */ } } });
|
||||||
|
|
||||||
Flag these and suggest the fix:
|
Flag these and suggest the fix:
|
||||||
|
|
||||||
| Bad | Good | Reason |
|
| Bad | Good | Reason |
|
||||||
|-----|------|--------|
|
| ---------------------------------------------------------------- | ------------------------------------------- | ----------------------------------- |
|
||||||
| `value !== null && value !== undefined` | `value` or `isNonNullish(value)` | Verbose |
|
| `value !== null && value !== undefined` | `value` or `value != null` | Verbose |
|
||||||
| `array && array.length > 0` | `array.length` | Redundant check |
|
| `array && array.length > 0` | `array?.length` | Redundant check |
|
||||||
| `settings?.store?.value` | `settings.store.value` | Store is always defined |
|
| `settings?.store?.value` | `settings.store.value` | Store is always defined |
|
||||||
| `value \|\| defaultValue` | `value ?? defaultValue` | `\|\|` falsifies `0`, `""`, `false` |
|
| `value \|\| defaultValue` | `value ?? defaultValue` | `\|\|` falsifies `0`, `""`, `false` |
|
||||||
| `` `${classA} ${classB}` `` | `classes(classA, classB)` | Handles null/false gracefully |
|
| `` `${classA} ${classB}` `` | `classes(classA, classB)` | Handles null/false gracefully |
|
||||||
| `"vc-plugin-class"` hardcoded | `cl("class")` via `classNameFactory` | Consistent, typo-proof |
|
| `"vc-plugin-class"` hardcoded | `cl("class")` via `classNameFactory` | Consistent, typo-proof |
|
||||||
| `console.log/warn` | Remove it | No logging in plugin code |
|
| `console.log/warn` | Remove it | No logging in plugin code |
|
||||||
| `cdn.discordapp.com/avatars/...` | `IconUtils.getUserAvatarURL(user)` | Handles animated, sizing, CDN |
|
| `cdn.discordapp.com/avatars/...` | `IconUtils.getUserAvatarURL(user)` | Handles animated, sizing, CDN |
|
||||||
| `cdn.discordapp.com/icons/...` | `IconUtils.getGuildIconURL(...)` | Same |
|
| `cdn.discordapp.com/icons/...` | `IconUtils.getGuildIconURL(...)` | Same |
|
||||||
| `cdn.discordapp.com/banners/...` | `IconUtils.getUserBannerURL(...)` | Same |
|
| `cdn.discordapp.com/banners/...` | `IconUtils.getUserBannerURL(...)` | Same |
|
||||||
| `cdn.discordapp.com/emojis/...` | `IconUtils.getEmojiURL(...)` | Same |
|
| `cdn.discordapp.com/emojis/...` | `IconUtils.getEmojiURL(...)` | Same |
|
||||||
| `/api/v9/...` or `/users/@me` | `Constants.Endpoints.*` or `RestAPI` | Endpoints change |
|
| `/api/v9/...` or `/users/@me` | `Constants.Endpoints.*` or `RestAPI` | Endpoints change |
|
||||||
| `@api/Styles` for classNameFactory | `@utils/css` | `@api/Styles` is deprecated |
|
| `@api/Styles` for classNameFactory | `@utils/css` | `@api/Styles` is deprecated |
|
||||||
| `any` for Discord objects | Import from `@vencord/discord-types` | Type safety |
|
| `any` for Discord objects | Import from `@vencord/discord-types` | Type safety |
|
||||||
| `as unknown as` casting | Find the correct type | Unsafe |
|
| `as unknown as` casting | Find the correct type | Unsafe |
|
||||||
| `React.memo()` | Remove it | Not needed |
|
| `React.memo()` | Remove it | Not needed |
|
||||||
| `React.cloneElement` / `React.isValidElement` / `React.Children` | Find another approach | Forbidden |
|
| `React.cloneElement` / `React.isValidElement` / `React.Children` | Find another approach | Forbidden |
|
||||||
| `React.lazy(() => import(...))` | `LazyComponent` from `@utils/lazyReact` | Framework-integrated |
|
| `React.lazy(() => import(...))` | `LazyComponent` from `@utils/lazyReact` | Framework-integrated |
|
||||||
| Empty `catch {}` | Handle the error (toast, fallback, rethrow) | Silent failures |
|
| Empty `catch {}` | Handle the error (toast, fallback, rethrow) | Silent failures |
|
||||||
| CSS-only plugins | Must have actual logic/patches | Not allowed |
|
| CSS-only plugins | Must have actual logic/patches | Not allowed |
|
||||||
| Commented-out dead code | Delete it | Git has history |
|
| Commented-out dead code | Delete it | Git has history |
|
||||||
| `document.querySelector(...)` | Use webpack patches | DOM manipulation forbidden |
|
| `document.querySelector(...)` | Use webpack patches | DOM manipulation forbidden |
|
||||||
| `Vencord.Plugins.plugins["X"]` | `isPluginEnabled` + direct import | Proper interop |
|
| `Vencord.Plugins.plugins["X"]` | `isPluginEnabled` + direct import | Proper interop |
|
||||||
| `plugin.started` check | `isPluginEnabled(plugin.name)` | Proper interop |
|
| `plugin.started` check | `isPluginEnabled(plugin.name)` | Proper interop |
|
||||||
| Unexplained magic numbers | Named constants | Readability |
|
| Unexplained magic numbers | Named constants | Readability |
|
||||||
| Unused imports | Remove them | Cleanliness |
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -140,7 +126,7 @@ Note: ESLint already enforces `prefer-const`, `prefer-destructuring`, `eqeqeq`,
|
||||||
|
|
||||||
**Conditional rendering:** return `null`, never `undefined` or bare `return;`
|
**Conditional rendering:** return `null`, never `undefined` or bare `return;`
|
||||||
|
|
||||||
**ErrorBoundary:** wrap complex components: `ErrorBoundary.wrap(MyComponent, { noop: true })`
|
**ErrorBoundary:** wrap any component that is used in patches (`$self.renderThing()`): `renderThing: ErrorBoundary.wrap((props) => { ... }, { noop: true })`
|
||||||
|
|
||||||
**useEffect cleanup:** always return cleanup when subscribing to events, timers, or resources:
|
**useEffect cleanup:** always return cleanup when subscribing to events, timers, or resources:
|
||||||
|
|
||||||
|
|
@ -187,8 +173,7 @@ className={classes(cl("wrapper"), someDiscordClass, isActive && cl("active"))}
|
||||||
## Settings
|
## Settings
|
||||||
|
|
||||||
- `settings.store.key` — reactive, auto-persists (React components)
|
- `settings.store.key` — reactive, auto-persists (React components)
|
||||||
- `settings.plain.key` — non-reactive raw value (performance-critical code)
|
- `settings.plain.key` — non-reactive raw value (basically never use this, only for special cases)
|
||||||
- **Never** `settings.use()` with arrays in variables. Mutate then reassign instead.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -199,10 +184,10 @@ Patches modify Discord's minified webpack modules. Stability is paramount.
|
||||||
- **One patch per concern.** Each replacement does one thing.
|
- **One patch per concern.** Each replacement does one thing.
|
||||||
- **Surgical.** Match only what needs replacing, let `find` target the module.
|
- **Surgical.** Match only what needs replacing, let `find` target the module.
|
||||||
- **No hardcoded minified vars.** Never `e`, `t`, `n`, `r`, `i`, `eD`, `eH` etc. Use `\i`.
|
- **No hardcoded minified vars.** Never `e`, `t`, `n`, `r`, `i`, `eD`, `eH` etc. Use `\i`.
|
||||||
- **Bounded gaps.** `.{0,50}` not `.+?` or `.*?` (unbounded = cross-match bugs).
|
- **Bounded gaps.** `.{0,50}?` not `.+?` or `.*?` (unbounded = cross-match bugs).
|
||||||
- **No generic patterns.** `/className:\i/` alone is too broad. Add stable anchors.
|
- **No generic patterns.** `/className:\i/` alone is too broad. Add stable anchors.
|
||||||
- **No raw intl hashes.** Use `#{intl::KEY_NAME}` not `.aA4Vce`.
|
- **No raw intl hashes.** Use `#{intl::KEY_NAME}` not `.aA4Vce`. If key is unknown, use `#{intl::aA4Vce::raw}`.
|
||||||
- **Capture groups only when reused** in replace via `$1`, `$2`.
|
- **Capture groups only when reused** in replace via `$1`, `$2` (or as replace function parameter).
|
||||||
- **`$&`** for append/prepend, **`$self`** for plugin method calls.
|
- **`$&`** for append/prepend, **`$self`** for plugin method calls.
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
|
|
@ -264,8 +249,8 @@ showToast("Module - not found");
|
||||||
|
|
||||||
- `Map`/`Set` for frequent lookups, not arrays
|
- `Map`/`Set` for frequent lookups, not arrays
|
||||||
- `.find()` / `.some()` not `.filter()[0]`
|
- `.find()` / `.some()` not `.filter()[0]`
|
||||||
- No spread `...` in loops
|
|
||||||
- `Promise.all()` for parallel async
|
- `Promise.all()` for parallel async
|
||||||
|
- no local scope webpack `find*` functions (including start or stop methods), always find*Lazy on top level
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -277,7 +262,6 @@ Plugins that don't use patches don't require a Discord restart to apply. Their `
|
||||||
|
|
||||||
- Event listeners added but never removed (FluxDispatcher, DOM events, MessageEvents)
|
- Event listeners added but never removed (FluxDispatcher, DOM events, MessageEvents)
|
||||||
- Intervals/timeouts set but never cleared
|
- Intervals/timeouts set but never cleared
|
||||||
- MutationObservers created but never disconnected
|
|
||||||
- Context menu patches added but never removed (use declarative `contextMenus` instead)
|
- Context menu patches added but never removed (use declarative `contextMenus` instead)
|
||||||
- Chat bar buttons added but never removed (use declarative `chatBarButton` instead)
|
- Chat bar buttons added but never removed (use declarative `chatBarButton` instead)
|
||||||
- Styles enabled but never disabled (use `managedStyle` instead)
|
- Styles enabled but never disabled (use `managedStyle` instead)
|
||||||
|
|
|
||||||
25
.github/ISSUE_TEMPLATE/blank.yml
vendored
25
.github/ISSUE_TEMPLATE/blank.yml
vendored
|
|
@ -1,25 +0,0 @@
|
||||||
name: Blank Issue
|
|
||||||
description: Create a blank issue. ALWAYS FIRST USE OUR SUPPORT CHANNEL! ONLY USE THIS FORM IF YOU ARE A CONTRIBUTOR OR WERE TOLD TO DO SO IN THE SUPPORT CHANNEL.
|
|
||||||
|
|
||||||
body:
|
|
||||||
- type: markdown
|
|
||||||
attributes:
|
|
||||||
value: |
|
|
||||||

|
|
||||||
|
|
||||||
GitHub Issues are for development, not support! Please use our [support server](https://equicord.org/discord) unless you are a Vencord Developer.
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
id: content
|
|
||||||
attributes:
|
|
||||||
label: Content
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: checkboxes
|
|
||||||
id: agreement-check
|
|
||||||
attributes:
|
|
||||||
label: Request Agreement
|
|
||||||
options:
|
|
||||||
- label: I have read the requirements for opening an issue above
|
|
||||||
required: true
|
|
||||||
22
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
22
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
|
|
@ -1,5 +1,5 @@
|
||||||
name: Bug/Crash Report
|
name: Bug/Crash Report
|
||||||
description: Create a bug or crash report for Equicord. ALWAYS FIRST USE OUR SUPPORT CHANNEL! ONLY USE THIS FORM IF YOU ARE A CONTRIBUTOR OR WERE TOLD TO DO SO IN THE SUPPORT CHANNEL.
|
description: Create a bug or crash report for Equicord.
|
||||||
labels: [bug]
|
labels: [bug]
|
||||||
title: "[Bug] <title>"
|
title: "[Bug] <title>"
|
||||||
|
|
||||||
|
|
@ -7,9 +7,16 @@ body:
|
||||||
- type: markdown
|
- type: markdown
|
||||||
attributes:
|
attributes:
|
||||||
value: |
|
value: |
|
||||||

|
GitHub Issues are for development, not support!
|
||||||
|
|
||||||
GitHub Issues are for development, not support! Please use our [support server](https://equicord.org/discord) unless you are a Equicord/Vencord Developer.
|
Some plugins may sometimes break, but we have automatic tracking for that. So please **do not report broken plugins**, it is useless.
|
||||||
|
However, if a plugin works fine, but has a bug in its functionality, then you can report that here.
|
||||||
|
|
||||||
|
If you are experiencing any of the following issues, go to our [Discord server](https://equicord.org/discord) for support:
|
||||||
|
- Equicord doesn't work or crashes
|
||||||
|
- A plugin doesn't work anymore
|
||||||
|
- You are having issues installing Equicord
|
||||||
|
- You want to ask a question about Equicord or one of its plugins
|
||||||
|
|
||||||
- type: textarea
|
- type: textarea
|
||||||
id: bug-description
|
id: bug-description
|
||||||
|
|
@ -46,7 +53,7 @@ body:
|
||||||
id: crash-log
|
id: crash-log
|
||||||
attributes:
|
attributes:
|
||||||
label: Errors
|
label: Errors
|
||||||
description: Open the Developer Console with Ctrl/Cmd + Shift + i. Then look for any red errors (Ignore network errors like Failed to load resource) and paste them between the "```".
|
description: Open the Developer Console with `Ctrl+Shift+i` / `Cmd+Option+i`. Then look for any red errors (Ignore network errors like Failed to load resource) and paste them between the "```".
|
||||||
value: |
|
value: |
|
||||||
```
|
```
|
||||||
Replace this text with your crash-log.
|
Replace this text with your crash-log.
|
||||||
|
|
@ -60,7 +67,8 @@ body:
|
||||||
label: Request Agreement
|
label: Request Agreement
|
||||||
description: We only accept reports for bugs that happen on Discord Stable. Canary and PTB are Development branches and may be unstable
|
description: We only accept reports for bugs that happen on Discord Stable. Canary and PTB are Development branches and may be unstable
|
||||||
options:
|
options:
|
||||||
|
- label: I've searched existing issues and this hasn't been reported before
|
||||||
- label: I am using Discord Stable or tried on Stable and this bug happens there as well
|
- label: I am using Discord Stable or tried on Stable and this bug happens there as well
|
||||||
required: true
|
- label: I installed Equicord via an official method (download from equicord.org or from source), not via something like AUR or Nix packages
|
||||||
- label: I am a Equicord/Vencord Developer
|
- label: This is not a support request
|
||||||
required: true
|
- label: I am willing to submit a fix for this myself
|
||||||
|
|
|
||||||
13
.github/ISSUE_TEMPLATE/config.yml
vendored
13
.github/ISSUE_TEMPLATE/config.yml
vendored
|
|
@ -1,8 +1,11 @@
|
||||||
blank_issues_enabled: false
|
blank_issues_enabled: false
|
||||||
contact_links:
|
contact_links:
|
||||||
- name: Equicord Support Server
|
- name: 💬 Discord Community
|
||||||
url: https://equicord.org/discord
|
url: https://equicord.org/discord
|
||||||
about: If you need help regarding Equicord, please join our support server!
|
about: For plugin requests, support questions, and general help - join our Discord server
|
||||||
- name: Equicord Installer
|
- name: 🔌 Plugin Requests
|
||||||
url: https://github.com/Equicord/Equilotl
|
url: https://equicord.org/discord
|
||||||
about: You can find the Equicord Installer here
|
about: Want a new plugin? Request it in our Discord community, not here
|
||||||
|
- name: ❓ Support & Questions
|
||||||
|
url: https://equicord.org/discord
|
||||||
|
about: Need help? Ask in our Discord server for faster responses
|
||||||
|
|
|
||||||
BIN
.github/ISSUE_TEMPLATE/developer-banner.png
vendored
BIN
.github/ISSUE_TEMPLATE/developer-banner.png
vendored
Binary file not shown.
|
Before Width: | Height: | Size: 31 KiB |
45
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
Normal file
45
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
name: Feature Request
|
||||||
|
description: Have an idea for a new feature? Request it here! No plugin requests, go to our Discord server for that
|
||||||
|
labels: [enhancement]
|
||||||
|
title: "[Feature] <title>"
|
||||||
|
|
||||||
|
body:
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |
|
||||||
|
This form is not for any of the following:
|
||||||
|
- Plugin requests — Go to our [Discord server](https://discord.gg/D9uwnFnqmd) for that
|
||||||
|
- Feature requests for plugins — Go to our [Discord server](https://discord.gg/D9uwnFnqmd) for that
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: feature-description
|
||||||
|
attributes:
|
||||||
|
label: A clear and concise description of the feature you'd like to see
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: implementation-notes
|
||||||
|
attributes:
|
||||||
|
label: Implementation Notes
|
||||||
|
description: If you have ideas about how this could be implemented technically, share them here
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: additional-context
|
||||||
|
attributes:
|
||||||
|
label: Additional context
|
||||||
|
description: Screenshots, mockups, examples from other apps, etc.
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
|
|
||||||
|
- type: checkboxes
|
||||||
|
id: agreement-check
|
||||||
|
attributes:
|
||||||
|
label: Request Agreement
|
||||||
|
options:
|
||||||
|
- label: I've searched existing issues and this hasn't been suggested before
|
||||||
|
- label: This is a **core modification feature**, not a plugin request (those go in Discord)
|
||||||
|
- label: This feature would benefit most users, not just a specific use case
|
||||||
|
- label: I am willing to work on this myself
|
||||||
9
.github/pull_request_template.md
vendored
Normal file
9
.github/pull_request_template.md
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
<!--
|
||||||
|
We do not accept PRs that were created by AI. You will be permanently blocked with no further warning if you submit AI generated PRs.
|
||||||
|
-->
|
||||||
|
|
||||||
|
## Describe your Changes
|
||||||
|
|
||||||
|
## Checklist before submitting
|
||||||
|
- [ ] I have read the [CONTRIBUTING.md](./CONTRIBUTING.md) file and made sure this pull request complies with it
|
||||||
|
- [ ] This pull request was written by me, and not an AI agent
|
||||||
|
|
@ -1,5 +1,11 @@
|
||||||
# Introduction
|
# Introduction
|
||||||
|
|
||||||
|
> [!NOTE]
|
||||||
|
> **AI Usage Notice**
|
||||||
|
>
|
||||||
|
> Your contribution must be majority human written! Some AI assistance like inline suggestions is acceptable, but "vibecoded" contributions are not welcome.
|
||||||
|
> Also **do not** use AI to generate your pull request description, README.md or in communication. Ignoring this rule will lead to a permanent block.
|
||||||
|
|
||||||
Equicord is a community project and welcomes any kind of contribution from anyone!
|
Equicord is a community project and welcomes any kind of contribution from anyone!
|
||||||
|
|
||||||
We have development documentation for new contributors, which can be found at <https://docs.equicord.org>.
|
We have development documentation for new contributors, which can be found at <https://docs.equicord.org>.
|
||||||
|
|
@ -11,8 +17,12 @@ We have development documentation for new contributors, which can be found at <h
|
||||||
|
|
||||||
Contributions are submitted through pull requests. If you are new to Git or GitHub, we recommend reading [this guide](https://opensource.com/article/19/7/create-pull-request-github).
|
Contributions are submitted through pull requests. If you are new to Git or GitHub, we recommend reading [this guide](https://opensource.com/article/19/7/create-pull-request-github).
|
||||||
|
|
||||||
Pull requests can target either the `main` or `dev` branch.
|
Pull requests can be made either to the `main` or the `dev` branch. However, unless you're an advanced user, I recommend sticking to `main`.
|
||||||
Unless you are experienced and know what you are doing, **always target `main`**. The `dev` branch may contain unstable changes and can be force-pushed frequently, which may break your pull request.
|
This is because the dev branch might contain unstable changes and be force pushed frequently, which could cause conflicts in your pull request.
|
||||||
|
|
||||||
|
Before working on a major change, I highly recommend opening a feature request for it, making sure to check "I am willing to work on this myself",
|
||||||
|
so we can discuss before you invest time. Alternatively, you can also do so in our Discord server's development
|
||||||
|
channels. This saves you a lot of time in case your feature is considered too niche or rejected for any other reason.
|
||||||
|
|
||||||
## Writing a Plugin
|
## Writing a Plugin
|
||||||
|
|
||||||
|
|
@ -20,6 +30,10 @@ Developing a plugin is the primary way to contribute.
|
||||||
|
|
||||||
Before starting your plugin:
|
Before starting your plugin:
|
||||||
|
|
||||||
|
- Consider if this plugin would be useful to a large portion of the userbase. We do not accept niche plugins
|
||||||
|
- Check existing pull requests to see if someone is already working on a similar plugin
|
||||||
|
- Familarise yourself with our plugin rules below to ensure your plugin is not banned
|
||||||
|
|
||||||
- Join our Discord server.
|
- Join our Discord server.
|
||||||
- Check existing pull requests to avoid duplicate work.
|
- Check existing pull requests to avoid duplicate work.
|
||||||
- Check the [plugin requests tracker](https://discord.com/channels/1173279886065029291/1419347113745059961) to see if your idea already exists or was rejected.
|
- Check the [plugin requests tracker](https://discord.com/channels/1173279886065029291/1419347113745059961) to see if your idea already exists or was rejected.
|
||||||
|
|
@ -33,6 +47,7 @@ Before starting your plugin:
|
||||||
## Plugin Rules
|
## Plugin Rules
|
||||||
|
|
||||||
To keep Equicord stable, secure and maintainable, all plugins must follow these rules:
|
To keep Equicord stable, secure and maintainable, all plugins must follow these rules:
|
||||||
|
|
||||||
1. No simple slash-command plugins (e.g. `/cat`). If applicable, create a [user-installable Discord app](https://discord.com/developers/docs/change-log#userinstallable-apps-preview) instead.
|
1. No simple slash-command plugins (e.g. `/cat`). If applicable, create a [user-installable Discord app](https://discord.com/developers/docs/change-log#userinstallable-apps-preview) instead.
|
||||||
2. No simple text replacement plugins (the built-in TextReplace plugin already covers this).
|
2. No simple text replacement plugins (the built-in TextReplace plugin already covers this).
|
||||||
3. No raw DOM manipulation — always use proper patches and React.
|
3. No raw DOM manipulation — always use proper patches and React.
|
||||||
|
|
|
||||||
|
|
@ -62,8 +62,8 @@ export default definePlugin({
|
||||||
find: "#{intl::AUTH_SESSIONS_OS_UNKNOWN}",
|
find: "#{intl::AUTH_SESSIONS_OS_UNKNOWN}",
|
||||||
replacement: [
|
replacement: [
|
||||||
{
|
{
|
||||||
match: /(?<=#{intl::AUTH_SESSIONS_ACTIVE_RECENTLY}.{0,230}role:"listitem",children:\[.{0,15},\{Icon:)(\i)/,
|
match: /(#{intl::AUTH_SESSIONS_ACTIVE_RECENTLY}.{0,230}role:"listitem",children:\[.{0,15},\{Icon:)\i/,
|
||||||
replace: "()=>$self.renderIcon({...arguments[0],DeviceIcon:$1})"
|
replace: "$1()=>$self.renderIcon(arguments[0])"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
match: /("horizontal",gap:"xs",children:)\[.{0,250}"text-subtle",children:\i\}\)\]\}\),/,
|
match: /("horizontal",gap:"xs",children:)\[.{0,250}"text-subtle",children:\i\}\)\]\}\),/,
|
||||||
|
|
@ -122,7 +122,7 @@ export default definePlugin({
|
||||||
);
|
);
|
||||||
}, { noop: true }),
|
}, { noop: true }),
|
||||||
|
|
||||||
renderIcon: ErrorBoundary.wrap(({ session, DeviceIcon }: { session: Session, DeviceIcon: React.ComponentType<any>; }) => {
|
renderIcon: ErrorBoundary.wrap(({ session, icon: DeviceIcon }: { session: Session; icon: React.ComponentType<any>; }) => {
|
||||||
const PlatformIcon = GetPlatformIcon(session.client_info.platform);
|
const PlatformIcon = GetPlatformIcon(session.client_info.platform);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue