Remove public servers (#1577)

This commit is contained in:
Zerebos 2023-03-22 14:59:39 -04:00 committed by GitHub
parent 2aa71d87d9
commit cec522189f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 0 additions and 906 deletions

View File

@ -2,7 +2,6 @@
export {default as CustomCSS} from "./customcss";
export {default as PublicServers} from "./general/publicservers";
export {default as VoiceDisconnect} from "./general/voicedisconnect";
export {default as MediaKeys} from "./general/mediakeys";

View File

@ -1,138 +0,0 @@
import Builtin from "../../structs/builtin";
import {DiscordModules, WebpackModules, Strings, DOMManager, React, ReactDOM} from "modules";
import PublicServersMenu from "../../ui/publicservers/menu";
import Globe from "../../ui/icons/globe";
const LayerManager = {
pushLayer(component) {
DiscordModules.Dispatcher.dispatch({
type: "LAYER_PUSH",
component
});
},
popLayer() {
DiscordModules.Dispatcher.dispatch({
type: "LAYER_POP"
});
},
popAllLayers() {
DiscordModules.Dispatcher.dispatch({
type: "LAYER_POP_ALL"
});
}
};
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = {hasError: false};
}
componentDidCatch() {
this.setState({hasError: true});
}
render() {
if (this.state.hasError) return null;
return this.props.children;
}
}
export default new class PublicServers extends Builtin {
get name() {return "PublicServers";}
get category() {return "general";}
get id() {return "publicServers";}
enabled() {
const PrivateChannelList = WebpackModules.getModule(m => m?.toString().includes("privateChannelIds"), {defaultExport: false});
if (!PrivateChannelList || !PrivateChannelList.Z) return this.warn("Could not find PrivateChannelList", PrivateChannelList);
const PrivateChannelButton = WebpackModules.getModule(m => m?.prototype?.render?.toString().includes("linkButton"), {searchExports: true});
if (!PrivateChannelButton) return this.warn("Could not find PrivateChannelButton", PrivateChannelButton);
this.after(PrivateChannelList, "Z", (_, __, returnValue) => {
const destination = returnValue?.props?.children?.props?.children;
if (!destination || !Array.isArray(destination)) return;
if (destination.find(b => b?.props?.children?.props?.id === "public-servers-button")) return; // If it exists, don't try to add again
destination.push(
React.createElement(ErrorBoundary, null,
React.createElement(PrivateChannelButton,
{
id: "public-servers-button",
onClick: () => this.openPublicServers(),
text: Strings.PublicServers.button,
icon: () => React.createElement(Globe, {color: "currentColor"})
}
)
)
);
});
/**
* On being first enabled, we have no way of forceUpdating the list,
* so clone and modify an existing button and add it to the end
* of the button list.
*/
const header = document.querySelector(`[class*="privateChannelsHeaderContainer-"]`);
if (!header) return; // No known element
const oldButton = header.previousElementSibling;
if (!oldButton.className.includes("channel-")) return; // Not what we expected to be there
// Clone existing button and set click handler
const newButton = oldButton.cloneNode(true);
newButton.addEventListener("click", (event) => {
event.stopImmediatePropagation();
event.stopPropagation();
event.preventDefault();
this.openPublicServers();
});
// Remove existing route and id
const aSlot = newButton.querySelector("a");
aSlot.href = "";
aSlot.dataset.listItemId = "public-servers";
// Remove any badges
const premiumBadge = newButton.querySelector(`[class*="premiumTrial"]`);
premiumBadge?.remove?.();
const numberBadge = newButton.querySelector(`[class*="numberBadge-"]`);
numberBadge?.remove?.();
// Render our icon in the avatar slot
const avatarSlot = newButton.querySelector(`[class*="avatar-"]`);
avatarSlot.replaceChildren();
ReactDOM.render(React.createElement(Globe, {color: "currentColor"}), avatarSlot);
DOMManager.onRemoved(avatarSlot, () => ReactDOM.unmountComponentAtNode(avatarSlot));
// Replace the existing name
const nameSlot = newButton.querySelector(`[class*="name-"]`);
nameSlot.textContent = Strings.PublicServers.button;
// Insert before the header, end of the list
header.parentNode.insertBefore(newButton, header);
this.button = newButton;
}
disabled() {
this.unpatchAll();
this.button?.remove?.();
document.querySelector("#public-servers-button")?.parentElement?.parentElement?.remove?.();
}
async _appendButton() {
await new Promise(r => setTimeout(r, 1000));
const existing = document.querySelector("#bd-pub-li");
if (existing) return;
const guilds = document.querySelector(`.${DiscordModules.GuildClasses.guilds} .${DiscordModules.GuildClasses.listItem}`);
if (!guilds) return;
guilds.parentNode.insertBefore(this.button, guilds.nextSibling);
}
openPublicServers() {
LayerManager.pushLayer(() => DiscordModules.React.createElement(PublicServersMenu, {close: LayerManager.popLayer}));
}
};

