mirror of
https://github.com/wassname/talk.git
synced 2026-09-12 13:01:11 +08:00
Merge pull request #269 from coralproject/design-pass-tweaks
Design pass tweaks
This commit is contained in:
@@ -1 +1,3 @@
|
|||||||
|
.Reply {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|||||||
@@ -16,6 +16,8 @@ import {ReplyBox, ReplyButton} from 'coral-plugin-replies';
|
|||||||
import FlagComment from 'coral-plugin-flags/FlagComment';
|
import FlagComment from 'coral-plugin-flags/FlagComment';
|
||||||
import LikeButton from 'coral-plugin-likes/LikeButton';
|
import LikeButton from 'coral-plugin-likes/LikeButton';
|
||||||
|
|
||||||
|
import styles from './Comment.css';
|
||||||
|
|
||||||
const getAction = (type, comment) => comment.actions.filter((a) => a.type === type)[0];
|
const getAction = (type, comment) => comment.actions.filter((a) => a.type === type)[0];
|
||||||
|
|
||||||
class Comment extends React.Component {
|
class Comment extends React.Component {
|
||||||
@@ -87,7 +89,7 @@ class Comment extends React.Component {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={parentId ? 'reply' : 'comment'}
|
className={parentId ? `reply ${styles.Reply}` : `comment ${styles.Comment}`}
|
||||||
id={`c_${comment.id}`}
|
id={`c_${comment.id}`}
|
||||||
style={{marginLeft: depth * 30}}>
|
style={{marginLeft: depth * 30}}>
|
||||||
<hr aria-hidden={true} />
|
<hr aria-hidden={true} />
|
||||||
@@ -103,11 +105,6 @@ class Comment extends React.Component {
|
|||||||
<PubDate created_at={comment.created_at} />
|
<PubDate created_at={comment.created_at} />
|
||||||
<Content body={comment.body} />
|
<Content body={comment.body} />
|
||||||
<div className="commentActionsLeft">
|
<div className="commentActionsLeft">
|
||||||
<ReplyButton
|
|
||||||
onClick={() => setActiveReplyBox(comment.id)}
|
|
||||||
parentCommentId={parentId || comment.id}
|
|
||||||
currentUserId={currentUser && currentUser.id}
|
|
||||||
banned={false} />
|
|
||||||
<LikeButton
|
<LikeButton
|
||||||
like={like}
|
like={like}
|
||||||
id={comment.id}
|
id={comment.id}
|
||||||
@@ -115,8 +112,14 @@ class Comment extends React.Component {
|
|||||||
deleteAction={deleteAction}
|
deleteAction={deleteAction}
|
||||||
showSignInDialog={showSignInDialog}
|
showSignInDialog={showSignInDialog}
|
||||||
currentUser={currentUser} />
|
currentUser={currentUser} />
|
||||||
|
<ReplyButton
|
||||||
|
onClick={() => setActiveReplyBox(comment.id)}
|
||||||
|
parentCommentId={parentId || comment.id}
|
||||||
|
currentUserId={currentUser && currentUser.id}
|
||||||
|
banned={false} />
|
||||||
</div>
|
</div>
|
||||||
<div className="commentActionsRight">
|
<div className="commentActionsRight">
|
||||||
|
<PermalinkButton articleURL={asset.url} commentId={comment.id} />
|
||||||
<FlagComment
|
<FlagComment
|
||||||
flag={flag}
|
flag={flag}
|
||||||
id={comment.id}
|
id={comment.id}
|
||||||
@@ -125,7 +128,6 @@ class Comment extends React.Component {
|
|||||||
deleteAction={deleteAction}
|
deleteAction={deleteAction}
|
||||||
showSignInDialog={showSignInDialog}
|
showSignInDialog={showSignInDialog}
|
||||||
currentUser={currentUser} />
|
currentUser={currentUser} />
|
||||||
<PermalinkButton articleURL={asset.url} commentId={comment.id} />
|
|
||||||
</div>
|
</div>
|
||||||
{
|
{
|
||||||
activeReplyBox === comment.id
|
activeReplyBox === comment.id
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import {compose} from 'react-apollo';
|
|||||||
import {connect} from 'react-redux';
|
import {connect} from 'react-redux';
|
||||||
import isEqual from 'lodash/isEqual';
|
import isEqual from 'lodash/isEqual';
|
||||||
|
|
||||||
import {TabBar, Tab, TabContent, Spinner} from '../../coral-ui';
|
import {TabBar, Tab, TabContent, Spinner} from 'coral-ui';
|
||||||
|
|
||||||
const {logout, showSignInDialog, requestConfirmEmail} = authActions;
|
const {logout, showSignInDialog, requestConfirmEmail} = authActions;
|
||||||
const {addNotification, clearNotification} = notificationActions;
|
const {addNotification, clearNotification} = notificationActions;
|
||||||
@@ -17,27 +17,24 @@ import Stream from './Stream';
|
|||||||
import InfoBox from 'coral-plugin-infobox/InfoBox';
|
import InfoBox from 'coral-plugin-infobox/InfoBox';
|
||||||
import Count from 'coral-plugin-comment-count/CommentCount';
|
import Count from 'coral-plugin-comment-count/CommentCount';
|
||||||
import CommentBox from 'coral-plugin-commentbox/CommentBox';
|
import CommentBox from 'coral-plugin-commentbox/CommentBox';
|
||||||
import UserBox from '../../coral-sign-in/components/UserBox';
|
import UserBox from 'coral-sign-in/components/UserBox';
|
||||||
import SignInContainer from '../../coral-sign-in/containers/SignInContainer';
|
import SignInContainer from 'coral-sign-in/containers/SignInContainer';
|
||||||
import SuspendedAccount from '../../coral-framework/components/SuspendedAccount';
|
import SuspendedAccount from 'coral-framework/components/SuspendedAccount';
|
||||||
import SettingsContainer from '../../coral-settings/containers/SettingsContainer';
|
import SettingsContainer from 'coral-settings/containers/SettingsContainer';
|
||||||
import RestrictedContent from '../../coral-framework/components/RestrictedContent';
|
import RestrictedContent from 'coral-framework/components/RestrictedContent';
|
||||||
import ConfigureStreamContainer from '../../coral-configure/containers/ConfigureStreamContainer';
|
import ConfigureStreamContainer from 'coral-configure/containers/ConfigureStreamContainer';
|
||||||
|
|
||||||
class Embed extends Component {
|
class Embed extends Component {
|
||||||
|
|
||||||
constructor (props) {
|
state = {activeTab: 0, showSignInDialog: false};
|
||||||
super(props);
|
|
||||||
|
|
||||||
this.state = {
|
changeTab = (tab) => {
|
||||||
activeTab: 0,
|
|
||||||
showSignInDialog: false
|
|
||||||
};
|
|
||||||
|
|
||||||
this.changeTab = this.changeTab.bind(this);
|
// Everytime the comes from another tab, the Stream needs to be updated.
|
||||||
}
|
if (tab === 0) {
|
||||||
|
this.props.data.refetch();
|
||||||
|
}
|
||||||
|
|
||||||
changeTab (tab) {
|
|
||||||
this.setState({
|
this.setState({
|
||||||
activeTab: tab
|
activeTab: tab
|
||||||
});
|
});
|
||||||
@@ -51,15 +48,6 @@ class Embed extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount () {
|
componentDidMount () {
|
||||||
|
|
||||||
// stream id, logged in user, settings
|
|
||||||
|
|
||||||
// Set up messaging between embedded Iframe an parent component
|
|
||||||
|
|
||||||
// this.props.getStream(path || window.location);
|
|
||||||
// this.path = window.location.href.split('#')[0];
|
|
||||||
//
|
|
||||||
|
|
||||||
pym.sendMessage('childReady');
|
pym.sendMessage('childReady');
|
||||||
|
|
||||||
pym.onMessage('DOMContentLoaded', hash => {
|
pym.onMessage('DOMContentLoaded', hash => {
|
||||||
@@ -78,7 +66,6 @@ class Embed extends Component {
|
|||||||
}
|
}
|
||||||
}, 100);
|
}, 100);
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillReceiveProps (nextProps) {
|
componentWillReceiveProps (nextProps) {
|
||||||
@@ -100,86 +87,89 @@ class Embed extends Component {
|
|||||||
minHeight: document.body.scrollHeight + 200
|
minHeight: document.body.scrollHeight + 200
|
||||||
} : {};
|
} : {};
|
||||||
|
|
||||||
return <div style={expandForLogin}>
|
if (loading) {
|
||||||
{
|
return <Spinner />;
|
||||||
loading ? <Spinner/>
|
}
|
||||||
: <div className="commentStream">
|
|
||||||
|
return (
|
||||||
|
<div style={expandForLogin}>
|
||||||
|
<div className="commentStream">
|
||||||
<TabBar onChange={this.changeTab} activeTab={activeTab}>
|
<TabBar onChange={this.changeTab} activeTab={activeTab}>
|
||||||
<Tab><Count count={asset.commentCount}/></Tab>
|
<Tab><Count count={asset.commentCount}/></Tab>
|
||||||
<Tab>Settings</Tab>
|
<Tab>Settings</Tab>
|
||||||
<Tab restricted={!isAdmin}>Configure Stream</Tab>
|
<Tab restricted={!isAdmin}>Configure Stream</Tab>
|
||||||
</TabBar>
|
</TabBar>
|
||||||
{loggedIn && <UserBox user={user} logout={this.props.logout} />}
|
{loggedIn && <UserBox user={user} logout={this.props.logout} changeTab={this.changeTab} />}
|
||||||
<TabContent show={activeTab === 0}>
|
<TabContent show={activeTab === 0}>
|
||||||
{
|
{
|
||||||
openStream
|
openStream
|
||||||
? <div id="commentBox">
|
? <div id="commentBox">
|
||||||
<InfoBox
|
<InfoBox
|
||||||
content={asset.settings.infoBoxContent}
|
content={asset.settings.infoBoxContent}
|
||||||
enable={asset.settings.infoBoxEnable}
|
enable={asset.settings.infoBoxEnable}
|
||||||
/>
|
/>
|
||||||
<RestrictedContent restricted={false} restrictedComp={<SuspendedAccount />}>
|
<RestrictedContent restricted={false} restrictedComp={<SuspendedAccount />}>
|
||||||
{
|
{
|
||||||
user
|
user
|
||||||
? <CommentBox
|
? <CommentBox
|
||||||
commentPostedHandler={refetch}
|
commentPostedHandler={refetch}
|
||||||
addNotification={this.props.addNotification}
|
addNotification={this.props.addNotification}
|
||||||
postItem={this.props.postItem}
|
postItem={this.props.postItem}
|
||||||
appendItemArray={this.props.appendItemArray}
|
appendItemArray={this.props.appendItemArray}
|
||||||
updateItem={this.props.updateItem}
|
updateItem={this.props.updateItem}
|
||||||
assetId={asset.id}
|
assetId={asset.id}
|
||||||
premod={asset.settings.moderation}
|
premod={asset.settings.moderation}
|
||||||
isReply={false}
|
isReply={false}
|
||||||
currentUser={this.props.auth.user}
|
currentUser={this.props.auth.user}
|
||||||
banned={false}
|
banned={false}
|
||||||
authorId={user.id}
|
authorId={user.id}
|
||||||
charCount={asset.settings.charCountEnable && asset.settings.charCount} />
|
charCount={asset.settings.charCountEnable && asset.settings.charCount} />
|
||||||
: null
|
: null
|
||||||
}
|
}
|
||||||
</RestrictedContent>
|
</RestrictedContent>
|
||||||
</div>
|
</div>
|
||||||
: <p>{asset.settings.closedMessage}</p>
|
: <p>{asset.settings.closedMessage}</p>
|
||||||
}
|
}
|
||||||
{!loggedIn && <SignInContainer offset={signInOffset}/>}
|
{!loggedIn && <SignInContainer offset={signInOffset}/>}
|
||||||
<Stream
|
<Stream
|
||||||
refetch={refetch}
|
refetch={refetch}
|
||||||
addNotification={this.props.addNotification}
|
addNotification={this.props.addNotification}
|
||||||
postItem={this.props.postItem}
|
postItem={this.props.postItem}
|
||||||
asset={asset}
|
asset={asset}
|
||||||
currentUser={user}
|
currentUser={user}
|
||||||
postAction={this.props.postAction}
|
postAction={this.props.postAction}
|
||||||
deleteAction={this.props.deleteAction}
|
deleteAction={this.props.deleteAction}
|
||||||
showSignInDialog={this.props.showSignInDialog}
|
showSignInDialog={this.props.showSignInDialog}
|
||||||
comments={asset.comments} />
|
comments={asset.comments} />
|
||||||
<Notification
|
<Notification
|
||||||
notifLength={4500}
|
notifLength={4500}
|
||||||
clearNotification={this.props.clearNotification}
|
clearNotification={this.props.clearNotification}
|
||||||
notification={{text: null}}
|
notification={{text: null}}
|
||||||
/>
|
/>
|
||||||
</TabContent>
|
</TabContent>
|
||||||
<TabContent show={activeTab === 1}>
|
<TabContent show={activeTab === 1}>
|
||||||
<SettingsContainer
|
<SettingsContainer
|
||||||
loggedIn={loggedIn}
|
loggedIn={loggedIn}
|
||||||
userData={this.props.userData}
|
userData={this.props.userData}
|
||||||
showSignInDialog={this.props.showSignInDialog}
|
showSignInDialog={this.props.showSignInDialog}
|
||||||
/>
|
/>
|
||||||
</TabContent>
|
</TabContent>
|
||||||
<TabContent show={activeTab === 2}>
|
<TabContent show={activeTab === 2}>
|
||||||
<RestrictedContent restricted={!loggedIn}>
|
<RestrictedContent restricted={!loggedIn}>
|
||||||
<ConfigureStreamContainer
|
<ConfigureStreamContainer
|
||||||
status={status}
|
status={status}
|
||||||
onClick={this.toggleStatus}
|
onClick={this.toggleStatus}
|
||||||
/>
|
/>
|
||||||
</RestrictedContent>
|
</RestrictedContent>
|
||||||
</TabContent>
|
</TabContent>
|
||||||
<Notification
|
<Notification
|
||||||
notifLength={4500}
|
notifLength={4500}
|
||||||
clearNotification={this.props.clearNotification}
|
clearNotification={this.props.clearNotification}
|
||||||
notification={this.props.notification}
|
notification={this.props.notification}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
}
|
</div>
|
||||||
</div>;
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -193,7 +183,13 @@ const mapStateToProps = state => ({
|
|||||||
const mapDispatchToProps = dispatch => ({
|
const mapDispatchToProps = dispatch => ({
|
||||||
requestConfirmEmail: () => dispatch(requestConfirmEmail()),
|
requestConfirmEmail: () => dispatch(requestConfirmEmail()),
|
||||||
loadAsset: (asset) => dispatch(fetchAssetSuccess(asset)),
|
loadAsset: (asset) => dispatch(fetchAssetSuccess(asset)),
|
||||||
addNotification: (type, text) => dispatch(addNotification(type, text)),
|
addNotification: (type, text) => {
|
||||||
|
pym.sendMessage('getPosition');
|
||||||
|
|
||||||
|
pym.onMessage('position', position => {
|
||||||
|
dispatch(addNotification(type, text, position));
|
||||||
|
});
|
||||||
|
},
|
||||||
clearNotification: () => dispatch(clearNotification()),
|
clearNotification: () => dispatch(clearNotification()),
|
||||||
showSignInDialog: (offset) => dispatch(showSignInDialog(offset)),
|
showSignInDialog: (offset) => dispatch(showSignInDialog(offset)),
|
||||||
logout: () => dispatch(logout()),
|
logout: () => dispatch(logout()),
|
||||||
|
|||||||
@@ -1,3 +1,8 @@
|
|||||||
|
html, body {
|
||||||
|
width:auto;
|
||||||
|
height:auto;
|
||||||
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
font-family: 'Lato', sans-serif;
|
font-family: 'Lato', sans-serif;
|
||||||
font-family: 'Open Sans', sans-serif;
|
font-family: 'Open Sans', sans-serif;
|
||||||
@@ -46,7 +51,6 @@ hr {
|
|||||||
/* Notification styles */
|
/* Notification styles */
|
||||||
#coral-notif {
|
#coral-notif {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
bottom: 0;
|
|
||||||
border: 0;
|
border: 0;
|
||||||
background: rgb(105,105,105);
|
background: rgb(105,105,105);
|
||||||
color: white;
|
color: white;
|
||||||
@@ -76,6 +80,8 @@ hr {
|
|||||||
.commentStream {
|
.commentStream {
|
||||||
/* prevent absolutely positioned final permalink popover from being clipped */
|
/* prevent absolutely positioned final permalink popover from being clipped */
|
||||||
padding-bottom: 50px;
|
padding-bottom: 50px;
|
||||||
|
min-height: 600px;
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Comment Box Styles */
|
/* Comment Box Styles */
|
||||||
@@ -219,8 +225,8 @@ hr {
|
|||||||
.coral-plugin-flags-popup span {
|
.coral-plugin-flags-popup span {
|
||||||
min-width: 280px;
|
min-width: 280px;
|
||||||
bottom: 36px;
|
bottom: 36px;
|
||||||
left: -190px;
|
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
right: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.coral-plugin-flags-popup-form {
|
.coral-plugin-flags-popup-form {
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
export const ADD_NOTIFICATION = 'ADD_NOTIFICATION';
|
export const ADD_NOTIFICATION = 'ADD_NOTIFICATION';
|
||||||
export const CLEAR_NOTIFICATION = 'CLEAR_NOTIFICATION';
|
export const CLEAR_NOTIFICATION = 'CLEAR_NOTIFICATION';
|
||||||
|
|
||||||
export const addNotification = (notifType, text) => {
|
export const addNotification = (notifType, text, position) => {
|
||||||
return {
|
return {
|
||||||
type: ADD_NOTIFICATION,
|
type: ADD_NOTIFICATION,
|
||||||
notifType,
|
notifType,
|
||||||
text
|
text,
|
||||||
|
position
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import {SnackBar} from 'coral-ui';
|
||||||
|
|
||||||
const Notification = (props) => {
|
const Notification = (props) => {
|
||||||
if (props.notification.text) {
|
if (props.notification.text) {
|
||||||
@@ -6,14 +7,16 @@ const Notification = (props) => {
|
|||||||
props.clearNotification();
|
props.clearNotification();
|
||||||
}, props.notifLength);
|
}, props.notifLength);
|
||||||
}
|
}
|
||||||
return <div>
|
return (
|
||||||
{
|
<div>
|
||||||
props.notification.text &&
|
{
|
||||||
<dialog open id='coral-notif' className={`coral-notif-${ props.notification.type}`}>
|
props.notification.text &&
|
||||||
{props.notification.text}
|
<SnackBar id='coral-notif' className={`coral-notif-${props.notification.type}`} position={props.notification.position}>
|
||||||
</dialog>
|
{props.notification.text}
|
||||||
}
|
</SnackBar>
|
||||||
</div>;
|
}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Notification;
|
export default Notification;
|
||||||
|
|||||||
@@ -1,14 +1,21 @@
|
|||||||
/* Items Notifications */
|
|
||||||
|
|
||||||
import * as actions from '../actions/notification';
|
import * as actions from '../actions/notification';
|
||||||
import {fromJS} from 'immutable';
|
import {Map} from 'immutable';
|
||||||
|
|
||||||
const initialState = fromJS({});
|
const initialState = Map({
|
||||||
|
text: '',
|
||||||
|
type: '',
|
||||||
|
position: 400
|
||||||
|
});
|
||||||
|
|
||||||
export default (state = initialState, action) => {
|
export default (state = initialState, action) => {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case actions.ADD_NOTIFICATION:
|
case actions.ADD_NOTIFICATION:
|
||||||
return state.set('text', action.text).set('type', action.notifType);
|
return state
|
||||||
|
.merge({
|
||||||
|
type: action.notifType,
|
||||||
|
text: action.text,
|
||||||
|
position: action.position
|
||||||
|
});
|
||||||
case actions.CLEAR_NOTIFICATION:
|
case actions.CLEAR_NOTIFICATION:
|
||||||
return initialState;
|
return initialState;
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -1,51 +1,47 @@
|
|||||||
import React, {Component} from 'react';
|
import React, {Component} from 'react';
|
||||||
import {Tooltip} from 'coral-ui';
|
import {Tooltip} from 'coral-ui';
|
||||||
import FlagBio from '../coral-plugin-flags/FlagBio';
|
import FlagBio from 'coral-plugin-flags/FlagBio';
|
||||||
const packagename = 'coral-plugin-author-name';
|
const packagename = 'coral-plugin-author-name';
|
||||||
|
import styles from './styles.css';
|
||||||
|
|
||||||
export default class AuthorName extends Component {
|
export default class AuthorName extends Component {
|
||||||
constructor (props) {
|
|
||||||
super(props);
|
|
||||||
|
|
||||||
this.state = {
|
state = {showTooltip: false}
|
||||||
showTooltip: false
|
|
||||||
};
|
|
||||||
|
|
||||||
this.handleMouseOver = this.handleMouseOver.bind(this);
|
handleClick = () => {
|
||||||
this.handleMouseLeave = this.handleMouseLeave.bind(this);
|
this.setState(state => ({
|
||||||
|
showTooltip: !state.showTooltip
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
handleMouseOver () {
|
handleMouseLeave = () => {
|
||||||
this.setState({
|
setTimeout(() => {
|
||||||
showTooltip: true
|
this.setState({
|
||||||
});
|
showTooltip: false
|
||||||
}
|
});
|
||||||
|
}, 500);
|
||||||
handleMouseLeave () {
|
|
||||||
this.setState({
|
|
||||||
showTooltip: false
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const {author} = this.props;
|
const {author} = this.props;
|
||||||
const {showTooltip} = this.state;
|
const {showTooltip} = this.state;
|
||||||
return (
|
return (
|
||||||
<div
|
<div className={`${packagename}-text ${styles.container}`} onClick={this.handleClick} onMouseLeave={this.handleMouseLeave}>
|
||||||
className={`${packagename}-text`}
|
<a className={`${styles.authorName} ${author.settings.bio ? styles.hasBio : ''}`}>
|
||||||
onMouseOver={this.handleMouseOver}
|
{author && author.name}
|
||||||
onMouseLeave={this.handleMouseLeave}
|
{author.settings.bio ? <span className={`${styles.arrowDown} ${showTooltip ? styles.arrowUp : ''}`} /> : null}
|
||||||
>
|
</a>
|
||||||
{author && author.name}
|
{showTooltip && author.settings.bio
|
||||||
{ showTooltip && author.settings.bio && <Tooltip>
|
&& (
|
||||||
|
<Tooltip>
|
||||||
<div className={`${packagename}-bio`}>
|
<div className={`${packagename}-bio`}>
|
||||||
{author.settings.bio}
|
{author.settings.bio}
|
||||||
</div>
|
</div>
|
||||||
<div className={`${packagename}-bio-flag`}>
|
<div className={`${packagename}-bio-flag`}>
|
||||||
<FlagBio {...this.props}/>
|
<FlagBio {...this.props}/>
|
||||||
</div>
|
</div>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
.authorName {
|
||||||
|
color: black;
|
||||||
|
display: inline-block;
|
||||||
|
margin: 10px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hasBio {
|
||||||
|
&:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.arrowDown {
|
||||||
|
top: 0;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
margin-top: -2px;
|
||||||
|
margin-left: 2px;
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
|
border-bottom: 0;
|
||||||
|
border-left: 3px solid transparent;
|
||||||
|
border-right: 3px solid transparent;
|
||||||
|
border-top: 3px solid #000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.arrowUp {
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
border-top: 0;
|
||||||
|
border-left: 3px solid transparent;
|
||||||
|
border-right: 3px solid transparent;
|
||||||
|
border-bottom: 3px solid black;
|
||||||
|
}
|
||||||
@@ -10,8 +10,8 @@ const getPopupMenu = [
|
|||||||
return {
|
return {
|
||||||
header: lang.t('step-1-header'),
|
header: lang.t('step-1-header'),
|
||||||
options: [
|
options: [
|
||||||
{val: 'USERS', text: lang.t('flag-username')},
|
{val: 'COMMENTS', text: lang.t('flag-comment')},
|
||||||
{val: 'COMMENTS', text: lang.t('flag-comment')}
|
{val: 'USERS', text: lang.t('flag-username')}
|
||||||
],
|
],
|
||||||
button: lang.t('continue'),
|
button: lang.t('continue'),
|
||||||
sets: 'itemType'
|
sets: 'itemType'
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ import I18n from 'coral-framework/modules/i18n/i18n';
|
|||||||
import translations from './translations';
|
import translations from './translations';
|
||||||
import onClickOutside from 'react-onclickoutside';
|
import onClickOutside from 'react-onclickoutside';
|
||||||
const name = 'coral-plugin-permalinks';
|
const name = 'coral-plugin-permalinks';
|
||||||
|
import {Button} from 'coral-ui';
|
||||||
|
import styles from './styles.css';
|
||||||
|
|
||||||
const lang = new I18n(translations);
|
const lang = new I18n(translations);
|
||||||
|
|
||||||
@@ -32,40 +34,37 @@ class PermalinkButton extends React.Component {
|
|||||||
this.permalinkInput.select();
|
this.permalinkInput.select();
|
||||||
try {
|
try {
|
||||||
document.execCommand('copy');
|
document.execCommand('copy');
|
||||||
this.setState({copySuccessful: true});
|
this.setState({copySuccessful: true, copyFailure: null});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this.setState({copyFailure: true});
|
this.setState({copyFailure: true, copySuccessful: null});
|
||||||
}
|
}
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.setState({copyFailure: null, copySuccessful: null});
|
this.setState({copyFailure: null, copySuccessful: null});
|
||||||
}, 4500);
|
}, 3000);
|
||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
|
const {copySuccessful, copyFailure} = this.state;
|
||||||
return (
|
return (
|
||||||
<div className={`${name}-container`}>
|
<div className={`${name}-container`}>
|
||||||
<button onClick={this.toggle} className={`${name}-button`}>
|
<button onClick={this.toggle} className={`${name}-button`}>
|
||||||
<i className={`${name}-icon material-icons`} aria-hidden={true}>link</i>
|
<i className={`${name}-icon material-icons`} aria-hidden={true}>link</i>
|
||||||
{lang.t('permalink.permalink')}
|
{lang.t('permalink.permalink')}
|
||||||
</button>
|
</button>
|
||||||
<div
|
<div className={`${name}-popover ${styles.container} ${this.state.popoverOpen ? 'active' : ''}`}>
|
||||||
className={`${name}-popover ${this.state.popoverOpen ? 'active' : ''}`}>
|
|
||||||
<input
|
<input
|
||||||
className={`${name}-copy-field`}
|
className={`${name}-copy-field`}
|
||||||
type='text'
|
type='text'
|
||||||
ref={input => this.permalinkInput = input}
|
ref={input => this.permalinkInput = input}
|
||||||
value={`${this.props.articleURL}#${this.props.commentId}`}
|
value={`${this.props.articleURL}#${this.props.commentId}`}
|
||||||
onChange={() => {}} />
|
onChange={() => {}} />
|
||||||
<button className={`${name}-copy-button`} onClick={this.copyPermalink}>Copy</button>
|
<Button className={`${name}-copy-button ${copySuccessful ? styles.success : ''} ${copyFailure ? styles.failure : ''}`}
|
||||||
{
|
onClick={this.copyPermalink} >
|
||||||
this.state.copySuccessful ? <p className={`${name}-copied-text`}>copied to clipboard</p> : null
|
{!copyFailure && !copySuccessful && 'Copy'}
|
||||||
}
|
{copySuccessful && 'Copied'}
|
||||||
{
|
{copyFailure && 'Not supported'}
|
||||||
this.state.copyFailure
|
</Button>
|
||||||
? <p className={`${name}-copied-error`}>copying to clipboard not supported in this browser. Use Cmd + C.</p>
|
|
||||||
: null
|
|
||||||
}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -0,0 +1,74 @@
|
|||||||
|
.container {
|
||||||
|
border-radius: 3px;
|
||||||
|
padding: 15px 10px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
/* box-shadow: 3px 3px 5px 0 rgba(0, 0, 0, 0.3); */
|
||||||
|
border: solid 1px rgba(153, 153, 153, 0.33);
|
||||||
|
width: auto;
|
||||||
|
margin: 0 auto;
|
||||||
|
left: 0;
|
||||||
|
margin: 0 5px;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
margin: 0;
|
||||||
|
margin-top: -13px;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
content: '';
|
||||||
|
border: 10px solid transparent;
|
||||||
|
border-top-color: white;
|
||||||
|
position: absolute;
|
||||||
|
right: 8.69em;
|
||||||
|
bottom: -20px;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::after{
|
||||||
|
content: '';
|
||||||
|
border: 10px solid transparent;
|
||||||
|
border-top-color: rgba(153, 153, 153, 0.33);
|
||||||
|
position: absolute;
|
||||||
|
right: 8.69em;
|
||||||
|
bottom: -21px;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
display: inline-block;
|
||||||
|
width: calc(100% - 78px);
|
||||||
|
padding: 8px;
|
||||||
|
border-radius: 3px;
|
||||||
|
border: solid 1px #e0e0e0;
|
||||||
|
height: 32px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
font-size: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
display: inline-block;
|
||||||
|
float: right;
|
||||||
|
box-sizing: border-box;
|
||||||
|
margin: 0;
|
||||||
|
background-color: #e0e0e0;
|
||||||
|
font-size: 1em;
|
||||||
|
width: auto;
|
||||||
|
height: auto;
|
||||||
|
padding: 2px;
|
||||||
|
transition: background-color 0.4s ease;
|
||||||
|
|
||||||
|
&:hover{
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.success {
|
||||||
|
background-color: #00897B;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.failure {
|
||||||
|
background-color: #FF5252;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"en": {
|
"en": {
|
||||||
"permalink": {
|
"permalink": {
|
||||||
"permalink": "Permalink"
|
"permalink": "Link"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"es": {
|
"es": {
|
||||||
"permalink": {
|
"permalink": {
|
||||||
"permalink": "Enlace permanente"
|
"permalink": "Enlace"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,14 +4,11 @@ import I18n from 'coral-framework/modules/i18n/i18n';
|
|||||||
import translations from '../translations';
|
import translations from '../translations';
|
||||||
const lang = new I18n(translations);
|
const lang = new I18n(translations);
|
||||||
|
|
||||||
const UserBox = ({className, user, logout, ...props}) => (
|
const UserBox = ({className, user, logout, changeTab}) => (
|
||||||
<div
|
<div className={`${styles.userBox} ${className ? className : ''}`}>
|
||||||
className={`${styles.userBox} ${className ? className : ''}`}
|
|
||||||
{...props}
|
|
||||||
>
|
|
||||||
{lang.t('signIn.loggedInAs')}
|
{lang.t('signIn.loggedInAs')}
|
||||||
<a>{user.displayName}</a>. {lang.t('signIn.notYou')}
|
<a onClick={() => changeTab(1)}>{user.displayName}</a>. {lang.t('signIn.notYou')}
|
||||||
<a onClick={logout} id='logout'>{lang.t('signIn.logout')}</a>
|
<a className={styles.logout} onClick={logout} id='logout'>{lang.t('signIn.logout')}</a>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -93,7 +93,10 @@ input.error{
|
|||||||
margin: 0px;
|
margin: 0px;
|
||||||
margin-left: 4px;
|
margin-left: 4px;
|
||||||
padding-bottom: 2px;
|
padding-bottom: 2px;
|
||||||
border-bottom: solid 1px black;
|
}
|
||||||
|
|
||||||
|
.userBox .logout {
|
||||||
|
border-bottom: solid 1px black;
|
||||||
}
|
}
|
||||||
|
|
||||||
.attention {
|
.attention {
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import styles from './Checkbox.css';
|
import styles from './Checkbox.css';
|
||||||
|
|
||||||
export default ({name, cStyle = 'base', onChange, label, className, info, ...props}) => (
|
export default ({name, cStyle = 'base', onChange, label, className, info, ...attrs}) => (
|
||||||
<label className={`${styles.label} ${styles[`type--${cStyle}`]} ${className}`} htmlFor={name}>
|
<label className={`${styles.label} ${styles[`type--${cStyle}`]} ${className}`} htmlFor={name}>
|
||||||
<input type="checkbox" id={name} name={name} onChange={onChange} {...props} />
|
<input type="checkbox" id={name} name={name} onChange={onChange} {...attrs} />
|
||||||
<span className={styles.checkbox}></span>
|
<span className={styles.checkbox}></span>
|
||||||
{label && <span>{label}</span>}
|
{label && <span>{label}</span>}
|
||||||
{info && (
|
{info && (
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
.SnackBar {
|
||||||
|
position: fixed;
|
||||||
|
cursor: default;
|
||||||
|
background-color: #323232;
|
||||||
|
z-index: 3;
|
||||||
|
display: flex;
|
||||||
|
will-change: transform;
|
||||||
|
transition: transform .25s cubic-bezier(.4,0,1,1);
|
||||||
|
pointer-events: none;
|
||||||
|
padding: 18px 14px;
|
||||||
|
vertical-align: middle;
|
||||||
|
color: #fff;
|
||||||
|
border-radius: 3px;
|
||||||
|
text-align: center;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, 0);
|
||||||
|
top: 0;
|
||||||
|
bottom: auto;
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import styles from './SnackBar.css';
|
||||||
|
|
||||||
|
const SnackBar = ({children, className, position, ...attrs}) => {
|
||||||
|
return (
|
||||||
|
<div className={`${styles.SnackBar} ${className}`}
|
||||||
|
style={ position ? {top: `${position}px`} : fixedStyle}
|
||||||
|
{...attrs} >
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const fixedStyle = {bottom: '200px', top: 'auto'};
|
||||||
|
|
||||||
|
export default SnackBar;
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border: solid 1px #2376D8;
|
border: solid 1px #2376D8;
|
||||||
top: 33px;
|
top: 48px;
|
||||||
left: 0;
|
left: 0;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
background: white;
|
background: white;
|
||||||
|
|||||||
@@ -16,3 +16,4 @@ export {default as Card} from './components/Card';
|
|||||||
export {default as FormField} from './components/FormField';
|
export {default as FormField} from './components/FormField';
|
||||||
export {default as Success} from './components/Success';
|
export {default as Success} from './components/Success';
|
||||||
export {default as Pager} from './components/Pager';
|
export {default as Pager} from './components/Pager';
|
||||||
|
export {default as SnackBar} from './components/SnackBar';
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ const getCountsByParentID = (context, parent_ids) => {
|
|||||||
* @param {Object} context graph context
|
* @param {Object} context graph context
|
||||||
* @param {Object} query query terms to apply to the comments query
|
* @param {Object} query query terms to apply to the comments query
|
||||||
*/
|
*/
|
||||||
const getCommentsByQuery = ({user}, {ids, statuses, asset_id, parent_id, limit, cursor, sort}) => {
|
const getCommentsByQuery = ({user}, {ids, statuses, asset_id, parent_id, author_id, limit, cursor, sort}) => {
|
||||||
let comments = CommentModel.find();
|
let comments = CommentModel.find();
|
||||||
|
|
||||||
// Only administrators can search for comments with statuses that are not
|
// Only administrators can search for comments with statuses that are not
|
||||||
@@ -100,6 +100,10 @@ const getCommentsByQuery = ({user}, {ids, statuses, asset_id, parent_id, limit,
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (user && (user.hasRoles('ADMIN') || user.id === author_id)) {
|
||||||
|
comments = comments.where({author_id});
|
||||||
|
}
|
||||||
|
|
||||||
if (asset_id) {
|
if (asset_id) {
|
||||||
comments = comments.where({asset_id});
|
comments = comments.where({asset_id});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,8 +28,8 @@ describe ('notificationsReducer', () => {
|
|||||||
type: 'test'
|
type: 'test'
|
||||||
});
|
});
|
||||||
const result = notificationReducer(store, action);
|
const result = notificationReducer(store, action);
|
||||||
expect(result.get('text')).to.equal(undefined);
|
expect(result.get('text')).to.equal('');
|
||||||
expect(result.get('type')).to.equal(undefined);
|
expect(result.get('type')).to.equal('');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
+25
-1
@@ -28,6 +28,7 @@
|
|||||||
<script type='text/javascript' src='<%= basePath %>/pym.v1.min.js'></script>
|
<script type='text/javascript' src='<%= basePath %>/pym.v1.min.js'></script>
|
||||||
<script>
|
<script>
|
||||||
var ready = false;
|
var ready = false;
|
||||||
|
var notificationOffset = 200;
|
||||||
|
|
||||||
// default to using the window.location
|
// default to using the window.location
|
||||||
var url = window.location.protocol + '//' + window.location.host + window.location.pathname;
|
var url = window.location.protocol + '//' + window.location.host + window.location.pathname;
|
||||||
@@ -38,7 +39,21 @@
|
|||||||
<%}%>
|
<%}%>
|
||||||
|
|
||||||
var pymParent = new pym.Parent('coralStreamEmbed', '/embed/stream?asset_url=' + encodeURIComponent(url), {title: 'Talk Comments', id:'coralStreamIframe', name: 'coralStreamIframe', asset_url: url});
|
var pymParent = new pym.Parent('coralStreamEmbed', '/embed/stream?asset_url=' + encodeURIComponent(url), {title: 'Talk Comments', id:'coralStreamIframe', name: 'coralStreamIframe', asset_url: url});
|
||||||
pymParent.onMessage('height', function(height) {document.querySelector('#coralStreamEmbed iframe').height = height + 'px'})
|
pymParent.onMessage('height', function(height) {
|
||||||
|
document.querySelector('#coralStreamEmbed iframe').height = height + 'px';
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
pymParent.onMessage('getPosition', function(notification) {
|
||||||
|
var position = viewport().height + document.body.scrollTop;
|
||||||
|
|
||||||
|
if (position > notificationOffset) {
|
||||||
|
position = position - notificationOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
pymParent.sendMessage('position', position);
|
||||||
|
});
|
||||||
|
|
||||||
pymParent.onMessage('childReady', function () {
|
pymParent.onMessage('childReady', function () {
|
||||||
var interval = setInterval(function () {
|
var interval = setInterval(function () {
|
||||||
if (ready) {
|
if (ready) {
|
||||||
@@ -65,6 +80,15 @@
|
|||||||
document.addEventListener('DOMContentLoaded', function () {
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
ready = true;
|
ready = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function viewport() {
|
||||||
|
var e = window, a = 'inner';
|
||||||
|
if ( !( 'innerWidth' in window ) ){
|
||||||
|
a = 'client';
|
||||||
|
e = document.documentElement || document.body;
|
||||||
|
}
|
||||||
|
return { width : e[ a+'Width' ] , height : e[ a+'Height' ] }
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
Reference in New Issue
Block a user