├── .gitattributes ├── .gitignore ├── LICENSE ├── README.md ├── package-lock.json ├── package.json ├── public ├── favicon.ico ├── images │ ├── myProfile.jpg │ └── portfolio │ │ ├── adventure │ │ ├── p1.jpg │ │ └── p2.jpg │ │ ├── animal-shelter │ │ ├── p1.jpg │ │ └── p2.jpg │ │ └── photography │ │ ├── p1.jpg │ │ └── p2.jpg ├── index.html ├── manifest.json ├── portfolio_shared_data.json ├── res_primaryLanguage.json ├── res_secondaryLanguage.json └── robots.txt └── src ├── App.js ├── App.scss ├── App.test.js ├── components ├── About.js ├── Experience.js ├── Footer.js ├── Header.js ├── ProjectDetailsModal.js ├── Projects.js └── Skills.js ├── index.js ├── index.scss ├── logo.svg ├── scss ├── dark-slider.scss ├── light-slider.scss └── themes │ ├── theme-dark.scss │ └── theme-light.scss ├── serviceWorker.js └── setupTests.js /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Dorota Gil 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | portfolio template mockup
2 | portfolio mobile demo gif 3 | 4 | react icon 5 |

Portfolio Template

6 | 7 |
  8 | ⭐ Easy to adapt and deploy portfolio project covering most important 
  9 | sections(about, exp, skills, projects), inspired with solutions found 
 10 | at GitHub. Check live preview(link below).
 11 | 
12 | 13 | :crown: advantages 14 | 15 | multilingual   mobile friendly   light/dark mode   json fetched data   minimalistic   expandable 16 | 17 |
18 | 19 |

:eye_speech_bubble: Live demo

20 | 21 | Check live demonstration here 22 | 23 | react frontend dev portfolio preview 24 | 25 |

:books: Getting started

26 | 27 | 1. Clone or fork project. 28 | 2. Install required dependencies with `npm install`. 29 | 3. Remove `homepage` entirely from `package.json` or set it to single dot. 30 | 31 | ``` 32 | // package.json 33 | { 34 | "name": "react-frontend-dev-portfolio", 35 | "homepage": "https://dorota1997.github.io/react-frontend-dev-portfolio/", <-- remove/edit this 36 | "version": "0.1.0", 37 | "private": true, 38 | "dependencies": { 39 | ... 40 | } 41 | ``` 42 | 43 | 4. `npm start` project and customize it. 44 | 5. Deploy on github-pages using `npm run deploy` command. 45 | 46 |
 47 | ⚠️ Note that:
 48 | - if you want to have portfolio on different repository than `{username}.github.io`, 
 49 | set `homepage` in `package.json` to `https://{username}.github.io/{repository-name}/` 
 50 | before deploying portfolio.
 51 | - if you want to run it locally with npm run start, make sure that you have edited 
 52 | homepage property or json data won't load.
 53 | 
54 | 55 |

:star: Inspirations

56 | 57 | React Vertical Timeline
58 | React Awesome Slider
59 | React Switch
60 | React Typical
61 | Iconify Design
62 | Polaroid effect
63 | GitHub Ref Corner 64 | 65 |

:memo: Changelog

66 |
67 | [ 05.03.2022, contributor: @mangelarilla ] 68 |
 69 | - update DevIcon stylesheet to latest one
 70 | 
71 |
72 |
73 | [ 03.10.2021, contributor: @shahednasser ] 74 |
 75 | - updated sass dependency.
 76 | 
77 |
78 |
79 | [ 26.05.2021, contributor: @DavidMatalik ] 80 |
 81 | - removed nonexisting logos references: logo192 and logo512.  
 82 | 
83 |
84 |
85 | [ 17.01.2021, contributor: @igorperic17 ] 86 |
 87 | - wrapped the Typical component into a fixed height div due to the bad transitions for a brief moment between two titles when the string is empty (the content bellow jumps up-down very quickly).
 88 | - removed the title from the page document.title due to the increased title length.
 89 | 
90 |
91 |
92 | [ 30.11.2020, contributor: @dorota1997 ] 93 |
 94 | - updated readme section
 95 | - fixed problem of json files not being read
 96 | 
97 |
98 |
99 | [ 29/30.11.2020, contributor: @trolit ] 100 |
101 | - changed resume files names to more "universal"
102 | - moved languages names to global variables
103 | - moved section names to json files
104 | - added target="_blank" for footer links
105 | - added startDate property for projects
106 | - excluded common json data to portfolio_shared_data file
107 | - added header section height calculation based on formula: window.innerHeight - 140
108 | - small changes to vertical timeline item (color/font-size)
109 | - project link in modal is not shown if empty
110 | - changed slider preloader bar color
111 | - wrapped each skill into tile
112 | - footer fullname is fetched from json now
113 | - added mising "px" for avatar in About.js component
114 | - updated json files content
115 | - page title is fetched from json data
116 | - added GitHub reference corner "label"
117 | - edited page meta
118 | - added margin, padding 0 for html tag
119 | - excluded light theme ref from theme-dark file
120 | - slightly changed Header.js section look
121 | - made some changes to App.js to apply global variables/shared json etc.
122 | - centered fullname/pos/theme toggler in Header section
123 | 
124 |
125 | 126 |

:gear: Contribution

127 | 128 | If you have any suggestions on what to improve in react-frontend-dev-portfolio and would like to share them, feel free to leave an issue or fork project to implement your own ideas :slightly_smiling_face: 129 | 130 |

:camera: Credits(images)

