add user-info in iframe (#131)

closes #98
This commit is contained in:
Efremov Alexey
2018-07-09 18:32:14 +04:00
committed by Aleksei Gurianov
parent 4cea9d5855
commit 1539c1f043
18 changed files with 154 additions and 30 deletions
@@ -1,3 +1,3 @@
.comment__avatar_default {
.avatar-icon_default {
border: 1px solid #9cdddb;
}
@@ -0,0 +1,12 @@
/** @jsx h */
import { h } from 'preact';
export default function AvatarIcon({ picture, className }) {
return (
<img
className={b('avatar-icon', { mix: className }, { default: !picture })}
src={picture || require('./avatar-icon.svg')}
alt=""
/>
);
}
@@ -1,4 +1,4 @@
.comment__avatar {
.avatar-icon {
display: inline-block;
width: 24px;
height: 24px;

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

+4
View File
@@ -0,0 +1,4 @@
export { default } from './avatar-icon';
require('./avatar-icon.scss');
require('./_default/avatar-icon_default.scss');
@@ -1,12 +0,0 @@
/** @jsx h */
import { h } from 'preact';
export default function Avatar({ picture }) {
return (
<img
className={b('comment__avatar', {}, { default: !picture })}
src={picture || require('./comment__avatar.svg')}
alt=""
/>
);
}
+7 -7
View File
@@ -8,8 +8,8 @@ import { url } from 'common/settings';
import store from 'common/store';
import Input from 'components/input';
import UserInfo from 'components/user-info';
import Avatar from './__avatar/comment__avatar';
import Avatar from 'components/avatar-icon';
export default class Comment extends Component {
constructor(props) {
@@ -19,7 +19,6 @@ export default class Comment extends Component {
isReplying: false,
isEditing: false,
isUserVerified: false,
isUserInfoShown: false,
editTimeLeft: null,
};
@@ -134,7 +133,11 @@ export default class Comment extends Component {
}
toggleUserInfoVisibility() {
this.setState({ isUserInfoShown: !this.state.isUserInfoShown });
if (window.parent) {
const { user } = this.props.data;
const data = JSON.stringify({ isUserInfoShown: true, user });
window.parent.postMessage(data, '*');
}
}
togglePin(isPinned) {
@@ -315,7 +318,6 @@ export default class Comment extends Component {
isEditing,
isUserVerified,
editTimeLeft,
isUserInfoShown,
}
) {
const { data, mods = {} } = props;
@@ -558,8 +560,6 @@ export default class Comment extends Component {
</div>
</div>
{isUserInfoShown && <UserInfo mix="comment__user-info" user={o.user} onClose={this.toggleUserInfoVisibility} />}
{isReplying &&
mods.view !== 'user' && (
<Input mix="comment__input" onSubmit={this.onReply} onCancel={this.toggleReplying} pid={o.id} />
-3
View File
@@ -8,9 +8,6 @@ require('./__action/comment__action.scss');
require('./__action/_type/_collapse/comment__action_type_collapse.scss');
require('./__action/_type/_edit/comment__action_type_edit.scss');
require('./__avatar/comment__avatar.scss');
require('./__avatar/_default/comment__avatar_default.scss');
require('./__body/comment__body.scss');
require('./__control/comment__control.scss');
require('./__control/_select/comment__control_select.scss');
+4
View File
@@ -5,4 +5,8 @@
::selection {
background: #c6efef;
}
&_user-info {
position: static;
}
}
@@ -0,0 +1,6 @@
.user-info__avatar {
position: absolute;
top: 17px;
height: 30px;
width: 30px;
}
@@ -1,4 +1,7 @@
.user-info__close {
position: absolute;
top: 10px;
right: 10px;
font-size: 14px;
line-height: 18px;
cursor: pointer;
@@ -4,4 +4,5 @@
font-weight: 400;
line-height: 18px;
color: #888;
padding-left: 40px;
}
@@ -3,4 +3,5 @@
font-size: 18px;
font-weight: 700;
line-height: 20px;
padding-left: 40px;
}
+1
View File
@@ -6,3 +6,4 @@ require('./__close/user-info__close.scss');
require('./__id/user-info__id.scss');
require('./__preloader/user-info__preloader.scss');
require('./__title/user-info__title.scss');
require('./__avatar/user-info__avatar.scss');
+4 -2
View File
@@ -5,6 +5,7 @@ import api from 'common/api';
import { getHandleClickProps } from 'common/accessibility';
import LastCommentsList from './last-comments-list';
import Avatar from 'components/avatar-icon';
class UserInfo extends Component {
constructor(props) {
@@ -29,19 +30,20 @@ class UserInfo extends Component {
render(props, { comments, isLoading }) {
const {
user: { name, id },
user: { name, id, isDefaultPicture, picture },
onClose,
} = props;
return (
<div className={b('user-info', props)}>
<Avatar className="user-info__avatar" picture={isDefaultPicture ? null : picture} />
<p className="user-info__title">Last comments by {name}</p>
<p className="user-info__id">{id}</p>
<LastCommentsList isLoading={isLoading} comments={comments} />
<span {...getHandleClickProps(onClose)} className="user-info__close">
Close
Close &#10006;
</span>
</div>
);
+12 -3
View File
@@ -1,7 +1,16 @@
.user-info {
padding: 10px 20px;
overflow: hidden;
background: #fafafa;
border: 1px solid #efefef;
border-radius: 2px;
position: absolute;
top: 0;
bottom: 0;
right: 0;
width: 100%;
background: white;
padding: 10px;
box-sizing: border-box;
overflow: inherit;
overflow-x: hidden;
overflow-y: auto;
}
+58
View File
@@ -56,6 +56,56 @@ function init() {
setTimeout(postHashToIframe, 1000);
const userInfo = {
node: null,
back: null,
init(user) {
if (!this.node) {
this.node = document.createElement('div');
this.node.style = `position: fixed; top: 0; right: 0; bottom: 0;width: 400px; transform: translate(400px, 0); transition: transform 0.4s ease-out; max-width: 100%`;
}
if (!this.back) {
this.back = document.createElement('div');
this.back.style = `position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0,0,0,0.7);opacity: 0;transition: opacity 0.4s ease-out;`;
this.back.onclick = () => this.close();
}
const queryUserInfo =
query +
'&page=user-info&' +
`&id=${user.id}&name=${user.name}&picture=${user.picture || ''}&isDefaultPicture=${user.isDefaultPicture || 0}`;
this.node.innerHTML = `
<iframe
src="${process.env.NODE_ENV === 'production' ? `${BASE_URL}/web` : ''}/iframe.html?${queryUserInfo}"
width="100%"
height="100%"
frameborder="0"
allowtransparency="true"
scrolling="no"
tabindex="0"
title="Remark42"
verticalscrolling="no"
horizontalscrolling="no"
/>
`;
document.body.appendChild(this.back);
document.body.appendChild(this.node);
setTimeout(() => {
this.back.style.opacity = 1;
this.node.style.transform = '';
}, 400);
},
close() {
if (this.node) {
this.node.style.transform = 'translate(400px, 0)';
this.node.remove();
}
if (this.back) {
this.back.style.opacity = 0;
this.back.remove();
}
},
};
function receiveMessages(event) {
try {
const data = typeof event.data === 'string' ? JSON.parse(event.data) : event.data;
@@ -66,6 +116,14 @@ function init() {
if (data.scrollTo) {
window.scrollTo(window.pageXOffset, data.scrollTo + iframe.getBoundingClientRect().top + window.pageYOffset);
}
if (data.hasOwnProperty('isUserInfoShown')) {
if (data.isUserInfoShown) {
userInfo.init(data.user || {});
} else {
userInfo.close();
}
}
} catch (e) {}
}
+39 -1
View File
@@ -4,6 +4,9 @@ import loadPolyfills from 'common/polyfills';
import { h, render } from 'preact';
import Root from './components/root';
import UserInfo from 'components/user-info';
import store from 'common/store';
// eslint-disable-next-line no-unused-vars
import ListComments from './components/list-comments'; // TODO: temp solution for extracting styles
@@ -25,5 +28,40 @@ function init() {
return;
}
render(<Root />, node.parentElement, node);
const params = window.location.search
.replace(/^\?/, '')
.split('&')
.reduce((memo, value) => {
const vals = value.split('=');
if (vals.length === 2) {
memo[vals[0]] = vals[1];
}
return memo;
}, {});
if (params.page === 'user-info') {
const user = {
id: params.id,
name: params.name || '',
isDefaultPicture: params.isDefaultPicture,
picture: params.picture,
};
store.set('user', user);
const onClose = () => {
if (window.parent) {
window.parent.postMessage(JSON.stringify({ isUserInfoShown: false }), '*');
}
};
render(
<div id={NODE_ID}>
<div className="root root_user-info">
<UserInfo user={user} onClose={onClose} />
</div>
</div>,
node.parentElement,
node
);
} else {
render(<Root />, node.parentElement, node);
}
}