├── .github
└── workflows
│ └── build-deploy.yml
├── .gitignore
├── .prettierrc
├── CNAME
├── README.md
├── package-lock.json
├── package.json
├── public
├── favicon.ico
├── index.html
├── logo192.png
├── logo512.png
├── manifest.json
└── robots.txt
├── src
├── App.tsx
├── assets
│ └── images
│ │ └── react-stripe-dropdown.png
├── components
│ ├── DropDown
│ │ ├── CompanyComponent.tsx
│ │ ├── DevelopersComponent.tsx
│ │ ├── DropdownContent.tsx
│ │ └── ProductsComponent.tsx
│ └── Navbar
│ │ ├── Container.style.tsx
│ │ ├── NavItems.tsx
│ │ └── Navbar.tsx
├── index.tsx
├── react-app-env.d.ts
├── serviceWorker.js
└── styles
│ └── GlobalStyles.ts
├── tsconfig.json
└── yarn.lock
/.github/workflows/build-deploy.yml:
--------------------------------------------------------------------------------
1 | name: Build and Deploy
2 | on: [push]
3 |
4 | jobs:
5 | build-and-deploy:
6 | runs-on: ubuntu-latest
7 | steps:
8 | - name: Checkout
9 | uses: actions/checkout@master
10 |
11 | - name: Build and Deploy
12 | uses: JamesIves/github-pages-deploy-action@releases/v2
13 | env:
14 | ACCESS_TOKEN: ${{ secrets.ACCESS_TOKEN }}
15 | BASE_BRANCH: master # The branch the action should deploy from.
16 | BRANCH: gh-pages # The branch the action should deploy to.
17 | FOLDER: build # The folder the action should deploy.
18 | BUILD_SCRIPT: npm install && npm run-script build # The build script the action should run prior to deploying.
19 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {}
--------------------------------------------------------------------------------
/CNAME:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/anuraghazra/react-stripe-dropdown/6e07c3594f5ba676bd3598ba7c7c95cbe01b47c3/CNAME
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## React Stripe Inspired Dropdown
2 |
3 | (Warning: This Dropdown is hugely inaccessible, do not reenginner and use it in your project)
4 |
5 | Stripe Inspired Dropdown made with React and FramerMotion.
6 |
7 | **demo:** https://anuraghazra.github.io/react-stripe-dropdown
8 |
9 | 
10 |
11 | ### :wrench: Tools Used
12 | - [React](http://reactjs.org/)
13 | - [Framer Motion](https://www.framer.com/motion/)
14 | - [Styled Components](https://www.styled-components.com/)
15 | - [normalize.css](https://www.npmjs.com/package/normalize.css)
16 |
17 |
18 | ## :v: Contributing
19 | Great!,
20 | after cloning & setting up the local project you can push the changes to your github fork and make a pull request.
21 |
22 | -----
23 |
24 | **local development**
25 |
26 | ### Step 1: Clone The Repo
27 |
28 | Fork the repository. then clone the repo locally by doing -
29 |
30 | ```bash
31 | git clone https://github.com/anuraghazra/react-stripe-dropdown.git
32 | ```
33 |
34 | ### Step 2: Install Dependencies
35 |
36 | cd into the directory
37 |
38 | ```bash
39 | cd react-stripe-dropdown
40 | ```
41 |
42 | install all the dependencies
43 | ```bash
44 | npm install
45 | ```
46 |
47 | ### Step 3: Start Development Server
48 |
49 | Then start the development Server
50 | ```
51 | npm start
52 | ```
53 | After running the development server the site should be running on https://localhost:3000
54 |
55 |
56 | Give the project a :star: if you liked it.
57 | Made with :heart: and React.
58 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "stripe-dropdown-menu",
3 | "version": "0.1.0",
4 | "private": true,
5 | "homepage": "https://anuraghazra.github.io/react-stripe-dropdown",
6 | "dependencies": {
7 | "@types/jest": "^24.0.22",
8 | "@types/node": "^12.12.7",
9 | "@types/react": "^16.9.11",
10 | "@types/react-dom": "^16.9.4",
11 | "@types/styled-components": "^4.4.0",
12 | "framer-motion": "^1.6.15",
13 | "normalize.css": "^8.0.1",
14 | "react": "^16.11.0",
15 | "react-dom": "^16.11.0",
16 | "react-scripts": "3.2.0",
17 | "styled-components": "^4.4.1",
18 | "typescript": "^3.7.2"
19 | },
20 | "scripts": {
21 | "predeploy": "npm run build",
22 | "deploy": "gh-pages -d build",
23 | "start": "react-scripts start",
24 | "build": "react-scripts build",
25 | "test": "react-scripts test",
26 | "eject": "react-scripts eject"
27 | },
28 | "eslintConfig": {
29 | "extends": "react-app"
30 | },
31 | "browserslist": {
32 | "production": [
33 | ">0.2%",
34 | "not dead",
35 | "not op_mini all"
36 | ],
37 | "development": [
38 | "last 1 chrome version",
39 | "last 1 firefox version",
40 | "last 1 safari version"
41 | ]
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/anuraghazra/react-stripe-dropdown/6e07c3594f5ba676bd3598ba7c7c95cbe01b47c3/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/anuraghazra/react-stripe-dropdown/6e07c3594f5ba676bd3598ba7c7c95cbe01b47c3/public/logo192.png
--------------------------------------------------------------------------------
/public/logo512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/anuraghazra/react-stripe-dropdown/6e07c3594f5ba676bd3598ba7c7c95cbe01b47c3/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 |
--------------------------------------------------------------------------------
/src/App.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Navbar from './components/Navbar/Navbar';
3 | import GlobalStyles from './styles/GlobalStyles'
4 |
5 | import { ThemeProvider, DefaultTheme } from 'styled-components';
6 |
7 | // and extend them!
8 | declare module 'styled-components' {
9 | export interface DefaultTheme {
10 | primaryBlack: string
11 | lightGray: string
12 | gray: string
13 | gradient: string
14 | }
15 | }
16 |
17 | const theme: DefaultTheme = {
18 | primaryBlack: '#424770',
19 | lightGray: '#8898aa',
20 | gray: '#696e98',
21 | gradient: 'linear-gradient(45deg, #0ec3ff, #5533ff)'
22 | }
23 |
24 | function App() {
25 | return (
26 |
36 | );
37 | }
38 |
39 | export default App;
40 |
--------------------------------------------------------------------------------
/src/assets/images/react-stripe-dropdown.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/anuraghazra/react-stripe-dropdown/6e07c3594f5ba676bd3598ba7c7c95cbe01b47c3/src/assets/images/react-stripe-dropdown.png
--------------------------------------------------------------------------------
/src/components/DropDown/CompanyComponent.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import DropdownContent from './DropdownContent';
3 | import { IconLink } from './DropdownContent';
4 | import { motion } from "framer-motion";
5 |
6 | const container = {
7 | hidden: { opacity: 1, scale: 0 },
8 | visible: {
9 | opacity: 1,
10 | scale: 1,
11 | transition: {
12 | when: "beforeChildren",
13 | staggerChildren: 0.04
14 | }
15 | }
16 | };
17 |
18 | const item = {
19 | hidden: { y: 5, opacity: 0 },
20 | visible: {
21 | y: 0,
22 | opacity: 1
23 | }
24 | };
25 |
26 | function CompanyComponent() {
27 | return (
28 |
29 |
35 | {
36 | [
37 | 'About',
38 | 'Customers',
39 | 'Enterprise',
40 | 'Partners',
41 | 'Partners Program',
42 | 'Job',
43 | 'Enviournment',
44 | 'Newsroom'
45 | ].map((link, index) => {
46 | return (
47 |
48 | {link}
49 |
50 | )
51 | })
52 | }
53 |
54 |
55 |
56 | FROM THE BLOG
57 |
62 |
63 | );
64 | }
65 | export default CompanyComponent;
--------------------------------------------------------------------------------
/src/components/DropDown/DevelopersComponent.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import styled from 'styled-components';
3 | import DropdownContent from './DropdownContent';
4 |
5 | import { IconLink } from './DropdownContent';
6 |
7 | const DevelopersDDContent = styled(DropdownContent)`
8 | .developers__title {
9 | font-weight: bold;
10 | margin-top: 20px;
11 | margin-bottom: 5px;
12 | text-transform: uppercase;
13 | font-size: 16px;
14 | }
15 |
16 | .grid {
17 | display: grid;
18 | grid-template-columns: 1fr 1fr;
19 | grid-template-rows: 1fr;
20 | margin-left: 30px;
21 | h4 {
22 | color: ${p => p.theme.lightGray};
23 | }
24 | }
25 |
26 | a {
27 | margin: 15px auto;
28 | font-size: 14px;
29 | text-transform: capitalize;
30 | }
31 | `
32 |
33 | function DevelopersComponent() {
34 | return (
35 |
36 |
37 | Documentation
38 | Start integrating the APIs right away
39 |
40 |
41 |
42 |
43 |
59 |
60 |
61 | Full API Reference
62 | API Status
63 | API Changelog
64 |
65 |
66 | );
67 | }
68 | export default DevelopersComponent;
--------------------------------------------------------------------------------
/src/components/DropDown/DropdownContent.tsx:
--------------------------------------------------------------------------------
1 | import styled from 'styled-components';
2 |
3 | const DropdownContent = styled.div`
4 | .company__blog--links {
5 | a {
6 | text-overflow: ellipsis;
7 | font-size: 14px;
8 | margin-left: 30px;
9 |
10 | &:after {
11 | content: '>';
12 | margin-left: 10px;
13 | font-weight: 900;
14 | }
15 | }
16 | }
17 | `
18 |
19 |
20 | export const IconLink = styled.a`
21 | font-weight: bold;
22 | letter-spacing: 1px;
23 |
24 | &:before {
25 | content: '';
26 | position: relative;
27 | top: 2px;
28 | margin-right: 15px;
29 | border-radius: 50%;
30 | display: inline-block;
31 | width: 15px;
32 | height: 15px;
33 | background-color: ${p => p.theme.primaryBlack};
34 | }
35 | `
36 |
37 | export default DropdownContent;
--------------------------------------------------------------------------------
/src/components/DropDown/ProductsComponent.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import styled, { css } from 'styled-components';
3 | import DropdownContent from './DropdownContent';
4 |
5 |
6 | const DescriptionLinkWrapper = styled.div<{ oneliner?: boolean }>`
7 | margin: 20px 0;
8 | font-size: 14px;
9 |
10 | .flex {
11 | display: flex;
12 | justify-content: flex-start;
13 | align-items: center;
14 | }
15 |
16 | .link__icon {
17 | ${p => p.oneliner ? css`
18 | width: 30px;
19 | height: 30px;
20 | `: css`
21 | width: 50px;
22 | height: 50px;
23 | `}
24 | border-radius: 50%;
25 | margin-right: 15px;
26 | }
27 |
28 | .text-body {
29 | align-items: center;
30 | display: flex;
31 |
32 | h3 {
33 | font-size: 16px;
34 | margin-right: 10px
35 | }
36 | }
37 |
38 | .title {
39 | text-transform: uppercase;
40 | color: ${p => p.theme.primaryBlack};
41 | }
42 | `
43 |
44 |
45 | interface DescriptionLinkProps {
46 | title: string;
47 | children: React.ReactNode;
48 | iconColor: string;
49 | oneliner?: boolean;
50 | }
51 | const DescriptionLink: React.FC = ({ title, children, iconColor, oneliner }) => {
52 | return (
53 |
54 |
55 |
56 |
57 |
58 |
{title}
59 | {children}
60 |
61 |
62 |
63 | )
64 | }
65 |
66 | function ProductsComponent() {
67 | return (
68 |
69 |
70 | Full platform for online payments
71 |
72 |
73 | Smart invoice & subscriptions
74 |
75 |
76 | Multy-party payments for platforms
77 |
78 |
79 |
80 | {/* oneliners */}
81 |
82 | Advanced bussiness analytics
83 |
84 |
85 | Advanced bussiness analytics
86 |
87 |
88 | Advanced bussiness analytics
89 |
90 |
91 | Advanced bussiness analytics
92 |
93 |
94 | );
95 | }
96 | export default ProductsComponent;
--------------------------------------------------------------------------------
/src/components/Navbar/Container.style.tsx:
--------------------------------------------------------------------------------
1 | import styled from 'styled-components';
2 |
3 | const Container = styled.section`
4 | color: ${p => p.theme.gray};
5 | /* color: #6d7580; */
6 |
7 | font-size: 14px;
8 | transform: translate(-50%,0);
9 |
10 | position: absolute;
11 | left: 50%;
12 | margin-top: 15px;
13 |
14 | background-color: rgba(255,255,255);
15 | border-radius: 5px;
16 | min-width: 400px;
17 | min-height: 300px;
18 | box-shadow: 0 5px 20px 5px rgba(0,0,0,0.1);
19 |
20 | /* arrow */
21 | &:after {
22 | position: absolute;
23 | content: '';
24 | top: -8px;
25 | left: 50%;
26 | transform: translate(-50%, 0);
27 | width: 0;
28 | height: 0;
29 | border-left: 8px solid transparent;
30 | border-right: 8px solid transparent;
31 |
32 | border-bottom: 8px solid rgba(255,255,255);
33 | }
34 |
35 | .header__title {
36 | &:before {
37 | content: '';
38 | position: relative;
39 | top: 2px;
40 | margin-right: 15px;
41 | border-radius: 50%;
42 | display: inline-block;
43 | width: 15px;
44 | height: 15px;
45 | background-color: ${p => p.theme.primaryBlack};
46 | }
47 | }
48 |
49 | a {
50 | text-decoration: none;
51 | display: block;
52 | color: ${p => p.theme.primaryBlack};
53 | text-transform: uppercase;
54 |
55 | &:hover {
56 | color: ${p => p.theme.gray};
57 | }
58 | &:hover:before {
59 | background-color: ${p => p.theme.gray};
60 | }
61 | margin: 20px 0;
62 | }
63 |
64 | h1, h2, h3, h4, h5 {
65 | color: ${p => p.theme.primaryBlack};
66 | text-transform: uppercase;
67 | }
68 | `;
69 |
70 | export default Container;
71 |
--------------------------------------------------------------------------------
/src/components/Navbar/NavItems.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import styled from 'styled-components';
3 |
4 | import Container from './Container.style';
5 | import { motion, AnimatePresence } from 'framer-motion';
6 |
7 | export const Menu = styled.ul`
8 | display: flex;
9 | width: 400px;
10 | list-style: none;
11 | align-items: center;
12 | justify-content: space-between;
13 | `
14 |
15 | export const MenuItemWrapper = styled.li`
16 | padding: 20px 0;
17 | position: relative;
18 | `
19 |
20 | const ItemTitle = styled.span`
21 | cursor: pointer;
22 | `
23 |
24 | interface ItemProps {
25 | title: string;
26 | children: any;
27 | handleMouseEnter: () => void;
28 | handleIndexLeave: () => void;
29 | direction: number;
30 | }
31 |
32 | export const Item: React.FC = ({
33 | title,
34 | children,
35 | handleMouseEnter,
36 | handleIndexLeave,
37 | direction
38 | }) => {
39 | let animationDirection = direction * 50;
40 |
41 | return (
42 |
43 |
47 | {title}
48 |
49 |
50 | {/* AnimatePresence needed for exit */}
51 |
52 | {children && (
53 |
61 |
62 |
63 |
68 | {children}
69 |
70 |
71 |
72 |
73 | )}
74 |
75 |
76 | )
77 | }
78 |
79 | export default Menu;
--------------------------------------------------------------------------------
/src/components/Navbar/Navbar.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 | import styled from 'styled-components';
3 |
4 | import Menu, { Item } from './NavItems'
5 | import ProductsComponent from '../DropDown/ProductsComponent';
6 | import DevelopersComponent from '../DropDown/DevelopersComponent';
7 | import CompanyComponent from '../DropDown/CompanyComponent';
8 |
9 |
10 |
11 | const navConfig: { title: string, component: React.ReactNode }[] = [
12 | { title: 'Products', component: },
13 | { title: 'Developers', component: },
14 | { title: 'Company', component: },
15 | ]
16 |
17 | const NavWrapper = styled.nav`
18 | display: flex;
19 | align-items: center;
20 | justify-content: center;
21 | /* background: linear-gradient(45deg, #5533ff, #0ec3ff); */
22 | width: 100%;
23 | position: absolute;
24 | left: 0;
25 | top: 0;
26 | color: white;
27 | height: 65px;
28 | padding: 0 250px;
29 |
30 | .logo {
31 | background-color: white;
32 | border-radius: 50%;
33 | width: 40px;
34 | height: 40px;
35 | text-align: center;
36 | line-height: 40px;
37 | margin-right: auto;
38 | }
39 |
40 | @media all and (max-width: 1200px) {
41 | padding: 0 100px;
42 | }
43 | `
44 |
45 |
46 | const Navbar = () => {
47 | const [activeIndex, setActiveIndex] = useState(null);
48 | const [previousIndex, setPreviousIndex] = useState(null);
49 |
50 | function handleActiveIndex(index: number) {
51 | setActiveIndex(index);
52 | }
53 |
54 | function handleMouseLeave() {
55 | setActiveIndex(null)
56 | }
57 |
58 | function handleIndexLeave() {
59 | setPreviousIndex(activeIndex);
60 | }
61 |
62 | return (
63 |
64 |
65 |
66 |
81 |
82 | );
83 | }
84 | export default Navbar;
--------------------------------------------------------------------------------
/src/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 |
4 | import App from './App';
5 | import * as serviceWorker from './serviceWorker';
6 |
7 | import 'normalize.css';
8 |
9 | ReactDOM.render(, document.getElementById('root'));
10 |
11 | // If you want your app to work offline and load faster, you can change
12 | // unregister() to register() below. Note this comes with some pitfalls.
13 | // Learn more about service workers: https://bit.ly/CRA-PWA
14 | serviceWorker.unregister();
15 |
--------------------------------------------------------------------------------
/src/react-app-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/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.1/8 is 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 | .then(response => {
105 | // Ensure service worker exists, and that we really are getting a JS file.
106 | const contentType = response.headers.get('content-type');
107 | if (
108 | response.status === 404 ||
109 | (contentType != null && contentType.indexOf('javascript') === -1)
110 | ) {
111 | // No service worker found. Probably a different app. Reload the page.
112 | navigator.serviceWorker.ready.then(registration => {
113 | registration.unregister().then(() => {
114 | window.location.reload();
115 | });
116 | });
117 | } else {
118 | // Service worker found. Proceed as normal.
119 | registerValidSW(swUrl, config);
120 | }
121 | })
122 | .catch(() => {
123 | console.log(
124 | 'No internet connection found. App is running in offline mode.'
125 | );
126 | });
127 | }
128 |
129 | export function unregister() {
130 | if ('serviceWorker' in navigator) {
131 | navigator.serviceWorker.ready.then(registration => {
132 | registration.unregister();
133 | });
134 | }
135 | }
136 |
--------------------------------------------------------------------------------
/src/styles/GlobalStyles.ts:
--------------------------------------------------------------------------------
1 | import { createGlobalStyle } from 'styled-components';
2 |
3 | export default createGlobalStyle`
4 | @import url('https://fonts.googleapis.com/css?family=Karla:400,700');
5 |
6 | * {
7 | box-sizing: border-box;
8 | }
9 |
10 | body {
11 | font-family: karla, -apple-system, system-ui, "Segoe UI", "Roboto", "Helvetica Neue", Arial, sans-serif;
12 | -webkit-font-smoothing: antialiased;
13 | color: whtie;
14 |
15 | height: 100vh;
16 | background: ${p => p.theme.gradient};
17 | }
18 |
19 | h1,h2,h3,h4,h5,h6 {
20 | margin: 0;
21 | line-height: 150%;
22 | }
23 |
24 | a {
25 | text-decoration: none;
26 | color: #0ec3ff;
27 |
28 | &:hover {
29 | color: #3670ff;
30 | }
31 | }
32 |
33 | .credits {
34 | position: absolute;
35 | bottom: 20px;
36 | color: #c5f0ff;
37 | left: 50%;
38 | transform: translateX(-50%);
39 |
40 |
41 | a {
42 | color: #06070f;
43 |
44 | &:hover {
45 | color: #c5f0ff;
46 | }
47 | }
48 | }
49 |
50 | .overflow__content {
51 | padding: 10px 30px;
52 | overflow: hidden !important;
53 | }
54 | .text-14 {
55 | font-size: 14px;
56 | }
57 | `
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "module": "esnext",
4 | "target": "es5",
5 | "incremental": true,
6 | "allowJs": true,
7 | "checkJs": false,
8 | "jsx": "react",
9 | "removeComments": true,
10 | "noEmit": true,
11 | "pretty": true,
12 | "skipLibCheck": true,
13 | "strict": false,
14 | "moduleResolution": "node",
15 | "esModuleInterop": true,
16 | "lib": [
17 | "dom",
18 | "dom.iterable",
19 | "esnext"
20 | ],
21 | "allowSyntheticDefaultImports": true,
22 | "forceConsistentCasingInFileNames": true,
23 | "resolveJsonModule": true,
24 | "isolatedModules": true,
25 | },
26 | "exclude": [
27 | "node_modules"
28 | ],
29 | "include": [
30 | "src"
31 | ]
32 | }
33 |
--------------------------------------------------------------------------------