Commit f0bfefe8 authored by Tasso Evangelista's avatar Tasso Evangelista Committed by Renato Becker

[CHORE] Code base maintenance (#255)

* Use light theme on Storybook

* Update Storybook

* Update dependencies

* Update ESLint rules

* Add stylelint
parent 214a323f
/build/*
/src/i18n/index.js
{
"parserOptions": {
"sourceType": "module",
"ecmaVersion": 2017,
"ecmaFeatures": {
"experimentalObjectRestSpread" : true
}
"extends": [
"@rocket.chat/eslint-config",
],
"plugins": ["react"],
"parser": "babel-eslint",
"globals": {
"I18n": true,
},
"env": {
"browser": true,
"commonjs": true,
"es6": true,
"node": true,
"jquery": true
"jest": true,
},
"rules": {
"no-multi-spaces": 2,
"no-eval": 2,
"no-extend-native": 2,
"no-multi-str": 2,
"no-use-before-define": 2,
"no-const-assign": 2,
"no-cond-assign": 2,
"no-constant-condition": 2,
"no-control-regex": 2,
"no-debugger": 2,
"no-delete-var": 2,
"no-dupe-keys": 2,
"no-dupe-args": 2,
"no-dupe-class-members": 2,
"no-duplicate-case": 2,
"no-empty": 2,
"no-empty-character-class": 2,
"no-ex-assign": 2,
"no-extra-boolean-cast": 2,
"no-extra-semi": 2,
"no-fallthrough": 2,
"no-func-assign": 2,
"no-inner-declarations": [2, "functions"],
"no-invalid-regexp": 2,
"no-irregular-whitespace": 2,
"no-mixed-operators": [2, {
"groups": [
["%", "**"],
["%", "+"],
["%", "-"],
["%", "*"],
["%", "/"],
["**", "+"],
["**", "-"],
["**", "*"],
["**", "/"],
["&", "|", "^", "~", "<<", ">>", ">>>"],
["==", "!=", "===", "!==", ">", ">=", "<", "<="],
["&&", "||"],
["in", "instanceof"]
],
"allowSamePrecedence": false
}],
"no-mixed-spaces-and-tabs": 2,
"no-sparse-arrays": 2,
"no-negated-in-lhs": 2,
"no-obj-calls": 2,
"no-octal": 2,
"no-redeclare": 2,
"no-regex-spaces": 2,
"no-undef": 2,
"no-unreachable": 2,
"no-unused-vars": [2, {
"vars": "all",
"args": "after-used",
"varsIgnorePattern": "^h$"
}],
"no-void": 2,
"no-var": 2,
"no-multiple-empty-lines": [2, { "max": 2 }],
"no-nested-ternary": 2,
"prefer-rest-params": 2,
"array-callback-return": 2,
"prefer-destructuring": [2, {
"VariableDeclarator": {
"array": false,
"object": true
},
"AssignmentExpression": {
"array": false,
"object": false
}
}, {
"enforceForRenamedProperties": false
"import/order": ["error", {
"newlines-between": "always",
"groups": ["builtin", "external", "internal", ["parent", "sibling", "index"]],
}],
"no-duplicate-imports": 2,
"arrow-parens": [2, "always"],
"quote-props": [2, "as-needed"],
"no-array-constructor": 2,
"arrow-spacing": 2,
"arrow-body-style": [2, "as-needed"],
"no-confusing-arrow": [2, { "allowParens": true }],
"dot-notation": 2,
"no-unneeded-ternary": 2,
"spaced-comment": 2,
"space-infix-ops": 2,
"array-bracket-spacing": [2, "never"],
"object-curly-spacing": [2, "always"],
"one-var": [2, "never"],
"no-lonely-if": 2,
"no-trailing-spaces": 2,
"complexity": [1, 31],
"space-in-parens": [2, "never"],
"space-before-function-paren": [2, "never"],
"space-before-blocks": [2, "always"],
"indent": [2, "tab", {"SwitchCase": 1}],
"eol-last": [2, "always"],
"comma-dangle": [2, "always-multiline"],
"keyword-spacing": 2,
"block-spacing": 2,
"brace-style": [2, "1tbs", { "allowSingleLine": true }],
"computed-property-spacing": 2,
"comma-spacing": 2,
"comma-style": 2,
"guard-for-in": 2,
"wrap-iife": 2,
"block-scoped-var": 2,
"curly": [2, "all"],
"eqeqeq": [2, "allow-null"],
"new-cap": [2, {
"capIsNewExceptions": ["Match.Optional", "Match.Maybe", "Match.OneOf", "Match.Where", "Match.ObjectIncluding", "Push.Configure", "SHA256"]
}],
"use-isnan": 2,
"valid-typeof": 2,
"linebreak-style": [2, "unix"],
"prefer-template": 2,
"template-curly-spacing": [2, "always"],
"quotes": [2, "single"],
"semi": [2, "always"],
"prefer-const": 2,
"object-shorthand": 2
},
"globals": {
"I18n": true
"react/jsx-uses-react": "error",
"react/jsx-uses-vars": "error",
"react/jsx-no-undef": "error",
"react/jsx-fragments": ["error", "syntax"],
},
"extends": "eslint-config-synacor"
}
import { addDecorator, configure, addParameters } from '@storybook/react';
import { addDecorator, addParameters, configure } from '@storybook/react';
import { withA11y } from '@storybook/addon-a11y';
import { withOptions } from '@storybook/addon-options';
import { create } from '@storybook/theming';
......@@ -7,7 +7,7 @@ import { create } from '@storybook/theming';
addParameters({
options: {
theme: create({
base: 'dark',
base: 'light',
brandTitle: 'Rocket.Chat Livechat',
brandImage: 'https://rocket.chat/images/default/logo--dark.svg',
brandUrl: 'https://github.com/RocketChat/Rocket.Chat.Livechat',
......@@ -15,13 +15,6 @@ addParameters({
hierarchySeparator: /\//,
hierarchyRootSeparator: /\|/,
},
backgrounds: [
{
name: 'white',
value: 'white',
default: true,
},
],
});
addDecorator(withA11y);
......
......@@ -3,6 +3,7 @@ const webpackOverride = require('../webpackOverride.config');
module.exports = ({ config, mode }) => {
delete config.resolve.alias['core-js'];
config = webpackOverride(config, mode);
config.resolve.alias = Object.assign(
......@@ -40,6 +41,7 @@ module.exports = ({ config, mode }) => {
config.plugins.push(
new ProvidePlugin({
h: ['preact', 'h'],
Component: ['preact', 'Component'],
React: ['preact-compat'],
})
......
This diff is collapsed.
module.exports = {
presets: ['preact-cli/babel'],
};
......@@ -14,7 +14,9 @@
"build": "run-s build:app build:widget build:pack",
"serve": "preact build --no-prerender --optimize-minimize && preact serve",
"dev": "preact watch",
"lint": "eslint src",
"lint": "run-s eslint stylelint",
"eslint": "eslint src",
"stylelint": "stylelint 'src/**/*.scss'",
"test": "jest ./tests",
"coverage": "jest --coverage",
"storybook": "start-storybook -p 9001 -c .storybook",
......@@ -23,20 +25,18 @@
"bundle-analyzer": "webpack-bundle-analyzer build/stats.json",
"release": "gh-release -c master --assets build.tar.gz"
},
"eslintIgnore": [
"build/*"
],
"devDependencies": {
"@storybook/addon-a11y": "5.0.1",
"@storybook/addon-actions": "^5.0.1",
"@storybook/addon-backgrounds": "^5.0.3",
"@storybook/addon-centered": "^5.0.1",
"@storybook/addon-knobs": "^5.0.1",
"@storybook/addon-options": "^5.0.1",
"@storybook/addon-viewport": "^5.0.1",
"@storybook/react": "^5.0.1",
"@storybook/storybook-deployer": "^2.3.0",
"@storybook/theming": "^5.0.1",
"@rocket.chat/eslint-config": "^0.3.0",
"@storybook/addon-a11y": "^5.1.9",
"@storybook/addon-actions": "^5.1.9",
"@storybook/addon-backgrounds": "^5.1.9",
"@storybook/addon-centered": "^5.1.9",
"@storybook/addon-knobs": "^5.1.9",
"@storybook/addon-options": "^5.1.9",
"@storybook/addon-viewport": "^5.1.9",
"@storybook/react": "^5.1.9",
"@storybook/storybook-deployer": "^2.8.1",
"@storybook/theming": "^5.1.9",
"create-react-ref": "^0.1.0",
"css-loader": "^2.1.0",
"desvg-loader": "^0.1.0",
......@@ -57,6 +57,8 @@
"prompts": "^2.0.1",
"sass-loader": "^7.1.0",
"style-loader": "^0.23.1",
"stylelint": "^10.1.0",
"stylelint-order": "^3.0.0",
"svg-loader": "0.0.2",
"webpack-bundle-analyzer": "^3.0.2",
"webpack-cli": "^3.2.1"
......
{
"presets": [
["preact-cli/babel", { "modules": "commonjs" }]
]
}
\ No newline at end of file
import queryString from 'query-string';
import LivechatClient from '@rocket.chat/sdk/lib/clients/Livechat';
const host = (
window.SERVER_URL ||
queryString.parse(window.location.search).serverUrl ||
(process.env.NODE_ENV === 'development' ? 'http://localhost:3000' : null)
);
const host = window.SERVER_URL
|| queryString.parse(window.location.search).serverUrl
|| (process.env.NODE_ENV === 'development' ? 'http://localhost:3000' : null);
const useSsl = host && host.match(/^https:/) !== null;
export const Livechat = new LivechatClient({ host, protocol: 'ddp', useSsl });
import { Component } from 'preact';
import { createClassName } from '../helpers';
import CloseIcon from '../../icons/close.svg';
import styles from './styles';
import styles from './styles.scss';
export class Alert extends Component {
......@@ -32,7 +33,7 @@ export class Alert extends Component {
className={createClassName(styles, 'alert', { success, warning, error }, [className])}
style={{
...style,
...(color && { backgroundColor: color }),
...color && { backgroundColor: color },
}}
>
<div className={createClassName(styles, 'alert__content')}>
......
import { action } from '@storybook/addon-actions';
import { withKnobs, boolean, color, text } from '@storybook/addon-knobs';
import { storiesOf } from '@storybook/react';
import { screenCentered, memedIpsum } from '../../helpers.stories';
import { Alert } from '.';
......@@ -79,5 +80,4 @@ storiesOf('Components|Alert', module)
>
{text('text', memedIpsum({ count: 3, units: 'words' }))}
</Alert>
))
;
));
......@@ -2,7 +2,6 @@
@import '~styles/helpers';
@import '~styles/variables';
$alert-color: $color-text-lighter;
$alert-font-family: $font-family;
$alert-background-color: $bg-color-darker;
......@@ -11,35 +10,43 @@ $alert-warning-background-color: $color-yellow;
$alert-error-background-color: $color-red;
.alert {
display: flex;
overflow: hidden;
width: 100%;
height: 28px;
padding: 6px 16px;
letter-spacing: 0;
color: $alert-color;
font-size: 12px;
background-color: $alert-background-color;
font-family: $alert-font-family;
font-size: 12px;
font-weight: 600;
overflow: hidden;
letter-spacing: 0;
line-height: 16px;
background-color: $alert-background-color;
display: flex;
align-items: center;
justify-content: space-between;
&__content {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
&__close {
display: flex;
padding: 0;
background: none;
cursor: pointer;
color: $alert-color;
border: none;
outline: none;
color: $alert-color;
cursor: pointer;
display: flex;
background: none;
@include pressable-button(1px);
}
......
import { Component } from 'preact';
import { Router, route } from 'preact-router';
import queryString from 'query-string';
import { Livechat } from '../../api';
import history from '../../history';
import { loadConfig, clearConnectionAlerts } from '../../lib/main';
......@@ -22,12 +23,11 @@ import constants from '../../lib/constants';
import { loadMessages } from '../../lib/room';
export class App extends Component {
state = {
initialized: false,
}
handleRoute = async() => {
handleRoute = async () => {
setTimeout(() => {
const {
config: {
......@@ -58,11 +58,11 @@ export class App extends Component {
const showDepartment = departments.filter((dept) => dept.showOnRegistration).length > 0;
const showRegistrationForm = (
(registrationForm && (nameFieldRegistrationForm || emailFieldRegistrationForm || showDepartment)) &&
!triggered &&
!(user && user.token)
);
registrationForm
&& (nameFieldRegistrationForm || emailFieldRegistrationForm || showDepartment)
)
&& !triggered
&& !(user && user.token);
if (showRegistrationForm) {
return route('/register');
}
......@@ -112,7 +112,7 @@ export class App extends Component {
dispatch({ alerts: alerts.filter((alert) => alert.id !== id) });
}
handleVisibilityChange = async() => {
handleVisibilityChange = async () => {
const { dispatch } = this.props;
await dispatch({ visible: !visibility.hidden });
}
......@@ -121,7 +121,7 @@ export class App extends Component {
this.forceUpdate();
}
handleConnected = async() => {
handleConnected = async () => {
await clearConnectionAlerts();
const { livechatConnectedAlertId } = constants;
......@@ -132,14 +132,14 @@ export class App extends Component {
await loadMessages();
}
handleDisconnected = async() => {
handleDisconnected = async () => {
await clearConnectionAlerts();
const { livechatDisconnectedAlertId } = constants;
const { alerts, dispatch } = this.props;
await dispatch({ alerts: (alerts.push({ id: livechatDisconnectedAlertId, children: I18n.t('Livechat is not connected.'), error: true, timeout: 0 }), alerts) });
}
initWidget() {
setWidgetLanguage();
const { minimized, iframe: { visible } } = this.props;
......
import { Component } from 'preact';
import { createClassName } from '../helpers';
import styles from './styles';
import styles from './styles.scss';
export class Avatar extends Component {
......
import centered from '@storybook/addon-centered/react';
import { withKnobs, boolean, text, select } from '@storybook/addon-knobs';
import { storiesOf } from '@storybook/react';
import { avatarResolver } from '../../helpers.stories';
import { Avatar } from '.';
......@@ -90,5 +91,4 @@ storiesOf('Components|Avatar', module)
style={{ margin: '0.5rem' }}
/>
</div>
))
;
));
@import '~styles/colors';
@import '~styles/variables';
$avatar-size-small: 20px;
$avatar-status-indicator-size-small: 10px;
$avatar-size-medium: 32px;
......@@ -10,48 +9,57 @@ $avatar-size-large: 46px;
$avatar-status-indicator-size-large: 14px;
.avatar {
position: relative;
flex: 0 0 auto;
width: $avatar-size-medium;
height: $avatar-size-medium;
border-radius: $default-border-radius;
background-color: #000000;
background-image: url(./profile.png);
background-position: right;
background-repeat: no-repeat;
background-position: right;
background-size: contain;
position: relative;
border-radius: $default-border-radius;
width: $avatar-size-medium;
height: $avatar-size-medium;
&__image {
width: 100%;
height: 100%;
object-fit: cover;
border-radius: $default-border-radius;
color: transparent;
border-radius: $default-border-radius;
object-fit: cover;
}
&__status {
position: absolute;
bottom: -3px;
right: -2px;
bottom: -3px;
overflow: hidden;
height: $avatar-status-indicator-size-medium;
width: $avatar-status-indicator-size-medium;
height: $avatar-status-indicator-size-medium;
border: 2px solid var(--color, transparent);
border-radius: 50%;
background-color: $bg-color-grey;
border: 2px solid var(--color, transparent);
&--small {
bottom: -2px;
right: -2px;
bottom: -2px;
width: $avatar-status-indicator-size-small;
height: $avatar-status-indicator-size-small;
width: $avatar-status-indicator-size-small;
}
&--large {
bottom: -4px;
right: -2px;
bottom: -4px;
width: $avatar-status-indicator-size-large;
height: $avatar-status-indicator-size-large;
width: $avatar-status-indicator-size-large;
}
&--status {
......
import { createClassName, memo } from '../helpers';
import styles from './styles';
import styles from './styles.scss';
const handleMouseUp = ({ target }) => target.blur();
......
......@@ -2,6 +2,7 @@ import { action } from '@storybook/addon-actions';
import { withKnobs, boolean, text } from '@storybook/addon-knobs';
import centered from '@storybook/addon-centered/react';
import { storiesOf } from '@storybook/react';
import ChatIcon from '../../icons/chat.svg';
import { Button } from '.';
......@@ -188,5 +189,4 @@ storiesOf('Components|Button', module)
>
{text('text', defaultText)}
</Button>
))
;
));
......@@ -2,7 +2,6 @@
@import '~styles/helpers';
@import '~styles/variables';
$button-border-width: $default-border;
$button-border-radius: $default-border-radius;
$button-padding: (0.75 * $default-gap - $default-border) (1.5 * $default-gap - $default-border);
......@@ -48,36 +47,38 @@ $button-icon-padding: 10px;
color: $color;
&.button--loading::after {
border-color: $color $alpha-color $alpha-color $alpha-color;
border-color: $color $alpha-color $alpha-color $alpha-color;
}
}
}
position: relative;
display: flex;
flex-direction: row;
justify-content: center;
box-sizing: border-box;
border: $button-border-width solid;
border-radius: $button-border-radius;
padding: $button-padding;
cursor: pointer;
user-select: none;
transition:
color $default-time-animation,
background-color $default-time-animation,
border-color $default-time-animation,
transform $default-time-animation / 2;
white-space: nowrap;
text-decoration: none;
color: var(--font-color, $button-color);
border: $button-border-width solid;
border-radius: $button-border-radius;
font-family: $button-font-family;
font-size: $button-font-size;
font-weight: $button-font-weight;
line-height: $button-line-height;
white-space: nowrap;
text-decoration: none;
cursor: pointer;
transition: color $default-time-animation,
background-color $default-time-animation,
border-color $default-time-animation,
transform $default-time-animation / 2;
user-select: none;
justify-content: center;
@include state(var(--color, $button-background-color), transparent);
@include pressable-button($button-active-displacement, $button-border-width);
......@@ -88,11 +89,13 @@ $button-icon-padding: 10px;
&--danger {
color: $button-color;
@include state($button-danger-background-color);
}
&--secondary {
color: $button-color;
@include state($button-secondary-background-color);
}
......@@ -101,8 +104,8 @@ $button-icon-padding: 10px;
}
&--nude {
background: none;
border-color: transparent;
background: none;
&:focus {
box-shadow: none;
......@@ -118,31 +121,35 @@ $button-icon-padding: 10px;
}
&--disabled {
opacity: $button-disabled-opacity;
cursor: not-allowed;
opacity: $button-disabled-opacity;
}
&--loading {
&::after {
content: "";
display: inline-flex;
box-sizing: border-box;
position: relative;
left: $button-loading-gap;
border: $button-loading-border-width solid;
border-radius: 50%;
display: inline-flex;