diff --git a/bin/cli-plugins b/bin/cli-plugins
index b1dee381b..942036d29 100755
--- a/bin/cli-plugins
+++ b/bin/cli-plugins
@@ -8,13 +8,14 @@
// https://yarnpkg.com/
const program = require('./commander');
+const inquirer = require('inquirer');
// Make things colorful!
require('colors');
const emoji = require('node-emoji');
const dir = process.cwd();
-const fs = require('fs');
+const fs = require('fs-extra');
const path = require('path');
const spawn = require('cross-spawn');
const semver = require('semver');
@@ -272,10 +273,128 @@ async function reconcilePluginDeps({skipLocal, skipRemote, dryRun, upgradeRemote
console.log(`✨ Done in ${totalTime}s.`);
}
+async function createSeedPlugin() {
+ const pluginsDir = path.join(__dirname, 'plugins');
+
+ function pluginNameExists(pluginName) {
+ const pluginNames = fs.readdirSync(pluginsDir);
+ return !!pluginNames
+ .filter((pn) => pn === pluginName).length;
+ }
+
+ let answers = await inquirer.prompt([
+ {
+ type: 'input',
+ name: 'pluginName',
+ message: 'Plugin Name:',
+ validate: (input) => {
+
+ if (pluginNameExists(input)) {
+ return 'Please, choose another name. That name already exists';
+ }
+
+ if (input && input.length > 0) {
+ return true;
+ }
+
+ return 'Plugin Name is required.';
+ }
+ },
+ {
+ type: 'confirm',
+ name: 'server',
+ message: 'Is this plugin extending the server capabilities?'
+ },
+ {
+ type: 'confirm',
+ name: 'client',
+ message: 'Is this plugin extending the client capabilities?'
+ },
+ {
+ type: 'confirm',
+ name: 'addPluginsJson',
+ message: 'Should we add it to the plugins.json?'
+ }
+ ]);
+
+ //==============================================================================
+ // Creating plugin seed
+ //==============================================================================
+
+ const seedPlugin = path.join(__dirname, 'bin/templates/plugin');
+ const newPluginPath = path.join(pluginsDir, answers.pluginName);
+
+ if (fs.existsSync(seedPlugin)) {
+
+ if (answers.server && answers.client) {
+
+ // This is a server-side and client-side plugin!, let's copy the template
+ fs.copySync(seedPlugin, newPluginPath);
+ } else {
+
+ fs.copySync(seedPlugin, newPluginPath, {filter: (p) => {
+
+ // Allowing plugin folder and files with no subfolders
+ const rootRx = /plugin$|plugin\/[^/]*(\.).{2,3}/igm;
+ if (rootRx.test(p) && (fs.lstatSync(p).isDirectory() || fs.lstatSync(p).isFile())) {
+ return true;
+ }
+
+ // If it's a client-side plugin, copying client folder
+ if (answers.client) {
+ return /client/.test(p);
+ }
+
+ // If it's a server-side plugin, copying server folder
+ if (answers.server) {
+ return /server/.test(p);
+ }
+
+ }});
+ }
+
+ // Let's add this to the plugins.json
+ if (answers.addPluginsJson) {
+ const pluginsJson = path.join(dir, 'plugins.json');
+
+ fs.readJson(pluginsJson)
+ .then((j) => {
+
+ // This is a client-side plugin, let's push this.
+ if (answers.client) {
+ j.client.push(answers.pluginName);
+
+ const output = JSON.stringify(j, null, 2);
+ fs.writeFileSync(pluginsJson, output);
+ }
+
+ // This is a server-side plugin, let's push this.
+ if (answers.server) {
+ j.server.push(answers.pluginName);
+
+ const output = JSON.stringify(j, null, 2);
+ fs.writeFileSync(pluginsJson, output);
+ }
+ })
+ .catch((err) => {
+ console.error(err);
+ });
+ }
+
+ console.log(`✨ Yay! Plugin created! Find your plugin: ${answers.pluginName} in the ./plugins folder`);
+ }
+
+}
+
//==============================================================================
// Setting up the program command line arguments.
//==============================================================================
+program
+ .command('create')
+ .description('creates a seed plugin')
+ .action(createSeedPlugin);
+
program
.command('list')
.description('')
diff --git a/bin/templates/plugin/client/.babelrc b/bin/templates/plugin/client/.babelrc
new file mode 100644
index 000000000..60be246eb
--- /dev/null
+++ b/bin/templates/plugin/client/.babelrc
@@ -0,0 +1,14 @@
+{
+ "presets": [
+ "es2015"
+ ],
+ "plugins": [
+ "add-module-exports",
+ "transform-class-properties",
+ "transform-decorators-legacy",
+ "transform-object-assign",
+ "transform-object-rest-spread",
+ "transform-async-to-generator",
+ "transform-react-jsx"
+ ]
+}
\ No newline at end of file
diff --git a/bin/templates/plugin/client/.eslintrc.json b/bin/templates/plugin/client/.eslintrc.json
new file mode 100644
index 000000000..9fe56bd14
--- /dev/null
+++ b/bin/templates/plugin/client/.eslintrc.json
@@ -0,0 +1,23 @@
+{
+ "env": {
+ "browser": true,
+ "es6": true,
+ "mocha": true
+ },
+ "parserOptions": {
+ "sourceType": "module",
+ "ecmaFeatures": {
+ "experimentalObjectRestSpread": true,
+ "jsx": true
+ }
+ },
+ "parser": "babel-eslint",
+ "plugins": [
+ "react"
+ ],
+ "rules": {
+ "react/jsx-uses-react": "error",
+ "react/jsx-uses-vars": "error",
+ "no-console": ["warn", { "allow": ["warn", "error"] }]
+ }
+}
diff --git a/bin/templates/plugin/client/components/MyPluginComponent.css b/bin/templates/plugin/client/components/MyPluginComponent.css
new file mode 100644
index 000000000..187e68750
--- /dev/null
+++ b/bin/templates/plugin/client/components/MyPluginComponent.css
@@ -0,0 +1,27 @@
+.myPluginContainer {
+ padding: 10px;
+ background: #f0f0f0;
+ border: 1px solid #d6d6d6;
+ margin: 10px 0;
+ text-align: center;
+ border-radius: 3px;
+}
+
+.logo {
+ position: block;
+ animation: spin 2s infinite ease;
+ animation-delay: 1s;
+}
+
+@keyframes spin {
+ 0% {
+ transform: rotate(0deg);
+ }
+ 100% {
+ transform: rotate(360deg);
+ }
+}
+
+.description {
+ color: #444444;
+}
diff --git a/bin/templates/plugin/client/components/MyPluginComponent.js b/bin/templates/plugin/client/components/MyPluginComponent.js
new file mode 100644
index 000000000..89e274e1a
--- /dev/null
+++ b/bin/templates/plugin/client/components/MyPluginComponent.js
@@ -0,0 +1,25 @@
+import React from 'react';
+import {CoralLogo} from 'plugin-api/beta/client/components/ui';
+import styles from './MyPluginComponent.css';
+
+class MyPluginComponent extends React.Component {
+ render() {
+ return (
+
+ );
+ }
+}
+
+export default MyPluginComponent;
diff --git a/bin/templates/plugin/client/index.js b/bin/templates/plugin/client/index.js
new file mode 100644
index 000000000..acd0910be
--- /dev/null
+++ b/bin/templates/plugin/client/index.js
@@ -0,0 +1,26 @@
+
+/**
+ This is a client index example file and it could look like this:
+
+ ```
+ import LoveButton from './components/LoveButton';
+
+ export default {
+ slots: {
+ commentReactions: [LoveButton]
+ },
+ reducer,
+ translations
+ };
+ ```
+
+ To read more info on how to build client plugins. Please, go to: https://coralproject.github.io/talk/plugins-client.html
+ */
+
+import MyPluginComponent from './components/MyPluginComponent';
+
+export default {
+ slots: {
+ stream: [MyPluginComponent]
+ }
+};
diff --git a/bin/templates/plugin/client/translations.yml b/bin/templates/plugin/client/translations.yml
new file mode 100644
index 000000000..d8407b801
--- /dev/null
+++ b/bin/templates/plugin/client/translations.yml
@@ -0,0 +1,15 @@
+#
+# This file is for translations and they should look like this:
+#
+#
+# ```
+# en:
+# coral-plugin-respect:
+# respect: Respect
+# respected: Respected
+# es:
+# coral-plugin-respect:
+# respect: Respetar
+# respected: Respetado
+# ```
+#
diff --git a/bin/templates/plugin/index.js b/bin/templates/plugin/index.js
new file mode 100644
index 000000000..f053ebf79
--- /dev/null
+++ b/bin/templates/plugin/index.js
@@ -0,0 +1 @@
+module.exports = {};
diff --git a/client/coral-embed-stream/src/components/Embed.js b/client/coral-embed-stream/src/components/Embed.js
index 145e8340a..98137624f 100644
--- a/client/coral-embed-stream/src/components/Embed.js
+++ b/client/coral-embed-stream/src/components/Embed.js
@@ -9,6 +9,7 @@ import Count from 'coral-plugin-comment-count/CommentCount';
import ProfileContainer from 'coral-settings/containers/ProfileContainer';
import ConfigureStreamContainer
from 'coral-configure/containers/ConfigureStreamContainer';
+import cn from 'classnames';
export default class Embed extends React.Component {
changeTab = (tab) => {
@@ -37,34 +38,36 @@ export default class Embed extends React.Component {
const {activeTab, viewAllComments, commentId} = this.props;
const {asset: {totalCommentCount}} = this.props.root;
const {user} = this.props.auth;
+ const hasHighlightedComment = !!commentId;
return (
-
-
-
-
- {t('framework.my_profile')}
- {t('framework.configure_stream')}
-
- {commentId &&
-
}
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+ {t('framework.my_profile')}
+
+ {t('framework.configure_stream')}
+
+
+ {commentId &&
+
}
+
+
+
+
+
+
+
+
+
+
);
}
diff --git a/client/coral-embed-stream/src/index.js b/client/coral-embed-stream/src/index.js
index f5be3922d..9020a8457 100644
--- a/client/coral-embed-stream/src/index.js
+++ b/client/coral-embed-stream/src/index.js
@@ -48,5 +48,5 @@ render(
- , document.querySelector('#coralStream')
+ , document.querySelector('#talk-embed-stream-container')
);
diff --git a/client/coral-framework/helpers/plugins.js b/client/coral-framework/helpers/plugins.js
index ab5e3080e..2e5934bc4 100644
--- a/client/coral-framework/helpers/plugins.js
+++ b/client/coral-framework/helpers/plugins.js
@@ -15,9 +15,9 @@ function getSlotComponents(slot) {
// Filter out components that have been disabled in `plugin_config`
return flatten(plugins
-
- // Filter out components that have been disabled in `plugin_config`
- .filter((o) => !pluginConfig || !pluginConfig[o.plugin] || !pluginConfig[o.plugin].disable_components)
+
+ // Filter out components that have slots and have been disabled in `plugin_config`
+ .filter((o) => o.module.slots && (!pluginConfig || !pluginConfig[o.plugin] || !pluginConfig[o.plugin].disable_components))
.filter((o) => o.module.slots[slot])
.map((o) => o.module.slots[slot]));
@@ -78,7 +78,7 @@ export function getSlotsFragments(slots) {
}
const components = uniq(flattenDeep(slots.map((slot) => {
return plugins
- .filter((o) => o.module.slots[slot])
+ .filter((o) => o.module.slots ? o.module.slots[slot] : false)
.map((o) => o.module.slots[slot]);
})));
diff --git a/client/coral-plugin-flags/components/FlagButton.js b/client/coral-plugin-flags/components/FlagButton.js
index 25fcf21a9..33499e83d 100644
--- a/client/coral-plugin-flags/components/FlagButton.js
+++ b/client/coral-plugin-flags/components/FlagButton.js
@@ -148,7 +148,7 @@ export default class FlagButton extends Component {