├── .gitignore ├── CHANGELOG.md ├── README.md ├── craco.config.js ├── package-lock.json ├── package.json ├── public ├── favicon.ico ├── index.html ├── logo192.png ├── logo512.png ├── manifest.json └── robots.txt ├── src ├── App.js ├── App.test.js ├── css │ ├── additional-styles │ │ ├── range-slider.scss │ │ ├── theme.scss │ │ ├── toggle-switch.scss │ │ └── utility-patterns.scss │ └── style.scss ├── images │ ├── favicon.png │ ├── features-bg.png │ ├── features-element.png │ ├── hero-image.png │ └── testimonial.jpg ├── index.js ├── pages │ ├── Home.js │ ├── ResetPassword.js │ ├── SignIn.js │ └── SignUp.js ├── partials │ ├── Features.js │ ├── FeaturesBlocks.js │ ├── Footer.js │ ├── Header.js │ ├── HeroHome.js │ ├── Newsletter.js │ └── Testimonials.js ├── serviceWorker.js ├── setupTests.js └── utils │ ├── Dropdown.js │ ├── Modal.js │ └── Transition.js ├── tailwind.config.js └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # CHANGELOG.md 2 | 3 | ## [1.0.1] - 2020-10-19 4 | 5 | Fix issue with testimonail image on mobile 6 | 7 | ## [1.0.0] - 2020-10-15 8 | 9 | First release 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Free Tailwind landing page template 2 | 3 | ![Simple TailwindCSS template preview](https://user-images.githubusercontent.com/2683512/96160974-f93aa780-0f16-11eb-9ce4-81d94b216be6.png) 4 | 5 | **Simple Light** is a free landing page template built on top of **TailwindCSS** and fully coded in **React**. Simple light is designed to provide all the basic components a developer need to create a landing page for SaaS products, online services, and more. 6 | Use it for whatever you want, and be sure to reach us out on Twitter if you build anything cool/useful with it. 7 | Created and maintained with ❤️ by [Cruip.com](https://cruip.com/). 8 | 9 | ## Live demo 10 | 11 | Check the live demo here 👉️ [Live Demo](https://oscar-tailwind-landing.vercel.app/) 12 | 13 | ## Simple PRO 14 | 15 | Looking for more pages and components? Have a look at the **premium version** here 👉️ [https://cruip.com/demos/simple/](https://cruip.com/demos/simple/) 16 | 17 | ## Table of contents 18 | 19 | * [Usage](#usage) 20 | * [Available Scripts](#available-scripts) 21 | * [npm start](#npm-start) 22 | * [npm test](#npm-test) 23 | * [npm run build](#npm-run-build) 24 | * [npm run eject](#npm-run-eject) 25 | * [Learn More](#learn-more) 26 | * [Code Splitting](#code-splitting) 27 | * [Analyzing the Bundle Size](#analyzing-the-bundle-size) 28 | * [Making a Progressive Web App](#making-a-progressive-web-app) 29 | * [Advanced Configuration](#advanced-configuration) 30 | * [Deployment](#deployment) 31 | * [npm run build fails to minify](#npm-run-build-fails-to-minify) 32 | * [Google Analytics Setup](#google-analytics-setup) 33 | * [Credits](#credits) 34 | * [Terms and License](#terms-and-license) 35 | * [About Us](#about-us) 36 | * [Stay in the loop](#stay-in-the-loop) 37 | 38 | ## Usage 39 | 40 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). 41 | 42 | ### Available Scripts 43 | 44 | In the project directory, you can run: 45 | 46 | #### `npm install` 47 | To install the dependencies package. 48 | 49 | #### `npm start` 50 | 51 | Runs the app in the development mode.
52 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser. 53 | 54 | The page will reload if you make edits.
55 | You will also see any lint errors in the console. 56 | 57 | #### `npm test` 58 | 59 | Launches the test runner in the interactive watch mode.
60 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. 61 | 62 | #### `npm run build` 63 | 64 | Builds the app for production to the `build` folder.
65 | It correctly bundles React in production mode and optimizes the build for the best performance. 66 | 67 | The build is minified and the filenames include the hashes.
68 | Your app is ready to be deployed! 69 | 70 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. 71 | 72 | #### `npm run eject` 73 | 74 | **Note: this is a one-way operation. Once you `eject`, you can’t go back!** 75 | 76 | If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. 77 | 78 | Instead, it will copy all the configuration files and the transitive dependencies (Webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own. 79 | 80 | You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it. 81 | 82 | ### Learn More 83 | 84 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). 85 | 86 | To learn React, check out the [React documentation](https://reactjs.org/). 87 | 88 | #### Code Splitting 89 | 90 | This section has moved here: https://facebook.github.io/create-react-app/docs/code-splitting 91 | 92 | #### Analyzing the Bundle Size 93 | 94 | This section has moved here: https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size 95 | 96 | #### Making a Progressive Web App 97 | 98 | This section has moved here: https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app 99 | 100 | #### Advanced Configuration 101 | 102 | This section has moved here: https://facebook.github.io/create-react-app/docs/advanced-configuration 103 | 104 | #### Deployment 105 | 106 | This section has moved here: https://facebook.github.io/create-react-app/docs/deployment 107 | 108 | #### `npm run build` fails to minify 109 | 110 | This section has moved here: https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify 111 | 112 | ### Google Analytics Setup 113 | 114 | This template uses the [React Google Analytics Module](https://github.com/react-ga/react-ga). 115 | 116 | In order to track visitors, you need to set an [environment variable](https://create-react-app.dev/docs/adding-custom-environment-variables/) called `REACT_APP_GA_CODE` storing your [GA Tracking ID](https://support.google.com/analytics/answer/7372977). 117 | 118 | ## Credits 119 | 120 | - [Nucleo](https://nucleoapp.com/) 121 | 122 | ## Terms and License 123 | 124 | - Released under the [GPL](https://www.gnu.org/licenses/gpl-3.0.html). 125 | - Copyright 2020 [Cruip](https://cruip.com/). 126 | - Use it for personal and commercial projects, but please don’t republish, redistribute, or resell the template. 127 | - Attribution is not required, although it is really appreciated. 128 | 129 | ## About Us 130 | 131 | We're an Italian developer/designer duo creating high-quality design/code resources for developers, makers, and startups. 132 | 133 | ## Stay in the loop 134 | 135 | If you would like to know when we release new resources, you can follow us on [Twitter](https://twitter.com/Cruip_com), or you can subscribe to our monthly [newsletter](https://cruip.com/#subscribe). 136 | -------------------------------------------------------------------------------- /craco.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | style: { 3 | postcss: { 4 | plugins: [ 5 | require('tailwindcss')('./tailwind.config.js'), 6 | require('autoprefixer') 7 | ], 8 | }, 9 | }, 10 | }; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "simple-light-react", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@craco/craco": "^5.7.0", 7 | "@tailwindcss/custom-forms": "^0.2.1", 8 | "@testing-library/jest-dom": "^4.2.4", 9 | "@testing-library/react": "^9.3.2", 10 | "@testing-library/user-event": "^7.1.2", 11 | "aos": "^3.0.0-beta.6", 12 | "autoprefixer": "^9.8.6", 13 | "cruip-js-toolkit": "^1.0.2", 14 | "node-sass": "^4.14.1", 15 | "postcss-cli": "^7.1.2", 16 | "react": "^16.13.1", 17 | "react-dom": "^16.13.1", 18 | "react-router-dom": "^5.2.0", 19 | "react-scripts": "3.4.1", 20 | "react-transition-group": "^4.4.1", 21 | "tailwindcss": "^1.8.10" 22 | }, 23 | "scripts": { 24 | "start": "craco start", 25 | "build": "craco build", 26 | "test": "craco test", 27 | "eject": "craco eject" 28 | }, 29 | "eslintConfig": { 30 | "extends": "react-app" 31 | }, 32 | "browserslist": { 33 | "production": [ 34 | ">0.2%", 35 | "not dead", 36 | "not op_mini all" 37 | ], 38 | "development": [ 39 | "last 1 chrome version", 40 | "last 1 firefox version", 41 | "last 1 safari version" 42 | ] 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cardoso-topdev/react-tailwind-template/3f0ef671a15e21f8919cd46e1cdb798f7b40ccd7/public/favicon.ico -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 27 | React App 28 | 29 | 30 | 31 |
32 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cardoso-topdev/react-tailwind-template/3f0ef671a15e21f8919cd46e1cdb798f7b40ccd7/public/logo192.png -------------------------------------------------------------------------------- /public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cardoso-topdev/react-tailwind-template/3f0ef671a15e21f8919cd46e1cdb798f7b40ccd7/public/logo512.png -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /src/App.js: -------------------------------------------------------------------------------- 1 | import React, { useEffect } from 'react'; 2 | import { 3 | Switch, 4 | Route, 5 | useLocation 6 | } from 'react-router-dom'; 7 | 8 | import './css/style.scss'; 9 | 10 | import AOS from 'aos'; 11 | import { focusHandling } from 'cruip-js-toolkit'; 12 | 13 | import Home from './pages/Home'; 14 | import SignIn from './pages/SignIn'; 15 | import SignUp from './pages/SignUp'; 16 | import ResetPassword from './pages/ResetPassword'; 17 | 18 | function App() { 19 | 20 | const location = useLocation(); 21 | 22 | useEffect(() => { 23 | AOS.init({ 24 | once: true, 25 | disable: 'phone', 26 | duration: 700, 27 | easing: 'ease-out-cubic', 28 | }); 29 | }); 30 | 31 | useEffect(() => { 32 | document.querySelector('html').style.scrollBehavior = 'auto' 33 | window.scroll({ top: 0 }) 34 | document.querySelector('html').style.scrollBehavior = '' 35 | focusHandling('outline'); 36 | }, [location.pathname]); // triggered on route change 37 | 38 | return ( 39 | <> 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | ); 56 | } 57 | 58 | export default App; 59 | -------------------------------------------------------------------------------- /src/App.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render } from '@testing-library/react'; 3 | import App from './App'; 4 | 5 | test('renders learn react link', () => { 6 | const { getByText } = render(); 7 | const linkElement = getByText(/learn react/i); 8 | expect(linkElement).toBeInTheDocument(); 9 | }); 10 | -------------------------------------------------------------------------------- /src/css/additional-styles/range-slider.scss: -------------------------------------------------------------------------------- 1 | // Range slider 2 | $range-thumb-size: 36px; 3 | 4 | input[type=range] { 5 | appearance: none; 6 | background: #ccc; 7 | border-radius: 3px; 8 | height: 6px; 9 | margin-top: ($range-thumb-size - 6px) / 2; 10 | margin-bottom: ($range-thumb-size - 6px) / 2; 11 | --thumb-size: #{$range-thumb-size}; 12 | 13 | &::-webkit-slider-thumb { 14 | appearance: none; 15 | -webkit-appearance: none; 16 | background-color: #000; 17 | background-image: url("data:image/svg+xml,%3Csvg width='12' height='8' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M8 .5v7L12 4zM0 4l4 3.5v-7z' fill='%23FFF' fill-rule='nonzero'/%3E%3C/svg%3E"); 18 | background-position: center; 19 | background-repeat: no-repeat; 20 | border: 0; 21 | border-radius: 50%; 22 | cursor: pointer; 23 | height: $range-thumb-size; 24 | width: $range-thumb-size; 25 | } 26 | 27 | &::-moz-range-thumb { 28 | background-color: #000; 29 | background-image: url("data:image/svg+xml,%3Csvg width='12' height='8' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M8 .5v7L12 4zM0 4l4 3.5v-7z' fill='%23FFF' fill-rule='nonzero'/%3E%3C/svg%3E"); 30 | background-position: center; 31 | background-repeat: no-repeat; 32 | border: 0; 33 | border: none; 34 | border-radius: 50%; 35 | cursor: pointer; 36 | height: $range-thumb-size; 37 | width: $range-thumb-size; 38 | } 39 | 40 | &::-ms-thumb { 41 | background-color: #000; 42 | background-image: url("data:image/svg+xml,%3Csvg width='12' height='8' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M8 .5v7L12 4zM0 4l4 3.5v-7z' fill='%23FFF' fill-rule='nonzero'/%3E%3C/svg%3E"); 43 | background-position: center; 44 | background-repeat: no-repeat; 45 | border: 0; 46 | border-radius: 50%; 47 | cursor: pointer; 48 | height: $range-thumb-size; 49 | width: $range-thumb-size; 50 | } 51 | 52 | &::-moz-focus-outer { 53 | border: 0; 54 | } 55 | } -------------------------------------------------------------------------------- /src/css/additional-styles/theme.scss: -------------------------------------------------------------------------------- 1 | html { 2 | scroll-behavior: smooth; 3 | } 4 | 5 | :focus, 6 | button:focus, 7 | .btn:focus, 8 | .btn-sm:focus { 9 | outline: 2px solid rgba(#0070F4, 0.5); 10 | } 11 | 12 | // Hamburger button 13 | .hamburger { 14 | 15 | svg > * { 16 | 17 | &:nth-child(1), 18 | &:nth-child(2), 19 | &:nth-child(3) { 20 | transform-origin: center; 21 | } 22 | 23 | &:nth-child(1) { 24 | transition: y 0.1s 0.25s ease-in, transform 0.22s cubic-bezier(0.55, 0.055, 0.675, 0.19), opacity 0.1s ease-in; 25 | } 26 | 27 | &:nth-child(2) { 28 | transition: transform 0.22s cubic-bezier(0.55, 0.055, 0.675, 0.19); 29 | } 30 | 31 | &:nth-child(3) { 32 | transition: y 0.1s 0.25s ease-in, transform 0.22s cubic-bezier(0.55, 0.055, 0.675, 0.19), width 0.1s 0.25s ease-in; 33 | } 34 | } 35 | 36 | &.active { 37 | 38 | svg > * { 39 | 40 | &:nth-child(1) { 41 | opacity: 0; 42 | y: 11; 43 | transform: rotate(225deg); 44 | transition: y 0.1s ease-out, transform 0.22s 0.12s cubic-bezier(0.215, 0.61, 0.355, 1), opacity 0.1s 0.12s ease-out; 45 | } 46 | 47 | &:nth-child(2) { 48 | transform: rotate(225deg); 49 | transition: transform 0.22s 0.12s cubic-bezier(0.215, 0.61, 0.355, 1); 50 | } 51 | 52 | &:nth-child(3) { 53 | y: 11; 54 | transform: rotate(135deg); 55 | transition: y 0.1s ease-out, transform 0.22s 0.12s cubic-bezier(0.215, 0.61, 0.355, 1), width 0.1s ease-out; 56 | } 57 | } 58 | } 59 | } 60 | 61 | .blur { 62 | backdrop-filter: blur(3px); 63 | -webkit-backdrop-filter: blur(3px); 64 | } 65 | 66 | // Pulsing animation 67 | @keyframes pulseLoop { 68 | 0% { opacity: .15; transform: scale(1) translateZ(0); } 69 | 30% { opacity: .15; } 70 | 60% { opacity: 0; } 71 | 80% { opacity: 0; transform: scale(1.8) translateZ(0); } 72 | } 73 | @keyframes pulseMiniLoop { 74 | 0% { opacity: 0; transform: scale(1) translateZ(0); } 75 | 30% { opacity: .3; } 76 | 50% { opacity: .3; } 77 | 80% { opacity: 0; transform: scale(3) translateZ(0); } 78 | } 79 | .pulse { 80 | transform: scale(1); 81 | opacity: 0; 82 | transform-origin: center; 83 | animation: pulseLoop 10000ms linear infinite; 84 | } 85 | .pulse-mini { 86 | animation: pulseMiniLoop 6000ms linear infinite; 87 | } 88 | .pulse-1 { 89 | animation-delay: -3000ms; 90 | } 91 | .pulse-2 { 92 | animation-delay: -6000ms; 93 | } 94 | 95 | // Animations delay 96 | .animation-delay-500 { 97 | animation-delay: 500ms !important; 98 | } 99 | 100 | .animation-delay-1000 { 101 | animation-delay: 1000ms !important; 102 | } 103 | 104 | .translate-z-0 { 105 | transform: translateZ(0); 106 | } 107 | 108 | // Custom AOS animations 109 | [data-aos="zoom-y-out"] { 110 | transform: scaleX(1.03); 111 | opacity: 0; 112 | transition-property: transform, opacity; 113 | } -------------------------------------------------------------------------------- /src/css/additional-styles/toggle-switch.scss: -------------------------------------------------------------------------------- 1 | // Switch element 2 | .form-switch { 3 | 4 | @apply relative select-none; 5 | width: 68px; 6 | 7 | label { 8 | @apply block overflow-hidden cursor-pointer rounded; 9 | height: 38px; 10 | 11 | > span:first-child { 12 | @apply absolute block rounded shadow; 13 | width: 30px; 14 | height: 30px; 15 | top: 4px; 16 | left: 4px; 17 | right: 50%; 18 | transition: all .15s ease-out; 19 | } 20 | } 21 | 22 | input[type="checkbox"] { 23 | 24 | &:checked { 25 | 26 | + label { 27 | @apply bg-blue-600; 28 | 29 | > span:first-child { 30 | left: 34px; 31 | } 32 | } 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /src/css/additional-styles/utility-patterns.scss: -------------------------------------------------------------------------------- 1 | // Typography 2 | .h1 { 3 | @apply text-4xl font-extrabold leading-tight tracking-tighter; 4 | } 5 | 6 | .h2 { 7 | @apply text-3xl font-extrabold leading-tight tracking-tighter; 8 | } 9 | 10 | .h3 { 11 | @apply text-3xl font-bold leading-tight; 12 | } 13 | 14 | .h4 { 15 | @apply text-2xl font-bold leading-snug tracking-tight; 16 | } 17 | 18 | @screen md { 19 | .h1 { 20 | @apply text-5xl; 21 | } 22 | 23 | .h2 { 24 | @apply text-4xl; 25 | } 26 | } 27 | 28 | // Buttons 29 | .btn, 30 | .btn-sm { 31 | @apply font-medium inline-flex items-center justify-center border border-transparent rounded leading-snug transition duration-150 ease-in-out; 32 | } 33 | 34 | .btn { 35 | @apply px-8 py-3 shadow-lg; 36 | } 37 | 38 | .btn-sm { 39 | @apply px-4 py-2 shadow; 40 | } -------------------------------------------------------------------------------- /src/css/style.scss: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;700;800;900&display=fallback'); 2 | 3 | @tailwind base; 4 | @tailwind components; 5 | 6 | // Additional styles 7 | @import 'additional-styles/utility-patterns.scss'; 8 | @import 'additional-styles/range-slider.scss'; 9 | @import 'additional-styles/toggle-switch.scss'; 10 | @import 'additional-styles/theme.scss'; 11 | 12 | @tailwind utilities; 13 | 14 | // Additional Tailwind directives: https://tailwindcss.com/docs/functions-and-directives/#responsive 15 | @responsive { 16 | .rtl { 17 | direction: rtl; 18 | } 19 | } 20 | 21 | // See Alpine.js: https://github.com/alpinejs/alpine#x-cloak 22 | [x-cloak] { 23 | display: none; 24 | } 25 | 26 | // AOS styles 27 | $aos-distance: 10px; 28 | @import 'node_modules/aos/src/sass/aos.scss'; -------------------------------------------------------------------------------- /src/images/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cardoso-topdev/react-tailwind-template/3f0ef671a15e21f8919cd46e1cdb798f7b40ccd7/src/images/favicon.png -------------------------------------------------------------------------------- /src/images/features-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cardoso-topdev/react-tailwind-template/3f0ef671a15e21f8919cd46e1cdb798f7b40ccd7/src/images/features-bg.png -------------------------------------------------------------------------------- /src/images/features-element.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cardoso-topdev/react-tailwind-template/3f0ef671a15e21f8919cd46e1cdb798f7b40ccd7/src/images/features-element.png -------------------------------------------------------------------------------- /src/images/hero-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cardoso-topdev/react-tailwind-template/3f0ef671a15e21f8919cd46e1cdb798f7b40ccd7/src/images/hero-image.png -------------------------------------------------------------------------------- /src/images/testimonial.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cardoso-topdev/react-tailwind-template/3f0ef671a15e21f8919cd46e1cdb798f7b40ccd7/src/images/testimonial.jpg -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import { BrowserRouter as Router } from "react-router-dom"; 4 | import App from './App'; 5 | import * as serviceWorker from './serviceWorker'; 6 | 7 | ReactDOM.render( 8 | 9 | 10 | 11 | 12 | , 13 | document.getElementById('root') 14 | ); 15 | 16 | // If you want your app to work offline and load faster, you can change 17 | // unregister() to register() below. Note this comes with some pitfalls. 18 | // Learn more about service workers: https://bit.ly/CRA-PWA 19 | serviceWorker.unregister(); 20 | -------------------------------------------------------------------------------- /src/pages/Home.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import Header from '../partials/Header'; 4 | import HeroHome from '../partials/HeroHome'; 5 | import FeaturesHome from '../partials/Features'; 6 | import FeaturesBlocks from '../partials/FeaturesBlocks'; 7 | import Testimonials from '../partials/Testimonials'; 8 | import Newsletter from '../partials/Newsletter'; 9 | import Footer from '../partials/Footer'; 10 | 11 | function Home() { 12 | return ( 13 |
14 | 15 | {/* Site header */} 16 |
17 | 18 | {/* Page content */} 19 |
20 | 21 | {/* Page sections */} 22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | {/* Site footer */} 31 |
32 | 33 |
34 | ); 35 | } 36 | 37 | export default Home; -------------------------------------------------------------------------------- /src/pages/ResetPassword.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import Header from '../partials/Header'; 4 | 5 | function ResetPassword() { 6 | return ( 7 |
8 | 9 | {/* Site header */} 10 |
11 | 12 | {/* Page content */} 13 |
14 | 15 |
16 |
17 |
18 | 19 | {/* Page header */} 20 |
21 |

Let’s get you back up on your feet

22 |

Enter the email address you used when you signed up for your account, and we’ll email you a link to reset your password.

23 |
24 | 25 | {/* Form */} 26 |
27 |
28 |
29 |
30 | 31 | 32 |
33 |
34 |
35 |
36 | 37 |
38 |
39 |
40 |
41 | 42 |
43 |
44 |
45 | 46 |
47 | 48 |
49 | ); 50 | } 51 | 52 | export default ResetPassword; -------------------------------------------------------------------------------- /src/pages/SignIn.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Link } from 'react-router-dom'; 3 | 4 | import Header from '../partials/Header'; 5 | 6 | function SignIn() { 7 | return ( 8 |
9 | 10 | {/* Site header */} 11 |
12 | 13 | {/* Page content */} 14 |
15 | 16 |
17 |
18 |
19 | 20 | {/* Page header */} 21 |
22 |

Welcome back. We exist to make entrepreneurism easier.

23 |
24 | 25 | {/* Form */} 26 |
27 |
28 |
29 |
30 | 31 | 32 |
33 |
34 |
35 |
36 |
37 | 38 | Having trouble signing in? 39 |
40 | 41 |
42 |
43 |
44 |
45 |
46 | 50 |
51 |
52 |
53 |
54 |
55 | 56 |
57 |
58 |
59 |
60 | 61 |
Or
62 | 63 |
64 |
65 |
66 |
67 | 73 |
74 |
75 |
76 |
77 | 83 |
84 |
85 |
86 |
87 | Don’t you have an account? Sign up 88 |
89 |
90 | 91 |
92 |
93 |
94 | 95 |
96 | 97 |
98 | ); 99 | } 100 | 101 | export default SignIn; -------------------------------------------------------------------------------- /src/pages/SignUp.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Link } from 'react-router-dom'; 3 | 4 | import Header from '../partials/Header'; 5 | 6 | function SignUp() { 7 | return ( 8 |
9 | 10 | {/* Site header */} 11 |
12 | 13 | {/* Page content */} 14 |
15 | 16 |
17 |
18 |
19 | 20 | {/* Page header */} 21 |
22 |

Welcome. We exist to make entrepreneurism easier.

23 |
24 | 25 | {/* Form */} 26 |
27 |
28 |
29 |
30 | 31 | 32 |
33 |
34 |
35 |
36 | 37 | 38 |
39 |
40 |
41 |
42 | 43 | 44 |
45 |
46 |
47 |
48 | 49 |
50 |
51 |
52 | By creating an account, you agree to the terms & conditions, and our privacy policy. 53 |
54 |
55 |
56 | 57 |
Or
58 | 59 |
60 |
61 |
62 |
63 | 69 |
70 |
71 |
72 |
73 | 79 |
80 |
81 |
82 |
83 | Already using Simple? Sign in 84 |
85 |
86 | 87 |
88 |
89 |
90 | 91 |
92 | 93 |
94 | ); 95 | } 96 | 97 | export default SignUp; -------------------------------------------------------------------------------- /src/partials/Features.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useRef, useEffect } from 'react'; 2 | import Transition from '../utils/Transition.js'; 3 | 4 | function Features() { 5 | 6 | const [tab, setTab] = useState(1); 7 | 8 | const tabs = useRef(null); 9 | 10 | const heightFix = () => { 11 | if (tabs.current.children[tab]) { 12 | tabs.current.style.height = tabs.current.children[tab - 1].offsetHeight + 'px' 13 | } 14 | } 15 | 16 | useEffect(() => { 17 | heightFix() 18 | // eslint-disable-next-line react-hooks/exhaustive-deps 19 | }, [tab]) 20 | 21 | return ( 22 |
23 | 24 | {/* Section background (needs .relative class on parent and next sibling elements) */} 25 | 26 |
27 | 28 |
29 |
30 | 31 | {/* Section header */} 32 |
33 |

Explore the solutions

34 |

Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur excepteur sint occaecat cupidatat.

35 |
36 | 37 | {/* Section content */} 38 |
39 | 40 | {/* Content */} 41 |
42 |
43 |

Powerful suite of tools

44 |

Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa.

45 |
46 | {/* Tabs buttons */} 47 | 94 |
95 | 96 | {/* Tabs items */} 97 |
98 |
99 | {/* Item 1 */} 100 | 111 |
112 | Features bg 113 | Element 114 |
115 |
116 | {/* Item 2 */} 117 | 128 |
129 | Features bg 130 | Element 131 |
132 |
133 | {/* Item 3 */} 134 | 145 |
146 | Features bg 147 | Element 148 |
149 |
150 |
151 |
152 | 153 |
154 | 155 |
156 |
157 |
158 | ); 159 | } 160 | 161 | export default Features; 162 | -------------------------------------------------------------------------------- /src/partials/FeaturesBlocks.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | function FeaturesBlocks() { 4 | return ( 5 |
6 | 7 | {/* Section background (needs .relative class on parent and next sibling elements) */} 8 | 9 |
10 | 11 |
12 |
13 | 14 | {/* Section header */} 15 |
16 |

How Simple works

17 |

Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur excepteur sint occaecat cupidatat.

18 |
19 | 20 | {/* Items */} 21 |
22 | 23 | {/* 1st item */} 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 |

Initial Contact

37 |

Lorem ipsum dolor sit amet, consectetur adipiscing elit.

38 |
39 | 40 | {/* 2nd item */} 41 |
42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 |

Discovery Session

53 |

Lorem ipsum dolor sit amet, consectetur adipiscing elit.

54 |
55 | 56 | {/* 3rd item */} 57 |
58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 |

Contracting

68 |

Lorem ipsum dolor sit amet, consectetur adipiscing elit.

69 |
70 | 71 | {/* 4th item */} 72 |
73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 |

Fast Prototyping

85 |

Lorem ipsum dolor sit amet, consectetur adipiscing elit.

86 |
87 | 88 | {/* 5th item */} 89 |
90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 |

Design Phase

100 |

Lorem ipsum dolor sit amet, consectetur adipiscing elit.

101 |
102 | 103 | {/* 6th item */} 104 |
105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 |

Develop & Launch

117 |

Lorem ipsum dolor sit amet, consectetur adipiscing elit.

118 |
119 | 120 |
121 | 122 |
123 |
124 |
125 | ); 126 | } 127 | 128 | export default FeaturesBlocks; 129 | -------------------------------------------------------------------------------- /src/partials/Footer.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Link } from 'react-router-dom'; 3 | 4 | function Footer() { 5 | return ( 6 | 161 | ); 162 | } 163 | 164 | export default Footer; 165 | -------------------------------------------------------------------------------- /src/partials/Header.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from 'react'; 2 | import { Link } from 'react-router-dom'; 3 | 4 | function Header() { 5 | 6 | const [top, setTop] = useState(true); 7 | 8 | // detect whether user has scrolled the page down by 10px 9 | useEffect(() => { 10 | const scrollHandler = () => { 11 | window.pageYOffset > 10 ? setTop(false) : setTop(true) 12 | }; 13 | window.addEventListener('scroll', scrollHandler); 14 | return () => window.removeEventListener('scroll', scrollHandler); 15 | }, [top]); 16 | 17 | return ( 18 |
19 |
20 |
21 | 22 | {/* Site branding */} 23 |
24 | {/* Logo */} 25 | 26 | 27 | 28 | 33 | 34 | 35 | 36 | 37 |
38 | 39 | {/* Site navigation */} 40 | 56 | 57 |
58 |
59 |
60 | ); 61 | } 62 | 63 | export default Header; 64 | -------------------------------------------------------------------------------- /src/partials/HeroHome.js: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react'; 2 | import Modal from '../utils/Modal'; 3 | 4 | function HeroHome() { 5 | 6 | const [videoModalOpen, setVideoModalOpen] = useState(false); 7 | 8 | return ( 9 |
10 | 11 | {/* Illustration behind hero content */} 12 | 27 | 28 |
29 | 30 | {/* Hero content */} 31 |
32 | 33 | {/* Section header */} 34 |
35 |

