mirror of
https://github.com/moparisthebest/kaiwa
synced 2024-08-13 17:03:51 -04:00
Groupchat with avatars and nicknames autocomplete
This commit is contained in:
parent
44c9235ea2
commit
e3460cec6e
@ -91,6 +91,15 @@ module.exports = HumanModel.define({
|
|||||||
this._activeContact = curr.id;
|
this._activeContact = curr.id;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
getName: function () {
|
||||||
|
return this.displayName;
|
||||||
|
},
|
||||||
|
getNickname: function () {
|
||||||
|
return this.displayName != this.nick ? this.nick : '';
|
||||||
|
},
|
||||||
|
getAvatar: function () {
|
||||||
|
return this.avatar;
|
||||||
|
},
|
||||||
setAvatar: function (id, type, source) {
|
setAvatar: function (id, type, source) {
|
||||||
var self = this;
|
var self = this;
|
||||||
fetchAvatar('', id, type, source, function (avatar) {
|
fetchAvatar('', id, type, source, function (avatar) {
|
||||||
@ -102,7 +111,10 @@ module.exports = HumanModel.define({
|
|||||||
this.soundEnabled = enable;
|
this.soundEnabled = enable;
|
||||||
},
|
},
|
||||||
getContact: function (jid, alt) {
|
getContact: function (jid, alt) {
|
||||||
if (typeof jid === 'string') jid = new client.JID(jid);
|
if (typeof jid === 'string') {
|
||||||
|
if (SERVER_CONFIG.domain && jid.indexOf('@') == -1) jid += '@' + SERVER_CONFIG.domain;
|
||||||
|
jid = new client.JID(jid);
|
||||||
|
}
|
||||||
if (typeof alt === 'string') alt = new client.JID(alt);
|
if (typeof alt === 'string') alt = new client.JID(alt);
|
||||||
|
|
||||||
if (this.isMe(jid)) {
|
if (this.isMe(jid)) {
|
||||||
|
@ -76,6 +76,27 @@ module.exports = HumanModel.define({
|
|||||||
resources: Resources,
|
resources: Resources,
|
||||||
messages: Messages
|
messages: Messages
|
||||||
},
|
},
|
||||||
|
getName: function (jid) {
|
||||||
|
var nickname = jid.split('/')[1];
|
||||||
|
var name = nickname;
|
||||||
|
var xmppContact = me.getContact(nickname);
|
||||||
|
if (xmppContact) {
|
||||||
|
name = xmppContact.displayName;
|
||||||
|
}
|
||||||
|
return name != '' ? name : nickname;
|
||||||
|
},
|
||||||
|
getNickname: function (jid) {
|
||||||
|
var nickname = jid.split('/')[1];
|
||||||
|
return nickname != this.getName(jid) ? nickname : '';
|
||||||
|
},
|
||||||
|
getAvatar: function (jid) {
|
||||||
|
var avatar = "";
|
||||||
|
var xmppContact = me.getContact(jid.split('/')[1]);
|
||||||
|
if (xmppContact) {
|
||||||
|
avatar = xmppContact.avatar;
|
||||||
|
}
|
||||||
|
return avatar || 'https://gravatar.com/avatar';
|
||||||
|
},
|
||||||
addMessage: function (message, notify) {
|
addMessage: function (message, notify) {
|
||||||
message.owner = me.jid.bare;
|
message.owner = me.jid.bare;
|
||||||
|
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
var BaseCollection = require('./baseCollection');
|
var BaseCollection = require('./baseCollection');
|
||||||
var Resource = require('./resource');
|
var Resource = require('./resource');
|
||||||
|
|
||||||
|
|
||||||
module.exports = BaseCollection.extend({
|
module.exports = BaseCollection.extend({
|
||||||
type: 'resources',
|
type: 'resources',
|
||||||
model: Resource,
|
model: Resource,
|
||||||
@ -42,5 +41,20 @@ module.exports = BaseCollection.extend({
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
|
},
|
||||||
|
search : function (letters, removeMe, addAll) {
|
||||||
|
if(letters == "" && !removeMe) return this;
|
||||||
|
|
||||||
|
var collection = new module.exports(this.models);
|
||||||
|
if (addAll)
|
||||||
|
collection.add({id: this.parent.jid.bare + '/all'});
|
||||||
|
|
||||||
|
var pattern = new RegExp('^' + letters + '.*$', "i");
|
||||||
|
var filtered = collection.filter(function(data) {
|
||||||
|
var nick = data.get("mucDisplayName");
|
||||||
|
if (nick === me.nick) return false;
|
||||||
|
return pattern.test(nick);
|
||||||
|
});
|
||||||
|
return new module.exports(filtered);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -80,12 +80,15 @@ module.exports = BasePage.extend({
|
|||||||
this.$chatInput.val(app.composing[this.model.jid] || '');
|
this.$chatInput.val(app.composing[this.model.jid] || '');
|
||||||
this.$chatBox = this.$('.chatBox');
|
this.$chatBox = this.$('.chatBox');
|
||||||
this.$messageList = this.$('.messages');
|
this.$messageList = this.$('.messages');
|
||||||
|
this.$autoComplete = this.$('.autoComplete');
|
||||||
|
|
||||||
this.staydown = new StayDown(this.$messageList[0], 500);
|
this.staydown = new StayDown(this.$messageList[0], 500);
|
||||||
|
|
||||||
this.renderMessages();
|
this.renderMessages();
|
||||||
|
|
||||||
this.renderCollection(this.model.resources, MUCRosterItem, this.$('.groupRoster'));
|
this.renderCollection(this.model.resources, MUCRosterItem, this.$('.groupRoster'));
|
||||||
|
|
||||||
|
this.listenTo(this, 'rosterItemClicked', this.rosterItemSelected);
|
||||||
this.listenTo(this.model.messages, 'add', this.handleChatAdded);
|
this.listenTo(this.model.messages, 'add', this.handleChatAdded);
|
||||||
|
|
||||||
$(window).on('resize', _.bind(this.resizeInput, this));
|
$(window).on('resize', _.bind(this.resizeInput, this));
|
||||||
@ -117,19 +120,47 @@ module.exports = BasePage.extend({
|
|||||||
},
|
},
|
||||||
handleKeyDown: function (e) {
|
handleKeyDown: function (e) {
|
||||||
if (e.which === 13 && !e.shiftKey) {
|
if (e.which === 13 && !e.shiftKey) {
|
||||||
app.composing[this.model.jid] = '';
|
if (this.$autoComplete.css('display') != 'none') {
|
||||||
this.sendChat();
|
var nickname = this.$autoComplete.find(">:nth-child(" + this.autoCompletePos + ")>:first-child").text();
|
||||||
|
this.rosterItemSelected(nickname);
|
||||||
|
} else {
|
||||||
|
app.composing[this.model.jid] = '';
|
||||||
|
this.sendChat();
|
||||||
|
}
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
return false;
|
return false;
|
||||||
} else if (e.which === 38 && this.$chatInput.val() === '' && this.model.lastSentMessage) {
|
} else if (e.which === 38) { // Up arrow
|
||||||
this.editMode = true;
|
|
||||||
this.$chatInput.addClass('editing');
|
if (this.$autoComplete.css('display') != 'none') {
|
||||||
this.$chatInput.val(this.model.lastSentMessage.body);
|
var count = this.$autoComplete.find(">li").length;
|
||||||
|
var oldPos = this.autoCompletePos;
|
||||||
|
this.autoCompletePos = (oldPos - 1) < 1 ? count : oldPos - 1;
|
||||||
|
|
||||||
|
this.$autoComplete.find(">:nth-child(" + oldPos + ")").removeClass('selected');
|
||||||
|
this.$autoComplete.find(">:nth-child(" + this.autoCompletePos + ")").addClass('selected');
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (this.$chatInput.val() === '' && this.model.lastSentMessage) {
|
||||||
|
this.editMode = true;
|
||||||
|
this.$chatInput.addClass('editing');
|
||||||
|
this.$chatInput.val(this.model.lastSentMessage.body);
|
||||||
|
}
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
return false;
|
return false;
|
||||||
} else if (e.which === 40 && this.editMode) {
|
} else if (e.which === 40) { // Down arrow
|
||||||
this.editMode = false;
|
|
||||||
this.$chatInput.removeClass('editing');
|
if (this.$autoComplete.css('display') != 'none') {
|
||||||
|
var count = this.$autoComplete.find(">li").length;
|
||||||
|
var oldPos = this.autoCompletePos;
|
||||||
|
this.autoCompletePos = (oldPos + 1) > count ? 1 : oldPos + 1;
|
||||||
|
|
||||||
|
this.$autoComplete.find(">:nth-child(" + oldPos + ")").removeClass('selected');
|
||||||
|
this.$autoComplete.find(">:nth-child(" + this.autoCompletePos + ")").addClass('selected');
|
||||||
|
}
|
||||||
|
else if (this.editMode) {
|
||||||
|
this.editMode = false;
|
||||||
|
this.$chatInput.removeClass('editing');
|
||||||
|
}
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
return false;
|
return false;
|
||||||
} else if (!e.ctrlKey && !e.metaKey) {
|
} else if (!e.ctrlKey && !e.metaKey) {
|
||||||
@ -158,6 +189,43 @@ module.exports = BasePage.extend({
|
|||||||
} else if (this.typing) {
|
} else if (this.typing) {
|
||||||
this.pausedTyping();
|
this.pausedTyping();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (([38, 40, 13]).indexOf(e.which) === -1) {
|
||||||
|
var lastWord = this.$chatInput.val().split(' ').pop();
|
||||||
|
if (lastWord.charAt(0) === '@') {
|
||||||
|
var models = this.model.resources.search(lastWord.substr(1) || '', true, true);
|
||||||
|
if (models.length) {
|
||||||
|
this.renderCollection(models, MUCRosterItem, this.$autoComplete);
|
||||||
|
this.autoCompletePos = 1;
|
||||||
|
this.$autoComplete.find(">:nth-child(" + this.autoCompletePos + ")").addClass('selected');
|
||||||
|
this.$autoComplete.show();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
this.$autoComplete.hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.$autoComplete.css('display') != 'none') {
|
||||||
|
if( lastWord === '') {
|
||||||
|
this.$autoComplete.hide();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
rosterItemSelected: function (nickName) {
|
||||||
|
if (nickName == me.nick)
|
||||||
|
nickName = 'me';
|
||||||
|
var val = this.$chatInput.val();
|
||||||
|
var splited = val.split(' ');
|
||||||
|
var length = splited.length-1;
|
||||||
|
var lastWord = splited.pop();
|
||||||
|
if (('@' + nickName).indexOf(lastWord) > -1)
|
||||||
|
splited[length] = '@' + nickName + ' ';
|
||||||
|
else
|
||||||
|
splited.push('@' + nickName + ' ');
|
||||||
|
this.$chatInput.val(splited.join(' '));
|
||||||
|
this.$autoComplete.hide();
|
||||||
|
this.$chatInput.focus();
|
||||||
},
|
},
|
||||||
resizeInput: _.throttle(function () {
|
resizeInput: _.throttle(function () {
|
||||||
var height;
|
var height;
|
||||||
|
@ -313,14 +313,14 @@ exports.includes.mucWrappedMessage = function anonymous(locals) {
|
|||||||
with (locals || {}) {
|
with (locals || {}) {
|
||||||
var messageDate = Date.create(message.timestamp);
|
var messageDate = Date.create(message.timestamp);
|
||||||
buf.push('<li><div class="sender"><a href="#" class="messageAvatar"><img' + jade.attrs({
|
buf.push('<li><div class="sender"><a href="#" class="messageAvatar"><img' + jade.attrs({
|
||||||
src: "https://gravatar.com/avatar",
|
src: message.sender.getAvatar(message.from.full),
|
||||||
alt: message.from.resource,
|
alt: message.from.resource,
|
||||||
"data-placement": "below"
|
"data-placement": "below"
|
||||||
}, {
|
}, {
|
||||||
src: true,
|
src: true,
|
||||||
alt: true,
|
alt: true,
|
||||||
"data-placement": true
|
"data-placement": true
|
||||||
}) + '/></a></div><div class="messageWrapper"><div class="message_header"><div class="name">' + jade.escape((jade.interp = message.from.resource) == null ? "" : jade.interp) + "</div><div" + jade.attrs({
|
}) + '/></a></div><div class="messageWrapper"><div class="message_header"><div class="name">' + jade.escape((jade.interp = message.sender.getName(message.from.full)) == null ? "" : jade.interp) + '</div><div class="nickname">' + jade.escape((jade.interp = message.sender.getNickname(message.from.full)) == null ? "" : jade.interp) + "</div><div" + jade.attrs({
|
||||||
title: messageDate.format("{Dow}, {MM}/{dd}/{yyyy} - {h}:{mm} {Tt}"),
|
title: messageDate.format("{Dow}, {MM}/{dd}/{yyyy} - {h}:{mm} {Tt}"),
|
||||||
"class": "date"
|
"class": "date"
|
||||||
}, {
|
}, {
|
||||||
@ -503,7 +503,7 @@ exports.pages.chat = function anonymous(locals) {
|
|||||||
exports.pages.groupchat = function anonymous(locals) {
|
exports.pages.groupchat = function anonymous(locals) {
|
||||||
var buf = [];
|
var buf = [];
|
||||||
with (locals || {}) {
|
with (locals || {}) {
|
||||||
buf.push('<section class="page chat"><section class="group conversation"><header class="online"><div class="title"><span class="prefix">#</span><span class="name"></span><i class="channel_actions fa fa-comments-o"></i><span contenteditable="true" spellcheck="false" class="status"></span></div></header><ul class="messages"></ul><a id="members_toggle"><i class="fa fa-user"></i><span id="members_toggle_count"></span></a><ul class="groupRoster"></ul><div class="chatBox"><form class="formwrap"><textarea name="chatInput" type="text" placeholder="Send a message..." autocomplete="off"></textarea></form></div></section></section>');
|
buf.push('<section class="page chat"><section class="group conversation"><header class="online"><div class="title"><span class="prefix">#</span><span class="name"></span><i class="channel_actions fa fa-comments-o"></i><span contenteditable="true" spellcheck="false" class="status"></span></div></header><ul class="messages"></ul><a id="members_toggle"><i class="fa fa-user"></i><span id="members_toggle_count"></span></a><ul class="groupRoster"></ul><div class="chatBox"><ul class="autoComplete"></ul><form class="formwrap"><textarea name="chatInput" type="text" placeholder="Send a message..." autocomplete="off"></textarea></form></div></section></section>');
|
||||||
}
|
}
|
||||||
return buf.join("");
|
return buf.join("");
|
||||||
};
|
};
|
||||||
|
@ -2,9 +2,10 @@
|
|||||||
li
|
li
|
||||||
.sender
|
.sender
|
||||||
a.messageAvatar(href='#')
|
a.messageAvatar(href='#')
|
||||||
img(src="https://gravatar.com/avatar", alt=message.from.resource, data-placement="below")
|
img(src=message.sender.getAvatar(message.from.full), alt=message.from.resource, data-placement="below")
|
||||||
.messageWrapper
|
.messageWrapper
|
||||||
.message_header
|
.message_header
|
||||||
.name #{message.from.resource}
|
.name #{message.sender.getName(message.from.full)}
|
||||||
|
.nickname #{message.sender.getNickname(message.from.full)}
|
||||||
.date(title=messageDate.format('{Dow}, {MM}/{dd}/{yyyy} - {h}:{mm} {Tt}')) #{messageDate.format('{h}:{mm} {tt}')}
|
.date(title=messageDate.format('{Dow}, {MM}/{dd}/{yyyy} - {h}:{mm} {Tt}')) #{messageDate.format('{h}:{mm} {tt}')}
|
||||||
include mucBareMessage
|
include mucBareMessage
|
||||||
|
@ -12,5 +12,6 @@ section.page.chat
|
|||||||
span#members_toggle_count
|
span#members_toggle_count
|
||||||
ul.groupRoster
|
ul.groupRoster
|
||||||
.chatBox
|
.chatBox
|
||||||
|
ul.autoComplete
|
||||||
form.formwrap
|
form.formwrap
|
||||||
textarea(name='chatInput', type='text', placeholder='Send a message...', autocomplete='off')
|
textarea(name='chatInput', type='text', placeholder='Send a message...', autocomplete='off')
|
||||||
|
@ -8,6 +8,9 @@ var templates = require('../templates');
|
|||||||
|
|
||||||
module.exports = HumanView.extend({
|
module.exports = HumanView.extend({
|
||||||
template: templates.includes.mucRosterItem,
|
template: templates.includes.mucRosterItem,
|
||||||
|
events: {
|
||||||
|
'click': 'handleClick'
|
||||||
|
},
|
||||||
classBindings: {
|
classBindings: {
|
||||||
show: '',
|
show: '',
|
||||||
chatState: '',
|
chatState: '',
|
||||||
@ -19,5 +22,8 @@ module.exports = HumanView.extend({
|
|||||||
render: function () {
|
render: function () {
|
||||||
this.renderAndBind({contact: this.model});
|
this.renderAndBind({contact: this.model});
|
||||||
return this;
|
return this;
|
||||||
|
},
|
||||||
|
handleClick: function (e) {
|
||||||
|
this.parent.trigger('rosterItemClicked', this.model.mucDisplayName);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1154,6 +1154,40 @@ button.secondary:hover:not(:disabled) {
|
|||||||
transition: none;
|
transition: none;
|
||||||
-webkit-transition: none;
|
-webkit-transition: none;
|
||||||
}
|
}
|
||||||
|
.conversation .chatBox .autoComplete {
|
||||||
|
display: none;
|
||||||
|
position: fixed;
|
||||||
|
left: 245px;
|
||||||
|
bottom: 64px;
|
||||||
|
border: 2px solid #ddd;
|
||||||
|
border-bottom: 0;
|
||||||
|
border-radius: 0.25rem 0.25rem 0 0;
|
||||||
|
background-color: #fff;
|
||||||
|
z-index: 100;
|
||||||
|
list-style-type: none;
|
||||||
|
padding: 3px;
|
||||||
|
margin: 0px;
|
||||||
|
}
|
||||||
|
.conversation .chatBox .autoComplete li {
|
||||||
|
padding: 3px 25px;
|
||||||
|
margin: 0px;
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
position: relative;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.conversation .chatBox .autoComplete li:hover,
|
||||||
|
.conversation .chatBox .autoComplete li.selected {
|
||||||
|
background-color: #439fe0;
|
||||||
|
}
|
||||||
|
.conversation .chatBox .autoComplete li:hover .name,
|
||||||
|
.conversation .chatBox .autoComplete li.selected .name {
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
.conversation .chatBox .autoComplete li .name {
|
||||||
|
color: #9e9ea6;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
.conversation .chatBox .formwrap {
|
.conversation .chatBox .formwrap {
|
||||||
transition: none;
|
transition: none;
|
||||||
-webkit-transition: none;
|
-webkit-transition: none;
|
||||||
@ -1312,15 +1346,32 @@ button.secondary:hover:not(:disabled) {
|
|||||||
}
|
}
|
||||||
.messages .messageWrapper .message_header .name {
|
.messages .messageWrapper .message_header .name {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
margin-right: 0.25rem;
|
||||||
font-weight: 900;
|
font-weight: 900;
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
color: #3d3c40;
|
color: #3d3c40;
|
||||||
line-height: 22px;
|
line-height: 22px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
.messages .messageWrapper .message_header .name:empty {
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
.messages .messageWrapper .message_header .nickname {
|
||||||
|
display: inline-block;
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #9e9ea6;
|
||||||
|
line-height: 22px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.messages .messageWrapper .message_header .nickname:not(:empty) {
|
||||||
|
margin-right: 0.25rem;
|
||||||
|
}
|
||||||
|
.messages .messageWrapper .message_header .nickname:not(:empty):before {
|
||||||
|
content: '@';
|
||||||
|
}
|
||||||
.messages .messageWrapper .message_header .date {
|
.messages .messageWrapper .message_header .date {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
margin-left: 0.25rem;
|
|
||||||
color: #babbbf;
|
color: #babbbf;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
width: 60px;
|
width: 60px;
|
||||||
|
@ -194,6 +194,37 @@
|
|||||||
transition: none
|
transition: none
|
||||||
-webkit-transition: none
|
-webkit-transition: none
|
||||||
|
|
||||||
|
.autoComplete
|
||||||
|
display: none
|
||||||
|
position: fixed
|
||||||
|
left: 245px
|
||||||
|
bottom: 64px
|
||||||
|
border: 2px solid #ddd
|
||||||
|
border-bottom: 0
|
||||||
|
border-radius: 0.25rem 0.25rem 0 0
|
||||||
|
background-color: #fff
|
||||||
|
z-index: 100
|
||||||
|
list-style-type: none
|
||||||
|
padding: 3px
|
||||||
|
margin: 0px
|
||||||
|
|
||||||
|
li
|
||||||
|
padding: 3px 25px
|
||||||
|
margin: 0px
|
||||||
|
border-radius: 0.25rem
|
||||||
|
position: relative
|
||||||
|
cursor: pointer
|
||||||
|
|
||||||
|
&:hover, &.selected
|
||||||
|
background-color: #439FE0
|
||||||
|
.name
|
||||||
|
color: #fff
|
||||||
|
|
||||||
|
.name
|
||||||
|
color: $gray
|
||||||
|
font-size: 14px
|
||||||
|
font-weight: bold
|
||||||
|
|
||||||
.formwrap
|
.formwrap
|
||||||
transition: none
|
transition: none
|
||||||
-webkit-transition: none
|
-webkit-transition: none
|
||||||
@ -344,15 +375,29 @@
|
|||||||
|
|
||||||
.name
|
.name
|
||||||
display: inline-block
|
display: inline-block
|
||||||
|
margin-right: 0.25rem
|
||||||
font-weight: $font-weight-bolder
|
font-weight: $font-weight-bolder
|
||||||
font-size: $font-size-message
|
font-size: $font-size-message
|
||||||
color: $black
|
color: $black
|
||||||
line-height: 22px
|
line-height: 22px
|
||||||
cursor: pointer
|
cursor: pointer
|
||||||
|
&:empty
|
||||||
|
margin-right: 0
|
||||||
|
|
||||||
|
.nickname
|
||||||
|
display: inline-block
|
||||||
|
font-weight: $font-weight-classic
|
||||||
|
font-size: $font-size-base
|
||||||
|
color: $gray
|
||||||
|
line-height: 22px
|
||||||
|
cursor: pointer
|
||||||
|
&:not(:empty)
|
||||||
|
margin-right: 0.25rem
|
||||||
|
&:before
|
||||||
|
content: '@'
|
||||||
|
|
||||||
.date
|
.date
|
||||||
display: inline-block
|
display: inline-block
|
||||||
margin-left: 0.25rem
|
|
||||||
color: $gray-light
|
color: $gray-light
|
||||||
font-size: $font-size-small
|
font-size: $font-size-small
|
||||||
width: 60px
|
width: 60px
|
||||||
|
Loading…
Reference in New Issue
Block a user