Commit 097ad328 authored by Dan Notestein's avatar Dan Notestein
Browse files

Merge branch '144-fix-storybook' into 'develop'

Resolve "Fix storybook"

Closes #144

See merge request !278
parents f0685af3 c6c73f3e
......@@ -4,6 +4,7 @@
"@babel/plugin-transform-runtime",
["@babel/plugin-proposal-decorators", { "legacy": true }],
"@babel/plugin-proposal-class-properties",
"@babel/plugin-transform-modules-commonjs"
"@babel/plugin-transform-modules-commonjs",
"babel-plugin-transform-class-properties"
]
}
......@@ -40,6 +40,8 @@ find node_modules/eslint-config-airbnb -name '*.js'|xargs sed -i "s/': 2/': 1/"
"no-nested-ternary": [
0
],
"import/no-dynamic-require": 1,
"global-require": 1,
"prefer-destructuring": 0,
"react/no-unused-state": 1,
"no-unused-expressions": 1,
......@@ -48,6 +50,7 @@ find node_modules/eslint-config-airbnb -name '*.js'|xargs sed -i "s/': 2/': 1/"
"no-undef": 2,
"no-case-declarations": 0,
"no-underscore-dangle": 0,
"no-inner-declarations": 1,
"camelcase": [
0
],
......
......@@ -9,3 +9,5 @@ vendor/*
tmp/*
.vagrant
lib
*.bk
docs
import '@storybook/addon-knobs/register';
import 'storybook-addon-intl/register';
\ No newline at end of file
import { addDecorator, configure } from '@storybook/react';
import { setIntlConfig, withIntl } from 'storybook-addon-intl';
import tt from 'counterpart';
import { addLocaleData } from 'react-intl';
import en from 'react-intl/locale-data/en';
import es from 'react-intl/locale-data/es';
import ru from 'react-intl/locale-data/ru';
import fr from 'react-intl/locale-data/fr';
import it from 'react-intl/locale-data/it';
import ko from 'react-intl/locale-data/ko';
import zh from 'react-intl/locale-data/zh';
import pl from 'react-intl/locale-data/pl';
addLocaleData([...en, ...es, ...ru, ...fr, ...it, ...ko, ...zh, ...pl]);
tt.registerTranslations('en', require('counterpart/locales/en'));
tt.registerTranslations('en', require('app/locales/en.json'));
tt.registerTranslations('es', require('app/locales/counterpart/es'));
tt.registerTranslations('es', require('app/locales/es.json'));
tt.registerTranslations('ru', require('counterpart/locales/ru'));
tt.registerTranslations('ru', require('app/locales/ru.json'));
tt.registerTranslations('fr', require('app/locales/counterpart/fr'));
tt.registerTranslations('fr', require('app/locales/fr.json'));
tt.registerTranslations('it', require('app/locales/counterpart/it'));
tt.registerTranslations('it', require('app/locales/it.json'));
tt.registerTranslations('ko', require('app/locales/counterpart/ko'));
tt.registerTranslations('ko', require('app/locales/ko.json'));
tt.registerTranslations('zh', require('app/locales/counterpart/zh'));
tt.registerTranslations('zh', require('app/locales/zh.json'));
tt.registerTranslations('pl', require('app/locales/counterpart/pl'));
tt.registerTranslations('pl', require('app/locales/pl.json'));
const getMessages = (locale) => {
tt.setLocale(locale)
return tt('g')
}
setIntlConfig({
locales: ['en', 'es', 'ru', 'fr', 'it', 'ko', 'zh', 'pl'],
defaultLocale: 'en',
getMessages
});
addDecorator(withIntl);
const req = require.context('../src/app/components', true, /story\.jsx$/);
function loadStories() {
req.keys().forEach(req);
}
configure(loadStories, module);
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const path = require('path');
const css_loaders = [
{ loader: 'style-loader' },
{ loader: 'css-loader' },
{ loader: 'postcss-loader' }
];
const scss_loaders = [
{ loader: 'css-loader' },
{ loader: 'postcss-loader' },
{
loader: 'sass-loader',
options: {
sourceMap: true,
data: '@import "app";',
includePaths: [
path.join(__dirname, '../src/app/assets/stylesheets'),
]
}
},
];
module.exports = {
stories: [
// "../src/**/*.stories.mdx",
"../src/**/*.stories.@(js|jsx|ts|tsx)"
],
addons: [
"@storybook/addon-links",
"@storybook/addon-essentials",
"@storybook/addon-knobs",
"storybook-addon-intl/register",
'@storybook/addon-postcss',
{
name: '@storybook/addon-postcss',
options: {
postcssLoaderOptions: {
implementation: require('postcss'),
},
},
},
],
webpackFinal: async (config, { configType }) => {
config.resolve = {
alias: {
assets: path.resolve(__dirname, '../src/app/assets/'),
app: path.resolve(__dirname, '../src/app/'),
},
extensions: ['.js', '.json', '.jsx'],
modules: [
path.resolve(__dirname, '../src'),
'node_modules'
]
};
config.module = {
rules: [
{test: /\.(jpe?g|png)/, use: 'url-loader?limit=4096'},
// {test: /\.json$/, use: 'json-loader'},
{test: /\.js$|\.jsx$/, exclude: /node_modules/, use: 'babel-loader'},
{test: /\.svg$/, use: 'svg-inline-loader'},
{
test: /\.css$/,
use: css_loaders
},
{
test: /\.scss$/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: scss_loaders
})
},
]
};
return {
...config,
};
},
}
module.exports = {
plugins: [
require('autoprefixer'),
],
};
import React from 'react';
import '!style-loader!css-loader!sass-loader!../src/app/assets/stylesheets/app.scss';
const { addDecorator, configure } = require('@storybook/react');
const { setIntlConfig, withIntl } = require('storybook-addon-intl');
const tt = require('counterpart');
const { addLocaleData } = require('react-intl');
const en = require('react-intl/locale-data/en');
const es = require('react-intl/locale-data/es');
const ru = require('react-intl/locale-data/ru');
const fr = require('react-intl/locale-data/fr');
const it = require('react-intl/locale-data/it');
const ko = require('react-intl/locale-data/ko');
const zh = require('react-intl/locale-data/zh');
const pl = require('react-intl/locale-data/pl');
const { addons, mockChannel } = require('@storybook/addons');
addons.setChannel(mockChannel());
addLocaleData([...en, ...es, ...ru, ...fr, ...it, ...ko, ...zh, ...pl]);
tt.registerTranslations('en', require('counterpart/locales/en'));
tt.registerTranslations('en', require('../src/app/locales/en.json'));
tt.registerTranslations('es', require('../src/app/locales/counterpart/es'));
tt.registerTranslations('es', require('../src/app/locales/es.json'));
tt.registerTranslations('ru', require('counterpart/locales/ru'));
tt.registerTranslations('ru', require('../src/app/locales/ru.json'));
tt.registerTranslations('fr', require('../src/app/locales/counterpart/fr'));
tt.registerTranslations('fr', require('../src/app/locales/fr.json'));
tt.registerTranslations('it', require('../src/app/locales/counterpart/it'));
tt.registerTranslations('it', require('../src/app/locales/it.json'));
tt.registerTranslations('ko', require('../src/app/locales/counterpart/ko'));
tt.registerTranslations('ko', require('../src/app/locales/ko.json'));
tt.registerTranslations('zh', require('../src/app/locales/counterpart/zh'));
tt.registerTranslations('zh', require('../src/app/locales/zh.json'));
tt.registerTranslations('pl', require('../src/app/locales/counterpart/pl'));
tt.registerTranslations('pl', require('../src/app/locales/pl.json'));
const getMessages = (locale) => {
tt.setLocale(locale)
return tt('g')
}
setIntlConfig({
locales: ['en', 'es', 'ru', 'fr', 'it', 'ko', 'zh', 'pl'],
defaultLocale: 'en',
getMessages
});
const container = {
display: 'table',
position: 'absolute',
height: '100%',
width: '100%',
};
const middle = {
display: 'table-cell',
verticalAlign: 'middle',
};
const center = {
marginLeft: 'auto',
marginRight: 'auto',
//border: 'solid black',
width: '300px',
};
export const parameters = {
actions: { argTypesRegex: "^on[A-Z].*" },
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/,
},
},
}
export const decorators = [
(Story) => (
<div style={container}>
<div style={middle}>
<div style={center}>
<Story/>
</div>
</div>
</div>
),
withIntl,
];
require('@babel/register');
module.exports = require('../webpack/storybook.config.js');
......@@ -10,8 +10,8 @@
"scripts": {
"build": "NODE_ENV=production webpack --config ./webpack/prod.config.js && rm -rf ./lib && babel src --out-dir lib -D",
"test": "jest",
"eslint": "LIST=`git diff-index --name-only HEAD | grep .*\\.js | grep -v json`; if [ \"$LIST\" ]; then eslint $LIST; fi",
"eslint:fix": "LIST=`git diff-index --name-only HEAD | grep .*\\.js | grep -v json`; if [ \"$LIST\" ]; then eslint --fix $LIST; fi",
"eslint": "LIST=`git diff-index --diff-filter=ACMR --name-only HEAD | grep .*\\.js | grep -v json`; if [ \"$LIST\" ]; then eslint $LIST; fi",
"eslint:fix": "LIST=`git diff-index --diff-filter=ACMR --name-only HEAD | grep .*\\.js | grep -v json`; if [ \"$LIST\" ]; then eslint --fix $LIST; fi",
"ci:test": "jest --coverage",
"ci:eslint": "eslint src/",
"fmt": "prettier --config .prettierrc --write 'src/**/*.+(js|jsx)'",
......@@ -20,9 +20,10 @@
"start": "NODE_OPTIONS=\"--trace-warnings\" NODE_ENV=development babel-node ./webpack/dev-server.js",
"debug": "NODE_OPTIONS=\"--trace-warnings\" NODE_ENV=development webpack --config ./webpack/debug.config.js && rm -rf ./lib && babel src --source-maps --out-dir lib -D && node --inspect-brk lib/server/index.js",
"checktranslations": "node scripts/check_translations.js",
"storybook": "start-storybook -p 9001 -c .storybook",
"storybook": "start-storybook --no-manager-cache -p 6006",
"storybook-build": "build-storybook -c .storybook -o docs",
"build:analyze": "webpack-bundle-analyzer --port 4200 dist/stats.json"
"build:analyze": "webpack-bundle-analyzer --port 4200 dist/stats.json",
"build:storybook": "build-storybook"
},
"author": "HiveBlog",
"license": "MIT",
......@@ -160,13 +161,18 @@
"@babel/preset-env": "^7.0.0",
"@babel/preset-react": "^7.0.0",
"@babel/register": "^7.12.1",
"@storybook/addon-actions": "^6.3.8",
"@storybook/addon-essentials": "^6.3.8",
"@storybook/addon-knobs": "^6.3.1",
"@storybook/addon-links": "^6.3.8",
"@storybook/addon-postcss": "^2.0.0",
"@storybook/react": "^6.3.8",
"babel-core": "^7.0.0-bridge.0",
"babel-eslint": "10.1.0",
"babel-jest": "^23.4.2",
"babel-loader": "8.1.0",
"babel-plugin-react-intl": "2.3.1",
"babel-plugin-transform-class-properties": "^6.24.1",
"babel-plugin-transform-inline-environment-variables": "0.2.0",
"css-loader": "5.0.1",
"dev-ip": "1.0.1",
......
/*global $STM_Config*/
import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
......@@ -50,15 +51,17 @@ class App extends React.Component {
}
shouldComponentUpdate(nextProps, nextState) {
const { pathname, new_visitor, nightmodeEnabled, showAnnouncement } = this.props;
const {
pathname, new_visitor, nightmodeEnabled, showAnnouncement
} = this.props;
const n = nextProps;
return (
pathname !== n.pathname ||
new_visitor !== n.new_visitor ||
this.state.showBanner !== nextState.showBanner ||
this.state.showCallout !== nextState.showCallout ||
nightmodeEnabled !== n.nightmodeEnabled ||
showAnnouncement !== n.showAnnouncement
pathname !== n.pathname
|| new_visitor !== n.new_visitor
|| this.state.showBanner !== nextState.showBanner
|| this.state.showCallout !== nextState.showCallout
|| nightmodeEnabled !== n.nightmodeEnabled
|| showAnnouncement !== n.showAnnouncement
);
}
......@@ -67,14 +70,15 @@ class App extends React.Component {
};
render() {
const { params, children, new_visitor, nightmodeEnabled, viewMode, pathname, category, order } = this.props;
const {
params, children, new_visitor, nightmodeEnabled, viewMode, pathname, category, order,
} = this.props;
const whistleView = viewMode === VIEW_MODE_WHISTLE;
const headerHidden = whistleView;
const params_keys = Object.keys(params);
const ip =
pathname === '/' ||
(params_keys.length === 2 && params_keys[0] === 'order' && params_keys[1] === 'category');
const ip = pathname === '/'
|| (params_keys.length === 2 && params_keys[0] === 'order' && params_keys[1] === 'category');
const alert = this.props.error;
let callout = null;
if (this.state.showCallout && alert) {
......@@ -92,15 +96,13 @@ class App extends React.Component {
callout = (
<div className="App__announcement row">
<div className="column">
<div className={classNames('callout success', { alert }, { warning }, { success })}>
<div className={classNames('callout success', { alert })}>
<CloseButton onClick={() => this.setState({ showCallout: false })} />
<ul>
<li>
/*
<a href="https://steemit.com/steemit/@steemitblog/steemit-com-is-now-open-source">
...STORY TEXT...
</a>
*/
</li>
</ul>
</div>
......@@ -112,7 +114,7 @@ class App extends React.Component {
callout = (
<div className="App__announcement row">
<div className="column">
<div className={classNames('callout warning', { alert }, { warning }, { success })}>
<div className={classNames('callout warning', { alert })}>
<CloseButton onClick={() => this.setState({ showCallout: false })} />
<p>{tt('g.read_only_mode')}</p>
</div>
......@@ -161,17 +163,14 @@ App.propTypes = {
export default connect(
(state, ownProps) => {
const current_user = state.user.get('current');
const current_account_name = current_user ? current_user.get('username') : state.offchain.get('account');
return {
viewMode: state.app.get('viewMode'),
error: state.app.get('error'),
new_visitor:
!state.user.get('current') &&
!state.offchain.get('user') &&
!state.offchain.get('account') &&
state.offchain.get('new_visit'),
!state.user.get('current')
&& !state.offchain.get('user')
&& !state.offchain.get('account')
&& state.offchain.get('new_visit'),
nightmodeEnabled: state.app.getIn(['user_preferences', 'nightmode']),
pathname: ownProps.location.pathname,
......
import React, { PureComponent } from 'react';
import Autocomplete from 'react-autocomplete';
// import shouldComponentUpdate from 'app/utils/shouldComponentUpdate';
// import shouldComponentUpdate from 'app/utils/shouldComponentUpdate';
import { validate_account_name } from 'app/utils/ChainValidation';
import { List, Set } from 'immutable';
import tt from 'counterpart';
......
......@@ -6,7 +6,7 @@ import ReplyEditor from 'app/components/elements/ReplyEditor';
import MuteButton from 'app/components/elements/MuteButton';
import FlagButton from 'app/components/elements/FlagButton';
import MarkdownViewer from 'app/components/cards/MarkdownViewer';
// import shouldComponentUpdate from 'app/utils/shouldComponentUpdate';
// import shouldComponentUpdate from 'app/utils/shouldComponentUpdate';
import Voting from 'app/components/elements/Voting';
import { connect } from 'react-redux';
import { Link } from 'react-router';
......
import React from 'react';
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { Component } from 'react';
import Remarkable from 'remarkable';
import sanitizeConfig, { noImageText } from 'app/utils/SanitizeConfig';
import sanitize from 'sanitize-html';
......@@ -134,6 +134,7 @@ class MarkdownViewer extends Component {
chk += s.charCodeAt(i) * (i + 1);
}
// eslint-disable-next-line no-bitwise
return (chk & 0xffffffff).toString(16);
}
......@@ -146,6 +147,7 @@ class MarkdownViewer extends Component {
sections.push(markdown);
if (section === '') {
// eslint-disable-next-line no-continue
continue;
}
}
......@@ -155,23 +157,24 @@ class MarkdownViewer extends Component {
idx += 1;
}
const cn =
'Markdown' +
(this.props.className ? ` ${this.props.className}` : '') +
(html ? ' html' : '') +
(large ? '' : ' MarkdownViewer--small');
const cn = 'Markdown'
+ (this.props.className ? ` ${this.props.className}` : '')
+ (html ? ' html' : '')
+ (large ? '' : ' MarkdownViewer--small');
return (
<div className={'MarkdownViewer ' + cn}>
{sections}
{noImageActive && allowNoImage && (
<div
key={'hidden-content'}
role="link"
tabIndex={0}
key="hidden-content"
onClick={this.onAllowNoImage}
className="MarkdownViewer__negative_group"
>
{tt('markdownviewer_jsx.images_were_hidden_due_to_low_ratings')}
<button style={{ marginBottom: 0 }} className="button hollow tiny float-right">
<button type="button" style={{ marginBottom: 0 }} className="button hollow tiny float-right">
{tt('g.show')}
</button>
</div>
......
......@@ -7,9 +7,10 @@ export default class NotFoundMessage extends React.Component {
<div className="NotFound float-center">
<div>
<Icon name="hive" size="4x" />
<h4 className="NotFound__header">Sorry! This page doesn't exist.</h4>
<h4 className="NotFound__header">Sorry! This page doesn&aquote;t exist.</h4>
<p>
Not to worry. You can head back to{' '}
Not to worry. You can head back to
{' '}
<a style={{ fontWeight: 800 }} href="/">
our homepage
</a>
......
......@@ -47,7 +47,8 @@ const highlightText = (text, highlight) => {
<span key={i} style={part.toLowerCase() === highlight.toLowerCase() ? { fontWeight: 'bold' } : {}}>
{part}
</span>
))}{' '}
))}
{' '}
</span>
);
};
......@@ -89,10 +90,6 @@ class NotificationsList extends React.Component {
mentions: ['mention'],
};
constructor() {
super();
}
componentWillMount() {
const { username, getAccountNotifications } = this.props;
if (username) {
......@@ -137,7 +134,7 @@ class NotificationsList extends React.Component {
} else {
notificationElement.classList.remove('even');
}
} else if (this.notificationFilterToTypes.hasOwnProperty(notificationFilter)) {
} else if (Object.prototype.hasOwnProperty.call(this.notificationFilterToTypes, notificationFilter)) {
const notificationTypes = this.notificationFilterToTypes[notificationFilter];
let matchType = false;
......@@ -196,13 +193,13 @@ class NotificationsList extends React.Component {
const renderItem = (item) => {
const unRead = Date.parse(`${lastRead}Z`) <= Date.parse(`${item.date}Z`);
const usernamePattern = /\B@[a-z0-9\.-]+/gi;
const usernamePattern = /\B@[a-z0-9.-]+/gi;
const mentions = item.msg.match(usernamePattern);
const participants = mentions
? mentions.map((m) => (
<a href={'/' + m}>
<Userpic account={m.substring(1)} />
</a>
<a href={'/' + m}>
<Userpic account={m.substring(1)} />
</a>
))
: null;
return (
......@@ -319,7 +316,7 @@ class NotificationsList extends React.Component {
<div style={{ lineHeight: '1rem' }}>{notifications.map((item) => renderItem(item))}</div>
)}
{!notifications && !notificationActionPending && process.env.BROWSER && (
<Callout>Welcome! You don't have any notifications yet.</Callout>
<Callout>Welcome! You don&aquote;t have any notifications yet.</Callout>
)}
{!notificationActionPending && notifications && !isLastPage && (
......
......@@ -8,7 +8,7 @@ import PostSummary from 'app/components/cards/PostSummary';
import LoadingIndicator from 'app/components/elements/LoadingIndicator';
import GptAd from 'app/components/elements/GptAd';
import VideoAd from 'app/components/elements/VideoAd';
// import shouldComponentUpdate from 'app/utils/shouldComponentUpdate';
// import shouldComponentUpdate from 'app/utils/shouldComponentUpdate';
function topPosition(domElt) {
if (!domElt) {
......
import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
// import shouldComponentUpdate from 'app/utils/shouldComponentUpdate';
// import shouldComponentUpdate from 'app/utils/shouldComponentUpdate';
import { cleanReduxInput } from 'app/utils/ReduxForms';
import tt from 'counterpart';
......
......@@ -2,6 +2,8 @@ import React from 'react';
import { Link } from 'react-router';
import Follow from 'app/components/elements/Follow'