Browse Source

add server selector page

Markus-Rost 4 years ago
parent
commit
1eed566cdf

+ 4 - 0
cmds/eval.js

@@ -6,6 +6,10 @@ const {limit: {verification: verificationLimit, rcgcdw: rcgcdwLimit}} = require(
 const newMessage = require('../util/newMessage.js');
 var db = require('../util/database.js');
 
+var allSites = [];
+const getAllSites = require('../util/allSites.js');
+getAllSites.then( sites => allSites = sites );
+
 /**
  * Processes the "eval" command.
  * @param {import('../util/i18n.js')} lang - The user language.

+ 3 - 3
cmds/wiki/gamepedia/overview.js

@@ -32,9 +32,9 @@ function gamepedia_overview(lang, msg, wiki, reaction, spoiler) {
 		}
 		else {
 			wiki.updateWiki(body.query.general);
-			var site = false;
-			if ( allSites.some( site => site.wiki_domain === body.hostname ) ) {
-				site = allSites.find( site => site.wiki_domain === body.hostname );
+			var site = null;
+			if ( allSites.some( site => site.wiki_domain === wiki.hostname ) ) {
+				site = allSites.find( site => site.wiki_domain === wiki.hostname );
 				
 				var name = [lang.get('overview.name'), site.wiki_display_name];
 				var created = [lang.get('overview.created'), new Date(parseInt(site.created + '000', 10)).toLocaleString(lang.get('dateformat'), timeoptions)];

+ 55 - 22
dashboard/guilds.js

@@ -21,64 +21,60 @@ function dashboard_guilds(res, state, reqURL) {
 	var arguments = reqURL.pathname.split('/');
 	var settings = settingsData.get(state);
 	var $ = cheerio.load(file);
-	let notice = '';
 	if ( process.env.READONLY ) {
-		notice = createNotice($, {
+		createNotice($, {
 			title: 'Read-only database!',
 			text: 'You can currently only view your settings but not change them.'
-		});
+		}).prependTo('#text');
 	}
-	$('replace#notice').replaceWith(notice);
-	$('.navbar #logout img').attr('src', settings.user.avatar);
-	$('.navbar #logout span').text(`${settings.user.username} #${settings.user.discriminator}`);
+	$('#logout img').attr('src', settings.user.avatar);
+	$('#logout span').text(`${settings.user.username} #${settings.user.discriminator}`);
 	$('.guild#invite a').attr('href', oauth.generateAuthUrl( {
 		scope: ['identify', 'guilds', 'bot'],
 		permissions: defaultPermissions, state
 	} ));
 	$('.guild#refresh a').attr('href', '/refresh?return=' + reqURL.pathname);
-	let guilds = $('<div>');
 	if ( settings.guilds.isMember.size ) {
 		$('<div class="guild">').append(
 			$('<div class="separator">')
-		).appendTo(guilds);
+		).insertBefore('.guild#last-separator');
 		settings.guilds.isMember.forEach( guild => {
 			$('<div class="guild">').attr('id', guild.id).append(
 				$('<div class="bar">'),
 				$('<a>').attr('href', `/guild/${guild.id}`).attr('alt', guild.name).append(
 					( guild.icon ? 
-						$('<img class="avatar" width="48" height="48">').attr('src', guild.icon).attr('alt', guild.name)
+						$('<img class="avatar">').attr('src', `${guild.icon}?size=64`).attr('alt', guild.name)
 					 : $('<div class="avatar noicon">').text(guild.acronym) )
 				)
-			).appendTo(guilds);
+			).insertBefore('.guild#last-separator');
 		} );
 	}
 	if ( settings.guilds.notMember.size ) {
 		$('<div class="guild">').append(
 			$('<div class="separator">')
-		).appendTo(guilds);
+		).insertBefore('.guild#last-separator');
 		settings.guilds.notMember.forEach( guild => {
 			$('<div class="guild">').attr('id', guild.id).append(
 				$('<div class="bar">'),
 				$('<a>').attr('href', `/guild/${guild.id}`).attr('alt', guild.name).append(
 					( guild.icon ? 
-						$('<img class="avatar" width="48" height="48">').attr('src', guild.icon).attr('alt', guild.name)
+						$('<img class="avatar">').attr('src', `${guild.icon}?size=64`).attr('alt', guild.name)
 					 : $('<div class="avatar noicon">').text(guild.acronym) )
 				)
-			).appendTo(guilds);
+			).insertBefore('.guild#last-separator');
 		} );
 	}
-	$('replace#guilds').replaceWith(guilds.children());
 
-	if ( reqURL.pathname.startsWith( '/guild/' ) ) {
-		let id = reqURL.pathname.replace( '/guild/', '' );
+	if ( arguments[1] === 'guild' ) {
+		let id = arguments[2];
 		if ( settings.guilds.isMember.has(id) ) {
 			$(`.guild#${id}`).addClass('selected');
 			let guild = settings.guilds.isMember.get(id);
 			$('head title').text(`${guild.name} – ` + $('head title').text());
 			res.setHeader('Set-Cookie', [`guild="${id}"; HttpOnly; Path=/`]);
-			$('replace#text').replaceWith(`${guild.permissions}`);
+			$('<a>').text(`${guild.permissions}`).appendTo('#text');
 		}
-		if ( settings.guilds.notMember.has(id) ) {
+		else if ( settings.guilds.notMember.has(id) ) {
 			$(`.guild#${id}`).addClass('selected');
 			let guild = settings.guilds.notMember.get(id);
 			$('head title').text(`${guild.name} – ` + $('head title').text());
@@ -88,12 +84,49 @@ function dashboard_guilds(res, state, reqURL) {
 				permissions: defaultPermissions,
 				guild_id: id, state
 			} );
-			$('replace#text').replaceWith($('<a>').attr('href', url).text(guild.permissions));
+			$('<a>').attr('href', url).text(guild.permissions).appendTo('#text');
+		}
+		else {
+			$('<p>').text('You are missing the <code>MANAGE_GUILD</code> permission.').appendTo('#text');
 		}
-		$('replace#text').replaceWith('You are missing the <code>MANAGE_GUILD</code> permission.');
 	}
-
-	$('replace#text').replaceWith('Keks');
+	else {
+		$('#channellist').empty();
+		$('<div>').text('This is a list of all servers you can change settings on. Please select a server:').appendTo('#text');
+		if ( settings.guilds.isMember.size ) {
+			$('<h2 id="with-wikibot">').text('Server with Wiki-Bot').appendTo('#text');
+			$('<a class="channel">').attr('href', '#with-wikibot').append(
+				$('<img>').attr('src', '/src/channel.svg'),
+				$('<div>').text('Server with Wiki-Bot')
+			).appendTo('#channellist');
+			$('<div class="server-selector" id="isMember">').appendTo('#text');
+			settings.guilds.isMember.forEach( guild => {
+				$('<a class="server">').attr('href', `/guild/${guild.id}`).append(
+					( guild.icon ? 
+						$('<img class="avatar">').attr('src', `${guild.icon}?size=256`).attr('alt', guild.name)
+					 : $('<div class="avatar noicon">').text(guild.acronym) ),
+					$('<div class="server-name">').text(guild.name)
+				).appendTo('.server-selector#isMember');
+			} );
+		}
+		if ( settings.guilds.notMember.size ) {
+			$('<h2 id="without-wikibot">').text('Server without Wiki-Bot').appendTo('#text');
+			$('<a class="channel">').attr('href', '#without-wikibot').append(
+				$('<img>').attr('src', '/src/channel.svg'),
+				$('<div>').text('Server without Wiki-Bot')
+			).appendTo('#channellist');
+			$('<div class="server-selector" id="notMember">').appendTo('#text');
+			settings.guilds.notMember.forEach( guild => {
+				$('<a class="server">').attr('href', `/guild/${guild.id}`).append(
+					( guild.icon ? 
+						$('<img class="avatar">').attr('src', `${guild.icon}?size=256`).attr('alt', guild.name)
+					 : $('<div class="avatar noicon">').text(guild.acronym) ),
+					$('<div class="server-name">').text(guild.name)
+				).appendTo('.server-selector#notMember');
+			} );
+		}
+		$('#channellist:empty').remove();
+	}
 	let body = $.html();
 	res.writeHead(200, {'Content-Length': body.length});
 	res.write( body );

+ 12 - 16
dashboard/index.html

@@ -12,24 +12,21 @@
 	<meta itemprop="author" content="MarkusRost">
 	<link rel="stylesheet" type="text/css" href="/src/index.css">
 </head>
-<body class="settings">
-	<div class="text">
-		<replace id="notice">Some text here</replace>
-		<replace id="text">Some text here</replace>
-	</div>
-	<div class="navbar">
+<body>
+	<div id="text"></div>
+	<div id="navbar">
 		<div style="width: 150px;"></div>
 		<a id="support" href="https://discord.gg/v77RTk5" target="_blank" alt="Support server">
-			<img class="avatar" src="https://cdn.discordapp.com/icons/464084451165732868/c6a8b9fc902b09545de8194a911e6045.png?size=128" alt="Support server" width="32" height="32">
+			<img class="avatar" src="https://cdn.discordapp.com/icons/464084451165732868/c6a8b9fc902b09545de8194a911e6045.png?size=128" alt="Support server">
 			<span>Support server</span>
 		</a>
 		<a id="logout" href="/logout" alt="Logout">
-			<img class="avatar" src="https://cdn.discordapp.com/avatars/461189216198590464/f69cdc197791aed829882b64f9760dbb.png?size=64" alt="Logout" width="32" height="32">
+			<img class="avatar" src="https://cdn.discordapp.com/avatars/461189216198590464/f69cdc197791aed829882b64f9760dbb.png?size=64" alt="Logout">
 			<span>Wiki-Bot #2998</span>
 		</a>
 	</div>
-	<div class="sidebar">
-		<div class="guildlist">
+	<div class="scrollbar" id="sidebar">
+		<div id="guildlist">
 			<div class="guild" id="invite">
 				<div class="bar"></div>
 				<a href="https://discord.com/oauth2/authorize?client_id=461189216198590464&permissions=939912256&scope=bot" alt="Invite Wiki-Bot">
@@ -40,8 +37,7 @@
 					</div>
 				</a>
 			</div>
-			<replace id="guilds">List of guilds here</replace>
-			<div class="guild">
+			<div class="guild" id="last-separator">
 				<div class="separator"></div>
 			</div>
 			<div class="guild" id="refresh">
@@ -55,21 +51,21 @@
 				</a>
 			</div>
 		</div>
-		<div class="channellist">
+		<div class="scrollbar" id="channellist">
 			<a class="channel channel-header" id="settings">
-				<svg width="24" height="24" viewBox="0 0 24 24">
+				<svg viewBox="0 0 24 24">
 					<path fill="currentColor" fill-rule="evenodd" clip-rule="evenodd" d="M19.738 10H22V14H19.739C19.498 14.931 19.1 15.798 18.565 16.564L20 18L18 20L16.565 18.564C15.797 19.099 14.932 19.498 14 19.738V22H10V19.738C9.069 19.498 8.203 19.099 7.436 18.564L6 20L4 18L5.436 16.564C4.901 15.799 4.502 14.932 4.262 14H2V10H4.262C4.502 9.068 4.9 8.202 5.436 7.436L4 6L6 4L7.436 5.436C8.202 4.9 9.068 4.502 10 4.262V2H14V4.261C14.932 4.502 15.797 4.9 16.565 5.435L18 3.999L20 5.999L18.564 7.436C19.099 8.202 19.498 9.069 19.738 10ZM12 16C14.2091 16 16 14.2091 16 12C16 9.79086 14.2091 8 12 8C9.79086 8 8 9.79086 8 12C8 14.2091 9.79086 16 12 16Z"></path>
 				</svg>
 				<div>Settings</div>
 			</a>
 			<a class="channel channel-header" id="verification">
-				<svg width="24" height="24" viewBox="0 0 24 24">
+				<svg viewBox="0 0 24 24">
 					<path fill="currentColor" fill-rule="evenodd" clip-rule="evenodd" d="M19.738 10H22V14H19.739C19.498 14.931 19.1 15.798 18.565 16.564L20 18L18 20L16.565 18.564C15.797 19.099 14.932 19.498 14 19.738V22H10V19.738C9.069 19.498 8.203 19.099 7.436 18.564L6 20L4 18L5.436 16.564C4.901 15.799 4.502 14.932 4.262 14H2V10H4.262C4.502 9.068 4.9 8.202 5.436 7.436L4 6L6 4L7.436 5.436C8.202 4.9 9.068 4.502 10 4.262V2H14V4.261C14.932 4.502 15.797 4.9 16.565 5.435L18 3.999L20 5.999L18.564 7.436C19.099 8.202 19.498 9.069 19.738 10ZM12 16C14.2091 16 16 14.2091 16 12C16 9.79086 14.2091 8 12 8C9.79086 8 8 9.79086 8 12C8 14.2091 9.79086 16 12 16Z"></path>
 				</svg>
 				<div>Verifications</div>
 			</a>
 			<a class="channel channel-header" id="rcgcdb">
-				<svg width="24" height="24" viewBox="0 0 24 24">
+				<svg viewBox="0 0 24 24">
 					<path fill="currentColor" fill-rule="evenodd" clip-rule="evenodd" d="M19.738 10H22V14H19.739C19.498 14.931 19.1 15.798 18.565 16.564L20 18L18 20L16.565 18.564C15.797 19.099 14.932 19.498 14 19.738V22H10V19.738C9.069 19.498 8.203 19.099 7.436 18.564L6 20L4 18L5.436 16.564C4.901 15.799 4.502 14.932 4.262 14H2V10H4.262C4.502 9.068 4.9 8.202 5.436 7.436L4 6L6 4L7.436 5.436C8.202 4.9 9.068 4.502 10 4.262V2H14V4.261C14.932 4.502 15.797 4.9 16.565 5.435L18 3.999L20 5.999L18.564 7.436C19.099 8.202 19.498 9.069 19.738 10ZM12 16C14.2091 16 16 14.2091 16 12C16 9.79086 14.2091 8 12 8C9.79086 8 8 9.79086 8 12C8 14.2091 9.79086 16 12 16Z"></path>
 				</svg>
 				<div>Recent Changes</div>

+ 15 - 12
dashboard/login.html

@@ -12,20 +12,17 @@
 	<meta itemprop="author" content="MarkusRost">
 	<link rel="stylesheet" type="text/css" href="/src/index.css">
 </head>
-<body class="settings">
-	<div class="text">
-		<replace id="notice">Some text here</replace>
-		<replace id="text">Some text here</replace>
-	</div>
-	<div class="navbar">
+<body>
+	<div id="text"></div>
+	<div id="navbar">
 		<div style="width: 150px;"></div>
 		<a id="support" href="https://discord.gg/v77RTk5" target="_blank" alt="Support server">
-			<img class="avatar" src="https://cdn.discordapp.com/icons/464084451165732868/c6a8b9fc902b09545de8194a911e6045.png?size=128" alt="Support server" width="32" height="32">
+			<img class="avatar" src="https://cdn.discordapp.com/icons/464084451165732868/c6a8b9fc902b09545de8194a911e6045.png?size=128" alt="Support server">
 			<span>Support server</span>
 		</a>
 	</div>
-	<div class="sidebar">
-		<div class="guildlist">
+	<div class="scrollbar" id="sidebar">
+		<div id="guildlist">
 			<div class="guild" id="invite">
 				<div class="bar"></div>
 				<a href="https://discord.com/oauth2/authorize?client_id=461189216198590464&permissions=939912256&scope=bot" alt="Invite Wiki-Bot">
@@ -37,11 +34,17 @@
 				</a>
 			</div>
 		</div>
-		<div class="channellist">
-			<a class="channel" id="login">
-				<img src="/src/channel.svg" width="20" height="20">
+		<div class="scrollbar" id="channellist">
+			<a class="channel channel-header" id="login">
+				<svg viewBox="0 0 24 24">
+					<path fill="currentColor" fill-rule="evenodd" clip-rule="evenodd" d="M19.738 10H22V14H19.739C19.498 14.931 19.1 15.798 18.565 16.564L20 18L18 20L16.565 18.564C15.797 19.099 14.932 19.498 14 19.738V22H10V19.738C9.069 19.498 8.203 19.099 7.436 18.564L6 20L4 18L5.436 16.564C4.901 15.799 4.502 14.932 4.262 14H2V10H4.262C4.502 9.068 4.9 8.202 5.436 7.436L4 6L6 4L7.436 5.436C8.202 4.9 9.068 4.502 10 4.262V2H14V4.261C14.932 4.502 15.797 4.9 16.565 5.435L18 3.999L20 5.999L18.564 7.436C19.099 8.202 19.498 9.069 19.738 10ZM12 16C14.2091 16 16 14.2091 16 12C16 9.79086 14.2091 8 12 8C9.79086 8 8 9.79086 8 12C8 14.2091 9.79086 16 12 16Z"></path>
+				</svg>
 				<div>Login</div>
 			</a>
+			<a class="channel" id="invite-wikibot">
+				<img src="/src/channel.svg" width="20" height="20">
+				<div>Invite Wiki-Bot</div>
+			</a>
 		</div>
 	</div>
 </body>

+ 14 - 14
dashboard/oauth.js

@@ -27,33 +27,33 @@ function dashboard_login(res, state, action) {
 		res.setHeader('Set-Cookie', [`wikibot="${state}"; Max-Age=0; HttpOnly`]);
 	}
 	var $ = cheerio.load(file);
-	$('.guild#invite a').attr('href', oauth.generateAuthUrl( {
+	let invite = oauth.generateAuthUrl( {
 		scope: ['identify', 'guilds', 'bot'],
 		permissions: defaultPermissions, state
-	} ));
+	} );
+	$('.guild#invite a').attr('href', invite);
+	$('.channel#invite-wikibot').attr('href', invite);
 	let responseCode = 200;
-	let notice = '';
 	if ( action === 'failed' ) {
 		responseCode = 400;
-		notice = createNotice($, {
+		createNotice($, {
 			title: 'Login failed!',
 			text: 'An error occurred while logging you in, please try again.'
-		});
+		}).prependTo('#text');
 	}
 	if ( action === 'unauthorized' ) {
 		responseCode = 401;
-		notice = createNotice($, {
+		createNotice($, {
 			title: 'Not logged in!',
 			text: 'Please login before you can change any settings.'
-		});
+		}).prependTo('#text');
 	}
 	if ( action === 'logout' ) {
-		notice = createNotice($, {
+		createNotice($, {
 			title: 'Successfully logged out!',
 			text: 'You have been successfully logged out. To change any settings you need to login again.'
-		});
+		}).prependTo('#text');
 	}
-	$('replace#notice').replaceWith(notice);
 	state = crypto.randomBytes(16).toString("hex");
 	while ( settingsData.has(state) ) {
 		state = crypto.randomBytes(16).toString("hex");
@@ -62,8 +62,8 @@ function dashboard_login(res, state, action) {
 		scope: ['identify', 'guilds'],
 		prompt: 'none', state
 	} );
-	$('a#login').attr('href', url);
-	$('replace#text').replaceWith(`<a href="${url}">Login</a>`);
+	$('.channel#login').attr('href', url);
+	$('<a>').attr('href', url).text('Login').appendTo('#text');
 	let body = $.html();
 	res.writeHead(responseCode, {
 		'Set-Cookie': [`wikibot="${state}"; HttpOnly`],
@@ -106,7 +106,7 @@ function dashboard_oauth(res, state, searchParams, lastGuild) {
 					name: guild.name,
 					acronym: guild.name.replace( /'s /g, ' ' ).replace( /\w+/g, e => e[0] ).replace( /\s/g, '' ),
 					icon: ( guild.icon ? `https://cdn.discordapp.com/icons/${guild.id}/${guild.icon}.`
-					+ ( guild.icon.startsWith( 'a_' ) ? 'gif' : 'png' ) + '?size=128' : null ),
+					+ ( guild.icon.startsWith( 'a_' ) ? 'gif' : 'png' ) : null ),
 					permissions: guild.permissions
 				};
 			} );
@@ -177,7 +177,7 @@ function dashboard_refresh(res, state, returnLocation = '/') {
 				name: guild.name,
 				acronym: guild.name.replace( /'s /g, ' ' ).replace( /\w+/g, e => e[0] ).replace( /\s/g, '' ),
 				icon: ( guild.icon ? `https://cdn.discordapp.com/icons/${guild.id}/${guild.icon}.`
-				+ ( guild.icon.startsWith( 'a_' ) ? 'gif' : 'png' ) + '?size=128' : null ),
+				+ ( guild.icon.startsWith( 'a_' ) ? 'gif' : 'png' ) : null ),
 				permissions: guild.permissions
 			};
 		} );

+ 1 - 1
dashboard/src/channel.svg

@@ -1,3 +1,3 @@
-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24">
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" viewBox="0 0 24 24">
 	<path fill="#8e9297" fill-rule="evenodd" clip-rule="evenodd" d="M5.88657 21C5.57547 21 5.3399 20.7189 5.39427 20.4126L6.00001 17H2.59511C2.28449 17 2.04905 16.7198 2.10259 16.4138L2.27759 15.4138C2.31946 15.1746 2.52722 15 2.77011 15H6.35001L7.41001 9H4.00511C3.69449 9 3.45905 8.71977 3.51259 8.41381L3.68759 7.41381C3.72946 7.17456 3.93722 7 4.18011 7H7.76001L8.39677 3.41262C8.43914 3.17391 8.64664 3 8.88907 3H9.87344C10.1845 3 10.4201 3.28107 10.3657 3.58738L9.76001 7H15.76L16.3968 3.41262C16.4391 3.17391 16.6466 3 16.8891 3H17.8734C18.1845 3 18.4201 3.28107 18.3657 3.58738L17.76 7H21.1649C21.4755 7 21.711 7.28023 21.6574 7.58619L21.4824 8.58619C21.4406 8.82544 21.2328 9 20.9899 9H17.41L16.35 15H19.7549C20.0655 15 20.301 15.2802 20.2474 15.5862L20.0724 16.5862C20.0306 16.8254 19.8228 17 19.5799 17H16L15.3632 20.5874C15.3209 20.8261 15.1134 21 14.8709 21H13.8866C13.5755 21 13.3399 20.7189 13.3943 20.4126L14 17H8.00001L7.36325 20.5874C7.32088 20.8261 7.11337 21 6.87094 21H5.88657ZM9.41045 9L8.35045 15H14.3504L15.4104 9H9.41045Z"></path>
 </svg>

+ 78 - 32
dashboard/src/index.css

@@ -21,17 +21,17 @@ a[alt]:hover:after {
 	color: #dcddde;
 	font-weight: bold;
 	font-size: 90%;
-	white-space: nowrap;
+	word-break: break-word;
 	border-radius: 4px;
 	padding: 8px;
 }
-.text a {
+#text a {
 	color: #00b0f4;
 }
-.text a:hover {
+#text a:hover {
 	text-decoration: underline;
 }
-.text {
+#text {
 	position: relative;
 	padding: 8px;
 	width: calc(100% - 328px);
@@ -47,7 +47,38 @@ a[alt]:hover:after {
 	background: #200;
 	border: 2px solid #500;
 }
-.navbar {
+.server-selector {
+	display: flex;
+	flex-wrap: wrap;
+}
+.server {
+	background-color: rgba(0,0,0,0.5);
+	text-align: center;
+	border-radius: 10%;
+	width: 200px;
+	margin: 5px;
+}
+.server-selector .server:hover {
+	background: rgba(0,0,0,0.3);
+	filter: brightness(1.2);
+	text-decoration: none;
+}
+.server .avatar {
+	border-radius: 10%;
+	width: 200px;
+	height: 200px;
+}
+.server .noicon {
+	font-size: 416%;
+	background-color: unset;
+}
+.server .server-name {
+	padding: 8px 12px;
+	word-break: break-word;
+	font-weight: bold;
+	font-size: 90%;
+}
+#navbar {
 	background: #2f3136;
 	position: fixed;
 	top: 0;
@@ -56,46 +87,62 @@ a[alt]:hover:after {
 	display: flex;
 	align-items: center;
 	justify-content: space-between;
-	height: 48px;
+	height: 47px;
 	padding: 0 0 0 8px;
 	font-size: 16px;
 	line-height: 20px;
 	font-weight: bold;
-	box-shadow: 0 1px 0 rgba(4,4,5,0.2),
-				0 1.5px 0 rgba(6,6,7,0.05),
-				0 2px 0 rgba(4,4,5,0.05);
-	z-index: 2;
+	border-bottom: 1px solid rgba(4,4,5,0.2);
 }
-.navbar a {
+:target::before {
+	content: "";
+	display: block;
+	height: 48px;
+	margin: -48px 0 0;
+}
+#navbar a {
 	display: flex;
 	align-items: center;
 	height: 100%;
 	padding-left: 10px;
 }
-.navbar a:hover {
+#navbar a:hover {
 	background: #202225;
 }
-.navbar .avatar {
+#navbar a[alt]:hover:after {
+	top: 48px;
+}
+#navbar .avatar {
 	width: 32px;
 	height: 32px;
 }
-.navbar span {
+#navbar span {
 	padding: 0 10px;
 }
-.sidebar {
-	background: #202225;
-	position: absolute;
+.scrollbar {
+	-ms-overflow-style: none;
+	scrollbar-width: none;
+}
+.scrollbar::-webkit-scrollbar {
+	display: none;
+}
+#sidebar {
+	position: fixed;
+	display: flex;
 	top: 0;
 	left: 0;
-	min-height: calc(100% + 48px);
-	width: 72px;
-	display: flex;
+	bottom: 0;
+	width: 312px;
+	overflow: visible scroll;
 }
-.guildlist {
+#guildlist {
+	background: #202225;
+	position: absolute;
 	padding: 12px 0;
-	position: relative;
 	flex: 1 1 auto;
-	z-index: 2;
+	min-height: calc(100% - 24px);
+	width: 72px;
+	z-index: 1;
 }
 .guild {
 	margin: 0 0 8px;
@@ -110,14 +157,13 @@ a[alt]:hover:after {
 	display: flex;
 	align-items: center;
 	justify-content: center;
-	font-weight: 500;
 	line-height: 1.2em;
 	white-space: nowrap;
 	overflow: hidden;
 	color: #dcddde;
 	font-weight: bold;
 }
-.navbar a:hover .avatar,
+#navbar a:hover .avatar,
 .guild.selected .avatar,
 .guild:hover .avatar {
 	border-radius: 30%;
@@ -167,19 +213,19 @@ a[alt]:hover:after {
 .guild a[alt]:hover:after {
 	top: 20%;
 	left: 72px;
+	max-width: 224px;
+	width: max-content;
 }
-.navbar a[alt]:hover:after {
-	top: 48px;
-}
-.channellist {
+#channellist {
 	background: #2f3136;
-	position: absolute;
-	min-height: calc(100% - 80px);
+	position: fixed;
+	overflow: hidden scroll;
 	padding: 16px 0;
 	width: 240px;
 	top: 48px;
 	left: 72px;
-	z-index: 1;
+	bottom: 0;
+	z-index: 0;
 }
 .channel {
 	padding: 0 8px;

+ 8 - 8
dashboard/util.js

@@ -73,16 +73,16 @@ function sendMsg(message) {
 /**
  * Create a red notice
  * @param {CheerioStatic} $ - The cheerio static
- * @param {{title: String, text: String}[]} notices - The notices to create
+ * @param {Object} notice - The notices to create
+ * @param {String} notice.title - The title of the notice
+ * @param {String} notice.text - The text of the notice
  * @returns {Cheerio}
  */
-function createNotice($, ...notices) {
-	return notices.map( notice => {
-		return $('<div class="notice">').append(
-			$('<b>').text(notice.title),
-			$('<div>').text(notice.text)
-		);
-	} );
+function createNotice($, notice) {
+	return $('<div class="notice">').append(
+		$('<b>').text(notice.title),
+		$('<div>').text(notice.text)
+	);
 }
 
 const permissions = {