├── README.md ├── .gitignore ├── src ├── static │ ├── cats.jpg │ ├── cats2.jpg │ ├── cats3.jpg │ ├── js │ │ ├── pages │ │ │ ├── view.js │ │ │ ├── About.js │ │ │ ├── Contact.js │ │ │ └── Home.js │ │ └── index.js │ └── css │ │ └── styles.css └── index.html ├── package.json └── server.js /README.md: -------------------------------------------------------------------------------- 1 | # single-page-application-LogRocket -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | node_modules/.bin/ 3 | 4 | node_modules/ 5 | -------------------------------------------------------------------------------- /src/static/cats.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Njong392/single-page-application-LogRocket/HEAD/src/static/cats.jpg -------------------------------------------------------------------------------- /src/static/cats2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Njong392/single-page-application-LogRocket/HEAD/src/static/cats2.jpg -------------------------------------------------------------------------------- /src/static/cats3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Njong392/single-page-application-LogRocket/HEAD/src/static/cats3.jpg -------------------------------------------------------------------------------- /src/static/js/pages/view.js: -------------------------------------------------------------------------------- 1 | export default class{ 2 | constructor(){ 3 | 4 | } 5 | 6 | setTitle(title){ 7 | document.title = title; 8 | } 9 | 10 | async getHtml(){ 11 | return ''; 12 | } 13 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "spa-logrocket", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "express": "^4.18.1" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const path = require('path'); 3 | const hostname = '127.0.0.1'; 4 | const port = 3001; 5 | 6 | const app = express(); 7 | 8 | app.use("/static", express.static(path.resolve(__dirname,'src', 'static'))); 9 | 10 | app.get("/*", (req, res) => { 11 | res.sendFile(path.resolve(__dirname, 'src', 'index.html')); 12 | }); 13 | 14 | //listen for request on port 3000, and as a callback function have the port listened on logged 15 | app.listen(port, hostname, () => { 16 | console.log(`Server running at http://${hostname}:${port}/`); 17 | }); 18 | -------------------------------------------------------------------------------- /src/static/js/pages/About.js: -------------------------------------------------------------------------------- 1 | import view from './view.js' 2 | 3 | export default class extends view{ 4 | constructor(){ 5 | super(); 6 | this.setTitle("About"); 7 | } 8 | 9 | async getHtml(){ 10 | return ` 11 | 12 |
13 |

What we do at Meowie

14 |

Meowies lets you upload pictures of your cats, so that you never lose them. Lorem ipsum dolor sit amet consectetur adipisicing elit. Consequatur commodi eveniet fugit veritatis. Id temporibus explicabo enim sunt, officiis sapiente. 15 |

16 | 17 |
18 | cat image with pink backgrounnd 19 |
20 | 21 | 22 | 23 | `; 24 | } 25 | } -------------------------------------------------------------------------------- /src/static/js/pages/Contact.js: -------------------------------------------------------------------------------- 1 | import view from './view.js' 2 | 3 | export default class extends view{ 4 | constructor(){ 5 | super(); 6 | this.setTitle("Contact us"); 7 | } 8 | 9 | async getHtml(){ 10 | return ` 11 | 12 | 13 |
14 |

Get to us to make a custom album for your cat

15 |

Meowies lets you upload pictures of your cats, so that you never lose them. Lorem ipsum dolor sit amet consectetur adipisicing elit. Consequatur commodi eveniet fugit veritatis. Id temporibus explicabo enim sunt, officiis sapiente. 16 | 17 |

18 | 19 |
20 | two cats holding each other 21 |
22 | 23 | 24 | 25 | 26 | `; 27 | } 28 | } -------------------------------------------------------------------------------- /src/static/js/pages/Home.js: -------------------------------------------------------------------------------- 1 | import view from './view.js' 2 | 3 | export default class extends view{ 4 | constructor(){ 5 | super(); 6 | this.setTitle("Home"); 7 | } 8 | 9 | async getHtml(){ 10 | return ` 11 | 12 |
13 |

An album for your cuties

14 |