View File

@ -4,7 +4,6 @@ export default [
id: "general",
collapsible: true,
settings: [
{type: "switch", id: "publicServers", value: true},
{type: "switch", id: "voiceDisconnect", value: false},
{type: "switch", id: "showToasts", value: true},
{type: "switch", id: "mediaKeys", value: false}

View File

@ -1,166 +0,0 @@
import Logger from "common/logger";
import {WebpackModules, IPC} from "modules";
const SortedGuildStore = WebpackModules.getByProps("getSortedGuilds");
const AvatarDefaults = WebpackModules.getByProps("DEFAULT_AVATARS");
const InviteActions = WebpackModules.getByProps("acceptInvite");
// const BrowserWindow = require("electron").remote.BrowserWindow;
const betterDiscordServer = {
name: "BetterDiscord",
members: 110000,
categories: ["community", "programming", "support"],
description: "Official BetterDiscord server for plugins, themes, support, etc",
identifier: "86004744966914048",
iconUrl: "https://cdn.discordapp.com/icons/86004744966914048/babd1af3fa6011a50e418a80f4970ceb.webp",
nativejoin: true,
invite_code: "BJD2yvJ",
pinned: true,
insertDate: 1517806800
};
const ITEMS_PER_PAGE = 50;
export default new class PublicServersConnection {
constructor() {
this.cache = new Map();
this.cache.set("featured", [betterDiscordServer]);
this.cache.set("popular", []);
this.cache.set("keywords", []);
this.cache.set("accessToken", "");
}
get endPoint() {return "https://search.discordservers.com";}
get joinEndPoint() {return "https://j.discordservers.com";}
get connectEndPoint() {return "https://auth.discordservers.com/info";}
get authorizeEndPoint() {return `https://auth.discordservers.com/connect?scopes=guilds.join&previousUrl=${this.connectEndPoint}`;}
getDefaultAvatar() {
return AvatarDefaults.DEFAULT_AVATARS[Math.floor(Math.random() * 5)];
}
hasJoined(id) {
return SortedGuildStore.getFlattenedGuildIds().includes(id);
}
async search({term = "", keyword = "", page = 1} = {}) {
if (this.cache.has(term + keyword + page)) return this.cache.get(term + keyword + page);
const from = (page - 1) * ITEMS_PER_PAGE;
const queries = [];
if (keyword) queries.push(`keyword=${keyword.replace(/ /g, "%20").toLowerCase()}`);
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();
const results = {
servers: data.results,
size: data.size,
total: data.total,
page: Math.ceil(from / ITEMS_PER_PAGE) + 1,
numPages: Math.ceil(data.total / ITEMS_PER_PAGE)
};
this.cache.set(term + keyword + page, results);
return results;
}
catch (error) {
Logger.stacktrace("PublicServers", "Could not reach search endpoint.", error);
}
}
async getDashboard() {
const cachedKeywords = this.cache.get("keywords");
if (cachedKeywords && cachedKeywords.length) return {featured: this.cache.get("featured"), popular: this.cache.get("popular"), keywords: cachedKeywords};
try {
const response = await fetch(`${this.endPoint}/dashboard`, {method: "GET"});
const data = await response.json();
const featuredFirst = data.results[0].key === "featured";
const featuredServers = data.results[featuredFirst ? 0 : 1].response.hits;
const popularServers = data.results[featuredFirst ? 1 : 0].response.hits;
const mainKeywords = data.mainKeywords.map(k => k.charAt(0).toUpperCase() + k.slice(1)).sort();
featuredServers.unshift(betterDiscordServer);
this.cache.set("featured", featuredServers);
this.cache.set("popular", popularServers);
this.cache.set("keywords", mainKeywords);
return {featured: this.cache.get("featured"), popular: this.cache.get("popular"), keywords: this.cache.get("keywords")};
}
catch (error) {
Logger.stacktrace("PublicServers", "Could not download dashboard.", error);
return {featured: this.cache.get("featured"), popular: this.cache.get("popular"), keywords: this.cache.get("keywords")};
}
}
async join(id, native = false) {
if (native) return InviteActions.acceptInvite({inviteKey: id});
try {
await fetch(`${this.joinEndPoint}/${id}`,{
method: "GET",
credentials: "include",
mode: "cors",
headers: {
"Accept": "application/json",
"Content-Type": "application/json"
}
});
return true;
}
catch (error) {
Logger.warn("PublicServers", "Could not join server.");
return false;
}
}
async checkConnection() {
try {
const response = await fetch(this.connectEndPoint, {
method: "GET",
credentials: "include",
mode: "cors",
headers: {
"Accept": "application/json",
"Content-Type": "application/json"
}
});
const data = await response.json();
this._accessToken = data.access_token;
return data;
}
catch (error) {
Logger.warn("PublicServers", "Could not verify connection.");
return false;
}
}
async connect() {
await IPC.openWindow(this.authorizeEndPoint, {
windowOptions: this.windowOptions,
closeOnUrl: this.connectEndPoint
});
}
get windowOptions() {
return {
width: 520,
height: 580,
backgroundColor: "#282b30",
show: true,
resizable: true,
maximizable: false,
minimizable: false,
alwaysOnTop: true,
frame: false,
center: true,
webPreferences: {
nodeIntegration: false
}
};
}
};

View File

@ -1,287 +0,0 @@
@keyframes bd-placeholder-card-pulse {
0% {
opacity: 0.6;
}
50% {
opacity: 0.8;
}
to {
opacity: 0.6;
}
}
#bd-pub-li {
height: 24px;
overflow: hidden;
}
#bd-pub-button {
border-radius: 4px;
background-color: var(--background-primary);
color: var(--text-normal);
text-align: center;
font-size: 12px;
line-height: 24px;
height: 24px;
transition: background-color 0.15s ease-out, color 0.15s ease-out;
}
#bd-pub-button:hover {
color: #FFFFFF;
background-color: #3E82E5;
}
#bd-connection {
margin-left: 10px;
}
.bd-footnote {
color: #B9BBBE;
font-size: 11px;
}
.bd-button-next,
.bd-button-reconnect {
margin: 5px 10px 10px 0;
width: 100%;
min-height: 20px;
}
/* Rewrite */
.bd-server-search {
margin-bottom: 5px;
}
.bd-card-list {
display: grid;
grid-gap: 16px;
grid-template-columns: repeat(auto-fill, minmax(248px, 1fr));
}
.bd-server-card {
display: flex;
flex-direction: column;
height: 320px;
width: 100%;
overflow: hidden;
border-radius: 8px;
position: relative;
transition: box-shadow 0.2s ease-out, transform 0.2s ease-out, background 0.2s ease-out, opacity 0.2s ease-in;
cursor: pointer;
background-color: var(--activity-card-background);
}
.theme-light .bd-server-card {
box-shadow: 0 0 0 1px rgba(185, 187, 190, 0.3), var(--elevation-medium);
}
.theme-dark .bd-server-card {
background-color: var(--background-secondary-alt);
}
.bd-server-card:hover,
.bd-server-card:focus,
.theme-light .bd-server-card:hover,
.theme-light .bd-server-card:focus {
transform: translateY(-1px);
box-shadow: var(--elevation-high);
}
.theme-dark .bd-server-card:hover,
.theme-dark .bd-server-card:focus {
background-color: var(--background-tertiary);
}
.bd-placeholder-card {
background-color: var(--background-secondary-alt);
animation: bd-placeholder-card-pulse 1.8s ease-in-out infinite;
height: 320px;
width: 100%;
overflow: hidden;
border-radius: 8px;
position: relative;
}
.bd-server-header {
height: 143px;
position: relative;
display: block;
overflow: visible;
margin-bottom: 32px;
}
.bd-server-splash-container {
width: 100%;
height: 100%;
display: block;
position: absolute;
top: 0;
left: 0;
transition: opacity 0.2s, transform 0.2s ease-out;
transform: scale(1);
overflow: hidden;
}
.bd-server-card:hover .bd-server-splash-container {
-webkit-transform: scale(1.01) translateZ(0);
transform: scale(1.01) translateZ(0);
}
.bd-server-splash {
object-fit: cover;
width: 100%;
height: 100%;
filter: blur(20px);
}
.bd-server-icon {
position: absolute;
bottom: -21px;
left: 12px;
width: 40px;
background: var(--background-secondary-alt);
border: 4px solid var(--background-secondary-alt);
border-radius: 25%;
transition: background 0.2s ease-out, transform 0.2s ease-out, border-color 0.2s ease-out;
}
.bd-server-card:hover .bd-server-icon {
border-color: var(--background-tertiary);
background: var(--background-tertiary);
}
.bd-server-info {
display: flex;
flex: 1 1 auto;
position: relative;
flex-direction: column;
align-content: stretch;
padding: 0 16px 16px;
overflow: hidden;
}
.bd-server-title {
display: flex;
align-items: center;
width: 100%;
font-weight: 600;
}
.bd-server-name {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
color: var(--header-primary);
font-size: 16px;
line-height: 20px;
}
.bd-server-description {
flex: 1 1 auto;
overflow: hidden;
margin: 4px 0 16px;
display: -webkit-box;
-webkit-line-clamp: 4;
-webkit-box-orient: vertical;
color: var(--header-secondary);
font-size: 14px;
line-height: normal;
}
.bd-server-footer {
display: flex;
align-items: center;
}
.bd-server-count {
display: flex;
align-items: center;
font-size: 0.75rem;
line-height: 1rem;
margin-right: 16px;
}
.bd-server-count-dot {
background-color: #43B581;
border-radius: 50%;
width: 8px;
height: 8px;
margin-right: 4px;
flex-shrink: 0;
}
.bd-server-count + .bd-server-count .bd-server-count-dot {
background-color: #B9BBBE;
}
.bd-server-count-text {
color: var(--header-secondary);
font-size: 12px;
line-height: 16px;
}
.bd-server-tag {
margin-left: 5px;
font-size: 10px;
text-transform: uppercase;
vertical-align: top;
display: inline-flex;
align-items: center;
flex-shrink: 0;
text-indent: 0;
height: 15px;
padding: 0 4px;
margin-top: 1px;
border-radius: 3px;
background: #3E82E5;
color: #FFFFFF;
}
.bd-pagination {
display: flex;
justify-content: space-between;
align-items: center;
margin: 15px;
color: var(--header-primary);
}
.bd-pagination span {
font-weight: 600;
}
.bd-pagination button {
background: none;
opacity: 0.7;
display: flex;
justify-content: center;
align-items: center;
border: 1px solid var(--background-tertiary);
border-radius: 3px;
padding: 0;
}
.bd-pagination button:hover,
.bd-pagination button:active {
opacity: 1;
background: var(--background-accent);
}
.bd-pagination button:active {
opacity: 1;
background: var(--background-secondary);
}
.bd-pagination button svg {
fill: var(--header-primary);
}
.bd-pagination button[disabled] {
opacity: 0.2;
cursor: not-allowed;
}
.bd-pagination + .bd-settings-title {
margin-top: 20px;
}

