Implement Rooms room

This commit is contained in:
Guangcong Luo 2019-03-21 20:10:55 +09:00
parent 3bef3920a8
commit fbaceafac1
10 changed files with 3564 additions and 20 deletions

View File

@ -1,10 +1,10 @@
<!DOCTYPE html> <!DOCTYPE html>
<html><head> <html><head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<title>Showdown!</title> <title>Showdown!</title>
<link rel="shortcut icon" href="favicon.ico" id="dynamic-favicon" /> <link rel="shortcut icon" href="favicon.ico" id="dynamic-favicon" />
<link rel="stylesheet" href="/style/client.css" /> <link rel="stylesheet" href="/style/client2.css" />
<meta id="viewport" name="viewport" content="width=640" />
<meta name="robots" content="noindex" /> <meta name="robots" content="noindex" />
<meta http-equiv="X-UA-Compatible" content="IE=Edge" /> <meta http-equiv="X-UA-Compatible" content="IE=Edge" />
<!--[if lte IE 8]><script> <!--[if lte IE 8]><script>

View File

@ -600,7 +600,7 @@ const PS = new class extends PSModel {
id: roomid2, id: roomid2,
type, type,
connected: true, connected: true,
}); }, roomid === 'staff' || roomid === 'upperstaff');
room = PS.rooms[roomid2]; room = PS.rooms[roomid2];
} else { } else {
room.type = type; room.type = type;

View File

@ -14,7 +14,7 @@ class ChatRoom extends PSRoom {
super(options); super(options);
if (options.pmTarget) this.pmTarget = options.pmTarget as string; if (options.pmTarget) this.pmTarget = options.pmTarget as string;
this.updateTarget(true); this.updateTarget(true);
if (!this.connected && PS.connected) { if (!this.connected) {
if (!this.pmTarget) PS.send(`|/join ${this.id}`); if (!this.pmTarget) PS.send(`|/join ${this.id}`);
this.connected = true; this.connected = true;
} }

View File

@ -5,6 +5,8 @@
* @license AGPLv3 * @license AGPLv3
*/ */
type RoomInfo = {title: string, desc: string, userCount: number, subRooms?: string[]};
class MainMenuRoom extends PSRoom { class MainMenuRoom extends PSRoom {
readonly classType: string = 'mainmenu'; readonly classType: string = 'mainmenu';
userdetailsCache: {[userid: string]: { userdetailsCache: {[userid: string]: {
@ -13,6 +15,13 @@ class MainMenuRoom extends PSRoom {
group?: string, group?: string,
rooms?: {[roomid: string]: {isPrivate?: true, p1?: string, p2?: string}}, rooms?: {[roomid: string]: {isPrivate?: true, p1?: string, p2?: string}},
}} = {}; }} = {};
roomsCache: {
battleCount?: number,
userCount?: number,
chat?: RoomInfo[],
official?: RoomInfo[],
pspl?: RoomInfo[],
} = {};
receive(line: string) { receive(line: string) {
const tokens = PS.lineParse(line); const tokens = PS.lineParse(line);
switch (tokens[0]) { switch (tokens[0]) {
@ -65,8 +74,13 @@ class MainMenuRoom extends PSRoom {
} else { } else {
Object.assign(userdetails, response); Object.assign(userdetails, response);
} }
const room = PS.rooms[`user-${userid}`] as UserRoom; const userRoom = PS.rooms[`user-${userid}`] as UserRoom;
if (room) room.update(''); if (userRoom) userRoom.update('');
break;
case 'rooms':
this.roomsCache = response;
const roomsRoom = PS.rooms[`rooms`] as RoomsRoom;
if (roomsRoom) roomsRoom.update('');
break; break;
} }
} }

View File

@ -6,18 +6,81 @@
*/ */
class RoomsRoom extends PSRoom { class RoomsRoom extends PSRoom {
readonly classType: string = 'mainmenu'; readonly classType: string = 'rooms';
constructor(options: RoomOptions) {
super(options);
PS.send(`|/cmd rooms`);
}
} }
class RoomsPanel extends PSRoomPanel { class RoomsPanel extends PSRoomPanel {
hidden = false;
componentDidMount() {
super.componentDidMount();
this.subscriptions.push(PS.user.subscribe(() => {
if (PS.user.named) PS.send(`|/cmd rooms`);
}));
}
hide = () => {
this.hidden = true;
PS.rightRoom = null;
PS.room = PS.leftRoom;
this.forceUpdate();
PS.update();
};
render() { render() {
return <PSPanelWrapper room={this.props.room}> if (this.hidden && PS.isVisible(this.props.room)) this.hidden = false;
<div class="mainmessage"> if (this.hidden) {
<p>[insert room list here]</p> return <PSPanelWrapper room={this.props.room} scrollable>{null}</PSPanelWrapper>;
<p><a href="/lobby">Lobby</a></p> }
<p><a href="/tours">Tours</a></p> const rooms = PS.mainmenu.roomsCache;
return <PSPanelWrapper room={this.props.room} scrollable><div class="pad">
<button class="button" style="float:right;font-size:10pt;margin-top:3px" onClick={this.hide}>
<i class="fa fa-caret-right"></i> Hide
</button>
<div class="roomcounters">
<span
style="background:transparent url(https://play.pokemonshowdown.com/sprites/smicons-sheet.png?a5) no-repeat scroll -0px -2790px;"
class="picon icon-left"
title="Meloetta is PS's mascot! The Aria forme is about using its voice, and represents our chatrooms."
></span> {}
<button class="button" data-href="/users" title="Find an online user">
<strong>{rooms.userCount || '-'}</strong> users online
</button> {}
<button class="button" data-href="/battles" title="Watch an active battle">
<strong>{rooms.battleCount || '-'}</strong> active battles
</button> {}
<span
style="background:transparent url(https://play.pokemonshowdown.com/sprites/smicons-sheet.png?a5) no-repeat scroll -0px -2220px"
class="picon icon-right"
title="Meloetta is PS's mascot! The Pirouette forme is Fighting-type, and represents our battles."
></span>
</div> </div>
</PSPanelWrapper>; {rooms.userCount === undefined && <h2>Connecting...</h2>}
{this.renderRoomList("Official chat rooms", rooms.official)}
{this.renderRoomList("PSPL winner", rooms.pspl)}
{this.renderRoomList("Chat rooms", rooms.chat)}
</div></PSPanelWrapper>;
}
renderRoomList(title: string, rooms?: RoomInfo[]) {
if (!rooms || !rooms.length) return null;
return <div class="roomlist">
<h2>{title}</h2>
{rooms.map(roomInfo => <div>
<a href={`/${toId(roomInfo.title)}`} class="ilink">
<small style="float:right">({roomInfo.userCount} users)</small>
<strong><i class="fa fa-comment-o"></i> {roomInfo.title}<br /></strong>
<small>{roomInfo.desc}</small>
{roomInfo.subRooms && <small><br />
<i class="fa fa-level-up fa-rotate-90"></i> Subrooms: <strong>
{roomInfo.subRooms.map((roomName, i) => [
<i class="fa fa-comment-o"></i>, " " + roomName + (i === roomInfo.subRooms!.length - 1 ? "" : ", "),
])}
</strong>
</small>}
</a>
</div>)}
</div>;
} }
} }

View File

@ -170,7 +170,7 @@ class PSMain extends preact.Component {
e.stopImmediatePropagation(); e.stopImmediatePropagation();
return; return;
} }
if (elem.tagName === 'A' || elem.className === 'team') { if (elem.tagName === 'A' || elem.getAttribute('data-href')) {
const roomid = this.roomidFromLink(elem as HTMLAnchorElement); const roomid = this.roomidFromLink(elem as HTMLAnchorElement);
if (roomid !== null) { if (roomid !== null) {
PS.addRoom({ PS.addRoom({

3467
style/client2.css Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,10 +1,10 @@
<!DOCTYPE html> <!DOCTYPE html>
<html><head> <html><head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<title>Showdown!</title> <title>Showdown!</title>
<link rel="shortcut icon" href="favicon.ico" id="dynamic-favicon" /> <link rel="shortcut icon" href="favicon.ico" id="dynamic-favicon" />
<link rel="stylesheet" href="style/client.css" /> <link rel="stylesheet" href="style/client2.css" />
<meta id="viewport" name="viewport" content="width=640" />
<meta name="robots" content="noindex" /> <meta name="robots" content="noindex" />
<meta http-equiv="X-UA-Compatible" content="IE=Edge" /> <meta http-equiv="X-UA-Compatible" content="IE=Edge" />
<!--[if lte IE 8]><script> <!--[if lte IE 8]><script>

View File

@ -1,7 +1,8 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" /> <meta charset="utf-8" />
<meta id="viewport" name="viewport" content="width=device-width" />
<title>Showdown!</title> <title>Showdown!</title>
<link rel="shortcut icon" href="favicon.ico" id="dynamic-favicon" /> <link rel="shortcut icon" href="favicon.ico" id="dynamic-favicon" />
<link rel="stylesheet" href="style/client.css" /> <link rel="stylesheet" href="style/client.css" />
@ -9,7 +10,6 @@
<link rel="stylesheet" href="style/battle.css" /> <link rel="stylesheet" href="style/battle.css" />
<link rel="stylesheet" href="style/utilichart.css" /> <link rel="stylesheet" href="style/utilichart.css" />
<link rel="stylesheet" href="style/font-awesome.css" /> <link rel="stylesheet" href="style/font-awesome.css" />
<meta id="viewport" name="viewport" content="width=640" />
<meta name="robots" content="noindex" /> <meta name="robots" content="noindex" />
<meta http-equiv="X-UA-Compatible" content="IE=Edge" /> <meta http-equiv="X-UA-Compatible" content="IE=Edge" />
<script> <script>

View File

@ -19,7 +19,7 @@
"severity": "warning", "severity": "warning",
"options": { "options": {
"limit": 120, "limit": 120,
"ignore-pattern": "template\\.replace\\(('\\[|/)|^\\s*(// \\s*)?((let |const )?[a-zA-Z0-9$.]+ \\+?= (\\$\\()?|(return |throw )?(new )?([a-zA-Z0-9$.]+\\()?)?['\"`/]" "ignore-pattern": "template\\.replace\\(('\\[|/)|[a-z0-9]=|^\\s*(// \\s*)?((let |const )?[a-zA-Z0-9$.]+ \\+?= (\\$\\()?|(return |throw )?(new )?([a-zA-Z0-9$.]+\\()?)?['\"`/]"
} }
}, },
"interface-name": false, "interface-name": false,