diff --git a/src/data/strings.js b/src/data/strings.js
index 0f91fa6e..fdf8a351 100644
--- a/src/data/strings.js
+++ b/src/data/strings.js
@@ -195,6 +195,7 @@ export default {
},
Addons: {
title: "{{name}} v{{version}} by {{author}}",
+ byline: "by {{author}}",
openFolder: "Open {{type}} Folder",
reload: "Reload",
addonSettings: "Settings",
diff --git a/src/modules/componentpatcher.js b/src/modules/componentpatcher.js
index e9ed923e..d6c050fc 100644
--- a/src/modules/componentpatcher.js
+++ b/src/modules/componentpatcher.js
@@ -149,4 +149,6 @@ export default new class ComponentPatcher {
});
}
-};
\ No newline at end of file
+};
+
+// as part of utility classes, i would like a way to distinguish channel types from the .content-3at_AU element. other than that, can't think of anything
\ No newline at end of file
diff --git a/src/modules/pluginmanager.js b/src/modules/pluginmanager.js
index fad1991f..7638cb7f 100644
--- a/src/modules/pluginmanager.js
+++ b/src/modules/pluginmanager.js
@@ -35,6 +35,7 @@ export default new class PluginManager extends AddonManager {
const errors = super.initialize();
this.setupFunctions();
Settings.registerPanel("plugins", Strings.Panels.plugins, {element: () => SettingsRenderer.getAddonPanel(Strings.Panels.plugins, this.addonList, this.state, {
+ type: this.prefix,
folder: this.addonFolder,
onChange: this.togglePlugin.bind(this),
reload: this.reloadPlugin.bind(this),
@@ -76,10 +77,10 @@ export default new class PluginManager extends AddonManager {
const PluginClass = addon.exports;
const thePlugin = new PluginClass();
addon.instance = thePlugin;
- addon.name = thePlugin.getName() || addon.name;
- addon.author = thePlugin.getAuthor() || addon.author || "No author";
- addon.description = thePlugin.getDescription() || addon.description || "No description";
- addon.version = thePlugin.getVersion() || addon.version || "No version";
+ addon.name = thePlugin.getName ? thePlugin.getName() : addon.name || "No name";
+ addon.author = thePlugin.getAuthor ? thePlugin.getAuthor() : addon.author || "No author";
+ addon.description = thePlugin.getDescription ? thePlugin.getDescription() : addon.description || "No description";
+ addon.version = thePlugin.getVersion ? thePlugin.getVersion() : addon.version || "No version";
try {
if (typeof(addon.instance.load) == "function") addon.instance.load();
}
diff --git a/src/modules/thememanager.js b/src/modules/thememanager.js
index 4c393e7f..0a1c36b7 100644
--- a/src/modules/thememanager.js
+++ b/src/modules/thememanager.js
@@ -22,6 +22,7 @@ export default new class ThemeManager extends AddonManager {
initialize() {
const errors = super.initialize();
Settings.registerPanel("themes", Strings.Panels.themes, {element: () => SettingsRenderer.getAddonPanel(Strings.Panels.themes, this.addonList, this.state, {
+ type: this.prefix,
folder: this.addonFolder,
onChange: this.toggleTheme.bind(this),
reload: this.reloadTheme.bind(this),
diff --git a/src/structs/psconnection.js b/src/structs/psconnection.js
index c8bf5a3d..74227fe7 100644
--- a/src/structs/psconnection.js
+++ b/src/structs/psconnection.js
@@ -54,7 +54,7 @@ export default new class PublicServersConnection {
if (term) queries.push(`term=${term.replace(/ /g, "%20")}`);
if (from) queries.push(`from=${from}`);
const query = `?${queries.join("&")}`;
-
+
try {
const response = await fetch(`${this.endPoint}${query}`, {method: "GET"});
const data = await response.json();
diff --git a/src/styles/builtins/publicservers.css b/src/styles/builtins/publicservers.css
index 7d15d7a6..6010e95f 100644
--- a/src/styles/builtins/publicservers.css
+++ b/src/styles/builtins/publicservers.css
@@ -256,7 +256,12 @@
.bd-pagination button:hover,
.bd-pagination button:active {
opacity: 1;
- background: transparent;
+ background: var(--background-accent);
+}
+
+.bd-pagination button:active {
+ opacity: 1;
+ background: var(--background-secondary);
}
.bd-pagination button svg {
diff --git a/src/styles/ui/addonlist.css b/src/styles/ui/addonlist.css
index 76e48b7d..4895a5e4 100644
--- a/src/styles/ui/addonlist.css
+++ b/src/styles/ui/addonlist.css
@@ -36,11 +36,9 @@
display: flex;
flex-direction: column;
margin-bottom: 20px;
- padding: 16px;
border-radius: 5px;
overflow: hidden;
- background: var(--background-secondary-alt);
- border: 1px solid var(--background-tertiary);
+ background: var(--background-secondary);
}
.bd-addon-list.bd-grid-view .bd-addon-card {
@@ -49,6 +47,8 @@
.bd-addon-list .bd-addon-header {
color: var(--header-primary);
+ background: var(--background-secondary-alt);
+ padding: 16px;
font-size: 14px;
line-height: 20px;
font-weight: 600;
@@ -58,8 +58,42 @@
overflow: hidden;
}
+.bd-addon-header .bd-icon {
+ margin-right: 8px;
+}
+
+.bd-title,
+.bd-name,
+.bd-meta {
+ display: inline;
+}
+
+.bd-title {
+ flex: 1;
+}
+
+.bd-meta {
+ color: var(--text-muted);
+}
+
+.bd-name::after,
+.bd-version::after {
+ display: inline;
+ content: " ";
+}
+
+.bd-grid-view .bd-title {
+ display: flex;
+ flex-direction: column;
+}
+
+.bd-grid-view .bd-meta {
+ font-size: 12px;
+}
+
.bd-description-wrap {
flex: 1;
+ padding: 8px 16px 0 16px;
}
.bd-addon-list .bd-description {
@@ -88,8 +122,7 @@
display: flex;
align-items: center;
justify-content: space-between;
- padding-top: 8px;
- border-top: thin solid var(--background-modifier-accent);
+ padding: 8px 16px 16px 16px;
overflow: hidden;
}
diff --git a/src/ui/draganddrop.js b/src/ui/draganddrop.js
new file mode 100644
index 00000000..40097064
--- /dev/null
+++ b/src/ui/draganddrop.js
@@ -0,0 +1,50 @@
+/*
+
+
+
+
Install Addon
+
Installs this plugin automatically
+
+
+*/
+
+/*
+.bd-drop-container-wrap {
+ display: none;
+ justify-content: center;
+ align-items: center;
+ background: rgba(0,0,0,0.7);
+ z-index: 1000;
+ width: 100%;
+}
+
+.bd-drop-container {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ background: #3e82e5;
+ padding: 20px;
+ border-radius: 20px;
+}
+
+.bd-drop-icon {
+ background: url('https://maxcdn.icons8.com/Share/icon/p1em/Very_Basic/plus1600.png');
+ background-size: contain;
+ height: 100px;
+ width: 100px;
+ filter: invert();
+}
+
+.bd-drop-title {
+ color: white;
+ font-weight: 600;
+ font-size: 24px;
+ margin-top: 8px
+}
+
+.bd-drop-message {
+ color: white;
+ margin-top: 8px;
+}
+*/
\ No newline at end of file
diff --git a/src/ui/icons/extension.jsx b/src/ui/icons/extension.jsx
new file mode 100644
index 00000000..0f396de0
--- /dev/null
+++ b/src/ui/icons/extension.jsx
@@ -0,0 +1,11 @@
+import {React} from "modules";
+
+export default class Extension extends React.Component {
+ render() {
+ const size = this.props.size || "24px";
+ return ;
+ }
+}
\ No newline at end of file
diff --git a/src/ui/icons/theme.jsx b/src/ui/icons/theme.jsx
new file mode 100644
index 00000000..f2e9906a
--- /dev/null
+++ b/src/ui/icons/theme.jsx
@@ -0,0 +1,11 @@
+import {React} from "modules";
+
+export default class Theme extends React.Component {
+ render() {
+ const size = this.props.size || "24px";
+ return ;
+ }
+}
\ No newline at end of file
diff --git a/src/ui/modals.js b/src/ui/modals.js
index 56e7b337..23ac42b8 100644
--- a/src/ui/modals.js
+++ b/src/ui/modals.js
@@ -267,7 +267,7 @@ export default class Modals {
const mc = this.ModalComponents;
const modal = props => {
- return React.createElement(mc.ModalRoot, Object.assign({size: mc.ModalSize.SMALL, className: "bd-addon-modal"}, props),
+ return React.createElement(mc.ModalRoot, Object.assign({size: mc.ModalSize.MEDIUM, className: "bd-addon-modal"}, props),
React.createElement(mc.ModalHeader, {separator: false, className: "bd-addon-modal-header"},
React.createElement(this.FormTitle, {tag: "h4"}, `${name} Settings`),
React.createElement(this.FlexElements.Child, {grow: 0},
diff --git a/src/ui/publicservers/menu.js b/src/ui/publicservers/menu.js
index ba971c37..fa9add0d 100644
--- a/src/ui/publicservers/menu.js
+++ b/src/ui/publicservers/menu.js
@@ -16,8 +16,8 @@ const EMPTY_RESULTS = {
servers: [],
size: 0,
total: 0,
- page: 0,
- numPages: 0
+ page: 1,
+ numPages: 1
};
export default class PublicServers extends React.Component {
@@ -166,8 +166,7 @@ export default class PublicServers extends React.Component {
return [React.createElement(SettingsTitle, {text: this.title, button: connectButton}),
this.state.results.numPages > 1 && this.pagination,
content,
- this.state.results.numPages > 1 && this.pagination,
- this.state.results.numPages > 1 && this.state.query && React.createElement(SettingsTitle, {text: this.title})
+ this.state.results.numPages > 1 && this.pagination
];
}
@@ -179,6 +178,8 @@ export default class PublicServers extends React.Component {
+
+
;
}
diff --git a/src/ui/settings.js b/src/ui/settings.js
index 082ebcab..6ce98b1d 100644
--- a/src/ui/settings.js
+++ b/src/ui/settings.js
@@ -78,14 +78,20 @@ export default new class SettingsRenderer {
if (collection.disabled) continue;
insert({
section: collection.name,
- label: collection.name,
+ label: collection.name.toString(),
+ className: `bd-${collection.id}-tab`,
element: () => this.buildSettingsPanel(collection.id, collection.name, collection.settings, Settings.state[collection.id], Settings.onSettingChange.bind(Settings, collection.id), collection.button ? collection.button : null)
});
}
for (const panel of Settings.panels.sort((a,b) => a.order > b.order)) {
if (panel.clickListener) panel.onClick = (event) => panel.clickListener(thisObject, event, returnValue);
+ if (!panel.className) panel.className = `bd-${panel.id}-tab`;
+ if (typeof(panel.label) !== "string") panel.label = panel.label.toString();
insert(panel);
}
+ // for (const tab of returnValue) {
+ // if (!tab.className) tab.className = `${DOM.escapeID(tab.section).toLowerCase()}-tab`;
+ // }
});
this.forceUpdate();
}
diff --git a/src/ui/settings/addoncard.jsx b/src/ui/settings/addoncard.jsx
index 2ce49553..1290db6d 100644
--- a/src/ui/settings/addoncard.jsx
+++ b/src/ui/settings/addoncard.jsx
@@ -11,6 +11,8 @@ import MoneyIcon from "../icons/dollarsign";
import WebIcon from "../icons/globe";
import PatreonIcon from "../icons/patreon";
import SupportIcon from "../icons/support";
+import ExtIcon from "../icons/extension";
+import ThemeIcon from "../icons/theme";
import Modals from "../modals";
import Toasts from "../toasts";
@@ -23,6 +25,11 @@ const LinkIcons = {
};
const Tooltip = WebpackModules.getByDisplayName("Tooltip");
+const LayerStack = WebpackModules.getByProps("popLayer");
+const UserStore = WebpackModules.getByProps("getCurrentUser");
+const ChannelStore = WebpackModules.getByProps("getDMFromUserId");
+const PrivateChannelActions = WebpackModules.getByProps("openPrivateChannel");
+const ChannelActions = WebpackModules.getByProps("selectPrivateChannel");
export default class AddonCard extends React.Component {
@@ -38,6 +45,7 @@ export default class AddonCard extends React.Component {
this.onChange = this.onChange.bind(this);
this.reload = this.reload.bind(this);
this.showSettings = this.showSettings.bind(this);
+ this.messageAuthor = this.messageAuthor.bind(this);
}
showSettings() {
@@ -66,15 +74,34 @@ export default class AddonCard extends React.Component {
this.forceUpdate();
}
+ messageAuthor() {
+ if (!this.props.addon.authorId) return;
+ if (LayerStack) LayerStack.popLayer();
+ if (!UserStore || !ChannelActions || !ChannelStore || !PrivateChannelActions) return;
+ const selfId = UserStore.getCurrentUser().id;
+ if (selfId == this.props.addon.authorId) return;
+ const privateChannelId = ChannelStore.getDMFromUserId(this.props.addon.authorId);
+ if (privateChannelId) return ChannelActions.selectPrivateChannel(privateChannelId);
+ PrivateChannelActions.openPrivateChannel(selfId, this.props.addon.authorId);
+ }
+
buildTitle(name, version, author) {
- const title = Strings.Addons.title.split(/({{[A-Za-z]+}})/);
- const nameIndex = title.findIndex(s => s == "{{name}}");
- if (nameIndex) title[nameIndex] = React.createElement("span", {className: "bd-name"}, name);
- const versionIndex = title.findIndex(s => s == "{{version}}");
- if (nameIndex) title[versionIndex] = React.createElement("span", {className: "bd-version"}, version);
- const authorIndex = title.findIndex(s => s == "{{author}}");
- if (nameIndex) title[authorIndex] = React.createElement("span", {className: "bd-author"}, author);
- return title.flat();
+ const authorArray = Strings.Addons.byline.split(/({{[A-Za-z]+}})/);
+ const authorComponent = author.link || author.id
+ ? {author.name}
+ : {author.name};
+
+ const authorIndex = authorArray.findIndex(s => s == "{{author}}");
+ if (authorIndex) authorArray[authorIndex] = authorComponent;
+
+ return [
+ React.createElement("div", {className: "bd-name"}, name),
+ React.createElement("div", {className: "bd-meta"},
+ React.createElement("span", {className: "bd-version"}, `v${version}`),
+ ...authorArray
+ )
+ ];
+
}
buildLink(which) {
@@ -139,7 +166,8 @@ export default class AddonCard extends React.Component {
return
-
{this.buildTitle(name, version, author)}
+ {this.props.type === "plugin" ?
:
}
+
{this.buildTitle(name, version, {name: author, id: this.props.addon.authorId, link: this.props.addon.authorLink})}
{SimpleMarkdown.parseToReact(description)}
diff --git a/src/ui/settings/addonlist.jsx b/src/ui/settings/addonlist.jsx
index 1df6bed1..b9836f71 100644
--- a/src/ui/settings/addonlist.jsx
+++ b/src/ui/settings/addonlist.jsx
@@ -41,16 +41,16 @@ export default class AddonList extends React.Component {
onControlChange(control, value) {
const addonlistControls = DataStore.getBDData("addonlistControls") || {};
- if (!addonlistControls[this.props.title.toLowerCase()]) addonlistControls[this.props.title.toLowerCase()] = {};
- addonlistControls[this.props.title.toLowerCase()][control] = value;
+ if (!addonlistControls[this.props.type]) addonlistControls[this.props.type] = {};
+ addonlistControls[this.props.type][control] = value;
DataStore.setBDData("addonlistControls", addonlistControls);
}
getControlState(control, defaultValue) {
const addonlistControls = DataStore.getBDData("addonlistControls") || {};
- if (!addonlistControls[this.props.title.toLowerCase()]) return defaultValue;
- if (!addonlistControls[this.props.title.toLowerCase()].hasOwnProperty(control)) return defaultValue;
- return addonlistControls[this.props.title.toLowerCase()][control];
+ if (!addonlistControls[this.props.type]) return defaultValue;
+ if (!addonlistControls[this.props.type].hasOwnProperty(control)) return defaultValue;
+ return addonlistControls[this.props.type][control];
}
update() {
@@ -107,9 +107,9 @@ export default class AddonList extends React.Component {
}
get emptyImage() {
- const message = Strings.Addons.blankSlateMessage.format({link: `https://betterdiscordlibrary.com/${this.props.title.toLowerCase()}`, type: this.props.title}).toString();
- return
-
+ const message = Strings.Addons.blankSlateMessage.format({link: `https://betterdiscordlibrary.com/${this.props.type}`, type: this.props.type}).toString();
+ return
+
;
}
@@ -147,7 +147,7 @@ export default class AddonList extends React.Component {
const renderedCards = sortedAddons.map(addon => {
const hasSettings = addon.instance && typeof(addon.instance.getSettingsPanel) === "function";
const getSettings = hasSettings && addon.instance.getSettingsPanel.bind(addon.instance);
- return ;
+ return ;
});
const hasAddonsInstalled = this.props.addonList.length !== 0;