diff --git a/client/modules/IDE/components/CollectionList/CollectionList.jsx b/client/modules/IDE/components/CollectionList/CollectionList.jsx index c161d2bb..1007ca97 100644 --- a/client/modules/IDE/components/CollectionList/CollectionList.jsx +++ b/client/modules/IDE/components/CollectionList/CollectionList.jsx @@ -143,9 +143,9 @@ class CollectionList extends React.Component { {this._renderFieldHeader('name', 'Name')} - {(!mobile) && this._renderFieldHeader('createdAt', 'Date Created')} - {this._renderFieldHeader('updatedAt', 'Date Updated')} - {this._renderFieldHeader('numItems', '# sketches')} + {this._renderFieldHeader('createdAt', `${mobile ? '' : 'Date '}Created`)} + {this._renderFieldHeader('updatedAt', `${mobile ? '' : 'Date '}Updated`)} + {this._renderFieldHeader('numItems', mobile ? 'Sketches' : '# sketches')} diff --git a/client/modules/IDE/components/CollectionList/CollectionListRow.jsx b/client/modules/IDE/components/CollectionList/CollectionListRow.jsx index f3119632..de20cea9 100644 --- a/client/modules/IDE/components/CollectionList/CollectionListRow.jsx +++ b/client/modules/IDE/components/CollectionList/CollectionListRow.jsx @@ -213,7 +213,7 @@ class CollectionListRowBase extends React.Component { {this.renderCollectionName()} - {(!mobile) && {format(new Date(collection.createdAt), 'MMM D, YYYY')}} + {mobile && 'Created: '}{format(new Date(collection.createdAt), 'MMM D, YYYY')} {mobile && 'Updated: '}{formatDateCell(collection.updatedAt)} {mobile && '# sketches: '}{(collection.items || []).length} diff --git a/client/modules/IDE/components/SketchList.jsx b/client/modules/IDE/components/SketchList.jsx index 4aacd8c2..d5f9d71d 100644 --- a/client/modules/IDE/components/SketchList.jsx +++ b/client/modules/IDE/components/SketchList.jsx @@ -437,8 +437,8 @@ class SketchList extends React.Component { {this._renderFieldHeader('name', 'Sketch')} - {this._renderFieldHeader('createdAt', 'Date Created')} - {this._renderFieldHeader('updatedAt', 'Date Updated')} + {this._renderFieldHeader('createdAt', `${mobile ? '' : 'Date '}Created`)} + {this._renderFieldHeader('updatedAt', `${mobile ? '' : 'Date '}Updated`)} diff --git a/client/modules/Mobile/MobileDashboardView.jsx b/client/modules/Mobile/MobileDashboardView.jsx index 7bae38f4..270faee7 100644 --- a/client/modules/Mobile/MobileDashboardView.jsx +++ b/client/modules/Mobile/MobileDashboardView.jsx @@ -24,9 +24,11 @@ import Loader from '../App/components/loader'; const EXAMPLE_USERNAME = 'p5'; +// @ghalestrilo 08/13/2020: I'm sorry const ContentWrapper = styled(Content)` table { table-layout: fixed; + margin-bottom: ${remSize(120)} } td ,thead button { @@ -55,14 +57,18 @@ const ContentWrapper = styled(Content)` tbody td { justify-self: start; text-align: start; padding: 0 } tbody td:nth-child(2) { justify-self: start; text-align: start; padding-left: ${remSize(12)}}; - tbody td:last-child { justify-self: end; text-align: end; }; + tbody td:last-child { + justify-self: end; + text-align: end; + grid-row-start: 1; + grid-column-start: 3; + }; .sketch-list__dropdown-column { width: auto; }; tbody { height: ${remSize(48)}; } .sketches-table-container { - padding-bottom: ${remSize(160)}; background: ${prop('SketchList.background')}; } .sketches-table__row { @@ -79,18 +85,33 @@ const ContentWrapper = styled(Content)` }; thead tr { - grid-template-columns: 1fr 1fr 1fr 0fr; + grid-template-columns: repeat(${props => props.fieldcount}, 1fr) 0fr; + ${props => props.noheader && 'display: none;'} } tbody tr { padding: ${remSize(8)}; border-radius: ${remSize(4)}; - grid-template-columns: 5fr 5fr 1fr; + grid-template-columns: repeat(${props => props.fieldcount - 1}) 1fr; grid-template-areas: "name name name" "content content content"; + grid-row-gap: ${remSize(12)} } .loader-container { position: fixed ; padding-bottom: 32% } + .sketches-table thead th { + background-color: transparent; + } + + .asset-table thead th { + height: initial; + align-self: center; + } + + .asset-table thead tr { + height: ${remSize(32)} + } + `; const Subheader = styled.div` @@ -168,7 +189,7 @@ const MobileDashboard = ({ params, location }) => { - + {panel === Tabs[0] && } {panel === Tabs[1] && } diff --git a/client/modules/User/components/APIKeyForm.jsx b/client/modules/User/components/APIKeyForm.jsx index b3a1a4b4..e5c7577f 100644 --- a/client/modules/User/components/APIKeyForm.jsx +++ b/client/modules/User/components/APIKeyForm.jsx @@ -1,6 +1,5 @@ import PropTypes from 'prop-types'; import React from 'react'; - import Button from '../../../common/Button'; import { PlusIcon } from '../../../common/icons'; import CopyableInput from '../../IDE/components/CopyableInput'; @@ -12,7 +11,7 @@ export const APIKeyPropType = PropTypes.shape({ token: PropTypes.object, // eslint-disable-line label: PropTypes.string.isRequired, createdAt: PropTypes.string.isRequired, - lastUsedAt: PropTypes.string, + lastUsedAt: PropTypes.string }); class APIKeyForm extends React.Component { @@ -39,7 +38,7 @@ class APIKeyForm extends React.Component { } removeKey(key) { - const message = `Are you sure you want to delete "${key.label}"?`; + const message = this.props.t('APIKeyForm.ConfirmDelete', { key_label: key.label }); if (window.confirm(message)) { this.props.removeApiKey(key.id); @@ -51,10 +50,10 @@ class APIKeyForm extends React.Component { if (hasApiKeys) { return ( - + ); } - return

You have no exsiting tokens.

; + return

{this.props.t('APIKeyForm.NoTokens')}

; } render() { @@ -63,27 +62,18 @@ class APIKeyForm extends React.Component { return (

- Personal Access Tokens act like your password to allow automated - scripts to access the Editor API. Create a token for each script that - needs access. + {this.props.t('APIKeyForm.Summary')}

-

Create new token

+

{this.props.t('APIKeyForm.CreateToken')}

- + { - this.setState({ keyLabel: event.target.value }); - }} - placeholder="What is this token for? e.g. Example import script" + onChange={(event) => { this.setState({ keyLabel: event.target.value }); }} + placeholder={this.props.t('APIKeyForm.TokenPlaceholder')} type="text" value={this.state.keyLabel} /> @@ -93,29 +83,25 @@ class APIKeyForm extends React.Component { label="Create new key" type="submit" > - Create + {this.props.t('APIKeyForm.CreateTokenSubmit')}
- {keyWithToken && ( -
-

- Your new access token -

-

- Make sure to copy your new personal access token now. You won’t - be able to see it again! -

- -
- )} + { + keyWithToken && ( +
+

{this.props.t('APIKeyForm.NewTokenTitle')}

+

+ {this.props.t('APIKeyForm.NewTokenInfo')} +

+ +
+ ) + }
-

Existing tokens

+

{this.props.t('APIKeyForm.ExistingTokensTitle')}

{this.renderApiKeys()}
@@ -127,6 +113,7 @@ APIKeyForm.propTypes = { apiKeys: PropTypes.arrayOf(PropTypes.shape(APIKeyPropType)).isRequired, createApiKey: PropTypes.func.isRequired, removeApiKey: PropTypes.func.isRequired, + t: PropTypes.func.isRequired }; export default APIKeyForm; diff --git a/client/modules/User/components/APIKeyList.jsx b/client/modules/User/components/APIKeyList.jsx index 9201aa4b..2c2e39ac 100644 --- a/client/modules/User/components/APIKeyList.jsx +++ b/client/modules/User/components/APIKeyList.jsx @@ -8,22 +8,22 @@ import { APIKeyPropType } from './APIKeyForm'; import TrashCanIcon from '../../../images/trash-can.svg'; -function APIKeyList({ apiKeys, onRemove }) { +function APIKeyList({ apiKeys, onRemove, t }) { return ( - - - - + + + + {orderBy(apiKeys, ['createdAt'], ['desc']).map((key) => { const lastUsed = key.lastUsedAt ? distanceInWordsToNow(new Date(key.lastUsedAt), { addSuffix: true }) : - 'Never'; + t('APIKeyList.Never'); return ( @@ -34,7 +34,7 @@ function APIKeyList({ apiKeys, onRemove }) { @@ -50,6 +50,7 @@ function APIKeyList({ apiKeys, onRemove }) { APIKeyList.propTypes = { apiKeys: PropTypes.arrayOf(PropTypes.shape(APIKeyPropType)).isRequired, onRemove: PropTypes.func.isRequired, + t: PropTypes.func.isRequired }; export default APIKeyList; diff --git a/client/modules/User/components/AccountForm.jsx b/client/modules/User/components/AccountForm.jsx index 90d5fc18..c1bfe6db 100644 --- a/client/modules/User/components/AccountForm.jsx +++ b/client/modules/User/components/AccountForm.jsx @@ -1,5 +1,6 @@ import PropTypes from 'prop-types'; import React from 'react'; +import { withTranslation } from 'react-i18next'; import { domOnlyProps } from '../../../utils/reduxFormUtils'; import Button from '../../../common/Button'; @@ -14,6 +15,7 @@ function AccountForm(props) { submitting, invalid, pristine, + t } = props; const handleInitiateVerification = (evt) => { @@ -24,12 +26,10 @@ function AccountForm(props) { return (

- + {email.error} )}

- {user.verified !== 'verified' && ( -

- Unconfirmed. - {user.emailVerificationInitiate === true ? ( - - {' '} - Confirmation sent, check your email. - - ) : ( - - )} -

- )} + { + user.verified !== 'verified' && + ( +

+ {t('AccountForm.Unconfirmed')} + { + user.emailVerificationInitiate === true ? + ( + {t('AccountForm.EmailSent')} + ) : + ( + + ) + } +

+ ) + }

- +

- +

- + {newPassword.error} )}

- ); @@ -123,6 +124,7 @@ AccountForm.propTypes = { submitting: PropTypes.bool, invalid: PropTypes.bool, pristine: PropTypes.bool, + t: PropTypes.func.isRequired }; AccountForm.defaultProps = { @@ -131,4 +133,4 @@ AccountForm.defaultProps = { invalid: false, }; -export default AccountForm; +export default withTranslation()(AccountForm); diff --git a/client/modules/User/components/NewPasswordForm.jsx b/client/modules/User/components/NewPasswordForm.jsx index c971eb49..cf8b3ad9 100644 --- a/client/modules/User/components/NewPasswordForm.jsx +++ b/client/modules/User/components/NewPasswordForm.jsx @@ -1,16 +1,13 @@ import PropTypes from 'prop-types'; import React from 'react'; - +import { withTranslation } from 'react-i18next'; import { domOnlyProps } from '../../../utils/reduxFormUtils'; import Button from '../../../common/Button'; function NewPasswordForm(props) { const { - fields: { password, confirmPassword }, - handleSubmit, - submitting, - invalid, - pristine, + fields: { password, confirmPassword }, handleSubmit, submitting, invalid, pristine, + t } = props; return (

- +

- + @@ -47,9 +40,7 @@ function NewPasswordForm(props) { {confirmPassword.error} )}

- + ); } @@ -67,6 +58,7 @@ NewPasswordForm.propTypes = { params: PropTypes.shape({ reset_password_token: PropTypes.string, }).isRequired, + t: PropTypes.func.isRequired }; NewPasswordForm.defaultProps = { @@ -75,4 +67,4 @@ NewPasswordForm.defaultProps = { submitting: false, }; -export default NewPasswordForm; +export default withTranslation()(NewPasswordForm); diff --git a/client/modules/User/components/ResetPasswordForm.jsx b/client/modules/User/components/ResetPasswordForm.jsx index dc48fe73..ccd05ecc 100644 --- a/client/modules/User/components/ResetPasswordForm.jsx +++ b/client/modules/User/components/ResetPasswordForm.jsx @@ -1,16 +1,12 @@ import PropTypes from 'prop-types'; import React from 'react'; - +import { withTranslation } from 'react-i18next'; import { domOnlyProps } from '../../../utils/reduxFormUtils'; import Button from '../../../common/Button'; function ResetPasswordForm(props) { const { - fields: { email }, - handleSubmit, - submitting, - invalid, - pristine, + fields: { email }, handleSubmit, submitting, invalid, pristine, t } = props; return (

- + ); @@ -54,8 +45,9 @@ ResetPasswordForm.propTypes = { invalid: PropTypes.bool, pristine: PropTypes.bool, user: PropTypes.shape({ - resetPasswordInitiate: PropTypes.bool, + resetPasswordInitiate: PropTypes.bool }).isRequired, + t: PropTypes.func.isRequired }; ResetPasswordForm.defaultProps = { @@ -64,4 +56,4 @@ ResetPasswordForm.defaultProps = { invalid: false, }; -export default ResetPasswordForm; +export default withTranslation()(ResetPasswordForm); diff --git a/client/modules/User/pages/AccountView.jsx b/client/modules/User/pages/AccountView.jsx index fff8d331..f9f46cc8 100644 --- a/client/modules/User/pages/AccountView.jsx +++ b/client/modules/User/pages/AccountView.jsx @@ -4,6 +4,7 @@ import { reduxForm } from 'redux-form'; import { bindActionCreators } from 'redux'; import { Tab, Tabs, TabList, TabPanel } from 'react-tabs'; import { Helmet } from 'react-helmet'; +import { withTranslation } from 'react-i18next'; import { updateSettings, initiateVerification, createApiKey, removeApiKey } from '../actions'; import AccountForm from '../components/AccountForm'; import apiClient from '../../../utils/apiClient'; @@ -16,9 +17,11 @@ function SocialLoginPanel(props) { return ( -

Social Login

+ {/* eslint-disable-next-line react/prop-types */} +

{props.t('AccountView.SocialLogin')}

- Use your GitHub or Google account to log into the p5.js Web Editor. + {/* eslint-disable-next-line react/prop-types */} + {props.t('AccountView.SocialLoginDescription')}

@@ -39,21 +42,21 @@ class AccountView extends React.Component { return (
- p5.js Web Editor | Account Settings + {this.props.t('AccountView.Title')}
NameCreated onLast usedActions{t('APIKeyList.Name')}{t('APIKeyList.Created')}{t('APIKeyList.LastUsed')}{t('APIKeyList.Actions')}