diff --git a/packages/strapi-admin/admin/src/components/Sub/index.js b/packages/strapi-admin/admin/src/components/Sub/index.js index 09cc07689d..7fe121b9e1 100644 --- a/packages/strapi-admin/admin/src/components/Sub/index.js +++ b/packages/strapi-admin/admin/src/components/Sub/index.js @@ -7,24 +7,39 @@ import React from 'react'; import PropTypes from 'prop-types'; import { FormattedMessage } from 'react-intl'; +import { isFunction, isObject } from 'lodash'; import cn from 'classnames'; import styles from './styles.scss'; -function Sub({ bordered, content, title, underline }) { +function Sub({ bordered, content, link, name, style, title, underline }) { + if (isObject(title)) { + return ( +
+ + {message => {message}{name}} + + {content()} +
+ ); + } + return ( -
- - {message => {message}} - - {content()} -
+ + {title} +

+ {isFunction(content) ? content() : content} +

+
); } Sub.defaultProps = { bordered: false, content: () => '', + link: '', + name: '', + style: {}, title: { id: 'app.utils.defaultMessage', defaultMessage: 'app.utils.defaultMessage', @@ -35,8 +50,17 @@ Sub.defaultProps = { Sub.propTypes = { bordered: PropTypes.bool, - content: PropTypes.func, - title: PropTypes.object, + content: PropTypes.oneOfType([ + PropTypes.func, + PropTypes.string, + ]), + link: PropTypes.string, + name: PropTypes.string, + style: PropTypes.object, + title: PropTypes.oneOfType([ + PropTypes.object, + PropTypes.string, + ]), underline: PropTypes.bool, }; diff --git a/packages/strapi-admin/admin/src/components/Sub/styles.scss b/packages/strapi-admin/admin/src/components/Sub/styles.scss index 798104acb6..017804a472 100644 --- a/packages/strapi-admin/admin/src/components/Sub/styles.scss +++ b/packages/strapi-admin/admin/src/components/Sub/styles.scss @@ -6,19 +6,25 @@ .subWrapper { position: relative; line-height: 18px; + text-decoration: none; + > span { + text-decoration: none; font-family: Lato-Bold; font-size: 20px; color: #333740; letter-spacing: 0; + transition: color .2s ease; } p { + text-decoration: none; display: block; - max-width: 550px; + max-width: calc(100% - 150px); margin-top: 18px; color: #333740; font-size: 14px; + transition: color .2s ease; } } @@ -26,3 +32,15 @@ .underlinedTitle { border-bottom: 3px solid #F0B41E; } + +.link{ + &:hover, &:focus, &:active{ + text-decoration: none; + } + + &:hover{ + > span, p { + color: lighten(#333740, 20%); + } + } +} diff --git a/packages/strapi-admin/admin/src/containers/HomePage/WelcomeContent.js b/packages/strapi-admin/admin/src/containers/HomePage/WelcomeContent.js index 61229f3005..ad208fa18b 100644 --- a/packages/strapi-admin/admin/src/containers/HomePage/WelcomeContent.js +++ b/packages/strapi-admin/admin/src/containers/HomePage/WelcomeContent.js @@ -6,38 +6,56 @@ import React from 'react'; import { FormattedMessage } from 'react-intl'; +import PropTypes from 'prop-types'; import styles from './styles.scss'; /* eslint-disable jsx-a11y/accessible-emoji */ -function WelcomeContent() { +function WelcomeContent({ hasContent }) { return (
đź‘‹
- - {message => ( -

- {message} - - Slack - - - - {message => ( - - {message} - - )} - -

- )} -
+ {!hasContent && ( + + {message => ( +

+ {message} + + Slack + + + + {message => ( + + {message} + + )} + +

+ )} +
+ )} + {hasContent && ( + + {message => ( +

{message}

+ )} +
+ )}
); } +WelcomeContent.defaultProps = { + hasContent: false, +}; + +WelcomeContent.propTypes = { + hasContent: PropTypes.bool, +}; + export default WelcomeContent; diff --git a/packages/strapi-admin/admin/src/containers/HomePage/actions.js b/packages/strapi-admin/admin/src/containers/HomePage/actions.js index d1b8e7d786..ddf7d6f2af 100644 --- a/packages/strapi-admin/admin/src/containers/HomePage/actions.js +++ b/packages/strapi-admin/admin/src/containers/HomePage/actions.js @@ -1,9 +1,24 @@ import { + GET_ARTICLES, + GET_ARTICLES_SUCCEEDED, ON_CHANGE, SUBMIT, SUBMIT_SUCCEEDED, } from './constants'; +export function getArticles() { + return { + type: GET_ARTICLES, + }; +} + +export function getArticlesSucceeded(articles) { + return { + type: GET_ARTICLES_SUCCEEDED, + articles, + }; +} + export function onChange({ target }) { return { type: ON_CHANGE, diff --git a/packages/strapi-admin/admin/src/containers/HomePage/constants.js b/packages/strapi-admin/admin/src/containers/HomePage/constants.js index a3f7ecc731..5184422017 100644 --- a/packages/strapi-admin/admin/src/containers/HomePage/constants.js +++ b/packages/strapi-admin/admin/src/containers/HomePage/constants.js @@ -1,3 +1,5 @@ +export const GET_ARTICLES = 'app/HomePage/GET_ARTICLES'; +export const GET_ARTICLES_SUCCEEDED = 'app/HomePage/GET_ARTICLES_SUCCEEDED'; export const ON_CHANGE = 'app/HomePage/ON_CHANGE'; export const SUBMIT = 'app/HomePage/SUBMIT'; export const SUBMIT_SUCCEEDED = 'app/HomePage/SUBMIT_SUCCEEDED'; diff --git a/packages/strapi-admin/admin/src/containers/HomePage/index.js b/packages/strapi-admin/admin/src/containers/HomePage/index.js index 816011cc22..83906e6191 100644 --- a/packages/strapi-admin/admin/src/containers/HomePage/index.js +++ b/packages/strapi-admin/admin/src/containers/HomePage/index.js @@ -11,7 +11,7 @@ import { FormattedMessage } from 'react-intl'; import { bindActionCreators, compose } from 'redux'; import { createStructuredSelector } from 'reselect'; import PropTypes from 'prop-types'; -import { get, isEmpty } from 'lodash'; +import { get, isEmpty, upperFirst } from 'lodash'; import cn from 'classnames'; import Block from 'components/HomePageBlock/Loadable'; @@ -23,6 +23,7 @@ import SupportUsTitle from 'components/SupportUsTitle/Loadable'; import { selectPlugins } from 'containers/App/selectors'; +import auth from 'utils/auth'; import injectReducer from 'utils/injectReducer'; import injectSaga from 'utils/injectSaga'; import validateInput from 'utils/inputsValidations'; @@ -33,7 +34,7 @@ import CreateContent from './CreateContent'; import SocialLink from './SocialLink'; import WelcomeContent from './WelcomeContent'; -import { onChange, submit } from './actions'; +import { getArticles, onChange, submit } from './actions'; import makeSelectHomePage from './selectors'; import reducer from './reducer'; import saga from './saga'; @@ -54,6 +55,16 @@ const FIRST_BLOCK = [ }, ]; +const WELCOME_AGAIN_BLOCK = [ + { + title: { + id: 'app.components.HomePage.welcome.again', + }, + name: upperFirst(`${get(auth.getUserInfo(), 'username')}!`), + content: () => , + }, +]; + const FIRST_BLOCK_LINKS = [ { link: 'https://strapi.io/documentation/', @@ -115,6 +126,10 @@ export class HomePage extends React.PureComponent { // eslint-disable-line react/prefer-stateless-function state = { errors: [] }; + componentDidMount() { + this.props.getArticles(); + } + handleSubmit = e => { e.preventDefault(); const errors = validateInput(this.props.homePage.body.email, { required: true }, 'email'); @@ -128,29 +143,58 @@ export class HomePage extends React.PureComponent { showFirstBlock = () => get(this.props.plugins.toJS(), 'content-manager.leftMenuSections.0.links', []).length === 0; + renderButton = () => { + const data = this.showFirstBlock() + ? { + className: styles.homePageTutorialButton, + href: 'https://strapi.io/documentation/getting-started/quick-start.html', + id: 'app.components.HomePage.button.quickStart', + primary: true, + } + : { + className: styles.homePageBlogButton, + id: 'app.components.HomePage.button.blog', + href: 'https://blog.strapi.io/', + primary: false, + }; + + return ( + + + + ); + }; + render() { - const { homePage: { body } } = this.props; + const { homePage: { articles, body } } = this.props; return (
- {this.showFirstBlock() && ( - - {FIRST_BLOCK.map((value, key) => ( + + {this.showFirstBlock() && + FIRST_BLOCK.map((value, key) => ( ))} - - - -
- {FIRST_BLOCK_LINKS.map((value, key) => )} -
-
- )} + {!this.showFirstBlock() && + WELCOME_AGAIN_BLOCK.concat(articles).map((value, key) => ( + + ))} + {this.renderButton()} +
+ {FIRST_BLOCK_LINKS.map((value, key) => )} +
+
@@ -199,6 +243,7 @@ export class HomePage extends React.PureComponent { } HomePage.propTypes = { + getArticles: PropTypes.func.isRequired, homePage: PropTypes.object.isRequired, onChange: PropTypes.func.isRequired, plugins: PropTypes.object.isRequired, @@ -213,6 +258,7 @@ const mapStateToProps = createStructuredSelector({ function mapDispatchToProps(dispatch) { return bindActionCreators( { + getArticles, onChange, submit, }, diff --git a/packages/strapi-admin/admin/src/containers/HomePage/reducer.js b/packages/strapi-admin/admin/src/containers/HomePage/reducer.js index 335b0b611c..bcbc3cc66d 100644 --- a/packages/strapi-admin/admin/src/containers/HomePage/reducer.js +++ b/packages/strapi-admin/admin/src/containers/HomePage/reducer.js @@ -3,11 +3,12 @@ * HomePage reducer */ -import { fromJS, Map } from 'immutable'; +import { fromJS, List, Map } from 'immutable'; -import { ON_CHANGE, SUBMIT_SUCCEEDED } from './constants'; +import { GET_ARTICLES_SUCCEEDED, ON_CHANGE, SUBMIT_SUCCEEDED } from './constants'; const initialState = fromJS({ + articles: List([]), body: Map({ email: '', }), @@ -15,6 +16,8 @@ const initialState = fromJS({ function homePageReducer(state = initialState, action) { switch (action.type) { + case GET_ARTICLES_SUCCEEDED: + return state.update('articles', () => List(action.articles)); case ON_CHANGE: return state.updateIn(['body', 'email'], () => action.value); case SUBMIT_SUCCEEDED: diff --git a/packages/strapi-admin/admin/src/containers/HomePage/saga.js b/packages/strapi-admin/admin/src/containers/HomePage/saga.js index e5704f14ea..d4086e6f8d 100644 --- a/packages/strapi-admin/admin/src/containers/HomePage/saga.js +++ b/packages/strapi-admin/admin/src/containers/HomePage/saga.js @@ -1,3 +1,6 @@ +import 'whatwg-fetch'; +import { dropRight, take } from 'lodash'; +import removeMd from 'remove-markdown'; import { call, fork, @@ -8,10 +11,33 @@ import { import request from 'utils/request'; -import { submitSucceeded } from './actions'; -import { SUBMIT } from './constants'; +import { getArticlesSucceeded, submitSucceeded } from './actions'; +import { GET_ARTICLES, SUBMIT } from './constants'; import { makeSelectBody } from './selectors'; +function* getArticles() { + try { + const articles = yield call(fetchArticles); + const posts = articles.posts.reduce((acc, curr) => { + // Limit to 200 characters and remove last word. + const content = dropRight(take(removeMd(curr.markdown), 250).join('').split(' ')).join(' '); + + acc.push({ + title: curr.title, + link: curr.slug, + content: `${content} [...]`, + }); + + return acc; + }, []); + + yield put(getArticlesSucceeded(posts)); + } catch(err) { + // Silent + } +} + + function* submit() { try { const body = yield select(makeSelectBody()); @@ -26,6 +52,14 @@ function* submit() { function* defaultSaga() { yield fork(takeLatest, SUBMIT, submit); + yield fork(takeLatest, GET_ARTICLES, getArticles); } + +function fetchArticles() { + return fetch('https://blog.strapi.io/ghost/api/v0.1/posts/?client_id=ghost-frontend&client_secret=1f260788b4ec&limit=2', {}) + .then(resp => { + return resp.json ? resp.json() : resp; + }); +} export default defaultSaga; diff --git a/packages/strapi-admin/admin/src/containers/HomePage/styles.scss b/packages/strapi-admin/admin/src/containers/HomePage/styles.scss index 504c0d137f..6e09318d2c 100644 --- a/packages/strapi-admin/admin/src/containers/HomePage/styles.scss +++ b/packages/strapi-admin/admin/src/containers/HomePage/styles.scss @@ -173,6 +173,32 @@ } } +.homePageBlogButton { + position: relative; + height: 34px; + margin-top: 17px; + margin-bottom: 1px; + padding-left: 40px; + padding-right: 20px; + background: #333740; + color: white; + font-size: 13px; + font-weight: 800; + line-height: 33px; + letter-spacing: 0.46px; + text-align: left; + &:before { + content: '\f105'; + position: absolute; + top: 0; + bottom: 0; + left: 20px; + font-size: 22px; + margin-right: 10px; + font-family: 'FontAwesome'; + } +} + .iconWave { position: absolute; top: 24px; @@ -237,6 +263,6 @@ .welcomeContentP { display: block; - max-width: 49rem !important; + max-width: 55rem !important; margin-bottom: 31px; } diff --git a/packages/strapi-admin/admin/src/translations/en.json b/packages/strapi-admin/admin/src/translations/en.json index 4ac03eb36d..9c21951945 100755 --- a/packages/strapi-admin/admin/src/translations/en.json +++ b/packages/strapi-admin/admin/src/translations/en.json @@ -9,18 +9,21 @@ "app.components.DownloadInfo.text": "This could take a minute. Thanks for your patience.", "app.components.HomePage.welcome": "Welcome on board!", + "app.components.HomePage.welcome.again": "Welcome ", "app.components.HomePage.cta": "CONFIRM", "app.components.HomePage.community": "Find the community on the web", "app.components.HomePage.newsLetter": "Subscribe to the newsletter to get in touch about Strapi", "app.components.HomePage.community.content": "Discuss with team members, contributors and developers on different channels.", "app.components.HomePage.create": "Create your first Content Type", "app.components.HomePage.welcomeBlock.content": "We are happy to have you as one of community member. We are constantly looking for feedback so feel free to send us DM on\u0020", + "app.components.HomePage.welcomeBlock.content.again": "We hope you are making progress on your project... Feel free to read the latest new about Strapi. We are giving our best to improve the product based on your feedback.", "app.components.HomePage.welcomeBlock.content.issues": "issues.", "app.components.HomePage.welcomeBlock.content.raise": "\u0020or raise\u0020", "app.components.HomePage.createBlock.content.first": "The\u0020", "app.components.HomePage.createBlock.content.second": "\u0020plugin will help you to define the data structure of your models. If you’re new here, we highly recommend you to follow our\u0020", "app.components.HomePage.createBlock.content.tutorial": "\u0020tutorial.", "app.components.HomePage.button.quickStart": "START THE QUICK START TUTORIAL", + "app.components.HomePage.button.blog": "SEE MORE ON THE BLOG", "app.components.HomePage.support": "SUPPORT US", "app.components.HomePage.support.content": "By buying the T-shirt (25€), it will allow us to continue our work on the project to give you the best possible experience!", "app.components.HomePage.support.link": "GET YOUR T-SHIRT NOW", diff --git a/packages/strapi-admin/admin/src/translations/fr.json b/packages/strapi-admin/admin/src/translations/fr.json index 231f10362b..4f66325c1e 100755 --- a/packages/strapi-admin/admin/src/translations/fr.json +++ b/packages/strapi-admin/admin/src/translations/fr.json @@ -9,17 +9,20 @@ "app.components.DownloadInfo.text": "Cela peut prendre une minute. Merci de patienter.", "app.components.HomePage.welcome": "Bienvenue à bord!", + "app.components.HomePage.welcome.again": "Bienvenue ", "app.components.HomePage.cta": "CONFIRMEZ", "app.components.HomePage.community": "Rejoignez la communauté", "app.components.HomePage.community.content": "Discutez avec les membres de l'équipe, contributeurs et développeurs sur différent supports.", "app.components.HomePage.create": "Créez votre premier Content Type", "app.components.HomePage.welcomeBlock.content": "Nous sommes heureux de vous compter parmi nos membres. Nous sommes à l'écoute de vos retours alors, n'hésitez pas à nous envoyer des DM sur\u0020", + "app.components.HomePage.welcomeBlock.content.again": "Nous espérons que votre projet avance bien... Découvrez les derniers articles à propos de Strapi. Nous faisons de notre mieux pour améliorer le produit selon vos retours.", "app.components.HomePage.welcomeBlock.content.issues": "issues", "app.components.HomePage.welcomeBlock.content.raise": "\u0020ou soumetez des\u0020", "app.components.HomePage.createBlock.content.first": "Le\u0020", "app.components.HomePage.createBlock.content.second": "\u0020plugin vous permet de définir la structure de vos modèles. Nous vous conseillons fortement de suivre notre\u0020", "app.components.HomePage.createBlock.content.tutorial": "\u0020tutoriel.", "app.components.HomePage.button.quickStart": "VOIR LE QUICK START TUTORIEL", + "app.components.HomePage.button.blog": "VOIR PLUS D'ARTICLES SUR LE BLOG", "app.components.HomePage.support": "SUPPORT US", "app.components.HomePage.support.content": "En achetant notre T-shirt (25€), vous nous aidez à poursuivre à maintenir le projet pour que nous puissions vous donner la meilleure expérience possible!", "app.components.HomePage.support.link": "OBTENEZ VOTRE T-SHIRT!", diff --git a/packages/strapi-admin/package.json b/packages/strapi-admin/package.json index fcefa77963..6ef3a01991 100755 --- a/packages/strapi-admin/package.json +++ b/packages/strapi-admin/package.json @@ -24,6 +24,7 @@ }, "dependencies": { "react-ga": "^2.4.1", + "remove-markdown": "^0.2.2", "shelljs": "^0.7.8" }, "devDependencies": {