Adjusts some more UI elements

This commit is contained in:
Zack Rauen 2020-11-07 01:03:29 -05:00
parent 5dc472c645
commit 618b577c75
15 changed files with 186 additions and 36 deletions

View File

@ -195,6 +195,7 @@ export default {
},
Addons: {
title: "{{name}} v{{version}} by {{author}}",
byline: "by {{author}}",
openFolder: "Open {{type}} Folder",
reload: "Reload",
addonSettings: "Settings",

View File

@ -149,4 +149,6 @@ export default new class ComponentPatcher {
});
}
};
};
// 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

View File

@ -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();
}

View File

@ -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),

View File

@ -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();

View File

@ -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 {

View File

@ -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;
}

50
src/ui/draganddrop.js Normal file
View File

@ -0,0 +1,50 @@
/*
<div class="bd-drop-container-wrap">
<div class="bd-drop-container">
<div class="bd-drop-icon"></div>
<div class="bd-drop-title">Install Addon</div>
<div class="bd-drop-message">Installs this plugin automatically</div>
</div>
</div>
*/
/*
.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;
}
*/

View File

@ -0,0 +1,11 @@
import {React} from "modules";
export default class Extension extends React.Component {
render() {
const size = this.props.size || "24px";
return <svg viewBox="0 0 24 24" fill="#FFFFFF" style={{width: size, height: size}} onClick={this.props.onClick} className={this.props.className}>
<path d="M0 0h24v24H0z" fill="none"/>
<path d="M20.5 11H19V7c0-1.1-.9-2-2-2h-4V3.5C13 2.12 11.88 1 10.5 1S8 2.12 8 3.5V5H4c-1.1 0-1.99.9-1.99 2v3.8H3.5c1.49 0 2.7 1.21 2.7 2.7s-1.21 2.7-2.7 2.7H2V20c0 1.1.9 2 2 2h3.8v-1.5c0-1.49 1.21-2.7 2.7-2.7 1.49 0 2.7 1.21 2.7 2.7V22H17c1.1 0 2-.9 2-2v-4h1.5c1.38 0 2.5-1.12 2.5-2.5S21.88 11 20.5 11z"/>
</svg>;
}
}

11
src/ui/icons/theme.jsx Normal file
View File

@ -0,0 +1,11 @@
import {React} from "modules";
export default class Theme extends React.Component {
render() {
const size = this.props.size || "24px";
return <svg viewBox="0 0 24 24" fill="#FFFFFF" style={{width: size, height: size}} onClick={this.props.onClick} className={this.props.className}>
<path d="M0 0h24v24H0z" fill="none"/>
<path d="M12 3c-4.97 0-9 4.03-9 9s4.03 9 9 9c.83 0 1.5-.67 1.5-1.5 0-.39-.15-.74-.39-1.01-.23-.26-.38-.61-.38-.99 0-.83.67-1.5 1.5-1.5H16c2.76 0 5-2.24 5-5 0-4.42-4.03-8-9-8zm-5.5 9c-.83 0-1.5-.67-1.5-1.5S5.67 9 6.5 9 8 9.67 8 10.5 7.33 12 6.5 12zm3-4C8.67 8 8 7.33 8 6.5S8.67 5 9.5 5s1.5.67 1.5 1.5S10.33 8 9.5 8zm5 0c-.83 0-1.5-.67-1.5-1.5S13.67 5 14.5 5s1.5.67 1.5 1.5S15.33 8 14.5 8zm3 4c-.83 0-1.5-.67-1.5-1.5S16.67 9 17.5 9s1.5.67 1.5 1.5-.67 1.5-1.5 1.5z"/>
</svg>;
}
}

View File

@ -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},

View File

@ -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 {
<div className="bd-placeholder-card"></div>
<div className="bd-placeholder-card"></div>
<div className="bd-placeholder-card"></div>
<div className="bd-placeholder-card"></div>
<div className="bd-placeholder-card"></div>
</div>;
}

View File

@ -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();
}

View File

@ -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
? <a className="bd-link bd-link-website" href={author.link || null} onClick={this.messageAuthor} target="_blank" rel="noopener noreferrer">{author.name}</a>
: <span className="bd-author">{author.name}</span>;
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 <div id={`${addon.id}-card`} className="bd-addon-card settings-closed">
<div className="bd-addon-header">
<span className="bd-title">{this.buildTitle(name, version, author)}</span>
{this.props.type === "plugin" ? <ExtIcon size="18px" className="bd-icon" /> : <ThemeIcon size="18px" className="bd-icon" />}
<div className="bd-title">{this.buildTitle(name, version, {name: author, id: this.props.addon.authorId, link: this.props.addon.authorLink})}</div>
<Switch checked={this.props.enabled} onChange={this.onChange} />
</div>
<div className="bd-description-wrap scroller-wrap fade"><div className="bd-description scroller">{SimpleMarkdown.parseToReact(description)}</div></div>

View File

@ -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 <EmptyImage title={Strings.Addons.blankSlateHeader.format({type: this.props.title})} message={message}>
<button className="bd-button" onClick={this.openFolder}>{Strings.Addons.openFolder.format({type: this.props.title})}</button>
const message = Strings.Addons.blankSlateMessage.format({link: `https://betterdiscordlibrary.com/${this.props.type}`, type: this.props.type}).toString();
return <EmptyImage title={Strings.Addons.blankSlateHeader.format({type: this.props.type})} message={message}>
<button className="bd-button" onClick={this.openFolder}>{Strings.Addons.openFolder.format({type: this.props.type})}</button>
</EmptyImage>;
}
@ -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 <ErrorBoundary><AddonCard editAddon={this.editAddon.bind(this, addon.id)} deleteAddon={this.deleteAddon.bind(this, addon.id)} showReloadIcon={showReloadIcon} key={addon.id} enabled={addonState[addon.id]} addon={addon} onChange={onChange} reload={reload} hasSettings={hasSettings} getSettingsPanel={getSettings} /></ErrorBoundary>;
return <ErrorBoundary><AddonCard type={this.props.type} editAddon={this.editAddon.bind(this, addon.id)} deleteAddon={this.deleteAddon.bind(this, addon.id)} showReloadIcon={showReloadIcon} key={addon.id} enabled={addonState[addon.id]} addon={addon} onChange={onChange} reload={reload} hasSettings={hasSettings} getSettingsPanel={getSettings} /></ErrorBoundary>;
});
const hasAddonsInstalled = this.props.addonList.length !== 0;