improve chat
This commit is contained in:
parent
687984724e
commit
db4c499dc8
|
@ -155,25 +155,26 @@ data-accept-languages="@acceptLanguages.mkString(",")">
|
|||
@ctx.chat.map { c =>
|
||||
<div id="chat_wrap"@if(ctx.pref.chat.on) { class="on"}>
|
||||
<div class="bar">
|
||||
<a class="on">@trans.chat()</a>
|
||||
<a class="friends">
|
||||
<div class="left"><a class="on">@trans.chat()</a></div>
|
||||
<div class="right friends">
|
||||
@trans.onlineFriends() - <strong class="online"> </strong>/<span class="total"> </span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="center last"></div>
|
||||
</div>
|
||||
<div id="chat">
|
||||
<a class="off"></a>
|
||||
<a class="help">help</a>
|
||||
<div class="chans"></div>
|
||||
<div class="lists">
|
||||
<div class="left chans"></div>
|
||||
<div class="right lists">
|
||||
<div class="tabs">
|
||||
<a data-tab="friends" class="friends">@trans.onlineFriends()</a>
|
||||
<a data-tab="teams" class="teams">@trans.teams()</a>
|
||||
</div>
|
||||
<div id="team_box" class="list_box teams" data-preload="@ctx.teams">
|
||||
<div class="content list"></div>
|
||||
<div class="content"></div>
|
||||
</div>
|
||||
<div id="friend_box" class="list_box friends" data-preload="@ctx.friends">
|
||||
<div class="content list"></div>
|
||||
<div class="content"></div>
|
||||
<div class="nobody">
|
||||
<span>@trans.noFriendsOnline()</span>
|
||||
<a class="find button" href="@routes.Relation.suggest(me.username)">
|
||||
|
@ -182,7 +183,7 @@ data-accept-languages="@acceptLanguages.mkString(",")">
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="room">
|
||||
<div class="center room">
|
||||
<div class="lines"></div>
|
||||
<div class="controls">
|
||||
<form action="#">
|
||||
|
|
|
@ -14,6 +14,8 @@ private[chat] final class Api(
|
|||
getTeamIds: String ⇒ Fu[List[String]],
|
||||
netDomain: String) {
|
||||
|
||||
private val NB_LINES = 30
|
||||
|
||||
def join(user: User, chat: ChatHead, chan: Chan): ChatHead = {
|
||||
chanVoter(user.id, chan.key)
|
||||
truncate(user, chat join chan, chan.key)
|
||||
|
@ -58,7 +60,7 @@ private[chat] final class Api(
|
|||
def populate(head: ChatHead, user: User): Fu[Chat] =
|
||||
namer.chans(head.chans, user) zip {
|
||||
relationApi blocking user.id flatMap {
|
||||
LineRepo.find(head.activeChanKeys, user.troll, _, 20) flatMap {
|
||||
LineRepo.find(head.activeChanKeys, user.troll, _, NB_LINES) flatMap {
|
||||
_.map(namer.line).sequenceFu
|
||||
}
|
||||
}
|
||||
|
|
|
@ -76,11 +76,11 @@ object LangChan {
|
|||
}
|
||||
|
||||
case class UserChan(u1: String, u2: String) extends IdChan("user", false) {
|
||||
val id = List(u1, u2).sorted mkString "-"
|
||||
val id = List(u1, u2).sorted mkString "/"
|
||||
def contains(userId: String) = u1 == userId || u2 == userId
|
||||
}
|
||||
object UserChan {
|
||||
def apply(id: String): Option[UserChan] = id.split("-") match {
|
||||
def apply(id: String): Option[UserChan] = id.split("/") match {
|
||||
case Array(u1, u2) ⇒ UserChan(u1, u2).some
|
||||
case _ ⇒ none
|
||||
}
|
||||
|
|
|
@ -40,6 +40,8 @@ case class ChatHead(
|
|||
|
||||
def join(c: Chan) = setChan(c, true).setActiveChanKey(c.key, true).setMainChanKey(c.key.some)
|
||||
|
||||
def part(c: Chan) = setChan(c, false)
|
||||
|
||||
def inactiveChanKeys = chanKeys filterNot activeChanKeys.contains
|
||||
|
||||
def updatePref(pref: ChatPref) = ChatPref(
|
||||
|
@ -48,6 +50,8 @@ case class ChatHead(
|
|||
activeChans = activeChanKeys filterNot Chan.autoActive,
|
||||
mainChan = (mainChanKey filterNot Chan.autoActive) orElse pref.mainChan)
|
||||
|
||||
def sees(line: Line) = (chanKeys contains line.chan.key) && (activeChanKeys contains line.chan.key)
|
||||
|
||||
def sorted = copy(chans = chans.sorted)
|
||||
}
|
||||
|
||||
|
|
|
@ -51,7 +51,12 @@ private[chat] final class ChatActor(
|
|||
saveAndReload(member)
|
||||
}
|
||||
|
||||
case Say(chan, member, text) => api.write(chan.key, member.userId, text) foreach { _ foreach self.! }
|
||||
case Part(member, chan) ⇒ {
|
||||
member setHead (member.head part chan)
|
||||
save(member)
|
||||
}
|
||||
|
||||
case Say(chan, member, text) ⇒ api.write(chan.key, member.userId, text) foreach { _ foreach self.! }
|
||||
|
||||
case Activate(member, chan) ⇒ api.active(member, chan) foreach { head ⇒
|
||||
member setHead head
|
||||
|
@ -134,8 +139,10 @@ private[chat] final class ChatActor(
|
|||
}
|
||||
}
|
||||
|
||||
private def save(member: ChatMember) = prefApi.setChatPref(member.userId, member.head.updatePref)
|
||||
|
||||
private def saveAndReload(member: ChatMember) {
|
||||
prefApi.setChatPref(member.userId, member.head.updatePref) >>- reload(member)
|
||||
save(member) >>- reload(member)
|
||||
}
|
||||
|
||||
private def reload(m: ChatMember) {
|
||||
|
|
|
@ -16,9 +16,7 @@ private[chat] final class ChatMember(
|
|||
|
||||
def wants(line: Line) = line.chan match {
|
||||
case c: UserChan if c.contains(userId) ⇒ true
|
||||
case _ ⇒ (troll || !line.troll) &&
|
||||
(head.activeChanKeys contains line.chan.key) &&
|
||||
!blocks(line.userId)
|
||||
case _ ⇒ (troll || !line.troll) && (head sees line) && !blocks(line.userId)
|
||||
}
|
||||
|
||||
def hasActiveChan = head.activeChanKeys contains _
|
||||
|
|
|
@ -20,21 +20,27 @@ private[chat] final class Commander(
|
|||
namer: Namer,
|
||||
getTeamIds: String ⇒ Fu[List[String]]) extends Actor {
|
||||
|
||||
val chat = context.parent
|
||||
private val chat = context.parent
|
||||
|
||||
private val aliases = Map(
|
||||
"leave" -> "part")
|
||||
|
||||
def receive = {
|
||||
case command@Command(chanOption, member, text) ⇒ text.split(' ').toList match {
|
||||
|
||||
case "help" :: "tutorial" :: _ ⇒ flash(member, tutorial)
|
||||
case "help" :: "mod" :: _ ⇒ flash(member, modHelp)
|
||||
case "help" :: _ ⇒ flash(member, help)
|
||||
case aliased :: words if aliases.contains(aliased) ⇒ self ! command.copy(
|
||||
text = ((aliases.get(aliased) | aliased) :: words) mkString " ")
|
||||
|
||||
case "open" :: _ ⇒ chat ! SetOpen(member, true)
|
||||
case "close" :: _ ⇒ chat ! SetOpen(member, false)
|
||||
case "help" :: "tutorial" :: Nil ⇒ flash(member, tutorial)
|
||||
case "help" :: "mod" :: Nil ⇒ flash(member, modHelp)
|
||||
case "help" :: Nil ⇒ flash(member, help)
|
||||
|
||||
case "query" :: username :: _ ⇒ chat ! Query(member, username.toLowerCase)
|
||||
case "open" :: Nil ⇒ chat ! SetOpen(member, true)
|
||||
case "close" :: Nil ⇒ chat ! SetOpen(member, false)
|
||||
|
||||
case "join" :: chanKey :: _ ⇒ Chan parse chanKey match {
|
||||
case "query" :: username :: Nil ⇒ chat ! Query(member, username.toLowerCase)
|
||||
|
||||
case "join" :: chanKey :: Nil ⇒ Chan parse chanKey match {
|
||||
case Some(chan@TeamChan(teamId)) ⇒ getTeamIds(member.userId) foreach {
|
||||
case teamIds if teamIds.contains(teamId) ⇒ chat ! Join(member, chan)
|
||||
case _ ⇒ flash(member, s"You are not a member of this team.")
|
||||
|
@ -42,18 +48,18 @@ private[chat] final class Commander(
|
|||
case Some(chan) ⇒ chat ! Join(member, chan)
|
||||
case None ⇒ flash(member, s"The channel $chanKey does not exist.")
|
||||
}
|
||||
case "show" :: chanKey :: _ ⇒ Chan parse chanKey foreach { chan ⇒
|
||||
chat ! Activate(member, chan)
|
||||
}
|
||||
case "hide" :: chanKey :: _ ⇒ Chan parse chanKey foreach { chan ⇒
|
||||
chat ! DeActivate(member, chan)
|
||||
}
|
||||
|
||||
case "show" :: chanKey :: Nil ⇒ withChan(chanKey) { chan ⇒ chat ! Activate(member, chan) }
|
||||
case "hide" :: chanKey :: Nil ⇒ withChan(chanKey) { chan ⇒ chat ! DeActivate(member, chan) }
|
||||
|
||||
case "part" :: chanKey :: Nil ⇒ withChan(chanKey) { chan ⇒ chat ! Part(member, chan) }
|
||||
case "part" :: Nil ⇒ member.head.mainChanKey flatMap Chan.parse foreach { chan ⇒ chat ! Part(member, chan) }
|
||||
|
||||
case "say" :: words ⇒ chanOption foreach { chan ⇒ chat ! Say(chan, member, words mkString " ") }
|
||||
|
||||
case escaped :: _ if escaped.startsWith("/") ⇒ self ! command.copy(text = "say " + text)
|
||||
|
||||
case "names" :: _ ⇒ chanOption foreach { chan ⇒
|
||||
case "names" :: Nil ⇒ chanOption foreach { chan ⇒
|
||||
userOf(member) foreach { user ⇒
|
||||
namer.chan(chan, user) foreach { named ⇒
|
||||
chat ! WithChanNicks(chan.key, { nicks ⇒
|
||||
|
@ -63,10 +69,10 @@ private[chat] final class Commander(
|
|||
}
|
||||
}
|
||||
|
||||
case ("rematch" | "resign" | "abort" | "takeback") :: _ ⇒ gameOnlyCommand(member)
|
||||
case MoveRegex(orig, dest) :: _ ⇒ gameOnlyCommand(member)
|
||||
case ("rematch" | "resign" | "abort" | "takeback") :: Nil ⇒ gameOnlyCommand(member)
|
||||
case MoveRegex(orig, dest) :: Nil ⇒ gameOnlyCommand(member)
|
||||
|
||||
case "troll" :: username :: _ ⇒ Secure(member, _.MarkTroll) { me ⇒
|
||||
case "troll" :: username :: Nil ⇒ Secure(member, _.MarkTroll) { me ⇒
|
||||
modApi.troll(me.id, username) foreach { troll ⇒
|
||||
flash(member, s"User $username is ${troll.fold("now", "no longer")} a troll.")
|
||||
}
|
||||
|
@ -97,6 +103,10 @@ private[chat] final class Commander(
|
|||
private def userOf(member: ChatMember): Fu[User] =
|
||||
UserRepo byId member.userId flatten s"No such user: $member.userId"
|
||||
|
||||
private def withChan(key: String)(f: Chan ⇒ Unit) {
|
||||
Chan parse key foreach f
|
||||
}
|
||||
|
||||
val tutorial = "<pre>" + escapeXml("""
|
||||
_______________________ lichess chat _______________________
|
||||
The text input at the bottom can be used to command lichess!
|
||||
|
@ -108,6 +118,7 @@ For instance, try and send /help to see available commands.
|
|||
_______________________ chat commands ______________________
|
||||
/join <chan> enter a chat room. Ex: /join en
|
||||
/query <friend> start a private chat with a friend
|
||||
/part quit the current room
|
||||
/names show the users connected to the current room
|
||||
_______________________ user commands ______________________
|
||||
/msg <user> send a message to a user
|
||||
|
|
|
@ -11,6 +11,7 @@ case class SetOpen(member: ChatMember, value: Boolean)
|
|||
case class Query(member: ChatMember, username: String)
|
||||
|
||||
case class Join(member: ChatMember, chan: Chan)
|
||||
case class Part(member: ChatMember, chan: Chan)
|
||||
|
||||
case class Say(chan: Chan, member: ChatMember, text: String)
|
||||
|
||||
|
|
|
@ -857,7 +857,6 @@ var storage = {
|
|||
self.$invite = self.$form.find('.invite');
|
||||
self.$input = self.$form.find('input');
|
||||
|
||||
self.on = _lc_.on;
|
||||
self.systemUsername = 'Lichess';
|
||||
self.reload(_lc_);
|
||||
|
||||
|
@ -868,8 +867,11 @@ var storage = {
|
|||
self._tell();
|
||||
return false;
|
||||
});
|
||||
self.$chans.on('click', '.close', function() {
|
||||
self._part($(this).parent().data('chan'));
|
||||
});
|
||||
self.$chans.on('click', '.name', function() {
|
||||
self._join($(this).data('chan'));
|
||||
self._join($(this).parent().data('chan'));
|
||||
});
|
||||
self.$chans.on('click', 'input', function() {
|
||||
self._show($(this).attr('name'), $(this).prop('checked'));
|
||||
|
@ -877,7 +879,7 @@ var storage = {
|
|||
self.element.find('.help').click(function() {
|
||||
self._send('/help tutorial');
|
||||
});
|
||||
self.$bar.find('> *').click(function() {
|
||||
self.$bar.click(function() {
|
||||
self._send('/open');
|
||||
});
|
||||
self.element.find('> .off').click(function() {
|
||||
|
@ -913,17 +915,20 @@ var storage = {
|
|||
this.head = c.head;
|
||||
if (!this._exists(this.head.mainChan)) this.head.mainChan = null;
|
||||
this.lines = c.lines;
|
||||
this._renderChans();
|
||||
this._renderLines();
|
||||
this._renderForm();
|
||||
this._renderAll();
|
||||
},
|
||||
line: function(l) {
|
||||
var self = this;
|
||||
self.lines.push(l);
|
||||
var rendered = self._renderLine(l);
|
||||
if (l.chan.type == "user" && !self._isActive(l.chan.key)) {
|
||||
self._send('/show ' + l.chan.key);
|
||||
}
|
||||
self.$lines.append(self._renderLine(l)).scrollTop(999999);
|
||||
if (!self.$wrap.hasClass('on') && self._isActive(l.chan.key)) {
|
||||
self.$bar.find('.last').html('<span class="user">' + l.user + '</span> : <span class="text">' + l.html + '</span>');
|
||||
}
|
||||
self.$lines.append(rendered);
|
||||
self._scrollLines();
|
||||
},
|
||||
flash: function(html) {
|
||||
var self = this;
|
||||
|
@ -958,6 +963,9 @@ var storage = {
|
|||
else if (text == '/open') {
|
||||
self.$wrap.addClass('on');
|
||||
self._joinFirst();
|
||||
self._scrollLines();
|
||||
} else if (text == '/part' || text == '/leave') {
|
||||
if (self.head.mainChan) self._part(self.head.mainChan);
|
||||
} else if (text.match(/^\/msg\s(\w+)/)) {
|
||||
location.href = '/inbox/new?username=' + text.match(/^\/msg\s(\w+)/)[1];
|
||||
return;
|
||||
|
@ -990,8 +998,19 @@ var storage = {
|
|||
},
|
||||
_join: function(chan) {
|
||||
this._disablePlaceholder();
|
||||
if (this._isActive(chan)) { // immediate rendering
|
||||
this.head.mainChan = chan;
|
||||
this._renderAll();
|
||||
}
|
||||
this._send('/join ' + chan);
|
||||
},
|
||||
_part: function(chan) {
|
||||
delete this.head.chans[chan];
|
||||
this.head.activeChans = _.difference(this.head.activeChans, [chan]);
|
||||
if (this.head.mainChan == chan) this.head.mainChan = null;
|
||||
this._renderAll();
|
||||
this._send('/part ' + chan);
|
||||
},
|
||||
_chanIndex: function(key) {
|
||||
return _.keys(this.head.chans).indexOf(key);
|
||||
},
|
||||
|
@ -1004,6 +1023,11 @@ var storage = {
|
|||
_isActive: function(chan) {
|
||||
return _.contains(this.head.activeChans, chan);
|
||||
},
|
||||
_renderAll: function() {
|
||||
this._renderForm();
|
||||
this._renderChans();
|
||||
this._renderLines();
|
||||
},
|
||||
_renderLine: function(line) {
|
||||
var self = this;
|
||||
if (!self._isActive(line.chan.key)) return '';
|
||||
|
@ -1023,7 +1047,11 @@ var storage = {
|
|||
var self = this;
|
||||
self.$lines.html(_.map(self.lines, function(line) {
|
||||
return self._renderLine(line);
|
||||
}).join('')).scrollTop(999999);
|
||||
}).join(''));
|
||||
self._scrollLines();
|
||||
},
|
||||
_scrollLines: function() {
|
||||
this.$lines.scrollTop(999999);
|
||||
},
|
||||
_renderChans: function() {
|
||||
var self = this;
|
||||
|
@ -1032,12 +1060,13 @@ var storage = {
|
|||
var active = self.head.activeChans.indexOf(chan.key) != -1;
|
||||
var main = self.head.mainChan == chan.key;
|
||||
var color = self._colorClass(self._chanIndex(chan.key));
|
||||
return '<div class="chan ' + color + (main ? ' main' : '') + ' clearfix">' +
|
||||
return '<div data-chan="' + chan.key + '" class="chan ' + color + (main ? ' main' : '') + ' clearfix">' +
|
||||
'<a class="close">x</a>' +
|
||||
'<div class="check">' +
|
||||
'<input type="checkbox"' + (active ? " checked" : "") + ' id="' + id + '" name="' + chan.key + '"/>' +
|
||||
'<label for="' + id + '"></label>' +
|
||||
'</div>' +
|
||||
'<span data-chan="' + chan.key + '" class="name">' + chan.name + '</span>' +
|
||||
'<span class="name">' + chan.name + '</span>' +
|
||||
'</div>';
|
||||
}).join(''));
|
||||
},
|
||||
|
@ -1062,7 +1091,7 @@ var storage = {
|
|||
$.widget("lichess.teams", {
|
||||
_create: function() {
|
||||
var self = this;
|
||||
self.$list = self.element.find("div.list");
|
||||
self.$list = self.element.find("div.content");
|
||||
self.$list.on('click', 'a', function() {
|
||||
$('#chat').onechat('team', $(this).data('id'));
|
||||
});
|
||||
|
@ -1086,7 +1115,7 @@ var storage = {
|
|||
self.$title = self.options.$title;
|
||||
self.$nbOnline = self.$title.find('.online');
|
||||
self.$nbTotal = self.$title.find('.total');
|
||||
self.$list = self.element.find("div.list");
|
||||
self.$list = self.element.find("div.content");
|
||||
self.$nobody = self.element.find("div.nobody");
|
||||
self.set(self.element.data('preload'));
|
||||
},
|
||||
|
|
|
@ -437,49 +437,66 @@ div.footer div.right {
|
|||
position: fixed;
|
||||
bottom: 0;
|
||||
}
|
||||
#chat_wrap div.left {
|
||||
float: left;
|
||||
width: 220px;
|
||||
border-right: 1px solid #ccc;
|
||||
}
|
||||
#chat_wrap div.right {
|
||||
float: right;
|
||||
width: 220px;
|
||||
border-left: 1px solid #ccc;
|
||||
}
|
||||
#chat_wrap div.center {
|
||||
margin: 0 221px;
|
||||
}
|
||||
#chat_wrap > .bar {
|
||||
width: 100%;
|
||||
height: 32px;
|
||||
border-top: 1px solid #444;
|
||||
background: rgba(20, 20, 20, 0.9);
|
||||
border-top: 1px solid #ccc;
|
||||
background: rgba(230, 230, 230, 0.7);
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
}
|
||||
#chat_wrap.on > .bar {
|
||||
display: none;
|
||||
}
|
||||
#chat_wrap > .bar > * {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
display:inline-block;
|
||||
#chat_wrap > .bar:hover {
|
||||
background: #ccc;
|
||||
}
|
||||
#chat_wrap > .bar > div > * {
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
text-decoration: none;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
#chat_wrap > .bar > *:hover {
|
||||
background-color: #0a0a0a;
|
||||
}
|
||||
#chat_wrap > .bar > .on {
|
||||
left: 0;
|
||||
#chat_wrap > .bar .on {
|
||||
display:block;
|
||||
background: url(/assets/images/open32.png) top left no-repeat;
|
||||
background-position: +10px +1px;
|
||||
font-size: 1.2em;
|
||||
padding: 0 10px 0 46px;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
#chat_wrap > .bar > .friends {
|
||||
right: 0;
|
||||
width: 220px;
|
||||
#chat_wrap > .bar .last {
|
||||
display: block;
|
||||
}
|
||||
#chat_wrap > .bar .last > span {
|
||||
display: inline-block;
|
||||
margin-left: 10px;
|
||||
color: #505050;
|
||||
}
|
||||
#chat_wrap > .bar .friends {
|
||||
text-transform: capitalize;
|
||||
text-align: center;
|
||||
border-left: 1px solid #444;
|
||||
}
|
||||
#chat {
|
||||
width: 100%;
|
||||
height: 195px;
|
||||
border-top: 1px solid #444;
|
||||
border-top: 1px solid #ccc;
|
||||
position: relative;
|
||||
display: none;
|
||||
background: rgba(20, 20, 20, 0.9);
|
||||
background: #f0f0f0;
|
||||
box-shadow: 0 0 15px #888;
|
||||
}
|
||||
#chat_wrap.on #chat {
|
||||
display: block;
|
||||
|
@ -499,7 +516,7 @@ div.footer div.right {
|
|||
-webkit-transform: rotate(180deg);
|
||||
}
|
||||
#chat > .off:hover {
|
||||
background-color: #0a0a0a;
|
||||
background-color: #ccc;
|
||||
}
|
||||
#chat > .help {
|
||||
display: inline-block;
|
||||
|
@ -509,16 +526,13 @@ div.footer div.right {
|
|||
height: 16px;
|
||||
line-height: 16px;
|
||||
padding: 0 8px;
|
||||
border-top: 1px solid #444;
|
||||
border-right: 1px solid #444;
|
||||
border-top: 1px solid #ccc;
|
||||
border-right: 1px solid #ccc;
|
||||
text-decoration: none;
|
||||
background: rgba(20, 20, 20, 0.9);
|
||||
background: #f0f0f0;
|
||||
}
|
||||
#chat > .chans {
|
||||
float: left;
|
||||
width: 220px;
|
||||
height: 100%;
|
||||
border-right: 1px solid #444;
|
||||
}
|
||||
#chat .chan {
|
||||
display: block;
|
||||
|
@ -526,11 +540,11 @@ div.footer div.right {
|
|||
line-height: 27px;
|
||||
height: 27px;
|
||||
padding: 0px 10px;
|
||||
border-bottom: 1px solid #3a3a3a;
|
||||
border-bottom: 1px solid #ccc;
|
||||
cursor: pointer;
|
||||
}
|
||||
#chat .chan.main {
|
||||
background: #030303;
|
||||
background: #ccc;
|
||||
}
|
||||
#chat .chan > .name {
|
||||
display: block;
|
||||
|
@ -538,6 +552,21 @@ div.footer div.right {
|
|||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
#chat .chan > .close {
|
||||
text-decoration: none;
|
||||
float: left;
|
||||
display: none;
|
||||
height: 17px;
|
||||
line-height: 17px;
|
||||
margin: 3px 0 0 -7px;
|
||||
padding: 2px 8px;
|
||||
}
|
||||
#chat .chan:hover > .close {
|
||||
display: block;
|
||||
}
|
||||
#chat a.close:hover {
|
||||
background-color: #ccc;
|
||||
}
|
||||
#chat div.check {
|
||||
float: right;
|
||||
width: 20px;
|
||||
|
@ -557,8 +586,8 @@ div.footer div.right {
|
|||
border-radius: 4px;
|
||||
}
|
||||
#chat .chan:hover div.check label {
|
||||
background: linear-gradient(to bottom, #222 0%, #45484d 100%);
|
||||
box-shadow: inset 0px 1px 1px rgba(0, 0, 0, 0.5), 0px 1px 0px rgba(255, 255, 255, .4);
|
||||
background: #c5c8cd;
|
||||
background: linear-gradient(to bottom, #ccc 0%, #a5a8ad 100%);
|
||||
}
|
||||
#chat div.check label:after {
|
||||
opacity: 0;
|
||||
|
@ -569,7 +598,7 @@ div.footer div.right {
|
|||
background: transparent;
|
||||
top: 5px;
|
||||
left: 4px;
|
||||
border: 3px solid #fcfff4;
|
||||
border: 3px solid #0c0f04;
|
||||
border-top: none;
|
||||
border-right: none;
|
||||
transform: rotate(-45deg);
|
||||
|
@ -584,14 +613,10 @@ div.footer div.right {
|
|||
#chat .chan:hover div.check input[type=checkbox]:checked + label:after {
|
||||
opacity: 1;
|
||||
}
|
||||
#chat > .room {
|
||||
margin-left: 221px;
|
||||
margin-right: 221px;
|
||||
}
|
||||
#chat > .room > .lines {
|
||||
height: 167px;
|
||||
overflow: hidden;
|
||||
border-bottom: 1px solid #444;
|
||||
border-bottom: 1px solid #ccc;
|
||||
}
|
||||
#chat > .room > .lines:hover {
|
||||
overflow-y: auto;
|
||||
|
@ -601,7 +626,7 @@ div.footer div.right {
|
|||
padding: 1px 10px;
|
||||
position: relative;
|
||||
opacity: 0.7;
|
||||
color: #b0b0b0;
|
||||
color: #505050;
|
||||
}
|
||||
#chat .line.main {
|
||||
opacity: 1;
|
||||
|
@ -620,20 +645,17 @@ div.footer div.right {
|
|||
text-decoration: none;
|
||||
}
|
||||
#chat .line > .text {
|
||||
display: inline-block;
|
||||
display: inline;
|
||||
}
|
||||
#chat .line pre {
|
||||
margin: 0;
|
||||
}
|
||||
#chat > .lists {
|
||||
float: right;
|
||||
width: 220px;
|
||||
height: 100%;
|
||||
border-left: 1px solid #444;
|
||||
height: 195px;
|
||||
overflow: hidden;
|
||||
}
|
||||
#chat > .lists > .tabs {
|
||||
border-bottom: 1px solid #444;
|
||||
border-bottom: 1px solid #ccc;
|
||||
display: block;
|
||||
}
|
||||
#chat > .lists > .tabs > a {
|
||||
|
@ -644,12 +666,13 @@ div.footer div.right {
|
|||
padding: 0 10px;
|
||||
}
|
||||
#chat > .lists > .tabs > a.active {
|
||||
background-color: #202020;
|
||||
background-color: #ccc;
|
||||
}
|
||||
#chat .list_box {
|
||||
display: none;
|
||||
height: 100%;
|
||||
height: 175px;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
#chat .list_box:hover {
|
||||
overflow-y: auto;
|
||||
|
@ -662,7 +685,7 @@ div.footer div.right {
|
|||
overflow: hidden;
|
||||
}
|
||||
#chat .list_box .content a:hover {
|
||||
background-color: #202020;
|
||||
background-color: #ccc;
|
||||
}
|
||||
#friend_box .content .s16 {
|
||||
background-position: 0 -208px;
|
||||
|
@ -700,13 +723,13 @@ div.footer div.right {
|
|||
line-height: 27px;
|
||||
position: relative;
|
||||
margin-right: 12px;
|
||||
background: #0a0a0a;
|
||||
background: #ccc;
|
||||
}
|
||||
#chat .controls > form .invite:after {
|
||||
content:"";
|
||||
border-top: 14px solid transparent;
|
||||
border-bottom: 14px solid transparent;
|
||||
border-left: 14px solid #0a0a0a;
|
||||
border-left: 14px solid #ccc;
|
||||
position: absolute;
|
||||
right: -14px;
|
||||
top: 0;
|
||||
|
@ -718,7 +741,7 @@ div.footer div.right {
|
|||
height: 19px;
|
||||
padding: 4px 10px;
|
||||
border: none;
|
||||
color: #b0b0b0;
|
||||
color: #505050;
|
||||
background: none;
|
||||
}
|
||||
#chat .color0 {
|
||||
|
|
|
@ -156,9 +156,37 @@ body.dark a#sound_state.sound_state_on span {
|
|||
body.dark .s16.ddown {
|
||||
background-position: right -368px;
|
||||
}
|
||||
body.dark #chat .chan {
|
||||
border-color: #2a2a2a;
|
||||
body.dark #chat {
|
||||
box-shadow: 0 0 15px #000;
|
||||
}
|
||||
body.dark #chat_wrap > .bar {
|
||||
background: rgba(20, 20, 20, 0.9);
|
||||
}
|
||||
body.dark #chat, body.dark #chat > .help {
|
||||
background: #101010;
|
||||
}
|
||||
body.dark #chat > .lists > .tabs, body.dark #chat > .room > .lines, body.dark #chat, body.dark #chat .chan, body.dark #chat_wrap > .bar, body.dark #chat > .help, body.dark #chat_wrap div.left, body.dark #chat_wrap div.right, body.dark #chat_wrap div.left {
|
||||
border-color: #303030;
|
||||
}
|
||||
body.dark #chat .controls > form .invite, body.dark #chat .list_box .content a:hover, body.dark #chat > .lists > .tabs > a.active, body.dark #chat .chan.main, body.dark #chat a.close:hover, body.dark #chat_wrap > .bar:hover, body.dark #chat > .off:hover {
|
||||
background-color: #0a0a0a;
|
||||
}
|
||||
body.dark #chat .controls > form .invite:after {
|
||||
border-left-color: #0a0a0a;
|
||||
}
|
||||
body.dark #chat .chan:hover div.check label {
|
||||
background-color: #45484d;
|
||||
}
|
||||
body.dark #chat div.check label:after {
|
||||
border-color: #fcfff4;
|
||||
}
|
||||
body.dark #chat_wrap > .bar .last > span, body.dark #chat .controls > form .input, body.dark #chat .line {
|
||||
color: #b0b0b0;
|
||||
}
|
||||
body.dark #chat .line.sys {
|
||||
color: #808080;
|
||||
}
|
||||
|
||||
body.dark ::-webkit-input-placeholder {
|
||||
color: #666;
|
||||
}
|
||||
|
|
5
todo
5
todo
|
@ -106,11 +106,8 @@ time pie chart colors http://en.lichess.org/52ede6hu/stats
|
|||
full page recent forum posts
|
||||
en_GB, en_US, pt_PT, pt_BR = localization
|
||||
/takeback to accept (or sys message)
|
||||
chat multiline
|
||||
badges out of screen
|
||||
chat click user to chat
|
||||
try to switch chan without server
|
||||
chat links = new tab
|
||||
moretime button position (>1hour)
|
||||
move command sys message
|
||||
abort system message
|
||||
|
@ -119,6 +116,8 @@ copy rematch chats
|
|||
chat logs
|
||||
maybe no chat transparency?
|
||||
indicator when someone talks to you but the chat is closed
|
||||
user badge is too large; also add a link to profile to it
|
||||
chat visited link color
|
||||
|
||||
deploy
|
||||
------
|
||||
|
|
Loading…
Reference in a new issue