diff --git a/examples/getstarted/api/article/models/Article.settings.json b/examples/getstarted/api/article/models/Article.settings.json index 8fc8906725..a7780d3038 100644 --- a/examples/getstarted/api/article/models/Article.settings.json +++ b/examples/getstarted/api/article/models/Article.settings.json @@ -87,7 +87,6 @@ "type": "group", "group": "ingredients", "repeatable": true, - "min": 1, "max": 10 }, "author": { diff --git a/packages/strapi-admin/admin/src/components/DownloadInfo/styles.scss b/packages/strapi-admin/admin/src/components/DownloadInfo/components.js similarity index 73% rename from packages/strapi-admin/admin/src/components/DownloadInfo/styles.scss rename to packages/strapi-admin/admin/src/components/DownloadInfo/components.js index 0f235ed3f9..10cda3636b 100644 --- a/packages/strapi-admin/admin/src/components/DownloadInfo/styles.scss +++ b/packages/strapi-admin/admin/src/components/DownloadInfo/components.js @@ -1,13 +1,14 @@ -.wrapper { +import styled from 'styled-components'; + +const Wrapper = styled.div` width: 372px; height: 159px; border-radius: 2px; background-color: #fff; -} +`; -.content { +const Content = styled.div` padding-top: 3rem; - // color: #F64D0A; text-align: center; font-family: Lato; font-size: 1.3rem; @@ -26,9 +27,10 @@ } > span { - color: #787E8F; + color: #787e8f; font-size: 13px; } } +`; -} +export { Content, Wrapper }; diff --git a/packages/strapi-admin/admin/src/components/DownloadInfo/index.js b/packages/strapi-admin/admin/src/components/DownloadInfo/index.js index 07fc3422e3..2f16bf81a1 100644 --- a/packages/strapi-admin/admin/src/components/DownloadInfo/index.js +++ b/packages/strapi-admin/admin/src/components/DownloadInfo/index.js @@ -1,26 +1,27 @@ /* -* -* DownloadInfo -* -*/ + * + * DownloadInfo + * + */ import React from 'react'; import { FormattedMessage } from 'react-intl'; + +import { Content, Wrapper } from './components'; import Icon from '../../assets/icons/icon_success.svg'; -import styles from './styles.scss'; function DownloadInfo() { return ( -
-
+ + info

-
-
+ + ); } diff --git a/packages/strapi-admin/admin/src/components/HomePageBlock/Loadable.js b/packages/strapi-admin/admin/src/components/HomePageBlock/Loadable.js deleted file mode 100644 index caed2adc89..0000000000 --- a/packages/strapi-admin/admin/src/components/HomePageBlock/Loadable.js +++ /dev/null @@ -1,8 +0,0 @@ -import Loadable from 'react-loadable'; - -import LoadingIndicator from 'components/LoadingIndicator'; - -export default Loadable({ - loader: () => import('./index'), - loading: LoadingIndicator, -}); diff --git a/packages/strapi-admin/admin/src/components/HomePageBlock/index.js b/packages/strapi-admin/admin/src/components/HomePageBlock/index.js deleted file mode 100644 index 19dfcf00dc..0000000000 --- a/packages/strapi-admin/admin/src/components/HomePageBlock/index.js +++ /dev/null @@ -1,36 +0,0 @@ -/** - * - * HomePageBlock - * - */ - -import React from 'react'; -import PropTypes from 'prop-types'; -import cn from 'classnames'; - -import styles from './styles.scss'; - -function HomePageBlock({ children, className }) { - return ( -
- {children} -
- ); -} - -HomePageBlock.defaultProps = { - children: '', - className: '', -}; - -HomePageBlock.propTypes = { - children: PropTypes.node, - className: PropTypes.string, -}; - -export default HomePageBlock; diff --git a/packages/strapi-admin/admin/src/components/HomePageBlock/styles.scss b/packages/strapi-admin/admin/src/components/HomePageBlock/styles.scss deleted file mode 100644 index 13cac9eb62..0000000000 --- a/packages/strapi-admin/admin/src/components/HomePageBlock/styles.scss +++ /dev/null @@ -1,8 +0,0 @@ -.homePageBlock { - width: 100%; - margin-bottom: 34px; - background: #ffffff; - padding: 20px 30px 30px 30px; - box-shadow: 0 2px 4px 0 #E3E9F3; - border-radius: 3px; -} diff --git a/packages/strapi-admin/admin/src/components/Sub/Loadable.js b/packages/strapi-admin/admin/src/components/Sub/Loadable.js deleted file mode 100644 index caed2adc89..0000000000 --- a/packages/strapi-admin/admin/src/components/Sub/Loadable.js +++ /dev/null @@ -1,8 +0,0 @@ -import Loadable from 'react-loadable'; - -import LoadingIndicator from 'components/LoadingIndicator'; - -export default Loadable({ - loader: () => import('./index'), - loading: LoadingIndicator, -}); diff --git a/packages/strapi-admin/admin/src/components/Sub/index.js b/packages/strapi-admin/admin/src/components/Sub/index.js deleted file mode 100644 index d6dc87e99a..0000000000 --- a/packages/strapi-admin/admin/src/components/Sub/index.js +++ /dev/null @@ -1,76 +0,0 @@ -/** - * - * Sub - * - */ - -import React from 'react'; -import PropTypes from 'prop-types'; -import { FormattedMessage } from 'react-intl'; -import { isFunction, isObject } from 'lodash'; -import cn from 'classnames'; -import { LoadingBar } from 'strapi-helper-plugin'; - -import styles from './styles.scss'; - -function Sub({ bordered, content, link, name, style, title, underline }) { - if (isObject(title)) { - return ( -
- - {message => ( - - {message} - {name} - - )} - - {content()} -
- ); - } - - return ( - - {title} - {title === '' && } - {content === '' && } -

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

-
- ); -} - -Sub.defaultProps = { - bordered: false, - content: () => '', - link: '', - name: '', - style: {}, - title: { - id: 'app.utils.defaultMessage', - defaultMessage: 'app.utils.defaultMessage', - values: {}, - }, - underline: false, -}; - -Sub.propTypes = { - bordered: PropTypes.bool, - 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, -}; - -export default Sub; diff --git a/packages/strapi-admin/admin/src/components/Sub/styles.scss b/packages/strapi-admin/admin/src/components/Sub/styles.scss deleted file mode 100644 index 017804a472..0000000000 --- a/packages/strapi-admin/admin/src/components/Sub/styles.scss +++ /dev/null @@ -1,46 +0,0 @@ -.subBordered { - margin-bottom: 18px; - border-bottom: 1px solid #F7F8F8; -} - -.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: calc(100% - 150px); - margin-top: 18px; - color: #333740; - font-size: 14px; - transition: color .2s ease; - } -} - - -.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/components/SupportUsCta/Loadable.js b/packages/strapi-admin/admin/src/components/SupportUsCta/Loadable.js deleted file mode 100644 index 83410f7c63..0000000000 --- a/packages/strapi-admin/admin/src/components/SupportUsCta/Loadable.js +++ /dev/null @@ -1,8 +0,0 @@ -import Loadable from 'react-loadable'; - -import { LoadingIndicator } from 'strapi-helper-plugin'; - -export default Loadable({ - loader: () => import('./index'), - loading: LoadingIndicator, -}); diff --git a/packages/strapi-admin/admin/src/components/SupportUsCta/index.js b/packages/strapi-admin/admin/src/components/SupportUsCta/index.js deleted file mode 100644 index 5ecb5104f1..0000000000 --- a/packages/strapi-admin/admin/src/components/SupportUsCta/index.js +++ /dev/null @@ -1,28 +0,0 @@ -/** - * - * SupportUsCta - */ - -import React from 'react'; -import { FormattedMessage } from 'react-intl'; - -import styles from './styles.scss'; - -function SupportUsCta() { - return ( - - {message => ( - - {message} - - )} - - ); -} - -export default SupportUsCta; diff --git a/packages/strapi-admin/admin/src/components/SupportUsCta/styles.scss b/packages/strapi-admin/admin/src/components/SupportUsCta/styles.scss deleted file mode 100644 index 9e27db6837..0000000000 --- a/packages/strapi-admin/admin/src/components/SupportUsCta/styles.scss +++ /dev/null @@ -1,18 +0,0 @@ -.supportUsCta { - padding: 7px 12px 7px 20px; - border: 1px solid #FFFFFF; - border-radius: 3px; - color: #FFFFFF; - font-size: 13px; - font-weight: 800; - letter-spacing: 0.5px; - &:after { - content: '\f178'; - font-family: 'FontAwesome'; - margin-left: 10px; - } - &:hover { - color: #FFFFFF; - text-decoration: none; - } -} diff --git a/packages/strapi-admin/admin/src/components/SupportUsTitle/Loadable.js b/packages/strapi-admin/admin/src/components/SupportUsTitle/Loadable.js deleted file mode 100644 index 83410f7c63..0000000000 --- a/packages/strapi-admin/admin/src/components/SupportUsTitle/Loadable.js +++ /dev/null @@ -1,8 +0,0 @@ -import Loadable from 'react-loadable'; - -import { LoadingIndicator } from 'strapi-helper-plugin'; - -export default Loadable({ - loader: () => import('./index'), - loading: LoadingIndicator, -}); diff --git a/packages/strapi-admin/admin/src/components/SupportUsTitle/index.js b/packages/strapi-admin/admin/src/components/SupportUsTitle/index.js deleted file mode 100644 index 11dfcc2d4d..0000000000 --- a/packages/strapi-admin/admin/src/components/SupportUsTitle/index.js +++ /dev/null @@ -1,19 +0,0 @@ -/** - * - * SupportUsTitle - */ - -import React from 'react'; -import { FormattedMessage } from 'react-intl'; - -import styles from './styles.scss'; - -function SupportUsTitle() { - return ( - - {message => {message}} - - ); -} - -export default SupportUsTitle; diff --git a/packages/strapi-admin/admin/src/components/SupportUsTitle/styles.scss b/packages/strapi-admin/admin/src/components/SupportUsTitle/styles.scss deleted file mode 100644 index e61eec6607..0000000000 --- a/packages/strapi-admin/admin/src/components/SupportUsTitle/styles.scss +++ /dev/null @@ -1,11 +0,0 @@ -.supportUsTitle { - color: #FFFFFF; - font-size: 18px; - font-weight: 800; - letter-spacing: 0.5px; - &:after { - content: '❤️'; - margin-left: 7px; - font-size: 18px; - } -} diff --git a/packages/strapi-admin/admin/src/containers/Admin/index.js b/packages/strapi-admin/admin/src/containers/Admin/index.js index d92f9619db..081cd699b1 100644 --- a/packages/strapi-admin/admin/src/containers/Admin/index.js +++ b/packages/strapi-admin/admin/src/containers/Admin/index.js @@ -221,6 +221,8 @@ export class Admin extends React.Component { return ; }; + renderRoute = (props, Component) => ; + render() { const { admin: { isLoading, showLogoutComponent, showMenu, strapiVersion }, @@ -256,7 +258,11 @@ export class Admin extends React.Component { {showMenu ?
: ''}
- + this.renderRoute(props, HomePage)} + exact + /> - - - {message =>

{message}

} -
- - ); -} - -BlockLink.propTypes = { - content: PropTypes.object.isRequired, - isDocumentation: PropTypes.bool.isRequired, - link: PropTypes.string.isRequired, - title: PropTypes.object.isRequired, -}; - -export default BlockLink; diff --git a/packages/strapi-admin/admin/src/containers/HomePage/BlogPost.js b/packages/strapi-admin/admin/src/containers/HomePage/BlogPost.js new file mode 100644 index 0000000000..68deada6ce --- /dev/null +++ b/packages/strapi-admin/admin/src/containers/HomePage/BlogPost.js @@ -0,0 +1,50 @@ +import React, { memo } from 'react'; +import PropTypes from 'prop-types'; +import { LoadingBar } from 'strapi-helper-plugin'; + +const BlogPost = ({ error, isFirst, isLoading, title, content, link }) => { + if (isLoading) { + return ( + <> + + + + ); + } + + if (error) { + return null; + } + + return ( + +

{title}

+

+ {content} +

+
+ ); +}; + +BlogPost.defaultProps = { + content: null, + isFirst: false, + link: null, + title: null, +}; + +BlogPost.propTypes = { + content: PropTypes.string, + error: PropTypes.bool.isRequired, + isFirst: PropTypes.bool, + isLoading: PropTypes.bool.isRequired, + link: PropTypes.string, + title: PropTypes.string, +}; + +export default memo(BlogPost); diff --git a/packages/strapi-admin/admin/src/containers/HomePage/CommunityContent.js b/packages/strapi-admin/admin/src/containers/HomePage/CommunityContent.js deleted file mode 100644 index a6caabc8e3..0000000000 --- a/packages/strapi-admin/admin/src/containers/HomePage/CommunityContent.js +++ /dev/null @@ -1,27 +0,0 @@ -/** - * - * CommunityContent - * - */ - -import React from 'react'; -import { FormattedMessage } from 'react-intl'; - -import styles from './styles.scss'; - -/* eslint-disable jsx-a11y/accessible-emoji */ -function CommunityContent() { - return ( - - - {message => ( -

- {message} -

- )} -
-
- ); -} - -export default CommunityContent; diff --git a/packages/strapi-admin/admin/src/containers/HomePage/CreateContent.js b/packages/strapi-admin/admin/src/containers/HomePage/CreateContent.js deleted file mode 100644 index 5c66ed2763..0000000000 --- a/packages/strapi-admin/admin/src/containers/HomePage/CreateContent.js +++ /dev/null @@ -1,30 +0,0 @@ -/** - * - * CreateContent - * - */ -/* eslint-disable */ -import React from 'react'; -import { FormattedMessage } from 'react-intl'; - -function CreateContent() { - return ( - - {message => ( -

- {message} - - Content Type Builder - - - - "Quick Start" - - -

- )} -
- ); -} - -export default CreateContent; diff --git a/packages/strapi-admin/admin/src/containers/HomePage/SocialLink.js b/packages/strapi-admin/admin/src/containers/HomePage/SocialLink.js index 87b3a471fb..5fbe046761 100644 --- a/packages/strapi-admin/admin/src/containers/HomePage/SocialLink.js +++ b/packages/strapi-admin/admin/src/containers/HomePage/SocialLink.js @@ -3,8 +3,7 @@ * SocialLink */ -import React from 'react'; -import cn from 'classnames'; +import React, { memo } from 'react'; import PropTypes from 'prop-types'; import Gh from '../../assets/images/social_gh.png'; @@ -14,7 +13,7 @@ import So from '../../assets/images/social_so.png'; import Twitter from '../../assets/images/social_twitter.png'; import Reddit from '../../assets/images/social_reddit.png'; -import styles from './styles.scss'; +import { SocialLinkWrapper } from './components'; /* eslint-disable jsx-a11y/alt-text */ function getSrc(name) { @@ -36,36 +35,22 @@ function getSrc(name) { } } -class SocialLink extends React.PureComponent { - state = { imgLoaded: false }; - - handleImgLoaded = () => this.setState({ imgLoaded: true }); - - render() { - const { link, name } = this.props; - const { imgLoaded } = this.state; - - return ( -
- - - ); - } -} +const SocialLink = ({ link, name }) => { + return ( + + +
+ +
+ {name} +
+
+ ); +}; SocialLink.propTypes = { link: PropTypes.string.isRequired, name: PropTypes.string.isRequired, }; -export default SocialLink; +export default memo(SocialLink); diff --git a/packages/strapi-admin/admin/src/containers/HomePage/WelcomeContent.js b/packages/strapi-admin/admin/src/containers/HomePage/WelcomeContent.js deleted file mode 100644 index a40c7d8c18..0000000000 --- a/packages/strapi-admin/admin/src/containers/HomePage/WelcomeContent.js +++ /dev/null @@ -1,65 +0,0 @@ -/** - * - * WelcomeContent - * - */ - -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({ hasContent }) { - return ( - -
👋
- {!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 deleted file mode 100644 index ddf7d6f2af..0000000000 --- a/packages/strapi-admin/admin/src/containers/HomePage/actions.js +++ /dev/null @@ -1,39 +0,0 @@ -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, - value: target.value, - }; -} - -export function submit() { - return { - type: SUBMIT, - }; -} - -export function submitSucceeded() { - return { - type: SUBMIT_SUCCEEDED, - }; -} diff --git a/packages/strapi-admin/admin/src/containers/HomePage/components.js b/packages/strapi-admin/admin/src/containers/HomePage/components.js new file mode 100644 index 0000000000..5e7f2874ac --- /dev/null +++ b/packages/strapi-admin/admin/src/containers/HomePage/components.js @@ -0,0 +1,261 @@ +import styled, { css } from 'styled-components'; + +const Block = styled.div` + width: 100%; + position: relative; + margin-bottom: 34px; + background: #ffffff; + padding: 19px 30px 30px 30px; + box-shadow: 0 2px 4px 0 #e3e9f3; + border-radius: 3px; + line-heigth: 18px; + + a { + position: relative; + text-decoration: none; + + &:hover::after { + position: absolute; + width: 100%; + height: 100%; + top: 0; + left: 0; + border-radius: 0.3rem; + content: ''; + opacity: 0.1; + background: #ffffff; + } + } + h2, + p { + line-height: 18px; + } + h2 { + display: inline-block; + } + #mainHeader { + &:after { + content: ''; + width: 100%; + height: 3px; + margin-top: 4px; + display: block; + background: #f0b41e; + } + } + + .social-wrapper { + span { + display: inline-block; + text-overflow: ellipsis; + overflow: hidden; + } + > div:nth-child(2n) { + padding-right: 0; + } + } +`; + +const Container = styled.div` + padding: 47px 13px 0 13px; + > div { + margin: 0; + } +`; + +const P = styled.p` + max-width: 550px; + padding-top: 10px; + padding-right: 30px; + color: #5c5f66; + font-size: 14px; + + b { + font-weight: 600; + } +`; + +const Wave = styled.div` + &:before { + content: '👋'; + position: absolute; + top: 24px; + right: 30px; + font-size: 50px; + } +`; + +const ALink = styled.a` + display: inline-block; + position: relative; + height: 34px; + margin-top: 16px; + padding-right: 20px; + + border-radius: 3px; + + text-overflow: ellipsis; + overflow: hidden; + line-height: 34px; + font-size: 13px; + font-weight: 600; + text-transform: uppercase; + + &:before { + content: '\f105'; + font-size: 18px; + font-weight: 600; + margin-right: 10px; + font-family: 'FontAwesome'; + } + + &:hover, + focus, + active { + text-decoration: none; + outline: 0; + } + + &:hover::after { + position: absolute; + width: 100%; + height: 100%; + top: 0; + left: 0; + border-radius: 0.3rem; + content: ''; + opacity: 0.1; + background: #ffffff; + } + + ${({ type }) => { + if (type === 'documentation') { + return css` + padding-left: 20px; + color: #ffffff; + background-color: #005fea; + &:hover { + color: #ffffff; + } + `; + } else if (type === 'blog') { + return css` + padding-left: 20px; + background-color: #333740; + color: #ffffff; + &:hover { + color: #ffffff; + } + `; + } else { + return css` + color: #005fea; + &:hover { + color: #005fea; + } + `; + } + }} +`; + +const Separator = styled.div` + height: 2px; + background-color: #f7f8f8; +`; + +const LinkWrapper = styled.a` + width: calc(50% - 6px); + position: relative; + padding: 21px 30px; + padding-left: 95px; + + height: auto; + line-height: 18px; + background-color: #f7f8f8; + &:hover, + focus, + active { + + text-decoration: none; + outline: 0; + } + + &:before { + ${({ type }) => { + if (type === 'doc') { + return css` + content: '\f02d'; + color: #42b88e; + `; + } + + return css` + content: '\f121'; + color: #f0811e; + `; + }} + position: absolute; + left: 30px; + top: 38px; + + + font-family: 'FontAwesome'; + font-size: 38px; + } + + > p { + margin: 0; + font-size: 16px; + color: #919BAE; + text-overflow: ellipsis; + overflow: hidden; + } + .bold { + color: #333740 + font-weight: 600; + } +`; + +const SocialLinkWrapper = styled.div` + height: 54px; + font-size: 14px; + font-weight: 500; + position: relative; + a { + width: 100%; + color: #333740 !important; + text-decoration: none; + line-height: 18px; + + div { + display: inline-block; + height: 25px; + width: 25px; + text-align: center; + vertical-align: top; + } + + img { + max-height: 25px; + max-width: 25px; + } + span { + margin-left: 11px; + width: calc(100% - 40px); + } + &:hover { + text-decoration: none; + } + } +`; + +export { + ALink, + Block, + Container, + LinkWrapper, + P, + Separator, + SocialLinkWrapper, + Wave, +}; diff --git a/packages/strapi-admin/admin/src/containers/HomePage/constants.js b/packages/strapi-admin/admin/src/containers/HomePage/constants.js deleted file mode 100644 index 5184422017..0000000000 --- a/packages/strapi-admin/admin/src/containers/HomePage/constants.js +++ /dev/null @@ -1,5 +0,0 @@ -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/hooks.js b/packages/strapi-admin/admin/src/containers/HomePage/hooks.js new file mode 100644 index 0000000000..f268a59043 --- /dev/null +++ b/packages/strapi-admin/admin/src/containers/HomePage/hooks.js @@ -0,0 +1,55 @@ +import { useEffect, useState } from 'react'; +import { request } from 'strapi-helper-plugin'; + +const useFetch = () => { + const [state, setState] = useState({ + error: false, + isLoading: true, + posts: [{ link: '1' }, { link: '2' }], + }); + + useEffect(() => { + const abortController = new AbortController(); + const { signal } = abortController; + const fetchData = async () => { + try { + const response = await request( + 'https://blog.strapi.io/ghost/api/v0.1/posts/?client_id=ghost-frontend&client_secret=1f260788b4ec&limit=2', + { + method: 'GET', + headers: { + 'Access-Control-Allow-Origin': '*', + }, + signal, + }, + false, + false, + { noAuth: true } + ); + const posts = response.posts.reduce((acc, curr) => { + acc.push({ + title: curr.title, + link: curr.slug, + content: curr.meta_description, + }); + + return acc; + }, []); + + setState({ isLoading: false, posts, error: false }); + } catch (err) { + setState({ isLoading: false, error: true, posts: [] }); + } + }; + + fetchData(); + + return () => { + abortController.abort(); + }; + }, []); + + return state; +}; + +export default useFetch; diff --git a/packages/strapi-admin/admin/src/containers/HomePage/index.js b/packages/strapi-admin/admin/src/containers/HomePage/index.js index 383f6951e5..e8834d639d 100644 --- a/packages/strapi-admin/admin/src/containers/HomePage/index.js +++ b/packages/strapi-admin/admin/src/containers/HomePage/index.js @@ -4,90 +4,39 @@ * */ /* eslint-disable */ -import React from 'react'; -import { connect } from 'react-redux'; +import React, { memo } from 'react'; import Helmet from 'react-helmet'; import { FormattedMessage } from 'react-intl'; -import { bindActionCreators, compose } from 'redux'; -import { createStructuredSelector } from 'reselect'; -import PropTypes from 'prop-types'; -import { get, isEmpty, upperFirst } from 'lodash'; -import cn from 'classnames'; +import { get, upperFirst } from 'lodash'; +import { auth } from 'strapi-helper-plugin'; +import useFetch from './hooks'; import { - Button, - InputText as Input, - auth, - validateInput, -} from 'strapi-helper-plugin'; - -import Block from '../../components/HomePageBlock'; -import Sub from '../../components/Sub'; -import SupportUsCta from '../../components/SupportUsCta'; -import SupportUsTitle from '../../components/SupportUsTitle'; - -import { selectPlugins } from '../App/selectors'; - -import injectReducer from '../../utils/injectReducer'; -import injectSaga from '../../utils/injectSaga'; - -import BlockLink from './BlockLink'; -import CommunityContent from './CommunityContent'; -import CreateContent from './CreateContent'; + ALink, + Block, + Container, + LinkWrapper, + P, + Wave, + Separator, +} from './components'; +import BlogPost from './BlogPost'; import SocialLink from './SocialLink'; -import WelcomeContent from './WelcomeContent'; - -import { getArticles, onChange, submit } from './actions'; -import makeSelectHomePage from './selectors'; -import reducer from './reducer'; -import saga from './saga'; -import styles from './styles.scss'; - -const FIRST_BLOCK = [ - { - title: { - id: 'app.components.HomePage.welcome', - }, - content: () => , - }, - { - title: { - id: 'app.components.HomePage.create', - }, - content: () => , - }, -]; const FIRST_BLOCK_LINKS = [ { - link: 'https://strapi.io/documentation/', - content: { - id: 'app.components.BlockLink.documentation.content', - }, - isDocumentation: true, - title: { - id: 'app.components.BlockLink.documentation', - }, + link: + 'https://strapi.io/documentation/3.0.0-beta.x/getting-started/quick-start.html#_4-create-a-new-content-type', + contentId: 'app.components.BlockLink.documentation.content', + titleId: 'app.components.BlockLink.documentation', }, { - link: 'https://github.com/strapi/strapi-examples', - content: { - id: 'app.components.BlockLink.code.content', - }, - isDocumentation: false, - title: { - id: 'app.components.BlockLink.code', - }, + link: 'https://github.com/strapi/foodadvisor', + contentId: 'app.components.BlockLink.code.content', + titleId: 'app.components.BlockLink.code', }, ]; -const SECOND_BLOCK = { - title: { - id: 'app.components.HomePage.community', - }, - content: () => , -}; - const SOCIAL_LINKS = [ { name: 'GitHub', @@ -115,196 +64,164 @@ const SOCIAL_LINKS = [ }, ]; -export class HomePage extends React.PureComponent { - // eslint-disable-line react/prefer-stateless-function - state = { errors: [] }; - - componentDidMount() { - this.props.getArticles(); - } - - handleSubmit = e => { +const HomePage = ({ global: { plugins }, history: { push } }) => { + const { error, isLoading, posts } = useFetch(); + const handleClick = e => { e.preventDefault(); - const errors = validateInput( - this.props.homePage.body.email, - { required: true }, - 'email' - ); - this.setState({ errors }); - if (isEmpty(errors)) { - return this.props.submit(); - } + push('/plugins/content-type-builder/models'); }; + const hasAlreadyCreatedContentTypes = + get( + plugins, + ['content-manager', 'leftMenuSections', '0', 'links'], + [] + ).filter(contentType => contentType.isDisplayed === true).length > 1; - showFirstBlock = () => - get(this.context.plugins, 'content-manager.leftMenuSections.0.links', []) - .length === 0; + const headerId = hasAlreadyCreatedContentTypes + ? 'HomePage.greetings' + : 'app.components.HomePage.welcome'; + const username = get(auth.getUserInfo(), 'username', ''); + const linkProps = hasAlreadyCreatedContentTypes + ? { + id: 'app.components.HomePage.button.blog', + href: 'https://blog.strapi.io/', + onClick: () => {}, + type: 'blog', + target: '_blank', + } + : { + id: 'app.components.HomePage.create', + href: '', + onClick: handleClick, + type: 'documentation', + }; - renderButton = () => { - /* eslint-disable indent */ - const data = this.showFirstBlock() - ? { - className: styles.homePageTutorialButton, - href: - 'https://strapi.io/documentation/getting-started/quick-start.html#_3-create-a-content-type', - id: 'app.components.HomePage.button.quickStart', - primary: true, - } - : { - className: styles.homePageBlogButton, - id: 'app.components.HomePage.button.blog', - href: 'https://blog.strapi.io/', - primary: false, - }; - /* eslint-enable indent */ - - return ( - - - - ); - }; - - render() { - const { - homePage: { articles, body }, - } = this.props; - - const WELCOME_AGAIN_BLOCK = [ - { - title: { - id: 'app.components.HomePage.welcome.again', - }, - name: upperFirst(`${get(auth.getUserInfo(), 'username')}!`), - content: () => , - }, - ]; - - return ( -
- + return ( + <> + + {title => } + +
-
+
- {this.showFirstBlock() && - FIRST_BLOCK.map((value, key) => ( - - ))} - {!this.showFirstBlock() && - WELCOME_AGAIN_BLOCK.concat(articles).map((value, key) => ( - - ))} - {this.renderButton()} -
- {FIRST_BLOCK_LINKS.map((value, key) => ( - - ))} -
-
- - -
-
- {SOCIAL_LINKS.map((value, key) => ( - + + + {msg =>

{msg}

} +
+ {hasAlreadyCreatedContentTypes ? ( + + {msg =>

{msg}

} +
+ ) : ( + + {congrats => { + return ( + + {content => { + return ( + + {boldContent => { + return ( +

+ {congrats}  + {content}   + {boldContent} +

+ ); + }} +
+ ); + }} +
+ ); + }} +
+ )} + {hasAlreadyCreatedContentTypes && ( +
+ {posts.map((post, index) => ( + ))}
-
-
- -
-
-
-
- - - {message => } - -
-
-
-
+ )} + + {msg => ( + + {msg} + + )} + + +
+ {FIRST_BLOCK_LINKS.map((data, index) => { + const type = index === 0 ? 'doc' : 'code'; + + return ( + + + {title =>

{title}

} +
+ + {content =>

{content}

} +
+
+ ); + })}
-
- -
- - - {message =>

{message}

} -
- + +
+ + + {msg =>

{msg}

} +
+ + {content =>

{content}

} +
+ + {msg => ( + + {msg} + + )} + +
+ {SOCIAL_LINKS.map((value, key) => ( + + ))}
-
- ); - } -} - -HomePage.contextTypes = { - plugins: PropTypes.object, -}; - -HomePage.propTypes = { - getArticles: PropTypes.func.isRequired, - homePage: PropTypes.object.isRequired, - onChange: PropTypes.func.isRequired, - submit: PropTypes.func.isRequired, -}; - -const mapStateToProps = createStructuredSelector({ - homePage: makeSelectHomePage(), - plugins: selectPlugins(), -}); - -function mapDispatchToProps(dispatch) { - return bindActionCreators( - { - getArticles, - onChange, - submit, - }, - dispatch + + ); -} +}; -const withConnect = connect( - mapStateToProps, - mapDispatchToProps -); - -const withReducer = injectReducer({ key: 'homePage', reducer }); -const withSaga = injectSaga({ key: 'homePage', saga }); - -// export default connect(mapDispatchToProps)(HomePage); -export default compose( - withReducer, - withSaga, - withConnect -)(HomePage); +export default memo(HomePage); diff --git a/packages/strapi-admin/admin/src/containers/HomePage/messages.json b/packages/strapi-admin/admin/src/containers/HomePage/messages.json deleted file mode 100644 index 18d78e2878..0000000000 --- a/packages/strapi-admin/admin/src/containers/HomePage/messages.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "welcome": { - "id": "app.components.HomePage.welcome", - "defaultMessage": "Welcome on board!" - } -} diff --git a/packages/strapi-admin/admin/src/containers/HomePage/reducer.js b/packages/strapi-admin/admin/src/containers/HomePage/reducer.js deleted file mode 100644 index 3f3a086ca8..0000000000 --- a/packages/strapi-admin/admin/src/containers/HomePage/reducer.js +++ /dev/null @@ -1,33 +0,0 @@ -/** - * - * HomePage reducer - */ - -import { fromJS, List, Map } from 'immutable'; - -import { GET_ARTICLES_SUCCEEDED, ON_CHANGE, SUBMIT_SUCCEEDED } from './constants'; - -const initialState = fromJS({ - articles: List([ - {content: '', title: '', link: ''}, - {content: '', title: '', link: ''}, - ]), - body: Map({ - email: '', - }), -}); - -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: - return state.updateIn(['body', 'email'], () => ''); - default: - return state; - } -} - -export default homePageReducer; diff --git a/packages/strapi-admin/admin/src/containers/HomePage/saga.js b/packages/strapi-admin/admin/src/containers/HomePage/saga.js deleted file mode 100644 index c302653dd4..0000000000 --- a/packages/strapi-admin/admin/src/containers/HomePage/saga.js +++ /dev/null @@ -1,67 +0,0 @@ -/* eslint-disable */ -import 'whatwg-fetch'; -import { dropRight, take } from 'lodash'; -import removeMd from 'remove-markdown'; -import { all, call, fork, put, select, takeLatest } from 'redux-saga/effects'; -import { request } from 'strapi-helper-plugin'; -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()); - yield call(request, 'https://analytics.strapi.io/register', { - method: 'POST', - body, - }); - } catch (err) { - // silent - } finally { - strapi.notification.success('HomePage.notification.newsLetter.success'); - yield put(submitSucceeded()); - } -} - -function* defaultSaga() { - yield all([ - fork(takeLatest, SUBMIT, submit), - 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/selectors.js b/packages/strapi-admin/admin/src/containers/HomePage/selectors.js deleted file mode 100644 index 46699dab14..0000000000 --- a/packages/strapi-admin/admin/src/containers/HomePage/selectors.js +++ /dev/null @@ -1,32 +0,0 @@ -import { createSelector } from 'reselect'; - -/** - * Direct selector to the homePage state domain - */ -const selectHomePageDomain = () => (state) => state.get('homePage'); - -/** - * Other specific selectors - */ - - -/** - * Default selector used by HomePage - */ - -const makeSelectHomePage = () => createSelector( - selectHomePageDomain(), - (substate) => substate.toJS(), -); - -const makeSelectBody = () => createSelector( - selectHomePageDomain(), - (substate) => substate.get('body').toJS(), -); - - -export default makeSelectHomePage; -export { - makeSelectBody, - selectHomePageDomain, -}; diff --git a/packages/strapi-admin/admin/src/containers/HomePage/styles.scss b/packages/strapi-admin/admin/src/containers/HomePage/styles.scss deleted file mode 100644 index 6c8c72d2fd..0000000000 --- a/packages/strapi-admin/admin/src/containers/HomePage/styles.scss +++ /dev/null @@ -1,289 +0,0 @@ -.blockLink { - position: relative; - width: calc(50% - 6px); - height: auto; - margin-top: 41px; - padding: 22px 25px 19px 96px; - background: #F7F8F8; - border-radius: 3px; - line-height: 18px; - text-decoration: none; - > span { - font-family: Lato-Bold; - font-size: 16px; - color: #333740; - letter-spacing: 0; - } - > p { - font-family: Lato-Regular; - font-size: 13px; - color: #919BAE; - letter-spacing: 0; - line-height: 18px; - margin: 0; - } - &:hover { - text-decoration: none; - } -} - -.blockLinkDocumentation { - &:before { - content: '\f02d'; - position: absolute; - left: 3rem; - top: 4rem; - color: #42B88E; - font-family: 'FontAwesome'; - font-size: 38px; - } -} - -.blockLinkCode { - &:before { - content: '\f121'; - position: absolute; - left: 3rem; - top: 4rem; - color: #F0811E; - font-family: 'FontAwesome'; - font-size: 38px; - } -} - -.blockShirt { - position: relative; - min-height: 34rem; - margin-bottom: 20px; - background-image: linear-gradient(45deg, #1A67DA 0%, #0097F6 100%) !important; - line-height: 18px; - > div { - position: absolute; - padding: 38px 0 62px 25px; - top: 0; - bottom: 0; - left: 0; - right: 0; - color: #FFFFFF; - - > p { - max-width: 400px; - margin-top: 18px; - margin-bottom: 125px; - padding-right: 35px; - font-size: 13px; - font-weight: 400; - } - } - &:before { - opacity: 0.7; - content: ''; - background-image: url('../../assets/images/bg_hp_tee_shirt.png') !important; - background-size: contain; - background-repeat: no-repeat; - position: absolute; - top: 0; - bottom: 0; - left: 0; - right: 0; - } -} -.communityContentP { - display: block; - max-width: 49rem !important; - margin-top: 0 !important; - margin-bottom: 51px; - color: #919BAE !important; -} - -.containerFluid { - padding: 47px 13px 0 13px; - > div { - margin: 0; - } -} - -.homePageFlex { - display: flex; - width: 100%; - justify-content: space-between; -} - -.homePageForm { - padding-top: 19px; - padding-left: 15px; - - div { - padding: 0; - } - - input { - float: left; - width: calc(100% - 120px); - border-top-right-radius: 0; - border-bottom-right-radius: 0; - - &:focus { - border-color: #E3E9F3; - } - - &::-webkit-input-placeholder { - font-style: italic; - } - } - - button { - float: left; - min-width: 100px; - height: 3.4rem; - margin-top: .9rem; - padding-left: 20px; - padding-right: 20px; - text-align: center; - background: #333740; - color: #FFFFFF; - border-top-right-radius: 3px; - border-bottom-right-radius: 3px; - font-size: 12px; - font-weight: 800; - letter-spacing: 0.5px; - } -} - -.homePageTutorialButton { - position: relative; - height: 34px; - margin-top: 17px; - margin-bottom: 1px; - padding-left: 40px; - padding-right: 20px; - 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'; - } -} - -.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; - right: 0px; - font-size: 50px; -} - -.newsLetterWrapper { - height: auto; - min-width: 50%; - padding: 20px 20px; - background: #F7F8F8; - border-radius: 3px; - line-height: 18px; - > div { - padding-right: 50px; - > span { - font-weight: 500; - font-size: 14px; - } - } -} - -.socialLink { - height: 54px; - font-size: 14px; - font-weight: 500; - position: relative; - a { - color: #333740 !important; - text-decoration: none; - line-height: 18px; - - div { - display: inline-block; - height: 25px; - width: 25px; - text-align: center; - vertical-align: top; - } - - img { - max-height: 25px; - max-width: 25px; - } - span { - margin-left: 11px; - } - &:hover { - text-decoration: none; - } - } -} - -.welcomeContentA { - color: #005FEA; - text-decoration: none; - &:hover { - text-decoration: none; - } -} - -.welcomeContentP { - display: block; - max-width: 55rem !important; - margin-bottom: 31px; -} - -.spinner { - display: flex; - justify-content: space-around; - width: 100%; - margin: auto; - > div { - border: 2px solid #f3f3f3; /* Light grey */ - border-top: 2px solid #3498db; /* Blue */ - border-radius: 50%; - width: 10px; - height: 10px; - animation: spin 2s linear infinite; - } -} - -@keyframes spin { - 0% { transform: rotate(0deg); } - 100% { transform: rotate(360deg); } -} diff --git a/packages/strapi-admin/admin/src/translations/en.json b/packages/strapi-admin/admin/src/translations/en.json index 7b0e5111ef..adc2d02ccf 100644 --- a/packages/strapi-admin/admin/src/translations/en.json +++ b/packages/strapi-admin/admin/src/translations/en.json @@ -154,5 +154,12 @@ "notification.error": "An error occurred", "notification.error.layout": "Couldn't retrieve the layout", "request.error.model.unknown": "This model doesn't exist", - "app.utils.delete": "Delete" + "app.utils.delete": "Delete", + "HomePage.helmet.title": "Homepage", + "HomePage.welcome.congrats": "Congrats!", + "HomePage.welcome.congrats.content": "You are logged as the first administrator. To discover the powerful features provided by Strapi,", + "HomePage.welcome.congrats.content.bold": "we recommend you to create your first Content-Type.", + "HomePage.community": "Join the Community", + "HomePage.roadmap": "See our roadmap", + "HomePage.greetings": "Hi {name}!" } diff --git a/packages/strapi-admin/admin/src/translations/fr.json b/packages/strapi-admin/admin/src/translations/fr.json index c8d78af213..4b26880309 100644 --- a/packages/strapi-admin/admin/src/translations/fr.json +++ b/packages/strapi-admin/admin/src/translations/fr.json @@ -154,5 +154,12 @@ "notification.error": "Une erreur est survenue", "notification.error.layout": "Impossible de récupérer le layout de l'admin", "request.error.model.unknown": "Le model n'existe pas", - "app.utils.delete": "Supprimer" + "app.utils.delete": "Supprimer", + "HomePage.helmet.title": "Accueil", + "HomePage.welcome.congrats": "Bravo!", + "HomePage.welcome.congrats.content": "Vous êtes connecté en tant que premier Administrateur. Afin de découvrir les fonctionnalités proposées par Strapi,", + "HomePage.welcome.congrats.content.bold": "nous vous conseillons de créer votre premier Type de Contenu.", + "HomePage.community": "Rejoignez la Communauté", + "HomePage.roadmap": "Regardez notre roadmap", + "HomePage.greetings": "Bonjour {name}!" }