├── .editorconfig ├── .eslintrc.json ├── .gitattributes ├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ └── bug_report.yml └── workflows │ ├── build.yml │ ├── lint.yml │ └── release.yml ├── .gitignore ├── .vscode └── settings.json ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── HEADER.txt ├── HEADER_ADDON.txt ├── LICENSE ├── README.md ├── assets ├── Dark.png ├── Light.png ├── Logo.svg └── Transparent.png ├── docs └── plugins │ └── index.md ├── globals.d.ts ├── module.d.ts ├── package-lock.json ├── package.json ├── packages ├── common │ ├── filesystem │ │ ├── main.ts │ │ └── types.ts │ ├── ipc.ts │ └── logger.ts ├── main │ ├── csp.ts │ ├── devtools.ts │ ├── index.ts │ ├── ipc.ts │ └── util │ │ ├── crx.ts │ │ ├── fetch.ts │ │ └── settings.ts ├── preload │ ├── index.ts │ └── util.ts └── renderer │ ├── aero.ts │ ├── api │ ├── attachments │ │ ├── badges.scss │ │ └── badges.tsx │ ├── docs │ │ ├── index.scss │ │ └── index.tsx │ ├── dom │ │ ├── elements.ts │ │ └── index.ts │ ├── notifications │ │ ├── Generic.tsx │ │ └── index.tsx │ ├── patcher │ │ ├── classic.ts │ │ ├── index.ts │ │ ├── menu.ts │ │ └── webpack.ts │ ├── plugins │ │ ├── actions.ts │ │ ├── builtin.tsx │ │ ├── external.ts │ │ ├── import.ts │ │ ├── index.ts │ │ ├── registry.ts │ │ ├── settings.ts │ │ └── types.ts │ ├── settings │ │ ├── index.ts │ │ └── useSettings.ts │ ├── snippets │ │ └── index.ts │ ├── stores.ts │ ├── themes │ │ ├── actions.ts │ │ ├── external.ts │ │ ├── index.ts │ │ └── types.ts │ ├── types.ts │ └── webpack │ │ ├── common │ │ ├── actions.ts │ │ ├── components.tsx │ │ ├── index.ts │ │ ├── misc.ts │ │ ├── react.ts │ │ └── stores.ts │ │ ├── index.ts │ │ └── webpack.ts │ ├── index.ts │ ├── ui │ ├── components │ │ ├── AddonCard.tsx │ │ ├── Alert.tsx │ │ ├── Button.tsx │ │ ├── EmptyState.tsx │ │ ├── ErrorBoundary.tsx │ │ ├── FormTitle.tsx │ │ ├── Icons │ │ │ ├── Book.tsx │ │ │ ├── Check.tsx │ │ │ ├── Cloud.tsx │ │ │ ├── Copy.tsx │ │ │ ├── Cross.tsx │ │ │ ├── Dev.tsx │ │ │ ├── External.tsx │ │ │ ├── Eye.tsx │ │ │ ├── File.tsx │ │ │ ├── Folder.tsx │ │ │ ├── Gear.tsx │ │ │ ├── Heart.tsx │ │ │ ├── Info.tsx │ │ │ ├── Pencil.tsx │ │ │ ├── Play.tsx │ │ │ ├── Plus.tsx │ │ │ ├── Sparkle.tsx │ │ │ ├── base.tsx │ │ │ └── index.ts │ │ ├── Modal │ │ │ ├── CloseButton.tsx │ │ │ ├── index.scss │ │ │ └── index.tsx │ │ ├── Monaco.tsx │ │ ├── PanelButton.tsx │ │ ├── SettingsItem.tsx │ │ ├── Switch.tsx │ │ ├── TextInput.tsx │ │ ├── Toast.tsx │ │ ├── addoncard.scss │ │ ├── alert.scss │ │ ├── button.scss │ │ ├── emptystate.scss │ │ ├── errorboundary.scss │ │ ├── formtitle.scss │ │ ├── index.ts │ │ ├── monaco.scss │ │ ├── panelbutton.scss │ │ ├── settingsitem.scss │ │ ├── switch.scss │ │ ├── textinput.scss │ │ └── toast.scss │ └── settings │ │ ├── buildSettings.tsx │ │ ├── index.tsx │ │ ├── panes │ │ ├── Addons.tsx │ │ ├── Dashboard.tsx │ │ ├── Snippets.tsx │ │ ├── addons.scss │ │ ├── dashboard.scss │ │ └── snippets.scss │ │ └── settings.scss │ ├── util.scss │ └── util │ ├── classes.ts │ ├── markdown.ts │ ├── polyfill.ts │ ├── preview.tsx │ ├── react.tsx │ └── time.ts ├── pnpm-lock.yaml ├── rollup.config.js ├── scripts ├── common.js ├── inject.js └── uninject.js └── tsconfig.json /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: https://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | [*] 7 | line-ending = lf 8 | charset = utf-8 9 | indent_style = space 10 | indent_size = 4 11 | insert_final_newline = true 12 | trim_trailing_whitespace = true 13 | max_line_length = 120 -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json.schemastore.org/eslintrc", 3 | "root": true, 4 | "ignorePatterns": ["node_modules", "dist"], 5 | "extends": ["plugin:@typescript-eslint/recommended", "prettier", "plugin:editorconfig/noconflict"], 6 | "parser": "@typescript-eslint/parser", 7 | "plugins": ["header", "editorconfig", "path-alias", "unused-imports", "simple-import-sort", "@typescript-eslint"], 8 | "settings": { 9 | "import/resolver": { 10 | "alias": { 11 | "map": [["~/*", "./packages/*"]] 12 | } 13 | } 14 | }, 15 | "rules": { 16 | "quotes": ["error", "double", { "avoidEscape": true }], 17 | "semi": ["error", "always"], 18 | "no-console": "warn", 19 | "header/header": [2, "HEADER.txt"] 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: TheCommieAxolotl 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.yml: -------------------------------------------------------------------------------- 1 | name: Bug report 2 | description: File a bug report 3 | title: "bug: " 4 | labels: 5 | - bug 6 | - triage 7 | assignees: 8 | - TheCommieAxolotl 9 | body: 10 | - type: checkboxes 11 | id: duplicate 12 | attributes: 13 | label: Checks 14 | options: 15 | - label: I have checked this is not a duplicate issue. 16 | required: true 17 | - label: I have checked and this issue is replicable. 18 | required: true 19 | - type: dropdown 20 | id: channel 21 | attributes: 22 | label: Aero Channel 23 | options: 24 | - Stable 25 | - Preview 26 | - Development 27 | - type: input 28 | id: version 29 | attributes: 30 | label: Aero Version 31 | placeholder: 1.x.x 32 | validations: 33 | required: true 34 | - type: textarea 35 | id: issue 36 | attributes: 37 | label: Actual Behaviour 38 | description: What actually happened? 39 | placeholder: discord died 40 | validations: 41 | required: true 42 | - type: textarea 43 | id: expected 44 | attributes: 45 | label: Expected Behaviour 46 | description: What did you think was going to happen? 47 | placeholder: discord alived 48 | - type: textarea 49 | id: logs 50 | attributes: 51 | label: Logs/Errors 52 | description: Any output logs or console messages relevant to the issue. 53 | placeholder: | 54 | Uncaught TypeError: Cannot read properties of undefined (reading 'aero') 55 | at Object. (aero:renderer:1:1) 56 | render: shell 57 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | on: 3 | push: 4 | branches: 5 | - main 6 | paths: 7 | - packages/** 8 | - docs/** 9 | - rollup.config.js 10 | - package.json 11 | - pnpm-lock.yaml 12 | - .github/workflows/build.yml 13 | 14 | jobs: 15 | build: 16 | runs-on: ubuntu-latest 17 | steps: 18 | - uses: actions/checkout@v2 19 | 20 | - uses: pnpm/action-setup@v2 21 | 22 | - uses: actions/setup-node@v2 23 | with: 24 | node-version: 19 25 | cache: "pnpm" 26 | 27 | - run: pnpm install --frozen-lockfile 28 | - run: pnpm build 29 | 30 | - name: "asar-ify" 31 | run: pnpx asar pack dist/ dist/aero.asar 32 | 33 | - name: "Find Hash" 34 | id: hash 35 | run: | 36 | echo "HASH=$(git rev-parse --short HEAD)" >> $GITHUB_ENV 37 | 38 | - name: "Create Release" 39 | run: | 40 | gh release upload development dist/aero.asar --clobber 41 | gh release edit development --title "Development #$HASH" 42 | env: 43 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 44 | HASH: ${{ env.HASH }} 45 | -------------------------------------------------------------------------------- /.github/workflows/lint.yml: -------------------------------------------------------------------------------- 1 | name: Lint 2 | on: 3 | push: 4 | branches: 5 | - "*" 6 | pull_request: 7 | branches: 8 | - "*" 9 | 10 | jobs: 11 | lint: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v2 15 | 16 | - uses: pnpm/action-setup@v2 17 | 18 | - uses: actions/setup-node@v2 19 | with: 20 | node-version: 19 21 | cache: "pnpm" 22 | 23 | - run: pnpm install --frozen-lockfile 24 | - run: pnpm lint 25 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | on: 3 | push: 4 | branches: 5 | - "main" 6 | 7 | jobs: 8 | release: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v2 12 | with: 13 | fetch-depth: 0 14 | 15 | - uses: pnpm/action-setup@v2 16 | 17 | - uses: actions/setup-node@v2 18 | with: 19 | node-version: 19 20 | cache: "pnpm" 21 | 22 | - run: pnpm install --frozen-lockfile 23 | - run: pnpm build 24 | 25 | - name: "asar-ify" 26 | run: pnpx asar pack dist/ dist/aero.asar 27 | 28 | - name: "Find Version in package.json" 29 | id: version 30 | run: | 31 | echo "VERSION=$(node -p "require('./package.json').version")" >> $GITHUB_ENV 32 | 33 | - name: "Create Release" 34 | if: "startsWith(github.event.head_commit.message, 'release: ')" 35 | run: | 36 | gh release upload stable dist/aero.asar --clobber 37 | gh release edit stable --title "Stable v$VERSION" 38 | env: 39 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 40 | VERSION: ${{ env.VERSION }} 41 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | node_modules 3 | **.env 4 | .DS_Store -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "cSpell.words": ["Wumpus"] 3 | } 4 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | - We are committed to providing a friendly, safe and welcoming environment for all, regardless of level of experience, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, nationality, or other similar characteristic. 4 | - Please avoid using overtly sexual aliases or other nicknames that might detract from a friendly, safe and welcoming environment for all. 5 | - Please be kind and courteous. There’s no need to be mean or rude. 6 | - Respect that people have differences of opinion and that every design or implementation choice carries a trade-off and numerous costs. There is seldom a right answer. 7 | - Please keep unstructured critique to a minimum. If you have solid ideas you want to experiment with, make a fork and see how it works. 8 | - We will exclude you from interaction if you insult, demean or harass anyone. That is not welcome behavior. We interpret the term “harassment” as including the definition in the [Citizen Code of Conduct](https://github.com/stumpsyn/policies/blob/master/citizen_code_of_conduct.md); if you have any lack of clarity about what might be included in that concept, please read their definition. In particular, we don’t tolerate behavior that excludes people in socially marginalized groups. 9 | - Private harassment is also unacceptable. No matter who you are, if you feel you have been or are being harassed or made uncomfortable by a community member, please contact any of the Aero moderation team immediately. Whether you’re a regular contributor or a newcomer, we care about making this community a safe place for you and we’ve got your back. 10 | - Likewise any spamming, trolling, flaming, baiting or other attention-stealing behavior is not welcome. 11 | 12 | Modified from the [Rust Code of Conduct](https://www.rust-lang.org/policies/code-of-conduct) -------------------------------------------------------------------------------- /HEADER.txt: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ -------------------------------------------------------------------------------- /HEADER_ADDON.txt: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is an addon created for use with Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * Copyright (c) . 5 | * 6 | * This addon is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This addon is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this addon. If not, see . 18 | */ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 5 |
6 | 7 |
8 | Aero Logo 9 |

Aero

