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;
}
#pubslayer #bd-settings-sidebar .ui-tab-bar-separator {
#pubslayer .ui-tab-bar-separator {
background-color: hsla(218,5%,47%,.3);
margin-left: 10px;
margin-right: 10px;
@ -899,7 +899,7 @@ body .ace_closeButton:active {
margin-left: 10px;
}
#bd-settings-sidebar .ui-tab-bar-item {
.ui-tab-bar-item {
font-size: 16px;
font-weight: 500;
line-height: 20px;
@ -912,33 +912,33 @@ body .ace_closeButton:active {
position: relative;
overflow: hidden;
}
#bd-settings-sidebar .ui-tab-bar-item.selected {
.ui-tab-bar-item.selected {
cursor: default;
}
.theme-dark #bd-settings-sidebar .ui-tab-bar-item {
.theme-dark .ui-tab-bar-item {
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);
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);
color: #fff;
}
.theme-light #bd-settings-sidebar .ui-tab-bar-item {
.theme-light .ui-tab-bar-item {
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);
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);
color: #fff;
}
#bd-settings-sidebar .ui-tab-bar-header {
.ui-tab-bar-header {
font-size: 12px;
font-weight: 700;
line-height: 16px;
@ -949,37 +949,33 @@ body .ace_closeButton:active {
padding: 6px 10px;
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;
}
.theme-light #bd-settings-sidebar .ui-tab-bar-header {
.theme-light .ui-tab-bar-header .bd-changelog-button {
color: #b9bbbe;
}
#bd-settings-sidebar .ui-tab-bar-header .bd-changelog-button {
height: 16px;
}
#bd-settings-sidebar .ui-tab-bar-header .bd-icon {
.ui-tab-bar-header .bd-icon {
cursor: pointer;
fill: #72767d;
}
#bd-settings-sidebar .ui-tab-bar-header .bd-icon:hover {
.ui-tab-bar-header .bd-icon:hover {
fill: #fff;
}
#bd-settings-sidebar .ui-tab-bar-separator {
.ui-tab-bar-separator {
height: 1px;
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);
}
.theme-light #bd-settings-sidebar .ui-tab-bar-separator {
.theme-light .ui-tab-bar-separator {
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

@ -249,4 +249,6 @@ const makeAddonAPI = (cookie, list, manager) => new class AddonAPI {
BdApi.Plugins = makeAddonAPI(pluginCookie, bdplugins, pluginModule);
BdApi.Themes = makeAddonAPI(themeCookie, bdthemes, themeModule);
export default BdApi;
export default BdApi;
window.Lightcord.BetterDiscord.BdApi = BdApi

View File

@ -1,6 +1,10 @@
/* BDEvents */
const EventEmitter = require("events");
export default new class BDEvents extends EventEmitter {
constructor(){
super()
window.Lightcord.BetterDiscord.BDEvents = this
}
dispatch(eventName, ...args) {this.emit(eventName, ...args);}
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}$`);
export default new class ClassNormalizer {
constructor(){
window.Lightcord.BetterDiscord.BDEvents = this
}
stop() {
if (!this.hasPatched) return;
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 themeModule from "./themeModule";
import Utils from "./utils";
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 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 escapedAtRegex = /^\\@/;
export let addonCache = {}
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 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) {
if (this.watchers[contentType]) return;
const isPlugin = contentType === "plugin";
@ -171,6 +219,39 @@ export default new class ContentManager {
if (typeof(filename) === "undefined" || typeof(type) === "undefined") return;
const isPlugin = type === "plugin";
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));}
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));
@ -244,4 +325,8 @@ export default new class ContentManager {
loadPlugins() {return this.loadAllContent("plugin");}
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 v2 from "./v2";
import webpackModules from "./webpackModules";
import contentManager from "./contentManager";
function Core() {
// Object.assign(bdConfig, __non_webpack_require__(DataStore.configFile));
@ -81,6 +82,9 @@ Core.prototype.init = async function() {
Utils.log("Startup", "Updating Settings");
settingsPanel.initializeSettings();
Utils.log("Startup", "Loading Addons Cache")
await contentManager.loadAddonCertifierCache()
Utils.log("Startup", "Loading Plugins");
await pluginModule.loadPlugins();
@ -147,16 +151,61 @@ Core.prototype.patchAttributes = async function() {
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"))
.then(UserPopout => {
console.log(UserPopout)
const render = UserPopout.default.prototype.render
UserPopout.default.prototype.render = function(){
const returnValue = render.call(this, ...arguments)
console.log(returnValue, this.props)
return returnValue
// TODO: try to patch correctly the user popout on a next update
const Anchor = WebpackModules.find(m => m.displayName == "Anchor");
ensureExported(e => e.default && e.default.displayName === "DiscordTag")
.then(DiscordTag => {
let DiscordTagComp = DiscordTag.default
DiscordTag.default = function(props){
let returnValue = DiscordTagComp(props)
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) => {
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
@ -414,6 +463,7 @@ Core.prototype.patchAttachment = function() {
const Anchor = WebpackModules.find(m => m.displayName == "Anchor");
if (!Anchor || !Attachment || !Attachment.default) return;
this.AttachmentPatch = Utils.monkeyPatch(Attachment, "default", {after: (data) => {
if(!settingsCookie["fork-ps-6"])return
const attachment = data.methodArguments[0] || null
const children = Utils.getNestedProp(data.returnValue, "props.children");
@ -421,7 +471,7 @@ Core.prototype.patchAttachment = function() {
if (!Array.isArray(children)) return;
const id = uuidv4()
children.push(BDV2.react.createElement("div", {
children.push(BDV2.react.createElement("span", {
id: "certified-"+id
}))
PluginCertifier.patch(attachment, "certified-"+id)
@ -644,4 +694,8 @@ Core.prototype.updateInjector = async function() {
return success;
};
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() {
this.data = {settings: {stable: {}, canary: {}, ptb: {}}};
this.pluginData = {};
window.Lightcord.BetterDiscord.DataStore = this
}
initialize() {

View File

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

View File

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

View File

@ -1,8 +1,5 @@
import {bdConfig, settingsCookie} from "../0globals";
import DataStore from "./dataStore";
import BDV2 from "./v2";
import Utils from "./utils";
//import DiscordCrypt from "./DiscordCrypt";
const Constants = {
EmojiRegex: /<a?\.(\w+)\.(\d+)>/g
@ -19,7 +16,7 @@ let emojiSearch = BDModules.get(e => e.default && e.default.getDisambiguatedEmoj
export default new class EmojiModule {
constructor(){
this.init()
this.init().catch(err => Utils.err("EmojiModule", "An error occured", err)) // better logging
}
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(!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(AutocompleteModule && AutoCompletionTemplates && EmojiModuleQuery && Messages && guildModule && emojiSearch){
console.log(`Patching getAutocompleteOptions of AutoCompletionTemplates`, AutoCompletionTemplates)
const getAutocompleteOptions = AutoCompletionTemplates.getAutocompleteOptions
@ -80,15 +78,14 @@ export default new class EmojiModule {
/** Emoji display */
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) => {
const message = Utils.getNestedProp(data.methodArguments[0], "childrenMessageContent.props.message")
if(!message)return
const content = Utils.getNestedProp(data.methodArguments[0], "childrenMessageContent.props.content")
if(!content || !content.length)return
// content = DiscordCrypt.decryptContent(content)
/**
* @type {{
* raw: string,

View File

@ -4,14 +4,18 @@ import * as crypto from "crypto"
import BDV2 from "./v2"
import tooltipWrap from "../ui/tooltipWrap"
import Utils from "./utils"
import { createReadStream } from "fs"
import { basename } from "path"
import { createReadStream, writeFileSync } from "fs"
import { basename, join } from "path"
import contentManager from "./contentManager"
import { addonCache } from "./contentManager"
const cache = {}
const cache2 = {}
export default new class PluginCertifier {
constructor(){}
constructor(){
window.Lightcord.BetterDiscord.PluginCertifier = this
}
patch(attachment, id){
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")
let isHarmful = false
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] = {
suspect: true,
name: hashToUrl[hash].split("/").pop(),
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}`)
@ -102,11 +108,13 @@ export function checkHash(hash, data, filename, resultCallback, removeCallback){
}
}).then(async res => {
if(res.status !== 200){
if(filename.endsWith(".theme.css"))return removeCallback()
checkViruses(hash, data, resultCallback, removeCallback)
if(filename.endsWith(".theme.css"))return removeCallback(hash)
checkViruses(hash, data, resultCallback, removeCallback, filename)
return
}
const result = await res.json()
result.hash = hash
result.filename = filename
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")
let data = Buffer.alloc(0)
@ -131,7 +139,16 @@ export function processFile(__path, resultCallback, removeCallback = () => {}){
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)
})
@ -185,7 +202,6 @@ function renderToElements(id, result, filename){
if(!flowerStarModule)flowerStarModule = BDModules.get(e => e.flowerStarContainer)[0]
if(!childModule)childModule = BDModules.get(e => e.childContainer)[0]
console.log(result)
if(result.suspect){
try{
div.parentNode.style.borderColor = "rgb(240, 71, 71)"
@ -224,8 +240,8 @@ function renderToElements(id, result, filename){
console.error(e)
}
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("svg", {className: BDModules.get(e => e.svg)[0].svg, "aria-hidden":"false",width:"16px",height:"16px",viewBox:"0 0 40 32"},
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:"20px",height:"20px",viewBox:"0 0 40 32"},
BDV2.react.createElement("rect", {
x:"0",
y:"0",
@ -241,31 +257,186 @@ function renderToElements(id, result, filename){
), div)
}else if(!result.official){
div.parentNode.style.borderColor = "#4087ed"
BDV2.reactDom.render(BDV2.react.createElement(tooltipWrap, {text: result.type+" "+result.name+" is certified by Lightcord."},
BDV2.react.createElement("div", {className: flowerStarModule.flowerStarContainer, style: {width: "16px", height: "16px"}},
BDV2.react.createElement("svg", {className: flowerStarModule.flowerStar, "aria-hidden":"false",width:"16px",height:"16px",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("div", {className: childModule.childContainer},
BDV2.react.createElement("svg", {"aria-hidden":"false",width:"16px",height:"16px",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"})
let span = BDV2.react.createElement("span", {style: {display: "inherit"}}, [
BDV2.react.createElement(tooltipWrap, {text: result.type+" "+result.name+" is certified by Lightcord."},
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("div", {className: childModule.childContainer},
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(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>
)
)
)
), div)
])
BDV2.reactDom.render(span, div)
}else{
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"},
BDV2.react.createElement("div", {className: flowerStarModule.flowerStarContainer, style: {width: "16px", height: "16px"}},
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("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("svg", {"aria-hidden":"false",width:"16px",height:"16px",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"})
let span = BDV2.react.createElement("span", {style: {display: "inherit"}}, [
BDV2.react.createElement(tooltipWrap, {text: result.type+" "+result.name+" was made by the developers of Lightcord.", style:"brand"},
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("div", {className: childModule.childContainer},
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(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>
)
)
)
), div)
])
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";
class PluginModule {
constructor(){
window.Lightcord.BetterDiscord.PluginModule = this
}
get folder() {return ContentManager.pluginsFolder;}
}

View File

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

View File

@ -45,4 +45,4 @@ export default new class reactDevTools {
stop() {
webContents.removeListener("devtools-opened", this.listener);
}
};
};

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 V2_SettingsPanel_Sidebar from "./settingsPanelSidebar";
import Utils from "./utils";
import BDV2 from "./v2";
import ContentManager from "./contentManager";
import BDEvents from "./bdEvents";
import coloredText from "./coloredText";
import tfHour from "./24hour";
import reactDevTools from "./reactDevTools";
import DOM from "./domtools";
import publicServersModule from "./publicServers";
@ -15,10 +13,7 @@ import voiceMode from "./voiceMode";
import ClassNormalizer from "./classNormalizer";
import dMode from "./devMode";
import Tools from "../ui/tools";
import Scroller from "../ui/scroller";
import SectionedSettingsPanel from "../ui/sectionedSettingsPanel";
import SettingsPanel from "../ui/settingsPanel";
import CssEditor from "../ui/cssEditor";
import CardList from "../ui/addonlist";
import V2C_PresenceSettings from "../ui/presenceSettings";
@ -29,9 +24,28 @@ import AntiAdDM from "./AntiAdDM";
import blurPrivate from "./blurPrivate";
import disableTyping from "./disableTyping";
import ApiPreview from "../ui/ApiPreview";
import V2C_SettingsTitle from "../ui/settingsTitle";
import Switch from "../ui/switch";
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 {
@ -51,6 +65,9 @@ export default new class V2_SettingsPanel {
this.sidebar.register("lcapipreview", makeComponent(this.ApiPreviewComponent.bind(this)))
/* Bandaged BD */
this.sidebar.register("BDChangelogTitle", makeComponent(() => {
return new BDSidebarHeader().render()
}))
this.sidebar.register("core", makeComponent(this.coreComponent.bind(this)))
this.sidebar.register("customcss", makeComponent(this.customCssComponent.bind(this)))
this.sidebar.register("plugins", makeComponent(this.renderAddonPane("plugins")))
@ -192,10 +209,10 @@ export default new class V2_SettingsPanel {
else dMode.stopCopySelector();
}
if (id === "reactDevTools") {
/*if (id === "reactDevTools") {
if (enabled) reactDevTools.start();
else reactDevTools.stop();
}
}*/
if (id === "lightcord-1") {
if (enabled) window.Lightcord.Settings.devMode = true
else window.Lightcord.Settings.devMode = false
@ -246,7 +263,7 @@ export default new class V2_SettingsPanel {
}
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-3"]) DOM.addClass(document.body, "bd-minimal-chan");
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(){
console.log("Should relaunch")
remote.app.relaunch({
args: remote.process.argv.slice(1).concat(["--disable-betterdiscord"])
})
remote.app.quit()
}}, "Relaunch without BetterDiscord")
BDV2.react.createElement(window.Lightcord.Api.Components.inputs.Button, {
color: "yellow",
look: "ghost",
size: "medium",
hoverColor: "red",
onClick(){
console.log("Should relaunch")
remote.app.relaunch({
args: remote.process.argv.slice(1).concat(["--disable-betterdiscord"])
})
remote.app.quit()
},
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){
class SettingComponent extends React.Component {
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 {
constructor() {
@ -50,7 +41,7 @@ export default class V2_SettingsPanel_Sidebar {
id: "accountinfo"
}
]
if(!!window.Lightcord.Settings.devMode)items.push({
if(window.Lightcord.Settings.devMode)items.push({
text: "Api Components Preview",
id: "lcapipreview"
})
@ -74,8 +65,8 @@ export default class V2_SettingsPanel_Sidebar {
section: "DIVIDER"
},
{
section: "HEADER",
label: "Bandaged BD"
section: "CUSTOM",
element: this.getComponent("BDChangelogTitle")
},
...this.items.map(e => {
return {
@ -89,4 +80,8 @@ 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";
class ThemeModule {
constructor(){
window.Lightcord.BetterDiscord.ThemeModule = this
}
get folder() {return ContentManager.themesFolder;}
}

View File

@ -70,6 +70,7 @@ export default new class V2 {
reactDom: this.WebpackModules.findByUniqueProperties(["findDOMNode"])
};
this.getInternalInstance = e => e[Object.keys(e).find(k => k.startsWith("__reactInternalInstance"))];
window.Lightcord.BetterDiscord.V2 = this
}
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 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>
<MarginTop></MarginTop>
<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}>
Documentation
</Lightcord.Api.Components.inputs.Button>
@ -71,7 +71,7 @@ export default class ApiPreview extends React.PureComponent {
return final
}
let renderPreview = () => {
return <div style={{marginTop: "20px", marginBottom: "20px"}}>
return <div style={{margin: "20px"}}>
<div style={{
backgroundColor: "var(--background-primary)",
padding: "30px 30px",
@ -82,7 +82,7 @@ export default class ApiPreview extends React.PureComponent {
</div>
}
let renderCode = () => {
return <div style={{marginTop: "20px", marginBottom: "20px"}}>
return <div style={{margin: "20px"}}>
<div style={{
backgroundColor: "var(--background-primary)",
padding: "30px 30px",
@ -100,7 +100,7 @@ export default class ApiPreview extends React.PureComponent {
</div>
</div>
}
let getStrForProp = (value) => {
let getStrForProp = (value, compPath, lang) => {
if(typeof value === "string"){
return value
}else if(typeof value === "boolean"){
@ -109,6 +109,33 @@ export default class ApiPreview extends React.PureComponent {
return value.toString()
}else if(typeof value === "object"){
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 JSON.stringify(value, null, " ")
@ -129,13 +156,13 @@ export default class ApiPreview extends React.PureComponent {
let childrenProp = null
Object.keys(props).forEach(key => {
if(key == "children"){
childrenProp = getStrForProp(props[key])
childrenProp = getStrForProp(props[key], compPath, lang)
}else{
let str = key+"="
if(typeof props[key] === "string"){
str += JSON.stringify(props[key])
}else{
str += `{${getStrForProp(props[key])}}`
str += `{${getStrForProp(props[key], compPath, lang)}}`
}
propStrings.push(str)
}
@ -153,7 +180,7 @@ export default class ApiPreview extends React.PureComponent {
let children = props.children || null
delete props.children
if(children && children.$$typeof && (children.$$typeof === Symbol.for("react.element") || children.$$typeof === 0xeac7)){
children = "Your components here."
children = getStrForProp(children, compPath, lang)
}
let propStrings = []
Object.keys(props).forEach(key => {
@ -162,7 +189,7 @@ export default class ApiPreview extends React.PureComponent {
if(typeof props[key] === "string"){
str += JSON.stringify(props[key])
}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
return " " + str
}).join("\n")
@ -186,7 +213,8 @@ export default class ApiPreview extends React.PureComponent {
}else{
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>

View File

@ -191,19 +191,26 @@ export default class V2C_PluginCard extends BDV2.reactComponent {
const {authorId, authorLink} = this.props.addon;
const style = {}
if(!this.isScanning){
this.isScanning = true
processFile(resolve(this.props.addon.filename.endsWith(".plugin.js") ? contentManager.pluginsFolder : contentManager.themesFolder, this.props.addon.filename), (result) => {
if(this.unmounted)return
this.setState({
isTrusted: !result.suspect
})
}, () => {})
}else{
if(this.state.isTrusted){
style.borderColor = "#4087ed"
if(settingsCookie["fork-ps-6"]){
if(!this.isScanning){
this.isScanning = true
processFile(resolve(this.props.addon.filename.endsWith(".plugin.js") ? contentManager.pluginsFolder : contentManager.themesFolder, this.props.addon.filename), (result) => {
if(this.unmounted)return
this.setState({
isTrusted: result.suspect ? "suspect" : true
})
}, () => {})
}else{
if(this.state.isTrusted === true){
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},
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})),

View File

@ -1,7 +1,3 @@
/**
* How the fuck did I do this
*/
import BDV2 from "../modules/v2";
import V2C_SettingsTitle from "./settingsTitle";
import V2C_SettingsGroup from "./settingsGroup";
@ -556,7 +552,7 @@ class Tab extends React.Component {
}
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(){
return popoutModule || (popoutModule = [
BDModules.get(e => e.userPopout)[0],
@ -722,7 +718,7 @@ class Status extends React.Component {
let timestampClass = ""
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(){
return ProfileModules || (ProfileModules = [
BDModules.get(e => e.flex && e._horizontal)[0],

View File

@ -1,11 +1,17 @@
# Lightcord's Discord.js
Disclaimer:
This part of Lightcord is still in development. Features could be added/change/removed.
### What is this ?
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 ?
[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 ?
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
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. */
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{
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 { DiscordGuild, channelsModule, guildModule, UserSettingsModule, ConstantsModule, CdnModule, AckModule } from "../util/DiscordToModules"
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 SnowflakeUtil from "../util/Snowflake"
import GuildMember from "./GuildMember"
@ -271,17 +271,39 @@ export default class Guild extends BaseStructure {
}).then(() => this)
}
ban(user:UserResolvable, {
async ban(user:UserResolvable, {
days = 0,
reason = null
}: {
days?: number,
reason?: string
}){
} = {}):Promise<Snowflake>{ // always returning a snowflake
let id = resolveUserID(user)
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){
}
fetch():Promise<Guild>{ // Guild is synced by Discord. Only refreshing from cache.

View File

@ -3,7 +3,7 @@ import GuildChannel from "./GuildChannel";
import { DiscordChannel } from "../util/DiscordToModules";
import { ChannelTypes } from "../util/Constants";
export class TextChannel extends GuildChannel/* implements TextBasedChannel*/ {
export default class TextChannel extends GuildChannel/* implements TextBasedChannel*/ {
constructor(data:DiscordChannel){
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 BaseChannel from "../structures/BaseChannel";
import Guild from "../structures/Guild";
import { TextChannel } from "../structures/TextChannel";
import TextChannel from "../structures/TextChannel";
import GuildMember from "../structures/GuildMember";
import Role from "../structures/Role";
import User from "../structures/User";
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{
let constructor = channels[channel.type] || BaseChannel
@ -108,4 +112,39 @@ export function resolveUserID(user:UserResolvable){
if(user instanceof Guild)return user.ownerID // Guild
if(user instanceof GuildMember)return user.id // GuildMember
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==",
"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": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
@ -2971,6 +2992,12 @@
"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": {
"version": "1.0.1",
"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": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz",
@ -3397,6 +3430,12 @@
"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": {
"version": "1.3.5",
"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==",
"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": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz",
@ -4144,6 +4189,15 @@
"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": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.1.tgz",
@ -4441,6 +4495,17 @@
"integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=",
"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": {
"version": "0.8.2",
"resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz",
@ -5006,12 +5071,74 @@
"integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=",
"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": {
"version": "3.9.5",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.5.tgz",
"integrity": "sha512-hSAifV3k+i6lEoCJ2k6R2Z/rp/H3+8sdmcn5NrS3/3kE7+RyZXm9aqvxWqjEXHAd8b0pShatpcdMTvEdvAJltQ==",
"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": {
"version": "1.0.4",
"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=",
"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": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.7.0.tgz",

View File

@ -7,7 +7,9 @@
"build": "webpack --progress --colors",
"watch": "webpack --progress --colors --watch",
"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": "",
"license": "ISC",
@ -22,6 +24,7 @@
"babel-loader": "^8.0.6",
"terser-webpack-plugin": "^3.0.6",
"ts-loader": "^7.0.5",
"typedoc": "^0.17.8",
"typescript": "^3.9.5",
"uuid": "^8.1.0",
"webpack": "^4.43.0",

View File

@ -9,9 +9,11 @@ import SettingsTitle from "./general/SettingsTitle"
import Tabs, { Tab } from "./general/Tabs"
import SettingSubTitle from "./general/SettingSubTitle"
import CodeBlock from "./general/CodeBlock"
import cloneNullProto from "../modules/cloneNullProto"
import Tooltip from "./general/Tooltip"
export default {
inputs: {
export default cloneNullProto({
inputs: cloneNullProto({
Button: DiscordButton,
Switch: Switch,
Choices: RadioGroup,
@ -19,12 +21,13 @@ export default {
TextArea: TextArea,
TextInput: TextInput,
Dropdown: Dropdown
},
general: {
}),
general: cloneNullProto({
Title: Title,
SettingsTitle: SettingsTitle,
SettingSubTitle: SettingSubTitle,
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 Title from "./Title"
export default class Tabs extends React.Component<{
type TabsProps = {
children?: ReactNode,
tabs: {label: string, id: string}[],
active?: string
onChange?: (tab: string) => void
}, {
onChange?: (tab: string) => void,
style?: CSSProperties
}
export default class Tabs extends React.Component<TabsProps, {
active: string
}> {
static defaultProps = {
static defaultProps:TabsProps = {
children: null,
tabs: {label: "No tabs was passed to <Tabs>.", id: "none"},
tabs: [{label: "No tabs was passed to <Tabs>.", id: "none"}],
active: null,
onChange: NOOP
onChange: NOOP,
style: {}
}
constructor(props){
constructor(props:TabsProps){
super(props)
this.state = {
active: this.props.active || null
@ -41,7 +44,7 @@ export default class Tabs extends React.Component<{
}
render(){
return (<div className="lc-tabWrapper">
return (<div className="lc-tabWrapper" style={this.props.style}>
<div className="lc-tabnav" style={{flex: "0 1 auto"}}>
{this.tabs.map(tab => {
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 { ReactNode } from "react"
import uuid from "../../modules/uuid"
import Utils from "../../modules/Utils"
type TitleProps = {
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,
look?: ButtonLook,
size?: ButtonSize,
hoverColor?: ButtonHovers
hoverColor?: ButtonHovers,
disabled?: boolean
}
export default class Button extends React.Component<ButtonProps, {hover: boolean}> {
constructor(props:ButtonProps){
@ -66,6 +67,11 @@ export default class Button extends React.Component<ButtonProps, {hover: boolean
if("hoverColor" in this.props){
props.hoverColor = this.props.hoverColor
}
if("disabled" in this.props){
props.disabled = this.props.disabled
}else{
props.disabled = false
}
}
if(props.color){
@ -124,9 +130,10 @@ export default class Button extends React.Component<ButtonProps, {hover: boolean
}} onMouseLeave={(ev) => {
if(!hoverColor)return
this.setState({hover: false})
}}>
}} disabled={props.disabled}>
<div className={euhModule1.contents}>{props.children}</div>
</button>
if(props.wrapper){
return <div className={buttonModule.buttonWrapper}>
{button}
@ -169,6 +176,7 @@ export default class Button extends React.Component<ButtonProps, {hover: boolean
AllPreviews.push([{children: "Test Button"}])
AllPreviews.push([{onClick: () => {}}])
AllPreviews.push([{wrapper: false}])
AllPreviews.push([{disabled: false}, {disabled: true}])
return AllPreviews
})()
}

View File

@ -1,7 +1,6 @@
import WebpackLoader from "./modules/WebpackLoader"
import Components from "./components/components"
import uuid from "./modules/uuid"
import PluginUtilities from "./modules/PluginUtilities"
import Utils from "./modules/Utils"
const LightcordApi = {
@ -14,75 +13,7 @@ const LightcordApi = {
declare global {
var React:typeof import("react")
interface Window {
Lightcord: {
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
},
Lightcord: LightcordGlobal,
BDModules: {
modules:any[],
get(filter:(mod:any)=>boolean, modules?:any[]):any[],
@ -90,8 +21,45 @@ declare global {
get(ids: [number|((mod:any)=>boolean)], modules?:any[]):any
}
}
var Lightcord:LightcordGlobal
}
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,
sourceMap: true,
terserOptions: {
mangle: true,
mangle: false,
keep_classnames: true,
keep_fnames: true
}

View File

@ -4,7 +4,7 @@ const terser = require("terser")
const util = require("util")
/** Super noisy if production is on. */
const production = false
const production = true
let fs = require("fs")
@ -23,7 +23,7 @@ async function main(){
await fs.promises.mkdir(__dirname+"/distApp/dist", {"recursive": true})
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 newDir = path.join(__dirname, "./distApp/dist")
@ -34,7 +34,7 @@ async function main(){
for(let file of fs.readdirSync(folder, {withFileTypes: true})){
if(file.isFile()){
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)), "..")
}else{
await fs.promises.copyFile(filepath, filepath.replace(folders.startDir, folders.newDir))
@ -85,6 +85,20 @@ async function main(){
await fs.promises.rmdir(path.join(__dirname, "distApp", "LightcordApi", "src"), {"recursive": true})
await fs.promises.unlink(path.join(__dirname, "distApp", "LightcordApi", "webpack.config.js"))
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", "css"), {recursive: true})

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
347721410082242572 # oafu
695254385432854588 # oafu
625350657829896224 # oafu
652189358048411648 # mir
703675553890435153 # blacklight more like black list :yoj:

View File

@ -68,49 +68,32 @@ async function privateInit(){
if(electron.remote.process.argv.includes("--disable-betterdiscord")){
let formComponents
let margins
let ButtonModules
class LightcordSettings extends React.Component {
render(){
if(!formComponents)formComponents = ModuleLoader.get(e => e.FormSection)[0]
if(!margins)margins = ModuleLoader.get(e => e.marginTop60)[0]
let [
flexModule,
euhModule1,
buttonModule,
colorsModule,
] = this.ButtonModules
let button = require("./Button").default
return React.createElement("div", {}, [
React.createElement(formComponents.FormSection, {
className: "",
tag: "h2",
title: "Lightcord's Settings"
}, [
React.createElement("div", { className: buttonModule.buttonWrapper }, [
React.createElement("button", {
type: "button",
className: `${flexModule.flexChild} ${euhModule1.button} ${euhModule1.lookFilled} ${colorsModule.ButtonColors.YELLOW} ${euhModule1.sizeSmall} ${euhModule1.grow}`,
style: { flex: "0 1 auto" },
onClick: () => {
console.log("Should relaunch")
electron.remote.app.relaunch({
args: electron.remote.process.argv.slice(1).filter(e => e !== "--disable-betterdiscord")
})
electron.remote.app.quit()
}
},
React.createElement("div", { className: euhModule1.contents }, "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]
}, React.createElement(button, {
color: "yellow",
look: "ghost",
size: "medium",
hoverColor: "red",
onClick: () => {
console.log("Should relaunch")
electron.remote.app.relaunch({
args: electron.remote.process.argv.slice(1).filter(e => e !== "--disable-betterdiscord")
})
electron.remote.app.quit()
},
wrapper: true
}, "Relaunch with BetterDiscord"))
])
}
}
@ -132,7 +115,6 @@ async function privateInit(){
let getPredicateSections = settingModule.default.prototype.getPredicateSections
settingModule.default.prototype.getPredicateSections = function(){
let result = getPredicateSections.call(this, ...arguments)
console.log(result)
if(result[1].section === "My Account"){ // user settings, not guild settings
let poped = []
@ -261,25 +243,33 @@ async function privateInit(){
}
const appSettings = electron.remote.getGlobal("appSettings")
let Authorization = appSettings.get("LIGHTCORD_AUTH", false)
/*let Authorization = appSettings.get("LIGHTCORD_AUTH", false)
let shouldShowPrompt = Authorization === false
if(typeof Authorization !== "string"){
Authorization = null
appSettings.set("LIGHTCORD_AUTH", null)
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 = {
DiscordModules: {
window.Lightcord = cloneNullProto({
DiscordModules: cloneNullProto({
dispatcher,
constants
},
Settings: {
}),
Settings: cloneNullProto({
devMode: false,
callRingingBeat: true
},
Api: {
}),
Api: cloneNullProto({/*
get Authorization(){
return Authorization
},
@ -287,19 +277,21 @@ async function privateInit(){
if(typeof data !== "string" && data !== null)return Authorization
appSettings.set("LIGHTCORD_AUTH", Authorization = data)
appSettings.save()
},
ensureExported
},
BetterDiscord: { // Global BetterDiscord's exported modules / only for exporting to Lightcord's main script, not for using in plugins
},*/
Authorization: null,
ensureExported,
cloneNullProto
}),
BetterDiscord: cloneNullProto({ // Global BetterDiscord's exported modules
}
}
})
})
dispatcher.subscribe("USER_SETTINGS_UPDATE", (data) => {
DiscordNative.ipc.send("UPDATE_THEME", data.settings.theme)
})
require("../../../../../LightcordApi/js/main")
require("../../../../../LightcordApi/js/main.js")
/*
if(shouldShowPrompt){
@ -377,10 +369,6 @@ async function privateInit(){
const Utils = window.Lightcord.BetterDiscord.Utils
const DOMTools = window.Lightcord.BetterDiscord.DOM
// delete
delete window.Lightcord.BetterDiscord.Utils
delete window.Lightcord.BetterDiscord.DOM
let isBot = false
;(async function(){
const gatewayModule = await ensureExported(e => e.default && e.default.prototype && e.default.prototype._handleDispatch)
@ -478,6 +466,9 @@ async function privateInit(){
}
return returnValue
}
dispatcher.subscribe("LOGOUT", () => {
isBot = false
})
function cancelGatewayPrototype(methodName){
if(gatewayModule.default.prototype[methodName]){
const original = gatewayModule.default.prototype[methodName]
@ -493,12 +484,18 @@ async function privateInit(){
cancelGatewayPrototype("lobbyConnect")
cancelGatewayPrototype("lobbyDisconnect")
cancelGatewayPrototype("lobbyVoiceStatesUpdate")
cancelGatewayPrototype("guildStreamCreate")
cancelGatewayPrototype("streamCreate")
cancelGatewayPrototype("streamWatch")
cancelGatewayPrototype("streamPing")
cancelGatewayPrototype("streamDelete")
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)
hasUnreadModules.forEach((mod) => {
const hasUnread = mod.default.hasUnread
@ -1068,7 +1065,22 @@ async function privateInit(){
}else{
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 = {}
@ -1169,7 +1181,7 @@ async function privateInit(){
] = [
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;
}`)
@ -1177,6 +1189,36 @@ async function privateInit(){
BetterDiscord.init()
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) => {
@ -1196,6 +1238,7 @@ require.extensions[".css"] = (m, filename) => {
let zlib = require("zlib")
let tmp = require("tmp")
const { remote } = require("electron")
require.extensions[".jsbr"] = (m, filename) => {
if(!zlib)zlib = require("zlib")

View File

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

View File

@ -110,7 +110,7 @@ function startup(bootstrapModules) {
console.log("Checking if version "+version+" is outdated...")
bootstrapModules.splashScreen.initSplash()
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: {
"User-Agent": "Lightcord-Updater/1.0"
}
@ -150,7 +150,7 @@ function setMainWindowVisible(visible) {
function updateApp(version){
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({
status: "downloading-updates",

View File

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

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