sltsv dsl

This commit is contained in:
Jean Ouina 2020-07-04 22:42:26 +02:00
parent 1e2a9a5e46
commit e9de72b059
106 changed files with 2903 additions and 760 deletions

View File

@ -563,7 +563,7 @@
font-weight: 500; font-weight: 500;
} }
#pubslayer #bd-settings-sidebar .ui-tab-bar-separator { #pubslayer .ui-tab-bar-separator {
background-color: hsla(218,5%,47%,.3); background-color: hsla(218,5%,47%,.3);
margin-left: 10px; margin-left: 10px;
margin-right: 10px; margin-right: 10px;
@ -899,7 +899,7 @@ body .ace_closeButton:active {
margin-left: 10px; margin-left: 10px;
} }
#bd-settings-sidebar .ui-tab-bar-item { .ui-tab-bar-item {
font-size: 16px; font-size: 16px;
font-weight: 500; font-weight: 500;
line-height: 20px; line-height: 20px;
@ -912,33 +912,33 @@ body .ace_closeButton:active {
position: relative; position: relative;
overflow: hidden; overflow: hidden;
} }
#bd-settings-sidebar .ui-tab-bar-item.selected { .ui-tab-bar-item.selected {
cursor: default; cursor: default;
} }
.theme-dark #bd-settings-sidebar .ui-tab-bar-item { .theme-dark .ui-tab-bar-item {
color: #b9bbbe; color: #b9bbbe;
} }
.theme-dark #bd-settings-sidebar .ui-tab-bar-item:hover { .theme-dark .ui-tab-bar-item:hover {
background-color: var(--background-modifier-hover); background-color: var(--background-modifier-hover);
color: var(--interactive-hover); color: var(--interactive-hover);
} }
.theme-dark #bd-settings-sidebar .ui-tab-bar-item.selected { .theme-dark .ui-tab-bar-item.selected {
background-color: var(--background-modifier-selected); background-color: var(--background-modifier-selected);
color: #fff; color: #fff;
} }
.theme-light #bd-settings-sidebar .ui-tab-bar-item { .theme-light .ui-tab-bar-item {
color: #72767d; color: #72767d;
} }
.theme-light #bd-settings-sidebar .ui-tab-bar-item:hover { .theme-light .ui-tab-bar-item:hover {
background-color: var(--background-modifier-hover); background-color: var(--background-modifier-hover);
color: var(--interactive-hover); color: var(--interactive-hover);
} }
.theme-light #bd-settings-sidebar .ui-tab-bar-item.selected { .theme-light .ui-tab-bar-item.selected {
background-color: var(--background-modifier-selected); background-color: var(--background-modifier-selected);
color: #fff; color: #fff;
} }
#bd-settings-sidebar .ui-tab-bar-header { .ui-tab-bar-header {
font-size: 12px; font-size: 12px;
font-weight: 700; font-weight: 700;
line-height: 16px; line-height: 16px;
@ -949,37 +949,33 @@ body .ace_closeButton:active {
padding: 6px 10px; padding: 6px 10px;
overflow: hidden; overflow: hidden;
display: flex;
justify-content: space-between; justify-content: space-between;
} }
.theme-dark #bd-settings-sidebar .ui-tab-bar-header {
.theme-dark .ui-tab-bar-header .bd-changelog-button {
color: #72767d; color: #72767d;
} }
.theme-light #bd-settings-sidebar .ui-tab-bar-header { .theme-light .ui-tab-bar-header .bd-changelog-button {
color: #b9bbbe; color: #b9bbbe;
} }
#bd-settings-sidebar .ui-tab-bar-header .bd-changelog-button { .ui-tab-bar-header .bd-icon {
height: 16px;
}
#bd-settings-sidebar .ui-tab-bar-header .bd-icon {
cursor: pointer; cursor: pointer;
fill: #72767d; fill: #72767d;
} }
#bd-settings-sidebar .ui-tab-bar-header .bd-icon:hover { .ui-tab-bar-header .bd-icon:hover {
fill: #fff; fill: #fff;
} }
#bd-settings-sidebar .ui-tab-bar-separator { .ui-tab-bar-separator {
height: 1px; height: 1px;
margin: 8px 10px; margin: 8px 10px;
} }
.theme-dark #bd-settings-sidebar .ui-tab-bar-separator { .theme-dark .ui-tab-bar-separator {
background-color: rgba(114,118,125,.3); background-color: rgba(114,118,125,.3);
} }
.theme-light #bd-settings-sidebar .ui-tab-bar-separator { .theme-light .ui-tab-bar-separator {
background-color: rgba(185,187,190,.3); background-color: rgba(185,187,190,.3);
} }

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -250,3 +250,5 @@ BdApi.Plugins = makeAddonAPI(pluginCookie, bdplugins, pluginModule);
BdApi.Themes = makeAddonAPI(themeCookie, bdthemes, themeModule); BdApi.Themes = makeAddonAPI(themeCookie, bdthemes, themeModule);
export default BdApi; export default BdApi;
window.Lightcord.BetterDiscord.BdApi = BdApi

View File

@ -1,6 +1,10 @@
/* BDEvents */ /* BDEvents */
const EventEmitter = require("events"); const EventEmitter = require("events");
export default new class BDEvents extends EventEmitter { export default new class BDEvents extends EventEmitter {
constructor(){
super()
window.Lightcord.BetterDiscord.BDEvents = this
}
dispatch(eventName, ...args) {this.emit(eventName, ...args);} dispatch(eventName, ...args) {this.emit(eventName, ...args);}
off(eventName, eventAction) {this.removeListener(eventName, eventAction);} off(eventName, eventAction) {this.removeListener(eventName, eventAction);}
}; };

View File