View File

@ -1,62 +0,0 @@
import {React, Strings} from "modules";
const {useState, useCallback, useMemo} = React;
const badge = <div className="flowerStarContainer-1QeD-L verified-1Jv_7P background-3Da2vZ rowIcon-2tDEcE" style={{width: "16px", height: "16px"}}>
<svg aria-label="Verified &amp; Partnered" className="flowerStar-2tNFCR" aria-hidden="false" width="16" height="16" viewBox="0 0 16 15.2">
<path fill="currentColor" fillRule="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"></path>
</svg>
<div className="childContainer-U_a6Yh">
<svg className="icon-3BYlXK" aria-hidden="false" width="16" height="16" viewBox="0 0 16 15.2">
<path d="M7.4,11.17,4,8.62,5,7.26l2,1.53L10.64,4l1.36,1Z" fill="currentColor"></path>
</svg>
</div>
</div>;
export default function ServerCard({server, joined, join, navigateTo, defaultAvatar}) {
const [isError, setError] = useState(false);
const handleError = useCallback(() => {
setError(true);
}, []);
const [hasJoined, setJoined] = useState(joined);
const doJoin = useCallback(async () => {
if (hasJoined) return navigateTo(server.identifier);
setJoined("joining");
const didJoin = await join(server.identifier, server.nativeJoin);
setJoined(didJoin);
}, [hasJoined, join, navigateTo, server.identifier, server.nativeJoin]);
const defaultIcon = useMemo(() => defaultAvatar(), [defaultAvatar]);
const currentIcon = !server.iconUrl || isError ? defaultIcon : server.iconUrl;
const addedDate = new Date(server.insertDate * 1000); // Convert from unix timestamp
const buttonText = typeof(hasJoined) == "string" ? `${Strings.PublicServers.joining}...` : hasJoined ? Strings.PublicServers.joined : Strings.PublicServers.join;
return <div className="bd-server-card" role="button" tabIndex="0" onClick={doJoin}>
<div className="bd-server-header">
<div className="bd-server-splash-container"><img src={currentIcon} onError={handleError} className="bd-server-splash" /></div>
<img src={currentIcon} onError={handleError} className="bd-server-icon" />
</div>
<div className="bd-server-info">
<div className="bd-server-title">
{server.pinned && badge}
<div className="bd-server-name">{server.name}</div>
{hasJoined && <div className="bd-server-tag">{buttonText}</div>}
</div>
<div className="bd-server-description">{server.description}</div>
<div className="bd-server-footer">
<div className="bd-server-count">
<div className="bd-server-count-dot"></div>
<div className="bd-server-count-text">{server.members.toLocaleString()} Members</div>
</div>
<div className="bd-server-count">
<div className="bd-server-count-dot"></div>
<div className="bd-server-count-text">Added {addedDate.toLocaleDateString()}</div>
</div>
</div>
</div>
</div>;
}