10 | A next-generation Discord mod empowering users and developers alike. 11 |
12 | 13 | --- 14 | ![aero](https://img.shields.io/badge/-aero-blue?style=flat-square&color=%236B87DE) 15 | ![Repo Stars](https://img.shields.io/github/stars/aero-mod/aero?style=flat-square&color=%236B87DE) 16 | [![Build Status](https://img.shields.io/github/actions/workflow/status/aero-mod/aero/build.yml?style=flat-square&color=%236B87DE)](https://github.com/aero-mod/aero/releases/tag/development) 17 | ![Wakatime](https://wakatime.com/badge/user/00c7afe5-77ae-4122-9969-8fa677814618/project/4a921a8c-f97e-4fe3-9804-9b18ed5c3c4a.svg?style=flat-square) 18 | 19 | ## Installing 20 | 21 | Clone this repo to your machine: 22 | ```bash 23 | $ git clone https://github.com/aero-mod/aero aero 24 | ``` 25 | 26 | Install dependencies and build locally 27 | ```bash 28 | $ pnpm i 29 | $ pnpm build 30 | ``` 31 | 32 | Inject into Discord 33 | ```bash 34 | $ pnpm inject 35 | ``` 36 | 37 | Tada! 🎉 38 | 39 | ## License Information 40 | 41 | This project is licensed under the GNU [General Public License v3.0](https://www.gnu.org/licenses/). All derivative works and addons must also be licensed under the GNU GPL v3.0 or later and may include one of the headers provided. 42 | 43 | 44 | ###### The spiritual successor to [Velocity](https://github.com/Velocity-Discord/Velocity). 45 | -------------------------------------------------------------------------------- /assets/Dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aero-mod/aero/4d589a4eb1301672cfee8fb7e54981368ea30532/assets/Dark.png -------------------------------------------------------------------------------- /assets/Light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aero-mod/aero/4d589a4eb1301672cfee8fb7e54981368ea30532/assets/Light.png -------------------------------------------------------------------------------- /assets/Logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/Transparent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aero-mod/aero/4d589a4eb1301672cfee8fb7e54981368ea30532/assets/Transparent.png -------------------------------------------------------------------------------- /docs/plugins/index.md: -------------------------------------------------------------------------------- 1 | # Plugins 2 | 3 | Hey! this page will walk you through how to get started with plugin development. 4 | 5 | # What can a plugin do. 6 | 7 | A plugin (as of `v0.0.0`) is a single-file module that can control, modify, and extend discord's functionality. You may be familiar with different plugin formats from client modifications such as [BetterDiscord](https://betterdiscord.app/), [Vencord](https://vencord.dev/), and [Replugged](https://replugged.dev/). Aero's plugin system is most resemblant to Vencord's, but with a few key differences. 8 | 9 | # Getting started & Structure. 10 | 11 | We're going to assume you're creating your plugin directly from the `/aero/plugins` directory. **This is not recommended**, but it's the easiest way to get started with the pre-bundled typedefs. 12 | 13 | Aero uses custom modules to let you write cleaner code. All plugins are transpiled at runtime so you can write in ts or tsx. The only requirement is that your plugin exports a default object that adheres to the structure we'll show you later on. 14 | 15 | To get started, we'll create a plugin, say `myplugin.tsx` that looks like this: 16 | 17 | ```tsx 18 | import { definePlugin } from 'aero/plugin'; 19 | 20 | export default definePlugin({ 21 | id: 'myplugin', 22 | name: 'My Plugin', 23 | description: 'This is my first plugin!', 24 | version: '1.0.0', 25 | author: { 26 | name: 'My Name', 27 | id: 'my discord id' 28 | } 29 | }) 30 | ``` 31 | 32 | ✨ Ta da! ✨ We've just made a valid plugin. Now, let's go over the structure of the plugin object. 33 | 34 | ```tsx 35 | type Plugin = { 36 | id: string; 37 | name: string; 38 | description: string; 39 | author: Author | Author[]; 40 | color?: string; 41 | self?: Record; 42 | dependencies?: string[]; 43 | patches?: Patch[]; 44 | start?(): void; 45 | stop?(): void; 46 | settings?: SettingsOption[]; 47 | }; 48 | ``` 49 | 50 | Look at that! We're only using a few of the properties, but we'll go over all of them. 51 | 52 | -------------------------------------------------------------------------------- /globals.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | /* eslint-disable @typescript-eslint/no-explicit-any */ 20 | 21 | export type AeroNative = typeof import("~/preload/index").aeroNative; 22 | export type Aero = typeof import("~/renderer/aero").default; 23 | 24 | export type SourceMap = { 25 | file?: string; 26 | sourceRoot?: string; 27 | version: string; 28 | sources: string[]; 29 | names: string[]; 30 | sourcesContent?: string[]; 31 | mappings: string; 32 | }; 33 | 34 | type RequireResult = "aero" extends T 35 | ? typeof import("~/renderer/aero").default 36 | : "aero/plugin" extends T 37 | ? { 38 | remoteImport: typeof import("~/renderer/api/plugins/import").remoteImport; 39 | definePlugin: typeof import("~/renderer/api/plugins/types").definePlugin; 40 | defineVencordPlugin: typeof import("~/renderer/api/plugins/types").defineVencordPlugin; 41 | SettingsItemType: typeof import("~/renderer/api/plugins/types").SettingsItemType; 42 | } 43 | : "aero/theme" extends T 44 | ? { 45 | defineTheme: typeof import("~/renderer/api/themes/types").defineTheme; 46 | } 47 | : "aero/webpack" extends T 48 | ? typeof import("~/renderer/api/webpack") 49 | : "aero/dom" extends T 50 | ? typeof import("~/renderer/api/dom") 51 | : "aero/ui" extends T 52 | ? typeof import("~/renderer/ui/components") 53 | : "aero/badges" extends T 54 | ? typeof import("~/renderer/api/attachments/badges") 55 | : never; 56 | 57 | type InternalModule = "aero" | "aero/plugin" | "aero/theme" | "aero/webpack" | "aero/dom" | "aero/ui" | "aero/badges"; 58 | 59 | declare global { 60 | interface Window { 61 | /** 62 | * This is not `NodeRequire`, this require function provides access to internal modules via plugins. 63 | * 64 | * *Do not use this explicitly* 65 | */ 66 | require: ((id: I) => RequireResult) & { 67 | all: InternalModule[]; 68 | }; 69 | webpackChunkdiscord_app: any; 70 | DiscordNative: any; 71 | 72 | aeroNative: AeroNative; 73 | aero: Aero; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /module.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | declare module "~content/*" { 20 | const str: string; 21 | 22 | export default str; 23 | } 24 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "aero", 3 | "version": "1.1.0", 4 | "description": "A next-generation Discord mod empowering users and developers alike.", 5 | "type": "module", 6 | "license": "GPL-3.0-or-later", 7 | "author": "TheCommieAxolotl", 8 | "main": "dist/index.js", 9 | "packageManager": "pnpm@7.29.1", 10 | "scripts": { 11 | "build": "rollup -c", 12 | "build:preview": "rollup -c --preview", 13 | "dev": "rollup -c -w", 14 | "inject": "node ./scripts/inject.js", 15 | "uninject": "node ./scripts/uninject.js", 16 | "format": "prettier --write \"packages/**/*.ts\" \"packages/**/*.tsx\" \"packages/**/*.scss\"", 17 | "lint": "eslint \"packages/**/*.ts\" \"packages/**/*.tsx\"" 18 | }, 19 | "devDependencies": { 20 | "@electron/asar": "^3.2.4", 21 | "@monaco-editor/loader": "^1.3.3", 22 | "@rollup/plugin-commonjs": "^25.0.1", 23 | "@rollup/plugin-json": "^6.0.0", 24 | "@rollup/plugin-node-resolve": "^15.1.0", 25 | "@rollup/plugin-swc": "^0.1.1", 26 | "@rollup/plugin-terser": "^0.4.3", 27 | "@rollup/plugin-typescript": "^11.1.1", 28 | "@rollup/plugin-url": "^8.0.1", 29 | "@swc/core": "^1.3.62", 30 | "@types/react": "^18.2.10", 31 | "@types/react-dom": "^18.2.4", 32 | "@typescript-eslint/eslint-plugin": "^5.59.11", 33 | "@typescript-eslint/parser": "^5.59.11", 34 | "discord-types": "^1.3.3", 35 | "electron": "^28.2.0", 36 | "eslint": "^8.42.0", 37 | "eslint-config-prettier": "^8.8.0", 38 | "eslint-plugin-editorconfig": "^4.0.3", 39 | "eslint-plugin-header": "^3.1.1", 40 | "eslint-plugin-path-alias": "^1.0.0", 41 | "eslint-plugin-simple-import-sort": "^10.0.0", 42 | "eslint-plugin-unused-imports": "^2.0.0", 43 | "fflate": "^0.8.0", 44 | "highlight.js": "^11.8.0", 45 | "monaco-editor": "^0.39.0", 46 | "prettier": "^2.8.8", 47 | "react": "^18.2.0", 48 | "react-dom": "^18.2.0", 49 | "react-spring": "^9.7.2", 50 | "rollup": "^3.24.0", 51 | "rollup-plugin-scss": "^4.0.0", 52 | "sass": "^1.63.3", 53 | "tslib": "^2.5.3", 54 | "typescript": "^4.9.5" 55 | }, 56 | "dependencies": { 57 | "@rollup/plugin-replace": "^5.0.2" 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /packages/common/filesystem/types.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | export type File = { 20 | type: "file"; 21 | relativePath: string; 22 | absolutePath: string; 23 | content: string; 24 | filename: string; 25 | extension: string; 26 | }; 27 | 28 | export type Directory = { 29 | type: "directory"; 30 | relativePath: string; 31 | absolutePath: string; 32 | files: { 33 | [filename: string]: File; 34 | }; 35 | directories: { 36 | [dirname: string]: Directory; 37 | }; 38 | name: string; 39 | }; 40 | -------------------------------------------------------------------------------- /packages/common/ipc.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | export const OPEN_SNIPPET_DIRECTORY = "aero:open_snippet_directory"; 20 | export const OPEN_PLUGIN_DIRECTORY = "aero:open_plugin_directory"; 21 | export const OPEN_THEME_DIRECTORY = "aero:open_theme_directory"; 22 | export const OPEN_DATA_DIRECTORY = "aero:open_data_directory"; 23 | export const SAVE_SETTINGS = "aero:save_settings"; 24 | export const OPEN_FILE = "aero:open_file"; 25 | export const RELAUNCH = "aero:relaunch"; 26 | -------------------------------------------------------------------------------- /packages/common/logger.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | import { originalConsole } from "~/renderer/util/polyfill"; 20 | import { loadSettings } from "~/renderer/api/settings"; 21 | 22 | export const makeLogger = (prefix: string) => { 23 | return { 24 | log: (...args: unknown[]) => { 25 | originalConsole.log(`%c[${prefix}]`, "color: #7AA2F7", ...args); 26 | }, 27 | info: (...args: unknown[]) => { 28 | originalConsole.log(`%c[${prefix}]`, "color: #7AA2F7", ...args); 29 | }, 30 | warn: (...args: unknown[]) => { 31 | originalConsole.warn(`%c[${prefix}]`, "color: #e5c062", ...args); 32 | }, 33 | error: (...args: unknown[]) => { 34 | originalConsole.error(`%c[${prefix}]`, "color: #e56269", ...args); 35 | }, 36 | debug: async (...args: unknown[]) => { 37 | if (loadSettings().debugLogs) { 38 | originalConsole.log(`%c[${prefix}]`, "color: #7AA2F7", ...args); 39 | } 40 | }, 41 | }; 42 | }; 43 | 44 | export default makeLogger("Aero"); 45 | -------------------------------------------------------------------------------- /packages/main/csp.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | import { session } from "electron"; 20 | 21 | const external = ["https://esm.sh", "https://unpkg.com", "https://cdn.jsdelivr.net"]; 22 | 23 | export default () => { 24 | session.defaultSession.webRequest.onHeadersReceived((event, cb) => { 25 | const key = Object.keys(event.responseHeaders).find((key) => key.toLowerCase() === "content-security-policy"); 26 | 27 | if (!key) return cb({ cancel: false, responseHeaders: event.responseHeaders }); 28 | 29 | event.responseHeaders[key] = [ 30 | `default-src * 'unsafe-inline' data: blob:; script-src ${external.join( 31 | " " 32 | )} 'self' 'unsafe-inline' 'unsafe-eval';`, 33 | ]; 34 | 35 | cb({ cancel: false, responseHeaders: event.responseHeaders }); 36 | }); 37 | }; 38 | -------------------------------------------------------------------------------- /packages/main/devtools.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | import { session } from "electron"; 20 | import { unzip } from "fflate"; 21 | 22 | import fs from "node:fs/promises"; 23 | import { existsSync } from "fs"; 24 | import path from "node:path"; 25 | 26 | import { dataDirectory } from "./ipc"; 27 | import { get } from "./util/fetch"; 28 | import crx from "./util/crx"; 29 | 30 | export const unpack = async (buffer: ArrayBuffer, extDir: string) => { 31 | return new Promise((resolve, reject) => { 32 | unzip(new Uint8Array(buffer), (err, files) => { 33 | if (err) { 34 | return void reject(err); 35 | } 36 | 37 | Promise.all( 38 | Object.keys(files).map(async (file) => { 39 | if (file.startsWith("_metadata/")) return 0; 40 | if (file.endsWith("/")) return void fs.mkdir(path.join(extDir, file), { recursive: true }); 41 | 42 | const pathElements = file.split("/"); 43 | const name = pathElements.pop(); 44 | const directories = pathElements.join("/"); 45 | const dir = path.join(extDir, directories); 46 | 47 | if (directories) { 48 | await fs.mkdir(dir, { recursive: true }); 49 | } 50 | 51 | await fs.writeFile(path.join(dir, name), files[file]); 52 | }) 53 | ) 54 | .then(() => resolve()) 55 | .catch((err) => { 56 | fs.rm(extDir, { recursive: true, force: true }); 57 | reject(err); 58 | }); 59 | }); 60 | }); 61 | }; 62 | 63 | export default async () => { 64 | const ext = path.join(dataDirectory, "extensionCache"); 65 | 66 | if (existsSync(ext)) { 67 | session.defaultSession.loadExtension(ext); 68 | 69 | return; 70 | } 71 | 72 | await fs.mkdir(ext); 73 | 74 | const url = 75 | "https://raw.githubusercontent.com/Vendicated/random-files/f6f550e4c58ac5f2012095a130406c2ab25b984d/fmkadmapgofadopljbjfkapdkoienihi.zip"; 76 | 77 | const buffer = await get(url); 78 | 79 | await unpack(crx(buffer), ext); 80 | 81 | session.defaultSession.loadExtension(ext); 82 | }; 83 | -------------------------------------------------------------------------------- /packages/main/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | import type { BrowserWindowConstructorOptions } from "electron"; 20 | 21 | import electron from "electron"; 22 | 23 | import path from "node:path"; 24 | 25 | import { readSettings } from "./util/settings"; 26 | import devtools from "./devtools"; 27 | import ipc from "./ipc"; 28 | import csp from "./csp"; 29 | 30 | electron.app.commandLine.appendSwitch("no-force-async-hooks-checks"); 31 | 32 | electron.app.on("ready", () => { 33 | devtools(); 34 | ipc(); 35 | csp(); 36 | }); 37 | 38 | class BrowserWindow extends electron.BrowserWindow { 39 | constructor(options: BrowserWindowConstructorOptions) { 40 | if (!options.webPreferences || !options.webPreferences.preload || process.argv.includes("--vanilla")) { 41 | super(options); 42 | 43 | return; 44 | } 45 | 46 | const settings = readSettings(); 47 | 48 | const originalPreload = options.webPreferences.preload; 49 | process.env.AERO_PRELOAD = originalPreload; 50 | 51 | const opts: BrowserWindowConstructorOptions = { 52 | ...options, 53 | webPreferences: { 54 | ...options.webPreferences, 55 | preload: originalPreload.includes("discord_desktop_core") 56 | ? path.join(__dirname, "preload.js") 57 | : originalPreload, 58 | devTools: true, 59 | }, 60 | ...(settings.vibrancy && process.platform === "darwin" 61 | ? { 62 | vibrancy: "sidebar", 63 | transparent: true, 64 | backgroundColor: "#00000000", 65 | } 66 | : {}), 67 | }; 68 | 69 | return super(opts) as unknown as BrowserWindow; 70 | } 71 | } 72 | 73 | // Make sure that discord loads this, thanks ven 74 | Object.defineProperty(BrowserWindow, "name", { value: "BrowserWindow" }); 75 | 76 | const electronPath = require.resolve("electron"); 77 | delete require.cache[electronPath]?.exports; 78 | require.cache[electronPath].exports = { 79 | ...electron, 80 | BrowserWindow, 81 | }; 82 | 83 | const devToolsKey = "DANGEROUS_ENABLE_DEVTOOLS_ONLY_ENABLE_IF_YOU_KNOW_WHAT_YOURE_DOING"; 84 | if (!global.appSettings) global.appSettings = {}; 85 | if (!global.appSettings?.settings) global.appSettings.settings = {}; 86 | const oldSettings = global.appSettings.settings; 87 | global.appSettings.settings = new Proxy(oldSettings, { 88 | get(target, prop) { 89 | if (prop === devToolsKey) return true; 90 | return target[prop]; 91 | }, 92 | set(target, prop, value) { 93 | if (prop === devToolsKey) return true; 94 | target[prop] = value; 95 | return true; 96 | }, 97 | }); 98 | 99 | //# sourceURL=aero:main 100 | -------------------------------------------------------------------------------- /packages/main/ipc.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | import { ipcMain, shell, app } from "electron"; 20 | 21 | import path from "node:path"; 22 | import fs from "node:fs"; 23 | 24 | import * as ipc from "~/common/ipc"; 25 | import { updateSettings } from "./util/settings"; 26 | 27 | export const dataDirectory = path.join(app.getPath("appData"), "aero"); 28 | 29 | process.env.DATA_PATH = dataDirectory; 30 | 31 | if (!fs.existsSync(dataDirectory)) fs.mkdirSync(dataDirectory); 32 | if (!fs.existsSync(path.join(dataDirectory, "snippets"))) fs.mkdirSync(path.join(dataDirectory, "snippets")); 33 | if (!fs.existsSync(path.join(dataDirectory, "plugins"))) fs.mkdirSync(path.join(dataDirectory, "plugins")); 34 | if (!fs.existsSync(path.join(dataDirectory, "themes"))) fs.mkdirSync(path.join(dataDirectory, "themes")); 35 | if (!fs.existsSync(path.join(dataDirectory, "data"))) fs.mkdirSync(path.join(dataDirectory, "data")); 36 | if (!fs.existsSync(path.join(dataDirectory, "settings.json"))) 37 | fs.writeFileSync(path.join(dataDirectory, "settings.json"), "{}"); 38 | 39 | export default () => { 40 | ipcMain.handle(ipc.OPEN_SNIPPET_DIRECTORY, () => { 41 | shell.openPath(path.join(dataDirectory, "snippets")); 42 | }); 43 | 44 | ipcMain.handle(ipc.OPEN_PLUGIN_DIRECTORY, () => { 45 | shell.openPath(path.join(dataDirectory, "plugins")); 46 | }); 47 | 48 | ipcMain.handle(ipc.OPEN_THEME_DIRECTORY, () => { 49 | shell.openPath(path.join(dataDirectory, "themes")); 50 | }); 51 | 52 | ipcMain.handle(ipc.OPEN_DATA_DIRECTORY, () => { 53 | shell.openPath(path.join(dataDirectory, "data")); 54 | }); 55 | 56 | ipcMain.handle(ipc.OPEN_FILE, (_, p: string) => { 57 | if (p.includes("..")) return; 58 | 59 | shell.openPath(path.join(dataDirectory, p)); 60 | }); 61 | 62 | ipcMain.handle(ipc.SAVE_SETTINGS, (_, pair) => { 63 | updateSettings(pair); 64 | }); 65 | 66 | ipcMain.handle(ipc.RELAUNCH, () => { 67 | app.relaunch(); 68 | app.exit(); 69 | }); 70 | }; 71 | -------------------------------------------------------------------------------- /packages/main/util/crx.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | /** 20 | * Taken from https://npmjs.com/package/unzip-crx-3 but only included part for bundle reasons 21 | * All credit goes to the original author(s) of the package 22 | * 23 | * https://github.com/peerigon/unzip-crx 24 | */ 25 | export default (buf) => { 26 | function calcLength(a, b, c, d) { 27 | let length = 0; 28 | 29 | length += a << 0; 30 | length += b << 8; 31 | length += c << 16; 32 | length += (d << 24) >>> 0; 33 | return length; 34 | } 35 | 36 | // 50 4b 03 04 37 | // This is actually a zip file 38 | if (buf[0] === 80 && buf[1] === 75 && buf[2] === 3 && buf[3] === 4) { 39 | return buf; 40 | } 41 | 42 | // 43 72 32 34 (Cr24) 43 | if (buf[0] !== 67 || buf[1] !== 114 || buf[2] !== 50 || buf[3] !== 52) { 44 | throw new Error("Invalid header: Does not start with Cr24"); 45 | } 46 | 47 | // 02 00 00 00 48 | // or 49 | // 03 00 00 00 50 | const isV3 = buf[4] === 3; 51 | const isV2 = buf[4] === 2; 52 | 53 | if ((!isV2 && !isV3) || buf[5] || buf[6] || buf[7]) { 54 | throw new Error("Unexpected crx format version number."); 55 | } 56 | 57 | if (isV2) { 58 | const publicKeyLength = calcLength(buf[8], buf[9], buf[10], buf[11]); 59 | const signatureLength = calcLength(buf[12], buf[13], buf[14], buf[15]); 60 | 61 | // 16 = Magic number (4), CRX format version (4), lengths (2x4) 62 | const zipStartOffset = 16 + publicKeyLength + signatureLength; 63 | 64 | return buf.slice(zipStartOffset, buf.length); 65 | } 66 | // v3 format has header size and then header 67 | const headerSize = calcLength(buf[8], buf[9], buf[10], buf[11]); 68 | const zipStartOffset = 12 + headerSize; 69 | 70 | return buf.slice(zipStartOffset, buf.length); 71 | }; 72 | -------------------------------------------------------------------------------- /packages/main/util/fetch.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | import https from "node:https"; 20 | 21 | const httpOptions = { 22 | headers: { 23 | "User-Agent": "Aero (https://github.com/aero-mod/aero)", 24 | }, 25 | }; 26 | 27 | export const get = (url: string): Promise => { 28 | return new Promise((resolve, reject) => { 29 | https 30 | .get(url, httpOptions, (res) => { 31 | if (res.statusCode > 399) return reject(res.statusMessage); 32 | 33 | const chunks: Buffer[] = []; 34 | 35 | res.on("error", reject); 36 | res.on("data", (chunk) => chunks.push(chunk)); 37 | res.on("end", () => resolve(Buffer.concat(chunks))); 38 | }) 39 | .on("error", reject); 40 | }); 41 | }; 42 | -------------------------------------------------------------------------------- /packages/main/util/settings.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | import { app } from "electron"; 20 | 21 | import { Settings } from "~/renderer/api/settings/useSettings"; 22 | 23 | import path from "node:path"; 24 | import fs from "node:fs"; 25 | 26 | export const dataDirectory = path.join(app.getPath("appData"), "aero"); 27 | 28 | const SETTINGS_FILE = path.join(dataDirectory, "settings.json"); 29 | 30 | export const readSettings = (): Partial => { 31 | try { 32 | return JSON.parse(fs.readFileSync(SETTINGS_FILE, "utf-8")); 33 | } catch { 34 | return {}; 35 | } 36 | }; 37 | 38 | export const updateSettings = (newPair: { 39 | [key in keyof Settings]: Settings[key]; 40 | }) => { 41 | fs.writeFileSync( 42 | SETTINGS_FILE, 43 | JSON.stringify( 44 | { 45 | ...readSettings(), 46 | ...newPair, 47 | }, 48 | null, 49 | 4 50 | ) 51 | ); 52 | }; 53 | -------------------------------------------------------------------------------- /packages/preload/util.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | export const dirname = (path: string): string => { 20 | return path.split("/").slice(0, -1).join("/"); 21 | }; 22 | -------------------------------------------------------------------------------- /packages/renderer/aero.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | import { 20 | Filters, 21 | getModule, 22 | waitFor, 23 | globalPromise, 24 | common, 25 | __webpack_require__, 26 | getByDisplayName, 27 | getByKeys, 28 | getByMangled, 29 | getByStore, 30 | getByStrings, 31 | } from "./api/webpack"; 32 | import { openDocumentationPageWithString, openByName } from "./api/docs"; 33 | import { showModal, showToast, removeToast } from "./api/notifications"; 34 | import { initialise } from "./ui/components/Toast"; 35 | import * as badges from "./api/attachments/badges"; 36 | import * as components from "./ui/components"; 37 | import * as menu from "./api/patcher/menu"; 38 | import { plugins } from "./api/plugins"; 39 | import { proxy } from "./api/settings"; 40 | import { themes } from "./api/themes"; 41 | import patcher from "./api/patcher"; 42 | import * as dom from "./api/dom"; 43 | 44 | export default { 45 | settings: proxy, 46 | dom, 47 | patcher, 48 | components, 49 | plugins, 50 | themes, 51 | badges, 52 | docs: { 53 | openByName, 54 | openDocumentationPageWithString, 55 | }, 56 | notifications: { 57 | showModal, 58 | showToast, 59 | removeToast, 60 | _initialiseToasts: initialise, 61 | }, 62 | contextMenu: { 63 | patch: menu.patch, 64 | unpatch: menu.unpatch, 65 | _patchContext: menu._patchContext, 66 | }, 67 | webpack: { 68 | get: getModule, 69 | getByDisplayName, 70 | getByKeys, 71 | getByMangled, 72 | getByStore, 73 | getByStrings, 74 | waitFor, 75 | Filters, 76 | common, 77 | globalPromise, 78 | get require() { 79 | return __webpack_require__; 80 | }, 81 | }, 82 | }; 83 | -------------------------------------------------------------------------------- /packages/renderer/api/attachments/badges.scss: -------------------------------------------------------------------------------- 1 | [class^="profileBadges"]:has(.aero-badge) { 2 | padding: 4px; 3 | } 4 | 5 | .aero-badge { 6 | &.format { 7 | width: 22px; 8 | height: 22px; 9 | display: flex; 10 | align-items: center; 11 | justify-content: center; 12 | } 13 | 14 | &.aero-interactive { 15 | cursor: pointer; 16 | } 17 | 18 | svg, 19 | img { 20 | width: 13px; 21 | height: 13px; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /packages/renderer/api/attachments/badges.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | import type React from "react"; 20 | 21 | import "./badges.scss"; 22 | 23 | export type PartialUser = { 24 | bot: boolean; 25 | id: string; 26 | username: string; 27 | globalName?: string; 28 | discriminator: string; 29 | }; 30 | 31 | export type ProfileBadge = { 32 | predicate?: (user: PartialUser) => boolean; 33 | tooltipText?: string; 34 | onClick?: (event: React.MouseEvent, user: PartialUser) => void; 35 | /** 36 | * Component to render on the user's profile. 37 | */ 38 | component?: (props: { user: PartialUser }) => React.JSX.Element; 39 | /** 40 | * URL to the image to render on the user's profile. 41 | */ 42 | url?: string; 43 | }; 44 | 45 | const badges = new Set(); 46 | 47 | export const addProfileBadge = (badge: ProfileBadge) => { 48 | badges.add(badge); 49 | }; 50 | 51 | export const removeProfileBadge = (badge: ProfileBadge) => { 52 | badges.delete(badge); 53 | }; 54 | 55 | export const _getProfileBadges = (user: PartialUser) => { 56 | return Array.from(badges).filter((badge) => { 57 | if (badge.predicate) { 58 | return badge.predicate(user); 59 | } 60 | 61 | return true; 62 | }); 63 | }; 64 | -------------------------------------------------------------------------------- /packages/renderer/api/docs/index.scss: -------------------------------------------------------------------------------- 1 | .docs-page { 2 | color: var(--text-normal); 3 | padding: 4rem; 4 | user-select: text; 5 | position: relative; 6 | overflow-y: auto; 7 | 8 | &::-webkit-scrollbar { 9 | width: 10px; 10 | 11 | &-track { 12 | background: var(--scrollbar-auto-track); 13 | } 14 | 15 | &-thumb { 16 | background: var(--scrollbar-auto-thumb); 17 | border-radius: 10px; 18 | } 19 | } 20 | 21 | .absolute-close-button { 22 | position: absolute; 23 | top: 0; 24 | right: 0; 25 | padding-right: 4rem; 26 | padding-top: 4rem; 27 | } 28 | 29 | > * { 30 | max-width: min(100%, 60rem); 31 | } 32 | 33 | h1:first-of-type { 34 | font-size: 4rem; 35 | line-height: 1; 36 | font-weight: 800; 37 | font-family: var(--font-headline); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /packages/renderer/api/docs/index.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | import { LayerActions } from "../webpack/common/actions"; 20 | import markdown from "~/renderer/util/markdown"; 21 | import { c } from "~/renderer/util/classes"; 22 | import { getModule } from "../webpack"; 23 | 24 | import CloseButton from "~/renderer/ui/components/Modal/CloseButton"; 25 | 26 | import plugin from "~content/docs/plugins/index.md"; 27 | 28 | import "./index.scss"; 29 | 30 | export const openDocumentationPageWithString = (content: string) => { 31 | LayerActions.pushLayer(() => ( 32 |
33 |
34 | LayerActions.popLayer()} /> 35 |
36 | {markdown(content, false, { 37 | allowHeading: true, 38 | allowLinks: true, 39 | allowList: true, 40 | })} 41 |
42 | )); 43 | }; 44 | 45 | export const openByName = (name: "plugin") => { 46 | switch (name) { 47 | case "plugin": 48 | openDocumentationPageWithString(plugin); 49 | break; 50 | default: 51 | break; 52 | } 53 | }; 54 | -------------------------------------------------------------------------------- /packages/renderer/api/dom/elements.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | export const head = document.createElement("aero-head"); 20 | export const body = document.createElement("aero-body"); 21 | 22 | export const themes = document.createElement("aero-themes"); 23 | export const styles = document.createElement("aero-styles"); 24 | export const snippets = document.createElement("aero-snippets"); 25 | 26 | head.append(themes, snippets, styles); 27 | 28 | window.addEventListener("DOMContentLoaded", () => { 29 | document.head.append(head); 30 | document.body.append(body); 31 | }); 32 | 33 | export const injectStyles = (id: string, css: string) => { 34 | const style = document.createElement("style"); 35 | 36 | style.id = id; 37 | style.textContent = window.aeroNative.external.transpileCSS(css, `${id}.css`).outputText; 38 | 39 | styles.append(style); 40 | }; 41 | 42 | export const removeStyles = (id: string) => { 43 | const style = document.getElementById(id); 44 | 45 | if (!style) return; 46 | 47 | style.remove(); 48 | }; 49 | -------------------------------------------------------------------------------- /packages/renderer/api/dom/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | import { sleep } from "~/renderer/util/time"; 20 | 21 | export * from "./elements"; 22 | 23 | export const h = ( 24 | type: T, 25 | props?: Partial<{ 26 | [key in keyof HTMLElementTagNameMap[T]]: unknown; 27 | }>, 28 | children?: HTMLElement 29 | ) => { 30 | const element = document.createElement(type); 31 | 32 | for (const [key, value] of Object.entries(props || {})) { 33 | element[key] = value; 34 | } 35 | 36 | element.append(children); 37 | 38 | return element; 39 | }; 40 | 41 | export const esm = async (str: TemplateStringsArray) => { 42 | const script = h("script"); 43 | 44 | const rand = (Math.random() * 100).toString(16).substring(7); 45 | 46 | script.type = "module"; 47 | script.async = true; 48 | script.innerHTML = `const $return = (val) => { window["${rand}"] = val; }; ${str}`; 49 | 50 | document.body.appendChild(script); 51 | 52 | while (!window.hasOwnProperty(rand)) { 53 | await sleep(1); 54 | } 55 | 56 | const ret = window[rand]; 57 | 58 | delete window[rand]; 59 | 60 | return ret; 61 | }; 62 | -------------------------------------------------------------------------------- /packages/renderer/api/notifications/Generic.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | import { ModalRoot, ModalHeader, ModalFooter, ModalContent, ModalSize } from "~/renderer/ui/components/Modal"; 20 | import { ButtonColor, ButtonLook, ButtonSize } from "~/renderer/ui/components/Button"; 21 | import FormTitle from "~/renderer/ui/components/FormTitle"; 22 | import { Button } from "~/renderer/ui/components"; 23 | import markdown from "~/renderer/util/markdown"; 24 | 25 | export default (props: { 26 | content: string; 27 | title: string; 28 | danger?: boolean; 29 | confirmText?: string; 30 | cancelText?: string; 31 | modalSize?: ModalSize; 32 | onConfirm?: () => void; 33 | onCancel?: () => void; 34 | rest: { 35 | onClose: () => void; 36 | [key: string]: unknown; 37 | }; 38 | }) => ( 39 | 40 | 41 | 42 | {props.title} 43 | 44 | 45 | {markdown(props.content)} 46 | 47 | 58 | 70 | 71 | 72 | ); 73 | -------------------------------------------------------------------------------- /packages/renderer/api/notifications/index.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | import { _MEGA_MODULE_DO_NOT_USE_OR_YOU_WILL_BE_FIRED } from "../webpack/common/components"; 20 | import { ToastProps, registry, toastSetter } from "~/renderer/ui/components/Toast"; 21 | import { ModalSize, ModalRoot } from "~/renderer/ui/components/Modal"; 22 | import Generic from "./Generic"; 23 | 24 | import { RELAUNCH } from "~/common/ipc"; 25 | 26 | export const showReloadDialog = (relaunch?: boolean) => { 27 | _MEGA_MODULE_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.openModal((props: { onClose: () => void; [key: string]: unknown }) => ( 28 | <_MEGA_MODULE_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.Dialog 29 | className="focus-lock" 30 | role="dialog" 31 | aria-labelledby=":re:" 32 | > 33 | { 39 | if (relaunch) { 40 | window.aeroNative.ipc.invoke(RELAUNCH); 41 | } 42 | 43 | window.location.reload(); 44 | }} 45 | confirmText="Reload" 46 | cancelText="Later" 47 | modalSize={ModalSize.Small} 48 | danger 49 | rest={props} 50 | /> 51 | 52 | )); 53 | }; 54 | 55 | export const showModal = (children: (onClose: () => void) => React.ReactNode, size?: ModalSize) => { 56 | _MEGA_MODULE_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.openModal((props: { onClose: () => void; [key: string]: unknown }) => ( 57 | <_MEGA_MODULE_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.Dialog 58 | className="focus-lock" 59 | role="dialog" 60 | aria-labelledby=":re:" 61 | > 62 | 63 | {children(props.onClose)} 64 | 65 | 66 | )); 67 | }; 68 | 69 | const toasts = new Map(); 70 | 71 | let i = 0; 72 | 73 | export const showToast = (props: ToastProps) => { 74 | toasts.set(i++, props); 75 | 76 | if (toastSetter) { 77 | toastSetter((prev) => [ 78 | ...prev, 79 | { 80 | ...props, 81 | id: i - 1, 82 | }, 83 | ]); 84 | } 85 | 86 | return i - 1; 87 | }; 88 | 89 | export const removeToast = (id: number) => { 90 | registry.get(id)?.(true); 91 | 92 | setTimeout(() => { 93 | toasts.delete(id); 94 | 95 | if (toastSetter) { 96 | toastSetter((prev) => prev.filter((t) => t.id !== id)); 97 | 98 | // FIXME: somehow this also removes the last toast in the list? 99 | } 100 | }, 1000); 101 | }; 102 | -------------------------------------------------------------------------------- /packages/renderer/api/patcher/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | export { default as default } from "./classic"; 20 | 21 | export * as webpack from "./webpack"; 22 | -------------------------------------------------------------------------------- /packages/renderer/api/patcher/menu.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | export const contextMenuPatches: Record void }[]> = 20 | {}; 21 | 22 | export const patch = (pluginId: string, navId: string, callback: (children: React.ReactNode) => void) => { 23 | contextMenuPatches[pluginId] ??= []; 24 | 25 | contextMenuPatches[pluginId].push({ navId, callback }); 26 | }; 27 | 28 | export const unpatch = (pluginId: string) => { 29 | delete contextMenuPatches[pluginId]; 30 | }; 31 | 32 | export const _patchContext = (props: { navId: string; children: React.ReactNode }) => { 33 | for (const pluginId of Object.keys(contextMenuPatches)) { 34 | for (const { navId, callback } of contextMenuPatches[pluginId]) { 35 | if (navId !== props.navId) continue; 36 | 37 | callback(props.children); 38 | } 39 | } 40 | }; 41 | -------------------------------------------------------------------------------- /packages/renderer/api/plugins/actions.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | import { AeroPlugin } from "./types"; 20 | import settings from "../settings"; 21 | 22 | export const togglePlugin = (plugin: AeroPlugin) => { 23 | settings.enabledAddons = { 24 | ...window.aero.settings.enabledAddons, 25 | plugins: { 26 | ...window.aero.settings.enabledAddons.plugins, 27 | [plugin.id]: !window.aero.settings.enabledAddons.plugins[plugin.id], 28 | }, 29 | }; 30 | }; 31 | 32 | export const startPlugin = (plugin: AeroPlugin) => { 33 | plugin.start?.(); 34 | }; 35 | 36 | export const stopPlugin = (plugin: AeroPlugin) => { 37 | plugin.stop?.(); 38 | }; 39 | -------------------------------------------------------------------------------- /packages/renderer/api/plugins/external.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | import { originalConsole } from "~/renderer/util/polyfill"; 20 | import logger from "~/common/logger"; 21 | 22 | const fs = window.aeroNative.fileSystem; 23 | 24 | export const wrapJSLike = (filename: string, code: string) => { 25 | const fn = new Function( 26 | "require", 27 | "module", 28 | "exports", 29 | "console", 30 | ` 31 | ${code} 32 | 33 | if (typeof module.exports === "function") { 34 | return module.exports(); 35 | } 36 | 37 | if (typeof module.exports === "object") { 38 | return module.exports; 39 | } 40 | 41 | return exports; 42 | 43 | //# sourceURL=${filename} 44 | `.trim() 45 | ); 46 | 47 | try { 48 | const res = fn(window.require, {}, {}, originalConsole); 49 | 50 | return res?.default || res; 51 | } catch (e) { 52 | logger.error("Failed to run javascript-like expression: ", e); 53 | } 54 | }; 55 | 56 | export const loadExternalPlugins = () => { 57 | const plugins = []; 58 | 59 | const pluginFiles = fs.readdir("/plugins"); 60 | 61 | for (const plugin of pluginFiles) { 62 | const pluginPath = `/plugins/${plugin}`; 63 | 64 | if (fs.readFile(pluginPath)) { 65 | const plugin = fs.readFile(pluginPath); 66 | 67 | if ( 68 | !pluginPath.endsWith(".ts") && 69 | !pluginPath.endsWith(".tsx") && 70 | !pluginPath.endsWith(".js") && 71 | !pluginPath.endsWith(".jsx") 72 | ) 73 | continue; 74 | 75 | if (!pluginPath.endsWith(".d.ts")) { 76 | const { outputText } = window.aeroNative.external.transpile(plugin, pluginPath.split("/").pop(), { 77 | module: 1, // CommonJS 78 | target: 99, // ESNext 79 | jsx: 2, // React 80 | sourceMap: true, 81 | inlineSourceMap: true, 82 | jsxFactory: "window.aero.webpack.common.React.createElement", 83 | jsxFragmentFactory: "window.aero.webpack.common.React.Fragment", 84 | }); 85 | 86 | plugins.push(wrapJSLike(pluginPath.split("/").pop(), outputText)); 87 | } 88 | } 89 | } 90 | 91 | return plugins; 92 | }; 93 | -------------------------------------------------------------------------------- /packages/renderer/api/plugins/import.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | // allows plugins to dynamically import modules without the typescript compiler abstracting it away 20 | export const remoteImport = async (url: string): Promise => { 21 | if (!url.startsWith("https://")) throw new Error("Dynamicly imported URL must start with https://"); 22 | 23 | const response = await import(url); 24 | 25 | return response; 26 | }; 27 | -------------------------------------------------------------------------------- /packages/renderer/api/plugins/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | import { loadExternalPlugins } from "./external"; 20 | export { pluginSettings } from "./settings"; 21 | import { startPlugin } from "./actions"; 22 | import * as builtin from "./builtin"; 23 | 24 | export * from "./registry"; 25 | export * from "./import"; 26 | 27 | import { registerPlugin } from "./registry"; 28 | 29 | export default async () => { 30 | const external = loadExternalPlugins(); 31 | 32 | for (const plugin of external) { 33 | registerPlugin(plugin); 34 | } 35 | }; 36 | 37 | export const injectBuiltin = () => { 38 | for (const plugin of Object.values(builtin)) { 39 | registerPlugin(plugin); 40 | 41 | startPlugin(plugin); 42 | } 43 | }; 44 | -------------------------------------------------------------------------------- /packages/renderer/api/plugins/settings.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | import { localStorage } from "~/renderer/util/polyfill"; 20 | import { plugins } from "./registry"; 21 | 22 | export const pluginSettings = (pluginID: string) => { 23 | return new Proxy( 24 | {}, 25 | { 26 | get(_, key: string) { 27 | const plugin = plugins[pluginID]; 28 | 29 | if (!plugin) return null; 30 | 31 | const storage = localStorage.getItem(`aero:plugin:${pluginID}`); 32 | 33 | if (!storage) return plugin.settings?.find((setting) => setting.id === key)?.initialValue ?? null; 34 | 35 | const parsed = JSON.parse(storage); 36 | 37 | if (parsed[key] === undefined) 38 | return plugin.settings?.find((setting) => setting.id === key)?.initialValue ?? null; 39 | 40 | return parsed[key]; 41 | }, 42 | set(_, key: string, value: unknown) { 43 | const storage = localStorage.getItem(`aero:plugin:${pluginID}`); 44 | 45 | if (!storage) { 46 | localStorage.setItem(`aero:plugin:${pluginID}`, JSON.stringify({ [key]: value })); 47 | 48 | return true; 49 | } 50 | 51 | const parsed = JSON.parse(storage); 52 | 53 | parsed[key] = value; 54 | 55 | localStorage.setItem(`aero:plugin:${pluginID}`, JSON.stringify(parsed)); 56 | 57 | return true; 58 | }, 59 | deleteProperty(_, key: string) { 60 | const storage = localStorage.getItem(`aero:plugin:${pluginID}`); 61 | 62 | if (!storage) return null; 63 | 64 | const parsed = JSON.parse(storage); 65 | 66 | delete parsed[key]; 67 | 68 | localStorage.setItem(`aero:plugin:${pluginID}`, JSON.stringify(parsed)); 69 | 70 | return true; 71 | }, 72 | } 73 | ); 74 | }; 75 | -------------------------------------------------------------------------------- /packages/renderer/api/settings/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | import { localStorage } from "~/renderer/util/polyfill"; 20 | import type { Settings } from "./useSettings"; 21 | import { SAVE_SETTINGS } from "~/common/ipc"; 22 | 23 | const listeners = new Set<[(settings: Settings) => void, keyof Settings]>(); 24 | 25 | let settings: Settings = { 26 | debugLogs: false, 27 | loadThirdParty: true, 28 | vibrancy: false, 29 | themeURLS: "", 30 | enabledAddons: { 31 | themes: {}, 32 | plugins: {}, 33 | }, 34 | }; 35 | 36 | export const saveSettings = (_settings: Partial, noEmit?: boolean) => { 37 | const prev = { ...settings }; 38 | 39 | settings = { 40 | ...settings, 41 | ..._settings, 42 | }; 43 | 44 | localStorage.setItem( 45 | "aero-settings", 46 | JSON.stringify({ 47 | ...settings, 48 | ..._settings, 49 | }) 50 | ); 51 | 52 | if (noEmit) return; 53 | 54 | for (const [listener, setting] of listeners) { 55 | if (setting === undefined || prev[setting] !== settings[setting]) { 56 | listener(settings); 57 | } 58 | } 59 | }; 60 | 61 | export const observeSettings = (callback: (settings: Settings) => void, setting?: keyof Settings) => { 62 | listeners.add([callback, setting]); 63 | }; 64 | 65 | export const loadSettings = () => { 66 | const prev = { ...settings }; 67 | 68 | settings = JSON.parse(localStorage.getItem("aero-settings") || "{}"); 69 | 70 | for (const key in settings) { 71 | if (key === "_update") continue; 72 | 73 | proxy[key] = settings[key]; 74 | } 75 | 76 | for (const [listener, setting] of listeners) { 77 | if (setting === undefined || prev[setting] !== settings[setting]) { 78 | listener(settings); 79 | } 80 | } 81 | 82 | return settings; 83 | }; 84 | 85 | export const proxy = new Proxy(settings, { 86 | set: (_target, key: T, value: Settings[T]) => { 87 | saveSettings({ 88 | [key as keyof Settings]: value, 89 | }); 90 | 91 | Reflect.set(_target, key, value); 92 | 93 | window.aeroNative.ipc.invoke(SAVE_SETTINGS, settings); 94 | 95 | return true; 96 | }, 97 | get: (target, key, receiver) => { 98 | return Reflect.get(target, key, receiver); 99 | }, 100 | deleteProperty: (target, key: keyof Settings) => { 101 | saveSettings({ 102 | [key]: undefined, 103 | }); 104 | 105 | return true; 106 | }, 107 | }); 108 | 109 | export default proxy; 110 | -------------------------------------------------------------------------------- /packages/renderer/api/settings/useSettings.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | import { reapply, isStyle } from "../snippets"; 20 | import { React } from "../webpack/common"; 21 | 22 | const fs = window.aeroNative.fileSystem; 23 | 24 | export interface Settings { 25 | debugLogs: boolean; 26 | loadThirdParty: boolean; 27 | themeURLS: string; 28 | vibrancy: boolean; 29 | enabledAddons: { 30 | themes: { 31 | [key: string]: boolean; 32 | }; 33 | plugins: { 34 | [key: string]: boolean; 35 | }; 36 | }; 37 | } 38 | 39 | export default (): [() => Settings, (newSettings: Partial) => void] => { 40 | const [_settings, setSettings] = React.useState(window.aero.settings); 41 | 42 | return [ 43 | () => _settings, 44 | (newSettings: Partial) => { 45 | setSettings({ ..._settings, ...newSettings }); 46 | 47 | for (const key in newSettings) { 48 | if (key === "_update") continue; 49 | 50 | window.aero.settings[key] = newSettings[key]; 51 | } 52 | }, 53 | ]; 54 | }; 55 | 56 | export const useSnippets = (): [ 57 | () => { 58 | [key: string]: string; 59 | } 60 | ] => { 61 | const files = fs.readdir("/snippets"); 62 | 63 | const [_snippetFiles] = React.useState(files); 64 | 65 | const proxy = new Proxy( 66 | {}, 67 | { 68 | get(_, prop: string) { 69 | if (prop === "_files") return _snippetFiles; 70 | 71 | return fs.readFile(`/snippets/${prop}`); 72 | }, 73 | set(_, prop: string, value: string) { 74 | fs.writeFile(`/snippets/${prop}`, value); 75 | 76 | if (isStyle(prop)) reapply(prop); 77 | 78 | return true; 79 | }, 80 | deleteProperty(_, prop: string) { 81 | fs.unlinkFile(`/snippets/${prop}`); 82 | 83 | if (isStyle(prop)) reapply(prop); 84 | 85 | return true; 86 | }, 87 | } 88 | ); 89 | 90 | return [() => proxy]; 91 | }; 92 | -------------------------------------------------------------------------------- /packages/renderer/api/stores.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | import settings, { observeSettings } from "./settings"; 20 | import { React } from "./webpack/common"; 21 | 22 | class Store< 23 | T = { 24 | [key: string]: unknown; 25 | } 26 | > { 27 | state: T | null; 28 | 29 | #listeners: Set<(value: T) => void> = new Set(); 30 | 31 | constructor(setup: () => T) { 32 | this.state = setup(); 33 | } 34 | 35 | emit() { 36 | this.#listeners.forEach((listener) => listener(this.state)); 37 | } 38 | 39 | setState(newState: (prevState: T) => T) { 40 | const state = this.state; 41 | 42 | this.state = newState(state); 43 | 44 | this.emit(); 45 | } 46 | 47 | addListener(listener: (value: T) => void) { 48 | this.#listeners.add(listener); 49 | } 50 | 51 | removeListener(listener: () => void) { 52 | this.#listeners.delete(listener); 53 | } 54 | } 55 | 56 | export const EnabledAddonStore = new Store<{ 57 | themes: { 58 | [key: string]: boolean; 59 | }; 60 | plugins: { 61 | [key: string]: boolean; 62 | }; 63 | }>(() => { 64 | const data = settings.enabledAddons; 65 | 66 | return data; 67 | }); 68 | 69 | observeSettings((settings) => { 70 | EnabledAddonStore.setState((state) => ({ 71 | ...state, 72 | ...settings.enabledAddons, 73 | })); 74 | }, "enabledAddons"); 75 | 76 | export const useStore = (store: Store) => { 77 | const [, forceUpdate] = React.useState(); 78 | 79 | React.useEffect(() => { 80 | const listener = () => forceUpdate({}); 81 | 82 | store.addListener(listener); 83 | 84 | return () => store.removeListener(listener); 85 | }, [store]); 86 | 87 | return store.state; 88 | }; 89 | -------------------------------------------------------------------------------- /packages/renderer/api/themes/actions.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | import { h, themes } from "~/renderer/api/dom"; 20 | import { loadCSS } from "./external"; 21 | import settings from "../settings"; 22 | import { Theme } from "./types"; 23 | 24 | const escape = (str: string) => `aero-t-${str.replace(/\W/g, "-")}`; 25 | 26 | const cssCache = new Map(); 27 | 28 | export const toggleTheme = (theme: Theme) => { 29 | settings.enabledAddons = { 30 | ...window.aero.settings.enabledAddons, 31 | themes: { 32 | ...window.aero.settings.enabledAddons.themes, 33 | [theme.id]: !window.aero.settings.enabledAddons.themes[theme.id], 34 | }, 35 | }; 36 | }; 37 | 38 | export const startTheme = (theme: Theme) => { 39 | const style = h("style"); 40 | 41 | style.id = escape(theme.id); 42 | 43 | if (cssCache.has(theme.id)) { 44 | style.innerHTML = cssCache.get(theme.id); 45 | } else { 46 | const css = loadCSS(theme); 47 | 48 | style.innerHTML = css; 49 | 50 | cssCache.set(theme.id, css); 51 | } 52 | 53 | themes.appendChild(style); 54 | 55 | document.body.classList.add(escape(theme.id)); 56 | }; 57 | 58 | export const stopTheme = (theme: Theme) => { 59 | const style = document.getElementById(escape(theme.id)); 60 | 61 | if (style) style.remove(); 62 | 63 | document.body.classList.remove(escape(theme.id)); 64 | }; 65 | 66 | export const enableRemoteTheme = async (url: string) => { 67 | const style = `@import url("${url}");`; 68 | 69 | const id = `remote-${escape(url.split("/").pop())}`; 70 | 71 | const styleEl = h("style"); 72 | 73 | styleEl.id = id; 74 | 75 | styleEl.innerHTML = style; 76 | 77 | themes.appendChild(styleEl); 78 | }; 79 | 80 | export const disableRemoteTheme = (url: string) => { 81 | const style = document.getElementById(`remote-${escape(url.split("/").pop())}`); 82 | 83 | if (style) style.remove(); 84 | }; 85 | -------------------------------------------------------------------------------- /packages/renderer/api/themes/external.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | import { wrapJSLike } from "../plugins/external"; 20 | import { scripts } from "../snippets"; 21 | import { Theme } from "./types"; 22 | 23 | const path = window.aeroNative.fileSystem.path; 24 | const fs = window.aeroNative.fileSystem; 25 | 26 | const possibleIndexes = (path: string) => { 27 | const indexes = []; 28 | 29 | for (const script of scripts) { 30 | indexes.push(`${path}/index.${script}`); 31 | } 32 | 33 | return indexes; 34 | }; 35 | 36 | export const loadExternalThemes = () => { 37 | const themes = []; 38 | 39 | const themeFiles = fs.subdirs("/themes"); 40 | 41 | for (const theme of themeFiles) { 42 | const themePath = `/themes/${theme}`; 43 | 44 | const indexes = possibleIndexes(themePath); 45 | 46 | for (const index of indexes) { 47 | if (!fs.exists(index)) continue; 48 | 49 | const content = fs.readFile(index); 50 | 51 | const { outputText } = window.aeroNative.external.transpile(content, index.split("/").pop(), { 52 | module: 1, // CommonJS 53 | target: 99, // ESNext 54 | jsx: 2, // React 55 | jsxFactory: "window.aero.webpack.common.React.createElement", 56 | jsxFragmentFactory: "window.aero.webpack.common.React.Fragment", 57 | }); 58 | 59 | const theme = wrapJSLike(index, outputText); 60 | 61 | if (theme.entrypoint) { 62 | theme.entrypoint = path.join(themePath, theme.entrypoint); 63 | } 64 | 65 | if (theme) themes.push(theme); 66 | } 67 | } 68 | 69 | return themes; 70 | }; 71 | 72 | export const loadCSS = (theme: Theme) => { 73 | const absolute = path.resolveToAbsolute(theme.entrypoint); 74 | 75 | const index = fs.readFile(theme.entrypoint); 76 | 77 | const { outputText, sourceMap } = window.aeroNative.external.transpileCSS(index, absolute); 78 | 79 | const codeWithSource = 80 | outputText + 81 | `\n\n/*# sourceURL=aero:theme */ \n/*# sourceMappingURL=data:application/json;charset=utf-8,${encodeURIComponent( 82 | JSON.stringify(sourceMap) 83 | )} */`; 84 | 85 | return codeWithSource; 86 | }; 87 | -------------------------------------------------------------------------------- /packages/renderer/api/themes/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | import { disableRemoteTheme, enableRemoteTheme, startTheme, stopTheme } from "./actions"; 20 | import { loadExternalThemes } from "./external"; 21 | import { EnabledAddonStore } from "../stores"; 22 | import { observeSettings } from "../settings"; 23 | import { Theme } from "./types"; 24 | 25 | const enabled = new Set(); 26 | 27 | export const themes: Record = {}; 28 | export const remoteThemes: Set = new Set(); 29 | 30 | EnabledAddonStore.addListener((val) => { 31 | for (const [t, value] of Object.entries(val.themes)) { 32 | const theme = Object.values(themes).find((tme) => { 33 | return tme.id === t; 34 | }); 35 | 36 | if (!theme) continue; 37 | 38 | if (value) { 39 | if (enabled.has(t)) continue; 40 | 41 | enabled.add(t); 42 | 43 | startTheme(theme); 44 | } 45 | 46 | if (!value) { 47 | enabled.delete(t); 48 | 49 | stopTheme(theme); 50 | } 51 | } 52 | }); 53 | 54 | observeSettings((settings) => { 55 | const urls = settings.themeURLS?.split("\n").filter((url) => url.length > 0); 56 | 57 | if (!urls) return; 58 | 59 | for (const url of [...urls, ...remoteThemes]) { 60 | if (urls.includes(url)) { 61 | if (remoteThemes.has(url)) continue; 62 | 63 | remoteThemes.add(url); 64 | 65 | enableRemoteTheme(url); 66 | } 67 | 68 | if (!urls.includes(url)) { 69 | remoteThemes.delete(url); 70 | 71 | disableRemoteTheme(url); 72 | } 73 | } 74 | }, "themeURLS"); 75 | 76 | export const validateTheme = (theme: Theme | unknown): Theme => { 77 | if (!theme) return null; 78 | 79 | if (!theme["id"]) return null; 80 | 81 | return theme as Theme; 82 | }; 83 | 84 | export const registerTheme = (theme: Theme) => { 85 | const validTheme = validateTheme(theme); 86 | 87 | if (!validTheme) throw new Error("Invalid theme, could not validate"); 88 | 89 | themes[theme.id] = validTheme; 90 | }; 91 | 92 | export default () => { 93 | const external = loadExternalThemes(); 94 | 95 | for (const theme of external) { 96 | registerTheme(theme); 97 | } 98 | }; 99 | -------------------------------------------------------------------------------- /packages/renderer/api/themes/types.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | import { Author } from "../plugins/types"; 20 | 21 | export type Theme = { 22 | id: string; 23 | name: string; 24 | entrypoint: string; 25 | description: string; 26 | author: Author | Author[]; 27 | dependencies?: string[]; 28 | color?: string; 29 | }; 30 | 31 | export const defineTheme = (theme: Theme): Theme => theme; 32 | -------------------------------------------------------------------------------- /packages/renderer/api/types.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | import { AeroPlugin } from "./plugins/types"; 20 | import { Theme } from "./themes/types"; 21 | 22 | export type Addon = Theme | AeroPlugin; 23 | -------------------------------------------------------------------------------- /packages/renderer/api/webpack/common/actions.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | import { Message } from "discord-types/general"; 20 | 21 | import type { ReactNode } from "react"; 22 | import { waitFor } from "../webpack"; 23 | import { Dispatcher } from "./misc"; 24 | 25 | export let MessageActions: { 26 | sendBotMessage: (channelId: string, content: string) => Message; 27 | }; 28 | 29 | export const LayerActions = { 30 | pushLayer: (layer: () => ReactNode) => { 31 | Dispatcher.dispatch({ 32 | type: "LAYER_PUSH", 33 | component: layer, 34 | }); 35 | }, 36 | popLayer: () => { 37 | Dispatcher.dispatch({ 38 | type: "LAYER_POP", 39 | }); 40 | }, 41 | popAllLayers: () => { 42 | Dispatcher.dispatch({ 43 | type: "LAYER_POP_ALL", 44 | }); 45 | }, 46 | }; 47 | 48 | waitFor(["sendBotMessage"]).then((md) => { 49 | MessageActions = md; 50 | }); 51 | -------------------------------------------------------------------------------- /packages/renderer/api/webpack/common/components.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | import logger from "~/common/logger"; 20 | import { Filters, waitFor } from "../webpack"; 21 | 22 | export let _MEGA_MODULE_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: { 23 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 24 | [x: string]: any; 25 | }; 26 | 27 | type ParentComponent = ( 28 | props: T & { 29 | children: JSX.Element | JSX.Element[] | ((props: { [x: string]: unknown }) => JSX.Element | JSX.Element[]); 30 | } 31 | ) => JSX.Element; 32 | 33 | /** 34 | * A Fallback component used for components aero depends on. 35 | */ 36 | const Fallback = 37 | (id: string) => 38 | ( 39 | /* eslint-disable-next-line @typescript-eslint/no-explicit-any */ 40 | props: Parameters>["0"] 41 | ) => { 42 | // to avoid circular dependency, use the window global 43 | window.aero.webpack.common.React.useEffect(() => { 44 | logger.warn( 45 | `Aero is using a fallback component instead of Discord's ${id} component. This is not recommended and may cause issues.` 46 | ); 47 | }, []); 48 | 49 | return props.children; 50 | }; 51 | 52 | export let Tooltip: 53 | | undefined 54 | | ParentComponent<{ 55 | text: string; 56 | }> = Fallback("Tooltip"); 57 | 58 | waitFor( 59 | Filters.byMangled((md) => { 60 | if (md["Colors"] && md["defaultProps"]) { 61 | return true; 62 | } 63 | 64 | return false; 65 | }) 66 | ).then((md) => { 67 | Tooltip = md; 68 | }); 69 | 70 | waitFor(["openModal", "Modal"]).then((md) => { 71 | _MEGA_MODULE_DO_NOT_USE_OR_YOU_WILL_BE_FIRED = md; 72 | }); 73 | -------------------------------------------------------------------------------- /packages/renderer/api/webpack/common/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | export * as components from "./components"; 20 | export * as actions from "./actions"; 21 | export * as stores from "./stores"; 22 | 23 | export * from "./react"; 24 | export * from "./misc"; 25 | -------------------------------------------------------------------------------- /packages/renderer/api/webpack/common/misc.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | import { FluxDispatcher } from "discord-types/other"; 20 | 21 | import { waitFor } from "../webpack"; 22 | 23 | export let Dispatcher: FluxDispatcher; 24 | export let hljs: typeof import("highlight.js"); 25 | 26 | waitFor(["subscribe", "dispatch", "register"]).then((md) => { 27 | Dispatcher = md; 28 | }); 29 | 30 | waitFor(["highlight", "getLanguage"]).then((md) => { 31 | hljs = md; 32 | }); 33 | -------------------------------------------------------------------------------- /packages/renderer/api/webpack/common/react.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | import { sleep } from "~/renderer/util/time"; 20 | import { waitFor } from "../webpack"; 21 | 22 | export let ReactSpring: typeof import("react-spring"); 23 | export let ReactDOM: typeof import("react-dom"); 24 | export let React: typeof import("react"); 25 | 26 | waitFor(["findDOMNode"], false).then((md) => { 27 | ReactDOM = md; 28 | }); 29 | 30 | waitFor(["useState"], false).then((md) => { 31 | React = md; 32 | }); 33 | 34 | waitFor(["useSpring"], false).then(async (md) => { 35 | ReactSpring = md; 36 | 37 | while (!window.aero?.notifications) { 38 | await sleep(1); 39 | } 40 | 41 | window.aero.notifications._initialiseToasts(); 42 | }); 43 | -------------------------------------------------------------------------------- /packages/renderer/api/webpack/common/stores.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | import { waitFor } from "../webpack"; 20 | 21 | import * as stores from "discord-types/stores"; 22 | 23 | export let DraftStore: 24 | | undefined 25 | | (stores.FluxStore & { 26 | getDraft: (channelId: string, draftType: number) => string; 27 | }); 28 | export let UserStore: undefined | stores.UserStore; 29 | export let GuildStore: undefined | stores.GuildStore; 30 | export let GuildMemberStore: undefined | stores.GuildMemberStore; 31 | export let ChannelStore: undefined | stores.ChannelStore; 32 | export let SelectedGuildStore: undefined | stores.SelectedGuildStore; 33 | export let SelectedChannelStore: undefined | stores.SelectedChannelStore; 34 | 35 | waitFor(["getDraft"]).then((md) => { 36 | DraftStore = md; 37 | }); 38 | 39 | waitFor(["getUser", "getUsers"]).then((md) => { 40 | UserStore = md; 41 | }); 42 | 43 | waitFor(["getGuild", "getGuildCount"]).then((md) => { 44 | GuildStore = md; 45 | }); 46 | 47 | waitFor(["getMember", "getMembers"]).then((md) => { 48 | GuildMemberStore = md; 49 | }); 50 | 51 | waitFor(["getChannel", "hasChannel"]).then((md) => { 52 | ChannelStore = md; 53 | }); 54 | 55 | waitFor(["getGuildId", "getLastSelectedGuildId"]).then((md) => { 56 | SelectedGuildStore = md; 57 | }); 58 | 59 | waitFor(["getChannelId", "getLastSelectedChannelId"]).then((md) => { 60 | SelectedChannelStore = md; 61 | }); 62 | -------------------------------------------------------------------------------- /packages/renderer/api/webpack/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | export * as common from "./common"; 20 | export * from "./webpack"; 21 | -------------------------------------------------------------------------------- /packages/renderer/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | import { globalPromise } from "./api/webpack"; 20 | 21 | import { definePlugin, defineVencordPlugin, SettingsItemType } from "./api/plugins/types"; 22 | import plugins, { injectBuiltin, pluginSettings, remoteImport } from "./api/plugins"; 23 | import polyfill, { localStorage } from "./util/polyfill"; 24 | import * as badges from "./api/attachments/badges"; 25 | import { defineTheme } from "./api/themes/types"; 26 | import * as components from "./ui/components"; 27 | import previewBanner from "./util/preview"; 28 | import * as webpack from "./api/webpack"; 29 | import snippets from "./api/snippets"; 30 | import logger from "../common/logger"; 31 | import settings from "./ui/settings"; 32 | import themes from "./api/themes"; 33 | import * as dom from "./api/dom"; 34 | import aero from "./aero"; 35 | 36 | import aeroSettings from "./api/settings"; 37 | 38 | import "./util.scss"; 39 | 40 | const wrap = unknown | Promise>(fn: T) => { 41 | try { 42 | // @ts-expect-error yes, i know 43 | return fn(); 44 | } catch (e) { 45 | logger.error(e); 46 | } 47 | }; 48 | 49 | // @ts-expect-error no typescript, this is not NodeRequire 50 | window.require = (id: string) => { 51 | switch (id) { 52 | case "aero": 53 | return aero; 54 | case "aero/dom": 55 | return dom; 56 | case "aero/badges": 57 | return badges; 58 | case "aero/plugin": 59 | return { 60 | remoteImport, 61 | definePlugin, 62 | defineVencordPlugin, 63 | pluginSettings, 64 | SettingsItemType, 65 | }; 66 | case "aero/webpack": 67 | return webpack; 68 | case "aero/theme": 69 | return { 70 | defineTheme, 71 | }; 72 | case "aero/ui": 73 | return components; 74 | default: 75 | return undefined; 76 | } 77 | }; 78 | 79 | window.require.all = ["aero", "aero/dom", "aero/badges", "aero/plugin", "aero/webpack", "aero/theme", "aero/ui"]; 80 | 81 | const initialise = async () => { 82 | window.DiscordNative?.window.setDevtoolsCallbacks((_) => _); 83 | 84 | await globalPromise; 85 | 86 | window.aero = aero; 87 | 88 | Object.freeze(window.aero); 89 | 90 | wrap(settings); 91 | 92 | wrap(injectBuiltin); 93 | 94 | if (aeroSettings.loadThirdParty) { 95 | wrap(themes); 96 | wrap(plugins); 97 | wrap(snippets); 98 | } 99 | 100 | wrap(previewBanner); 101 | 102 | localStorage.setItem( 103 | "aeroLaunches", 104 | (localStorage.getItem("aeroLaunches") ? parseInt(localStorage.getItem("aeroLaunches"), 36) + 1 : 1).toString(36) 105 | ); 106 | }; 107 | 108 | try { 109 | polyfill(); 110 | initialise(); 111 | 112 | logger.debug("Initialised"); 113 | } catch (e) { 114 | logger.error(e); 115 | } 116 | -------------------------------------------------------------------------------- /packages/renderer/ui/components/Alert.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | import { c } from "~/renderer/util/classes"; 20 | 21 | import "./alert.scss"; 22 | 23 | export default (props: { 24 | className?: string; 25 | header: string; 26 | details: string; 27 | type: "brand" | "danger" | "warning" | "success"; 28 | }) => { 29 | return ( 30 |
31 |
{props.header}
32 |
{props.details}
33 |
34 | ); 35 | }; 36 | -------------------------------------------------------------------------------- /packages/renderer/ui/components/Button.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | import { c } from "~/renderer/util/classes"; 20 | 21 | import "./button.scss"; 22 | 23 | export enum ButtonColor { 24 | BRAND = "brand", 25 | WHITE = "white", 26 | RED = "red", 27 | GREEN = "green", 28 | YELLOW = "yellow", 29 | LINK = "link", 30 | PRIMARY = "primary", 31 | TRANSPARENT = "transparent", 32 | } 33 | 34 | export enum ButtonSize { 35 | TINY = "tiny", 36 | SMALL = "small", 37 | MEDIUM = "medium", 38 | LARGE = "large", 39 | } 40 | 41 | export enum ButtonLook { 42 | LINK = "link", 43 | OUTLINE = "outline", 44 | FILLED = "filled", 45 | } 46 | 47 | type ButtonProps = { 48 | children: string | number | boolean | React.JSX.Element | React.ReactFragment; 49 | onClick?: () => void; 50 | disabled?: boolean; 51 | className?: string; 52 | style?: React.CSSProperties; 53 | color?: ButtonColor; 54 | size?: ButtonSize; 55 | look?: ButtonLook; 56 | fullwidth?: boolean; 57 | }; 58 | 59 | export default (props: ButtonProps) => { 60 | const { children, onClick, disabled, className, style, color, size, look } = props; 61 | 62 | return ( 63 | 80 | ); 81 | }; 82 | -------------------------------------------------------------------------------- /packages/renderer/ui/components/EmptyState.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | import FormTitle from "./FormTitle"; 20 | 21 | import "./emptystate.scss"; 22 | 23 | export const WUMPUS_NOT_FOUND = { 24 | light: "/assets/b669713872b43ca42333264abf9c858e.svg", 25 | dark: "/assets/b669713872b43ca42333264abf9c858e.svg", 26 | }; 27 | 28 | export const WUMPUS_GAMING = { 29 | light: "/assets/e0989b9d43cd9ca4417b49f4f8fbebc6.svg", 30 | dark: "/assets/e0989b9d43cd9ca4417b49f4f8fbebc6.svg", 31 | }; 32 | 33 | type EmptyStateProps = { 34 | image: string; 35 | title: string; 36 | description: string; 37 | }; 38 | 39 | export default (props: EmptyStateProps) => { 40 | return ( 41 |
42 | Wumpus 43 | 44 | {props.title} 45 | 46 |

{props.description}

47 |
48 | ); 49 | }; 50 | -------------------------------------------------------------------------------- /packages/renderer/ui/components/ErrorBoundary.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | import { LazyComponent } from "~/renderer/util/react"; 20 | import { React } from "~/renderer/api/webpack/common"; 21 | import logger from "~/common/logger"; 22 | 23 | import Button from "./Button"; 24 | 25 | import "./errorboundary.scss"; 26 | 27 | export default LazyComponent( 28 | () => 29 | class ErrorBoundary extends React.PureComponent { 30 | state = { 31 | hasError: false, 32 | retries: 0, 33 | error: { 34 | message: "", 35 | stack: "", 36 | }, 37 | }; 38 | 39 | static getDerivedStateFromError(error: Error) { 40 | return { 41 | hasError: true, 42 | error: { 43 | message: error.message, 44 | stack: error.stack, 45 | }, 46 | }; 47 | } 48 | 49 | render() { 50 | if (!this.state.hasError) return this.props.children; 51 | 52 | return ( 53 | <> 54 |
55 |
Oops! Something went wrong...
56 |
57 | Something went wrong while trying to render this component. More information is below. 58 |
59 |
60 | 67 |
68 | 69 |
{this.state.error.stack}
70 |
71 |
72 | 73 | ); 74 | } 75 | 76 | componentDidCatch(error: Error) { 77 | logger.error(error); 78 | } 79 | } 80 | ); 81 | -------------------------------------------------------------------------------- /packages/renderer/ui/components/FormTitle.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | import { c } from "~/renderer/util/classes"; 20 | 21 | import "./formtitle.scss"; 22 | 23 | export default (props: { 24 | className?: string; 25 | noMargin?: boolean; 26 | level: 1 | 2 | 3 | 4 | 5 | 6; 27 | children: string | number | boolean | React.JSX.Element | React.ReactFragment; 28 | }) => { 29 | const className = c( 30 | "form-title", 31 | { 32 | nomargin: props.noMargin, 33 | [`h${props.level}`]: true, 34 | }, 35 | props.className 36 | ); 37 | 38 | switch (props.level) { 39 | case 1: 40 | return

{props.children}

; 41 | case 2: 42 | return

{props.children}

; 43 | case 3: 44 | return

{props.children}

; 45 | case 4: 46 | return

{props.children}

; 47 | case 5: 48 | return
{props.children}
; 49 | case 6: 50 | return
{props.children}
; 51 | } 52 | }; 53 | -------------------------------------------------------------------------------- /packages/renderer/ui/components/Icons/Book.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | import { IconProps, makeSvg } from "./base"; 20 | 21 | export default (props: IconProps) => { 22 | return makeSvg( 23 | [ 24 | "M 33 34.5833 V 7.5 H 35 V 36.6666 H 9 C 6.791 36.6666 5 34.801 5 32.5 V 7.5 C 5 5.1989 6.791 3.3333 9 3.3333 H 31 V 30.4166 H 9 C 7.8955 30.4166 7 31.3485 7 32.5 C 7 33.6515 7.8955 34.5833 9 34.5833 H 33", 25 | ], 26 | "0 0 40 40", 27 | props.size || 16, 28 | props.fill, 29 | props.stroke 30 | ); 31 | }; 32 | -------------------------------------------------------------------------------- /packages/renderer/ui/components/Icons/Check.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | import { IconProps, makeSvg } from "./base"; 20 | 21 | export default (props: IconProps) => { 22 | return makeSvg( 23 | ["M8.99991 16.17L4.82991 12L3.40991 13.41L8.99991 19L20.9999 7.00003L19.5899 5.59003L8.99991 16.17Z"], 24 | "0 0 24 24", 25 | props.size || 16, 26 | props.fill, 27 | props.stroke 28 | ); 29 | }; 30 | -------------------------------------------------------------------------------- /packages/renderer/ui/components/Icons/Cloud.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | import { IconProps, makeSvg } from "./base"; 20 | 21 | export default (props: IconProps) => { 22 | return makeSvg( 23 | [ 24 | "M19.35 10.04C18.67 6.59 15.64 4 12 4 9.11 4 6.6 5.64 5.35 8.04 2.34 8.36 0 10.91 0 14c0 3.31 2.69 6 6 6h13c2.76 0 5-2.24 5-5 0-2.64-2.05-4.78-4.65-4.96z", 25 | ], 26 | "0 0 24 24", 27 | props.size || 16, 28 | props.fill, 29 | props.stroke 30 | ); 31 | }; 32 | -------------------------------------------------------------------------------- /packages/renderer/ui/components/Icons/Copy.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | import { IconProps, makeSvg } from "./base"; 20 | 21 | export default (props: IconProps) => { 22 | return makeSvg( 23 | [ 24 | "M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1z", 25 | "M15 5H8c-1.1 0-1.99.9-1.99 2L6 21c0 1.1.89 2 1.99 2H19c1.1 0 2-.9 2-2V11l-6-6zM8 21V7h6v5h5v9H8z", 26 | ], 27 | "0 0 24 24", 28 | props.size || 16, 29 | props.fill, 30 | props.stroke 31 | ); 32 | }; 33 | -------------------------------------------------------------------------------- /packages/renderer/ui/components/Icons/Cross.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | import { IconProps, makeSvg } from "./base"; 20 | 21 | export default (props: IconProps) => { 22 | return makeSvg( 23 | ["M18.4 4L12 10.4L5.6 4L4 5.6L10.4 12L4 18.4L5.6 20L12 13.6L18.4 20L20 18.4L13.6 12L20 5.6L18.4 4Z"], 24 | "0 0 24 24", 25 | props.size || 16, 26 | props.fill, 27 | props.stroke 28 | ); 29 | }; 30 | -------------------------------------------------------------------------------- /packages/renderer/ui/components/Icons/Dev.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | import { IconProps, makeSvg } from "./base"; 20 | 21 | export default (props: IconProps) => { 22 | return makeSvg( 23 | [ 24 | "M12.9297 3.25007C12.7343 3.05261 12.4154 3.05226 12.2196 3.24928L11.5746 3.89824C11.3811 4.09297 11.3808 4.40733 11.5739 4.60245L16.5685 9.64824C16.7614 9.84309 16.7614 10.1569 16.5685 10.3517L11.5739 15.3975C11.3808 15.5927 11.3811 15.907 11.5746 16.1017L12.2196 16.7507C12.4154 16.9477 12.7343 16.9474 12.9297 16.7499L19.2604 10.3517C19.4532 10.1568 19.4532 9.84314 19.2604 9.64832L12.9297 3.25007Z", 25 | "M8.42616 4.60245C8.6193 4.40733 8.61898 4.09297 8.42545 3.89824L7.78047 3.24928C7.58466 3.05226 7.26578 3.05261 7.07041 3.25007L0.739669 9.64832C0.5469 9.84314 0.546901 10.1568 0.739669 10.3517L7.07041 16.7499C7.26578 16.9474 7.58465 16.9477 7.78047 16.7507L8.42545 16.1017C8.61898 15.907 8.6193 15.5927 8.42616 15.3975L3.43155 10.3517C3.23869 10.1569 3.23869 9.84309 3.43155 9.64824L8.42616 4.60245Z", 26 | ], 27 | "0 0 20 20", 28 | props.size || 16, 29 | props.fill, 30 | props.stroke 31 | ); 32 | }; 33 | -------------------------------------------------------------------------------- /packages/renderer/ui/components/Icons/External.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | import { IconProps, makeSvg } from "./base"; 20 | 21 | export default (props: IconProps) => { 22 | return makeSvg( 23 | [ 24 | "M10 5V3H5.375C4.06519 3 3 4.06519 3 5.375V18.625C3 19.936 4.06519 21 5.375 21H18.625C19.936 21 21 19.936 21 18.625V14H19V19H5V5H10Z", 25 | "M21 2.99902H14V4.99902H17.586L9.29297 13.292L10.707 14.706L19 6.41302V9.99902H21V2.99902Z", 26 | ], 27 | "0 0 24 24", 28 | props.size || 16, 29 | props.fill, 30 | props.stroke 31 | ); 32 | }; 33 | -------------------------------------------------------------------------------- /packages/renderer/ui/components/Icons/Eye.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | import { IconProps, makeSvg } from "./base"; 20 | 21 | export default (props: IconProps) => { 22 | return makeSvg( 23 | [ 24 | "M12 5C5.648 5 1 12 1 12C1 12 5.648 19 12 19C18.352 19 23 12 23 12C23 12 18.352 5 12 5ZM12 16C9.791 16 8 14.21 8 12C8 9.79 9.791 8 12 8C14.209 8 16 9.79 16 12C16 14.21 14.209 16 12 16Z", 25 | "M12 14C13.1046 14 14 13.1046 14 12C14 10.8954 13.1046 10 12 10C10.8954 10 10 10.8954 10 12C10 13.1046 10.8954 14 12 14Z", 26 | ], 27 | "0 0 24 24", 28 | props.size || 16, 29 | props.fill, 30 | props.stroke 31 | ); 32 | }; 33 | -------------------------------------------------------------------------------- /packages/renderer/ui/components/Icons/File.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | import { IconProps, makeSvg } from "./base"; 20 | 21 | export default (props: IconProps) => { 22 | return makeSvg( 23 | [ 24 | "M6,7 L2,7 L2,6 L6,6 L6,7 Z M8,5 L2,5 L2,4 L8,4 L8,5 Z M8,3 L2,3 L2,2 L8,2 L8,3 Z M8.88888889,0 L1.11111111,0 C0.494444444,0 0,0.494444444 0,1.11111111 L0,8.88888889 C0,9.50253861 0.497461389,10 1.11111111,10 L8.88888889,10 C9.50253861,10 10,9.50253861 10,8.88888889 L10,1.11111111 C10,0.494444444 9.5,0 8.88888889,0 Z", 25 | ], 26 | "0 0 10 10", 27 | props.size || 16, 28 | props.fill, 29 | props.stroke 30 | ); 31 | }; 32 | -------------------------------------------------------------------------------- /packages/renderer/ui/components/Icons/Folder.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | import { IconProps, makeSvg } from "./base"; 20 | 21 | export default (props: IconProps) => { 22 | return makeSvg( 23 | [ 24 | "M20 7H12L10.553 5.106C10.214 4.428 9.521 4 8.764 4H3C2.447 4 2 4.447 2 5V19C2 20.104 2.895 21 4 21H20C21.104 21 22 20.104 22 19V9C22 7.896 21.104 7 20 7Z", 25 | ], 26 | "0 0 24 24", 27 | props.size || 16, 28 | props.fill, 29 | props.stroke 30 | ); 31 | }; 32 | -------------------------------------------------------------------------------- /packages/renderer/ui/components/Icons/Gear.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | import { IconProps, makeSvg } from "./base"; 20 | 21 | export default (props: IconProps) => { 22 | return makeSvg( 23 | [ 24 | "M19.738 10H22V14H19.739C19.498 14.931 19.1 15.798 18.565 16.564L20 18L18 20L16.565 18.564C15.797 19.099 14.932 19.498 14 19.738V22H10V19.738C9.069 19.498 8.203 19.099 7.436 18.564L6 20L4 18L5.436 16.564C4.901 15.799 4.502 14.932 4.262 14H2V10H4.262C4.502 9.068 4.9 8.202 5.436 7.436L4 6L6 4L7.436 5.436C8.202 4.9 9.068 4.502 10 4.262V2H14V4.261C14.932 4.502 15.797 4.9 16.565 5.435L18 3.999L20 5.999L18.564 7.436C19.099 8.202 19.498 9.069 19.738 10ZM12 16C14.2091 16 16 14.2091 16 12C16 9.79086 14.2091 8 12 8C9.79086 8 8 9.79086 8 12C8 14.2091 9.79086 16 12 16Z", 25 | ], 26 | "0 0 24 24", 27 | props.size || 16, 28 | props.fill, 29 | props.stroke 30 | ); 31 | }; 32 | -------------------------------------------------------------------------------- /packages/renderer/ui/components/Icons/Heart.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | import { IconProps, makeSvg } from "./base"; 20 | 21 | export default (props: IconProps) => { 22 | return makeSvg( 23 | ["M12 7.725C12.025-.722 23.022.577 23 9c-.017 6.875-11 13-11 13S1.08 15.875 1 9C.9.579 11.889-.722 12 7.725Z"], 24 | "0 0 24 24", 25 | props.size || 16, 26 | props.fill, 27 | props.stroke 28 | ); 29 | }; 30 | -------------------------------------------------------------------------------- /packages/renderer/ui/components/Icons/Info.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | import { IconProps, makeSvg } from "./base"; 20 | 21 | export default (props: IconProps) => { 22 | return makeSvg( 23 | [ 24 | "M12 2C6.486 2 2 6.487 2 12C2 17.515 6.486 22 12 22C17.514 22 22 17.515 22 12C22 6.487 17.514 2 12 2ZM12 6.751C12.69 6.751 13.25 7.311 13.25 8.001C13.25 8.692 12.69 9.251 12 9.251C11.31 9.251 10.75 8.691 10.75 8C10.75 7.31 11.31 6.751 12 6.751ZM15 17H9V15H11V12H10V10H12C12.553 10 13 10.448 13 11V15H15V17Z", 25 | ], 26 | "0 0 24 24", 27 | props.size || 16, 28 | props.fill, 29 | props.stroke, 30 | props.rest 31 | ); 32 | }; 33 | -------------------------------------------------------------------------------- /packages/renderer/ui/components/Icons/Pencil.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | import { IconProps, makeSvg } from "./base"; 20 | 21 | export default (props: IconProps) => { 22 | return makeSvg( 23 | [ 24 | "M19.2929 9.8299L19.9409 9.18278C21.353 7.77064 21.353 5.47197 19.9409 4.05892C18.5287 2.64678 16.2292 2.64678 14.817 4.05892L14.1699 4.70694L19.2929 9.8299ZM12.8962 5.97688L5.18469 13.6906L10.3085 18.813L18.0201 11.0992L12.8962 5.97688ZM4.11851 20.9704L8.75906 19.8112L4.18692 15.239L3.02678 19.8796C2.95028 20.1856 3.04028 20.5105 3.26349 20.7337C3.48669 20.9569 3.8116 21.046 4.11851 20.9704Z", 25 | ], 26 | "0 0 24 24", 27 | props.size || 16, 28 | props.fill, 29 | props.stroke 30 | ); 31 | }; 32 | -------------------------------------------------------------------------------- /packages/renderer/ui/components/Icons/Play.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | import { IconProps, makeSvg } from "./base"; 20 | 21 | export default (props: IconProps) => { 22 | return makeSvg( 23 | [ 24 | "M6.01053 2.82974C5.01058 2.24153 3.75 2.96251 3.75 4.12264V13.8774C3.75 15.0375 5.01058 15.7585 6.01053 15.1703L14.3021 10.2929C15.288 9.71294 15.288 8.28709 14.3021 7.70711L6.01053 2.82974Z", 25 | ], 26 | "0 0 18 18", 27 | props.size || 16, 28 | props.fill, 29 | props.stroke 30 | ); 31 | }; 32 | -------------------------------------------------------------------------------- /packages/renderer/ui/components/Icons/Plus.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | import { IconProps, makeSvg } from "./base"; 20 | 21 | export default (props: IconProps) => { 22 | return makeSvg( 23 | ["M20 11.1111H12.8889V4H11.1111V11.1111H4V12.8889H11.1111V20H12.8889V12.8889H20V11.1111Z"], 24 | "0 0 24 24", 25 | props.size || 16, 26 | props.fill, 27 | props.stroke 28 | ); 29 | }; 30 | -------------------------------------------------------------------------------- /packages/renderer/ui/components/Icons/Sparkle.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | import { IconProps, makeSvg } from "./base"; 20 | 21 | export default (props: IconProps) => { 22 | return makeSvg( 23 | [ 24 | "M21.4319 21.1098C19.3401 19.7799 17.5593 18.0272 16.2075 15.9678C14.8557 13.9084 13.9638 11.5895 13.5911 9.16477L12.3366 0.720848C12.311 0.520662 12.2117 0.336692 12.0575 0.203827C11.9034 0.0709621 11.7051 -0.00155639 11.5002 2.53393e-05C11.2954 -0.00155639 11.0971 0.0709621 10.9429 0.203827C10.7888 0.336692 10.6895 0.520662 10.6639 0.720848L9.30486 9.16477C8.9519 11.5956 8.06815 13.9223 6.71457 15.9844C5.36098 18.0465 3.56973 19.7952 1.46411 21.1098L0.314098 21.8307C0.211503 21.9209 0.130281 22.0322 0.0760932 22.1568C0.0219055 22.2813 -0.00391655 22.4161 0.000480577 22.5515C-0.00393532 22.6721 0.0224444 22.7919 0.0772418 22.8998C0.132039 23.0078 0.213487 23.1004 0.314098 23.1693L1.46411 23.8902C3.57262 25.2261 5.36427 26.9937 6.71725 29.0726C8.07022 31.1516 8.95279 33.4932 9.30486 35.9382L10.6639 44.2792C10.6895 44.4793 10.7888 44.6633 10.9429 44.7962C11.0971 44.929 11.2954 45.0016 11.5002 45C11.7051 45.0016 11.9034 44.929 12.0575 44.7962C12.2117 44.6633 12.311 44.4793 12.3366 44.2792L13.5911 35.9382C13.9627 33.4993 14.8532 31.1652 16.2044 29.0889C17.5557 27.0127 19.3371 25.241 21.4319 23.8902L22.5818 23.1693C22.6957 23.1058 22.793 23.0168 22.8656 22.9095C22.9383 22.8021 22.9843 22.6795 23 22.5515C22.9849 22.4093 22.9399 22.2718 22.8679 22.1477C22.7959 22.0236 22.6985 21.9156 22.5818 21.8307L21.4319 21.1098Z", 25 | ], 26 | "0 0 23 45", 27 | props.size || 16, 28 | props.fill, 29 | props.stroke 30 | ); 31 | }; 32 | -------------------------------------------------------------------------------- /packages/renderer/ui/components/Icons/base.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | export type IconProps = { 20 | size?: number; 21 | fill?: string; 22 | stroke?: string; 23 | rest?: object; 24 | }; 25 | 26 | export const makeSvg = ( 27 | paths: string[], 28 | viewBox: string, 29 | size: number, 30 | fill = "currentColor", 31 | stroke: string = null, 32 | rest: object = {} 33 | ) => { 34 | return ( 35 | 36 | {paths.map((path) => ( 37 | 38 | ))} 39 | 40 | ); 41 | }; 42 | -------------------------------------------------------------------------------- /packages/renderer/ui/components/Icons/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | export { default as External } from "./External"; 20 | export { default as Sparkle } from "./Sparkle"; 21 | export { default as Folder } from "./Folder"; 22 | export { default as Check } from "./Check"; 23 | export { default as Cross } from "./Cross"; 24 | export { default as Cloud } from "./Cloud"; 25 | export { default as Heart } from "./Heart"; 26 | export { default as File } from "./File"; 27 | export { default as Copy } from "./Copy"; 28 | export { default as Gear } from "./Gear"; 29 | export { default as Play } from "./Play"; 30 | export { default as Plus } from "./Plus"; 31 | export { default as Book } from "./Book"; 32 | export { default as Dev } from "./Dev"; 33 | export { default as Eye } from "./Eye"; 34 | -------------------------------------------------------------------------------- /packages/renderer/ui/components/Modal/CloseButton.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | export default (props: { onClick: () => void }) => { 20 | return ( 21 | 31 | ); 32 | }; 33 | -------------------------------------------------------------------------------- /packages/renderer/ui/components/Modal/index.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | import type { ReactNode } from "react"; 20 | 21 | import { c } from "~/renderer/util/classes"; 22 | 23 | export { default as ModalCloseButton } from "./CloseButton"; 24 | 25 | import "./index.scss"; 26 | 27 | export enum ModalSize { 28 | Small = "small", 29 | Medium = "medium", 30 | Large = "large", 31 | Dynamic = "dynamic", 32 | } 33 | 34 | type ModalRootProps = { 35 | size: ModalSize; 36 | children: ReactNode; 37 | rest: { 38 | [x: string]: unknown; 39 | }; 40 | }; 41 | 42 | export const ModalRoot = (props: ModalRootProps) => { 43 | const e = { 44 | transitionState: props.rest.transitionState, 45 | }; 46 | 47 | return ( 48 |
49 | {props.children} 50 |
51 | ); 52 | }; 53 | 54 | export const ModalHeader = (props: { 55 | children: JSX.Element | JSX.Element[]; 56 | center?: boolean; 57 | separator?: boolean; 58 | }) => { 59 | return ( 60 |
66 | {props.children} 67 |
68 | ); 69 | }; 70 | 71 | export const ModalContent = (props: { className?: string; children: JSX.Element | JSX.Element[] | ReactNode }) => { 72 | return
{props.children}
; 73 | }; 74 | 75 | export const ModalFooter = (props: { 76 | transparent?: boolean; 77 | center?: boolean; 78 | gap?: boolean; 79 | children: JSX.Element | JSX.Element[]; 80 | }) => { 81 | return ( 82 |
89 | {props.children} 90 |
91 | ); 92 | }; 93 | -------------------------------------------------------------------------------- /packages/renderer/ui/components/PanelButton.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | import { Tooltip } from "~/renderer/api/webpack/common/components"; 20 | import { c } from "~/renderer/util/classes"; 21 | 22 | import "./panelbutton.scss"; 23 | 24 | type PanelButtonProps = { 25 | children: string | number | boolean | React.JSX.Element | React.ReactFragment; 26 | onClick?: () => void; 27 | disabled?: boolean; 28 | className?: string; 29 | tooltipText: string; 30 | }; 31 | 32 | export default (props: PanelButtonProps) => { 33 | return ( 34 | 35 | {(p) => ( 36 | 44 | )} 45 | 46 | ); 47 | }; 48 | -------------------------------------------------------------------------------- /packages/renderer/ui/components/SettingsItem.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | import markdown from "../../util/markdown"; 20 | 21 | import TextInput from "./TextInput"; 22 | import Switch from "./Switch"; 23 | 24 | import "./settingsitem.scss"; 25 | 26 | type SettingsItemProps = 27 | | { 28 | type: "switch"; 29 | title: string; 30 | note?: string; 31 | value: boolean; 32 | onChange: (value: boolean) => void; 33 | } 34 | | { 35 | type: "input"; 36 | title: string; 37 | note?: string; 38 | value: string | number; 39 | onChange: (value: string | number) => void; 40 | }; 41 | 42 | export default (props: SettingsItemProps) => { 43 | const randomID = Math.random().toString(36).substring(2, 15); 44 | 45 | return ( 46 |
47 |
48 | 51 | {props.note &&
{markdown(props.note)}
} 52 |
53 |
54 | {props.type === "switch" ? ( 55 | 56 | ) : props.type === "input" ? ( 57 | props.onChange(e)} 62 | /> 63 | ) : null} 64 |
65 |
66 | ); 67 | }; 68 | -------------------------------------------------------------------------------- /packages/renderer/ui/components/Switch.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | import { c } from "~/renderer/util/classes"; 20 | 21 | import "./switch.scss"; 22 | 23 | type SwitchProps = { 24 | value: boolean; 25 | onChange: (value: boolean) => void; 26 | className?: string; 27 | disabled?: boolean; 28 | id?: string; 29 | }; 30 | 31 | export default (props: SwitchProps) => { 32 | const { value, onChange, className, disabled, id } = props; 33 | 34 | return ( 35 |
onChange(!value)} 44 | style={{ 45 | backgroundColor: value ? "rgba(35, 165, 90, 1)" : "rgba(128, 132, 142, 1)", 46 | }} 47 | > 48 | 75 | { 82 | // let it bubble 83 | }} 84 | /> 85 |
86 | ); 87 | }; 88 | -------------------------------------------------------------------------------- /packages/renderer/ui/components/TextInput.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | import { React } from "~/renderer/api/webpack/common"; 20 | 21 | import "./textinput.scss"; 22 | 23 | type TextInputProps = { 24 | id?: string; 25 | type: string; 26 | value: string | number; 27 | onChange: (value: string | number) => void; 28 | placeholder?: string; 29 | disabled?: boolean; 30 | className?: string; 31 | maxLength?: number; 32 | autoFocus?: boolean; 33 | }; 34 | 35 | export default (props: TextInputProps) => { 36 | const [value, setValue] = React.useState(props.value); 37 | 38 | return ( 39 |
40 | { 48 | setValue(e.target.value); 49 | 50 | props.onChange(e.target.value); 51 | }} 52 | /> 53 |
54 | ); 55 | }; 56 | -------------------------------------------------------------------------------- /packages/renderer/ui/components/addoncard.scss: -------------------------------------------------------------------------------- 1 | .addon-card { 2 | display: flex; 3 | background: var(--background-secondary); 4 | border-radius: var(--radius-md); 5 | color: var(--text-normal); 6 | overflow: hidden; 7 | 8 | &.agent { 9 | opacity: 0.5; 10 | } 11 | 12 | .addon-card-accent { 13 | width: 6px; 14 | background: var(--addon-accent, var(--text-muted)); 15 | } 16 | 17 | .addon-card-inner { 18 | width: 100%; 19 | padding: 20px; 20 | display: flex; 21 | flex-direction: column; 22 | gap: 15px; 23 | 24 | .addon-card-header { 25 | display: flex; 26 | align-items: flex-start; 27 | justify-content: space-between; 28 | 29 | .addon-card-text { 30 | display: flex; 31 | flex-direction: column; 32 | gap: 10px; 33 | } 34 | 35 | .addon-card-switch { 36 | display: flex; 37 | align-items: center; 38 | gap: 10px; 39 | } 40 | } 41 | 42 | .addon-card-name { 43 | font-size: 16px; 44 | font-weight: 500; 45 | } 46 | 47 | .addon-card-description { 48 | font-size: 14px; 49 | color: var(--text-muted); 50 | } 51 | 52 | .addon-card-footer { 53 | font-size: 12px; 54 | color: var(--text-muted); 55 | display: flex; 56 | width: 100%; 57 | gap: 10px; 58 | opacity: 0.8; 59 | padding-top: 5px; 60 | margin-top: auto; 61 | align-items: baseline; 62 | justify-content: flex-end; 63 | 64 | &:has(:nth-child(2)) { 65 | justify-content: space-between; 66 | } 67 | 68 | .addon-card-patches { 69 | text-transform: uppercase; 70 | display: flex; 71 | gap: 10px; 72 | font-weight: 600; 73 | 74 | .active { 75 | color: var(--text-positive); 76 | } 77 | 78 | .inactive { 79 | color: var(--text-warning); 80 | } 81 | } 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /packages/renderer/ui/components/alert.scss: -------------------------------------------------------------------------------- 1 | .alert { 2 | border-radius: var(--radius-md); 3 | border: 1px solid; 4 | padding: 16px; 5 | display: flex; 6 | flex-direction: column; 7 | gap: 16px; 8 | 9 | &.alert-danger { 10 | background-color: var(--info-danger-background); 11 | border-color: var(--info-danger-foreground); 12 | color: var(--info-danger-foreground); 13 | } 14 | 15 | &.alert-warning { 16 | background-color: var(--info-warning-background); 17 | border-color: var(--info-warning-foreground); 18 | color: var(--info-warning-foreground); 19 | } 20 | 21 | &.alert-success { 22 | background-color: var(--info-positive-background); 23 | border-color: var(--info-positive-foreground); 24 | color: var(--info-positive-foreground); 25 | } 26 | 27 | &.alert-brand { 28 | background-color: var(--brand-500); 29 | border-color: var(--aero-brand); 30 | color: var(--aero-brand); 31 | } 32 | 33 | .header { 34 | font-size: 18px; 35 | font-weight: 600; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /packages/renderer/ui/components/button.scss: -------------------------------------------------------------------------------- 1 | .button { 2 | position: relative; 3 | display: flex; 4 | justify-content: center; 5 | align-items: center; 6 | box-sizing: border-box; 7 | background: none; 8 | border: none; 9 | border-radius: 3px; 10 | font-size: 14px; 11 | font-weight: 500; 12 | line-height: 16px; 13 | padding: 2px 16px; 14 | user-select: none; 15 | cursor: pointer; 16 | 17 | .contents { 18 | display: flex; 19 | align-items: center; 20 | justify-content: center; 21 | gap: 8px; 22 | } 23 | 24 | &.disabled { 25 | opacity: 0.5; 26 | pointer-events: none; 27 | } 28 | 29 | &.look-filled { 30 | transition: background-color 0.17s ease, color 0.17s ease; 31 | background-color: var(--brand-500); 32 | color: var(--white); 33 | 34 | &.color-brand { 35 | background-color: var(--brand-500); 36 | color: var(--white); 37 | 38 | &:hover { 39 | background-color: var(--brand-experiment-560); 40 | } 41 | } 42 | 43 | &.color-primary { 44 | background-color: var(--primary-500); 45 | color: var(--white); 46 | 47 | &:hover { 48 | background-color: var(--primary-560); 49 | } 50 | } 51 | 52 | &.color-white { 53 | color: var(--primary-500); 54 | background-color: var(--white-500); 55 | } 56 | 57 | &.color-red { 58 | color: var(--white-500); 59 | background-color: var(--button-danger-background); 60 | 61 | &:hover { 62 | background-color: var(--button-danger-background-hover); 63 | } 64 | } 65 | 66 | &.color-green { 67 | color: var(--white-500); 68 | background-color: var(--button-success-background); 69 | 70 | &:hover { 71 | background-color: var(--button-success-background-hover); 72 | } 73 | } 74 | 75 | &.color-yellow { 76 | color: var(--white-500); 77 | background-color: var(--status-warning); 78 | } 79 | } 80 | 81 | &.look-link { 82 | background-color: transparent; 83 | color: var(--header-primary); 84 | 85 | &:hover { 86 | .contents { 87 | text-decoration: underline; 88 | } 89 | } 90 | } 91 | 92 | &.look-outline { 93 | transition: border-color 0.17s ease, color 0.17s ease; 94 | background-color: transparent; 95 | color: var(--header-primary); 96 | border: 1px solid var(--header-primary); 97 | 98 | &.color-primary { 99 | border-color: var(--primary-500); 100 | color: var(--white); 101 | 102 | &:hover { 103 | border-color: var(--header-primary); 104 | } 105 | } 106 | } 107 | 108 | &.size-tiny { 109 | height: 24px; 110 | min-width: 52px; 111 | min-height: 24px; 112 | } 113 | 114 | &.size-small { 115 | height: 32px; 116 | min-width: 60px; 117 | min-height: 32px; 118 | } 119 | 120 | &.size-medium { 121 | height: 38px; 122 | min-width: 96px; 123 | min-height: 38px; 124 | } 125 | 126 | &.size-large { 127 | height: 44px; 128 | min-width: 130px; 129 | min-height: 44px; 130 | } 131 | 132 | &.look-filled .contents, 133 | &.look-inverted .contents, 134 | &.look-link .contents, 135 | &.look-outlined .contents { 136 | margin: 0 auto; 137 | white-space: nowrap; 138 | text-overflow: ellipsis; 139 | overflow: hidden; 140 | } 141 | 142 | &.fullwidth { 143 | width: 100%; 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /packages/renderer/ui/components/emptystate.scss: -------------------------------------------------------------------------------- 1 | .empty-state { 2 | margin-top: 75px; 3 | width: 100%; 4 | display: flex; 5 | flex-direction: column; 6 | align-items: center; 7 | 8 | .empty-state-image { 9 | width: 404px; 10 | } 11 | 12 | .empty-state-heading { 13 | margin-top: 24px; 14 | margin-bottom: 8px; 15 | } 16 | 17 | .empty-state-description { 18 | color: var(--text-muted); 19 | font-size: 16px; 20 | line-height: 20px; 21 | margin-bottom: 24px; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /packages/renderer/ui/components/errorboundary.scss: -------------------------------------------------------------------------------- 1 | .error-boundary { 2 | height: 100%; 3 | width: 100%; 4 | background: var(--info-danger-background); 5 | color: var(--info-danger-foreground); 6 | border: 1px solid var(--info-danger-foreground); 7 | border-radius: var(--radius-md); 8 | padding: 16px; 9 | gap: 16px; 10 | display: flex; 11 | flex-direction: column; 12 | 13 | .heading { 14 | font-size: 18px; 15 | font-weight: 600; 16 | } 17 | 18 | .error-boundary-text { 19 | font-size: 16px; 20 | max-width: 500px; 21 | } 22 | 23 | .button-container { 24 | display: flex; 25 | gap: 10px; 26 | margin-top: 1rem; 27 | } 28 | 29 | code { 30 | width: 100%; 31 | background: var(--background-secondary); 32 | padding: 10px; 33 | border-radius: var(--radius-sm); 34 | overflow: auto; 35 | 36 | &::-webkit-scrollbar { 37 | width: 8px; 38 | height: 8px; 39 | } 40 | 41 | &::-webkit-scrollbar-thumb { 42 | background: var(--scrollbar-auto-thumb); 43 | border: 2px solid var(--scrollbar-auto-track); 44 | border-radius: 4px; 45 | } 46 | 47 | &::-webkit-scrollbar-track { 48 | background: var(--scrollbar-auto-track); 49 | border-radius: 4px; 50 | } 51 | 52 | pre { 53 | font-family: var(--font-mono); 54 | font-size: 14px; 55 | color: var(--text-muted); 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /packages/renderer/ui/components/formtitle.scss: -------------------------------------------------------------------------------- 1 | .form-title { 2 | color: var(--header-primary); 3 | font-family: var(--font-display); 4 | font-size: 20px; 5 | line-height: 24px; 6 | font-weight: 600; 7 | display: flex; 8 | align-items: center; 9 | gap: 6px; 10 | 11 | &.nomargin { 12 | margin: 0 !important; 13 | } 14 | 15 | &.h1, 16 | &.h2 { 17 | font-weight: 600; 18 | margin-bottom: 20px; 19 | } 20 | 21 | &.h3, 22 | &.h4, 23 | &.h5, 24 | &.h6 { 25 | font-weight: 700; 26 | text-transform: uppercase; 27 | letter-spacing: 0.02em; 28 | color: var(--text-muted); 29 | } 30 | 31 | &.h1 { 32 | font-size: 20px; 33 | line-height: 24px; 34 | } 35 | 36 | &.h2 { 37 | font-size: 16px; 38 | line-height: 20px; 39 | text-transform: uppercase; 40 | } 41 | 42 | &.h3 { 43 | font-size: 14px; 44 | line-height: 18px; 45 | } 46 | 47 | &.h4 { 48 | font-size: 12px; 49 | line-height: 16px; 50 | } 51 | 52 | &.h5 { 53 | font-size: 10px; 54 | line-height: 14px; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /packages/renderer/ui/components/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | export { default as ErrorBoundary } from "./ErrorBoundary"; 20 | export { default as SettingsItem } from "./SettingsItem"; 21 | export { default as PanelButton } from "./PanelButton"; 22 | export { default as FormTitle } from "./FormTitle"; 23 | export { default as TextInput } from "./TextInput"; 24 | export { default as Button } from "./Button"; 25 | export { default as Switch } from "./Switch"; 26 | export { default as Alert } from "./Alert"; 27 | 28 | export * as Modal from "./Modal"; 29 | 30 | export * as Icons from "./Icons"; 31 | -------------------------------------------------------------------------------- /packages/renderer/ui/components/monaco.scss: -------------------------------------------------------------------------------- 1 | .monaco-loading { 2 | &:not(:last-child) { 3 | display: none; 4 | } 5 | 6 | &:last-child { 7 | background-color: var(--background-secondary); 8 | display: flex; 9 | align-items: center; 10 | justify-content: center; 11 | position: relative; 12 | height: 100%; 13 | 14 | .monaco-loading-background { 15 | width: 100%; 16 | height: 100%; 17 | position: absolute; 18 | inset: 0; 19 | z-index: 1; 20 | } 21 | 22 | .monaco-loading-text { 23 | color: var(--text-muted); 24 | font-size: 16px; 25 | z-index: 2; 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /packages/renderer/ui/components/panelbutton.scss: -------------------------------------------------------------------------------- 1 | .panel-button { 2 | line-height: 0; 3 | width: 32px; 4 | height: 32px; 5 | display: flex; 6 | align-items: center; 7 | background-color: transparent; 8 | justify-content: center; 9 | box-sizing: border-box; 10 | border-radius: 4px; 11 | position: relative; 12 | font-size: 14px; 13 | font-weight: 500; 14 | color: var(--interactive-normal); 15 | cursor: pointer; 16 | 17 | &[disabled] { 18 | cursor: not-allowed; 19 | opacity: 0.5; 20 | } 21 | 22 | &:hover { 23 | color: var(--interactive-hover); 24 | background-color: var(--background-modifier-selected); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /packages/renderer/ui/components/settingsitem.scss: -------------------------------------------------------------------------------- 1 | .settings-item { 2 | display: flex; 3 | gap: 40px; 4 | padding-bottom: 20px; 5 | margin-block: 20px; 6 | border-bottom: thin solid var(--background-modifier-accent); 7 | 8 | .settings-item-text { 9 | display: flex; 10 | flex-direction: column; 11 | gap: 8px; 12 | width: 100%; 13 | 14 | .settings-item-title { 15 | display: block; 16 | overflow: hidden; 17 | margin-top: 0; 18 | margin-bottom: 0; 19 | color: var(--header-primary); 20 | line-height: 24px; 21 | font-size: 16px; 22 | font-weight: 500; 23 | word-wrap: break-word; 24 | cursor: pointer; 25 | } 26 | 27 | .settings-item-note { 28 | color: var(--header-secondary); 29 | font-size: 14px; 30 | line-height: 20px; 31 | font-weight: 400; 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /packages/renderer/ui/components/switch.scss: -------------------------------------------------------------------------------- 1 | .switch-container { 2 | border-radius: 14px; 3 | position: relative; 4 | width: 40px; 5 | height: 24px; 6 | cursor: pointer; 7 | transition: background 0.2s ease-in-out; 8 | 9 | .slider { 10 | display: block; 11 | position: absolute; 12 | left: 0; 13 | width: 28px; 14 | height: 18px; 15 | margin: 3px; 16 | transition: 0.2s ease-in-out; 17 | 18 | path { 19 | transition: 0.2s ease-in-out; 20 | } 21 | } 22 | 23 | .input { 24 | position: absolute; 25 | opacity: 0; 26 | width: 100%; 27 | height: 100%; 28 | top: 0; 29 | left: 0; 30 | margin: 0; 31 | cursor: pointer; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /packages/renderer/ui/components/textinput.scss: -------------------------------------------------------------------------------- 1 | /** 2 | 3 | return ( 4 |
5 | { 12 | setValue(e.target.value); 13 | props.onChange(e.target.value); 14 | }} 15 | /> 16 |
17 | ); 18 | */ 19 | 20 | .input-wrapper { 21 | display: flex; 22 | flex-direction: column; 23 | 24 | .input { 25 | padding: 10px; 26 | height: 40px; 27 | font-size: 16px; 28 | box-sizing: border-box; 29 | width: 100%; 30 | border-radius: 3px; 31 | color: var(--text-normal); 32 | background-color: var(--input-background); 33 | border: none; 34 | transition: border-color 0.2s ease-in-out; 35 | } 36 | } 37 | 38 | textarea.textarea { 39 | padding: 10px; 40 | height: 200px; 41 | font-size: 16px; 42 | box-sizing: border-box; 43 | width: 100%; 44 | border-radius: 3px; 45 | color: var(--text-normal); 46 | background-color: var(--input-background); 47 | border: none; 48 | transition: border-color 0.2s ease-in-out; 49 | resize: vertical; 50 | min-height: 100px; 51 | max-height: 500px; 52 | 53 | &::-webkit-scrollbar { 54 | width: 5px; 55 | } 56 | 57 | &::-webkit-scrollbar-track { 58 | background: var(--scrollbar-thin-track); 59 | } 60 | 61 | &::-webkit-scrollbar-thumb { 62 | background: var(----scrollbar-thin-thumb); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /packages/renderer/ui/components/toast.scss: -------------------------------------------------------------------------------- 1 | #toast-layer { 2 | position: fixed; 3 | right: 15px; 4 | top: 15px; 5 | z-index: 1001; 6 | display: flex; 7 | flex-direction: column; 8 | align-items: flex-end; 9 | transition: all 0.2s ease; 10 | pointer-events: none; 11 | } 12 | 13 | .toast { 14 | cursor: pointer; 15 | background-color: var(--background-floating); 16 | border-radius: var(--radius-sm); 17 | padding: 15px 15px 15px 20px; 18 | color: var(--header-primary); 19 | z-index: 1; 20 | max-width: 325px; 21 | width: fit-content; 22 | pointer-events: all; 23 | transition: all 0.2s ease; 24 | position: relative; 25 | overflow: hidden; 26 | display: flex; 27 | gap: 10px; 28 | 29 | .toast-color { 30 | width: 5px; 31 | background: var(--color, var(--header-primary)); 32 | height: 100%; 33 | position: absolute; 34 | inset: 0; 35 | } 36 | 37 | .toast-details { 38 | display: flex; 39 | flex-direction: column; 40 | gap: 5px; 41 | 42 | .toast-title { 43 | font-weight: 500; 44 | font-size: 16px; 45 | line-height: 18px; 46 | } 47 | 48 | .toast-content { 49 | font-weight: 400; 50 | font-size: 14px; 51 | line-height: 16px; 52 | color: var(--text-muted); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /packages/renderer/ui/settings/buildSettings.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | import { AeroPlugin } from "~/renderer/api/plugins/types"; 20 | import { pluginSettings } from "~/renderer/api/plugins"; 21 | import { React } from "~/renderer/api/webpack/common"; 22 | import { SettingsItem } from "../components"; 23 | 24 | const Item = (props: { setting: AeroPlugin["settings"][number]; settings: ProxyHandler> }) => { 25 | const type = props.setting.type === "boolean" ? "switch" : "input"; 26 | 27 | const [value, setValue] = React.useState( 28 | props.settings[props.setting.id] || props.setting.initialValue || undefined 29 | ); 30 | 31 | return ( 32 | { 38 | props.settings[props.setting.id] = val; 39 | 40 | setValue(val); 41 | }} 42 | /> 43 | ); 44 | }; 45 | 46 | export default (plugin: AeroPlugin) => { 47 | const settings = pluginSettings(plugin.id); 48 | 49 | return ( 50 | <> 51 | {plugin.settings?.map((s) => ( 52 | 53 | ))} 54 | 55 | ); 56 | }; 57 | -------------------------------------------------------------------------------- /packages/renderer/ui/settings/index.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | import { waitFor } from "~/renderer/api/webpack"; 20 | import aero from "~/renderer/aero"; 21 | 22 | import ErrorBoundary from "../components/ErrorBoundary"; 23 | import Dashboard from "./panes/Dashboard"; 24 | import Snippets from "./panes/Snippets"; 25 | import Addons from "./panes/Addons"; 26 | 27 | import "./settings.scss"; 28 | 29 | const patcher = new aero.patcher("aero:settings"); 30 | 31 | export default async () => { 32 | const UserSettings = await waitFor((m) => m["default"]?.prototype?.getPredicateSections); 33 | 34 | patcher.after( 35 | UserSettings.prototype, 36 | "getPredicateSections", 37 | ( 38 | _, 39 | ret: { 40 | section: string; 41 | label?: string; 42 | icon?: React.JSX.Element; 43 | className?: string; 44 | onClick?: (e: React.MouseEvent) => void; 45 | onContextMenu?: (e: React.MouseEvent) => void; 46 | element?: () => React.JSX.Element; 47 | }[] = [] 48 | ) => { 49 | let location = ret.findIndex((s: { section: string }) => s.section.toLowerCase() == "discord nitro") - 2; 50 | 51 | if (location < 0) return; 52 | 53 | const insertSettingsPane = (section: { 54 | section: string; 55 | label?: string; 56 | icon?: React.JSX.Element; 57 | className?: string; 58 | onClick?: (e: React.MouseEvent) => void; 59 | onContextMenu?: (e: React.MouseEvent) => void; 60 | element?: () => React.JSX.Element; 61 | }) => { 62 | ret.splice(location, 0, section); 63 | location++; 64 | }; 65 | 66 | insertSettingsPane({ section: "DIVIDER" }); 67 | insertSettingsPane({ section: "HEADER", label: "Aero" }); 68 | 69 | insertSettingsPane({ 70 | section: "aero", 71 | label: "Dashboard", 72 | element: () => ( 73 | 74 | 75 | 76 | ), 77 | }); 78 | 79 | insertSettingsPane({ 80 | section: "addons", 81 | label: "Addons", 82 | element: () => ( 83 | 84 | 85 | 86 | ), 87 | }); 88 | 89 | insertSettingsPane({ 90 | section: "snippets", 91 | label: "Snippets", 92 | element: () => ( 93 | 94 | 95 | 96 | ), 97 | }); 98 | } 99 | ); 100 | }; 101 | -------------------------------------------------------------------------------- /packages/renderer/ui/settings/panes/addons.scss: -------------------------------------------------------------------------------- 1 | .tab-bar { 2 | padding-top: 6px; 3 | margin-top: 24px; 4 | margin-bottom: 16px; 5 | border-bottom: 1px solid var(--background-modifier-accent); 6 | display: flex; 7 | align-items: flex-end; 8 | justify-content: space-between; 9 | gap: 16px; 10 | 11 | .tab-bar-options, 12 | .tab-bar-menu { 13 | display: flex; 14 | align-items: center; 15 | gap: 6px; 16 | } 17 | 18 | .tab-bar-options { 19 | position: relative; 20 | overflow-x: scroll; 21 | 22 | &::after { 23 | content: ""; 24 | position: absolute; 25 | z-index: 2; 26 | width: 20px; 27 | height: 40px; 28 | background: linear-gradient(to left, var(--background-primary), transparent); 29 | right: 0; 30 | top: 0; 31 | } 32 | 33 | &::-webkit-scrollbar { 34 | display: none; 35 | } 36 | } 37 | 38 | .tab-bar-menu { 39 | margin-bottom: 16px; 40 | } 41 | 42 | .tab { 43 | color: var(--interactive-normal); 44 | border-bottom: 2px solid transparent; 45 | padding-bottom: 16px; 46 | margin-right: 16px; 47 | position: relative; 48 | font-size: 16px; 49 | line-height: 20px; 50 | cursor: pointer; 51 | font-weight: 500; 52 | white-space: nowrap; 53 | text-overflow: ellipsis; 54 | 55 | &:hover { 56 | color: var(--interactive-hover); 57 | border-bottom-color: var(--brand-experiment); 58 | } 59 | 60 | &.active { 61 | cursor: default; 62 | color: var(--interactive-active); 63 | border-bottom-color: var(--control-brand-foreground); 64 | } 65 | } 66 | } 67 | 68 | .addons-container { 69 | display: flex; 70 | flex-direction: column; 71 | gap: 16px; 72 | 73 | &.disabled { 74 | .addons-section:not(#builtin) { 75 | opacity: 0.5; 76 | pointer-events: none; 77 | } 78 | } 79 | 80 | .addons-section { 81 | display: grid; 82 | grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); 83 | gap: 16px; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /packages/renderer/ui/settings/panes/dashboard.scss: -------------------------------------------------------------------------------- 1 | @keyframes fadeIn { 2 | 0% { 3 | filter: grayscale(1) blur(10px); 4 | } 5 | 100% { 6 | filter: grayscale(var(--progress)) blur(var(--progress-px)); 7 | } 8 | } 9 | 10 | @keyframes growIn { 11 | 0% { 12 | width: 0%; 13 | } 14 | 100% { 15 | width: var(--width); 16 | } 17 | } 18 | 19 | #aero-dash { 20 | display: flex; 21 | flex-direction: column; 22 | min-height: calc(100vh - 80px); 23 | 24 | .dash-banner { 25 | background-color: var(--background-secondary-alt); 26 | border-radius: var(--radius-md); 27 | overflow: hidden; 28 | color: var(--header-primary); 29 | font-family: var(--font-display); 30 | font-size: 18px; 31 | font-weight: 400; 32 | padding: 30px 20px; 33 | background: linear-gradient(45deg, var(--brand-500), var(--brand-460)); 34 | display: flex; 35 | gap: 100px; 36 | 37 | .dash-banner-left { 38 | flex-direction: column; 39 | display: flex; 40 | gap: 20px; 41 | width: 100%; 42 | z-index: 3; 43 | } 44 | 45 | .dash-banner-right { 46 | font-size: 56px; 47 | display: flex; 48 | align-items: center; 49 | justify-content: flex-end; 50 | z-index: 3; 51 | } 52 | 53 | .dash-banner-count { 54 | font-weight: 600; 55 | } 56 | 57 | .dash-banner-bar-wrapper { 58 | display: flex; 59 | align-items: center; 60 | gap: 10px; 61 | 62 | .dash-banner-bar { 63 | width: 100%; 64 | height: 12px; 65 | background-color: var(--background-secondary-alt); 66 | border-radius: var(--radius-lg); 67 | overflow: hidden; 68 | 69 | .dash-banner-bar-fill { 70 | animation: growIn 1s ease-in-out; 71 | height: 100%; 72 | width: var(--width); 73 | border-radius: var(--radius-lg); 74 | background-color: var(--white); 75 | transition: width 0.2s ease-in-out; 76 | } 77 | } 78 | 79 | p { 80 | margin: 0; 81 | animation: fadeIn 1s ease-in-out; 82 | filter: grayscale(var(--progress)) blur(var(--progress-px)); 83 | } 84 | } 85 | } 86 | 87 | .dash-footer { 88 | color: var(--text-muted); 89 | margin-top: auto; 90 | padding-block: 20px; 91 | display: flex; 92 | align-items: center; 93 | justify-content: space-between; 94 | gap: 10px; 95 | border-top: thin solid var(--background-modifier-accent); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /packages/renderer/ui/settings/panes/snippets.scss: -------------------------------------------------------------------------------- 1 | #aero-snippets { 2 | .aero-snippets-container { 3 | height: 540px; 4 | 5 | .monaco-header { 6 | border-radius: 8px 8px 0 0; 7 | background: var(--background-secondary); 8 | padding: 10px 18px; 9 | display: flex; 10 | align-items: center; 11 | 12 | .monaco-header-lang { 13 | text-transform: uppercase; 14 | font-size: 16px; 15 | line-height: 20px; 16 | font-weight: 600; 17 | color: var(--text-muted); 18 | padding-right: 8px; 19 | } 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /packages/renderer/ui/settings/settings.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aero-mod/aero/4d589a4eb1301672cfee8fb7e54981368ea30532/packages/renderer/ui/settings/settings.scss -------------------------------------------------------------------------------- /packages/renderer/util.scss: -------------------------------------------------------------------------------- 1 | :root { 2 | --aero-brand: #6388e5; 3 | } 4 | 5 | .text-normal { 6 | color: var(--text-normal); 7 | font-weight: 400; 8 | line-height: 20px; 9 | font-size: 16px; 10 | } 11 | 12 | @function level($level) { 13 | @return $level * 10px; 14 | } 15 | 16 | @for $i from 0 through 10 { 17 | .mt-#{$i} { 18 | margin-top: level($i); 19 | } 20 | 21 | .mb-#{$i} { 22 | margin-bottom: level($i); 23 | } 24 | 25 | .ml-#{$i} { 26 | margin-left: level($i); 27 | } 28 | 29 | .mr-#{$i} { 30 | margin-right: level($i); 31 | } 32 | } 33 | 34 | .icon { 35 | color: inherit; 36 | } 37 | 38 | code { 39 | &.inline { 40 | padding: 4px; 41 | background-color: var(--background-secondary-alt); 42 | border-radius: 4px; 43 | font-size: 12px; 44 | } 45 | } 46 | 47 | .aero-infoVersion { 48 | color: var(--interactive-normal); 49 | transition: color 0.15s ease; 50 | 51 | &:hover { 52 | color: var(--aero-brand); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /packages/renderer/util/classes.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | export const Margin = { 20 | Top: { 21 | 1: "mt-1", 22 | 2: "mt-2", 23 | 3: "mt-3", 24 | 4: "mt-4", 25 | }, 26 | Bottom: { 27 | 1: "mb-1", 28 | 2: "mb-2", 29 | 3: "mb-3", 30 | 4: "mb-4", 31 | }, 32 | Left: { 33 | 1: "ml-1", 34 | 2: "ml-2", 35 | 3: "ml-3", 36 | 4: "ml-4", 37 | }, 38 | Right: { 39 | 1: "mr-1", 40 | 2: "mr-2", 41 | 3: "mr-3", 42 | 4: "mr-4", 43 | }, 44 | }; 45 | 46 | export const c = (...names: (string | string[] | Record)[]): string => { 47 | const classNames = new Set(); 48 | 49 | for (const name of names) { 50 | switch (typeof name) { 51 | case "string": 52 | classNames.add(name); 53 | break; 54 | case "object": 55 | if (Array.isArray(name)) { 56 | name.forEach((n) => classNames.add(n)); 57 | } else { 58 | for (const [key, value] of Object.entries(name)) { 59 | if (value) classNames.add(key); 60 | } 61 | } 62 | break; 63 | } 64 | } 65 | 66 | return [...classNames].join(" "); 67 | }; 68 | -------------------------------------------------------------------------------- /packages/renderer/util/markdown.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | import type { ReactNode } from "react"; 20 | 21 | import { getModule } from "~/renderer/api/webpack"; 22 | 23 | import logger from "../../common/logger"; 24 | 25 | let mdModule: Record< 26 | | "parse" 27 | | "parseTopic" 28 | | "parseEmbedTitle" 29 | | "parseInlineReply" 30 | | "parseGuildVerificationFormRule" 31 | | "parseGuildEventDescription" 32 | | "parseAutoModerationSystemMessage" 33 | | "parseForumPostGuidelines" 34 | | "parseForumPostMostRecentMessage", 35 | (content: string, inline?: boolean, state?: Record) => ReactNode[] 36 | > & 37 | Record< 38 | "defaultRules" | "guildEventRules", 39 | Record> 40 | >; 41 | 42 | export default ( 43 | content: string, 44 | inline?: boolean, 45 | options?: Partial<{ 46 | allowLinks: boolean; 47 | allowEmojiLinks: boolean; 48 | channelId?: string; 49 | mentionChannels: string[]; 50 | isInteracting: boolean; 51 | formatInline: boolean; 52 | noStyleAndInteraction: boolean; 53 | allowHeading: boolean; 54 | allowList: boolean; 55 | previewLinkTarget: boolean; 56 | disableAnimatedEmoji: boolean; 57 | disableAutoBlockNewlines: boolean; 58 | }> 59 | ) => { 60 | if (!mdModule) mdModule = getModule(["parse", "defaultRules"]); 61 | 62 | if (!mdModule) { 63 | logger.warn("Aero failed to load the markdown module. This may cause unintended behavior."); 64 | 65 | return content; 66 | } 67 | 68 | return mdModule.parse(content, inline, options); 69 | }; 70 | -------------------------------------------------------------------------------- /packages/renderer/util/polyfill.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | export const { localStorage } = window; 20 | 21 | export const originalConsole = { 22 | // destroy the reference to the one discord modifies 23 | ...window.console, 24 | }; 25 | 26 | export default () => { 27 | // we're keeping this here for now, but it's not really needed anymore 28 | }; 29 | -------------------------------------------------------------------------------- /packages/renderer/util/preview.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | import { showModal } from "../api/notifications"; 20 | import { getModule } from "../api/webpack"; 21 | import markdown from "./markdown"; 22 | import { sleep } from "./time"; 23 | 24 | import { ModalSize, ModalContent, ModalFooter, ModalHeader } from "../ui/components/Modal"; 25 | import Button, { ButtonColor, ButtonSize } from "../ui/components/Button"; 26 | import FormTitle from "../ui/components/FormTitle"; 27 | 28 | export default async () => { 29 | await sleep(10000); 30 | 31 | if (window.aeroNative.channel === "preview") 32 | showModal( 33 | (close) => ( 34 | <> 35 | 36 | 37 | Aero Preview Build 38 | 39 | 40 | 41 | {markdown( 42 | ` 43 | You are using a distributed preview build of Aero. **Do not:** 44 | 45 | - Distribute this build. 46 | - Share screenshots of this build. 47 | - Share any information about this build *except* to Aero core team members. 48 | 49 | To continue using this build, press the button below. If you do not agree to these terms, please close this window and install the stable build of Aero. 50 | `.trim(), 51 | false, 52 | { 53 | allowList: true, 54 | } 55 | )} 56 | 57 | 58 | 61 | 62 | 63 | ), 64 | ModalSize.Small 65 | ); 66 | }; 67 | -------------------------------------------------------------------------------- /packages/renderer/util/react.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | export function makeLazy(factory: () => T): () => T { 20 | let cache: T; 21 | return () => cache ?? (cache = factory()); 22 | } 23 | 24 | export function LazyComponent(factory: () => React.ComponentType) { 25 | const get = makeLazy(factory); 26 | 27 | return (props: T) => { 28 | const Component = get(); 29 | 30 | return ; 31 | }; 32 | } 33 | -------------------------------------------------------------------------------- /packages/renderer/util/time.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | export const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); 20 | -------------------------------------------------------------------------------- /scripts/common.js: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | /* eslint-disable no-console */ 20 | 21 | // @ts-check 22 | 23 | import process from "node:process"; 24 | import path from "node:path"; 25 | import fs from "node:fs"; 26 | import os from "node:os"; 27 | 28 | export const channels = ["stable", "canary", "ptb"]; 29 | 30 | export const known = { 31 | darwin: { 32 | stable: ["/Applications/Discord.app/Contents/Resources/"], 33 | canary: ["/Applications/Discord Canary.app/Contents/Resources/"], 34 | ptb: ["/Applications/Discord PTB.app/Contents/Resources/"], 35 | }, 36 | win32: { 37 | stable: [path.join(os.homedir(), "AppData", "Local", "Discord")], 38 | canary: [path.join(os.homedir(), "AppData", "Local", "DiscordCanary")], 39 | ptb: [path.join(os.homedir(), "AppData", "Local", "DiscordPTB")], 40 | }, 41 | linux: { 42 | stable: [ 43 | path.join(os.homedir(), ".config", "discord"), 44 | "/usr/share/discord/resources/", 45 | "/usr/lib/discord/resources/", 46 | "/usr/opt/discord/resources/", 47 | "/opt/discord/resources", 48 | ], 49 | canary: [ 50 | path.join(os.homedir(), ".config", "discordcanary"), 51 | "/usr/share/discordcanary/resources/", 52 | "/usr/lib/discordcanary/resources/", 53 | "/usr/opt/discordcanary/resources/", 54 | "/opt/discord-canary/resources", 55 | ], 56 | ptb: [ 57 | path.join(os.homedir(), ".config", "discordptb"), 58 | "/usr/share/discordptb/resources/", 59 | "/usr/lib/discordptb/resources/", 60 | "/usr/opt/discordptb/resources/", 61 | "/opt/discord-ptb/resources", 62 | ], 63 | }, 64 | }; 65 | 66 | export const getAppPath = async (channel) => { 67 | const appPaths = known[process.platform]?.[channel] ?? []; 68 | 69 | for (const appPath of appPaths) { 70 | if (fs.statSync(appPath).isDirectory()) { 71 | let p = appPath; 72 | 73 | if (process.platform === "win32") { 74 | const files = fs.readdirSync(p); 75 | 76 | const appDir = files.find((f) => f.startsWith("app-")); 77 | 78 | if (appDir) { 79 | p = path.join(p, appDir, "resources"); 80 | } 81 | 82 | p = p.replace(/^\\/g, ""); 83 | } 84 | 85 | return p; 86 | } 87 | } 88 | 89 | throw new Error(`Could not find Discord ${channel} installation.`); 90 | }; 91 | 92 | export const banner = (name) => { 93 | console.log(`\u001b[1m\u001b[32maero: ${name}\u001b[0m`); 94 | }; 95 | -------------------------------------------------------------------------------- /scripts/inject.js: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | /* eslint-disable no-console */ 20 | 21 | // @ts-check 22 | 23 | import process from "node:process"; 24 | import path from "node:path"; 25 | import fs from "node:fs"; 26 | 27 | import { banner, channels, getAppPath } from "./common.js"; 28 | import { uninject } from "./uninject.js"; 29 | 30 | const safify = (str) => str.replace(/\\/g, "\\\\").replace("\\C:", "C:"); 31 | 32 | let channel = ""; 33 | let customPath = null; 34 | if (channels.includes(process.argv[2])) { 35 | channel = process.argv[2]; 36 | } else { 37 | customPath = process.argv[2]; 38 | } 39 | 40 | const inject = async () => { 41 | const appPath = customPath ?? await getAppPath(channel); 42 | 43 | console.log(""); 44 | 45 | console.log(`Injecting Discord ${channel}...`); 46 | 47 | const asarPath = path.join(appPath, "app.asar"); 48 | const newAsarPath = path.join(appPath, "app.old.asar"); 49 | const patchedPath = path.join(appPath, "app"); 50 | 51 | if (fs.existsSync(patchedPath)) { 52 | console.log(`Discord ${channel} is already injected, attempting to uninject...`); 53 | 54 | console.log(""); 55 | 56 | await uninject(); 57 | 58 | console.log(""); 59 | } 60 | 61 | if (!fs.existsSync(asarPath)) { 62 | throw new Error(`Could not find app.asar in Discord ${channel} installation.`); 63 | } 64 | 65 | await fs.promises.rename(asarPath, newAsarPath); 66 | 67 | await fs.promises.mkdir(patchedPath); 68 | 69 | await fs.promises.writeFile( 70 | path.join(patchedPath, "index.js"), 71 | `require("${safify(path.join(process.cwd(), "dist/main.js"))}")\n\nmodule.exports = require("${safify( 72 | newAsarPath 73 | )}");` 74 | ); 75 | await fs.promises.writeFile( 76 | path.join(patchedPath, "package.json"), 77 | JSON.stringify({ name: "discord", main: "index.js" }) 78 | ); 79 | 80 | console.log("Successfully patched app.asar."); 81 | 82 | console.log(""); 83 | 84 | console.log(`\u001b[1m\u001b[32mInjected Discord ${channel} successfully.\u001b[0m`); 85 | }; 86 | 87 | if (process.argv[1]?.endsWith("inject.js")) { 88 | banner("inject"); 89 | 90 | await inject(); 91 | } 92 | -------------------------------------------------------------------------------- /scripts/uninject.js: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of Aero, a next-generation Discord mod empowering users and developers alike. 3 | * Copyright (c) 2023 TheCommieAxolotl & contributors. 4 | * 5 | * Aero is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Aero is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Aero. If not, see . 17 | */ 18 | 19 | /* eslint-disable no-console */ 20 | 21 | // @ts-check 22 | 23 | import process from "node:process"; 24 | import path from "node:path"; 25 | import fs from "node:fs"; 26 | 27 | import { banner, channels, getAppPath } from "./common.js"; 28 | 29 | let channel = ""; 30 | let customPath = null; 31 | if (channels.includes(process.argv[2])) { 32 | channel = process.argv[2]; 33 | } else { 34 | customPath = process.argv[2]; 35 | } 36 | 37 | export const uninject = async () => { 38 | const appPath = customPath ?? await getAppPath(channel); 39 | 40 | console.log(""); 41 | 42 | console.log(`Uninjecting Discord ${channel}...`); 43 | 44 | const asarPath = path.join(appPath, "app.asar"); 45 | const newAsarPath = path.join(appPath, "app.old.asar"); 46 | const patchedPath = path.join(appPath, "app"); 47 | 48 | if (fs.existsSync(newAsarPath)) { 49 | await fs.promises.rename(newAsarPath, asarPath); 50 | } 51 | 52 | if (fs.existsSync(patchedPath)) { 53 | await fs.promises.rm(patchedPath, { recursive: true }); 54 | } 55 | 56 | console.log(""); 57 | 58 | console.log(`\u001b[1m\u001b[32mUninjected Discord ${channel} successfully.\u001b[0m`); 59 | }; 60 | 61 | if (process.argv[1]?.endsWith("uninject.js")) { 62 | banner("uninject"); 63 | 64 | await uninject(); 65 | } 66 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "jsx": "react", 4 | "jsxFactory": "window.aero.webpack.common.React.createElement", 5 | "jsxFragmentFactory": "window.aero.webpack.common.React.Fragment", 6 | "target": "ESNext", 7 | "module": "ESNext", 8 | "lib": ["ESNext", "DOM"], 9 | "esModuleInterop": true, 10 | "resolveJsonModule": true, 11 | "allowSyntheticDefaultImports": true, 12 | "moduleResolution": "node", 13 | "paths": { 14 | "~/*": ["./packages/*"], 15 | "~content/*": ["./*"] 16 | } 17 | } 18 | } 19 | --------------------------------------------------------------------------------