Reimplement QuestionBoxBuilder

This commit is contained in:
Chi Vinh Le
2017-11-20 17:53:26 +01:00
parent 4c7c3c9e42
commit 8f0eef7cb5
12 changed files with 366 additions and 15 deletions
@@ -0,0 +1,20 @@
.iconBubble{
position: absolute;
top: 8px;
left: 10px;
color: #9E9E9E;
font-size: 24px;
z-index: 0;
}
.iconPerson{
z-index: 2;
top: 12px;
left: 12px;
position: absolute;
font-size: 33px;
color: #262626;
}
.root {
}
@@ -0,0 +1,13 @@
import React from 'react';
import cn from 'classnames';
import styles from './DefaultQuestionBoxIcon.css';
import {Icon} from 'coral-ui';
const DefaultQuestionBoxIcon = ({className}) => (
<div className={cn(styles.root, className)}>
<Icon name="chat_bubble" className={cn(styles.iconBubble)} />
<Icon name="person" className={cn(styles.iconPerson)} />
</div>
);
export default DefaultQuestionBoxIcon;
@@ -0,0 +1,66 @@
.qbInfo {
top: 0;
border: 0;
background: #F0F0F0;
color: black;
width: 100%;
text-align: left;
padding-left: 0px;
margin-bottom: 0px;
font-weight: bold;
font-size: 14px;
overflow: hidden;
min-height: 50px;
display: flex;
border-radius: 3px;
}
.icon {
z-index: 2;
top: 12px;
left: 12px;
position: absolute;
font-size: 33px;
color: #262626;
}
.iconBubble{
position: absolute;
top: 8px;
left: 10px;
color: #9E9E9E;
font-size: 24px;
z-index: 0;
}
.iconPerson{
z-index: 2;
top: 12px;
left: 12px;
position: absolute;
font-size: 33px;
color: #262626;
}
.qbIconContainer {
position: relative;
border: 0;
color: white;
padding: 20px;
margin-left: 0px !important;
margin-right: 10px;
display: inline-block;
width: 10px;
min-height: 100%;
padding: 5px 20px;
vertical-align: middle;
}
.qbContent {
padding: 5px;
display: flex;
align-items: center;
justify-content: center;
font-weight: 400;
}
@@ -0,0 +1,28 @@
import React from 'react';
import cn from 'classnames';
import styles from './QuestionBox.css';
import {Icon} from 'coral-ui';
import Markdown from 'coral-framework/components/Markdown';
import DefaultQuestionBoxIcon from './DefaultQuestionBoxIcon';
const QuestionBox = ({content, icon, className, children}) => (
<div className={cn(styles.qbInfo, 'questionbox-info', className)}>
{
icon === 'default' ? (
<div className={cn(styles.qbIconContainer)}>
<DefaultQuestionBoxIcon />
</div>
) : (
<div className={cn(styles.qbIconContainer)}>
<Icon name={icon} className={cn(styles.icon)} />
</div>
)
}
<div className={cn(styles.qbContent, 'questionbox-content')}>
<Markdown content={content} />
</div>
{children}
</div>
);
export default QuestionBox;
@@ -1,6 +1,6 @@
.root {
position: relative;
margin: 12px 12px 12px 0;
margin: 12px 12px 24px 0;
}
.action {
@@ -12,16 +12,22 @@
}
.title {
display: block;
font-size: 14px;
margin-bottom: 5px;
font-weight: bold;
cursor: pointer;
padding-right: 50px;
}
.description{
padding-right: 50px;
}
.content {
display: inline-block;
padding: 0px 50px;
box-sizing: border-box;
padding-left: 50px;
}
@@ -10,7 +10,7 @@ class Configuration extends React.Component {
id = uuid();
render() {
const {title, children, className, onCheckbox, checked, ...rest} = this.props;
const {title, description, children, className, onCheckbox, checked, ...rest} = this.props;
return (
<div {...rest} className={cn(styles.root, className)}>
{checked !== undefined &&
@@ -26,6 +26,7 @@ class Configuration extends React.Component {
[styles.content]: checked !== undefined,
})}>
<label htmlFor={this.id} className={styles.title}>{title}</label>
<div className={styles.description}>{description}</div>
<div>
{children}
</div>
@@ -37,6 +38,7 @@ class Configuration extends React.Component {
Configuration.propTypes = {
title: PropTypes.string.isRequired,
description: PropTypes.string,
className: PropTypes.string,
onCheckbox: PropTypes.func,
checked: PropTypes.bool,
@@ -0,0 +1,60 @@
.root {
}
.iconList {
display: flex;
padding: 0;
margin: 10px 0;
}
.item {
list-style-type: none;
}
.button {
composes: buttonReset from "coral-framework/styles/reset.css";
display: flex;
align-items: center;
justify-content: center;
text-align: center;
background: #F0F0F0;
width: 48px;
height: 48px;
font-size: 24px;
text-align: center;
line-height: 48px;
color: #252525;
border-radius: 3px;
overflow: hidden;
margin-right: 10px;
position: relative;
border: solid 2px #F0F0F0;
transition: border 0.3s cubic-bezier(.4,0,.2,1);
outline: 0;
&:hover {
cursor: pointer;
}
}
.button:focus {
border: solid 2px #00c96B;
}
.buttonActive {
border: solid 2px #00796B;
}
.defaultIcon {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.questionBox {
margin: 10px 0;
}
@@ -0,0 +1,93 @@
import React from 'react';
import QuestionBox from '../../../components/QuestionBox';
import {Icon, Spinner} from 'coral-ui';
import DefaultQuestionBoxIcon from '../../../components/DefaultQuestionBoxIcon';
import cn from 'classnames';
import styles from './QuestionBoxBuilder.css';
const DefaultIcon = <DefaultQuestionBoxIcon className={styles.defaultIcon} />;
const icons = [
{'default': DefaultIcon},
'forum',
'build',
'format_quote',
];
class QuestionBoxBuilder extends React.Component {
constructor() {
super();
this.state = {
loading: true
};
}
componentWillMount() {
this.loadEditor();
}
async loadEditor() {
const {default: MarkdownEditor} = await import('coral-framework/components/MarkdownEditor');
return this.setState({
loading : false,
MarkdownEditor
});
}
render() {
const {questionBoxIcon, questionBoxContent, onContentChange, onIconChange} = this.props;
const {loading, MarkdownEditor} = this.state;
if (loading) {
return <Spinner/>;
}
return (
<div className={styles.root}>
<h4>Include an Icon</h4>
<ul className={styles.iconList}>
{icons.map((item) => {
const name = typeof item === 'object' ? Object.keys(item)[0] : item;
const icon = typeof item === 'object' ? item[name] : item;
return (
<li
className={styles.item}
key={name}
>
<button
className={cn(
styles.button,
{[styles.buttonActive]: questionBoxIcon === name},
)}
onClick={() => onIconChange(name)}
>
{typeof icon === 'string'
? <Icon name={icon} />
: icon
}
</button>
</li>
);
})}
</ul>
<QuestionBox
className={styles.questionBox}
icon={questionBoxIcon}
content={questionBoxContent}
/>
<MarkdownEditor
value={questionBoxContent}
onChange={onContentChange}
/>
</div>
);
}
}
export default QuestionBoxBuilder;
@@ -24,3 +24,6 @@
margin-bottom: 20px;
}
.questionBoxContainer {
margin-top: 24px;
}
@@ -5,10 +5,24 @@ import t from 'coral-framework/services/i18n';
import cn from 'classnames';
import styles from './Settings.css';
import Configuration from './Configuration';
import QuestionBoxBuilder from './QuestionBoxBuilder';
class Settings extends React.Component {
render() {
const {settings: {moderation, premodLinksEnable}, toggleModeration, togglePremodLinks} = this.props;
const {
settings: {
moderation,
premodLinksEnable,
questionBoxEnable,
questionBoxContent,
questionBoxIcon,
},
onToggleModeration,
onTogglePremodLinks,
onToggleQuestionBox,
onQuestionBoxIconChange,
onQuestionBoxContentChange,
} = this.props;
const changed = false;
return (
<div className={styles.wrapper}>
@@ -28,16 +42,32 @@ class Settings extends React.Component {
<Configuration
checked={moderation === 'PRE'}
title={t('configure.enable_premod')}
onCheckbox={toggleModeration}
>
{t('configure.enable_premod_description')}
</Configuration>
description={t('configure.enable_premod_description')}
onCheckbox={onToggleModeration}
/>
<Configuration
checked={premodLinksEnable}
title={t('configure.enable_premod_links')}
onCheckbox={togglePremodLinks}
description={t('configure.enable_premod_description')}
onCheckbox={onTogglePremodLinks}
/>
<Configuration
checked={questionBoxEnable}
title={t('configure.enable_questionbox')}
description={t('configure.enable_questionbox_description')}
onCheckbox={onToggleQuestionBox}
>
{t('configure.enable_premod_description')}
{
questionBoxEnable &&
<div className={styles.questionBoxContainer}>
<QuestionBoxBuilder
questionBoxIcon={questionBoxIcon}
questionBoxContent={questionBoxContent}
onIconChange={onQuestionBoxIconChange}
onContentChange={onQuestionBoxContentChange}
/>
</div>
}
</Configuration>
</div>
</div>
@@ -47,8 +77,9 @@ class Settings extends React.Component {
Settings.propTypes = {
settings: PropTypes.object.isRequired,
toggleModeration: PropTypes.func.isRequired,
togglePremodLinks: PropTypes.func.isRequired,
onToggleModeration: PropTypes.func.isRequired,
onTogglePremodLinks: PropTypes.func.isRequired,
onToggleQuestionBox: PropTypes.func.isRequired,
};
export default Settings;
@@ -22,6 +22,21 @@ class SettingsContainer extends React.Component {
this.props.updatePending({updater});
};
toggleQuestionBox = () => {
const updater = {questionBoxEnable: {$set: !this.props.mergedSettings.questionBoxEnable}};
this.props.updatePending({updater});
};
setQuestionBoxIcon = (icon) => {
const updater = {questionBoxIcon: {$set: icon}};
this.props.updatePending({updater});
};
setQuestionBoxContent = (content) => {
const updater = {questionBoxContent: {$set: content}};
this.props.updatePending({updater});
};
savePending = async () => {
try {
await this.props.updateAssetSettings(this.props.asset.id, this.props.pending);
@@ -36,8 +51,12 @@ class SettingsContainer extends React.Component {
return <Settings
settings={this.props.mergedSettings}
savePending={this.savePending}
toggleModeration={this.toggleModeration}
togglePremodLinks={this.togglePremodLinks}
onToggleModeration={this.toggleModeration}
onTogglePremodLinks={this.togglePremodLinks}
onToggleQuestionBox={this.toggleQuestionBox}
onQuestionBoxIconChange={this.setQuestionBoxIcon}
onQuestionBoxContentChange={this.setQuestionBoxContent}
/>;
}
}
@@ -59,6 +78,9 @@ const withSettingsFragments = withFragments({
settings {
moderation
premodLinksEnable
questionBoxEnable
questionBoxIcon
questionBoxContent
}
}
`,
@@ -252,7 +252,14 @@ class Stream extends React.Component {
content={asset.settings.questionBoxContent}
enable={asset.settings.questionBoxEnable}
icon={asset.settings.questionBoxIcon}
/>
>
<Slot
fill="streamQuestionArea"
queryData={slotQueryData}
{...slotProps}
/>
</QuestionBox>
{!banned &&
temporarilySuspended &&
<RestrictedMessageBox>