mirror of
https://github.com/wassname/talk.git
synced 2026-07-01 17:29:06 +08:00
Merge branch 'master' into refactor-global-dependencies
This commit is contained in:
@@ -5,10 +5,9 @@ const path = require('path');
|
||||
const helmet = require('helmet');
|
||||
const compression = require('compression');
|
||||
const cookieParser = require('cookie-parser');
|
||||
const {ROOT_URL, ROOT_URL_MOUNT_PATH} = require('./config');
|
||||
const {BASE_URL, BASE_PATH, MOUNT_PATH} = require('./url');
|
||||
const routes = require('./routes');
|
||||
const debug = require('debug')('talk:app');
|
||||
const {URL} = require('url');
|
||||
|
||||
const app = express();
|
||||
|
||||
@@ -51,17 +50,6 @@ app.set('view engine', 'ejs');
|
||||
// ROUTES
|
||||
//==============================================================================
|
||||
|
||||
// Set the BASE_URL as the ROOT_URL, here we derive the root url by ensuring
|
||||
// that it ends in a `/`.
|
||||
const BASE_URL = ROOT_URL && ROOT_URL.length > 0 && ROOT_URL[ROOT_URL.length - 1] === '/' ? ROOT_URL : `${ROOT_URL}/`;
|
||||
|
||||
// The BASE_PATH is simply the path component of the BASE_URL.
|
||||
const BASE_PATH = new URL(BASE_URL).pathname;
|
||||
|
||||
// The MOUNT_PATH is derived from the BASE_PATH, if it is provided and enabled.
|
||||
// This will mount all the application routes onto it.
|
||||
const MOUNT_PATH = ROOT_URL_MOUNT_PATH ? BASE_PATH : '/';
|
||||
|
||||
// Apply the BASE_PATH, BASE_URL, and MOUNT_PATH on the app.locals, which will
|
||||
// make them available on the templates and the routers.
|
||||
app.locals.BASE_URL = BASE_URL;
|
||||
|
||||
@@ -3,12 +3,11 @@
|
||||
color: white;
|
||||
background: grey;
|
||||
box-sizing: border-box;
|
||||
padding: 0px 5px;
|
||||
border-radius: 2px;
|
||||
padding: 2px 5px;
|
||||
font-size: 12px;
|
||||
height: 24px;
|
||||
letter-spacing: 0.4px;
|
||||
margin-bottom: 1px;
|
||||
line-height: 22px;
|
||||
|
||||
> i {
|
||||
font-size: 14px;
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
import React from 'react';
|
||||
import {Badge} from 'coral-ui';
|
||||
import t from 'coral-framework/services/i18n';
|
||||
|
||||
const ReplyBadge = () => (
|
||||
<Badge icon="reply">
|
||||
{t('modqueue.reply')}
|
||||
</Badge>
|
||||
);
|
||||
|
||||
export default ReplyBadge;
|
||||
@@ -55,7 +55,7 @@
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.commentType {
|
||||
.badgeBar {
|
||||
position: absolute;
|
||||
right: 0px;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ import {Link} from 'react-router';
|
||||
|
||||
import {Icon} from 'coral-ui';
|
||||
import FlagBox from './FlagBox';
|
||||
import ReplyBadge from './ReplyBadge';
|
||||
import styles from './UserDetailComment.css';
|
||||
import CommentType from './CommentType';
|
||||
import {getActionSummary} from 'coral-framework/utils';
|
||||
@@ -56,7 +57,11 @@ class UserDetailComment extends React.Component {
|
||||
? <span> <span className={styles.editedMarker}>({t('comment.edited')})</span></span>
|
||||
: null
|
||||
}
|
||||
<CommentType type={commentType} className={styles.commentType}/>
|
||||
|
||||
<div className={styles.badgeBar}>
|
||||
{comment.hasParent && <ReplyBadge/>}
|
||||
<CommentType type={commentType}/>
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.story}>
|
||||
Story: {comment.asset.title}
|
||||
|
||||
@@ -9,6 +9,7 @@ export default withFragments({
|
||||
body
|
||||
created_at
|
||||
status
|
||||
hasParent
|
||||
asset {
|
||||
id
|
||||
title
|
||||
|
||||
@@ -2,6 +2,7 @@ import React, {PropTypes} from 'react';
|
||||
import {Link} from 'react-router';
|
||||
|
||||
import {Icon} from 'coral-ui';
|
||||
import ReplyBadge from 'coral-admin/src/components/ReplyBadge';
|
||||
import FlagBox from 'coral-admin/src/components/FlagBox';
|
||||
import styles from './styles.css';
|
||||
import CommentType from 'coral-admin/src/components/CommentType';
|
||||
@@ -107,6 +108,7 @@ class Comment extends React.Component {
|
||||
</ActionsMenu>
|
||||
}
|
||||
<div className={styles.adminCommentInfoBar}>
|
||||
{comment.hasParent && <ReplyBadge/>}
|
||||
<CommentType type={commentType} className={styles.commentType}/>
|
||||
<Slot
|
||||
fill="adminCommentInfoBar"
|
||||
|
||||
@@ -37,6 +37,7 @@ export default withFragments({
|
||||
count
|
||||
... on FlagActionSummary {
|
||||
reason
|
||||
__typename
|
||||
}
|
||||
}
|
||||
actions {
|
||||
@@ -48,11 +49,14 @@ export default withFragments({
|
||||
id
|
||||
username
|
||||
}
|
||||
__typename
|
||||
}
|
||||
__typename
|
||||
}
|
||||
editing {
|
||||
edited
|
||||
}
|
||||
hasParent
|
||||
${getSlotFragmentSpreads(slots, 'comment')}
|
||||
}
|
||||
`
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
.badge {
|
||||
display: inline-block;
|
||||
color: white;
|
||||
background: grey;
|
||||
box-sizing: border-box;
|
||||
padding: 2px 5px;
|
||||
font-size: 12px;
|
||||
height: 24px;
|
||||
letter-spacing: 0.4px;
|
||||
line-height: 22px;
|
||||
background-color: #3D73D5;
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
.icon {
|
||||
font-size: 14px;
|
||||
vertical-align: text-top;
|
||||
margin: 0;
|
||||
margin-right: 4px;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import React from 'react';
|
||||
import styles from './Badge.css';
|
||||
import Icon from './Icon';
|
||||
import cn from 'classnames';
|
||||
|
||||
const Badge = ({className, children, icon, props}) => (
|
||||
<span className={cn(styles.badge, className)} {...props}>
|
||||
{icon && <Icon name={icon} className={styles.icon} />}
|
||||
{children}
|
||||
</span>
|
||||
);
|
||||
|
||||
export default Badge;
|
||||
@@ -26,3 +26,4 @@ export {default as Option} from './components/Option';
|
||||
export {default as SnackBar} from './components/SnackBar';
|
||||
export {default as TextArea} from './components/TextArea';
|
||||
export {default as Drawer} from './components/Drawer';
|
||||
export {default as Badge} from './components/Badge';
|
||||
|
||||
@@ -2,10 +2,11 @@ import React, {PropTypes} from 'react';
|
||||
import styles from './styles.css';
|
||||
|
||||
import t from 'coral-framework/services/i18n';
|
||||
import {BASE_PATH} from 'coral-framework/constants/url';
|
||||
|
||||
const ModerationLink = (props) => props.isAdmin ? (
|
||||
<div className={styles.moderationLink}>
|
||||
<a href={`/admin/moderate/${props.assetId}`} target="_blank">
|
||||
<a href={`${BASE_PATH}admin/moderate/${props.assetId}`} target="_blank">
|
||||
{t('moderate_this_stream')}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
const {decorateWithTags} = require('./util');
|
||||
|
||||
const Comment = {
|
||||
hasParent({parent_id}) {
|
||||
return !!parent_id;
|
||||
},
|
||||
parent({parent_id}, _, {loaders: {Comments}}) {
|
||||
if (parent_id == null) {
|
||||
return null;
|
||||
|
||||
@@ -26,6 +26,8 @@ const {
|
||||
SUBSCRIBE_ALL_USERNAME_REJECTED,
|
||||
} = require('../perms/constants');
|
||||
|
||||
const {BASE_PATH} = require('../url');
|
||||
|
||||
/**
|
||||
* Plugin support requires that we merge in existing setupFunctions with our new
|
||||
* plugin based ones. This allows plugins to extend existing setupFunctions as well
|
||||
@@ -170,7 +172,7 @@ const createSubscriptionManager = (server) => new SubscriptionServer({
|
||||
keepAlive: ms(KEEP_ALIVE)
|
||||
}, {
|
||||
server,
|
||||
path: '/api/v1/live'
|
||||
path: `${BASE_PATH}api/v1/live`
|
||||
});
|
||||
|
||||
module.exports = {
|
||||
|
||||
@@ -339,6 +339,9 @@ type Comment {
|
||||
|
||||
# describes how the comment can be edited
|
||||
editing: EditInfo
|
||||
|
||||
# Indicates if it has a parent
|
||||
hasParent: Boolean
|
||||
}
|
||||
|
||||
# CommentConnection represents a paginable subset of a comment list.
|
||||
|
||||
@@ -281,6 +281,7 @@ en:
|
||||
prev_comment: "Go to the previous comment"
|
||||
reject: "Reject"
|
||||
rejected: "Rejected"
|
||||
reply: "Reply"
|
||||
select_stream: "Select Stream"
|
||||
shift_key: "⇧"
|
||||
shortcuts: "Shortcuts"
|
||||
|
||||
@@ -272,6 +272,7 @@ es:
|
||||
prev_comment: "Ir al comentario anterior"
|
||||
reject: "Rechazar"
|
||||
rejected: "rechazado"
|
||||
reply: "Respuesta"
|
||||
select_stream: "Seleccionar hilo de comentarios"
|
||||
shift_key: ⇧
|
||||
shortcuts: Atajos
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
const {ROOT_URL, ROOT_URL_MOUNT_PATH} = require('./config');
|
||||
const {URL} = require('url');
|
||||
|
||||
// Set the BASE_URL as the ROOT_URL, here we derive the root url by ensuring
|
||||
// that it ends in a `/`.
|
||||
const BASE_URL = ROOT_URL && ROOT_URL.length > 0 && ROOT_URL[ROOT_URL.length - 1] === '/' ? ROOT_URL : `${ROOT_URL}/`;
|
||||
|
||||
// The BASE_PATH is simply the path component of the BASE_URL.
|
||||
const BASE_PATH = new URL(BASE_URL).pathname;
|
||||
|
||||
// The MOUNT_PATH is derived from the BASE_PATH, if it is provided and enabled.
|
||||
// This will mount all the application routes onto it.
|
||||
const MOUNT_PATH = ROOT_URL_MOUNT_PATH ? BASE_PATH : '/';
|
||||
|
||||
module.exports = {
|
||||
BASE_URL: BASE_URL,
|
||||
BASE_PATH: BASE_PATH,
|
||||
MOUNT_PATH: MOUNT_PATH,
|
||||
};
|
||||
+1
-1
@@ -22,7 +22,7 @@
|
||||
<main>
|
||||
<h1><%= title %></h1>
|
||||
<p><%= body %></p>
|
||||
<p><a href="admin">Admin</a> - <a href="assets">All Assets</a></p>
|
||||
<p><a href="<%= BASE_PATH %>admin">Admin</a> - <a href="<%= BASE_PATH %>assets">All Assets</a></p>
|
||||
<div id='coralStreamEmbed'></div>
|
||||
<script src="<%= BASE_URL %>embed.js" async onload="
|
||||
window.TalkEmbed = Coral.Talk.render(document.getElementById('coralStreamEmbed'), {
|
||||
|
||||
Reference in New Issue
Block a user