131 | 132 | Images used in portfolio template come from Pixabay, references: 133 | 134 | p1, p2, p3, p4, p5, p6 135 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-frontend-dev-portfolio", 3 | "homepage": "https://dorota1997.github.io/react-frontend-dev-portfolio/", 4 | "version": "0.1.0", 5 | "private": true, 6 | "dependencies": { 7 | "@testing-library/jest-dom": "^4.2.4", 8 | "@testing-library/react": "^9.5.0", 9 | "@testing-library/user-event": "^7.2.1", 10 | "bootstrap": "^4.5.2", 11 | "jquery": "^3.5.1", 12 | "react": "^16.13.1", 13 | "react-awesome-slider": "^4.1.0", 14 | "react-bootstrap": "^1.3.0", 15 | "react-dom": "^16.13.1", 16 | "react-ga": "^3.1.2", 17 | "react-scripts": "3.4.3", 18 | "react-switch": "^5.0.1", 19 | "react-typical": "^0.1.3", 20 | "react-vertical-timeline-component": "^3.3.1" 21 | }, 22 | "scripts": { 23 | "start": "react-scripts start", 24 | "build": "react-scripts build", 25 | "test": "react-scripts test", 26 | "eject": "react-scripts eject", 27 | "predeploy": "npm run build", 28 | "deploy": "gh-pages -d build" 29 | }, 30 | "eslintConfig": { 31 | "extends": "react-app" 32 | }, 33 | "browserslist": { 34 | "production": [ 35 | ">0.2%", 36 | "not dead", 37 | "not op_mini all" 38 | ], 39 | "development": [ 40 | "last 1 chrome version", 41 | "last 1 firefox version", 42 | "last 1 safari version" 43 | ] 44 | }, 45 | "devDependencies": { 46 | "@iconify/icons-logos": "^1.0.12", 47 | "@iconify/react": "^1.1.3", 48 | "gh-pages": "^3.1.0", 49 | "sass": "^1.42.1" 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dorota1997/react-frontend-dev-portfolio/befb05c7704da57ca083225610918129a7686b40/public/favicon.ico -------------------------------------------------------------------------------- /public/images/myProfile.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dorota1997/react-frontend-dev-portfolio/befb05c7704da57ca083225610918129a7686b40/public/images/myProfile.jpg -------------------------------------------------------------------------------- /public/images/portfolio/adventure/p1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dorota1997/react-frontend-dev-portfolio/befb05c7704da57ca083225610918129a7686b40/public/images/portfolio/adventure/p1.jpg -------------------------------------------------------------------------------- /public/images/portfolio/adventure/p2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dorota1997/react-frontend-dev-portfolio/befb05c7704da57ca083225610918129a7686b40/public/images/portfolio/adventure/p2.jpg -------------------------------------------------------------------------------- /public/images/portfolio/animal-shelter/p1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dorota1997/react-frontend-dev-portfolio/befb05c7704da57ca083225610918129a7686b40/public/images/portfolio/animal-shelter/p1.jpg -------------------------------------------------------------------------------- /public/images/portfolio/animal-shelter/p2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dorota1997/react-frontend-dev-portfolio/befb05c7704da57ca083225610918129a7686b40/public/images/portfolio/animal-shelter/p2.jpg -------------------------------------------------------------------------------- /public/images/portfolio/photography/p1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dorota1997/react-frontend-dev-portfolio/befb05c7704da57ca083225610918129a7686b40/public/images/portfolio/photography/p1.jpg -------------------------------------------------------------------------------- /public/images/portfolio/photography/p2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dorota1997/react-frontend-dev-portfolio/befb05c7704da57ca083225610918129a7686b40/public/images/portfolio/photography/p2.jpg -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Davina Griss | Front-end Developer 5 | 6 | 7 | 8 | 9 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /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 | "start_url": ".", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /public/portfolio_shared_data.json: -------------------------------------------------------------------------------- 1 | { 2 | "basic_info": { 3 | "name": "Davina Griss", 4 | "titles": [ "Front-end Developer", "Senior Data Engineer", "Dev Team lead", "Mobile App Developer" ], 5 | "social": [ 6 | { 7 | "name": "github", 8 | "url": "https://github.com", 9 | "class": "fab fa-github" 10 | }, 11 | { 12 | "name": "instagram", 13 | "url": "https://www.instagram.com", 14 | "class": "fab fa-instagram" 15 | } 16 | ], 17 | "image": "myProfile.jpg" 18 | }, 19 | "skills": { 20 | "icons": [ 21 | { 22 | "name": "HTML 5", 23 | "class": "devicon-html5-plain", 24 | "level": "95" 25 | }, 26 | { 27 | "name": "CSS 3", 28 | "class": "devicon-css3-plain", 29 | "level": "95" 30 | }, 31 | { 32 | "name": "Angular", 33 | "class": "devicon-angularjs-plain", 34 | "level": "80" 35 | }, 36 | { 37 | "name": "TypeScript", 38 | "class": "devicon-typescript-plain", 39 | "level": "90" 40 | }, 41 | { 42 | "name": "JavaScript", 43 | "class": "devicon-javascript-plain", 44 | "level": "70" 45 | }, 46 | { 47 | "name": "Sass", 48 | "class": "devicon-sass-original", 49 | "level": "75" 50 | }, 51 | { 52 | "name": "Bootstrap", 53 | "class": "devicon-bootstrap-plain", 54 | "level": "85" 55 | }, 56 | { 57 | "name": "C#", 58 | "class": "devicon-csharp-plain", 59 | "level": "65" 60 | }, 61 | { 62 | "name": "MySql", 63 | "class": "devicon-mysql-plain", 64 | "level": "60" 65 | } 66 | ] 67 | } 68 | } -------------------------------------------------------------------------------- /public/res_primaryLanguage.json: -------------------------------------------------------------------------------- 1 | { 2 | "basic_info": { 3 | "description_header": "Hi", 4 | "description": "👋 I'm Davina Griss. Fictional person for preview purposes :) I'm working with newest front-end frameworks like Angular, React and Vue. What you are seeing now is portfolio template from Dorota1997. If you like this portfolio template, make sure to ⭐ the repository to make it more recognizable for other users. Thank you 💜", 5 | "section_name": { 6 | "about": "About me", 7 | "projects": "Projects", 8 | "skills": "Skills", 9 | "experience": "Experience" 10 | } 11 | }, 12 | "projects": [ 13 | { 14 | "title": "Animal Shelter", 15 | "startDate": "2020", 16 | "description": "The most expanded application I had opportunity to work with. I've learned many technologies and my code was reviewed by awesome curator. Application handles all adoption processess and allows to store all evidence on adopting animals from animal shelter.", 17 | "images": [ 18 | "images/portfolio/animal-shelter/p1.jpg", 19 | "images/portfolio/animal-shelter/p2.jpg" 20 | ], 21 | "url": "", 22 | "technologies": [ 23 | { 24 | "class": "devicon-angularjs-plain", 25 | "name": "Angular" 26 | }, 27 | { 28 | "class": "devicon-typescript-plain", 29 | "name": "TypeScript" 30 | }, 31 | { 32 | "class": "devicon-csharp-plain", 33 | "name": "C#" 34 | } 35 | ] 36 | }, 37 | { 38 | "title": "Photography", 39 | "startDate": "2018", 40 | "description": "Personal project for study subject. I was responsible for testing photography application that optimizes images with popular algorithms used by graphic editors like Pixlr or Adobe Photoshop. I've earned A grade :)", 41 | "images": [ 42 | "images/portfolio/photography/p1.jpg", 43 | "images/portfolio/photography/p2.jpg" 44 | ], 45 | "url": "https://github.com", 46 | "technologies": [ 47 | { 48 | "class": "devicon-react-original", 49 | "name": "React" 50 | }, 51 | { 52 | "class": "devicon-javascript-plain", 53 | "name": "JavaScript" 54 | } 55 | ] 56 | }, 57 | { 58 | "title": "3D Object Viewer", 59 | "startDate": "2015", 60 | "description": "One of the first apps I was working on my internship. I had to develop front-end implementation for app that shows 3D models of known buildings. This was also my first project in Angular framework. I've learned a lot!", 61 | "images": [ 62 | "images/portfolio/adventure/p1.jpg", 63 | "images/portfolio/adventure/p2.jpg" 64 | ], 65 | "url": "https://github.com", 66 | "technologies": [ 67 | { 68 | "class": "devicon-angularjs-plain", 69 | "name": "Angular" 70 | }, 71 | { 72 | "class": "devicon-typescript-plain", 73 | "name": "TypeScript" 74 | }, 75 | { 76 | "class": "devicon-csharp-plain", 77 | "name": "C#" 78 | } 79 | ] 80 | } 81 | ], 82 | "experience": [ 83 | { 84 | "company": "DefOpenSource", 85 | "title": "Front-End Developer", 86 | "years": "10.2019 - present", 87 | "mainTech": [ 88 | "Angular 8/9/10" 89 | ], 90 | "technologies": [ 91 | "REST API", 92 | "RxJS", 93 | "JavaScript", 94 | "Bootstrap", 95 | "MDBootstrap", 96 | "EF Core", 97 | ".NET Core", 98 | "SignalR", 99 | "Angular Material" 100 | ] 101 | }, 102 | { 103 | "company": "Serros Solutions", 104 | "title": "Intern", 105 | "years": "01.2018 - 09.2019", 106 | "mainTech": [ 107 | "Angular 7/8" 108 | ], 109 | "technologies": [ 110 | "RxJS", 111 | "Django", 112 | "PHP", 113 | "JavaScript", 114 | "DHTMLX Gantt" 115 | ] 116 | } 117 | ] 118 | } -------------------------------------------------------------------------------- /public/res_secondaryLanguage.json: -------------------------------------------------------------------------------- 1 | { 2 | "basic_info": { 3 | "description_header": "Cześć", 4 | "description": "👋 Jestem Davina Griss. Fikcyjna osoba na potrzeby demonstracji. Pracuję z najnowszymi frameworkami front-end takimi jak Angular, React i Vue. To co teraz widzisz to szablon portfolio od Dorota1997. Jeżeli podoba Ci się ten szablon portfolio nie zapomnij o ⭐, żeby było bardziej rozpoznawalne dla innych użytkowników. Dzięki 💜", 5 | "section_name": { 6 | "about": "O mnie", 7 | "projects": "Projekty", 8 | "skills": "Umiejętności", 9 | "experience": "Doświadczenie" 10 | } 11 | }, 12 | "projects": [ 13 | { 14 | "title": "Animal Shelter", 15 | "startDate": "2020", 16 | "description": "Najbardziej rozbudowana aplikacja nad którą miałam okazję pracować. Poznałam dużo technologii a mój kod by sprawdzany przez super opiekuna. Aplikacja obsługuje wszystkie procesy adopcji i pozwala na przechowywanie wszelkiej dokumentacji związanej z adopcją zwierząt ze schroniska.", 17 | "images": [ 18 | "images/portfolio/animal-shelter/p1.jpg", 19 | "images/portfolio/animal-shelter/p2.jpg" 20 | ], 21 | "url": "", 22 | "technologies": [ 23 | { 24 | "class": "devicon-angularjs-plain", 25 | "name": "Angular" 26 | }, 27 | { 28 | "class": "devicon-typescript-plain", 29 | "name": "TypeScript" 30 | }, 31 | { 32 | "class": "devicon-csharp-plain", 33 | "name": "C#" 34 | } 35 | ] 36 | }, 37 | { 38 | "title": "Photography", 39 | "startDate": "2018", 40 | "description": "Osobisty projekt na przedmiot ze studiów. Byłam odpowiedzilna za testowanie aplikacji, która optymalizuje zdjęcia z pomocą popularnych algorytmów używanych przed edytory grafiki takie jak Pixlr czy Adobe Photoshop. Otrzymałam 5-tkę za projekt :)", 41 | "images": [ 42 | "images/portfolio/photography/p1.jpg", 43 | "images/portfolio/photography/p2.jpg" 44 | ], 45 | "url": "https://github.com", 46 | "technologies": [ 47 | { 48 | "class": "devicon-react-original", 49 | "name": "React" 50 | }, 51 | { 52 | "class": "devicon-javascript-plain", 53 | "name": "JavaScript" 54 | } 55 | ] 56 | }, 57 | { 58 | "title": "3D Object Viewer", 59 | "startDate": "2015", 60 | "description": "Jedna z pierwszych aplikacji nad którymi pracowałam na stażu. Musiałam przygotować front-end dla aplikacji, która pokazuje modele 3D znanych budynków. To był także mój pierwszy projekt w frameworku Angular. Dużo się nauczyłam!", 61 | "images": [ 62 | "images/portfolio/adventure/p1.jpg", 63 | "images/portfolio/adventure/p2.jpg" 64 | ], 65 | "url": "https://github.com", 66 | "technologies": [ 67 | { 68 | "class": "devicon-angularjs-plain", 69 | "name": "Angular" 70 | }, 71 | { 72 | "class": "devicon-typescript-plain", 73 | "name": "TypeScript" 74 | }, 75 | { 76 | "class": "devicon-csharp-plain", 77 | "name": "C#" 78 | } 79 | ] 80 | } 81 | ], 82 | "experience": [ 83 | { 84 | "company": "DefOpenSource", 85 | "title": "Front-End Developer", 86 | "years": "10.2019 - obecnie", 87 | "mainTech": [ 88 | "Angular 8/9/10" 89 | ], 90 | "technologies": [ 91 | "REST API", 92 | "RxJS", 93 | "JavaScript", 94 | "Bootstrap", 95 | "MDBootstrap", 96 | "EF Core", 97 | "Angular Material" 98 | ] 99 | }, 100 | { 101 | "company": "Serros Solutions", 102 | "title": "Stażystka", 103 | "years": "01.2018 - 09.2019", 104 | "mainTech": [ 105 | "Angular 7/8" 106 | ], 107 | "technologies": [ 108 | "REST API", 109 | "RxJS", 110 | "Swagger", 111 | "JavaScript", 112 | "DHTMLX Gantt" 113 | ] 114 | } 115 | ] 116 | } -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /src/App.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from "react"; 2 | import $ from "jquery"; 3 | import "./App.scss"; 4 | import Header from "./components/Header"; 5 | import Footer from "./components/Footer"; 6 | import About from "./components/About"; 7 | import Experience from "./components/Experience"; 8 | import Projects from "./components/Projects"; 9 | import Skills from "./components/Skills"; 10 | 11 | class App extends Component { 12 | 13 | constructor(props) { 14 | super(); 15 | this.state = { 16 | foo: "bar", 17 | resumeData: {}, 18 | sharedData: {}, 19 | }; 20 | } 21 | 22 | applyPickedLanguage(pickedLanguage, oppositeLangIconId) { 23 | this.swapCurrentlyActiveLanguage(oppositeLangIconId); 24 | document.documentElement.lang = pickedLanguage; 25 | var resumePath = 26 | document.documentElement.lang === window.$primaryLanguage 27 | ? `res_primaryLanguage.json` 28 | : `res_secondaryLanguage.json`; 29 | this.loadResumeFromPath(resumePath); 30 | } 31 | 32 | swapCurrentlyActiveLanguage(oppositeLangIconId) { 33 | var pickedLangIconId = 34 | oppositeLangIconId === window.$primaryLanguageIconId 35 | ? window.$secondaryLanguageIconId 36 | : window.$primaryLanguageIconId; 37 | document 38 | .getElementById(oppositeLangIconId) 39 | .removeAttribute("filter", "brightness(40%)"); 40 | document 41 | .getElementById(pickedLangIconId) 42 | .setAttribute("filter", "brightness(40%)"); 43 | } 44 | 45 | componentDidMount() { 46 | this.loadSharedData(); 47 | this.applyPickedLanguage( 48 | window.$primaryLanguage, 49 | window.$secondaryLanguageIconId 50 | ); 51 | } 52 | 53 | loadResumeFromPath(path) { 54 | $.ajax({ 55 | url: path, 56 | dataType: "json", 57 | cache: false, 58 | success: function (data) { 59 | this.setState({ resumeData: data }); 60 | }.bind(this), 61 | error: function (xhr, status, err) { 62 | alert(err); 63 | }, 64 | }); 65 | } 66 | 67 | loadSharedData() { 68 | $.ajax({ 69 | url: `portfolio_shared_data.json`, 70 | dataType: "json", 71 | cache: false, 72 | success: function (data) { 73 | this.setState({ sharedData: data }); 74 | document.title = `${this.state.sharedData.basic_info.name}`; 75 | }.bind(this), 76 | error: function (xhr, status, err) { 77 | alert(err); 78 | }, 79 | }); 80 | } 81 | 82 | render() { 83 | return ( 84 |
85 |
86 |
87 |
89 | this.applyPickedLanguage( 90 | window.$primaryLanguage, 91 | window.$secondaryLanguageIconId 92 | ) 93 | } 94 | style={{ display: "inline" }} 95 | > 96 | 102 |
103 |
105 | this.applyPickedLanguage( 106 | window.$secondaryLanguage, 107 | window.$primaryLanguageIconId 108 | ) 109 | } 110 | style={{ display: "inline" }} 111 | > 112 | 118 |
119 |
120 | 124 | 128 | 132 | 136 |
138 | ); 139 | } 140 | } 141 | 142 | export default App; 143 | -------------------------------------------------------------------------------- /src/App.scss: -------------------------------------------------------------------------------- 1 | @import '../src/scss/themes/theme-dark.scss'; 2 | @import '../src/scss/themes/theme-light.scss'; 3 | @import url('https://fonts.googleapis.com/css2?family=Raleway:wght@200;300&display=swap'); 4 | 5 | html { 6 | font-size: 62.5%; 7 | -webkit-font-smoothing: antialiased; 8 | margin: 0; 9 | padding: 0; 10 | } 11 | 12 | .aligner { 13 | display: flex; 14 | align-items: center; 15 | justify-content: center; 16 | } 17 | 18 | .title-container { 19 | height: 50px; 20 | } 21 | 22 | .title-styles { 23 | font-family: 'Raleway', sans-serif; 24 | font-size: 250%; 25 | } 26 | 27 | .header-icon { 28 | height: 150px; 29 | width: 150px; 30 | } 31 | 32 | header { 33 | position: relative; 34 | height: 520px; 35 | min-height: 450px; 36 | width: 100%; 37 | background-size: cover; 38 | -webkit-background-size: cover; 39 | text-align: center; 40 | overflow: hidden; 41 | background-color: #e9d5a1; 42 | -webkit-background-size: cover; 43 | -moz-background-size: cover; 44 | -o-background-size: cover; 45 | background-size: cover; 46 | padding-top: 150px; 47 | padding-bottom: 0; 48 | } 49 | 50 | .language-icon { 51 | font-size: 50px; 52 | cursor: pointer; 53 | } 54 | 55 | .project-date { 56 | font-size: 16px; 57 | font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; 58 | padding: 8px 15px 2px 15px; 59 | position: relative; 60 | z-index: -500; 61 | border-top: 5px solid #696969; 62 | border-radius: 0 0 5px 5px; 63 | background-color: #696969; 64 | color: white; 65 | } 66 | 67 | .skills-tile { 68 | background-color: transparentize(#F8F5F4, 0.95); 69 | padding: 10px 10px 5px 10px; 70 | width: 100px; 71 | margin: 5px 0 5px 0; 72 | border-radius: 8px; 73 | } 74 | 75 | .language { 76 | font-size: 25px; 77 | background-color: #e9d5a1; 78 | padding-bottom: 10px; 79 | padding-top: 80px; 80 | } 81 | 82 | header h1 { 83 | font-size: 400%; 84 | text-align: center; 85 | font-weight: 600 !important; 86 | color: #353239; 87 | font-family: 'Franklin Gothic Medium', 'Arial Narrow', Arial, sans-serif; 88 | margin: 0 auto 18px auto; 89 | width: 100%; 90 | } 91 | 92 | .slider-image { 93 | border: 5px solid #D7CAAA; 94 | } 95 | 96 | .slider-tab { 97 | background-color: #D7CAAA; 98 | height: 25px; 99 | } 100 | 101 | .slider-iconfiy { 102 | margin-top: 10px; 103 | } 104 | 105 | .styles_typicalWrapper__1_Uvh::after { 106 | cursor: none !important; 107 | display: none; 108 | } 109 | 110 | #about { 111 | background: #fff; 112 | overflow: hidden; 113 | } 114 | 115 | #about h1 { 116 | padding-top: 5%; 117 | font: 18px/24px 'opensans-bold', sans-serif; 118 | text-transform: uppercase; 119 | letter-spacing: 3px; 120 | color: black; 121 | text-align: center; 122 | } 123 | 124 | .foto img { 125 | display: block; 126 | width: 100%; 127 | } 128 | 129 | .foto div { 130 | background: #ffffff; 131 | display: inline-block; 132 | margin: 0 auto 5% auto; 133 | padding: 10px 10px 5px; 134 | text-align: center; 135 | text-decoration: none; 136 | -webkit-box-shadow: 0 4px 6px rgba(0, 0, 0, .3); 137 | -moz-box-shadow: 0 4px 6px rgba(0, 0, 0, .3); 138 | box-shadow: 0 4px 6px rgba(0, 0, 0, .3); 139 | -webkit-transition: all .20s linear; 140 | -moz-transition: all .20s linear; 141 | transition: all .20s linear; 142 | z-index: 0; 143 | position: relative; 144 | } 145 | 146 | .foto div:after { 147 | color: #333; 148 | font-size: 25px; 149 | content: attr(title); 150 | position: relative; 151 | top: 15px; 152 | } 153 | 154 | .foto div:hover { 155 | -webkit-transform: scale(1.01); 156 | -moz-transform: scale(1.01); 157 | transform: scale(1.01); 158 | z-index: 10; 159 | -webkit-box-shadow: 0 10px 20px rgba(0, 0, 0, .7); 160 | -moz-box-shadow: 0 10px 20px rgba(0, 0, 0, .7); 161 | box-shadow: 0 10px 20px rgba(0, 0, 0, .7); 162 | } 163 | 164 | .project-title-settings { 165 | margin-top: 5%; 166 | font: 18px/24px 'opensans-bold', sans-serif; 167 | text-transform: uppercase; 168 | letter-spacing: 3px; 169 | color: black; 170 | text-align: center; 171 | } 172 | 173 | .polaroid img { 174 | display: block; 175 | max-width: 200px; 176 | } 177 | 178 | .polaroid span { 179 | background: #ffffff; 180 | display: inline-block; 181 | margin: 55px 75px 30px; 182 | padding: 15px 15px 30px; 183 | text-align: center; 184 | text-decoration: none; 185 | -webkit-box-shadow: 0 4px 6px rgba(0, 0, 0, .3); 186 | -moz-box-shadow: 0 4px 6px rgba(0, 0, 0, .3); 187 | box-shadow: 0 4px 6px rgba(0, 0, 0, .3); 188 | -webkit-transition: all .20s linear; 189 | -moz-transition: all .20s linear; 190 | transition: all .20s linear; 191 | z-index: 0; 192 | position: relative; 193 | } 194 | 195 | .link-href { 196 | color: black; 197 | } 198 | 199 | .wave { 200 | font-size: 160%; 201 | } 202 | 203 | .font-trebuchet { 204 | font-family: 'Trebuchet MS', 'Lucida Sans Unicode', 'Lucida Grande', 'Lucida Sans', Arial, sans-serif; 205 | } 206 | 207 | #preview { 208 | width: 500px; 209 | background-color: #ebeaf5; 210 | padding: 15px; 211 | position: relative; 212 | margin-bottom: 15%; 213 | } 214 | 215 | .center { 216 | display: flex; 217 | justify-content: center; 218 | align-items: center; 219 | } 220 | 221 | #resume { 222 | background: #efe1bd; 223 | } 224 | 225 | .experience-icon { 226 | font-size: 300%; 227 | margin-top: 25%; 228 | text-align: center; 229 | } 230 | 231 | .main-badge { 232 | font-size: 13px !important; 233 | text-align: left !important; 234 | padding: 5px 8px 5px 8px !important; 235 | vertical-align: baseline; 236 | background-color: #AE944F !important; 237 | color: white; 238 | font-weight: lighter !important; 239 | font-family: Cambria, Cochin, Georgia, Times, 'Times New Roman', serif; 240 | } 241 | 242 | .experience-badge { 243 | font-size: 11px !important; 244 | text-align: left !important; 245 | padding: 5px 8px 5px 8px !important; 246 | vertical-align: baseline; 247 | background-color: #f9f5e9 !important; 248 | color: black; 249 | font-weight: lighter !important; 250 | font-family: Cambria, Cochin, Georgia, Times, 'Times New Roman', serif; 251 | } 252 | 253 | .vertical-timeline-element-date { 254 | padding: 0 !important; 255 | margin: 0 !important; 256 | } 257 | 258 | @media only screen and (max-width: 1170px) { 259 | .experience-icon { 260 | font-size: 170%; 261 | margin-top: 27%; 262 | text-align: center; 263 | } 264 | } 265 | 266 | .modal-inside .modal-content { 267 | background: white; 268 | } 269 | 270 | .bars { 271 | width: 95%; 272 | float: left; 273 | padding: 0; 274 | text-align: left; 275 | } 276 | 277 | .bars .skills { 278 | margin-top: 36px; 279 | list-style: none; 280 | } 281 | 282 | .bars li { 283 | position: relative; 284 | margin-bottom: 60px; 285 | background: #ccc; 286 | height: 42px; 287 | border-radius: 3px; 288 | } 289 | 290 | .bars li em { 291 | font: 15px 'opensans-bold', sans-serif; 292 | color: #313131; 293 | text-transform: uppercase; 294 | letter-spacing: 2px; 295 | font-weight: normal; 296 | position: relative; 297 | top: -36px; 298 | } 299 | 300 | .bar-expand { 301 | position: absolute; 302 | left: 0; 303 | top: 0; 304 | margin: 0; 305 | padding-right: 24px; 306 | background: #313131; 307 | display: inline-block; 308 | height: 42px; 309 | line-height: 42px; 310 | border-radius: 3px 0 0 3px; 311 | } 312 | 313 | .modal-close { 314 | text-align: right; 315 | padding: 10px 15px 10px 15px; 316 | cursor: pointer; 317 | } 318 | 319 | .close-icon { 320 | color: black; 321 | font-weight: lighter !important; 322 | } 323 | 324 | .modal-description { 325 | text-align: justify; 326 | padding: 5px 5px 0 5px; 327 | margin-bottom: 20px; 328 | font-size: 12px; 329 | } 330 | 331 | .awssld__next { 332 | outline: none !important; 333 | } 334 | 335 | .awssld__prev { 336 | outline: none !important; 337 | } 338 | 339 | .loader-bar-color { 340 | color: black !important; 341 | } 342 | 343 | #portfolio { 344 | background: #efe1bd; 345 | padding-bottom: 5%; 346 | } 347 | 348 | .portfolio-item { 349 | max-width: 100%; 350 | margin-bottom: 15px; 351 | text-align: center; 352 | } 353 | 354 | .portfolio .portfolio-item .portfolio-item-caption { 355 | -webkit-transition: all ease 0.5s; 356 | -moz-transition: all ease 0.5s; 357 | transition: all ease 0.5s; 358 | opacity: 0; 359 | background-color: rgba(51, 51, 51, 0.9); 360 | } 361 | 362 | .portfolio .portfolio-item .portfolio-item-caption:hover { 363 | opacity: 1; 364 | } 365 | 366 | .portfolio .portfolio-item .portfolio-item-caption .portfolio-item-caption-content { 367 | font-size: 1.5rem; 368 | } 369 | 370 | @media (min-width: 576px) { 371 | .portfolio .closeButtonResponsive { 372 | display: block; 373 | } 374 | .portfolio .portfolio-item { 375 | margin-bottom: 30px; 376 | } 377 | } 378 | 379 | #skills { 380 | background: #1F1F1F; 381 | min-height: 200px; 382 | width: 100%; 383 | overflow: hidden; 384 | padding-bottom: 10%; 385 | } 386 | 387 | .section-title { 388 | padding-top: 5%; 389 | padding-bottom: 5%; 390 | font: 18px/24px 'opensans-bold', sans-serif; 391 | text-transform: uppercase; 392 | letter-spacing: 3px; 393 | color: #fff; 394 | text-align: center; 395 | } 396 | 397 | .skill-icon { 398 | font-size: 180%; 399 | color: white; 400 | text-align: center; 401 | position: relative; 402 | } 403 | 404 | footer { 405 | background: #1F1F1F; 406 | min-height: 100px; 407 | width: 100%; 408 | overflow: hidden; 409 | font-size: 14px; 410 | color: white; 411 | position: relative; 412 | text-align: center; 413 | } 414 | 415 | footer a, 416 | footer a:visited { 417 | color: #fff; 418 | } 419 | 420 | footer a:hover, 421 | footer a:focus { 422 | color: #fff; 423 | } 424 | 425 | .social-links { 426 | margin-top: 50px; 427 | font-size: 22px; 428 | } -------------------------------------------------------------------------------- /src/App.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render } from '@testing-library/react'; 3 | import App from './App'; 4 | 5 | it('renders without crashing', () => { 6 | const div = document.createElement('div'); 7 | ReactDOM.render(, div); 8 | }); -------------------------------------------------------------------------------- /src/components/About.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from "react"; 2 | import { Icon } from "@iconify/react"; 3 | import angularIcon from "@iconify/icons-logos/angular-icon"; 4 | import reactIcon from "@iconify/icons-logos/react"; 5 | import vueIcon from "@iconify/icons-logos/vue"; 6 | 7 | class About extends Component { 8 | render() { 9 | if (this.props.sharedBasicInfo) { 10 | var profilepic = "images/" + this.props.sharedBasicInfo.image; 11 | } 12 | if (this.props.resumeBasicInfo) { 13 | var sectionName = this.props.resumeBasicInfo.section_name.about; 14 | var hello = this.props.resumeBasicInfo.description_header; 15 | var about = this.props.resumeBasicInfo.description; 16 | } 17 | 18 | return ( 19 |
20 |
21 |

22 | {sectionName} 23 |

24 |
25 |
26 |
27 | 28 | Avatar placeholder 33 | 37 | 41 | 45 | 46 |
47 |
48 | 49 |
50 |
51 |
52 |
53 | {" "} 58 |  {" "} 59 | {" "} 64 |  {" "} 65 | 70 |
71 |
79 |
80 | {hello} :) 81 |
82 |
83 | {about} 84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 | ); 92 | } 93 | } 94 | 95 | export default About; 96 | -------------------------------------------------------------------------------- /src/components/Experience.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from "react"; 2 | import { 3 | VerticalTimeline, 4 | VerticalTimelineElement, 5 | } from "react-vertical-timeline-component"; 6 | import "react-vertical-timeline-component/style.min.css"; 7 | import Badge from "react-bootstrap/Badge"; 8 | 9 | class Experience extends Component { 10 | render() { 11 | if (this.props.resumeExperience && this.props.resumeBasicInfo) { 12 | var sectionName = this.props.resumeBasicInfo.section_name.experience; 13 | var work = this.props.resumeExperience.map(function (work, i) { 14 | const technologies = work.technologies; 15 | const mainTechnologies = work.mainTech; 16 | 17 | var mainTech = mainTechnologies.map((technology, i) => { 18 | return ( 19 | 20 | {technology} 21 | 22 | ); 23 | }); 24 | var tech = technologies.map((technology, i) => { 25 | return ( 26 | 27 | {technology} 28 | 29 | ); 30 | }); 31 | return ( 32 | } 41 | key={i} 42 | > 43 |
44 | {mainTech} 45 |
46 | 47 |

51 | {work.title} 52 |

53 |

57 | {work.company} 58 |

59 |
{tech}
60 |
61 | ); 62 | }); 63 | } 64 | 65 | return ( 66 |
67 |
68 |
69 |

70 | 71 | {sectionName} 72 | 73 |

74 |
75 |
76 |
77 | 78 | {work} 79 | 87 | } 88 | /> 89 | 90 |
91 |
92 | ); 93 | } 94 | } 95 | 96 | export default Experience; 97 | -------------------------------------------------------------------------------- /src/components/Footer.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from "react"; 2 | 3 | class Footer extends Component { 4 | render() { 5 | if (this.props.sharedBasicInfo) { 6 | var networks = this.props.sharedBasicInfo.social.map(function (network) { 7 | return ( 8 | 9 | 10 | 11 | 12 | 13 | ); 14 | }); 15 | } 16 | 17 | return ( 18 | 34 | ); 35 | } 36 | } 37 | 38 | export default Footer; 39 | -------------------------------------------------------------------------------- /src/components/Header.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from "react"; 2 | import Typical from "react-typical"; 3 | import Switch from "react-switch"; 4 | 5 | class Header extends Component { 6 | titles = []; 7 | 8 | constructor() { 9 | super(); 10 | this.state = { checked: false }; 11 | this.onThemeSwitchChange = this.onThemeSwitchChange.bind(this); 12 | } 13 | 14 | onThemeSwitchChange(checked) { 15 | this.setState({ checked }); 16 | this.setTheme(); 17 | } 18 | 19 | setTheme() { 20 | var dataThemeAttribute = "data-theme"; 21 | var body = document.body; 22 | var newTheme = 23 | body.getAttribute(dataThemeAttribute) === "dark" ? "light" : "dark"; 24 | body.setAttribute(dataThemeAttribute, newTheme); 25 | } 26 | 27 | render() { 28 | if (this.props.sharedData) { 29 | var name = this.props.sharedData.name; 30 | this.titles = this.props.sharedData.titles.map(x => [ x.toUpperCase(), 1500 ] ).flat(); 31 | } 32 | 33 | const HeaderTitleTypeAnimation = React.memo( () => { 34 | return 35 | }, (props, prevProp) => true); 36 | 37 | return ( 38 |
39 |
40 |
41 |
42 | 43 |
44 |

45 | 46 |

47 |
48 | 49 |
50 | 72 | } 73 | checkedIcon={ 74 | 87 | } 88 | id="icon-switch" 89 | /> 90 |
91 |
92 |
93 |
94 | ); 95 | } 96 | } 97 | 98 | export default Header; 99 | -------------------------------------------------------------------------------- /src/components/ProjectDetailsModal.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from "react"; 2 | import { Modal } from "react-bootstrap"; 3 | import AwesomeSlider from "react-awesome-slider"; 4 | import AwesomeSliderStyles from "../scss/light-slider.scss"; 5 | import AwesomeSliderStyles2 from "../scss/dark-slider.scss"; 6 | import "react-awesome-slider/dist/custom-animations/scale-out-animation.css"; 7 | class ProjectDetailsModal extends Component { 8 | render() { 9 | if (this.props.data) { 10 | const technologies = this.props.data.technologies; 11 | const images = this.props.data.images; 12 | var title = this.props.data.title; 13 | var description = this.props.data.description; 14 | var url = this.props.data.url; 15 | if (this.props.data.technologies) { 16 | var tech = technologies.map((icons, i) => { 17 | return ( 18 |
  • 19 | 20 |
    21 | 22 |

    23 | {icons.name} 24 |

    25 |
    26 |
    27 |
    28 |
  • 29 | ); 30 | }); 31 | if (this.props.data.images) { 32 | var img = images.map((elem, i) => { 33 | return
    ; 34 | }); 35 | } 36 | } 37 | } 38 | return ( 39 | 46 | 47 | 48 | 49 |
    50 |
    51 |
    52 | {" "} 58 |  {" "} 59 | {" "} 64 |  {" "} 65 | 70 |
    71 | 76 | {img} 77 | 78 |
    79 |
    80 |

    81 | {title} 82 | {url ? ( 83 | 89 | 93 | 94 | ) : null} 95 |

    96 |

    {description}

    97 |
    98 |
      {tech}
    99 |
    100 |
    101 |
    102 |
    103 | ); 104 | } 105 | } 106 | 107 | export default ProjectDetailsModal; 108 | -------------------------------------------------------------------------------- /src/components/Projects.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from "react"; 2 | import ProjectDetailsModal from "./ProjectDetailsModal"; 3 | 4 | class Projects extends Component { 5 | constructor(props) { 6 | super(props); 7 | this.state = { 8 | deps: {}, 9 | detailsModalShow: false, 10 | }; 11 | } 12 | 13 | render() { 14 | let detailsModalShow = (data) => { 15 | this.setState({ detailsModalShow: true, deps: data }); 16 | }; 17 | 18 | let detailsModalClose = () => this.setState({ detailsModalShow: false }); 19 | if (this.props.resumeProjects && this.props.resumeBasicInfo) { 20 | var sectionName = this.props.resumeBasicInfo.section_name.projects; 21 | var projects = this.props.resumeProjects.map(function (projects) { 22 | return ( 23 |
    28 | 29 |
    detailsModalShow(projects)}> 30 |
    31 | projectImages 37 | {projects.startDate} 38 |
    39 |

    40 | {projects.title} 41 |

    42 |
    43 |
    44 |
    45 |
    46 | ); 47 | }); 48 | } 49 | 50 | return ( 51 |
    52 |
    53 |

    54 | {sectionName} 55 |

    56 |
    57 |
    {projects}
    58 |
    59 | 64 |
    65 |
    66 | ); 67 | } 68 | } 69 | 70 | export default Projects; 71 | -------------------------------------------------------------------------------- /src/components/Skills.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from "react"; 2 | 3 | class Skills extends Component { 4 | render() { 5 | if (this.props.sharedSkills && this.props.resumeBasicInfo) { 6 | var sectionName = this.props.resumeBasicInfo.section_name.skills; 7 | var skills = this.props.sharedSkills.icons.map(function (skills, i) { 8 | return ( 9 |
  • 10 | 11 |
    12 | 13 |

    17 | {skills.name} 18 |

    19 |
    20 |
    21 |
    22 |
  • 23 | ); 24 | }); 25 | } 26 | 27 | return ( 28 |
    29 |
    30 |
    31 |

    32 | {sectionName} 33 |

    34 |
    35 |
    36 |
      {skills}
    37 |
    38 |
    39 |
    40 | ); 41 | } 42 | } 43 | 44 | export default Skills; 45 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.scss'; 4 | import App from './App'; 5 | import * as serviceWorker from './serviceWorker'; 6 | import 'bootstrap/dist/css/bootstrap.min.css'; 7 | 8 | /* GLOBAL VARIABLES */ 9 | 10 | window.$primaryLanguage = 'en'; 11 | window.$secondaryLanguage = 'pl'; 12 | window.$primaryLanguageIconId = 'primary-lang-icon'; 13 | window.$secondaryLanguageIconId = 'secondary-lang-icon'; 14 | 15 | ReactDOM.render(, document.getElementById('root')); 16 | serviceWorker.register(); 17 | -------------------------------------------------------------------------------- /src/index.scss: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /src/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/scss/dark-slider.scss: -------------------------------------------------------------------------------- 1 | $root-element: 'awssld'; 2 | $cos45: 0.7071; 3 | $transition-bezier: cubic-bezier(0.5, 0.075, 0.25, 0.95); 4 | $slider-height-percentage: 60%; 5 | $slider-transition-duration: 575ms; 6 | $organic-arrow-color: #8C8C8C; 7 | $organic-arrow-thickness: 4px; 8 | $organic-arrow-height: 40px; 9 | $organic-arrow-border-radius: 0; 10 | $control-button-width: 10%; 11 | $control-button-height: 25%; 12 | $control-button-opacity: 0.5; 13 | $control-button-hover-opacity: 0.75; 14 | $control-button-background: transparent; 15 | $loader-bar-color: #656565; 16 | $loader-bar-height: 6px; 17 | $control-bullet-color: #8C8C8C; 18 | $control-bullet-active-color: #8C8C8C; 19 | $content-background-color: #8C8C8C; 20 | 21 | %fill-parent { 22 | display: block; 23 | position: absolute; 24 | width: 100%; 25 | height: 100%; 26 | top: 0; 27 | left: 0; 28 | } 29 | 30 | %clear-spacing { 31 | padding: 0; 32 | margin: 0; 33 | } 34 | 35 | %clear-focus { 36 | outline-color: 0; 37 | outline-style: none; 38 | outline-width: 0; 39 | } 40 | 41 | %clear-selection { 42 | user-select: none; 43 | -webkit-tap-highlight-color: rgba(0, 0, 0, 0); 44 | -webkit-tap-highlight-color: transparent; 45 | } 46 | 47 | .#{$root-element} { 48 | --organic-arrow-thickness: #{$organic-arrow-thickness}; 49 | --organic-arrow-height: #{$organic-arrow-height}; 50 | --slider-height-percentage: #{$slider-height-percentage}; 51 | --loader-bar-color: #{$loader-bar-color}; 52 | --loader-bar-height: #{$loader-bar-height}; 53 | --control-button-width: #{$control-button-width}; 54 | --control-button-height: #{$control-button-height}; 55 | --control-button-opacity: #{$control-button-opacity}; 56 | --control-button-hover-opacity: #{$control-button-hover-opacity}; 57 | --control-button-background: #{$control-button-background}; 58 | --transition-bezier: #{$transition-bezier}; 59 | --slider-transition-duration: #{$slider-transition-duration}; 60 | --organic-arrow-color: #{$organic-arrow-color}; 61 | --organic-arrow-border-radius: #{$organic-arrow-border-radius}; 62 | --control-bullet-color: #{$control-bullet-color}; 63 | --control-bullet-active-color: #{$control-bullet-active-color}; 64 | --content-background-color: #{$content-background-color}; 65 | } 66 | 67 | .#{$root-element} { 68 | display: block; 69 | position: relative; 70 | width: 100%; 71 | max-width: 100%; 72 | 73 | &__wrapper { 74 | display: block; 75 | overflow: hidden; 76 | position: relative; 77 | height: 100%; 78 | width: 100%; 79 | } 80 | &__container { 81 | display: block; 82 | width: 100%; 83 | height: 0; 84 | padding-bottom: var(--slider-height-percentage); 85 | 86 | @media all and (max-width: 500px) { 87 | padding-bottom: calc(var(--slider-height-percentage) * 1.25); 88 | } 89 | 90 | figure { 91 | @extend %fill-parent; 92 | } 93 | } 94 | &__startUp { 95 | background-color: red; 96 | height: 100%; 97 | width: 100%; 98 | 99 | > div { 100 | height: 100%; 101 | width: 100%; 102 | display: flex; 103 | align-items: center; 104 | justify-content: center; 105 | } 106 | 107 | img { 108 | width: 35%; 109 | height: auto; 110 | } 111 | } 112 | &__content { 113 | @extend %fill-parent; 114 | background-color: var(--content-background-color); 115 | overflow: hidden; 116 | display: flex; 117 | align-items: center; 118 | justify-content: center; 119 | > img, 120 | > video { 121 | height: 100%; 122 | top: 0; 123 | left: 0; 124 | } 125 | } 126 | &__controls { 127 | button { 128 | @extend %clear-focus; 129 | display: flex; 130 | align-items: center; 131 | justify-content: center; 132 | width: var(--control-button-width); 133 | height: var(--control-button-height); 134 | position: absolute; 135 | z-index: 10; 136 | top: calc(50% - (0.5 * var(--control-button-height))); 137 | border: none; 138 | background-color: var(--control-button-background); 139 | color: #fff; 140 | cursor: pointer; 141 | .#{$root-element}__controls__arrow-left, 142 | .#{$root-element}__controls__arrow-right { 143 | opacity: var(--control-button-opacity); 144 | } 145 | &:hover { 146 | .#{$root-element}__controls__arrow-left, 147 | .#{$root-element}__controls__arrow-right { 148 | opacity: var(--control-button-opacity-hover); 149 | } 150 | } 151 | } 152 | &--active { 153 | .#{$root-element}__controls__arrow-left { 154 | opacity: var(--control-button-opacity-hover); 155 | transform: translate3d(-100%, 0, 0); 156 | } 157 | .#{$root-element}__controls__arrow-right { 158 | opacity: var(--control-button-opacity-hover); 159 | transform: translate3d(100%, 0, 0); 160 | } 161 | } 162 | &--hidden { 163 | display: none; 164 | } 165 | @media all and (max-width: 520px) { 166 | visibility: hidden; 167 | } 168 | } 169 | &__bar { 170 | display: block; 171 | width: 100%; 172 | height: var(--loader-bar-height); 173 | background-color: var(--loader-bar-color); 174 | position: absolute; 175 | top: 0; 176 | left: 0; 177 | z-index: 101; 178 | transition: transform 3000ms var(--transition-bezier); 179 | transform: translate3d(-100%, 0, 0); 180 | &--active { 181 | transform: translate3d(-20%, 0, 0); 182 | } 183 | &--end { 184 | transition-duration: 300ms; 185 | transform: translate3d(0, 0, 0); 186 | } 187 | } 188 | &__next { 189 | right: 0; 190 | } 191 | &__prev { 192 | left: 0; 193 | } 194 | &__box { 195 | z-index: 1; 196 | visibility: hidden; 197 | @extend %fill-parent; 198 | } 199 | &--animated { 200 | will-change: transform; 201 | visibility: visible; 202 | } 203 | &--animated-mobile { 204 | will-change: transform; 205 | transition: transform 325ms cubic-bezier(0.15, 0.65, 0.1, 1); 206 | } 207 | &--active { 208 | visibility: visible; 209 | z-index: 2; 210 | transform: translate3d(0, 0, 0); 211 | } 212 | &--moveRight, 213 | &--moveLeft { 214 | backface-visibility: hidden; 215 | } 216 | &--moveRight { 217 | // transform: translate3d(100%, 0, 0); 218 | animation: slideFromRight var(--slider-transition-duration) both 219 | var(--transition-bezier); 220 | } 221 | &--moveLeft { 222 | animation: slideFromLeft var(--slider-transition-duration) both 223 | var(--transition-bezier); 224 | } 225 | &--exit { 226 | z-index: 0; 227 | &.#{$root-element}--moveLeft { 228 | animation: slideToLeft var(--slider-transition-duration) both 229 | var(--transition-bezier); 230 | } 231 | &.#{$root-element}--moveRight { 232 | animation: slideToRight var(--slider-transition-duration) both 233 | var(--transition-bezier); 234 | } 235 | } 236 | &--first { 237 | .#{$root-element}__prev { 238 | visibility: hidden; 239 | } 240 | } 241 | &--last { 242 | .#{$root-element}__next { 243 | visibility: hidden; 244 | } 245 | } 246 | &--fill-parent { 247 | position: absolute !important; 248 | width: 100% !important; 249 | height: 100% !important; 250 | top: 0; 251 | left: 0; 252 | 253 | .#{$root-element}__container { 254 | height: 100%; 255 | padding: 0; 256 | } 257 | } 258 | &__bullets { 259 | position: absolute; 260 | bottom: -40px; 261 | width: 100%; 262 | display: flex; 263 | align-items: center; 264 | justify-content: center; 265 | button { 266 | @extend %clear-focus; 267 | padding: 0; 268 | display: block; 269 | width: 16px; 270 | height: 16px; 271 | margin: 5px; 272 | border-radius: 50%; 273 | background: var(--control-bullet-color); 274 | text-indent: -9999px; 275 | overflow: hidden; 276 | cursor: pointer; 277 | border: none; 278 | transition: transform 0.225s cubic-bezier(0.8, 1.35, 0.75, 1.45), 279 | background-color 0.175s ease-out; 280 | 281 | &:hover { 282 | transform: scale(1.2); 283 | } 284 | } 285 | .#{$root-element}__bullets--loading { 286 | transform: scale(1.2); 287 | } 288 | .#{$root-element}__bullets--active { 289 | transform: scale(1.5); 290 | background: var(--control-bullet-active-color); 291 | 292 | &:hover { 293 | transform: scale(1.5); 294 | } 295 | } 296 | } 297 | 298 | &__controls__arrow-left, 299 | &__controls__arrow-right { 300 | width: 100%; 301 | height: var(--organic-arrow-height); 302 | position: relative; 303 | display: block; 304 | transition: transform 0.2s ease-out 0.125s, opacity 0.2s ease-out; 305 | &:before, 306 | &:after { 307 | content: ' '; 308 | position: absolute; 309 | right: calc( 310 | 50% - 311 | ( 312 | #{$cos45} * (var(--organic-arrow-height) + 313 | var(--organic-arrow-thickness)) 314 | ) / 2 315 | ); 316 | height: 100%; 317 | border-radius: var(--organic-arrow-border-radius); 318 | width: var(--organic-arrow-thickness); 319 | background-color: var(--organic-arrow-color); 320 | transition: transform 0.15s ease-out, background-color 0.15s ease-out; 321 | } 322 | &:before { 323 | transform-origin: 100% 100% 0; 324 | // background-color: rgba(76, 177, 6, 0.75); 325 | top: -50%; 326 | transform: rotate(-45deg); 327 | } 328 | &:after { 329 | transform-origin: 100% 0% 0; 330 | // background-color: rgba(255, 247, 43, 0.75); 331 | top: 50%; 332 | transform: rotate(45deg); 333 | } 334 | } 335 | &__controls__arrow-right { 336 | &--active { 337 | transform: translate3d(100%, 0, 0); 338 | &:after { 339 | transform: rotate(90deg) translate3d(50%, 0, 0) !important; 340 | } 341 | &:before { 342 | transform: rotate(-90deg) translate3d(50%, 0, 0) !important; 343 | } 344 | } 345 | } 346 | &__controls__arrow-left { 347 | &:before, 348 | &:after { 349 | right: auto; 350 | left: calc( 351 | 50% - 352 | ( 353 | #{$cos45} * (var(--organic-arrow-height) + 354 | var(--organic-arrow-thickness)) 355 | ) / 2 356 | ); 357 | } 358 | &:before { 359 | transform-origin: 0 100% 0; 360 | top: -50%; 361 | transform: rotate(45deg); 362 | } 363 | &:after { 364 | transform-origin: 0 0 0; 365 | top: 50%; 366 | transform: rotate(-45deg); 367 | } 368 | &--active { 369 | transform: translate3d(-100%, 0, 0); 370 | &:after { 371 | transform: rotate(-90deg) translate3d(-50%, 0, 0) !important; 372 | } 373 | &:before { 374 | transform: rotate(90deg) translate3d(-50%, 0, 0) !important; 375 | } 376 | } 377 | } 378 | &__controls { 379 | button:hover { 380 | .#{$root-element}__controls__arrow-left { 381 | &:before { 382 | opacity: 1; 383 | transform: rotate(30deg); 384 | } 385 | 386 | &:after { 387 | opacity: 1; 388 | transform: rotate(-30deg); 389 | } 390 | } 391 | .#{$root-element}__controls__arrow-right { 392 | &:before { 393 | opacity: 1; 394 | transform: rotate(-30deg); 395 | } 396 | &:after { 397 | opacity: 1; 398 | transform: rotate(30deg); 399 | } 400 | } 401 | } 402 | } 403 | &__timer { 404 | --timer-delay: 2000ms; 405 | --timer-release: 200ms; 406 | --timer-height: 4px; 407 | --timer-background-color: rgba(0, 0, 0, 0.15); 408 | 409 | width: 100%; 410 | height: var(--timer-height); 411 | background-color: var(--timer-background-color); 412 | position: absolute; 413 | top: 0; 414 | left: 0; 415 | z-index: 100; 416 | transform: translateX(-100%); 417 | 418 | &--animated { 419 | will-change: transform; 420 | transition: transform var(--timer-delay) linear; 421 | } 422 | 423 | &--run { 424 | transform: translateX(0); 425 | } 426 | 427 | &--fast { 428 | transition: transform calc(var(--timer-release) / 2) linear; 429 | transform: translateX(-0.00001px); 430 | } 431 | 432 | &--end { 433 | transform: translateX(-0.0001px); 434 | transition: transform var(--timer-release) linear; 435 | } 436 | 437 | &--hidden { 438 | display: none; 439 | } 440 | } 441 | } 442 | 443 | @keyframes slideFromLeft { 444 | from { 445 | transform: translate3d(-100%, 0, 0); 446 | } 447 | to { 448 | transform: translate3d(0, 0, 0); 449 | } 450 | } 451 | 452 | @keyframes slideFromRight { 453 | from { 454 | transform: translate3d(100%, 0, 0); 455 | } 456 | to { 457 | transform: translate3d(0, 0, 0); 458 | } 459 | } 460 | 461 | @keyframes slideToLeft { 462 | from { 463 | transform: translate3d(0, 0, 0); 464 | } 465 | to { 466 | transform: translate3d(-100%, 0, 0); 467 | } 468 | } 469 | 470 | @keyframes slideToRight { 471 | from { 472 | transform: translate3d(0, 0, 0); 473 | } 474 | to { 475 | transform: translate3d(100%, 0, 0); 476 | } 477 | } -------------------------------------------------------------------------------- /src/scss/light-slider.scss: -------------------------------------------------------------------------------- 1 | $root-element: 'awssld'; 2 | $cos45: 0.7071; 3 | $transition-bezier: cubic-bezier(0.5, 0.075, 0.25, 0.95); 4 | $slider-height-percentage: 60%; 5 | $slider-transition-duration: 575ms; 6 | $organic-arrow-color: #D7CAAA; 7 | $organic-arrow-thickness: 4px; 8 | $organic-arrow-height: 40px; 9 | $organic-arrow-border-radius: 0; 10 | $control-button-width: 10%; 11 | $control-button-height: 25%; 12 | $control-button-opacity: 0.5; 13 | $control-button-hover-opacity: 0.75; 14 | $control-button-background: transparent; 15 | $loader-bar-color:#BFAA76; 16 | $loader-bar-height: 6px; 17 | $control-bullet-color: #D7CAAA; 18 | $control-bullet-active-color: #D7CAAA; 19 | $content-background-color: #D7CAAA; 20 | 21 | %fill-parent { 22 | display: block; 23 | position: absolute; 24 | width: 100%; 25 | height: 100%; 26 | top: 0; 27 | left: 0; 28 | } 29 | 30 | %clear-spacing { 31 | padding: 0; 32 | margin: 0; 33 | } 34 | 35 | %clear-focus { 36 | outline-color: 0; 37 | outline-style: none; 38 | outline-width: 0; 39 | } 40 | 41 | %clear-selection { 42 | user-select: none; 43 | -webkit-tap-highlight-color: rgba(0, 0, 0, 0); 44 | -webkit-tap-highlight-color: transparent; 45 | } 46 | 47 | .#{$root-element} { 48 | --organic-arrow-thickness: #{$organic-arrow-thickness}; 49 | --organic-arrow-height: #{$organic-arrow-height}; 50 | --slider-height-percentage: #{$slider-height-percentage}; 51 | --loader-bar-color: #{$loader-bar-color}; 52 | --loader-bar-height: #{$loader-bar-height}; 53 | --control-button-width: #{$control-button-width}; 54 | --control-button-height: #{$control-button-height}; 55 | --control-button-opacity: #{$control-button-opacity}; 56 | --control-button-hover-opacity: #{$control-button-hover-opacity}; 57 | --control-button-background: #{$control-button-background}; 58 | --transition-bezier: #{$transition-bezier}; 59 | --slider-transition-duration: #{$slider-transition-duration}; 60 | --organic-arrow-color: #{$organic-arrow-color}; 61 | --organic-arrow-border-radius: #{$organic-arrow-border-radius}; 62 | --control-bullet-color: #{$control-bullet-color}; 63 | --control-bullet-active-color: #{$control-bullet-active-color}; 64 | --content-background-color: #{$content-background-color}; 65 | } 66 | 67 | .#{$root-element} { 68 | display: block; 69 | position: relative; 70 | width: 100%; 71 | max-width: 100%; 72 | 73 | &__wrapper { 74 | display: block; 75 | overflow: hidden; 76 | position: relative; 77 | height: 100%; 78 | width: 100%; 79 | } 80 | &__container { 81 | display: block; 82 | width: 100%; 83 | height: 0; 84 | padding-bottom: var(--slider-height-percentage); 85 | 86 | @media all and (max-width: 500px) { 87 | padding-bottom: calc(var(--slider-height-percentage) * 1.25); 88 | } 89 | 90 | figure { 91 | @extend %fill-parent; 92 | } 93 | } 94 | &__startUp { 95 | background-color: red; 96 | height: 100%; 97 | width: 100%; 98 | 99 | > div { 100 | height: 100%; 101 | width: 100%; 102 | display: flex; 103 | align-items: center; 104 | justify-content: center; 105 | } 106 | 107 | img { 108 | width: 35%; 109 | height: auto; 110 | } 111 | } 112 | &__content { 113 | @extend %fill-parent; 114 | background-color: var(--content-background-color); 115 | overflow: hidden; 116 | display: flex; 117 | align-items: center; 118 | justify-content: center; 119 | > img, 120 | > video { 121 | width: 100%; 122 | position: absolute; 123 | top: 0; 124 | left: 0; 125 | } 126 | } 127 | &__controls { 128 | button { 129 | @extend %clear-focus; 130 | display: flex; 131 | align-items: center; 132 | justify-content: center; 133 | width: var(--control-button-width); 134 | height: var(--control-button-height); 135 | position: absolute; 136 | z-index: 10; 137 | top: calc(50% - (0.5 * var(--control-button-height))); 138 | border: none; 139 | background-color: var(--control-button-background); 140 | color: #fff; 141 | cursor: pointer; 142 | .#{$root-element}__controls__arrow-left, 143 | .#{$root-element}__controls__arrow-right { 144 | opacity: var(--control-button-opacity); 145 | } 146 | &:hover { 147 | .#{$root-element}__controls__arrow-left, 148 | .#{$root-element}__controls__arrow-right { 149 | opacity: var(--control-button-opacity-hover); 150 | } 151 | } 152 | } 153 | &--active { 154 | .#{$root-element}__controls__arrow-left { 155 | opacity: var(--control-button-opacity-hover); 156 | transform: translate3d(-100%, 0, 0); 157 | } 158 | .#{$root-element}__controls__arrow-right { 159 | opacity: var(--control-button-opacity-hover); 160 | transform: translate3d(100%, 0, 0); 161 | } 162 | } 163 | &--hidden { 164 | display: none; 165 | } 166 | @media all and (max-width: 520px) { 167 | visibility: hidden; 168 | } 169 | } 170 | &__bar { 171 | display: block; 172 | width: 100%; 173 | height: var(--loader-bar-height); 174 | background-color: var(--loader-bar-color); 175 | position: absolute; 176 | top: 0; 177 | left: 0; 178 | z-index: 101; 179 | transition: transform 3000ms var(--transition-bezier); 180 | transform: translate3d(-100%, 0, 0); 181 | &--active { 182 | transform: translate3d(-20%, 0, 0); 183 | } 184 | &--end { 185 | transition-duration: 300ms; 186 | transform: translate3d(0, 0, 0); 187 | } 188 | } 189 | &__next { 190 | right: 0; 191 | } 192 | &__prev { 193 | left: 0; 194 | } 195 | &__box { 196 | z-index: 1; 197 | visibility: hidden; 198 | @extend %fill-parent; 199 | } 200 | &--animated { 201 | will-change: transform; 202 | visibility: visible; 203 | } 204 | &--animated-mobile { 205 | will-change: transform; 206 | transition: transform 325ms cubic-bezier(0.15, 0.65, 0.1, 1); 207 | } 208 | &--active { 209 | visibility: visible; 210 | z-index: 2; 211 | transform: translate3d(0, 0, 0); 212 | } 213 | &--moveRight, 214 | &--moveLeft { 215 | backface-visibility: hidden; 216 | } 217 | &--moveRight { 218 | // transform: translate3d(100%, 0, 0); 219 | animation: slideFromRight var(--slider-transition-duration) both 220 | var(--transition-bezier); 221 | } 222 | &--moveLeft { 223 | animation: slideFromLeft var(--slider-transition-duration) both 224 | var(--transition-bezier); 225 | } 226 | &--exit { 227 | z-index: 0; 228 | &.#{$root-element}--moveLeft { 229 | animation: slideToLeft var(--slider-transition-duration) both 230 | var(--transition-bezier); 231 | } 232 | &.#{$root-element}--moveRight { 233 | animation: slideToRight var(--slider-transition-duration) both 234 | var(--transition-bezier); 235 | } 236 | } 237 | &--first { 238 | .#{$root-element}__prev { 239 | visibility: hidden; 240 | } 241 | } 242 | &--last { 243 | .#{$root-element}__next { 244 | visibility: hidden; 245 | } 246 | } 247 | &--fill-parent { 248 | position: absolute !important; 249 | width: 100% !important; 250 | height: 100% !important; 251 | top: 0; 252 | left: 0; 253 | 254 | .#{$root-element}__container { 255 | height: 100%; 256 | padding: 0; 257 | } 258 | } 259 | &__bullets { 260 | position: absolute; 261 | bottom: -40px; 262 | width: 100%; 263 | display: flex; 264 | align-items: center; 265 | justify-content: center; 266 | button { 267 | @extend %clear-focus; 268 | padding: 0; 269 | display: block; 270 | width: 16px; 271 | height: 16px; 272 | margin: 5px; 273 | border-radius: 50%; 274 | background: var(--control-bullet-color); 275 | text-indent: -9999px; 276 | overflow: hidden; 277 | cursor: pointer; 278 | border: none; 279 | transition: transform 0.225s cubic-bezier(0.8, 1.35, 0.75, 1.45), 280 | background-color 0.175s ease-out; 281 | 282 | &:hover { 283 | transform: scale(1.2); 284 | } 285 | } 286 | .#{$root-element}__bullets--loading { 287 | transform: scale(1.2); 288 | } 289 | .#{$root-element}__bullets--active { 290 | transform: scale(1.5); 291 | background: var(--control-bullet-active-color); 292 | 293 | &:hover { 294 | transform: scale(1.5); 295 | } 296 | } 297 | } 298 | 299 | &__controls__arrow-left, 300 | &__controls__arrow-right { 301 | width: 100%; 302 | height: var(--organic-arrow-height); 303 | position: relative; 304 | display: block; 305 | transition: transform 0.2s ease-out 0.125s, opacity 0.2s ease-out; 306 | &:before, 307 | &:after { 308 | content: ' '; 309 | position: absolute; 310 | right: calc( 311 | 50% - 312 | ( 313 | #{$cos45} * (var(--organic-arrow-height) + 314 | var(--organic-arrow-thickness)) 315 | ) / 2 316 | ); 317 | height: 100%; 318 | border-radius: var(--organic-arrow-border-radius); 319 | width: var(--organic-arrow-thickness); 320 | background-color: var(--organic-arrow-color); 321 | transition: transform 0.15s ease-out, background-color 0.15s ease-out; 322 | } 323 | &:before { 324 | transform-origin: 100% 100% 0; 325 | // background-color: rgba(76, 177, 6, 0.75); 326 | top: -50%; 327 | transform: rotate(-45deg); 328 | } 329 | &:after { 330 | transform-origin: 100% 0% 0; 331 | // background-color: rgba(255, 247, 43, 0.75); 332 | top: 50%; 333 | transform: rotate(45deg); 334 | } 335 | } 336 | &__controls__arrow-right { 337 | &--active { 338 | transform: translate3d(100%, 0, 0); 339 | &:after { 340 | transform: rotate(90deg) translate3d(50%, 0, 0) !important; 341 | } 342 | &:before { 343 | transform: rotate(-90deg) translate3d(50%, 0, 0) !important; 344 | } 345 | } 346 | } 347 | &__controls__arrow-left { 348 | &:before, 349 | &:after { 350 | right: auto; 351 | left: calc( 352 | 50% - 353 | ( 354 | #{$cos45} * (var(--organic-arrow-height) + 355 | var(--organic-arrow-thickness)) 356 | ) / 2 357 | ); 358 | } 359 | &:before { 360 | transform-origin: 0 100% 0; 361 | top: -50%; 362 | transform: rotate(45deg); 363 | } 364 | &:after { 365 | transform-origin: 0 0 0; 366 | top: 50%; 367 | transform: rotate(-45deg); 368 | } 369 | &--active { 370 | transform: translate3d(-100%, 0, 0); 371 | &:after { 372 | transform: rotate(-90deg) translate3d(-50%, 0, 0) !important; 373 | } 374 | &:before { 375 | transform: rotate(90deg) translate3d(-50%, 0, 0) !important; 376 | } 377 | } 378 | } 379 | &__controls { 380 | button:hover { 381 | .#{$root-element}__controls__arrow-left { 382 | &:before { 383 | opacity: 1; 384 | transform: rotate(30deg); 385 | } 386 | 387 | &:after { 388 | opacity: 1; 389 | transform: rotate(-30deg); 390 | } 391 | } 392 | .#{$root-element}__controls__arrow-right { 393 | &:before { 394 | opacity: 1; 395 | transform: rotate(-30deg); 396 | } 397 | &:after { 398 | opacity: 1; 399 | transform: rotate(30deg); 400 | } 401 | } 402 | } 403 | } 404 | &__timer { 405 | --timer-delay: 2000ms; 406 | --timer-release: 200ms; 407 | --timer-height: 4px; 408 | --timer-background-color: rgba(0, 0, 0, 0.15); 409 | 410 | width: 100%; 411 | height: var(--timer-height); 412 | background-color: var(--timer-background-color); 413 | position: absolute; 414 | top: 0; 415 | left: 0; 416 | z-index: 100; 417 | transform: translateX(-100%); 418 | 419 | &--animated { 420 | will-change: transform; 421 | transition: transform var(--timer-delay) linear; 422 | } 423 | 424 | &--run { 425 | transform: translateX(0); 426 | } 427 | 428 | &--fast { 429 | transition: transform calc(var(--timer-release) / 2) linear; 430 | transform: translateX(-0.00001px); 431 | } 432 | 433 | &--end { 434 | transform: translateX(-0.0001px); 435 | transition: transform var(--timer-release) linear; 436 | } 437 | 438 | &--hidden { 439 | display: none; 440 | } 441 | } 442 | } 443 | 444 | @keyframes slideFromLeft { 445 | from { 446 | transform: translate3d(-100%, 0, 0); 447 | } 448 | to { 449 | transform: translate3d(0, 0, 0); 450 | } 451 | } 452 | 453 | @keyframes slideFromRight { 454 | from { 455 | transform: translate3d(100%, 0, 0); 456 | } 457 | to { 458 | transform: translate3d(0, 0, 0); 459 | } 460 | } 461 | 462 | @keyframes slideToLeft { 463 | from { 464 | transform: translate3d(0, 0, 0); 465 | } 466 | to { 467 | transform: translate3d(-100%, 0, 0); 468 | } 469 | } 470 | 471 | @keyframes slideToRight { 472 | from { 473 | transform: translate3d(0, 0, 0); 474 | } 475 | to { 476 | transform: translate3d(100%, 0, 0); 477 | } 478 | } -------------------------------------------------------------------------------- /src/scss/themes/theme-dark.scss: -------------------------------------------------------------------------------- 1 | body[data-theme="dark"] { 2 | 3 | @import '../src/scss/dark-slider.scss'; 4 | 5 | .slider-tab { 6 | background-color: #8C8C8C; 7 | } 8 | 9 | .title-styles { 10 | color: white; 11 | } 12 | 13 | .header-icon { 14 | color: #3C342C; 15 | opacity: 0.8; 16 | } 17 | 18 | .slider-image { 19 | border: 5px solid #8C8C8C; 20 | } 21 | 22 | .language { 23 | background-color: #494949; 24 | } 25 | 26 | .link-href { 27 | color: white; 28 | } 29 | 30 | .project-date { 31 | background-color: #918e97; 32 | color: white; 33 | } 34 | 35 | header { 36 | background-color: #494949; 37 | h1 { 38 | color: white; 39 | } 40 | } 41 | 42 | #about { 43 | background-color: #7f7f7f; 44 | h1 span { 45 | color: white; 46 | } 47 | .polaroid span { 48 | background: #6d6d6d; 49 | } 50 | .card { 51 | background: #6d6d6d; 52 | color: white; 53 | } 54 | } 55 | 56 | #portfolio { 57 | background: #5b5b5b; 58 | .section-title { 59 | color: white !important; 60 | } 61 | .foto div { 62 | background: #6d6d6d; 63 | } 64 | .project-title-settings { 65 | color: white; 66 | } 67 | } 68 | 69 | #resume { 70 | filter: brightness(80%); 71 | background: #5b5b5b; 72 | .section-title { 73 | color: white !important; 74 | } 75 | 76 | .experience-badge { 77 | background: #919191 !important; 78 | color: white; 79 | } 80 | 81 | .main-badge { 82 | background: #919191 !important; 83 | } 84 | 85 | .vertical-timeline-element-date { 86 | color: white; 87 | } 88 | 89 | .vertical-timeline-element-icon { 90 | background: #919191 !important; 91 | } 92 | @media only screen and (max-width: 1169px) { 93 | .vertical-timeline-element-date { 94 | color: black; 95 | } 96 | } 97 | } 98 | 99 | .modal-inside .modal-content { 100 | background: #5b5b5b; 101 | color: white; 102 | } 103 | 104 | .close-icon { 105 | color: white; 106 | } 107 | } -------------------------------------------------------------------------------- /src/scss/themes/theme-light.scss: -------------------------------------------------------------------------------- 1 | body[data-theme="light"] { 2 | @import '../src/scss/light-slider.scss'; 3 | 4 | .slider-tab { 5 | background-color: #D7CAAA; 6 | } 7 | } -------------------------------------------------------------------------------- /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 | --------------------------------------------------------------------------------