View File

@ -1,251 +0,0 @@
import {React, WebpackModules, Strings, DiscordModules} from "modules";
import Modals from "../modals";
import SettingsTitle from "../settings/title";
import ServerCard from "./card";
import EmptyResults from "../blankslates/noresults";
import Connection from "../../structs/psconnection";
import Search from "../settings/components/search";
import Previous from "../icons/previous";
import Next from "../icons/next";
const SettingsView = WebpackModules.getByPrototypes("renderSidebar");
const GuildActions = WebpackModules.getByProps("transitionToGuildSync");
const LayerManager = {
pushLayer(component) {
DiscordModules.Dispatcher.dispatch({
type: "LAYER_PUSH",
component
});
},
popLayer() {
DiscordModules.Dispatcher.dispatch({
type: "LAYER_POP"
});
},
popAllLayers() {
DiscordModules.Dispatcher.dispatch({
type: "LAYER_POP_ALL"
});
}
};
const EMPTY_RESULTS = {
servers: [],
size: 0,
total: 0,
page: 1,
numPages: 1
};
export default class PublicServers extends React.Component {
constructor(props) {
super(props);
this.state = {
tab: "Featured",
query: "",
loading: true,
user: null,
results: Object.assign({}, EMPTY_RESULTS)
};
this.featured = [];
this.popular = [];
this.keywords = [];
this.changeTab = this.changeTab.bind(this);
this.searchKeyDown = this.searchKeyDown.bind(this);
this.connect = this.connect.bind(this);
this.loadPreviousPage = this.loadPreviousPage.bind(this);
this.loadNextPage = this.loadNextPage.bind(this);
this.join = this.join.bind(this);
this.navigateTo = this.navigateTo.bind(this);
}
componentDidMount() {
this.getDashboard();
this.checkConnection();
}
async checkConnection() {
const userData = await Connection.checkConnection();
if (!userData) return this.setState({user: null});
this.setState({user: userData});
}
async getDashboard() {
const dashboardData = await Connection.getDashboard();
this.featured = dashboardData.featured;
this.popular = dashboardData.popular;
this.keywords = dashboardData.keywords;
this.setState({loading: false});
this.changeTab(this.state.tab);
if (!this.keywords || !this.keywords.length) Modals.showConfirmationModal(Strings.PublicServers.connectionError, Strings.PublicServers.connectionErrorMessage);
}
async connect() {
await Connection.connect();
this.checkConnection();
}
searchKeyDown(e) {
if (this.state.loading || e.key !== "Enter") return;
const term = e.target.value;
if (this.state.tab == "Featured" || this.state.tab == "Popular") this.setState({tab: "All"}, () => this.search(term));
else this.search(term);
}
async search(term = "", page = 1) {
this.setState({query: term, loading: true});
const results = await Connection.search({term, keyword: this.state.tab == "All" || this.state.tab == "Featured" || this.state.tab == "Popular" ? "" : this.state.tab, page});
if (!results) return this.setState({results: Object.assign({}, EMPTY_RESULTS)});
this.setState({loading: false, results});
}
async changeTab(id) {
if (this.state.loading) return;
await new Promise(resolve => this.setState({tab: id}, resolve));
if (this.state.tab === "Featured" || this.state.tab == "Popular") {
const fakeResults = {
servers: this[this.state.tab.toLowerCase()],
size: this[this.state.tab.toLowerCase()].length,
total: this[this.state.tab.toLowerCase()].length,
page: 1,
numPages: 1
};
return this.setState({results: fakeResults});
}
this.search();
}
get hasPrevious() {return this.state.results.page > 1;}
get hasNext() {return this.state.results.page < this.state.results.numPages;}
loadPreviousPage() {
if (this.state.loading || !this.hasPrevious) return;
this.search(this.state.query, this.state.results.page - 1);
}
loadNextPage() {
if (this.state.loading || !this.hasNext) return;
this.search(this.state.query, this.state.results.page + 1);
}
async join(id, native = false) {
if (!this.state.user && !native) {
return Modals.showConfirmationModal(Strings.PublicServers.notConnected, Strings.PublicServers.connectionRequired, {
cancelText: Strings.Modals.nevermind,
confirmText: Strings.Modals.okay,
onConfirm: () => {
this.connect().then(() => Connection.join(id, native));
}
});
}
return await Connection.join(id, native);
}
navigateTo(id) {
if (GuildActions) GuildActions.transitionToGuildSync(id);
if (LayerManager) LayerManager.popLayer();
}
get searchBox() {
return <Search onKeyDown={this.searchKeyDown} className="bd-server-search" placeholder={`${Strings.PublicServers.search}...`} value={this.state.query} />;
}
get title() {
if (this.state.loading) return `${Strings.PublicServers.loading}...`;
if (this.state.query) {
const start = ((this.state.results.page - 1) * this.state.results.size) + 1;
const total = this.state.results.total;
const end = this.hasNext ? (start - 1) + this.state.results.size : total;
let title = Strings.PublicServers.results.format({start, end, total, category: this.state.tab});
if (this.state.query) title += " " + Strings.PublicServers.query.format({query: this.state.query});
return title;
}
return this.state.tab;
}
get content() {
const connectButton = this.state.user ? null : {title: Strings.PublicServers.connect, onClick: this.connect};
const servers = this.state.results.servers.map((server) => {
return React.createElement(ServerCard, {key: server.identifier, server: server, joined: Connection.hasJoined(server.identifier), join: this.join, navigateTo: this.navigateTo, defaultAvatar: Connection.getDefaultAvatar});
});
let content = React.createElement(EmptyResults);
if (this.state.loading) content = this.loadingScreen;
else if (this.state.results.total) content = React.createElement("div", {className: "bd-card-list"}, servers);
return [React.createElement(SettingsTitle, {text: this.title, button: connectButton}),
this.state.results.numPages > 1 && this.pagination,
content,
this.state.results.numPages > 1 && this.pagination
];
}
get loadingScreen() {
return <div className="bd-card-list">
<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 className="bd-placeholder-card"></div>
<div className="bd-placeholder-card"></div>
<div className="bd-placeholder-card"></div>
</div>;
}
get pagination() {
return React.createElement("div", {className: "bd-pagination"},
React.createElement("button", {type: "button", className: "bd-button bd-pagination-previous", disabled: !this.hasPrevious, onClick: this.loadPreviousPage}, <Previous />),
React.createElement("span", {className: "bd-pagination-info"}, Strings.PublicServers.pagination.format({page: this.state.results.page, count: this.state.results.numPages})),
React.createElement("button", {type: "button", className: "bd-button bd-pagination-next", disabled: !this.hasNext, onClick: this.loadNextPage}, <Next />)
);
}
get connection() {
const {user} = this.state;
if (!user) return React.createElement("div", {id: "bd-connection"});
return React.createElement("div", {id: "bd-connection"},
React.createElement("div", {className: "bd-footnote"}, Strings.PublicServers.connection.format(user)),
React.createElement("button", {type: "button", className: "bd-button bd-button-reconnect", onClick: this.connect}, Strings.PublicServers.reconnect)
);
}
render() {
const keywords = this.keywords.map(name => ({
section: name,
label: name,
element: () => this.content
})
);
return React.createElement(SettingsView, {
onClose: this.props.close,
onSetSection: this.changeTab,
section: this.state.tab,
sections: [
{section: "HEADER", label: Strings.PublicServers.search},
{section: "CUSTOM", element: () => this.searchBox},
{section: "DIVIDER"},
{section: "HEADER", label: Strings.PublicServers.categories},
{section: "All", label: "All", element: () => this.content},
{section: "Featured", label: "Featured", element: () => this.content},
{section: "Popular", label: "Popular", element: () => this.content},
{section: "DIVIDER"},
{section: "HEADER", label: Strings.PublicServers.keywords},
...keywords,
{section: "DIVIDER"},
{section: "HEADER", label: React.createElement("a", {href: "https://discordservers.com", target: "_blank"}, "DiscordServers.com")},
{section: "DIVIDER"},
{section: "CUSTOM", element: () => this.connection}
],
theme: "dark"
});
}
}