msg convo actions
parent
26bbf71694
commit
25e869f71b
|
@ -0,0 +1,4 @@
|
|||
<svg viewBox="-1 -1 52 52" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill="#000000" stroke="#000000" stroke-linejoin="round" style="stroke-width:3"
|
||||
d="M38.956.5c-3.53.418-6.452.902-9.286 2.984C5.534 1.786-.692 18.533.68 29.364 3.493 50.214 31.918 55.785 41.329 41.7c-7.444 7.696-19.276 8.752-28.323 3.084C3.959 39.116-.506 27.392 4.683 17.567 9.873 7.742 18.996 4.535 29.03 6.405c2.43-1.418 5.225-3.22 7.655-3.187l-1.694 4.86 12.752 21.37c-.439 5.654-5.459 6.112-5.459 6.112-.574-1.47-1.634-2.942-4.842-6.036-3.207-3.094-17.465-10.177-15.788-16.207-2.001 6.967 10.311 14.152 14.04 17.663 3.73 3.51 5.426 6.04 5.795 6.756 0 0 9.392-2.504 7.838-8.927L37.4 7.171z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 671 B |
|
@ -5,11 +5,11 @@
|
|||
@extend %flex-column;
|
||||
flex: 1 1 100%;
|
||||
&__head {
|
||||
@extend %flex-center;
|
||||
@extend %flex-between;
|
||||
flex: 0 0 $msg-top-height;
|
||||
background: $c-bg-zebra2;
|
||||
border-bottom: $border;
|
||||
padding: 0 1vw;
|
||||
padding: 0 1.5em 0 1vw;
|
||||
.user-link {
|
||||
@extend %flex-center-nowrap;
|
||||
flex: 0 0 auto;
|
||||
|
@ -23,6 +23,15 @@
|
|||
font-size: 1.5em;
|
||||
}
|
||||
}
|
||||
&__actions {
|
||||
@extend %flex-center;
|
||||
}
|
||||
}
|
||||
&__action.button {
|
||||
color: $c-font;
|
||||
&.bad:hover {
|
||||
color: $c-bad;
|
||||
}
|
||||
}
|
||||
&__reply {
|
||||
@extend %flex-center-nowrap;
|
||||
|
@ -37,6 +46,11 @@
|
|||
background: $c-bg-box;
|
||||
resize: none;
|
||||
}
|
||||
&__block {
|
||||
flex: 1 1 auto;
|
||||
text-align: center;
|
||||
margin: .6em;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -55,4 +55,14 @@ export default class MsgCtrl {
|
|||
this.redraw();
|
||||
}
|
||||
}
|
||||
|
||||
block = () => {
|
||||
const userId = this.data.convo?.thread.contact.id;
|
||||
if (userId) network.block(userId).then(() => this.openConvo(userId));
|
||||
}
|
||||
|
||||
unblock = () => {
|
||||
const userId = this.data.convo?.thread.contact.id;
|
||||
if (userId) network.unblock(userId).then(() => this.openConvo(userId));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,6 +36,20 @@ export function search(q: string) {
|
|||
});
|
||||
}
|
||||
|
||||
export function block(u: string) {
|
||||
return $.ajax({
|
||||
url: `/rel/block/${u}`,
|
||||
method: 'post'
|
||||
});
|
||||
}
|
||||
|
||||
export function unblock(u: string) {
|
||||
return $.ajax({
|
||||
url: `/rel/unblock/${u}`,
|
||||
method: 'post'
|
||||
});
|
||||
}
|
||||
|
||||
export function post(dest: string, text: string) {
|
||||
window.lichess.pubsub.emit('socket.send', 'msgSend', { dest, text });
|
||||
}
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
import { h } from 'snabbdom'
|
||||
import { VNode } from 'snabbdom/vnode'
|
||||
import { Convo } from '../interfaces'
|
||||
import { bind } from './util';
|
||||
import MsgCtrl from '../ctrl';
|
||||
|
||||
export default function renderActions(ctrl: MsgCtrl, convo: Convo): VNode[] {
|
||||
const user = convo.thread.contact, nodes = [];
|
||||
const cls = 'msg-app__convo__action.button.button-empty';
|
||||
nodes.push(
|
||||
h(`a.${cls}`, {
|
||||
key: 'play',
|
||||
attrs: {
|
||||
'data-icon': 'U',
|
||||
href: `/?user=${user.name}#friend`,
|
||||
title: ctrl.trans.noarg('challengeToPlay')
|
||||
}
|
||||
})
|
||||
);
|
||||
if (convo.relations.out === false) nodes.push(
|
||||
h(`button.${cls}.unbad.text.hover-text`, {
|
||||
key: 'unblock',
|
||||
attrs: {
|
||||
'data-icon': 'k',
|
||||
title: ctrl.trans.noarg('blocked'),
|
||||
'data-hover-text': ctrl.trans.noarg('unblock')
|
||||
},
|
||||
hook: bind('click', ctrl.unblock)
|
||||
})
|
||||
);
|
||||
else nodes.push(
|
||||
h(`button.${cls}.bad`, {
|
||||
key: 'block',
|
||||
attrs: {
|
||||
'data-icon': 'k',
|
||||
title: ctrl.trans.noarg('block')
|
||||
},
|
||||
hook: bind('click', ctrl.block)
|
||||
})
|
||||
);
|
||||
nodes.push(
|
||||
h(`button.${cls}.bad.confirm`, {
|
||||
key: 'report',
|
||||
attrs: {
|
||||
'data-icon': '!',
|
||||
href: '/report/flag',
|
||||
title: ctrl.trans.noarg('report')
|
||||
}
|
||||
})
|
||||
);
|
||||
return nodes;
|
||||
}
|
|
@ -3,7 +3,8 @@ import { VNode } from 'snabbdom/vnode'
|
|||
import { Convo } from '../interfaces'
|
||||
import { userName } from './util';
|
||||
import renderMsgs from './msgs';
|
||||
import throttle from 'common/throttle';
|
||||
import renderActions from './actions';
|
||||
import renderTextarea from './textarea';
|
||||
import MsgCtrl from '../ctrl';
|
||||
|
||||
export default function renderConvo(ctrl: MsgCtrl, convo: Convo): VNode {
|
||||
|
@ -26,109 +27,11 @@ export default function renderConvo(ctrl: MsgCtrl, convo: Convo): VNode {
|
|||
]),
|
||||
renderMsgs(ctrl, convo.msgs),
|
||||
h('div.msg-app__convo__reply', [
|
||||
h('textarea.msg-app__convo__reply__text', {
|
||||
attrs: {
|
||||
rows: 1,
|
||||
autofocus: 1
|
||||
},
|
||||
hook: {
|
||||
insert(vnode) {
|
||||
setupTextarea(vnode.elm as HTMLTextAreaElement, user.id, ctrl.post);
|
||||
}
|
||||
}
|
||||
})
|
||||
convo.relations.out === false || convo.relations.in === false ?
|
||||
h('div.msg-app__convo__reply__block.text', {
|
||||
attrs: { 'data-icon': 'k' }
|
||||
}, 'This conversation is blocked.') :
|
||||
renderTextarea(ctrl, user)
|
||||
])
|
||||
]);
|
||||
}
|
||||
|
||||
function renderActions(ctrl: MsgCtrl, convo: Convo): VNode[] {
|
||||
const user = convo.thread.contact, nodes = [];
|
||||
if (convo.relations.out) nodes.push(
|
||||
h('button.msg-app__convo__action.text.hover-text', {
|
||||
attrs: {
|
||||
'data-icon': 'h',
|
||||
href: `/rel/unfollow/${user.id}`,
|
||||
title: ctrl.trans.noarg('following'),
|
||||
'data-hover-text': ctrl.trans.noarg('unfollow')
|
||||
}
|
||||
})
|
||||
);
|
||||
else if (convo.relations.out === false) nodes.push(
|
||||
h('button.msg-app__convo__action.text.hover-text', {
|
||||
attrs: {
|
||||
'data-icon': 'k',
|
||||
href: `/rel/unblock/${user.id}`,
|
||||
title: ctrl.trans.noarg('blocked'),
|
||||
'data-hover-text': ctrl.trans.noarg('unblock')
|
||||
}
|
||||
})
|
||||
);
|
||||
else {
|
||||
nodes.push(
|
||||
h('a.msg-app__convo__action', {
|
||||
attrs: {
|
||||
'data-icon': 'h',
|
||||
href: `/rel/follow/${user.id}`,
|
||||
title: ctrl.trans.noarg('follow')
|
||||
}
|
||||
})
|
||||
);
|
||||
nodes.push(
|
||||
h('a.msg-app__convo__action', {
|
||||
attrs: {
|
||||
'data-icon': 'k',
|
||||
href: `/rel/block/${user.id}`,
|
||||
title: ctrl.trans.noarg('block')
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
nodes.push(
|
||||
h('a.msg-app__convo__action', {
|
||||
attrs: {
|
||||
'data-icon': 'i',
|
||||
href: '/report/flag',
|
||||
title: ctrl.trans.noarg('report')
|
||||
}
|
||||
})
|
||||
);
|
||||
return nodes;
|
||||
}
|
||||
|
||||
function setupTextarea(area: HTMLTextAreaElement, contact: string, post: (text: string) => void) {
|
||||
|
||||
// save the textarea content until sent
|
||||
const storage = window.lichess.storage.make(`msg:area:${contact}`);
|
||||
|
||||
// hack to automatically resize the textarea based on content
|
||||
area.value = '';
|
||||
let baseScrollHeight = area.scrollHeight;
|
||||
area.addEventListener('input', throttle(500, () =>
|
||||
setTimeout(() => {
|
||||
const text = area.value.trim();
|
||||
area.rows = 1;
|
||||
// the resize magic
|
||||
if (text) area.rows = Math.min(10, 1 + Math.ceil((area.scrollHeight - baseScrollHeight) / 19));
|
||||
// and save content
|
||||
storage.set(text);
|
||||
})
|
||||
));
|
||||
|
||||
// restore previously saved content
|
||||
area.value = storage.get() || '';
|
||||
if (area.value) area.dispatchEvent(new Event('input'));
|
||||
|
||||
// send the content on <enter.
|
||||
area.addEventListener('keypress', (e: KeyboardEvent) => {
|
||||
if ((e.which == 10 || e.which == 13) && !e.shiftKey) {
|
||||
setTimeout(() => {
|
||||
const txt = area.value.trim();
|
||||
if (txt) post(txt);
|
||||
area.value = '';
|
||||
area.dispatchEvent(new Event('input')); // resize the textarea
|
||||
storage.remove();
|
||||
});
|
||||
}
|
||||
});
|
||||
area.focus();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
import { h } from 'snabbdom'
|
||||
import { VNode } from 'snabbdom/vnode'
|
||||
import { User } from '../interfaces'
|
||||
import MsgCtrl from '../ctrl';
|
||||
import throttle from 'common/throttle';
|
||||
|
||||
export default function renderTextarea(ctrl: MsgCtrl, user: User): VNode {
|
||||
return h('textarea.msg-app__convo__reply__text', {
|
||||
attrs: {
|
||||
rows: 1,
|
||||
autofocus: 1
|
||||
},
|
||||
hook: {
|
||||
insert(vnode) {
|
||||
setupTextarea(vnode.elm as HTMLTextAreaElement, user.id, ctrl.post);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function setupTextarea(area: HTMLTextAreaElement, contact: string, post: (text: string) => void) {
|
||||
|
||||
// save the textarea content until sent
|
||||
const storage = window.lichess.storage.make(`msg:area:${contact}`);
|
||||
|
||||
// hack to automatically resize the textarea based on content
|
||||
area.value = '';
|
||||
let baseScrollHeight = area.scrollHeight;
|
||||
area.addEventListener('input', throttle(500, () =>
|
||||
setTimeout(() => {
|
||||
const text = area.value.trim();
|
||||
area.rows = 1;
|
||||
// the resize magic
|
||||
if (text) area.rows = Math.min(10, 1 + Math.ceil((area.scrollHeight - baseScrollHeight) / 19));
|
||||
// and save content
|
||||
storage.set(text);
|
||||
})
|
||||
));
|
||||
|
||||
// restore previously saved content
|
||||
area.value = storage.get() || '';
|
||||
if (area.value) area.dispatchEvent(new Event('input'));
|
||||
|
||||
// send the content on <enter.
|
||||
area.addEventListener('keypress', (e: KeyboardEvent) => {
|
||||
if ((e.which == 10 || e.which == 13) && !e.shiftKey) {
|
||||
setTimeout(() => {
|
||||
const txt = area.value.trim();
|
||||
if (txt) post(txt);
|
||||
area.value = '';
|
||||
area.dispatchEvent(new Event('input')); // resize the textarea
|
||||
storage.remove();
|
||||
});
|
||||
}
|
||||
});
|
||||
area.focus();
|
||||
}
|
Loading…
Reference in New Issue