Meowies lets you upload pictures of your cats, so that you never lose them. Lorem ipsum dolor sit amet consectetur adipisicing elit. Consequatur commodi eveniet fugit veritatis. Id temporibus explicabo enim sunt, officiis sapiente. 15 | Read about us here

16 |
17 | 18 |
19 | cat in ribbons 20 |
21 | 22 | `; 23 | } 24 | } -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Single Page App 8 | 9 | 10 | 11 | 12 | 13 | 25 | 26 |
27 | 28 |
29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /src/static/css/styles.css: -------------------------------------------------------------------------------- 1 | *{ 2 | padding: 0; 3 | margin: 0; 4 | box-sizing: border-box; 5 | } 6 | 7 | .navbar{ 8 | background-color: pink; 9 | padding: 20px; 10 | display: flex; 11 | justify-content: space-between; 12 | align-items: center; 13 | } 14 | .nav-items{ 15 | display: flex; 16 | } 17 | 18 | 19 | a{ 20 | text-decoration: none; 21 | color: white; 22 | font-weight: bold; 23 | font-size: x-large; 24 | } 25 | .link{ 26 | color: pink; 27 | font-size: medium; 28 | } 29 | .logo{ 30 | color: white; 31 | font-weight: bold; 32 | font-size: xx-large; 33 | font-style: oblique; 34 | } 35 | ul{ 36 | list-style: none; 37 | } 38 | .navbar ul li{ 39 | margin-left: 15px; 40 | } 41 | 42 | #home{ 43 | display: flex; 44 | align-items: center; 45 | margin: 20px; 46 | transform: translateY(100%); 47 | 48 | } 49 | 50 | .img{ 51 | width: 80%; 52 | height: 80%; 53 | } 54 | 55 | .slider{ 56 | position:fixed; 57 | top:0; 58 | left: 0; 59 | background-color: palevioletred; 60 | width: 100%; 61 | height: 100%; 62 | transform: translateY(100%); 63 | } 64 | 65 | 66 | -------------------------------------------------------------------------------- /src/static/js/index.js: -------------------------------------------------------------------------------- 1 | import Home from './pages/Home.js' 2 | import About from './pages/About.js' 3 | import Contact from './pages/Contact.js' 4 | 5 | const tl = gsap.timeline({ defaults: {ease:'power2.out'} }); 6 | tl.to('.slider', {y: "-100%", duration:1.2}); 7 | tl.to('#home', {y: "0%", duration:1.2}, "-=1"); 8 | 9 | 10 | 11 | const navigateTo = url => { 12 | history.pushState(null, null, url); 13 | router(); 14 | }; 15 | 16 | const router = async () => { 17 | const routes = [ 18 | { 19 | path: "/", 20 | view: Home 21 | }, 22 | 23 | { 24 | path: "/about", 25 | view: About 26 | }, 27 | 28 | { 29 | path: "/contact", 30 | view: Contact 31 | } 32 | 33 | 34 | ]; 35 | 36 | //test each route for match 37 | const checkMatches = routes.map(route => { 38 | return{ 39 | route: route, 40 | isMatch: location.pathname === route.path //returns a boolean value 41 | }; 42 | }); 43 | 44 | let match = checkMatches.find(checkMatch => checkMatch.isMatch); 45 | 46 | if(!match){ 47 | match = { 48 | route: routes[0], 49 | }; 50 | } 51 | 52 | const view = new match.route.view(); 53 | 54 | document.querySelector("#home").innerHTML = await view.getHtml(); 55 | 56 | 57 | }; 58 | 59 | window.addEventListener('popstate', router); 60 | 61 | 62 | 63 | document.addEventListener('DOMContentLoaded', () => { 64 | 65 | document.body.addEventListener('click', e => { 66 | e.preventDefault(); 67 | tl.to('.slider', {y: "100%", duration:0}); 68 | 69 | 70 | if(e.target.matches('[data-link]')){ 71 | 72 | tl.to('.slider', {y: "-100%", duration:1.2}); 73 | tl.fromTo('#home', {opacity: 0}, {opacity:1, duration:0.5}); 74 | navigateTo(e.target.href); 75 | 76 | } 77 | 78 | 79 | 80 | }) 81 | 82 | 83 | router(); 84 | }) --------------------------------------------------------------------------------