Make your website wonderful

36 |
37 |

Our landing page template works on all devices, so you only have to set it up once, and get beautiful results forever.

38 |
39 |
40 | Start free trial 41 |
42 |
43 | Learn more 44 |
45 |
46 |
47 |
48 | 49 | {/* Hero image */} 50 |
51 |
52 |
53 | Hero 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 |
83 | 90 |
91 | 92 | {/* Modal */} 93 | setVideoModalOpen(false)}> 94 |
95 | 96 |
97 |
98 | 99 |
100 | 101 |
102 | 103 |
104 |
105 | ); 106 | } 107 | 108 | export default HeroHome; -------------------------------------------------------------------------------- /src/partials/Newsletter.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | function Newsletter() { 4 | return ( 5 |
6 |
7 |
8 | 9 | {/* CTA box */} 10 |
11 | 12 | {/* Background illustration */} 13 | 37 | 38 |
39 | 40 | {/* CTA content */} 41 |
42 |

Powering your business

43 |

Lorem ipsum dolor sit amet consectetur adipisicing elit nemo expedita voluptas culpa sapiente.

44 | 45 | {/* CTA form */} 46 |
47 |
48 | 49 | Subscribe 50 |
51 | {/* Success message */} 52 | {/*

Thanks for subscribing!

*/} 53 |

7 days free trial. No credit card required.

54 |
55 |
56 | 57 |
58 | 59 |
60 | 61 |
62 |
63 |
64 | ); 65 | } 66 | 67 | export default Newsletter; 68 | -------------------------------------------------------------------------------- /src/partials/Testimonials.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | function Testimonials() { 4 | return ( 5 |
6 | 7 | {/* Illustration behind content */} 8 | 23 | 24 |
25 |
26 | 27 | {/* Section header */} 28 |
29 |

Trusted by over 20,000 companies all over the world

30 |

Arcu cursus vitae congue mauris rhoncus viverra nibh cras pulvinar mattis 31 | blandit libero cursus mattis.

32 |
33 | 34 | {/* Items */} 35 |
36 | 37 | {/* Item */} 38 |
39 | 40 | 41 | 42 |
43 | 44 | {/* Item */} 45 |
46 | 47 | 48 | 49 |
50 | 51 | {/* Item */} 52 |
53 | 54 | 55 | 56 |
57 | 58 | {/* Item */} 59 |
60 | 61 | 62 | 63 |
64 | 65 | {/* Item */} 66 |
67 | 68 | 69 | 70 |
71 | 72 |
73 | 74 | {/* Testimonials */} 75 |
76 |
77 | 78 | {/* Testimonial */} 79 |
80 |
81 | 84 | Testimonial 01 85 |
86 |
87 | “ I love this product and would recommend it to anyone. Could be not easier to use, and our multiple websites are wonderful. We get nice comments all the time. “ 88 |
89 | Darya Finger 90 |
91 | CEO & Co-Founder @Dropbox 92 |
93 |
94 | 95 |
96 |
97 | 98 |
99 |
100 |
101 | ); 102 | } 103 | 104 | export default Testimonials; -------------------------------------------------------------------------------- /src/serviceWorker.js: -------------------------------------------------------------------------------- 1 | // This optional code is used to register a service worker. 2 | // register() is not called by default. 3 | 4 | // This lets the app load faster on subsequent visits in production, and gives 5 | // it offline capabilities. However, it also means that developers (and users) 6 | // will only see deployed updates on subsequent visits to a page, after all the 7 | // existing tabs open on the page have been closed, since previously cached 8 | // resources are updated in the background. 9 | 10 | // To learn more about the benefits of this model and instructions on how to 11 | // opt-in, read https://bit.ly/CRA-PWA 12 | 13 | const isLocalhost = Boolean( 14 | window.location.hostname === 'localhost' || 15 | // [::1] is the IPv6 localhost address. 16 | window.location.hostname === '[::1]' || 17 | // 127.0.0.0/8 are considered localhost for IPv4. 18 | window.location.hostname.match( 19 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ 20 | ) 21 | ); 22 | 23 | export function register(config) { 24 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { 25 | // The URL constructor is available in all browsers that support SW. 26 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href); 27 | if (publicUrl.origin !== window.location.origin) { 28 | // Our service worker won't work if PUBLIC_URL is on a different origin 29 | // from what our page is served on. This might happen if a CDN is used to 30 | // serve assets; see https://github.com/facebook/create-react-app/issues/2374 31 | return; 32 | } 33 | 34 | window.addEventListener('load', () => { 35 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; 36 | 37 | if (isLocalhost) { 38 | // This is running on localhost. Let's check if a service worker still exists or not. 39 | checkValidServiceWorker(swUrl, config); 40 | 41 | // Add some additional logging to localhost, pointing developers to the 42 | // service worker/PWA documentation. 43 | navigator.serviceWorker.ready.then(() => { 44 | console.log( 45 | 'This web app is being served cache-first by a service ' + 46 | 'worker. To learn more, visit https://bit.ly/CRA-PWA' 47 | ); 48 | }); 49 | } else { 50 | // Is not localhost. Just register service worker 51 | registerValidSW(swUrl, config); 52 | } 53 | }); 54 | } 55 | } 56 | 57 | function registerValidSW(swUrl, config) { 58 | navigator.serviceWorker 59 | .register(swUrl) 60 | .then(registration => { 61 | registration.onupdatefound = () => { 62 | const installingWorker = registration.installing; 63 | if (installingWorker == null) { 64 | return; 65 | } 66 | installingWorker.onstatechange = () => { 67 | if (installingWorker.state === 'installed') { 68 | if (navigator.serviceWorker.controller) { 69 | // At this point, the updated precached content has been fetched, 70 | // but the previous service worker will still serve the older 71 | // content until all client tabs are closed. 72 | console.log( 73 | 'New content is available and will be used when all ' + 74 | 'tabs for this page are closed. See https://bit.ly/CRA-PWA.' 75 | ); 76 | 77 | // Execute callback 78 | if (config && config.onUpdate) { 79 | config.onUpdate(registration); 80 | } 81 | } else { 82 | // At this point, everything has been precached. 83 | // It's the perfect time to display a 84 | // "Content is cached for offline use." message. 85 | console.log('Content is cached for offline use.'); 86 | 87 | // Execute callback 88 | if (config && config.onSuccess) { 89 | config.onSuccess(registration); 90 | } 91 | } 92 | } 93 | }; 94 | }; 95 | }) 96 | .catch(error => { 97 | console.error('Error during service worker registration:', error); 98 | }); 99 | } 100 | 101 | function checkValidServiceWorker(swUrl, config) { 102 | // Check if the service worker can be found. If it can't reload the page. 103 | fetch(swUrl, { 104 | headers: { 'Service-Worker': 'script' }, 105 | }) 106 | .then(response => { 107 | // Ensure service worker exists, and that we really are getting a JS file. 108 | const contentType = response.headers.get('content-type'); 109 | if ( 110 | response.status === 404 || 111 | (contentType != null && contentType.indexOf('javascript') === -1) 112 | ) { 113 | // No service worker found. Probably a different app. Reload the page. 114 | navigator.serviceWorker.ready.then(registration => { 115 | registration.unregister().then(() => { 116 | window.location.reload(); 117 | }); 118 | }); 119 | } else { 120 | // Service worker found. Proceed as normal. 121 | registerValidSW(swUrl, config); 122 | } 123 | }) 124 | .catch(() => { 125 | console.log( 126 | 'No internet connection found. App is running in offline mode.' 127 | ); 128 | }); 129 | } 130 | 131 | export function unregister() { 132 | if ('serviceWorker' in navigator) { 133 | navigator.serviceWorker.ready 134 | .then(registration => { 135 | registration.unregister(); 136 | }) 137 | .catch(error => { 138 | console.error(error.message); 139 | }); 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /src/setupTests.js: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import '@testing-library/jest-dom/extend-expect'; 6 | -------------------------------------------------------------------------------- /src/utils/Dropdown.js: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import Transition from '../utils/Transition.js'; 4 | 5 | function Dropdown({ 6 | children, 7 | title 8 | }) { 9 | 10 | const [dropdownOpen, setDropdownOpen] = useState(false); 11 | 12 | return ( 13 |
  • setDropdownOpen(true)} 16 | onMouseLeave={() => setDropdownOpen(false)} 17 | onFocus={() => setDropdownOpen(true)} 18 | onBlur={() => setDropdownOpen(false)} 19 | > 20 | e.preventDefault()} 26 | > 27 | {title} 28 | 29 | 30 | 31 | 32 | 43 | {children} 44 | 45 |
  • 46 | ); 47 | } 48 | 49 | export default Dropdown; 50 | 51 | Dropdown.propTypes = { 52 | children: PropTypes.oneOfType([ 53 | PropTypes.arrayOf(PropTypes.element), 54 | PropTypes.element.isRequired 55 | ]), 56 | title: PropTypes.string.isRequired, 57 | }; 58 | -------------------------------------------------------------------------------- /src/utils/Modal.js: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useRef } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import Transition from '../utils/Transition.js'; 4 | 5 | function Modal({ 6 | children, 7 | id, 8 | ariaLabel, 9 | show, 10 | handleClose 11 | }) { 12 | 13 | const modalContent = useRef(null); 14 | 15 | // close the modal on click outside 16 | useEffect(() => { 17 | const clickHandler = ({ target }) => { 18 | if (!show || modalContent.current.contains(target)) return; 19 | handleClose(); 20 | }; 21 | document.addEventListener('click', clickHandler); 22 | return () => document.removeEventListener('click', clickHandler); 23 | }); 24 | 25 | // close the modal if the esc key is pressed 26 | useEffect(() => { 27 | const keyHandler = ({ keyCode }) => { 28 | if (keyCode !== 27) return; 29 | handleClose(); 30 | }; 31 | document.addEventListener('keydown', keyHandler); 32 | 33 | return () => document.removeEventListener('keydown', keyHandler); 34 | }); 35 | 36 | return ( 37 | <> 38 | {/* Modal backdrop */} 39 |