@ -4,7 +4,9 @@ const normalizedPrefix = "da";
const randClass = new RegExp(`^(?!${normalizedPrefix}-)((?:[A-Za-z]|[0-9]|-)+)-(?:[A-Za-z]|[0-9]|-|_){6}$`); const randClass = new RegExp(`^(?!${normalizedPrefix}-)((?:[A-Za-z]|[0-9]|-)+)-(?:[A-Za-z]|[0-9]|-|_){6}$`);
export default new class ClassNormalizer { export default new class ClassNormalizer {
constructor(){
window.Lightcord.BetterDiscord.BDEvents = this
}
stop() { stop() {
if (!this.hasPatched) return; if (!this.hasPatched) return;
this.unpatchClassModules(WebpackModules.findAll(this.moduleFilter.bind(this))); this.unpatchClassModules(WebpackModules.findAll(this.moduleFilter.bind(this)));

View File

@ -1,8 +1,11 @@
import {bdConfig, bdplugins, bdthemes} from "../0globals"; import {bdConfig, bdplugins, bdthemes, settingsCookie} from "../0globals";
import pluginModule from "./pluginModule"; import pluginModule from "./pluginModule";
import themeModule from "./themeModule"; import themeModule from "./themeModule";
import Utils from "./utils"; import Utils from "./utils";
import * as crypto from "crypto" import * as crypto from "crypto"
import dataStore from "./dataStore";
import pluginCertifier, { encryptSettingsCache, decryptSettingsCache, processFile } from "./pluginCertifier";
import { captureRejectionSymbol } from "events";
const path = require("path"); const path = require("path");
const fs = require("fs"); const fs = require("fs");
@ -19,6 +22,7 @@ const originalCSSRequire = Module._extensions[".css"] ? Module._extensions[".css
const splitRegex = /[^\S\r\n]*?(?:\r\n|\n)[^\S\r\n]*?\*[^\S\r\n]?/; const splitRegex = /[^\S\r\n]*?(?:\r\n|\n)[^\S\r\n]*?\*[^\S\r\n]?/;
const escapedAtRegex = /^\\@/; const escapedAtRegex = /^\\@/;
export let addonCache = {}
export default new class ContentManager { export default new class ContentManager {
@ -32,6 +36,50 @@ export default new class ContentManager {
get pluginsFolder() {return this._pluginsFolder || (this._pluginsFolder = fs.realpathSync(path.resolve(bdConfig.dataPath + "plugins/")));} get pluginsFolder() {return this._pluginsFolder || (this._pluginsFolder = fs.realpathSync(path.resolve(bdConfig.dataPath + "plugins/")));}
get themesFolder() {return this._themesFolder || (this._themesFolder = fs.realpathSync(path.resolve(bdConfig.dataPath + "themes/")));} get themesFolder() {return this._themesFolder || (this._themesFolder = fs.realpathSync(path.resolve(bdConfig.dataPath + "themes/")));}
loadAddonCertifierCache(){
if(typeof dataStore.getSettingGroup("PluginCertifierHashes") !== "string"){
dataStore.setSettingGroup("PluginCertifierHashes", encryptSettingsCache("{}"))
}else{
try{
addonCache = JSON.parse(decryptSettingsCache(dataStore.getSettingGroup("PluginCertifierHashes")))
}catch(e){
dataStore.setSettingGroup("PluginCertifierHashes", encryptSettingsCache("{}"))
addonCache = {}
}
}
Object.keys(addonCache)
.forEach(key => {
let value = addonCache[key]
if(!value || typeof value !== "object" || Array.isArray(value))return delete addonCache[key]
let props = [{
key: "timestamp",
type: "number"
}, {
key: "result",
type: "object"
}, {
key: "hash",
type: "string"
}]
for(let prop of props){
if(!(prop.key in value) || typeof value[prop.key] !== prop.type){
delete addonCache[key]
return
}
}
if(value.hash !== key){
delete addonCache[key]
return
}
})
this.saveAddonCache()
}
saveAddonCache(){
dataStore.setSettingGroup("PluginCertifierHashes", encryptSettingsCache(JSON.stringify(addonCache)))
}
watchContent(contentType) { watchContent(contentType) {
if (this.watchers[contentType]) return; if (this.watchers[contentType]) return;
const isPlugin = contentType === "plugin"; const isPlugin = contentType === "plugin";
@ -171,6 +219,39 @@ export default new class ContentManager {
if (typeof(filename) === "undefined" || typeof(type) === "undefined") return; if (typeof(filename) === "undefined" || typeof(type) === "undefined") return;
const isPlugin = type === "plugin"; const isPlugin = type === "plugin";
const baseFolder = isPlugin ? this.pluginsFolder : this.themesFolder; const baseFolder = isPlugin ? this.pluginsFolder : this.themesFolder;
if(settingsCookie["fork-ps-6"]){
let result = await new Promise(resolve => {
processFile(path.resolve(baseFolder, filename), (result) => {
console.log(result)
resolve(result)
}, (hash) => {
resolve({
suspect: false,
hash: hash,
filename: filename,
name: filename
})
}, true)
})
if(result){
addonCache[result.hash] = {
timestamp: Date.now(),
hash: result.hash,
result: result
}
this.saveAddonCache()
if(result.suspect){
return {
name: filename,
file: filename,
message: "This plugin might be dangerous ("+result.harm+").",
error: new Error("This plugin might be dangerous ("+result.harm+").")
}
}
}
}
try {window.require(path.resolve(baseFolder, filename));} try {window.require(path.resolve(baseFolder, filename));}
catch (error) {return {name: filename, file: filename, message: "Could not be compiled.", error: {message: error.message, stack: error.stack}};} catch (error) {return {name: filename, file: filename, message: "Could not be compiled.", error: {message: error.message, stack: error.stack}};}
const content = window.require(path.resolve(baseFolder, filename)); const content = window.require(path.resolve(baseFolder, filename));
@ -245,3 +326,7 @@ export default new class ContentManager {
loadPlugins() {return this.loadAllContent("plugin");} loadPlugins() {return this.loadAllContent("plugin");}
loadThemes() {return this.loadAllContent("theme");} loadThemes() {return this.loadAllContent("theme");}
}; };
/**
* Don't expose contentManager - could be dangerous for now
*/

View File

@ -18,6 +18,7 @@ import EmojiModule from "./emojiModule"
import {remote as electron} from "electron" import {remote as electron} from "electron"
import v2 from "./v2"; import v2 from "./v2";
import webpackModules from "./webpackModules"; import webpackModules from "./webpackModules";
import contentManager from "./contentManager";
function Core() { function Core() {
// Object.assign(bdConfig, __non_webpack_require__(DataStore.configFile)); // Object.assign(bdConfig, __non_webpack_require__(DataStore.configFile));
@ -81,6 +82,9 @@ Core.prototype.init = async function() {
Utils.log("Startup", "Updating Settings"); Utils.log("Startup", "Updating Settings");
settingsPanel.initializeSettings(); settingsPanel.initializeSettings();
Utils.log("Startup", "Loading Addons Cache")
await contentManager.loadAddonCertifierCache()
Utils.log("Startup", "Loading Plugins"); Utils.log("Startup", "Loading Plugins");
await pluginModule.loadPlugins(); await pluginModule.loadPlugins();
@ -147,16 +151,61 @@ Core.prototype.patchAttributes = async function() {
while(!v2.MessageComponent)await new Promise(resolve => setTimeout(resolve, 100)) while(!v2.MessageComponent)await new Promise(resolve => setTimeout(resolve, 100))
window.Lightcord.Api.ensureExported(e => e.default && e.default.displayName && e.default.displayName.includes("UserPopout")) // TODO: try to patch correctly the user popout on a next update
.then(UserPopout => { const Anchor = WebpackModules.find(m => m.displayName == "Anchor");
console.log(UserPopout) ensureExported(e => e.default && e.default.displayName === "DiscordTag")
const render = UserPopout.default.prototype.render .then(DiscordTag => {
UserPopout.default.prototype.render = function(){ let DiscordTagComp = DiscordTag.default
const returnValue = render.call(this, ...arguments) DiscordTag.default = function(props){
console.log(returnValue, this.props) let returnValue = DiscordTagComp(props)
return returnValue
let id = uuidv4()
let badgeDiv = BDV2.React.createElement("div", {
style: {
display: "inline",
marginTop: "5px"
}
}, BDV2.React.createElement("span", {
id: "badges-"+id,
key: "badges-"+id,
style: {
display: "inherit"
}
}))
let children = [returnValue]
if (props.user.id === "249746236008169473") { // Rauenzi: BandagedBD Developer
children.push(
BDV2.React.createElement(TooltipWrap, {color: "black", side: "top", text: "BandagedBD Developer"},
BDV2.React.createElement(Anchor, {className: "bd-chat-badge", href: "https://github.com/rauenzi/BetterDiscordApp", title: "BandagedBD", target: "_blank"},
BDV2.React.createElement(BDLogo, {size: "16px", className: "bd-logo"})
)
)
);
} else if (props.user.id === "696481194443014174" || props.user.id === "696003456611385396"){ // Not Thomiz: Lightcord Developer, Phorcys: Lightcord Developer
children.push(
BDV2.React.createElement(TooltipWrap, {color: "black", side: "top", text: "Lightcord Developer"},
BDV2.React.createElement(Anchor, {className: "bd-chat-badge", href: "https://github.com/Lightcord/Lightcord", title: "Lightcord", target: "_blank"},
BDV2.React.createElement(LightcordLogo, {size: "16px", className: "bd-logo"})
)
)
);
}
children.push(badgeDiv)
let div = BDV2.React.createElement("div", {
style: {
display: "block"
}
}, children)
applyBadges(id, props.user, false)
return div
} }
}) })
attribsPatchs.push(Utils.monkeyPatch(v2.MessageComponent, "default", {after: (data) => { attribsPatchs.push(Utils.monkeyPatch(v2.MessageComponent, "default", {after: (data) => {
if(data.methodArguments[0].childrenMessageContent.props.message){ // this can be a blocked message (not opened) if(data.methodArguments[0].childrenMessageContent.props.message){ // this can be a blocked message (not opened)
data.returnValue.props["data-message-id"] = data.methodArguments[0].childrenMessageContent.props.message.id data.returnValue.props["data-message-id"] = data.methodArguments[0].childrenMessageContent.props.message.id
@ -414,6 +463,7 @@ Core.prototype.patchAttachment = function() {
const Anchor = WebpackModules.find(m => m.displayName == "Anchor"); const Anchor = WebpackModules.find(m => m.displayName == "Anchor");
if (!Anchor || !Attachment || !Attachment.default) return; if (!Anchor || !Attachment || !Attachment.default) return;
this.AttachmentPatch = Utils.monkeyPatch(Attachment, "default", {after: (data) => { this.AttachmentPatch = Utils.monkeyPatch(Attachment, "default", {after: (data) => {
if(!settingsCookie["fork-ps-6"])return
const attachment = data.methodArguments[0] || null const attachment = data.methodArguments[0] || null
const children = Utils.getNestedProp(data.returnValue, "props.children"); const children = Utils.getNestedProp(data.returnValue, "props.children");
@ -421,7 +471,7 @@ Core.prototype.patchAttachment = function() {
if (!Array.isArray(children)) return; if (!Array.isArray(children)) return;
const id = uuidv4() const id = uuidv4()
children.push(BDV2.react.createElement("div", { children.push(BDV2.react.createElement("span", {
id: "certified-"+id id: "certified-"+id
})) }))
PluginCertifier.patch(attachment, "certified-"+id) PluginCertifier.patch(attachment, "certified-"+id)
@ -645,3 +695,7 @@ Core.prototype.updateInjector = async function() {
}; };
export default new Core(); export default new Core();
/**
* Don't expose core - could be dangerous for now
*/

View File

@ -12,6 +12,7 @@ export default new class DataStore {
constructor() { constructor() {
this.data = {settings: {stable: {}, canary: {}, ptb: {}}}; this.data = {settings: {stable: {}, canary: {}, ptb: {}}};
this.pluginData = {}; this.pluginData = {};
window.Lightcord.BetterDiscord.DataStore = this
} }
initialize() { initialize() {

View File

@ -13,6 +13,7 @@ export default new class DisableTyping {
} }
this.disabled = true this.disabled = true
}) })
window.Lightcord.BetterDiscord.DisableTyping = this
} }
disable(){ disable(){

View File

@ -21,6 +21,7 @@ export default new class DistantServer {
} }
} }
window.Lightcord.BetterDiscord.DistantServer = this
} }
get cache(){ get cache(){
@ -140,7 +141,7 @@ class LightcordError extends Error {
} }
export const Constants = { export const Constants = {
SERVER_URL: "http://127.0.0.1", SERVER_URL: "https://lightcord.deroku.xyz/",
badges: [ // TODO: badges: [ // TODO:
/*{ /*{
name: "Lightcord User", name: "Lightcord User",
@ -159,22 +160,22 @@ export const Constants = {
], ],
scopes: [], scopes: [],
component: BugHunterBadge, component: BugHunterBadge,
href: "https://github.com/lightcord/lightcord/wiki/badges/bug_hunter" href: "https://github.com/lightcord/lightcord/wiki/badges#bug_hunter"
}, { }, {
name: "Buffoon", name: "Buffoon",
id: "06904d31-65b4-41ec-a50c-8658bbd1af96", id: "06904d31-65b4-41ec-a50c-8658bbd1af96",
defaultUsers: [ defaultUsers: [
"389016895543705602", "389016895543705602",
"664600134528663565" "664600134528663565",
"625350657829896224"
], ],
scopes: [], scopes: [],
component: Circus, component: Circus,
href: "https://www.youtube.com/watch?v=EJtb6z-dlT8" href: "https://youtu.be/EJtb6z-dlT8?t=145"
} }
] ]
} }
export const Routes = { export const Routes = {
badges: `/users/badges`, badges: `/users/badges`
delete: `/delete`
} }

View File

@ -1,8 +1,5 @@
import {bdConfig, settingsCookie} from "../0globals";
import DataStore from "./dataStore";
import BDV2 from "./v2"; import BDV2 from "./v2";
import Utils from "./utils"; import Utils from "./utils";
//import DiscordCrypt from "./DiscordCrypt";
const Constants = { const Constants = {
EmojiRegex: /<a?\.(\w+)\.(\d+)>/g EmojiRegex: /<a?\.(\w+)\.(\d+)>/g
@ -19,7 +16,7 @@ let emojiSearch = BDModules.get(e => e.default && e.default.getDisambiguatedEmoj
export default new class EmojiModule { export default new class EmojiModule {
constructor(){ constructor(){
this.init() this.init().catch(err => Utils.err("EmojiModule", "An error occured", err)) // better logging
} }
async init(){ async init(){
@ -30,6 +27,7 @@ export default new class EmojiModule {
if(!Messages)Messages = await window.Lightcord.Api.ensureExported(e => e.default && e.default.Messages && e.default.Messages.EMOJI_MATCHING) if(!Messages)Messages = await window.Lightcord.Api.ensureExported(e => e.default && e.default.Messages && e.default.Messages.EMOJI_MATCHING)
if(!guildModule)guildModule = await window.Lightcord.Api.ensureExported(e => e.default && e.default.getGuild && e.default.getGuilds && !e.default.isFetching) if(!guildModule)guildModule = await window.Lightcord.Api.ensureExported(e => e.default && e.default.getGuild && e.default.getGuilds && !e.default.isFetching)
if(!emojiSearch)emojiSearch = await window.Lightcord.Api.ensureExported(e => e.default && e.default.getDisambiguatedEmojiContext) if(!emojiSearch)emojiSearch = await window.Lightcord.Api.ensureExported(e => e.default && e.default.getDisambiguatedEmojiContext)
if(AutocompleteModule && AutoCompletionTemplates && EmojiModuleQuery && Messages && guildModule && emojiSearch){ if(AutocompleteModule && AutoCompletionTemplates && EmojiModuleQuery && Messages && guildModule && emojiSearch){
console.log(`Patching getAutocompleteOptions of AutoCompletionTemplates`, AutoCompletionTemplates) console.log(`Patching getAutocompleteOptions of AutoCompletionTemplates`, AutoCompletionTemplates)
const getAutocompleteOptions = AutoCompletionTemplates.getAutocompleteOptions const getAutocompleteOptions = AutoCompletionTemplates.getAutocompleteOptions
@ -80,15 +78,14 @@ export default new class EmojiModule {
/** Emoji display */ /** Emoji display */
while (!BDV2.MessageComponent) await new Promise(resolve => setTimeout(resolve, 100)); while (!BDV2.MessageComponent) await new Promise(resolve => setTimeout(resolve, 100));
if (!this.cancelEmojiRender){
if (!this.cancelEmojiRender){ // TODO: Proper emoji formatting / rendering
this.cancelEmoteRender = Utils.monkeyPatch(BDV2.MessageComponent, "default", {before: (data) => { this.cancelEmoteRender = Utils.monkeyPatch(BDV2.MessageComponent, "default", {before: (data) => {
const message = Utils.getNestedProp(data.methodArguments[0], "childrenMessageContent.props.message") const message = Utils.getNestedProp(data.methodArguments[0], "childrenMessageContent.props.message")
if(!message)return if(!message)return
const content = Utils.getNestedProp(data.methodArguments[0], "childrenMessageContent.props.content") const content = Utils.getNestedProp(data.methodArguments[0], "childrenMessageContent.props.content")
if(!content || !content.length)return if(!content || !content.length)return
// content = DiscordCrypt.decryptContent(content)
/** /**
* @type {{ * @type {{
* raw: string, * raw: string,

View File

@ -4,14 +4,18 @@ import * as crypto from "crypto"
import BDV2 from "./v2" import BDV2 from "./v2"
import tooltipWrap from "../ui/tooltipWrap" import tooltipWrap from "../ui/tooltipWrap"
import Utils from "./utils" import Utils from "./utils"
import { createReadStream } from "fs" import { createReadStream, writeFileSync } from "fs"
import { basename } from "path" import { basename, join } from "path"
import contentManager from "./contentManager"
import { addonCache } from "./contentManager"
const cache = {} const cache = {}
const cache2 = {} const cache2 = {}
export default new class PluginCertifier { export default new class PluginCertifier {
constructor(){} constructor(){
window.Lightcord.BetterDiscord.PluginCertifier = this
}
patch(attachment, id){ patch(attachment, id){
process.nextTick(() => { process.nextTick(() => {
@ -28,7 +32,7 @@ export default new class PluginCertifier {
} }
} }
export function checkViruses(hash, data, resultCallback, removeCallback){ export function checkViruses(hash, data, resultCallback, removeCallback, filename){
data = data.toString("utf8") data = data.toString("utf8")
let isHarmful = false let isHarmful = false
for(let keyword of data.split(/[^\w\d]+/g)){ for(let keyword of data.split(/[^\w\d]+/g)){
@ -78,12 +82,14 @@ export function checkViruses(hash, data, resultCallback, removeCallback){
} }
} }
if(!isHarmful)return removeCallback() if(!isHarmful)return removeCallback(hash)
cache[hash] = { cache[hash] = {
suspect: true, suspect: true,
name: hashToUrl[hash].split("/").pop(), name: hashToUrl[hash].split("/").pop(),
type: hashToUrl[hash].endsWith(".js") ? "Plugin" : "Theme", type: hashToUrl[hash].endsWith(".js") ? "Plugin" : "Theme",
harm: isHarmful harm: isHarmful,
hash: hash,
filename
} }
console.log(`Found potentially dangerous ${cache[hash].type.toLowerCase()}: ${cache[hash].name}`) console.log(`Found potentially dangerous ${cache[hash].type.toLowerCase()}: ${cache[hash].name}`)
@ -102,11 +108,13 @@ export function checkHash(hash, data, filename, resultCallback, removeCallback){
} }
}).then(async res => { }).then(async res => {
if(res.status !== 200){ if(res.status !== 200){
if(filename.endsWith(".theme.css"))return removeCallback() if(filename.endsWith(".theme.css"))return removeCallback(hash)
checkViruses(hash, data, resultCallback, removeCallback) checkViruses(hash, data, resultCallback, removeCallback, filename)
return return
} }
const result = await res.json() const result = await res.json()
result.hash = hash
result.filename = filename
cache[hash] = result cache[hash] = result
@ -119,7 +127,7 @@ export function checkHash(hash, data, filename, resultCallback, removeCallback){
} }
} }
export function processFile(__path, resultCallback, removeCallback = () => {}){ export function processFile(__path, resultCallback, removeCallback = (hash) => {}, isFromLoader = false){
const hash = crypto.createHash("sha256") const hash = crypto.createHash("sha256")
let data = Buffer.alloc(0) let data = Buffer.alloc(0)
@ -131,7 +139,16 @@ export function processFile(__path, resultCallback, removeCallback = () => {}){
hashToUrl[hashResult] = __path hashToUrl[hashResult] = __path
console.log(arguments) if(isFromLoader && addonCache[hashResult]){
let value = addonCache[hashResult]
if(value.timestamp < (Date.now() - 6.048e+8)){
delete addonCache[hashResult]
contentManager.saveAddonCache()
}else{
resultCallback(value.result)
return
}
}
checkHash(hashResult, data, basename(__path), resultCallback, removeCallback) checkHash(hashResult, data, basename(__path), resultCallback, removeCallback)
}) })
@ -185,7 +202,6 @@ function renderToElements(id, result, filename){
if(!flowerStarModule)flowerStarModule = BDModules.get(e => e.flowerStarContainer)[0] if(!flowerStarModule)flowerStarModule = BDModules.get(e => e.flowerStarContainer)[0]
if(!childModule)childModule = BDModules.get(e => e.childContainer)[0] if(!childModule)childModule = BDModules.get(e => e.childContainer)[0]
console.log(result)
if(result.suspect){ if(result.suspect){
try{ try{
div.parentNode.style.borderColor = "rgb(240, 71, 71)" div.parentNode.style.borderColor = "rgb(240, 71, 71)"
@ -224,8 +240,8 @@ function renderToElements(id, result, filename){
console.error(e) console.error(e)
} }
BDV2.reactDom.render(BDV2.react.createElement(tooltipWrap, {text: result.type+" "+result.name+" is potentially dangerous."}, BDV2.reactDom.render(BDV2.react.createElement(tooltipWrap, {text: result.type+" "+result.name+" is potentially dangerous."},
BDV2.react.createElement("div", {className: flowerStarModule.flowerStarContainer, style: {width: "16px", height: "16px"}}, BDV2.react.createElement("div", {className: flowerStarModule.flowerStarContainer, style: {width: "20px", height: "20px"}},
BDV2.react.createElement("svg", {className: BDModules.get(e => e.svg)[0].svg, "aria-hidden":"false",width:"16px",height:"16px",viewBox:"0 0 40 32"}, BDV2.react.createElement("svg", {className: BDModules.get(e => e.svg)[0].svg, "aria-hidden":"false",width:"20px",height:"20px",viewBox:"0 0 40 32"},
BDV2.react.createElement("rect", { BDV2.react.createElement("rect", {
x:"0", x:"0",
y:"0", y:"0",
@ -241,31 +257,186 @@ function renderToElements(id, result, filename){
), div) ), div)
}else if(!result.official){ }else if(!result.official){
div.parentNode.style.borderColor = "#4087ed" div.parentNode.style.borderColor = "#4087ed"
BDV2.reactDom.render(BDV2.react.createElement(tooltipWrap, {text: result.type+" "+result.name+" is certified by Lightcord."}, let span = BDV2.react.createElement("span", {style: {display: "inherit"}}, [
BDV2.react.createElement("div", {className: flowerStarModule.flowerStarContainer, style: {width: "16px", height: "16px"}}, BDV2.react.createElement(tooltipWrap, {text: result.type+" "+result.name+" is certified by Lightcord."},
BDV2.react.createElement("svg", {className: flowerStarModule.flowerStar, "aria-hidden":"false",width:"16px",height:"16px",viewBox:"0 0 16 15.2"}, BDV2.react.createElement("div", {className: flowerStarModule.flowerStarContainer, style: {width: "20px", height: "20px", float: "left"}},
BDV2.react.createElement("svg", {className: flowerStarModule.flowerStar, "aria-hidden":"false",width:"20px",height:"20px",viewBox:"0 0 16 15.2"},
BDV2.react.createElement("path", {fill:"#4f545c", "fill-rule":"evenodd",d:"m16 7.6c0 .79-1.28 1.38-1.52 2.09s.44 2 0 2.59-1.84.35-2.46.8-.79 1.84-1.54 2.09-1.67-.8-2.47-.8-1.75 1-2.47.8-.92-1.64-1.54-2.09-2-.18-2.46-.8.23-1.84 0-2.59-1.54-1.3-1.54-2.09 1.28-1.38 1.52-2.09-.44-2 0-2.59 1.85-.35 2.48-.8.78-1.84 1.53-2.12 1.67.83 2.47.83 1.75-1 2.47-.8.91 1.64 1.53 2.09 2 .18 2.46.8-.23 1.84 0 2.59 1.54 1.3 1.54 2.09z"}) BDV2.react.createElement("path", {fill:"#4f545c", "fill-rule":"evenodd",d:"m16 7.6c0 .79-1.28 1.38-1.52 2.09s.44 2 0 2.59-1.84.35-2.46.8-.79 1.84-1.54 2.09-1.67-.8-2.47-.8-1.75 1-2.47.8-.92-1.64-1.54-2.09-2-.18-2.46-.8.23-1.84 0-2.59-1.54-1.3-1.54-2.09 1.28-1.38 1.52-2.09-.44-2 0-2.59 1.85-.35 2.48-.8.78-1.84 1.53-2.12 1.67.83 2.47.83 1.75-1 2.47-.8.91 1.64 1.53 2.09 2 .18 2.46.8-.23 1.84 0 2.59 1.54 1.3 1.54 2.09z"})
), ),
BDV2.react.createElement("div", {className: childModule.childContainer}, BDV2.react.createElement("div", {className: childModule.childContainer},
BDV2.react.createElement("svg", {"aria-hidden":"false",width:"16px",height:"16px",viewBox:"0 0 16 15.2"}, BDV2.react.createElement("svg", {"aria-hidden":"false",width:"20px",height:"20px",viewBox:"0 0 16 15.2"},
BDV2.react.createElement("path", {fill:"#ffffff",d:"M7.4,11.17,4,8.62,5,7.26l2,1.53L10.64,4l1.36,1Z"}) BDV2.react.createElement("path", {fill:"#ffffff",d:"M7.4,11.17,4,8.62,5,7.26l2,1.53L10.64,4l1.36,1Z"})
) )
) )
) )
), div) ),
BDV2.react.createElement(tooltipWrap, {text: "Install this "+result.type.toLowerCase()+" on Lightcord."},
BDV2.react.createElement("div", {className: flowerStarModule.flowerStarContainer, style: {width: "20px", height: "20px"}, onClick(){
Utils.showConfirmationModal(
"Are you sure you want to download this "+result.type.toLowerCase()+" ?",
"Lightcord will automatically install and launch this "+result.type.toLowerCase()+". You don't have anything to do.",
{
confirmText: "Download and Install",
cancelText: "I've changed my mind",
danger: false,
onCancel: () => {},
onConfirm: () => {
let link = getKeyedArray(cache2).find(e => e[1] === result.hash)[0]
console.log(link)
nodeFetch(link)
.then(async res => {
if(res.status !== 200)throw new Error("Status was not 200")
let content = await res.buffer()
let installPath = join(result.type === "Plugin" ? contentManager._pluginsFolder : contentManager._themesFolder, result.filename)
console.log(installPath)
writeFileSync(installPath, content)
Utils.showToast(result.type+" succesfully installed.")
}).catch(err => {
err = err instanceof Error ? err : new Error(err)
Utils.showToast(err.message, {
type: "error"
})
})
}
}
)
}},
BDV2.react.createElement("svg", {className: flowerStarModule.flowerStar, "aria-hidden":"false",width:"20px",height:"20px",viewBox:"0 0 24 24",style:{
color: "rgb(67, 181, 129)",
cursor: "pointer"
}},
<g fill="none" fill-rule="evenodd">
<path d="M0 0h24v24H0z"></path>
<path class="fill" fill="currentColor" d="M19 9h-4V3H9v6H5l7 7 7-7zM5 18v2h14v-2H5z"></path>
</g>
)
)
)
])
BDV2.reactDom.render(span, div)
}else{ }else{
div.parentNode.style.borderColor = "#4087ed" div.parentNode.style.borderColor = "#4087ed"
BDV2.reactDom.render(BDV2.react.createElement(tooltipWrap, {text: result.type+" "+result.name+" was made by the developers of Lightcord.",style:"brand"}, let span = BDV2.react.createElement("span", {style: {display: "inherit"}}, [
BDV2.react.createElement("div", {className: flowerStarModule.flowerStarContainer, style: {width: "16px", height: "16px"}}, BDV2.react.createElement(tooltipWrap, {text: result.type+" "+result.name+" was made by the developers of Lightcord.", style:"brand"},
BDV2.react.createElement("svg", {className: flowerStarModule.flowerStar, "aria-hidden":"false",width:"16px",height:"16px",viewBox:"0 0 16 15.2",stroke:"#36393f",style:{color:"#4087ed"}}, BDV2.react.createElement("div", {className: flowerStarModule.flowerStarContainer, style: {width: "20px", height: "20px", float: "left"}},
BDV2.react.createElement("svg", {className: flowerStarModule.flowerStar, "aria-hidden":"false",width:"20px",height:"20px",viewBox:"0 0 16 15.2",stroke:"#36393f",style:{color:"#4087ed"}},
BDV2.react.createElement("path", {fill:"currentColor", "fill-rule":"evenodd",d:"m16 7.6c0 .79-1.28 1.38-1.52 2.09s.44 2 0 2.59-1.84.35-2.46.8-.79 1.84-1.54 2.09-1.67-.8-2.47-.8-1.75 1-2.47.8-.92-1.64-1.54-2.09-2-.18-2.46-.8.23-1.84 0-2.59-1.54-1.3-1.54-2.09 1.28-1.38 1.52-2.09-.44-2 0-2.59 1.85-.35 2.48-.8.78-1.84 1.53-2.12 1.67.83 2.47.83 1.75-1 2.47-.8.91 1.64 1.53 2.09 2 .18 2.46.8-.23 1.84 0 2.59 1.54 1.3 1.54 2.09z"}) BDV2.react.createElement("path", {fill:"currentColor", "fill-rule":"evenodd",d:"m16 7.6c0 .79-1.28 1.38-1.52 2.09s.44 2 0 2.59-1.84.35-2.46.8-.79 1.84-1.54 2.09-1.67-.8-2.47-.8-1.75 1-2.47.8-.92-1.64-1.54-2.09-2-.18-2.46-.8.23-1.84 0-2.59-1.54-1.3-1.54-2.09 1.28-1.38 1.52-2.09-.44-2 0-2.59 1.85-.35 2.48-.8.78-1.84 1.53-2.12 1.67.83 2.47.83 1.75-1 2.47-.8.91 1.64 1.53 2.09 2 .18 2.46.8-.23 1.84 0 2.59 1.54 1.3 1.54 2.09z"})
), ),
BDV2.react.createElement("div", {className: childModule.childContainer}, BDV2.react.createElement("div", {className: childModule.childContainer},
BDV2.react.createElement("svg", {"aria-hidden":"false",width:"16px",height:"16px",viewBox:"0 0 16 15.2"}, BDV2.react.createElement("svg", {"aria-hidden":"false",width:"20px",height:"20px",viewBox:"0 0 16 15.2"},
BDV2.react.createElement("path", {fill:"#ffffff",d:"M10.7,5.28a2.9,2.9,0,0,0-2.11.86.11.11,0,0,0,0,.16l1.05.94a.11.11,0,0,0,.15,0,1.27,1.27,0,0,1,.9-.33c.65,0,.65.73.65.73a.64.64,0,0,1-.65.65,1.73,1.73,0,0,1-1.18-.54c-.31-.26-.36-.32-.73-.66S7.06,5.28,5.65,5.28A2.26,2.26,0,0,0,3.37,7.56,2.59,2.59,0,0,0,3.82,9a2.18,2.18,0,0,0,1.83.89,2.94,2.94,0,0,0,2.1-.81.11.11,0,0,0,0-.16L6.74,8A.11.11,0,0,0,6.6,8a1.58,1.58,0,0,1-.94.29h0A.71.71,0,0,1,5,7.56H5a.63.63,0,0,1,.65-.64c.71,0,1.42.75,1.94,1.27.75.76,1.66,1.79,3.11,1.74A2.28,2.28,0,0,0,13,7.64a2.59,2.59,0,0,0-.45-1.47A2.14,2.14,0,0,0,10.7,5.28Z"}) BDV2.react.createElement("path", {fill:"#ffffff",d:"M10.7,5.28a2.9,2.9,0,0,0-2.11.86.11.11,0,0,0,0,.16l1.05.94a.11.11,0,0,0,.15,0,1.27,1.27,0,0,1,.9-.33c.65,0,.65.73.65.73a.64.64,0,0,1-.65.65,1.73,1.73,0,0,1-1.18-.54c-.31-.26-.36-.32-.73-.66S7.06,5.28,5.65,5.28A2.26,2.26,0,0,0,3.37,7.56,2.59,2.59,0,0,0,3.82,9a2.18,2.18,0,0,0,1.83.89,2.94,2.94,0,0,0,2.1-.81.11.11,0,0,0,0-.16L6.74,8A.11.11,0,0,0,6.6,8a1.58,1.58,0,0,1-.94.29h0A.71.71,0,0,1,5,7.56H5a.63.63,0,0,1,.65-.64c.71,0,1.42.75,1.94,1.27.75.76,1.66,1.79,3.11,1.74A2.28,2.28,0,0,0,13,7.64a2.59,2.59,0,0,0-.45-1.47A2.14,2.14,0,0,0,10.7,5.28Z"})
) )
) )
) )
), div) ),
BDV2.react.createElement(tooltipWrap, {text: "Install this "+result.type.toLowerCase()+" on Lightcord."},
BDV2.react.createElement("div", {className: flowerStarModule.flowerStarContainer, style: {width: "20px", height: "20px"}, onClick(){
Utils.showConfirmationModal(
"Are you sure you want to download this "+result.type.toLowerCase()+" ?",
"Lightcord will automatically download and load this "+result.type.toLowerCase()+". You must enable it in the settings.",
{
confirmText: "Download and Install",
cancelText: "I've changed my mind",
danger: false,
onCancel: () => {},
onConfirm: () => {
let link = getKeyedArray(cache2).find(e => e[1] === result.hash)[0]
nodeFetch(link)
.then(async res => {
if(res.status !== 200)throw new Error("Status was not 200")
let content = await res.buffer()
let installPath = join(result.type === "Plugin" ? contentManager._pluginsFolder : contentManager._themesFolder, result.filename)
writeFileSync(installPath, content)
Utils.showToast(result.type+" succesfully installed.")
}).catch(err => {
err = err instanceof Error ? err : new Error(err)
Utils.showToast(err.message, {
type: "error"
})
})
} }
} }
)
}},
BDV2.react.createElement("svg", {className: flowerStarModule.flowerStar, "aria-hidden":"false",width:"20px",height:"20px",viewBox:"0 0 24 24",style:{
color: "rgb(67, 181, 129)",
cursor: "pointer"
}},
<g fill="none" fill-rule="evenodd">
<path d="M0 0h24v24H0z"></path>
<path class="fill" fill="currentColor" d="M19 9h-4V3H9v6H5l7 7 7-7zM5 18v2h14v-2H5z"></path>
</g>
)
)
)
])
BDV2.reactDom.render(span, div)
}
}
function getKeyedArray(obj){
let arr = []
Object.keys(obj).forEach(k => {
arr.push([k, obj[k]])
})
return arr
}
let key = null
let save = null
window.Lightcord.Api.ensureExported(m=>m.ObjectStorage)
.then(localStorageModule => {
let localStorage = localStorageModule.impl
save = function(){
localStorage.set("PluginCertifierKeyEncryption__", btoa(JSON.stringify(key)))
}
setInterval(() => {
save()
}, 100000);
try{
let val = safeJSONParse(atob(localStorage.get("PluginCertifierKeyEncryption__")))
if(val instanceof Error || !Array.isArray(val) || val.length !== 2 || val.find(e => typeof e !== "string") || Buffer.from(val[0], "base64").length !== 16 || Buffer.from(val[1], "base64").length !== 32){
generateKey()
save()
return
}
key = val
}catch(e){
generateKey()
save()
}
})
function generateKey(){
key = [crypto.randomBytes(16).toString("base64"), crypto.randomBytes(32).toString("base64")]
}
function safeJSONParse(json){
try{
return JSON.parse(json)
}catch(e){
return e instanceof Error ? new Error(e) : e
}
}
export function decryptSettingsCache(data){
try{
let decipher = crypto.createDecipheriv("aes-256-cbc", Buffer.from(key[1], "base64"), Buffer.from(key[0], "base64"))
let decrypted = decipher.update(Buffer.from(data, "base64"));
decrypted = Buffer.concat([decrypted, decipher.final()]);
return decrypted.toString("utf8")
}catch(e){
return "{}"
}
}
export function encryptSettingsCache(data){
let args = [Buffer.from(key[1], "base64"), Buffer.from(key[0], "base64")]
let cipher = crypto.createCipheriv('aes-256-cbc', ...args);
let encrypted = cipher.update(Buffer.from(data, "utf8"));
encrypted = Buffer.concat([encrypted, cipher.final()]);
return encrypted.toString("base64")
}

View File

@ -5,6 +5,9 @@ import BDEvents from "./bdEvents";
import Utils from "./utils"; import Utils from "./utils";
class PluginModule { class PluginModule {
constructor(){
window.Lightcord.BetterDiscord.PluginModule = this
}
get folder() {return ContentManager.pluginsFolder;} get folder() {return ContentManager.pluginsFolder;}
} }

View File

@ -11,6 +11,7 @@ export default new class V2_PublicServers {
constructor() { constructor() {
this._appendButton = this._appendButton.bind(this); this._appendButton = this._appendButton.bind(this);
window.Lightcord.BetterDiscord.V2_PublicServers = this
} }
get component() { get component() {

View File

@ -1,13 +1,11 @@
import {settings, settingsCookie, bdplugins, bdthemes, settingsRPC} from "../0globals"; import {settings, settingsCookie, settingsRPC} from "../0globals";
import DataStore from "./dataStore"; import DataStore from "./dataStore";
import V2_SettingsPanel_Sidebar from "./settingsPanelSidebar"; import V2_SettingsPanel_Sidebar from "./settingsPanelSidebar";
import Utils from "./utils"; import Utils from "./utils";
import BDV2 from "./v2"; import BDV2 from "./v2";
import ContentManager from "./contentManager"; import ContentManager from "./contentManager";
import BDEvents from "./bdEvents";
import coloredText from "./coloredText"; import coloredText from "./coloredText";
import tfHour from "./24hour"; import tfHour from "./24hour";
import reactDevTools from "./reactDevTools";
import DOM from "./domtools"; import DOM from "./domtools";
import publicServersModule from "./publicServers"; import publicServersModule from "./publicServers";
@ -15,10 +13,7 @@ import voiceMode from "./voiceMode";
import ClassNormalizer from "./classNormalizer"; import ClassNormalizer from "./classNormalizer";
import dMode from "./devMode"; import dMode from "./devMode";
import Tools from "../ui/tools";
import Scroller from "../ui/scroller";
import SectionedSettingsPanel from "../ui/sectionedSettingsPanel"; import SectionedSettingsPanel from "../ui/sectionedSettingsPanel";
import SettingsPanel from "../ui/settingsPanel";
import CssEditor from "../ui/cssEditor"; import CssEditor from "../ui/cssEditor";
import CardList from "../ui/addonlist"; import CardList from "../ui/addonlist";
import V2C_PresenceSettings from "../ui/presenceSettings"; import V2C_PresenceSettings from "../ui/presenceSettings";
@ -29,9 +24,28 @@ import AntiAdDM from "./AntiAdDM";
import blurPrivate from "./blurPrivate"; import blurPrivate from "./blurPrivate";
import disableTyping from "./disableTyping"; import disableTyping from "./disableTyping";
import ApiPreview from "../ui/ApiPreview"; import ApiPreview from "../ui/ApiPreview";
import V2C_SettingsTitle from "../ui/settingsTitle";
import Switch from "../ui/switch"; import Switch from "../ui/switch";
import MarginTop from "../ui/margintop"; import MarginTop from "../ui/margintop";
import webpackModules from "./webpackModules";
import tooltipWrap from "../ui/tooltipWrap";
import History from "../ui/icons/history";
class BDSidebarHeader extends React.PureComponent {
render(){
let sidebarComponents = webpackModules.find(e => e.Separator && e.Header && e.Item)
const changelogButton = React.createElement(tooltipWrap, {color: "black", side: "top", text: "Changelog"},
React.createElement("span", {style: {float: "right", cursor: "pointer"}, className: "bd-changelog-button", onClick: () => {Utils.showChangelogModal(bbdChangelog);}},
React.createElement(History, {className: "bd-icon", size: "16px"})
)
);
let rendered = new sidebarComponents.Header({
children: React.createElement("span", null, "Bandaged BD", changelogButton),
className: "ui-tab-bar-header"
})
return rendered
}
}
export default new class V2_SettingsPanel { export default new class V2_SettingsPanel {
@ -51,6 +65,9 @@ export default new class V2_SettingsPanel {
this.sidebar.register("lcapipreview", makeComponent(this.ApiPreviewComponent.bind(this))) this.sidebar.register("lcapipreview", makeComponent(this.ApiPreviewComponent.bind(this)))
/* Bandaged BD */ /* Bandaged BD */
this.sidebar.register("BDChangelogTitle", makeComponent(() => {
return new BDSidebarHeader().render()
}))
this.sidebar.register("core", makeComponent(this.coreComponent.bind(this))) this.sidebar.register("core", makeComponent(this.coreComponent.bind(this)))
this.sidebar.register("customcss", makeComponent(this.customCssComponent.bind(this))) this.sidebar.register("customcss", makeComponent(this.customCssComponent.bind(this)))
this.sidebar.register("plugins", makeComponent(this.renderAddonPane("plugins"))) this.sidebar.register("plugins", makeComponent(this.renderAddonPane("plugins")))
@ -192,10 +209,10 @@ export default new class V2_SettingsPanel {
else dMode.stopCopySelector(); else dMode.stopCopySelector();
} }
if (id === "reactDevTools") { /*if (id === "reactDevTools") {
if (enabled) reactDevTools.start(); if (enabled) reactDevTools.start();
else reactDevTools.stop(); else reactDevTools.stop();
} }*/
if (id === "lightcord-1") { if (id === "lightcord-1") {
if (enabled) window.Lightcord.Settings.devMode = true if (enabled) window.Lightcord.Settings.devMode = true
else window.Lightcord.Settings.devMode = false else window.Lightcord.Settings.devMode = false
@ -246,7 +263,7 @@ export default new class V2_SettingsPanel {
} }
async initializeSettings() { async initializeSettings() {
if (settingsCookie.reactDevTools) reactDevTools.start(); //if (settingsCookie.reactDevTools) reactDevTools.start();
if (settingsCookie["bda-gs-2"]) DOM.addClass(document.body, "bd-minimal"); if (settingsCookie["bda-gs-2"]) DOM.addClass(document.body, "bd-minimal");
if (settingsCookie["bda-gs-3"]) DOM.addClass(document.body, "bd-minimal-chan"); if (settingsCookie["bda-gs-3"]) DOM.addClass(document.body, "bd-minimal-chan");
if (settingsCookie["bda-gs-1"]) publicServersModule.addButton(); if (settingsCookie["bda-gs-1"]) publicServersModule.addButton();
@ -305,13 +322,20 @@ export default new class V2_SettingsPanel {
}) })
] ]
}), }),
BDV2.react.createElement(window.Lightcord.Api.Components.inputs.Button, {color: "yellow", onClick(){ BDV2.react.createElement(window.Lightcord.Api.Components.inputs.Button, {
color: "yellow",
look: "ghost",
size: "medium",
hoverColor: "red",
onClick(){
console.log("Should relaunch") console.log("Should relaunch")
remote.app.relaunch({ remote.app.relaunch({
args: remote.process.argv.slice(1).concat(["--disable-betterdiscord"]) args: remote.process.argv.slice(1).concat(["--disable-betterdiscord"])
}) })
remote.app.quit() remote.app.quit()
}}, "Relaunch without BetterDiscord") },
wrapper: true
}, "Relaunch without BetterDiscord")
] ]
} }
@ -369,6 +393,10 @@ export default new class V2_SettingsPanel {
} }
}; };
/**
* No need to export settingsPanel on window
*/
function makeComponent(children){ function makeComponent(children){
class SettingComponent extends React.Component { class SettingComponent extends React.Component {
render(){ render(){

View File

@ -1,12 +1,3 @@
import {bbdChangelog, LCChanelog} from "../0globals";
import Utils from "./utils";
import BDV2 from "./v2";
import DOM from "./domtools";
import SideBar from "../ui/sidebar";
import History from "../ui/icons/history";
import TooltipWrap from "../ui/tooltipWrap";
export default class V2_SettingsPanel_Sidebar { export default class V2_SettingsPanel_Sidebar {
constructor() { constructor() {
@ -50,7 +41,7 @@ export default class V2_SettingsPanel_Sidebar {
id: "accountinfo" id: "accountinfo"
} }
] ]
if(!!window.Lightcord.Settings.devMode)items.push({ if(window.Lightcord.Settings.devMode)items.push({
text: "Api Components Preview", text: "Api Components Preview",
id: "lcapipreview" id: "lcapipreview"
}) })
@ -74,8 +65,8 @@ export default class V2_SettingsPanel_Sidebar {
section: "DIVIDER" section: "DIVIDER"
}, },
{ {
section: "HEADER", section: "CUSTOM",
label: "Bandaged BD" element: this.getComponent("BDChangelogTitle")
}, },
...this.items.map(e => { ...this.items.map(e => {
return { return {
@ -90,3 +81,7 @@ export default class V2_SettingsPanel_Sidebar {
] ]
} }
} }
/**
* No need to export settingsPanelSidebar on window
*/

View File

@ -6,6 +6,9 @@ import Utils from "./utils";
import DOM from "./domtools"; import DOM from "./domtools";
class ThemeModule { class ThemeModule {
constructor(){
window.Lightcord.BetterDiscord.ThemeModule = this
}
get folder() {return ContentManager.themesFolder;} get folder() {return ContentManager.themesFolder;}
} }

View File

@ -70,6 +70,7 @@ export default new class V2 {
reactDom: this.WebpackModules.findByUniqueProperties(["findDOMNode"]) reactDom: this.WebpackModules.findByUniqueProperties(["findDOMNode"])
}; };
this.getInternalInstance = e => e[Object.keys(e).find(k => k.startsWith("__reactInternalInstance"))]; this.getInternalInstance = e => e[Object.keys(e).find(k => k.startsWith("__reactInternalInstance"))];
window.Lightcord.BetterDiscord.V2 = this
} }
initialize() { initialize() {

View File

@ -29,4 +29,7 @@ const findByProps = (...propNames) => find(module => propNames.every(prop => mod
const findByPrototypes = (...protoNames) => find(module => module.prototype && protoNames.every(protoProp => module.prototype[protoProp] !== undefined)); const findByPrototypes = (...protoNames) => find(module => module.prototype && protoNames.every(protoProp => module.prototype[protoProp] !== undefined));
const findByDisplayName = (displayName) => find(module => module.displayName === displayName); const findByDisplayName = (displayName) => find(module => module.displayName === displayName);
export default {find, findAll, findByProps, findByPrototypes, findByDisplayName}; let mod = {find, findAll, findByProps, findByPrototypes, findByDisplayName};
export default mod
window.Lightcord.BetterDiscord.WebpackModules = mod

View File

@ -33,7 +33,7 @@ export default class ApiPreview extends React.PureComponent {
</formModule.FormText> </formModule.FormText>
<MarginTop></MarginTop> <MarginTop></MarginTop>
<Lightcord.Api.Components.inputs.Button color="brand" look="outlined" size="medium" hoverColor="green" onClick={() => { <Lightcord.Api.Components.inputs.Button color="brand" look="outlined" size="medium" hoverColor="green" onClick={() => {
remote.shell.openExternal("https://github.com/lightcord/lightcord/wiki/apis") remote.shell.openExternal("https://github.com/lightcord/lightcord/wiki/Apis")
}} wrapper={false}> }} wrapper={false}>
Documentation Documentation
</Lightcord.Api.Components.inputs.Button> </Lightcord.Api.Components.inputs.Button>
@ -71,7 +71,7 @@ export default class ApiPreview extends React.PureComponent {
return final return final
} }
let renderPreview = () => { let renderPreview = () => {
return <div style={{marginTop: "20px", marginBottom: "20px"}}> return <div style={{margin: "20px"}}>
<div style={{ <div style={{
backgroundColor: "var(--background-primary)", backgroundColor: "var(--background-primary)",
padding: "30px 30px", padding: "30px 30px",
@ -82,7 +82,7 @@ export default class ApiPreview extends React.PureComponent {
</div> </div>
} }
let renderCode = () => { let renderCode = () => {
return <div style={{marginTop: "20px", marginBottom: "20px"}}> return <div style={{margin: "20px"}}>
<div style={{ <div style={{
backgroundColor: "var(--background-primary)", backgroundColor: "var(--background-primary)",
padding: "30px 30px", padding: "30px 30px",
@ -100,7 +100,7 @@ export default class ApiPreview extends React.PureComponent {
</div> </div>
</div> </div>
} }
let getStrForProp = (value) => { let getStrForProp = (value, compPath, lang) => {
if(typeof value === "string"){ if(typeof value === "string"){
return value return value
}else if(typeof value === "boolean"){ }else if(typeof value === "boolean"){
@ -109,6 +109,33 @@ export default class ApiPreview extends React.PureComponent {
return value.toString() return value.toString()
}else if(typeof value === "object"){ }else if(typeof value === "object"){
if(value && value.$$typeof && (value.$$typeof === Symbol.for("react.element") || value.$$typeof === 0xeac7)){ if(value && value.$$typeof && (value.$$typeof === Symbol.for("react.element") || value.$$typeof === 0xeac7)){
if(compPath === "Lightcord.Api.Components.general.Tabs"){
if(lang === "react"){
return `React.createElement("div", {style: {
marginTop: "20px", marginBottom: "20px"
}},
React.createElement("div", {style: {
backgroundColor: "var(--background-primary)",
padding: "30px 30px",
borderRadius: "8px"
}, className: "lc-tab-box-shadow" },
React.createElement(Lightcord.Api.Components.general.Title, null, "Preview tabs")
)
)`
}else if(lang === "jsx"){
return `<div style={{
marginTop: "20px", marginBottom: "20px"
}}>
<div style={{
backgroundColor: "var(--background-primary)",
padding: "30px 30px",
borderRadius: "8px"
}} className="lc-tab-box-shadow">
<Lightcord.Api.Components.general.Title>Preview tabs</Lightcord.Api.Components.general.Title>
</div>
</div>`
}
}
return "Your components here." return "Your components here."
} }
return JSON.stringify(value, null, " ") return JSON.stringify(value, null, " ")
@ -129,13 +156,13 @@ export default class ApiPreview extends React.PureComponent {
let childrenProp = null let childrenProp = null
Object.keys(props).forEach(key => { Object.keys(props).forEach(key => {
if(key == "children"){ if(key == "children"){
childrenProp = getStrForProp(props[key]) childrenProp = getStrForProp(props[key], compPath, lang)
}else{ }else{
let str = key+"=" let str = key+"="
if(typeof props[key] === "string"){ if(typeof props[key] === "string"){
str += JSON.stringify(props[key]) str += JSON.stringify(props[key])
}else{ }else{
str += `{${getStrForProp(props[key])}}` str += `{${getStrForProp(props[key], compPath, lang)}}`
} }
propStrings.push(str) propStrings.push(str)
} }
@ -153,7 +180,7 @@ export default class ApiPreview extends React.PureComponent {
let children = props.children || null let children = props.children || null
delete props.children delete props.children
if(children && children.$$typeof && (children.$$typeof === Symbol.for("react.element") || children.$$typeof === 0xeac7)){ if(children && children.$$typeof && (children.$$typeof === Symbol.for("react.element") || children.$$typeof === 0xeac7)){
children = "Your components here." children = getStrForProp(children, compPath, lang)
} }
let propStrings = [] let propStrings = []
Object.keys(props).forEach(key => { Object.keys(props).forEach(key => {
@ -162,7 +189,7 @@ export default class ApiPreview extends React.PureComponent {
if(typeof props[key] === "string"){ if(typeof props[key] === "string"){
str += JSON.stringify(props[key]) str += JSON.stringify(props[key])
}else{ }else{
str += getStrForProp(props[key]).split("\n").map((str, i) => { str += getStrForProp(props[key], compPath, lang).split("\n").map((str, i) => {
if(i === 0)return str if(i === 0)return str
return " " + str return " " + str
}).join("\n") }).join("\n")
@ -186,7 +213,8 @@ export default class ApiPreview extends React.PureComponent {
}else{ }else{
propObject += "}" propObject += "}"
} }
return `React.createElement(${compPath}, ${propObject}, ${JSON.stringify(children)})` let childrenData = typeof children === "string" && children.startsWith("React.createElement") ? children : JSON.stringify(children)
return `React.createElement(${compPath}, ${propObject}, ${childrenData})`
} }
} }
return (<div> return (<div>

View File

@ -191,19 +191,26 @@ export default class V2C_PluginCard extends BDV2.reactComponent {
const {authorId, authorLink} = this.props.addon; const {authorId, authorLink} = this.props.addon;
const style = {} const style = {}
if(settingsCookie["fork-ps-6"]){
if(!this.isScanning){ if(!this.isScanning){
this.isScanning = true this.isScanning = true
processFile(resolve(this.props.addon.filename.endsWith(".plugin.js") ? contentManager.pluginsFolder : contentManager.themesFolder, this.props.addon.filename), (result) => { processFile(resolve(this.props.addon.filename.endsWith(".plugin.js") ? contentManager.pluginsFolder : contentManager.themesFolder, this.props.addon.filename), (result) => {
if(this.unmounted)return if(this.unmounted)return
this.setState({ this.setState({
isTrusted: !result.suspect isTrusted: result.suspect ? "suspect" : true
}) })
}, () => {}) }, () => {})
}else{ }else{
if(this.state.isTrusted){ if(this.state.isTrusted === true){
style.borderColor = "#4087ed" style.borderColor = "#4087ed"
} }
if(this.state.isTrusted === "suspect"){
style.borderColor = "rgb(240, 71, 71)"
} }
}
}
return BDV2.react.createElement("div", {className: "bd-card bd-addon-card settings-closed ui-switch-item", style}, return BDV2.react.createElement("div", {className: "bd-card bd-addon-card settings-closed ui-switch-item", style},
BDV2.react.createElement("div", {className: "bd-addon-header bda-header"}, BDV2.react.createElement("div", {className: "bd-addon-header bda-header"},
BDV2.react.createElement("div", {className: "bd-card-title bda-header-title"}, this.buildTitle(this.name, this.version, {name: this.author, id: authorId, link: authorLink})), BDV2.react.createElement("div", {className: "bd-card-title bda-header-title"}, this.buildTitle(this.name, this.version, {name: this.author, id: authorId, link: authorLink})),

View File

@ -1,7 +1,3 @@
/**
* How the fuck did I do this
*/
import BDV2 from "../modules/v2"; import BDV2 from "../modules/v2";
import V2C_SettingsTitle from "./settingsTitle"; import V2C_SettingsTitle from "./settingsTitle";
import V2C_SettingsGroup from "./settingsGroup"; import V2C_SettingsGroup from "./settingsGroup";
@ -556,7 +552,7 @@ class Tab extends React.Component {
} }
let popoutModule let popoutModule
class Popout extends React.Component { class Popout extends React.Component { // TODO: Probably use internal Components instead of making it from scratch.
get modules(){ get modules(){
return popoutModule || (popoutModule = [ return popoutModule || (popoutModule = [
BDModules.get(e => e.userPopout)[0], BDModules.get(e => e.userPopout)[0],
@ -722,7 +718,7 @@ class Status extends React.Component {
let timestampClass = "" let timestampClass = ""
let ProfileModules let ProfileModules
class Profile extends React.Component { class Profile extends React.Component { // TODO: Probably use internal Components instead of making it from scratch.
get modules(){ get modules(){
return ProfileModules || (ProfileModules = [ return ProfileModules || (ProfileModules = [
BDModules.get(e => e.flex && e._horizontal)[0], BDModules.get(e => e.flex && e._horizontal)[0],

View File

@ -1,11 +1,17 @@
# Lightcord's Discord.js # Lightcord's Discord.js
Disclaimer:
This part of Lightcord is still in development. Features could be added/change/removed.
### What is this ? ### What is this ?
Lightcord includes a Discord.js-like api. This is written in this folder. Lightcord includes a Discord.js-like api. This is written in this folder.
<warn>This is not for making selfbots.
The purpose of this is only to make an easy, intuitive and object oriented api.</warn>
### Where can I get the documentation ? ### Where can I get the documentation ?
[Documentation here](https://discord.js.org/#/docs/main/11.6.4/general/welcome) [Documentation here](https://discord.js.org/#/docs/main/11.6.4/general/welcome)
Discord.js on Lightcord is following Discord.js 11.6.4 specs. Discord.js on Lightcord is based on Discord.js 11.6.4.
### How do I use it ? ### How do I use it ?
Discord.js can be accessed under the following global properties Discord.js can be accessed under the following global properties
@ -18,4 +24,10 @@ Discord.js can be accessed under the following global properties
### Deprecations ### Deprecations
1. Any method that only bot can use (it will throw a `DiscordJSError` saying that Lightcord can't do that) 1. Any method that only bot can use (it will throw a `DiscordJSError` saying that Lightcord can't do that)
3. Any method 2. Original Voice Methods. They're documented below:
3. Try to not use deprecated methods flagged on DiscordJS's website. They might be removed on Lightcord.
### Voice
Lightcord can't make the client join multiple voice channels / join but the user doesn't know.
When joining a voice channel, The user's mic is sent. This is not for broadcasting/playing music in voice, but only to make the user join a voice channel.

File diff suppressed because one or more lines are too long

View File

@ -78,10 +78,10 @@ export default class Client extends EventEmitter {
/** Warnings and overrides for functions that are not compatible. */ /** Warnings and overrides for functions that are not compatible. */
async login():Promise<never>{ async login():Promise<never>{
throw new DiscordJSError("Client#login is not supported. DiscordJS on lightcord will use the connected account.") throw new DiscordJSError("Client#login is not supported. DiscordJS on lightcord will use the logged in account.")
} }
get token():never{ get token():never{
throw new DiscordJSError("Client#token is not supported. DiscordJS on lightcord will use the connected account.") throw new DiscordJSError("Client#token is not supported. DiscordJS on lightcord will use the logged in account.")
} }
} }

View File

@ -0,0 +1,13 @@
import GuildChannel from "./GuildChannel";
import { DiscordChannel } from "../util/DiscordToModules";
import { ChannelTypes } from "../util/Constants";
export default class CategoryChannel extends GuildChannel/* implements TextBasedChannel*/ {
constructor(data:DiscordChannel){
super(data)
}
get type(): ChannelTypes.CATEGORY{
return ChannelTypes.CATEGORY
}
}

View File

@ -1,7 +1,7 @@
import { Snowflake, Channel } from ".." import { Snowflake, Channel } from ".."
import { DiscordGuild, channelsModule, guildModule, UserSettingsModule, ConstantsModule, CdnModule, AckModule } from "../util/DiscordToModules" import { DiscordGuild, channelsModule, guildModule, UserSettingsModule, ConstantsModule, CdnModule, AckModule } from "../util/DiscordToModules"
import BaseStructure from "./BaseStructure" import BaseStructure from "./BaseStructure"
import { createChannel, createGuildMember, createRole, UserResolvable, resolveUserID } from "../util/util" import { createChannel, createGuildMember, createRole, UserResolvable, resolveUserID, ChannelData, ChannelCreationOverwrites, PermissionOverwrites } from "../util/util"
import Collection from "@discordjs/collection" import Collection from "@discordjs/collection"
import SnowflakeUtil from "../util/Snowflake" import SnowflakeUtil from "../util/Snowflake"
import GuildMember from "./GuildMember" import GuildMember from "./GuildMember"
@ -271,16 +271,38 @@ export default class Guild extends BaseStructure {
}).then(() => this) }).then(() => this)
} }
ban(user:UserResolvable, { async ban(user:UserResolvable, {
days = 0, days = 0,
reason = null reason = null
}: { }: {
days?: number, days?: number,
reason?: string reason?: string
}){ } = {}):Promise<Snowflake>{ // always returning a snowflake
let id = resolveUserID(user) let id = resolveUserID(user)
if(!id)return Promise.reject(new DiscordJSError("Given user could not be resolved to an user ID.")) if(!id)return Promise.reject(new DiscordJSError("Given user could not be resolved to an user ID."))
let result = await guildModule.banUser(this.id, id, days, reason).catch(err => err)
if(result instanceof Error || result.status !== 204){
let message = result.body
if(Array.isArray(message)){
message = message[0]
}else{
if(message.user_id){
message = "User: "+ message.user_id[0]
}else if(message.delete_message_days){
message = "Days: "+ message.delete_message_days[0]
}else if(message.reason){
message = "Reason: "+ message.reason[0]
}else{
message = result.text
}
}
throw new DiscordJSError(message)
}
return id
}
createChannel(name:string, typeOrOptions:string|ChannelData = 'text', permissionOverwrites?: ChannelCreationOverwrites[] | Collection<Snowflake, PermissionOverwrites>, reason?: string){
} }

View File

@ -3,7 +3,7 @@ import GuildChannel from "./GuildChannel";
import { DiscordChannel } from "../util/DiscordToModules"; import { DiscordChannel } from "../util/DiscordToModules";
import { ChannelTypes } from "../util/Constants"; import { ChannelTypes } from "../util/Constants";
export class TextChannel extends GuildChannel/* implements TextBasedChannel*/ { export default class TextChannel extends GuildChannel/* implements TextBasedChannel*/ {
constructor(data:DiscordChannel){ constructor(data:DiscordChannel){
super(data) super(data)
} }

View File

@ -0,0 +1,172 @@
/**
* Data structure that makes it easy to interact with a bitfield.
*/
export default class BitField {
/**
* @param {BitFieldResolvable} [bits=0] Bits(s) to read from
*/
constructor(bits: BitFieldResolvable) {
this.bitfield = (this.constructor as any).resolve(bits);
}
/**
* Bitfield of the packed bits
* @type {number}
*/
bitfield:number
/**
* Checks whether the bitfield has a bit, or any of multiple bits.
* @param {BitFieldResolvable} bit Bit(s) to check for
* @returns {boolean}
*/
any(bit: BitFieldResolvable): boolean {
return (this.bitfield & (this.constructor as any).resolve(bit)) !== 0;
}
/**
* Checks if this bitfield equals another
* @param {BitFieldResolvable} bit Bit(s) to check for
* @returns {boolean}
*/
equals(bit: BitFieldResolvable): boolean {
return this.bitfield === (this.constructor as any).resolve(bit);
}
/**
* Checks whether the bitfield has a bit, or multiple bits.
* @param {BitFieldResolvable} bit Bit(s) to check for
* @returns {boolean}
*/
has(bit: BitFieldResolvable, ...hasParams: any[]): boolean {
if (Array.isArray(bit)) return bit.every((p) => this.has(p));
bit = (this.constructor as any).resolve(bit) as number;
return (this.bitfield & bit) === bit;
}
/**
* Gets all given bits that are missing from the bitfield.
* @param {BitFieldResolvable} bits Bits(s) to check for
* @param {...*} hasParams Additional parameters for the has method, if any
* @returns {string[]}
*/
missing(bits: BitFieldResolvable, ...hasParams: any[]): string[] {
if (!Array.isArray(bits))
bits = new (this.constructor as any)(bits).toArray(false)
return (bits as string[]).filter((p) => !this.has(p, ...hasParams));
}
/**
* Freezes these bits, making them immutable.
* @returns {Readonly<BitField>} These bits
*/
freeze(): Readonly<BitField> {
return Object.freeze(this);
}
/**
* Adds bits to these ones.
* @param {...BitFieldResolvable} [bits] Bits to add
* @returns {BitField} These bits or new BitField if the instance is frozen.
*/
add(...bits: BitFieldResolvable[]): BitField {
let total = 0;
for (const bit of bits) {
total |= (this.constructor as any).resolve(bit);
}
if (Object.isFrozen(this))
return new (this.constructor as any)(this.bitfield | total);
this.bitfield |= total;
return this;
}
/**
* Removes bits from these.
* @param {...BitFieldResolvable} [bits] Bits to remove
* @returns {BitField} These bits or new BitField if the instance is frozen.
*/
remove(...bits: BitFieldResolvable[]): BitField {
let total = 0;
for (const bit of bits) {
total |= (this.constructor as any).resolve(bit);
}
if (Object.isFrozen(this))
return new (this.constructor as any)(this.bitfield & ~total);
this.bitfield &= ~total;
return this;
}
/**
* Gets an object mapping field names to a {@link boolean} indicating whether the
* bit is available.
* @param {...*} hasParams Additional parameters for the has method, if any
* @returns {Object}
*/
serialize(...hasParams: any[]): object {
const serialized = {};
for (const flag of Object.keys((this.constructor as any).FLAGS)) {
serialized[flag] = this.has(
(this.constructor as any).FLAGS[flag],
...hasParams
);
}
return serialized;
}
/**
* Gets an {@link Array} of bitfield names based on the bits available.
* @param {...*} hasParams Additional parameters for the has method, if any
* @returns {string[]}
*/
toArray(...hasParams: any[]): string[] {
return Object.keys((this.constructor as any).FLAGS).filter((bit) =>
this.has(bit, ...hasParams)
);
}
toJSON() {
return this.bitfield;
}
valueOf() {
return this.bitfield;
}
*[Symbol.iterator]() {
yield* this.toArray();
}
/**
* Resolves bitfields to their numeric form.
* @param {BitFieldResolvable} [bit=0] - bit(s) to resolve
* @returns {number}
*/
static resolve(bit: BitFieldResolvable = 0): number {
if (typeof bit === "number" && bit >= 0) return bit;
if (bit instanceof BitField) return bit.bitfield;
if (Array.isArray(bit))
return bit
.map((p) => this.resolve(p))
.reduce((prev, p) => prev | p, 0);
if (typeof bit === "string" && typeof this.FLAGS[bit] !== "undefined")
return this.FLAGS[bit];
throw new RangeError("Invalid bitfield flag or number.");
}
/**
* Numeric bitfield flags.
* <info>Defined in extension classes</info>
* @type {Object}
* @abstract
*/
static FLAGS: object = {};
}
/**
* Data that can be resolved to give a bitfield. This can be:
* * A string (see {@link BitField.FLAGS})
* * A bit number
* * An instance of BitField
* * An Array of BitFieldResolvable
*/
export type BitFieldResolvable = string|number|BitField|BitFieldResolvable[]

View File

@ -0,0 +1,210 @@
import BitField from "./BitField";
import * as util from "util";
/**
* Data structure that makes it easy to interact with a permission bitfield. All {@link GuildMember}s have a set of
* permissions in their guild, and each channel in the guild may also have {@link PermissionOverwrites} for the member
* that override their default permissions.
* @extends {BitField}
*/
export default class Permissions extends BitField {
/**
* @param {number|PermissionResolvable} permissions Permissions or bitfield to read from
*/
constructor(permissions: number | PermissionResolvable) {
super(permissions);
}
/**
* Bitfield of the packed permissions
* @type {number}
* @see {@link Permissions#bitfield}
* @deprecated
* @readonly
*/
get raw() {
return this.bitfield;
}
set raw(raw) {
this.bitfield = raw;
}
/**
* Checks whether the bitfield has a permission, or any of multiple permissions.
* @param {PermissionResolvable} permission Permission(s) to check for
* @param {boolean} [checkAdmin=true] Whether to allow the administrator permission to override
* @returns {boolean}
*/
any(permission: PermissionResolvable, checkAdmin: boolean = true): boolean {
return (
(checkAdmin && super.has((this.constructor as any).FLAGS.ADMINISTRATOR)) ||
super.any(permission)
);
}
/**
* Checks whether the bitfield has a permission, or multiple permissions.
* @param {PermissionResolvable} permission Permission(s) to check for
* @param {boolean} [checkAdmin=true] Whether to allow the administrator permission to override
* @returns {boolean}
*/
has(permission: PermissionResolvable, checkAdmin: boolean = true): boolean {
return (
(checkAdmin && super.has((this.constructor as any).FLAGS.ADMINISTRATOR)) ||
super.has(permission)
);
}
/**
* Numeric permission flags. All available properties:
* - `ADMINISTRATOR` (implicitly has *all* permissions, and bypasses all channel overwrites)
* - `CREATE_INSTANT_INVITE` (create invitations to the guild)
* - `KICK_MEMBERS`
* - `BAN_MEMBERS`
* - `MANAGE_CHANNELS` (edit and reorder channels)
* - `MANAGE_GUILD` (edit the guild information, region, etc.)
* - `ADD_REACTIONS` (add new reactions to messages)
* - `VIEW_AUDIT_LOG`
* - `PRIORITY_SPEAKER`
* - `STREAM`
* - `VIEW_CHANNEL`
* - `READ_MESSAGES` **(deprecated)**
* - `SEND_MESSAGES`
* - `SEND_TTS_MESSAGES`
* - `MANAGE_MESSAGES` (delete messages and reactions)
* - `EMBED_LINKS` (links posted will have a preview embedded)
* - `ATTACH_FILES`
* - `READ_MESSAGE_HISTORY` (view messages that were posted prior to opening Discord)
* - `MENTION_EVERYONE`
* - `USE_EXTERNAL_EMOJIS` (use emojis from different guilds)
* - `EXTERNAL_EMOJIS` **(deprecated)**
* - `CONNECT` (connect to a voice channel)
* - `SPEAK` (speak in a voice channel)
* - `MUTE_MEMBERS` (mute members across all voice channels)
* - `DEAFEN_MEMBERS` (deafen members across all voice channels)
* - `MOVE_MEMBERS` (move members between voice channels)
* - `USE_VAD` (use voice activity detection)
* - `CHANGE_NICKNAME`
* - `MANAGE_NICKNAMES` (change other members' nicknames)
* - `MANAGE_ROLES`
* - `MANAGE_ROLES_OR_PERMISSIONS` **(deprecated)**
* - `MANAGE_WEBHOOKS`
* - `MANAGE_EMOJIS`
* @type {Object}
* @see {@link https://discordapp.com/developers/docs/topics/permissions}
*/
static FLAGS:{
CREATE_INSTANT_INVITE: number,
KICK_MEMBERS: number,
BAN_MEMBERS: number,
ADMINISTRATOR: number,
MANAGE_CHANNELS: number,
MANAGE_GUILD: number,
ADD_REACTIONS: number,
VIEW_AUDIT_LOG: number,
PRIORITY_SPEAKER: number,
STREAM: number,
VIEW_CHANNEL: number,
READ_MESSAGES: number,
SEND_MESSAGES: number,
SEND_TTS_MESSAGES: number,
MANAGE_MESSAGES: number,
EMBED_LINKS: number,
ATTACH_FILES: number,
READ_MESSAGE_HISTORY: number,
MENTION_EVERYONE: number,
EXTERNAL_EMOJIS: number,
USE_EXTERNAL_EMOJIS: number,
CONNECT: number,
SPEAK: number,
MUTE_MEMBERS: number,
DEAFEN_MEMBERS: number,
MOVE_MEMBERS: number,
USE_VAD: number,
CHANGE_NICKNAME: number,
MANAGE_NICKNAMES: number,
MANAGE_ROLES: number,
MANAGE_ROLES_OR_PERMISSIONS: number,
MANAGE_WEBHOOKS: number,
MANAGE_EMOJIS: number,
} = {
CREATE_INSTANT_INVITE: 1 << 0,
KICK_MEMBERS: 1 << 1,
BAN_MEMBERS: 1 << 2,
ADMINISTRATOR: 1 << 3,
MANAGE_CHANNELS: 1 << 4,
MANAGE_GUILD: 1 << 5,
ADD_REACTIONS: 1 << 6,
VIEW_AUDIT_LOG: 1 << 7,
PRIORITY_SPEAKER: 1 << 8,
STREAM: 1 << 9,
VIEW_CHANNEL: 1 << 10,
READ_MESSAGES: 1 << 10,
SEND_MESSAGES: 1 << 11,
SEND_TTS_MESSAGES: 1 << 12,
MANAGE_MESSAGES: 1 << 13,
EMBED_LINKS: 1 << 14,
ATTACH_FILES: 1 << 15,
READ_MESSAGE_HISTORY: 1 << 16,
MENTION_EVERYONE: 1 << 17,
EXTERNAL_EMOJIS: 1 << 18,
USE_EXTERNAL_EMOJIS: 1 << 18,
CONNECT: 1 << 20,
SPEAK: 1 << 21,
MUTE_MEMBERS: 1 << 22,
DEAFEN_MEMBERS: 1 << 23,
MOVE_MEMBERS: 1 << 24,
USE_VAD: 1 << 25,
CHANGE_NICKNAME: 1 << 26,
MANAGE_NICKNAMES: 1 << 27,
MANAGE_ROLES: 1 << 28,
MANAGE_ROLES_OR_PERMISSIONS: 1 << 28,
MANAGE_WEBHOOKS: 1 << 29,
MANAGE_EMOJIS: 1 << 30,
};
/**
* Bitfield representing every permission combined
* @type {number}
*/
static ALL: number = Object.keys(Permissions.FLAGS).reduce(
(all, p) => all | Permissions.FLAGS[p],
0
);
/**
* Bitfield representing the default permissions for users
* @type {number}
*/
static DEFAULT: number = 104324673;
}
Object.defineProperty(Permissions.prototype, "raw", {
get: util.deprecate(
Object.getOwnPropertyDescriptor(Permissions.prototype, "raw").get,
"EvaluatedPermissions#raw is deprecated use Permissions#bitfield instead"
),
set: util.deprecate(
Object.getOwnPropertyDescriptor(Permissions.prototype, "raw").set,
"EvaluatedPermissions#raw is deprecated use Permissions#bitfield instead"
),
});
/**
* Data that can be resolved to give a permission number. This can be:
* * A string (see {@link Permissions.FLAGS})
* * A permission number
* @typedef {string|number|Permissions|PermissionResolvable[]} PermissionResolvable
*/
export type PermissionResolvable =
| string
| number
| Permissions
| PermissionResolvable[];

View File

@ -2,11 +2,15 @@ import { DiscordChannel, DiscordGuild, DiscordGuildMember, DiscordRole, DiscordM
import { Channel, Snowflake } from ".."; import { Channel, Snowflake } from "..";
import BaseChannel from "../structures/BaseChannel"; import BaseChannel from "../structures/BaseChannel";
import Guild from "../structures/Guild"; import Guild from "../structures/Guild";
import { TextChannel } from "../structures/TextChannel"; import TextChannel from "../structures/TextChannel";
import GuildMember from "../structures/GuildMember"; import GuildMember from "../structures/GuildMember";
import Role from "../structures/Role"; import Role from "../structures/Role";
import User from "../structures/User"; import User from "../structures/User";
import Message from "../structures/Message"; import Message from "../structures/Message";
import { ChannelTypes } from "./Constants";
import CategoryChannel from "../structures/CategoryChannel";
import Collection from "@discordjs/collection";
import Permissions, { PermissionResolvable } from "./Permissions";
export function createChannel(channel:DiscordChannel):Channel{ export function createChannel(channel:DiscordChannel):Channel{
let constructor = channels[channel.type] || BaseChannel let constructor = channels[channel.type] || BaseChannel
@ -109,3 +113,38 @@ export function resolveUserID(user:UserResolvable){
if(user instanceof GuildMember)return user.id // GuildMember if(user instanceof GuildMember)return user.id // GuildMember
return null return null
} }
export type ChannelData = {
type?: ChannelTypes,
name?: string,
position?: number,
topic?: string,
nsfw?: boolean,
bitrate?: number,
userLimit?: number,
parent?: CategoryChannel|Snowflake,
permissionOverwrites?: ChannelCreationOverwrites[] | Collection<Snowflake, PermissionOverwrites>,
rateLimitPerUser?: number
}
export type ChannelCreationOverwrites = {
allow?: PermissionResolvable,
/**
* @deprecated
*/
allowed?: PermissionResolvable,
deny?: PermissionResolvable,
/**
* @deprecated
*/
denied?: PermissionResolvable,
id?: GuildMemberResolvable | RoleResolvable
}
export type PermissionOverwrites = keyof typeof Permissions.FLAGS | number | Permissions | PermissionResolvable[]
export {BitFieldResolvable} from "./BitField"
export type GuildMemberResolvable = GuildMember | User
export type RoleResolvable = Role | Snowflake

7
LightcordApi/README.md Normal file
View File

@ -0,0 +1,7 @@
# LightcordApi
Welcome to LightcordApi's Documentation !
The api is mainly written here.
The main's module documentation can be found [here](./interfaces/_index_.lightcordglobal.html)

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -2867,6 +2867,27 @@
"integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==",
"dev": true "dev": true
}, },
"handlebars": {
"version": "4.7.6",
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.6.tgz",
"integrity": "sha512-1f2BACcBfiwAfStCKZNrUCgqNZkGsAT7UM3kkYtXuLo0KnaVfjKOyf7PRzB6++aK9STyT1Pd2ZCPe3EGOXleXA==",
"dev": true,
"requires": {
"minimist": "^1.2.5",
"neo-async": "^2.6.0",
"source-map": "^0.6.1",
"uglify-js": "^3.1.4",
"wordwrap": "^1.0.0"
},
"dependencies": {
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"dev": true
}
}
},
"has-flag": { "has-flag": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
@ -2971,6 +2992,12 @@
"minimalistic-assert": "^1.0.1" "minimalistic-assert": "^1.0.1"
} }
}, },
"highlight.js": {
"version": "10.1.1",
"resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.1.1.tgz",
"integrity": "sha512-b4L09127uVa+9vkMgPpdUQP78ickGbHEQTWeBrQFTJZ4/n2aihWOGS0ZoUqAwjVmfjhq/C76HRzkqwZhK4sBbg==",
"dev": true
},
"hmac-drbg": { "hmac-drbg": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz",
@ -3372,6 +3399,12 @@
} }
} }
}, },
"lunr": {
"version": "2.3.8",
"resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.8.tgz",
"integrity": "sha512-oxMeX/Y35PNFuZoHp+jUj5OSEmLCaIH4KTFJh7a93cHBoFmpw2IoPs22VIz7vyO2YUnx2Tn9dzIwO2P/4quIRg==",
"dev": true
},
"make-dir": { "make-dir": {
"version": "2.1.0", "version": "2.1.0",
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz",
@ -3397,6 +3430,12 @@
"object-visit": "^1.0.0" "object-visit": "^1.0.0"
} }
}, },
"marked": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/marked/-/marked-1.0.0.tgz",
"integrity": "sha512-Wo+L1pWTVibfrSr+TTtMuiMfNzmZWiOPeO7rZsQUY5bgsxpHesBEcIWJloWVTFnrMXnf/TL30eTFSGJddmQAng==",
"dev": true
},
"md5.js": { "md5.js": {
"version": "1.3.5", "version": "1.3.5",
"resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz",
@ -4015,6 +4054,12 @@
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
"dev": true "dev": true
}, },
"progress": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
"integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==",
"dev": true
},
"promise-inflight": { "promise-inflight": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz",
@ -4144,6 +4189,15 @@
"picomatch": "^2.2.1" "picomatch": "^2.2.1"
} }
}, },
"rechoir": {
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz",
"integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=",
"dev": true,
"requires": {
"resolve": "^1.1.6"
}
},
"regenerate": { "regenerate": {
"version": "1.4.1", "version": "1.4.1",
"resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.1.tgz", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.1.tgz",
@ -4441,6 +4495,17 @@
"integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=",
"dev": true "dev": true
}, },
"shelljs": {
"version": "0.8.4",
"resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.4.tgz",
"integrity": "sha512-7gk3UZ9kOfPLIAbslLzyWeGiEqx9e3rxwZM0KE6EL8GlGwjym9Mrlx5/p33bWTu9YG6vcS4MBxYZDHYr5lr8BQ==",
"dev": true,
"requires": {
"glob": "^7.0.0",
"interpret": "^1.0.0",
"rechoir": "^0.6.2"
}
},
"snapdragon": { "snapdragon": {
"version": "0.8.2", "version": "0.8.2",
"resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz",
@ -5006,12 +5071,74 @@
"integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=",
"dev": true "dev": true
}, },
"typedoc": {
"version": "0.17.8",
"resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.17.8.tgz",
"integrity": "sha512-/OyrHCJ8jtzu+QZ+771YaxQ9s4g5Z3XsQE3Ma7q+BL392xxBn4UMvvCdVnqKC2T/dz03/VXSLVKOP3lHmDdc/w==",
"dev": true,
"requires": {
"fs-extra": "^8.1.0",
"handlebars": "^4.7.6",
"highlight.js": "^10.0.0",
"lodash": "^4.17.15",
"lunr": "^2.3.8",
"marked": "1.0.0",
"minimatch": "^3.0.0",
"progress": "^2.0.3",
"shelljs": "^0.8.4",
"typedoc-default-themes": "^0.10.2"
},
"dependencies": {
"fs-extra": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
"integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==",
"dev": true,
"requires": {
"graceful-fs": "^4.2.0",
"jsonfile": "^4.0.0",
"universalify": "^0.1.0"
}
},
"jsonfile": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
"integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=",
"dev": true,
"requires": {
"graceful-fs": "^4.1.6"
}
},
"universalify": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
"integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==",
"dev": true
}
}
},
"typedoc-default-themes": {
"version": "0.10.2",
"resolved": "https://registry.npmjs.org/typedoc-default-themes/-/typedoc-default-themes-0.10.2.tgz",
"integrity": "sha512-zo09yRj+xwLFE3hyhJeVHWRSPuKEIAsFK5r2u47KL/HBKqpwdUSanoaz5L34IKiSATFrjG5ywmIu98hPVMfxZg==",
"dev": true,
"requires": {
"lunr": "^2.3.8"
}
},
"typescript": { "typescript": {
"version": "3.9.5", "version": "3.9.5",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.5.tgz", "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.5.tgz",
"integrity": "sha512-hSAifV3k+i6lEoCJ2k6R2Z/rp/H3+8sdmcn5NrS3/3kE7+RyZXm9aqvxWqjEXHAd8b0pShatpcdMTvEdvAJltQ==", "integrity": "sha512-hSAifV3k+i6lEoCJ2k6R2Z/rp/H3+8sdmcn5NrS3/3kE7+RyZXm9aqvxWqjEXHAd8b0pShatpcdMTvEdvAJltQ==",
"dev": true "dev": true
}, },
"uglify-js": {
"version": "3.10.0",
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.10.0.tgz",
"integrity": "sha512-Esj5HG5WAyrLIdYU74Z3JdG2PxdIusvj6IWHMtlyESxc7kcDz7zYlYjpnSokn1UbpV0d/QX9fan7gkCNd/9BQA==",
"dev": true,
"optional": true
},
"unicode-canonical-property-names-ecmascript": { "unicode-canonical-property-names-ecmascript": {
"version": "1.0.4", "version": "1.0.4",
"resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz",
@ -5734,6 +5861,12 @@
"integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=",
"dev": true "dev": true
}, },
"wordwrap": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
"integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=",
"dev": true
},
"worker-farm": { "worker-farm": {
"version": "1.7.0", "version": "1.7.0",
"resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.7.0.tgz", "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.7.0.tgz",

View File

@ -7,7 +7,9 @@
"build": "webpack --progress --colors", "build": "webpack --progress --colors",
"watch": "webpack --progress --colors --watch", "watch": "webpack --progress --colors --watch",
"build-prod": "webpack --progress --colors --mode production -o js/main.min.js --devtool none", "build-prod": "webpack --progress --colors --mode production -o js/main.min.js --devtool none",
"test": "echo \"Error: no test specified\" && exit 1" "watch-prod": "webpack --progress --colors --watch --mode production -o js/main.min.js --devtool none",
"test": "echo \"Error: no test specified\" && exit 1",
"docs": "typedoc --plugin ./node_modules/typedoc-plugin-markdown --out ../../LightcordApiDocs ./src"
}, },
"author": "", "author": "",
"license": "ISC", "license": "ISC",
@ -22,6 +24,7 @@
"babel-loader": "^8.0.6", "babel-loader": "^8.0.6",
"terser-webpack-plugin": "^3.0.6", "terser-webpack-plugin": "^3.0.6",
"ts-loader": "^7.0.5", "ts-loader": "^7.0.5",
"typedoc": "^0.17.8",
"typescript": "^3.9.5", "typescript": "^3.9.5",
"uuid": "^8.1.0", "uuid": "^8.1.0",
"webpack": "^4.43.0", "webpack": "^4.43.0",

View File

@ -9,9 +9,11 @@ import SettingsTitle from "./general/SettingsTitle"
import Tabs, { Tab } from "./general/Tabs" import Tabs, { Tab } from "./general/Tabs"
import SettingSubTitle from "./general/SettingSubTitle" import SettingSubTitle from "./general/SettingSubTitle"
import CodeBlock from "./general/CodeBlock" import CodeBlock from "./general/CodeBlock"
import cloneNullProto from "../modules/cloneNullProto"
import Tooltip from "./general/Tooltip"
export default { export default cloneNullProto({
inputs: { inputs: cloneNullProto({
Button: DiscordButton, Button: DiscordButton,
Switch: Switch, Switch: Switch,
Choices: RadioGroup, Choices: RadioGroup,
@ -19,12 +21,13 @@ export default {
TextArea: TextArea, TextArea: TextArea,
TextInput: TextInput, TextInput: TextInput,
Dropdown: Dropdown Dropdown: Dropdown
}, }),
general: { general: cloneNullProto({
Title: Title, Title: Title,
SettingsTitle: SettingsTitle, SettingsTitle: SettingsTitle,
SettingSubTitle: SettingSubTitle, SettingSubTitle: SettingSubTitle,
Tabs: Tabs, Tabs: Tabs,
CodeBlock: CodeBlock CodeBlock: CodeBlock,
} Tooltip: Tooltip
} })
})

View File

@ -1,24 +1,27 @@
import { ReactNode } from "react" import { ReactNode, CSSProperties } from "react"
import NOOP from "../../modules/noop" import NOOP from "../../modules/noop"
import Title from "./Title" import Title from "./Title"
type TabsProps = {
export default class Tabs extends React.Component<{
children?: ReactNode, children?: ReactNode,
tabs: {label: string, id: string}[], tabs: {label: string, id: string}[],
active?: string active?: string
onChange?: (tab: string) => void onChange?: (tab: string) => void,
}, { style?: CSSProperties
active: string
}> {
static defaultProps = {
children: null,
tabs: {label: "No tabs was passed to <Tabs>.", id: "none"},
active: null,
onChange: NOOP
} }
constructor(props){ export default class Tabs extends React.Component<TabsProps, {
active: string
}> {
static defaultProps:TabsProps = {
children: null,
tabs: [{label: "No tabs was passed to <Tabs>.", id: "none"}],
active: null,
onChange: NOOP,
style: {}
}
constructor(props:TabsProps){
super(props) super(props)
this.state = { this.state = {
active: this.props.active || null active: this.props.active || null
@ -41,7 +44,7 @@ export default class Tabs extends React.Component<{
} }
render(){ render(){
return (<div className="lc-tabWrapper"> return (<div className="lc-tabWrapper" style={this.props.style}>
<div className="lc-tabnav" style={{flex: "0 1 auto"}}> <div className="lc-tabnav" style={{flex: "0 1 auto"}}>
{this.tabs.map(tab => { {this.tabs.map(tab => {
return React.createElement(Tab, {TabContainer: this, title: tab.label, id: tab.id, key: btoa(tab.label+":"+tab.id)}) return React.createElement(Tab, {TabContainer: this, title: tab.label, id: tab.id, key: btoa(tab.label+":"+tab.id)})

View File

@ -1,7 +1,5 @@
import WebpackLoader from "../../modules/WebpackLoader" import WebpackLoader from "../../modules/WebpackLoader"
import { ReactNode } from "react" import { ReactNode } from "react"
import uuid from "../../modules/uuid"
import Utils from "../../modules/Utils"
type TitleProps = { type TitleProps = {
children?: ReactNode, children?: ReactNode,

View File

@ -0,0 +1,100 @@
import WebpackLoader from "../../modules/WebpackLoader"
import { ReactNode } from "react"
import excludeProperties from "../../modules/excludeProperties"
type TooltipData = {
onClick():void
onMouseEnter():void
onMouseLeave():void
onContextMenu():void
"aria-label": string
}
type TooltipProps = {
children:ReactNode,
text: string,
position?: TooltipPosition,
color?: TooltipColor
}
let TooltipModules
export default class Tooltip extends React.Component<TooltipProps> {
constructor(props: TooltipProps){
super(props)
}
get modules(){
return TooltipModules || (TooltipModules = [
WebpackLoader.find(e => e.default && e.default.displayName === "Tooltip")
])
}
render(){
let [
Tooltip
] = this.modules
let props = excludeProperties(this.props, ["children"])
return React.createElement(Tooltip.default, props, (data:TooltipData) => {
return React.createElement("div", {
...data,
style: {
width: "fit-content",
height: "fit-content"
}
}, this.props.children)
})
}
static defaultProps:TooltipProps = {
children: null,
text: "No text was passed to Tooltip",
position: "top",
color: "brand"
}
static get AllPreviews(){
return AllPreviews || (() => {
AllPreviews = []
AllPreviews.push([
{
children: React.createElement(window.Lightcord.Api.Components.inputs.Button, {
color: "green",
look: "ghost",
size: "small",
hoverColor: "yellow",
onClick: () => { },
wrapper: false
}, "Hover this button to see the tooltip")
}
])
AllPreviews.push([
{
text: "Example Tooltip Text"
}
])
let colors = []
Tooltip.Colors.forEach(color => {
colors.push({
color: color
})
})
AllPreviews.push(colors)
let positions = []
Tooltip.Positions.forEach(p => {
positions.push({
position: p
})
})
AllPreviews.push(positions)
return AllPreviews
})()
}
static Positions:TooltipPosition[] = ["top", "left", "right", "bottom"]
static Colors:TooltipColor[] = ["black", "grey", "brand", "green", "yellow", "red"]
}
let AllPreviews
export type TooltipPosition = "top" | "left" | "right" | "bottom"
export type TooltipColor = "black" | "grey" | "brand" | "green" | "yellow" | "red"

View File

@ -10,7 +10,8 @@ type ButtonProps = {
wrapper?: boolean, wrapper?: boolean,
look?: ButtonLook, look?: ButtonLook,
size?: ButtonSize, size?: ButtonSize,
hoverColor?: ButtonHovers hoverColor?: ButtonHovers,
disabled?: boolean
} }
export default class Button extends React.Component<ButtonProps, {hover: boolean}> { export default class Button extends React.Component<ButtonProps, {hover: boolean}> {
constructor(props:ButtonProps){ constructor(props:ButtonProps){
@ -66,6 +67,11 @@ export default class Button extends React.Component<ButtonProps, {hover: boolean
if("hoverColor" in this.props){ if("hoverColor" in this.props){
props.hoverColor = this.props.hoverColor props.hoverColor = this.props.hoverColor
} }
if("disabled" in this.props){
props.disabled = this.props.disabled
}else{
props.disabled = false
}
} }
if(props.color){ if(props.color){
@ -124,9 +130,10 @@ export default class Button extends React.Component<ButtonProps, {hover: boolean
}} onMouseLeave={(ev) => { }} onMouseLeave={(ev) => {
if(!hoverColor)return if(!hoverColor)return
this.setState({hover: false}) this.setState({hover: false})
}}> }} disabled={props.disabled}>
<div className={euhModule1.contents}>{props.children}</div> <div className={euhModule1.contents}>{props.children}</div>
</button> </button>
if(props.wrapper){ if(props.wrapper){
return <div className={buttonModule.buttonWrapper}> return <div className={buttonModule.buttonWrapper}>
{button} {button}
@ -169,6 +176,7 @@ export default class Button extends React.Component<ButtonProps, {hover: boolean
AllPreviews.push([{children: "Test Button"}]) AllPreviews.push([{children: "Test Button"}])
AllPreviews.push([{onClick: () => {}}]) AllPreviews.push([{onClick: () => {}}])
AllPreviews.push([{wrapper: false}]) AllPreviews.push([{wrapper: false}])
AllPreviews.push([{disabled: false}, {disabled: true}])
return AllPreviews return AllPreviews
})() })()
} }

View File

@ -1,7 +1,6 @@
import WebpackLoader from "./modules/WebpackLoader" import WebpackLoader from "./modules/WebpackLoader"
import Components from "./components/components" import Components from "./components/components"
import uuid from "./modules/uuid" import uuid from "./modules/uuid"
import PluginUtilities from "./modules/PluginUtilities"
import Utils from "./modules/Utils" import Utils from "./modules/Utils"
const LightcordApi = { const LightcordApi = {
@ -14,75 +13,7 @@ const LightcordApi = {
declare global { declare global {
var React:typeof import("react") var React:typeof import("react")
interface Window { interface Window {
Lightcord: { Lightcord: LightcordGlobal,
DiscordModules: {
/**
* Internal Discord's dispatcher - can be used to subscribe to gateway events / client events.
*/
dispatcher: {
_subscriptions: any,
_waitQueue: (() => void)[],
_processingWaitQueue: boolean,
_currentDispatchActionType: string | null,
_orderedActionHandlers: any,
_orderedCallbackTokens: any,
_lastID: number,
_dependencyGraph: any
isDispatching():boolean,
/**
* If the dispatcher isn't dispatching, then dispatch
*/
maybeDispatch(event: {type: string, [k: string]:any}):void,
/**
* Wait until the dispatcher finished dispatching, then dispatch
*/
dirtyDispatch(event: {type: string, [k: string]:any}):void,
/**
* dispatch
*/
dispatch(event: {type: string, [k: string]:any}):void,
/** Same as dispatcher.dispatch */
_dispatch(event: {type: string, [k: string]:any}):void,
/**
* Intercept events before they happens, if returning true, then the event will be blocked from dispatching.
*/
setInterceptor(interceptor: (event) => boolean):void,
/**
* Wait until the dispatcher has finished dispatching
*/
wait(waiting: () => void):void,
/** Subscribe to an event */
subscribe(event: string, listener: (event: {type: string, [k: string]:any}) => void):void,
/**
* Unsubscribe from the event.
*/
unsubscribe(event: string, listener: (event: {type: string, [k: string]:any}) => void):void,
register(name: string, actionHandler: any, storeDidChange: any):void
addDependencies,
_invalidateCaches,
_processWaitQueue,
_computeOrderedActionHandlers,
_computeOrderedCallbackTokens
},
constants: import("./types/DiscordConstantsTypes").default
},
Settings: {
devMode: boolean,
callRingingBeat: boolean
},
Api: {
/**
* Lightcord's autorization for lightcord's servers
*/
Authorization: string,
/**
* Waits until the first module that match the filter gets exported
* @param filter The filter that specifies the module to match.
*/
ensureExported(filter: (mod:any) => boolean):Promise<any>
} & typeof LightcordApi
},
BDModules: { BDModules: {
modules:any[], modules:any[],
get(filter:(mod:any)=>boolean, modules?:any[]):any[], get(filter:(mod:any)=>boolean, modules?:any[]):any[],
@ -90,8 +21,45 @@ declare global {
get(ids: [number|((mod:any)=>boolean)], modules?:any[]):any get(ids: [number|((mod:any)=>boolean)], modules?:any[]):any
} }
} }
var Lightcord:LightcordGlobal
} }
export default LightcordApi export default LightcordApi
Object.assign(window.Lightcord.Api, LightcordApi) Object.assign(window.Lightcord.Api, LightcordApi)
/**
* The main Lightcord exports. Can be accessed with `window.Lightcord`
*/
export interface LightcordGlobal {
DiscordModules: {
/**
* Internal Discord's dispatcher - can be used to subscribe to gateway events / client events.
*/
dispatcher: import("./types/DiscordDispatcherTypes").default,
constants: import("./types/DiscordConstantsTypes").default
},
Settings: {
devMode: boolean,
callRingingBeat: boolean
},
Api: LightcordApiGlobal
}
/**
* The main Api. Can be accessed with `window.Lightcord.Api`
*/
type LightcordApiGlobal = lightcordApiMainExports & typeof LightcordApi
type lightcordApiMainExports = {
/**
* Waits until the first module that match the filter gets exported
* @param filter The filter that specifies the module to match.
*/
ensureExported(filter: (mod:any) => boolean):Promise<any>,
/**
* Recreate the object without the `__proto__` and `prototype` properties - usefull for better formatting in console.
* @param obj The object to recreate
*/
cloneNullProto<Obj = any>(obj:Obj):Obj
}

View File

@ -0,0 +1,7 @@
export default function cloneNullProto<Obj=any>(obj:Obj):Obj{ // recreate object without __proto__
let o = Object.create(null)
Object.keys(obj).forEach(k => {
o[k] = obj[k]
})
return o
}

View File

@ -0,0 +1,10 @@
export default function excludeProperties<Obj = any>(obj:Obj, props:(keyof Obj)[]):Partial<Obj>{
let newObj = {}
Object.keys(obj).forEach((k) => {
if(props.includes(k as keyof Obj))return
newObj[k] = obj[k]
})
return newObj
}

View File

@ -0,0 +1,46 @@
export default interface DispatcherTypes {
_subscriptions: any,
_waitQueue: (() => void)[],
_processingWaitQueue: boolean,
_currentDispatchActionType: string | null,
_orderedActionHandlers: any,
_orderedCallbackTokens: any,
_lastID: number,
_dependencyGraph: any
isDispatching():boolean,
/**
* If the dispatcher isn't dispatching, then dispatch
*/
maybeDispatch(event: {type: string, [k: string]:any}):void,
/**
* Wait until the dispatcher finished dispatching, then dispatch
*/
dirtyDispatch(event: {type: string, [k: string]:any}):void,
/**
* dispatch
*/
dispatch(event: {type: string, [k: string]:any}):void,
/** Same as dispatcher.dispatch */
_dispatch(event: {type: string, [k: string]:any}):void,
/**
* Intercept events before they happens, if returning true, then the event will be blocked from dispatching.
*/
setInterceptor(interceptor: (event) => boolean):void,
/**
* Wait until the dispatcher has finished dispatching
*/
wait(waiting: () => void):void,
/** Subscribe to an event */
subscribe(event: string, listener: (event: {type: string, [k: string]:any}) => void):void,
/**
* Unsubscribe from the event.
*/
unsubscribe(event: string, listener: (event: {type: string, [k: string]:any}) => void):void,
register(name: string, actionHandler: any, storeDidChange: any):void
addDependencies,
_invalidateCaches,
_processWaitQueue,
_computeOrderedActionHandlers,
_computeOrderedCallbackTokens
}

View File

@ -60,7 +60,7 @@ module.exports = {
parallel: true, parallel: true,
sourceMap: true, sourceMap: true,
terserOptions: { terserOptions: {
mangle: true, mangle: false,
keep_classnames: true, keep_classnames: true,
keep_fnames: true keep_fnames: true
} }

View File

@ -4,7 +4,7 @@ const terser = require("terser")
const util = require("util") const util = require("util")
/** Super noisy if production is on. */ /** Super noisy if production is on. */
const production = false const production = true
let fs = require("fs") let fs = require("fs")
@ -23,7 +23,7 @@ async function main(){
await fs.promises.mkdir(__dirname+"/distApp/dist", {"recursive": true}) await fs.promises.mkdir(__dirname+"/distApp/dist", {"recursive": true})
console.info("Executing command `npm run compile`") console.info("Executing command `npm run compile`")
console.log(child_process.execSync("npm run compile", {encoding: "binary"})) //console.log(child_process.execSync("npm run compile", {encoding: "binary"}))
let startDir = path.join(__dirname, "./dist") let startDir = path.join(__dirname, "./dist")
let newDir = path.join(__dirname, "./distApp/dist") let newDir = path.join(__dirname, "./distApp/dist")
@ -34,7 +34,7 @@ async function main(){
for(let file of fs.readdirSync(folder, {withFileTypes: true})){ for(let file of fs.readdirSync(folder, {withFileTypes: true})){
if(file.isFile()){ if(file.isFile()){
let filepath = path.join(folder, file.name) let filepath = path.join(folder, file.name)
if(predicate(filepath)){ if(predicate(filepath) && filepath.split(/[\\/]+/).reverse()[1] !== "js"){
await compile(filepath, path.join(filepath.replace(folders.startDir, folders.newDir)), "..") await compile(filepath, path.join(filepath.replace(folders.startDir, folders.newDir)), "..")
}else{ }else{
await fs.promises.copyFile(filepath, filepath.replace(folders.startDir, folders.newDir)) await fs.promises.copyFile(filepath, filepath.replace(folders.startDir, folders.newDir))
@ -86,6 +86,20 @@ async function main(){
await fs.promises.unlink(path.join(__dirname, "distApp", "LightcordApi", "webpack.config.js")) await fs.promises.unlink(path.join(__dirname, "distApp", "LightcordApi", "webpack.config.js"))
await fs.promises.unlink(path.join(__dirname, "distApp", "LightcordApi", "tsconfig.json")) await fs.promises.unlink(path.join(__dirname, "distApp", "LightcordApi", "tsconfig.json"))
await processNextDir(path.join(__dirname, "DiscordJS"), {
startDir: path.join(__dirname, "DiscordJS"),
newDir: path.join(__dirname, "distApp", "DiscordJS")
}, ((filepath) => filepath.endsWith(".js") && (!production ? !filepath.includes("node_modules") : true)), async (filepath, newpath) => {
console.info(`Minifying ${filepath} to ${newpath}`)
await fs.promises.writeFile(newpath, terser.minify(await fs.promises.readFile(filepath, "utf8")).code, "utf8")
}).then(() => {
console.info(`Copied files and minified them from ${path.join(__dirname, "DiscordJS")}.`)
})
await fs.promises.rmdir(path.join(__dirname, "distApp", "DiscordJS", "src"), {"recursive": true})
await fs.promises.unlink(path.join(__dirname, "distApp", "DiscordJS", "webpack.config.js"))
await fs.promises.unlink(path.join(__dirname, "distApp", "DiscordJS", "tsconfig.json"))
fs.mkdirSync(path.join(__dirname, "distApp", "BetterDiscordApp", "js"), {recursive: true}) fs.mkdirSync(path.join(__dirname, "distApp", "BetterDiscordApp", "js"), {recursive: true})
fs.mkdirSync(path.join(__dirname, "distApp", "BetterDiscordApp", "css"), {recursive: true}) fs.mkdirSync(path.join(__dirname, "distApp", "BetterDiscordApp", "css"), {recursive: true})
const BDPackageJSON = require("./BetterDiscordApp/package.json") const BDPackageJSON = require("./BetterDiscordApp/package.json")

View File

@ -0,0 +1,143 @@
"use strict";
// This is a copy from LightcordApi/dist/components/inputs/Button.js
// Source code: LightcordApi/src/components/inputs/Button.ts
const ModuleLoader = require("./loaders/modules");
Object.defineProperty(exports, "__esModule", { value: true });
const WebpackLoader_1 = {
default: {
findByUniqueProperties: (props) => {
return ModuleLoader.get((mod) => {
if(mod.__esModule && ("default" in mod)){
let doesMatch = true
for(let prop of props){
if(!Object.prototype.hasOwnProperty.call(mod.default, prop))doesMatch = false
}
if(doesMatch)return true
}
for(let prop of props){
if(!Object.prototype.hasOwnProperty.call(mod, prop))return false
}
return true
})[0]
}
}
}
let ButtonModules;
let Button = /** @class */ (() => {
class Button extends React.Component {
constructor(props) {
super(props);
this.state = {
hover: false
};
}
get modules() {
return ButtonModules || (ButtonModules = [
WebpackLoader_1.default.findByUniqueProperties(["_horizontal"]),
WebpackLoader_1.default.findByUniqueProperties(["colorTransparent"]),
WebpackLoader_1.default.findByUniqueProperties(["buttonWrapper"]),
WebpackLoader_1.default.findByUniqueProperties(["ButtonColors"]),
]);
}
render() {
let [flexModule, euhModule1, buttonModule, colorsModule] = this.modules;
let props = {};
if (this.props) {
if ("color" in this.props) {
props.color = this.props.color;
}
if ("children" in this.props) {
props.children = this.props.children;
}
if ("onClick" in this.props) {
props.onClick = this.props.onClick;
}
if ("wrapper" in this.props) {
props.wrapper = !!this.props.wrapper;
}
if ("look" in this.props) {
props.look = this.props.look;
}
if ("size" in this.props) {
props.size = this.props.size;
}
if ("hoverColor" in this.props) {
props.hoverColor = this.props.hoverColor;
}
}
if (props.color) {
props.color = props.color.toLowerCase();
if (!Button.Colors.includes(props.color)) {
props.color = Button.Colors[0];
}
}
else {
props.color = Button.Colors[0];
}
if (props.look) {
props.look = props.look.toLowerCase();
if (!Button.Looks.includes(props.look)) {
props.look = Button.Looks[0];
}
}
else {
props.look = Button.Looks[0];
}
if (props.size) {
props.size = props.size.toLowerCase();
if (!Button.Sizes.includes(props.size)) {
props.size = Button.Sizes[0];
}
}
else {
props.size = Button.Sizes[0];
}
if (props.hoverColor) {
props.hoverColor = props.hoverColor.toLowerCase();
if (!Button.HoverColors.includes(props.hoverColor)) {
props.hoverColor = Button.HoverColors[0];
}
}
else {
props.hoverColor = Button.HoverColors[0];
}
let buttonSize = props.size ? colorsModule.ButtonSizes[props.size.toUpperCase()] || "" : "";
if (buttonSize)
buttonSize = " " + buttonSize;
let hoverColor = props.hoverColor ? colorsModule.ButtonHovers[props.hoverColor.toUpperCase()] || "" : "";
if (hoverColor)
hoverColor = " " + hoverColor;
props.onClick = typeof props.onClick === "function" ? props.onClick : () => { };
if (typeof props.wrapper !== "boolean")
props.wrapper = true;
let hover = this.state.hover ? euhModule1.hasHover : "";
if (hover)
hover = " " + hover;
let button = React.createElement("button", { type: "button", className: `${flexModule.flexChild} ${euhModule1.button} ${colorsModule.ButtonLooks[props.look.toUpperCase()]} ${colorsModule.ButtonColors[props.color.toUpperCase()]}${buttonSize}${hoverColor}${hover} ${euhModule1.grow}`, style: { flex: "0 1 auto" }, onClick: this.props.onClick, onMouseEnter: (ev) => {
if (!hoverColor)
return;
this.setState({ hover: true });
}, onMouseLeave: (ev) => {
if (!hoverColor)
return;
this.setState({ hover: false });
} },
React.createElement("div", { className: euhModule1.contents }, props.children));
if (props.wrapper) {
return React.createElement("div", { className: buttonModule.buttonWrapper }, button);
}
return button;
}
}
Button.Colors = ["brand", "grey", "red", "green", "yellow", "primary", "link", "white", "black", "transparent"];
Button.Looks = ["filled", "inverted", "outlined", "ghost", "link", "blank"];
Button.Sizes = ["small", "medium", "large", "xlarge", "min", "max", "icon", "none"];
Button.HoverColors = ["default", ...Button.Colors];
return Button;
})();
exports.default = Button;
//# sourceMappingURL=Button.js.map

View File

@ -7,4 +7,6 @@
720388515329998869 # fall 720388515329998869 # fall
347721410082242572 # oafu 347721410082242572 # oafu
695254385432854588 # oafu 695254385432854588 # oafu
625350657829896224 # oafu
652189358048411648 # mir
703675553890435153 # blacklight more like black list :yoj: 703675553890435153 # blacklight more like black list :yoj:

View File

@ -68,49 +68,32 @@ async function privateInit(){
if(electron.remote.process.argv.includes("--disable-betterdiscord")){ if(electron.remote.process.argv.includes("--disable-betterdiscord")){
let formComponents let formComponents
let margins let margins
let ButtonModules
class LightcordSettings extends React.Component { class LightcordSettings extends React.Component {
render(){ render(){
if(!formComponents)formComponents = ModuleLoader.get(e => e.FormSection)[0] if(!formComponents)formComponents = ModuleLoader.get(e => e.FormSection)[0]
if(!margins)margins = ModuleLoader.get(e => e.marginTop60)[0] if(!margins)margins = ModuleLoader.get(e => e.marginTop60)[0]
let [ let button = require("./Button").default
flexModule,
euhModule1,
buttonModule,
colorsModule,
] = this.ButtonModules
return React.createElement("div", {}, [ return React.createElement("div", {}, [
React.createElement(formComponents.FormSection, { React.createElement(formComponents.FormSection, {
className: "", className: "",
tag: "h2", tag: "h2",
title: "Lightcord's Settings" title: "Lightcord's Settings"
}, [ }, React.createElement(button, {
React.createElement("div", { className: buttonModule.buttonWrapper }, [ color: "yellow",
React.createElement("button", { look: "ghost",
type: "button", size: "medium",
className: `${flexModule.flexChild} ${euhModule1.button} ${euhModule1.lookFilled} ${colorsModule.ButtonColors.YELLOW} ${euhModule1.sizeSmall} ${euhModule1.grow}`, hoverColor: "red",
style: { flex: "0 1 auto" },
onClick: () => { onClick: () => {
console.log("Should relaunch") console.log("Should relaunch")
electron.remote.app.relaunch({ electron.remote.app.relaunch({
args: electron.remote.process.argv.slice(1).filter(e => e !== "--disable-betterdiscord") args: electron.remote.process.argv.slice(1).filter(e => e !== "--disable-betterdiscord")
}) })
electron.remote.app.quit() electron.remote.app.quit()
}
}, },
React.createElement("div", { className: euhModule1.contents }, "Relaunch with BetterDiscord")) wrapper: true
]) }, "Relaunch with BetterDiscord"))
])
])
}
get ButtonModules(){ // caching modules
return ButtonModules || (ButtonModules = [
ModuleLoader.get(e => e["_horizontal"])[0],
ModuleLoader.get(e => e["colorTransparent"])[0],
ModuleLoader.get(e => e["buttonWrapper"])[0],
ModuleLoader.get(e => e["ButtonColors"])[0]
]) ])
} }
} }
@ -132,7 +115,6 @@ async function privateInit(){
let getPredicateSections = settingModule.default.prototype.getPredicateSections let getPredicateSections = settingModule.default.prototype.getPredicateSections
settingModule.default.prototype.getPredicateSections = function(){ settingModule.default.prototype.getPredicateSections = function(){
let result = getPredicateSections.call(this, ...arguments) let result = getPredicateSections.call(this, ...arguments)
console.log(result)
if(result[1].section === "My Account"){ // user settings, not guild settings if(result[1].section === "My Account"){ // user settings, not guild settings
let poped = [] let poped = []
@ -261,25 +243,33 @@ async function privateInit(){
} }
const appSettings = electron.remote.getGlobal("appSettings") const appSettings = electron.remote.getGlobal("appSettings")
let Authorization = appSettings.get("LIGHTCORD_AUTH", false) /*let Authorization = appSettings.get("LIGHTCORD_AUTH", false)
let shouldShowPrompt = Authorization === false let shouldShowPrompt = Authorization === false
if(typeof Authorization !== "string"){ if(typeof Authorization !== "string"){
Authorization = null Authorization = null
appSettings.set("LIGHTCORD_AUTH", null) appSettings.set("LIGHTCORD_AUTH", null)
appSettings.save() appSettings.save()
}*/
let cloneNullProto = (obj) => { // recreate object without __proto__
let o = Object.create(null)
Object.keys(obj).forEach(k => {
o[k] = obj[k]
})
return o
} }
window.Lightcord = { window.Lightcord = cloneNullProto({
DiscordModules: { DiscordModules: cloneNullProto({
dispatcher, dispatcher,
constants constants
}, }),
Settings: { Settings: cloneNullProto({
devMode: false, devMode: false,
callRingingBeat: true callRingingBeat: true
}, }),
Api: { Api: cloneNullProto({/*
get Authorization(){ get Authorization(){
return Authorization return Authorization
}, },
@ -287,19 +277,21 @@ async function privateInit(){
if(typeof data !== "string" && data !== null)return Authorization if(typeof data !== "string" && data !== null)return Authorization
appSettings.set("LIGHTCORD_AUTH", Authorization = data) appSettings.set("LIGHTCORD_AUTH", Authorization = data)
appSettings.save() appSettings.save()
}, },*/
ensureExported Authorization: null,
}, ensureExported,
BetterDiscord: { // Global BetterDiscord's exported modules / only for exporting to Lightcord's main script, not for using in plugins cloneNullProto
}),
BetterDiscord: cloneNullProto({ // Global BetterDiscord's exported modules
} })
} })
dispatcher.subscribe("USER_SETTINGS_UPDATE", (data) => { dispatcher.subscribe("USER_SETTINGS_UPDATE", (data) => {
DiscordNative.ipc.send("UPDATE_THEME", data.settings.theme) DiscordNative.ipc.send("UPDATE_THEME", data.settings.theme)
}) })
require("../../../../../LightcordApi/js/main") require("../../../../../LightcordApi/js/main.js")
/* /*
if(shouldShowPrompt){ if(shouldShowPrompt){
@ -377,10 +369,6 @@ async function privateInit(){
const Utils = window.Lightcord.BetterDiscord.Utils const Utils = window.Lightcord.BetterDiscord.Utils
const DOMTools = window.Lightcord.BetterDiscord.DOM const DOMTools = window.Lightcord.BetterDiscord.DOM
// delete
delete window.Lightcord.BetterDiscord.Utils
delete window.Lightcord.BetterDiscord.DOM
let isBot = false let isBot = false
;(async function(){ ;(async function(){
const gatewayModule = await ensureExported(e => e.default && e.default.prototype && e.default.prototype._handleDispatch) const gatewayModule = await ensureExported(e => e.default && e.default.prototype && e.default.prototype._handleDispatch)
@ -478,6 +466,9 @@ async function privateInit(){
} }
return returnValue return returnValue
} }
dispatcher.subscribe("LOGOUT", () => {
isBot = false
})
function cancelGatewayPrototype(methodName){ function cancelGatewayPrototype(methodName){
if(gatewayModule.default.prototype[methodName]){ if(gatewayModule.default.prototype[methodName]){
const original = gatewayModule.default.prototype[methodName] const original = gatewayModule.default.prototype[methodName]
@ -493,12 +484,18 @@ async function privateInit(){
cancelGatewayPrototype("lobbyConnect") cancelGatewayPrototype("lobbyConnect")
cancelGatewayPrototype("lobbyDisconnect") cancelGatewayPrototype("lobbyDisconnect")
cancelGatewayPrototype("lobbyVoiceStatesUpdate") cancelGatewayPrototype("lobbyVoiceStatesUpdate")
cancelGatewayPrototype("guildStreamCreate") cancelGatewayPrototype("streamCreate")
cancelGatewayPrototype("streamWatch") cancelGatewayPrototype("streamWatch")
cancelGatewayPrototype("streamPing") cancelGatewayPrototype("streamPing")
cancelGatewayPrototype("streamDelete") cancelGatewayPrototype("streamDelete")
cancelGatewayPrototype("streamSetPaused") cancelGatewayPrototype("streamSetPaused")
const requestGuildMembers = gatewayModule.default.prototype.requestGuildMembers
gatewayModule.default.prototype.requestGuildMembers = function(){ // TODO: requestGuildMembers patch for bots.
/*if(!isBot)*/return requestGuildMembers.call(this, ...arguments)
console.log(arguments)
}
const hasUnreadModules = BDModules.get(e => e.default && e.default.hasUnread) const hasUnreadModules = BDModules.get(e => e.default && e.default.hasUnread)
hasUnreadModules.forEach((mod) => { hasUnreadModules.forEach((mod) => {
const hasUnread = mod.default.hasUnread const hasUnread = mod.default.hasUnread
@ -1068,7 +1065,22 @@ async function privateInit(){
}else{ }else{
logger.warn(new Error("Couldn't find module here")) logger.warn(new Error("Couldn't find module here"))
} }
})().catch(() => {}) const inviteModule = BDModules.get(e => e.default && e.default.acceptInvite)[0]
if(inviteModule){
const acceptInvite = inviteModule.default.acceptInvite
inviteModule.default.acceptInvite = function(code, location, extraOptions){
if(!isBot)return acceptInvite.call(this, ...arguments)
dispatcher.dispatch({
type: "INVITE_ACCEPT_FAILURE",
code
})
Utils.showToast("Lightcord Bot Emulation cannot join guilds.", {type: "error"})
return Promise.reject("Lightcord Bot Emulation cannot join guilds.")
}
}else{
logger.warn(new Error("Couldn't find module here"))
}
})().catch(console.error.bind(console, `%c[Error Bot shit]`, "color:red"))
let usedWebhooks = {} let usedWebhooks = {}
@ -1169,7 +1181,7 @@ async function privateInit(){
] = [ ] = [
BDModules.get(e => e.authBoxExpanded && typeof e.authBoxExpanded === "string")[0] BDModules.get(e => e.authBoxExpanded && typeof e.authBoxExpanded === "string")[0]
] ]
DOMTools.addStyle("tokenLoginPatch", `.${authBoxExpanded ? authBoxExpanded.authBoxExpanded.split(" ")[0] : "authBoxExpanded-2jqaBe"} { DOMTools.addStyle("tokenLoginPatch", `.${authBoxExpanded ? Utils.removeDa(authBoxExpanded.authBoxExpanded) : "authBoxExpanded-2jqaBe"} {
width: 900px; width: 900px;
}`) }`)
@ -1177,6 +1189,36 @@ async function privateInit(){
BetterDiscord.init() BetterDiscord.init()
events.emit("ready") events.emit("ready")
let reactDevToolsPath = "";
if (process.platform === "win32") reactDevToolsPath = path.resolve(process.env.LOCALAPPDATA, "Google/Chrome/User Data");
else if (process.platform === "linux") reactDevToolsPath = path.resolve(process.env.HOME, ".config/google-chrome");
else if (process.platform === "darwin") reactDevToolsPath = path.resolve(process.env.HOME, "Library/Application Support/Google/Chrome");
else reactDevToolsPath = path.resolve(process.env.HOME, ".config/chromium");
reactDevToolsPath += "/Default/Extensions/fmkadmapgofadopljbjfkapdkoienihi/";
if (fs.existsSync(reactDevToolsPath)) {
const versions = fs.readdirSync(reactDevToolsPath);
reactDevToolsPath = path.resolve(reactDevToolsPath, versions[versions.length - 1]);
}
if (!fs.existsSync(reactDevToolsPath), true){
reactDevToolsPath = path.join(__dirname, "../../../../react_devtools")
}
if(fs.existsSync(reactDevToolsPath)){
const webContents = remote.getCurrentWebContents()
const BrowserWindow = remote.BrowserWindow
setImmediate(() => webContents.on("devtools-opened", devToolsListener));
if (webContents.isDevToolsOpened()) devToolsListener();
function devToolsListener(){
if (!this.isExtensionInstalled) return;
BrowserWindow.removeDevToolsExtension("React Developer Tools");
const didInstall = BrowserWindow.addDevToolsExtension(reactDevToolsPath);
if (didInstall) Utils.log("React DevTools", "Successfully installed react devtools.");
else Utils.err("React DevTools", "Couldn't find react devtools.");
}
}
} }
require.extensions[".css"] = (m, filename) => { require.extensions[".css"] = (m, filename) => {
@ -1196,6 +1238,7 @@ require.extensions[".css"] = (m, filename) => {
let zlib = require("zlib") let zlib = require("zlib")
let tmp = require("tmp") let tmp = require("tmp")
const { remote } = require("electron")
require.extensions[".jsbr"] = (m, filename) => { require.extensions[".jsbr"] = (m, filename) => {
if(!zlib)zlib = require("zlib") if(!zlib)zlib = require("zlib")

View File

@ -3,8 +3,8 @@
position: relative; position: relative;
overflow: hidden; overflow: hidden;
height: 100%; height: 100%;
background: #18191c; background: var(--background-floating);
border: 1px solid #040405; border: 1px solid var(--deprecated-text-input-border-hover);
border-radius: 5px; border-radius: 5px;
display: -webkit-box; display: -webkit-box;
display: -ms-flexbox; display: -ms-flexbox;
@ -17,7 +17,7 @@
.lc-tabnav { .lc-tabnav {
top: 0; top: 0;
border-bottom: 1px solid #040405; border-bottom: 1px solid var(--deprecated-text-input-border-hover);
padding: 0 4px; padding: 0 4px;
width: 100%; width: 100%;
-ms-flex-item-align: start; -ms-flex-item-align: start;
@ -50,14 +50,10 @@
overflow: hidden; overflow: hidden;
position: relative; position: relative;
margin: 0 auto; margin: 0 auto;
width: 600px; width: 100%;
max-width: 100%; max-width: 100%;
-webkit-transform: scale(.85);
transform: scale(.85);
-webkit-box-sizing: border-box; -webkit-box-sizing: border-box;
box-sizing: border-box; box-sizing: border-box;
display: -webkit-box;
display: -ms-flexbox;
display: flex; display: flex;
-ms-flex-wrap: wrap; -ms-flex-wrap: wrap;
flex-wrap: wrap; flex-wrap: wrap;
@ -71,11 +67,16 @@
-webkit-box-direction: normal; -webkit-box-direction: normal;
-ms-flex-direction: column; -ms-flex-direction: column;
flex-direction: column; flex-direction: column;
padding: 40px;
} }
.lc-tab-box-shadow { .theme-dark .lc-tab-box-shadow {
-webkit-box-shadow: 0 0 20px 2px rgba(4,4,5,.3); -webkit-box-shadow: 0 0 20px 2px rgba(4,4,5,.3);
box-shadow: 0 0 20px 2px rgba(4,4,5,.3); box-shadow: 0 0 20px 2px rgba(4,4,5,.3);
} }
.theme-light .lc-tab-box-shadow {
-webkit-box-shadow: 0 0 5px 2px rgba(4,4,5,.1);
box-shadow: 0 0 5px 2px rgba(4,4,5,.1);
}
.lc-navItem { .lc-navItem {
padding: 14px 20px; padding: 14px 20px;
position: relative; position: relative;
@ -101,14 +102,17 @@
transition: transform .125s,-webkit-transform .125s; transition: transform .125s,-webkit-transform .125s;
} }
.lc-navItemActive { .lc-navItemActive {
color: #fff; color: var(--interactive-active);
} }
.lc-navItemActive::after { .lc-navItemActive::after {
-webkit-transform: none; -webkit-transform: none;
transform: none; transform: none;
} }
.lc-navItemInactive { .lc-navItemInactive {
color: #b9bbbe; color: var(--interactive-normal);
}
.lc-navItemInactive:hover {
color: var(--interactive-hover)
} }
.lc-navItemInactive::after { .lc-navItemInactive::after {
-webkit-transform: translateY(16px); -webkit-transform: translateY(16px);

View File

@ -110,7 +110,7 @@ function startup(bootstrapModules) {
console.log("Checking if version "+version+" is outdated...") console.log("Checking if version "+version+" is outdated...")
bootstrapModules.splashScreen.initSplash() bootstrapModules.splashScreen.initSplash()
bootstrapModules.splashScreen.events.on("SPLASH_SCREEN_READY", () => { bootstrapModules.splashScreen.events.on("SPLASH_SCREEN_READY", () => {
fetch("https://haste.deroku.xyz/raw/oqigetomog", { fetch("https://raw.githubusercontent.com/Lightcord/Lightcord/master/package.json", {
headers: { headers: {
"User-Agent": "Lightcord-Updater/1.0" "User-Agent": "Lightcord-Updater/1.0"
} }
@ -150,7 +150,7 @@ function setMainWindowVisible(visible) {
function updateApp(version){ function updateApp(version){
const bootstrapModules = require('./bootstrapModules') const bootstrapModules = require('./bootstrapModules')
const updateLink = "https://github.com/Lightcord/Lightcord/archive/master.zip" //const updateLink = "https://github.com/Lightcord/Lightcord/archive/master.zip"
bootstrapModules.splashScreen.setSplashState({ bootstrapModules.splashScreen.setSplashState({
status: "downloading-updates", status: "downloading-updates",

View File

@ -7,6 +7,7 @@ process.on("uncaughtException", console.error)
const ipcRenderer = require('./discord_native/ipc'); const ipcRenderer = require('./discord_native/ipc');
const electron = require("electron") const electron = require("electron")
electron.remote.getCurrentWindow().setBackgroundColor("#2f3136")
const TRACK_ANALYTICS_EVENT = 'TRACK_ANALYTICS_EVENT'; const TRACK_ANALYTICS_EVENT = 'TRACK_ANALYTICS_EVENT';
const TRACK_ANALYTICS_EVENT_COMMIT = 'TRACK_ANALYTICS_EVENT_COMMIT'; const TRACK_ANALYTICS_EVENT_COMMIT = 'TRACK_ANALYTICS_EVENT_COMMIT';
@ -82,7 +83,6 @@ process.once('loaded', () => {
}catch(e){} }catch(e){}
setTimeout(() => { setTimeout(() => {
electron.remote.getCurrentWindow().setBackgroundColor("#00000000") electron.remote.getCurrentWindow().setBackgroundColor("#00000000")
electron.remote.getCurrentWindow().center()
}, 500); }, 500);
}) })

View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) Facebook, Inc. and its affiliates.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -0,0 +1,6 @@
# Disclaimer
This folder is only a copy of react devtools.
The files in this folder are under the right of Facebook.
https://github.com/facebook/react/tree/master/packages/react-devtools

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
!function(e){var n={};function t(o){if(n[o])return n[o].exports;var r=n[o]={i:o,l:!1,exports:{}};return e[o].call(r.exports,r,r.exports,t),r.l=!0,r.exports}t.m=e,t.c=n,t.d=function(e,n,o){t.o(e,n)||Object.defineProperty(e,n,{enumerable:!0,get:o})},t.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},t.t=function(e,n){if(1&n&&(e=t(e)),8&n)return e;if(4&n&&"object"==typeof e&&e&&e.__esModule)return e;var o=Object.create(null);if(t.r(o),Object.defineProperty(o,"default",{enumerable:!0,value:e}),2&n&&"string"!=typeof e)for(var r in e)t.d(o,r,function(n){return e[n]}.bind(null,r));return o},t.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,"a",n),n},t.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},t.p="",t(t.s=89)}({89:function(e,n,t){"use strict";var o={},r=navigator.userAgent.indexOf("Firefox")>=0;function i(e,n){chrome.browserAction.setIcon({tabId:n,path:{16:"icons/16-"+e+".png",32:"icons/32-"+e+".png",48:"icons/48-"+e+".png",128:"icons/128-"+e+".png"}}),chrome.browserAction.setPopup({tabId:n,popup:"popups/"+e+".html"})}chrome.runtime.onConnect.addListener((function(e){var n,t,r=null,i=null;+(t=e.name)+""===t?(r=e.name,i="devtools",n=+e.name,chrome.tabs.executeScript(n,{file:"/build/contentScript.js"},(function(){}))):(r=e.sender.tab.id,i="content-script"),o[r]||(o[r]={devtools:null,"content-script":null}),o[r][i]=e,o[r].devtools&&o[r]["content-script"]&&function(e,n){function t(e){n.postMessage(e)}function o(n){e.postMessage(n)}function r(){e.onMessage.removeListener(t),n.onMessage.removeListener(o),e.disconnect(),n.disconnect()}e.onMessage.addListener(t),n.onMessage.addListener(o),e.onDisconnect.addListener(r),n.onDisconnect.addListener(r)}(o[r].devtools,o[r]["content-script"])})),r&&chrome.tabs.onUpdated.addListener((function(e,n,t){t.active&&"loading"===n.status&&i("disabled",e)})),chrome.runtime.onMessage.addListener((function(e,n){if(n.tab&&e.hasDetectedReact){var t=e.reactBuildType;-1!==n.url.indexOf("facebook.github.io/react")&&(t="production"),i(t,n.tab.id)}}))}});

View File

@ -0,0 +1 @@
!function(e){var t={};function n(o){if(t[o])return t[o].exports;var r=t[o]={i:o,l:!1,exports:{}};return e[o].call(r.exports,r,r.exports,n),r.l=!0,r.exports}n.m=e,n.c=t,n.d=function(e,t,o){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:o})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var o=Object.create(null);if(n.r(o),Object.defineProperty(o,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var r in e)n.d(o,r,function(t){return e[t]}.bind(null,r));return o},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=90)}({90:function(e,t,n){"use strict";var o=!1,r=!1;function a(){window.postMessage({source:"react-devtools-content-script",hello:!0},"*")}function c(e){e.source===window&&e.data&&"react-devtools-bridge"===e.data.source&&(r=!0,s.postMessage(e.data.payload))}var s=chrome.runtime.connect({name:"content-script"});if(s.onMessage.addListener((function(e){window.postMessage({source:"react-devtools-content-script",payload:e},"*")})),s.onDisconnect.addListener((function(){o=!0,window.removeEventListener("message",c),window.postMessage({source:"react-devtools-content-script",payload:{type:"event",event:"shutdown"}},"*")})),window.addEventListener("message",c),a(),!r)var i=setInterval((function(){r||o?clearInterval(i):a()}),500)}});

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
!function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=158)}({158:function(e,t){window.container=document.getElementById("container");var n=!1;window.injectStyles=function(e){if(!n){n=!0;var t=e(),r=!0,o=!1,u=void 0;try{for(var i,l=t[Symbol.iterator]();!(r=(i=l.next()).done);r=!0){var a=i.value;document.head.appendChild(a)}}catch(e){o=!0,u=e}finally{try{r||null==l.return||l.return()}finally{if(o)throw u}}}}}});

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 638 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 638 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 522 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 558 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 594 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 638 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -0,0 +1 @@
<svg id="Development" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024"><defs><style>.cls-1{fill:#d94a38;}.cls-2{fill:#fff;}.cls-3{fill:#231f20;}.cls-4{font-size:12px;font-family:MyriadPro-Regular, Myriad Pro;}</style></defs><title>development</title><g id="Background"><rect class="cls-1" width="1024" height="1024" rx="96" ry="96"/></g><g id="Rings"><g id="Ring-2" data-name="Ring"><path class="cls-2" d="M959,509c0-62-74-117-189-150,27-115,17-207-37-238s-139,6-224,88c-86-81-171-118-224-87s-64,123-36,239C135,394,61,449,61,511s74,117,189,150c-27,115-17,207,37,238s139-6,224-88c86,81,171,118,224,87s64-123,36-239C885,626,959,571,959,509ZM713,157c40,23,45,97,21,193a900,900,0,0,0-121-19,900,900,0,0,0-78-94C606,166,673,133,713,157ZM635,583c-14,24-28,47-43,69-27,2-54,3-83,3l-81-3c-15-22-30-46-44-70s-27-48-38-72c12-24,24-49,39-73s28-47,43-69c27-2,54-3,83-3l81,3c15,22,30,46,44,70s27,48,38,72C662,534,649,558,635,583Zm60-27c11,26,21,52,29,77-25,6-52,10-81,14l26-44ZM511,757c-17-19-35-40-52-63H563C546,716,528,738,511,757ZM378,647c-29-3-56-8-81-13,8-25,17-50,28-77l25,45ZM325,464c-11-26-21-52-29-77,25-6,52-10,81-14l-26,44ZM509,263c17,19,35,40,52,63H457C474,304,492,282,509,263ZM670,418l-28-45c29,3,56,8,81,13-8,25-17,50-28,77ZM305,158c40-23,106,9,177,78a900,900,0,0,0-77,95,900,900,0,0,0-120,20C260,255,265,181,305,158ZM102,511c0-46,61-88,156-114a900,900,0,0,0,44,114,900,900,0,0,0-43,114C164,599,102,558,102,511ZM307,863c-40-23-45-97-21-193a900,900,0,0,0,121,19,900,900,0,0,0,78,94C414,854,347,887,307,863Zm408-1c-40,23-106-9-177-78a900,900,0,0,0,77-95,900,900,0,0,0,120-20C760,765,755,839,715,862Zm46-239a900,900,0,0,0-44-114,900,900,0,0,0,43-114c96,26,157,67,157,114S856,597,761,623Z"/></g></g><g id="Ring_Blockers" data-name="Ring Blockers"><circle class="cls-1" cx="417" cy="672" r="45"/><circle class="cls-1" cx="699" cy="513" r="45"/><circle class="cls-1" cx="797" cy="634" r="45"/><circle class="cls-1" cx="479" cy="818" r="45"/><g id="Layer_14" data-name="Layer 14"><rect class="cls-1" x="420" y="621" width="377" height="188"/><rect class="cls-1" x="500" y="530" width="312" height="405"/></g></g><g id="Bug"><g id="Legs"><path class="cls-3" d="M702,496a17,17,0,0,0-21,13l-19,78,34,8,19-78A17,17,0,0,0,702,496Z"/><text class="cls-4" transform="translate(512 512)">780</text><text class="cls-4" transform="translate(512 512)">780</text><path class="cls-3" d="M813,626a17,17,0,0,0-23-9l-73,32,14,32,73-32A17,17,0,0,0,813,626Z"/><path class="cls-3" d="M834,756l-77-20-9,34,77,20a18,18,0,0,0,9-34Z"/><path class="cls-3" d="M425,656a17,17,0,1,0-10,33l76,23,10-33Z"/><path class="cls-3" d="M532,756l-64,48a18,18,0,1,0,21,28l64-48Z"/><path class="cls-3" d="M584,836l-21,77a17,17,0,1,0,34,9l21-77Z"/></g><g id="Body"><path class="cls-3" d="M762,690h0l-51-92h0A125,125,0,0,0,492,721h0l51,92h0A125,125,0,0,0,762,690Z"/></g><g id="Line"><path class="cls-1" d="M613,649h0a17,17,0,0,0-30,18h0L711,887l30-18Z"/></g><g id="Head_Ring" data-name="Head Ring"><circle class="cls-1" cx="511" cy="509" r="113"/></g><g id="Head"><circle class="cls-3" cx="512" cy="512" r="80"/></g></g></svg>

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

@ -0,0 +1 @@
<svg id="Development" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024"><defs><style>.cls-1{fill:#d94a38;}.cls-2{fill:#fff;}.cls-3{fill:#231f20;}.cls-4{font-size:12px;font-family:MyriadPro-Regular, Myriad Pro;}</style></defs><title>development</title><g id="Background"><rect class="cls-1" width="1024" height="1024" rx="96" ry="96"/></g><g id="Rings"><g id="Ring-2" data-name="Ring"><path class="cls-2" d="M959,509c0-62-74-117-189-150,27-115,17-207-37-238s-139,6-224,88c-86-81-171-118-224-87s-64,123-36,239C135,394,61,449,61,511s74,117,189,150c-27,115-17,207,37,238s139-6,224-88c86,81,171,118,224,87s64-123,36-239C885,626,959,571,959,509ZM713,157c40,23,45,97,21,193a900,900,0,0,0-121-19,900,900,0,0,0-78-94C606,166,673,133,713,157ZM635,583c-14,24-28,47-43,69-27,2-54,3-83,3l-81-3c-15-22-30-46-44-70s-27-48-38-72c12-24,24-49,39-73s28-47,43-69c27-2,54-3,83-3l81,3c15,22,30,46,44,70s27,48,38,72C662,534,649,558,635,583Zm60-27c11,26,21,52,29,77-25,6-52,10-81,14l26-44ZM511,757c-17-19-35-40-52-63H563C546,716,528,738,511,757ZM378,647c-29-3-56-8-81-13,8-25,17-50,28-77l25,45ZM325,464c-11-26-21-52-29-77,25-6,52-10,81-14l-26,44ZM509,263c17,19,35,40,52,63H457C474,304,492,282,509,263ZM670,418l-28-45c29,3,56,8,81,13-8,25-17,50-28,77ZM305,158c40-23,106,9,177,78a900,900,0,0,0-77,95,900,900,0,0,0-120,20C260,255,265,181,305,158ZM102,511c0-46,61-88,156-114a900,900,0,0,0,44,114,900,900,0,0,0-43,114C164,599,102,558,102,511ZM307,863c-40-23-45-97-21-193a900,900,0,0,0,121,19,900,900,0,0,0,78,94C414,854,347,887,307,863Zm408-1c-40,23-106-9-177-78a900,900,0,0,0,77-95,900,900,0,0,0,120-20C760,765,755,839,715,862Zm46-239a900,900,0,0,0-44-114,900,900,0,0,0,43-114c96,26,157,67,157,114S856,597,761,623Z"/></g></g><g id="Ring_Blockers" data-name="Ring Blockers"><circle class="cls-1" cx="417" cy="672" r="45"/><circle class="cls-1" cx="699" cy="513" r="45"/><circle class="cls-1" cx="797" cy="634" r="45"/><circle class="cls-1" cx="479" cy="818" r="45"/><g id="Layer_14" data-name="Layer 14"><rect class="cls-1" x="420" y="621" width="377" height="188"/><rect class="cls-1" x="500" y="530" width="312" height="405"/></g></g><g id="Bug"><g id="Legs"><path class="cls-3" d="M702,496a17,17,0,0,0-21,13l-19,78,34,8,19-78A17,17,0,0,0,702,496Z"/><text class="cls-4" transform="translate(512 512)">780</text><text class="cls-4" transform="translate(512 512)">780</text><path class="cls-3" d="M813,626a17,17,0,0,0-23-9l-73,32,14,32,73-32A17,17,0,0,0,813,626Z"/><path class="cls-3" d="M834,756l-77-20-9,34,77,20a18,18,0,0,0,9-34Z"/><path class="cls-3" d="M425,656a17,17,0,1,0-10,33l76,23,10-33Z"/><path class="cls-3" d="M532,756l-64,48a18,18,0,1,0,21,28l64-48Z"/><path class="cls-3" d="M584,836l-21,77a17,17,0,1,0,34,9l21-77Z"/></g><g id="Body"><path class="cls-3" d="M762,690h0l-51-92h0A125,125,0,0,0,492,721h0l51,92h0A125,125,0,0,0,762,690Z"/></g><g id="Line"><path class="cls-1" d="M613,649h0a17,17,0,0,0-30,18h0L711,887l30-18Z"/></g><g id="Head_Ring" data-name="Head Ring"><circle class="cls-1" cx="511" cy="509" r="113"/></g><g id="Head"><circle class="cls-3" cx="512" cy="512" r="80"/></g></g></svg>

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

@ -0,0 +1 @@
<svg id="Disabled" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024"><defs><style>.cls-1{fill:#aaa;}.cls-2{fill:#fff;}</style></defs><title>disabled</title><g id="Background"><rect class="cls-1" width="1024" height="1024" rx="96" ry="96"/></g><g id="Rings"><path class="cls-2" d="M959,509c0-62-74-117-189-150,27-115,17-207-37-238s-139,6-224,88c-86-81-171-118-224-87s-64,123-36,239C135,394,61,449,61,511s74,117,189,150c-27,115-17,207,37,238s139-6,224-88c86,81,171,118,224,87s64-123,36-239C885,626,959,571,959,509ZM713,157c40,23,45,97,21,193a900,900,0,0,0-121-19,900,900,0,0,0-78-94C606,166,673,133,713,157ZM635,583c-14,24-28,47-43,69-27,2-54,3-83,3l-81-3c-15-22-30-46-44-70s-27-48-38-72c12-24,24-49,39-73s28-47,43-69c27-2,54-3,83-3l81,3c15,22,30,46,44,70s27,48,38,72C662,534,649,558,635,583Zm60-27c11,26,21,52,29,77-25,6-52,10-81,14l26-44ZM511,757c-17-19-35-40-52-63H563C546,716,528,738,511,757ZM378,647c-29-3-56-8-81-13,8-25,17-50,28-77l25,45ZM325,464c-11-26-21-52-29-77,25-6,52-10,81-14l-26,44ZM509,263c17,19,35,40,52,63H457C474,304,492,282,509,263ZM670,418l-28-45c29,3,56,8,81,13-8,25-17,50-28,77ZM305,158c40-23,106,9,177,78a900,900,0,0,0-77,95,900,900,0,0,0-120,20C260,255,265,181,305,158ZM102,511c0-46,61-88,156-114a900,900,0,0,0,44,114,900,900,0,0,0-43,114C164,599,102,558,102,511ZM307,863c-40-23-45-97-21-193a900,900,0,0,0,121,19,900,900,0,0,0,78,94C414,854,347,887,307,863Zm408-1c-40,23-106-9-177-78a900,900,0,0,0,77-95,900,900,0,0,0,120-20C760,765,755,839,715,862Zm46-239a900,900,0,0,0-44-114,900,900,0,0,0,43-114c96,26,157,67,157,114S856,597,761,623Z"/></g><g id="Circle"><circle class="cls-2" cx="510" cy="510" r="80"/></g></svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -0,0 +1 @@
<svg id="Outdated" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024"><defs><style>.cls-1{fill:#202020;}.cls-2{fill:#fff;}.cls-3{fill:#f9f453;}</style></defs><title>outdated</title><g id="Background"><rect class="cls-1" width="1024" height="1024" rx="96" ry="96"/></g><g id="Rings"><path class="cls-2" d="M510,325C261,325,60,408,60,510S261,695,510,695s450-83,450-185S759,325,510,325Zm0,330c-225,0-407-65-407-145S285,365,510,365s408,65,408,145S735,655,510,655Z"/><path class="cls-2" d="M670,417C546,202,373,69,285,120s-59,267,65,482S647,951,735,900,794,633,670,417ZM384,583C272,388,237,197,306,157s217,86,329,280,148,385,78,425S497,777,384,583Z"/><g id="BLOCKER"><rect class="cls-1" x="564" y="572" width="315" height="397.12" transform="translate(652 -283) rotate(39)"/><rect class="cls-1" x="685" y="369" width="283" height="360.81" transform="translate(255 -262) rotate(21)"/></g><path class="cls-2" d="M670,603c124-215,153-431,65-482S474,202,350,417,197,849,285,900,546,818,670,603ZM384,437C497,243,644,117,714,157s34,231-78,425S376,903,306,863,272,632,384,437Z"/></g><g id="Circle"><circle class="cls-2" cx="512" cy="512" r="80"/></g><g id="Shield"><path class="cls-3" d="M960,887a24,24,0,0,0-5-15h0L807,605h0v-2h0a25,25,0,0,0-43,3h0L613,876h0a24,24,0,0,0-3,11,25,25,0,0,0,24,25H936A25,25,0,0,0,960,887ZM810,848a15,15,0,0,1-15,15H775a15,15,0,0,1-15-15V828a15,15,0,0,1,15-15h20a15,15,0,0,1,15,15Zm0-74a15,15,0,0,1-15,15H775a15,15,0,0,1-15-15V705a15,15,0,0,1,15-15h20a15,15,0,0,1,15,15Z"/></g></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -0,0 +1 @@
<svg id="Production" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024"><defs><style>.cls-1{fill:#202020;}.cls-2{fill:#59c9f1;}</style></defs><title>production</title><g id="Background"><rect class="cls-1" width="1024" height="1024" rx="96" ry="96"/></g><g id="Rings"><path class="cls-2" d="M959,509c0-62-74-117-189-150,27-115,17-207-37-238s-139,6-224,88c-86-81-171-118-224-87s-64,123-36,239C135,394,61,449,61,511s74,117,189,150c-27,115-17,207,37,238s139-6,224-88c86,81,171,118,224,87s64-123,36-239C885,626,959,571,959,509ZM713,157c40,23,45,97,21,193a900,900,0,0,0-121-19,900,900,0,0,0-78-94C606,166,673,133,713,157ZM635,583c-14,24-28,47-43,69-27,2-54,3-83,3l-81-3c-15-22-30-46-44-70s-27-48-38-72c12-24,24-49,39-73s28-47,43-69c27-2,54-3,83-3l81,3c15,22,30,46,44,70s27,48,38,72C662,534,649,558,635,583Zm60-27c11,26,21,52,29,77-25,6-52,10-81,14l26-44ZM511,757c-17-19-35-40-52-63H563C546,716,528,738,511,757ZM378,647c-29-3-56-8-81-13,8-25,17-50,28-77l25,45ZM325,464c-11-26-21-52-29-77,25-6,52-10,81-14l-26,44ZM509,263c17,19,35,40,52,63H457C474,304,492,282,509,263ZM670,418l-28-45c29,3,56,8,81,13-8,25-17,50-28,77ZM305,158c40-23,106,9,177,78a900,900,0,0,0-77,95,900,900,0,0,0-120,20C260,255,265,181,305,158ZM102,511c0-46,61-88,156-114a900,900,0,0,0,44,114,900,900,0,0,0-43,114C164,599,102,558,102,511ZM307,863c-40-23-45-97-21-193a900,900,0,0,0,121,19,900,900,0,0,0,78,94C414,854,347,887,307,863Zm408-1c-40,23-106-9-177-78a900,900,0,0,0,77-95,900,900,0,0,0,120-20C760,765,755,839,715,862Zm46-239a900,900,0,0,0-44-114,900,900,0,0,0,43-114c96,26,157,67,157,114S856,597,761,623Z"/></g><g id="Circle"><circle class="cls-2" cx="510" cy="510" r="80"/></g></svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -0,0 +1,9 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<script src="./build/main.js"></script>
</head>
<body>
</body>
</html>

View File

@ -0,0 +1,38 @@
{
"background": {
"persistent": false,
"scripts": [ "build/background.js" ]
},
"browser_action": {
"default_icon": {
"128": "icons/128-disabled.png",
"16": "icons/16-disabled.png",
"32": "icons/32-disabled.png",
"48": "icons/48-disabled.png"
},
"default_popup": "popups/disabled.html"
},
"content_scripts": [ {
"js": [ "build/injectGlobalHook.js" ],
"matches": [ "\u003Call_urls>" ],
"run_at": "document_start"
} ],
"content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'",
"description": "Adds React debugging tools to the Chrome Developer Tools.\n\nCreated from revision 23309eb38 on 5/18/2020.",
"devtools_page": "main.html",
"icons": {
"128": "icons/128-production.png",
"16": "icons/16-production.png",
"32": "icons/32-production.png",
"48": "icons/48-production.png"
},
"key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA39Lr82J1eer+RvXeQG6HYHb2A6xU/83bcIyOcu+Wu2vYO/jbBvlD3m/xqrU4xSXJ/uAC1XY/YtlRs2X2RE1XiYMMlnqw27QdI5tVcSnKedmTFNAsnSaQ/OZT5tzH3HntLDfrFof5BC5RmFuie+kQKGTh673JW0ZdKTUsW406Fckagl9WpPL+qp3Gah3Jw02zxfQX9yUd5gJHYvv8T31DO9+HsI8lPeEjanURY59rRUfg3JKy1aPfts6eISy9kpHC+LrRSHU2Zp5AuUkOh8qEg6DoHFwBNYX20bdd6ekj0OZiIz/9xj9ceNhAr85QYB0641Tzhs3Tg96k56VNwjdN2QIDAQAB",
"manifest_version": 2,
"minimum_chrome_version": "49",
"name": "React Developer Tools",
"permissions": [ "file:///*", "http://*/*", "https://*/*" ],
"update_url": "https://clients2.google.com/service/update2/crx",
"version": "4.7.0",
"version_name": "4.7.0 (5/18/2020)",
"web_accessible_resources": [ "main.html", "panel.html", "build/react_devtools_backend.js", "build/renderer.js" ]
}

View File

@ -0,0 +1,32 @@
<!doctype html>
<html style="display: flex">
<head>
<meta charset="utf8">
<style>
html {
display: flex;
}
body {
margin: 0;
padding: 0;
flex: 1;
display: flex;
}
#container {
display: flex;
flex: 1;
width: 100%;
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
</style>
</head>
<body>
<!-- main react mount point -->
<div id="container">Unable to find React on the page.</div>
<script src="./build/panel.js"></script>
</body>
</html>

View File

@ -0,0 +1,32 @@
<script src="shared.js"></script>
<style>
html, body {
font-size: 14px;
min-width: 460px;
min-height: 133px;
}
body {
margin: 8px;
}
hr {
width: 100%;
}
</style>
<p>
<b>This page includes an extra development build of React. &#x1f6a7;</b>
</p>
<p>
The React build on this page includes both development and production versions because dead code elimination has not been applied correctly.
<br />
<br />
This makes its size larger, and causes React to run slower.
<br />
<br />
Make sure to <a href="https://facebook.github.io/react/docs/optimizing-performance.html#use-the-production-build">set up dead code elimination</a> before deployment.
</p>
<hr />
<p>
Open the developer tools, and "Components" and "Profiler" tabs will appear to the right.
</p>

View File

@ -0,0 +1,28 @@
<script src="shared.js"></script>
<style>
html, body {
font-size: 14px;
min-width: 460px;
min-height: 101px;
}
body {
margin: 8px;
}
hr {
width: 100%;
}
</style>
<p>
<b>This page is using the development build of React. &#x1f6a7;</b>
</p>
<p>
Note that the development build is not suitable for production.
<br />
Make sure to <a href="https://facebook.github.io/react/docs/optimizing-performance.html#use-the-production-build">use the production build</a> before deployment.
</p>
<hr />
<p>
Open the developer tools, and "Components" and "Profiler" tabs will appear to the right.
</p>

Some files were not shown because too many files have changed in this diff Show More