diff --git a/package-lock.json b/package-lock.json index fe87c1d..8e7578f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,12 +8,21 @@ "name": "my-portfolio", "version": "0.1.0", "dependencies": { + "@emailjs/browser": "^3.12.1", + "@emotion/react": "^11.11.3", + "@emotion/styled": "^11.11.0", + "@fontsource/roboto": "^5.0.8", + "@mui/icons-material": "^5.15.4", + "@mui/material": "^5.15.4", "@testing-library/jest-dom": "^5.17.0", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-icons": "^5.0.1", + "react-router-dom": "^6.21.2", "react-scripts": "5.0.1", + "react-toastify": "^10.0.2", "web-vitals": "^2.1.4" } }, @@ -2283,6 +2292,171 @@ "postcss-selector-parser": "^6.0.10" } }, + "node_modules/@emailjs/browser": { + "version": "3.12.1", + "resolved": "https://registry.npmjs.org/@emailjs/browser/-/browser-3.12.1.tgz", + "integrity": "sha512-C5nK07CgSCFx3onsuRt/ZaaMvIi0T3SHHanM7fKozjSvbZu+OjHHP9W608fYpic0OavF7yIlfy4+lRDO33JdbA==", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@emotion/babel-plugin": { + "version": "11.11.0", + "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.11.0.tgz", + "integrity": "sha512-m4HEDZleaaCH+XgDDsPF15Ht6wTLsgDTeR3WYj9Q/k76JtWhrJjcP4+/XlG8LGT/Rol9qUfOIztXeA84ATpqPQ==", + "dependencies": { + "@babel/helper-module-imports": "^7.16.7", + "@babel/runtime": "^7.18.3", + "@emotion/hash": "^0.9.1", + "@emotion/memoize": "^0.8.1", + "@emotion/serialize": "^1.1.2", + "babel-plugin-macros": "^3.1.0", + "convert-source-map": "^1.5.0", + "escape-string-regexp": "^4.0.0", + "find-root": "^1.1.0", + "source-map": "^0.5.7", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/babel-plugin/node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" + }, + "node_modules/@emotion/babel-plugin/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@emotion/babel-plugin/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@emotion/cache": { + "version": "11.11.0", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.11.0.tgz", + "integrity": "sha512-P34z9ssTCBi3e9EI1ZsWpNHcfY1r09ZO0rZbRO2ob3ZQMnFI35jB536qoXbkdesr5EUhYi22anuEJuyxifaqAQ==", + "dependencies": { + "@emotion/memoize": "^0.8.1", + "@emotion/sheet": "^1.2.2", + "@emotion/utils": "^1.2.1", + "@emotion/weak-memoize": "^0.3.1", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/hash": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.1.tgz", + "integrity": "sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ==" + }, + "node_modules/@emotion/is-prop-valid": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.1.tgz", + "integrity": "sha512-61Mf7Ufx4aDxx1xlDeOm8aFFigGHE4z+0sKCa+IHCeZKiyP9RLD0Mmx7m8b9/Cf37f7NAvQOOJAbQQGVr5uERw==", + "dependencies": { + "@emotion/memoize": "^0.8.1" + } + }, + "node_modules/@emotion/memoize": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.1.tgz", + "integrity": "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==" + }, + "node_modules/@emotion/react": { + "version": "11.11.3", + "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.11.3.tgz", + "integrity": "sha512-Cnn0kuq4DoONOMcnoVsTOR8E+AdnKFf//6kUWc4LCdnxj31pZWn7rIULd6Y7/Js1PiPHzn7SKCM9vB/jBni8eA==", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.11.0", + "@emotion/cache": "^11.11.0", + "@emotion/serialize": "^1.1.3", + "@emotion/use-insertion-effect-with-fallbacks": "^1.0.1", + "@emotion/utils": "^1.2.1", + "@emotion/weak-memoize": "^0.3.1", + "hoist-non-react-statics": "^3.3.1" + }, + "peerDependencies": { + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/serialize": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.1.3.tgz", + "integrity": "sha512-iD4D6QVZFDhcbH0RAG1uVu1CwVLMWUkCvAqqlewO/rxf8+87yIBAlt4+AxMiiKPLs5hFc0owNk/sLLAOROw3cA==", + "dependencies": { + "@emotion/hash": "^0.9.1", + "@emotion/memoize": "^0.8.1", + "@emotion/unitless": "^0.8.1", + "@emotion/utils": "^1.2.1", + "csstype": "^3.0.2" + } + }, + "node_modules/@emotion/sheet": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.2.2.tgz", + "integrity": "sha512-0QBtGvaqtWi+nx6doRwDdBIzhNdZrXUppvTM4dtZZWEGTXL/XE/yJxLMGlDT1Gt+UHH5IX1n+jkXyytE/av7OA==" + }, + "node_modules/@emotion/styled": { + "version": "11.11.0", + "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.11.0.tgz", + "integrity": "sha512-hM5Nnvu9P3midq5aaXj4I+lnSfNi7Pmd4EWk1fOZ3pxookaQTNew6bp4JaCBYM4HVFZF9g7UjJmsUmC2JlxOng==", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.11.0", + "@emotion/is-prop-valid": "^1.2.1", + "@emotion/serialize": "^1.1.2", + "@emotion/use-insertion-effect-with-fallbacks": "^1.0.1", + "@emotion/utils": "^1.2.1" + }, + "peerDependencies": { + "@emotion/react": "^11.0.0-rc.0", + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/unitless": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.1.tgz", + "integrity": "sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==" + }, + "node_modules/@emotion/use-insertion-effect-with-fallbacks": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.1.tgz", + "integrity": "sha512-jT/qyKZ9rzLErtrjGgdkMBn2OP8wl0G3sQlBb3YPryvKHsjvINUhVaPFfP+fpBcOkmrVOVEEHQFJ7nbj2TH2gw==", + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@emotion/utils": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.2.1.tgz", + "integrity": "sha512-Y2tGf3I+XVnajdItskUCn6LX+VUDmP6lTL4fcqsXAv43dnlbZiuW4MWQW38rW/BVWSE7Q/7+XQocmpnRYILUmg==" + }, + "node_modules/@emotion/weak-memoize": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.3.1.tgz", + "integrity": "sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww==" + }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", @@ -2376,6 +2550,45 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@floating-ui/core": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.5.3.tgz", + "integrity": "sha512-O0WKDOo0yhJuugCx6trZQj5jVJ9yR0ystG2JaNAemYUWce+pmM6WUEFIibnWyEJKdrDxhm75NoSRME35FNaM/Q==", + "dependencies": { + "@floating-ui/utils": "^0.2.0" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.5.4.tgz", + "integrity": "sha512-jByEsHIY+eEdCjnTVu+E3ephzTOzkQ8hgUfGwos+bg7NlH33Zc5uO+QHz1mrQUOgIKKDD1RtS201P9NvAfq3XQ==", + "dependencies": { + "@floating-ui/core": "^1.5.3", + "@floating-ui/utils": "^0.2.0" + } + }, + "node_modules/@floating-ui/react-dom": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.0.5.tgz", + "integrity": "sha512-UsBK30Bg+s6+nsgblXtZmwHhgS2vmbuQK22qgt2pTQM6M3X6H1+cQcLXqgRY3ihVLcZJE6IvqDQozhsnIVqK/Q==", + "dependencies": { + "@floating-ui/dom": "^1.5.4" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.1.tgz", + "integrity": "sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q==" + }, + "node_modules/@fontsource/roboto": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/@fontsource/roboto/-/roboto-5.0.8.tgz", + "integrity": "sha512-XxPltXs5R31D6UZeLIV1td3wTXU3jzd3f2DLsXI8tytMGBkIsGcc9sIyiupRtA8y73HAhuSCeweOoBqf6DbWCA==" + }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.14", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", @@ -3234,6 +3447,261 @@ "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz", "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==" }, + "node_modules/@mui/base": { + "version": "5.0.0-beta.31", + "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.31.tgz", + "integrity": "sha512-+uNbP3OHJuZVI00WyMg7xfLZotaEY7LgvYXDfONVJbrS+K9wyjCIPNfjy8r9XJn4fbHo/5ibiZqjWnU9LMNv+A==", + "dependencies": { + "@babel/runtime": "^7.23.7", + "@floating-ui/react-dom": "^2.0.5", + "@mui/types": "^7.2.13", + "@mui/utils": "^5.15.4", + "@popperjs/core": "^2.11.8", + "clsx": "^2.1.0", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0", + "react-dom": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/core-downloads-tracker": { + "version": "5.15.4", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.15.4.tgz", + "integrity": "sha512-0OZN9O6hAtBpx70mMNFOPaAIol/ytwZYPY+z7Rf9dK3+1Xlzwvj5/IeShJKvtp76S1qJyhPuvZg0+BGqQaUnUw==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + } + }, + "node_modules/@mui/icons-material": { + "version": "5.15.4", + "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-5.15.4.tgz", + "integrity": "sha512-q/Yk7aokN8qGMpR7bwoDpBSeaNe6Bv7vaY9yHYodP37c64TM6ime05ueb/wgksOVszrKkNXC67E/XYbRWOoUFA==", + "dependencies": { + "@babel/runtime": "^7.23.7" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@mui/material": "^5.0.0", + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/material": { + "version": "5.15.4", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.15.4.tgz", + "integrity": "sha512-T/LGRAC+M0c+D3+y67eHwIN5bSje0TxbcJCWR0esNvU11T0QwrX3jedXItPNBwMupF2F5VWCDHBVLlFnN3+ABA==", + "dependencies": { + "@babel/runtime": "^7.23.7", + "@mui/base": "5.0.0-beta.31", + "@mui/core-downloads-tracker": "^5.15.4", + "@mui/system": "^5.15.4", + "@mui/types": "^7.2.13", + "@mui/utils": "^5.15.4", + "@types/react-transition-group": "^4.4.10", + "clsx": "^2.1.0", + "csstype": "^3.1.2", + "prop-types": "^15.8.1", + "react-is": "^18.2.0", + "react-transition-group": "^4.4.5" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.5.0", + "@emotion/styled": "^11.3.0", + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0", + "react-dom": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/material/node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" + }, + "node_modules/@mui/private-theming": { + "version": "5.15.4", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.15.4.tgz", + "integrity": "sha512-9N5myIMEEQTM5WYWPGvvYADzjFo12LgJ7S+2iTZkBNOcJpUxQYM1tvYjkHCDV+t1ocMOEgjR2EfJ9Dus30dBlg==", + "dependencies": { + "@babel/runtime": "^7.23.7", + "@mui/utils": "^5.15.4", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/styled-engine": { + "version": "5.15.4", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.15.4.tgz", + "integrity": "sha512-vtrZUXG5XI8CNiNLcxjIirW4dEbOloR+ikfm6ePBo7jXpJdpXjVzBWetrfE+5eI0cHkKWlTptnJ2voKV8pBRfw==", + "dependencies": { + "@babel/runtime": "^7.23.7", + "@emotion/cache": "^11.11.0", + "csstype": "^3.1.2", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.4.1", + "@emotion/styled": "^11.3.0", + "react": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + } + } + }, + "node_modules/@mui/system": { + "version": "5.15.4", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.15.4.tgz", + "integrity": "sha512-KCwkHajGBXPs2TK1HJjIyab4NDk0cZoBDYN/TTlXVo1qBAmCjY0vjqrlsjeoG+wrwwcezXMLs/e6OGP66fPCog==", + "dependencies": { + "@babel/runtime": "^7.23.7", + "@mui/private-theming": "^5.15.4", + "@mui/styled-engine": "^5.15.4", + "@mui/types": "^7.2.13", + "@mui/utils": "^5.15.4", + "clsx": "^2.1.0", + "csstype": "^3.1.2", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.5.0", + "@emotion/styled": "^11.3.0", + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/types": { + "version": "7.2.13", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.13.tgz", + "integrity": "sha512-qP9OgacN62s+l8rdDhSFRe05HWtLLJ5TGclC9I1+tQngbssu0m2dmFZs+Px53AcOs9fD7TbYd4gc9AXzVqO/+g==", + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/utils": { + "version": "5.15.4", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.15.4.tgz", + "integrity": "sha512-E2wLQGBcs3VR52CpMRjk46cGscC4cbf3Q2uyHNaAeL36yTTm+aVNbtsTCazXtjOP4BDd8lu6VtlTpVC8Rtl4mg==", + "dependencies": { + "@babel/runtime": "^7.23.7", + "@types/prop-types": "^15.7.11", + "prop-types": "^15.8.1", + "react-is": "^18.2.0" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/utils/node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" + }, "node_modules/@nicolo-ribaudo/eslint-scope-5-internals": { "version": "5.1.1-v1", "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", @@ -3352,6 +3820,23 @@ } } }, + "node_modules/@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, + "node_modules/@remix-run/router": { + "version": "1.14.2", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.14.2.tgz", + "integrity": "sha512-ACXpdMM9hmKZww21yEqWwiLws/UPLhNKvimN8RrYSqPSvB3ov7sLvAcfvaxePeLvccTQKGdkDIhLYApZVDFuKg==", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/@rollup/plugin-babel": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz", @@ -4471,6 +4956,14 @@ "@types/react": "*" } }, + "node_modules/@types/react-transition-group": { + "version": "4.4.10", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.10.tgz", + "integrity": "sha512-hT/+s0VQs2ojCX823m60m5f0sL5idt9SO6Tj6Dg+rdphGPIeJbJ6CxvBYkgkGKrYeDjvIpKTR38UzmtHJOGW3Q==", + "dependencies": { + "@types/react": "*" + } + }, "node_modules/@types/resolve": { "version": "1.17.1", "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", @@ -6110,6 +6603,14 @@ "wrap-ansi": "^7.0.0" } }, + "node_modules/clsx": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.0.tgz", + "integrity": "sha512-m3iNNWpd9rl3jvvcBnu70ylMdrXt8Vlq4HYadnU5fwcOtvkSQWPmj7amUcDT2qYI7risszBjI5AUIUox9D16pg==", + "engines": { + "node": ">=6" + } + }, "node_modules/co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", @@ -7041,6 +7542,15 @@ "utila": "~0.4" } }, + "node_modules/dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "dependencies": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, "node_modules/dom-serializer": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", @@ -8393,6 +8903,11 @@ "url": "https://github.com/avajs/find-cache-dir?sponsor=1" } }, + "node_modules/find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==" + }, "node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -9052,6 +9567,19 @@ "he": "bin/he" } }, + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "dependencies": { + "react-is": "^16.7.0" + } + }, + "node_modules/hoist-non-react-statics/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, "node_modules/hoopy": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz", @@ -14895,6 +15423,14 @@ "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz", "integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==" }, + "node_modules/react-icons": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.0.1.tgz", + "integrity": "sha512-WqLZJ4bLzlhmsvme6iFdgO8gfZP17rfjYEJ2m9RsZjZ+cc4k1hTzknEz63YS1MeT50kVzoa1Nz36f4BEx+Wigw==", + "peerDependencies": { + "react": "*" + } + }, "node_modules/react-is": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", @@ -14908,6 +15444,36 @@ "node": ">=0.10.0" } }, + "node_modules/react-router": { + "version": "6.21.2", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.21.2.tgz", + "integrity": "sha512-jJcgiwDsnaHIeC+IN7atO0XiSRCrOsQAHHbChtJxmgqG2IaYQXSnhqGb5vk2CU/wBQA12Zt+TkbuJjIn65gzbA==", + "dependencies": { + "@remix-run/router": "1.14.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/react-router-dom": { + "version": "6.21.2", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.21.2.tgz", + "integrity": "sha512-tE13UukgUOh2/sqYr6jPzZTzmzc70aGRP4pAjG2if0IP3aUT+sBtAKUJh0qMh0zylJHGLmzS+XWVaON4UklHeg==", + "dependencies": { + "@remix-run/router": "1.14.2", + "react-router": "6.21.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, "node_modules/react-scripts": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz", @@ -14980,6 +15546,33 @@ } } }, + "node_modules/react-toastify": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-10.0.2.tgz", + "integrity": "sha512-U4qt1h0TV2VhHV2hscN1lKfqkZ6XiK1GkkQSa1gO2+IuEyQK13NLruorI8NWzknS3eTjJQcFBSqi9M62TeixMQ==", + "dependencies": { + "clsx": "^2.1.0" + }, + "peerDependencies": { + "react": ">=16", + "react-dom": ">=16" + } + }, + "node_modules/react-transition-group": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "dependencies": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": ">=16.6.0", + "react-dom": ">=16.6.0" + } + }, "node_modules/read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", @@ -16301,6 +16894,11 @@ "postcss": "^8.2.15" } }, + "node_modules/stylis": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", + "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==" + }, "node_modules/sucrase": { "version": "3.35.0", "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", diff --git a/package.json b/package.json index 60776b7..e80f65c 100644 --- a/package.json +++ b/package.json @@ -3,12 +3,21 @@ "version": "0.1.0", "private": true, "dependencies": { + "@emailjs/browser": "^3.12.1", + "@emotion/react": "^11.11.3", + "@emotion/styled": "^11.11.0", + "@fontsource/roboto": "^5.0.8", + "@mui/icons-material": "^5.15.4", + "@mui/material": "^5.15.4", "@testing-library/jest-dom": "^5.17.0", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-icons": "^5.0.1", + "react-router-dom": "^6.21.2", "react-scripts": "5.0.1", + "react-toastify": "^10.0.2", "web-vitals": "^2.1.4" }, "scripts": { diff --git a/public/favicon.ico b/public/favicon.ico index a11777c..b8d1cb9 100644 Binary files a/public/favicon.ico and b/public/favicon.ico differ diff --git a/public/index.html b/public/index.html index aa069f2..1ac240a 100644 --- a/public/index.html +++ b/public/index.html @@ -10,34 +10,17 @@ content="Web site created using create-react-app" /> - - - React App + + Fernando Videira's Portfolio
- diff --git a/src/App.js b/src/App.js index 3784575..7901e34 100644 --- a/src/App.js +++ b/src/App.js @@ -1,24 +1,19 @@ -import logo from './logo.svg'; -import './App.css'; +import React from "react"; +import "./index.css"; +import Home from "./routes/Home"; +import About from "./routes/About"; +import Project from "./routes/Project"; +import Contact from "./routes/Contact"; +import { Routes, Route } from "react-router-dom"; function App() { return ( -
-
- logo -

- Edit src/App.js and save to reload. -

- - Learn React - -
-
+ + } /> + } /> + } /> + } /> + ); } diff --git a/src/Components/About/AboutContent.css b/src/Components/About/AboutContent.css new file mode 100644 index 0000000..cf7e633 --- /dev/null +++ b/src/Components/About/AboutContent.css @@ -0,0 +1,48 @@ +.about{ + width: 100%; + margin: 3rem 0; + display: flex; + align-items: center; + justify-content: center; + flex-wrap: wrap; + height: 100%; +} + +.about .left{ + margin: auto; + padding: 0.5rem; + max-width: 45rem; +} + +.about .left p{ + margin: 1.2rem 0; +} + +.about .right{ + max-width: 700px; +} + +.right .img-container{ + display: grid; + grid-template-columns: repeat(12, 1fr); + align-items: center; + text-align: center; +} + +.right .img{ + max-width: 90%; + border: 1px solid #333; +} + +.right .top{ + grid-column: 1 / span 8; + grid-row: 1; + padding-top: 20%; + z-index: 6; +} + +.right .bottom { + grid-column: 4 / -1; + grid-row: 1; + z-index: 5; +} diff --git a/src/Components/About/AboutContent.js b/src/Components/About/AboutContent.js new file mode 100644 index 0000000..372618f --- /dev/null +++ b/src/Components/About/AboutContent.js @@ -0,0 +1,48 @@ +import { Link } from "react-router-dom"; +import "./AboutContent.css"; + +import React from "react"; + +import React1 from "../../assets/react1.jpg"; +import React2 from "../../assets/react2.webp"; + +const AboutContent = () => { + return ( +
+
+

Who am I?

+

+ I am a Software Engineering student from Portugal, I am passionate + about learning and applying new technologies and frameworks to create + innovative and engaging applications. I am currently pursuing my + Bachelor of Engineering in Information Technology, after completing a + CTeSP in programming, where I gained a solid foundation in C, .NET, + PHP, Java, and MySQL. I have also enhanced my skills and knowledge by + taking online courses in Unity 3D, Swift/SwiftUI, Cypress, Git, and + React, and by working as a QA/QC at VOID Software, a leading software + development company, for five months. There, I contributed to the + testing and quality assurance of several projects, using Cypress and + Cucumber to automate and streamline the testing process, and Git to + manage the source code and collaborate with the development team. I am + eager to continue developing my competencies and exploring new + opportunities in the software industry. +

+ + + +
+
+
+
+ true +
+
+ true +
+
+
+
+ ); +}; + +export default AboutContent; diff --git a/src/Components/ContactForm/ContactForm.css b/src/Components/ContactForm/ContactForm.css new file mode 100644 index 0000000..14ceeb4 --- /dev/null +++ b/src/Components/ContactForm/ContactForm.css @@ -0,0 +1,21 @@ +label{ + color: #fff; + margin-bottom: 0.5rem; +} + +form{ + display: flex; + flex-direction: column; + padding: 4rem 1rem; + margin: auto; + max-width: 600px; +} + +form input, form textarea{ + padding: 10px 18px; + margin-bottom: 1rem; + font-size: 1.2rem; + background-color: rgba(255, 255, 255, 0.1); + border-color: rgba(255, 255, 255, 0.1); + color: #f4f4f4; +} \ No newline at end of file diff --git a/src/Components/ContactForm/ContactForm.js b/src/Components/ContactForm/ContactForm.js new file mode 100644 index 0000000..9e249b8 --- /dev/null +++ b/src/Components/ContactForm/ContactForm.js @@ -0,0 +1,89 @@ +import "./ContactForm.css"; + +import React from "react"; +import { useRef } from "react"; +import emailjs from "@emailjs/browser"; +import { ToastContainer, toast } from "react-toastify"; +import "react-toastify/dist/ReactToastify.css"; + +const ContactForm = () => { + const form = useRef(); + const notify = () => { + toast.success("Message Sent Successfully!"); + }; + + const errorToast = () => { + toast.error("Error Sending Message!"); + }; + + const emptyForm = () => { + toast.warning("Please fill all the fields!"); + }; + + const sendEmail = (e) => { + e.preventDefault(); + + let isEmpty = Array.from(form.current.elements).some( + (input) => input.type !== "submit" && input.value.trim() === "" + ); + + if (isEmpty) { + emptyForm(); + return; + } + + emailjs + .sendForm( + "service_0oh6s0e", + "template_4s8pg7r", + form.current, + "fSghIDn2dawqKYyH7" + ) + .then( + (result) => { + console.log(result.text); + notify(); + }, + (error) => { + console.log(error.text); + errorToast(); + } + ); + e.target.reset(); + }; + return ( +
+
+ + + + + + + + + + + +
+ ); +}; + +export default ContactForm; diff --git a/src/Components/Footer/Footer.css b/src/Components/Footer/Footer.css new file mode 100644 index 0000000..ad1632c --- /dev/null +++ b/src/Components/Footer/Footer.css @@ -0,0 +1,48 @@ +.footer{ + width: 100%; + padding: 6rem 0; + background-color: rgba(19,19,19,0.8); +} + +.footer-container{ + max-width: 1140px; + margin: auto; + display: grid; + grid-template-columns: repeat(2, 1fr); + grid-gap: 40px; +} + +.left{ + height: 100%; + max-width: 100%; + display: flex; + flex-direction: column; + padding: 1rem; +} + +.right{ + height: 100%; + max-width: 100%; + display: flex; + flex-direction: column; + padding: 1rem; +} + +.social{ + margin-top: 1rem; +} + +h4{ + font-size: 1.2rem; + padding-bottom: 0.7rem; +} + +p{ + font-size: 1.2rem; +} + +@media screen and (max-width: 640px) { + .footer-container { + grid-template-columns: 1fr; + } +} \ No newline at end of file diff --git a/src/Components/Footer/Footer.js b/src/Components/Footer/Footer.js new file mode 100644 index 0000000..a887d8f --- /dev/null +++ b/src/Components/Footer/Footer.js @@ -0,0 +1,84 @@ +import { + FaGithub, + FaLinkedin, + FaMailBulk, + FaPhone, + FaTwitter, +} from "react-icons/fa"; +import "./Footer.css"; + +import React from "react"; + +const Footer = () => { + return ( +
+
+
+
+

+ + 999-999-999 +

+
+
+

+ + info@fernandovideira.com +

+
+
+
+

A bit about me

+

+ I'm Fernando Videira, a Software Engineering student in Portugal + looking for some new projects and challenges and oportunities to + learn new things about the programming world! +

+
+ + + + + + + + + +
+
+
+
+ ); +}; + +export default Footer; diff --git a/src/Components/Hero/Hero.css b/src/Components/Hero/Hero.css new file mode 100644 index 0000000..4a008c8 --- /dev/null +++ b/src/Components/Hero/Hero.css @@ -0,0 +1,62 @@ +.mask{ + width: 100%; + height: 100vh; + position: relative; +} + +.intro-img{ + width: 100%; + height: 100%; + background-size: cover; + background-position: center; + object-fit: cover; +} + +.mask::after{ + content: ''; + width: 100%; + height: 100%; + position: absolute; + top: 0; + left: 0; + background-color: black; + opacity: 0.8; +} + +.hero{ + height: 100%; + width: 100%; +} + +.hero .content{ + position: absolute; + transform: translate(-50%, -50%); + top: 50%; + left: 50%; + text-align: center; +} + +.hero .content h1{ + font-size: 4rem; + font-weight: 900; + padding: 0.6rem 0 1.5rem; +} + +.hero .content p { + font-size: 1.4rem; + font-weight: 200; +} + +.hero .content .btn{ + margin: 1rem 0.2rem; +} + +@media screen and (max-width: 640px) { + .hero .content h1 { + font-size: 3rem; + } + + .hero .content p { + font-size: 1.4rem; + } +} diff --git a/src/Components/Hero/Hero.js b/src/Components/Hero/Hero.js new file mode 100644 index 0000000..8504060 --- /dev/null +++ b/src/Components/Hero/Hero.js @@ -0,0 +1,29 @@ +import "./Hero.css"; +import React from "react"; + +import IntroImg from "../../assets/intro-bg.jpg"; +import { Link } from "react-router-dom"; + +const Hero = () => { + return ( +
+
+ IntroImg +
+
+

Hi, I'm a Freelancer

+

Software Developer

+
+ + Projects + + + Contact + +
+
+
+ ); +}; + +export default Hero; diff --git a/src/Components/HeroSec/HeroSec.css b/src/Components/HeroSec/HeroSec.css new file mode 100644 index 0000000..9ac332f --- /dev/null +++ b/src/Components/HeroSec/HeroSec.css @@ -0,0 +1,43 @@ +.hero-img{ + width: 100%; + background: rgba(0,0,0,0.5); + height: 60vh; + position: relative; +} + +.hero-img::before{ + content: ""; + background: url("https://images.unsplash.com/photo-1571171637578-41bc2dd41cd2?q=80&w=3270&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D") repeat 0 0; + background-size: cover; + background-position: center top; + height: 100%; + width: 100%; + position: absolute; + top: 0; + left: 0; + z-index: -1; +} + +.heading{ + display: flex; + width: 100%; + height: 100%; + flex-direction: column; + justify-content: center; + align-items: center; +} + +.hero-img h1{ + font-size: 2.4rem; +} + +.hero-img p { + font-size: 1.4rem; + text-align: center; +} + +@media screen and (max-width: 640px) { + .hero-img h1{ + font-size: 2rem; + } +} \ No newline at end of file diff --git a/src/Components/HeroSec/HeroSec.js b/src/Components/HeroSec/HeroSec.js new file mode 100644 index 0000000..3da189e --- /dev/null +++ b/src/Components/HeroSec/HeroSec.js @@ -0,0 +1,16 @@ +import "./HeroSec.css"; + +import React from "react"; + +const HeroSec = ({ heading, paragraph }) => { + return ( +
+
+

{heading}

+

{paragraph}

+
+
+ ); +}; + +export default HeroSec; diff --git a/src/Components/Navbar/Navbar.css b/src/Components/Navbar/Navbar.css new file mode 100644 index 0000000..4bf7965 --- /dev/null +++ b/src/Components/Navbar/Navbar.css @@ -0,0 +1,86 @@ +.header{ +display: flex; +justify-content: space-between; +align-items: center; +padding: 1rem; +position: fixed; +width: 100%; +height: 90px; +z-index: 10; +} + +.header h1{ + padding-top: 7px; +} + +.logo{ + width: 60px; + height: 60px; +} + +.header-title-child{ + float: left; + width: 30%; +} + +.header-bg{ + background-color: rgba(0, 0, 0, 0.85); + transition: 0.5s; +} + +.nav-menu{ + display: flex; +} + +.nav-menu li{ + padding: 0 1rem; +} + +.nav-menu li a{ + font-size: 1.2rem; + font-weight: 500; +} + +.burger{ + display: none; +} + +@media screen and (max-width: 1040px){ + .nav-menu{ + flex-direction: column; + justify-content: center; + align-items: center; + width: 100%; + height: 100vh; + background-color: rgba(0, 0, 0, 0.9); + position: absolute; + top: 0; + left: -100%; + z-index: -3; + transition: 0.3s; + } + + .nav-menu.active{ + left: 0; + } + + .logo { + padding-top: 7px; + width: 45px; + height: 45px; + } + + .nav-menu li{ + padding: 1rem 0; + } + .nav-menu li a{ + font-size: 2rem; + } + + .burger{ + display: initial ; + cursor: pointer; + } + +} + diff --git a/src/Components/Navbar/Navbar.js b/src/Components/Navbar/Navbar.js new file mode 100644 index 0000000..ca31ac3 --- /dev/null +++ b/src/Components/Navbar/Navbar.js @@ -0,0 +1,63 @@ +import { Link } from "react-router-dom"; +import "./Navbar.css"; +import React, { useState } from "react"; + +import Logo from "../../assets/logo.png"; + +import { FaBars, FaTimes } from "react-icons/fa"; + +const Navbar = () => { + const [showLinks, setShowLinks] = useState(false); + const handleClick = () => setShowLinks(!showLinks); + + const [colorChange, setColorChange] = useState(false); + const changeColor = () => { + if (window.scrollY >= 100) { + setColorChange(true); + } else { + setColorChange(false); + } + }; + + window.addEventListener("scroll", changeColor); + + return ( +
+
+
+ + logo + +
+
+ +

Portfolio

+ +
+
+ +
+ {showLinks ? ( + + ) : ( + + )} +
+
+ ); +}; + +export default Navbar; diff --git a/src/Components/WorkCard/Work.js b/src/Components/WorkCard/Work.js new file mode 100644 index 0000000..0177857 --- /dev/null +++ b/src/Components/WorkCard/Work.js @@ -0,0 +1,27 @@ +import "./WorkCard.css"; +import WorkCard from "./WorkCard"; + +import React from "react"; + +const Work = ({ title, workcardData }) => { + return ( +
+

{title}

+
+ {workcardData.map((val, index) => { + return ( + + ); + })} +
+
+ ); +}; + +export default Work; diff --git a/src/Components/WorkCard/WorkCard.css b/src/Components/WorkCard/WorkCard.css new file mode 100644 index 0000000..4025fd0 --- /dev/null +++ b/src/Components/WorkCard/WorkCard.css @@ -0,0 +1,52 @@ +.project-heading{ + text-align: center; + padding: 4rem 0 2rem 0; +} + +.project-container { + max-width: 1140px; + margin: auto; + display: grid; + grid-template-columns: repeat(3, 1fr); + grid-gap: 40px; + padding-bottom: 5rem; +} + +.project-card{ + background: #1a1919; + padding: 1.2rem 1rem; +} + +.project-card img{ + width: 100%; +} + +.project-title{ + color: #fff; + padding: 1rem 0; +} + +.pro-details p{ + padding-bottom: 1rem; + font-size: 1.1rem; + text-align: justify; +} + +.pro-btns{ + display: flex; + justify-content: space-between; + align-items: center; + padding: 0.5rem 0; +} + +.pro-btns .btn { + padding: 0.5rem 1rem; +} + +@media screen and (max-width: 950px){ + .project-container{ + max-width: 90%; + margin: auto; + grid-template-columns: 1fr; + } +} \ No newline at end of file diff --git a/src/Components/WorkCard/WorkCard.js b/src/Components/WorkCard/WorkCard.js new file mode 100644 index 0000000..79fbe47 --- /dev/null +++ b/src/Components/WorkCard/WorkCard.js @@ -0,0 +1,23 @@ +import "./WorkCard.css"; + +import React from "react"; +import { NavLink } from "react-router-dom"; + +const WorkCard = (props) => { + return ( +
+ im +

{props.title}

+
+

{props.text}

+
+
+ + View + +
+
+ ); +}; + +export default WorkCard; diff --git a/src/Components/WorkData/AcademicProjects.js b/src/Components/WorkData/AcademicProjects.js new file mode 100644 index 0000000..b394f80 --- /dev/null +++ b/src/Components/WorkData/AcademicProjects.js @@ -0,0 +1,25 @@ +import umbBot from "../../assets/umbreonbot.jpg"; +import pro2 from "../../assets/project2.png"; +import pro3 from "../../assets/project3.png"; + +const AcademicProjectCardData = [ + { + imgsrc: umbBot, + title: "Stuff&Go Web Store", + text: "Stuff&Go is a web application dedicated to a supermarket chain. It allows the user to create an account, add items to a cart, and checkout. It also allows the user to see the history of their purchases. The application was developed using PHP, with the Yii2 framework, and a MySQL database. It also hosts a REST API, which implements the MQTT Broker for connection to the Mobile App.", + view: "https://github.com/FernandoJVideira/PL2-G7_ProjetoPlatSI", + }, + { + imgsrc: pro2, + title: "Stuff&Go Mobile App", + text: "Stuff&Go is a mobile application dedicated to a supermarket chain. It allows the user to login to their account, add items to a cart, and checkout. It also allows the user to see the history of their purchases. The application was developed using Android Studio, with the Java language, and connects to the REST API of the Web Store.", + view: "https://github.com/FernandoJVideira/PL2-G7_ProjetoAMSI", + }, + { + imgsrc: pro3, + title: "Project 3", + text: "Lorem ipsum dolor sit amet consectetur adipisicing elit. Quisquam voluptatum, quibusdam, tempora, voluptates voluptate dolores officia quas quae dolorum natus labore? Quisquam voluptatum, quibusdam, tempora, voluptates voluptate dolores officia quas quae dolorum natus labore?", + view: "https://github.com/FernandoJVideira/UmbreonBot", + }, +]; +export default AcademicProjectCardData; diff --git a/src/Components/WorkData/PersonalProjects.js b/src/Components/WorkData/PersonalProjects.js new file mode 100644 index 0000000..191cdde --- /dev/null +++ b/src/Components/WorkData/PersonalProjects.js @@ -0,0 +1,25 @@ +import umbBot from "../../assets/umbreonbot.jpg"; +import pro2 from "../../assets/project2.png"; +import pro3 from "../../assets/project3.png"; + +const PersonalProjectCardData = [ + { + imgsrc: umbBot, + title: "Umbreon Discord Bot", + text: "Umbreon bot is a general-purpose discord bot made in python. It is equiped with commands from moderation to playing music. It does so by connecting to a Lavalink server and using it to stream the songs. (And yes, it supports Youtube playback).", + view: "https://github.com/FernandoJVideira/UmbreonBot", + }, + { + imgsrc: pro2, + title: "Stuff&Go", + text: "Stu", + view: "https://github.com/FernandoJVideira/UmbreonBot", + }, + { + imgsrc: pro3, + title: "Project 3", + text: "Lorem ipsum dolor sit amet consectetur adipisicing elit. Quisquam voluptatum, quibusdam, tempora, voluptates voluptate dolores officia quas quae dolorum natus labore? Quisquam voluptatum, quibusdam, tempora, voluptates voluptate dolores officia quas quae dolorum natus labore?", + view: "https://github.com/FernandoJVideira/UmbreonBot", + }, +]; +export default PersonalProjectCardData; diff --git a/src/assets/intro-bg.jpg b/src/assets/intro-bg.jpg new file mode 100644 index 0000000..c563fe0 Binary files /dev/null and b/src/assets/intro-bg.jpg differ diff --git a/src/assets/logo.png b/src/assets/logo.png new file mode 100644 index 0000000..c24ef4f Binary files /dev/null and b/src/assets/logo.png differ diff --git a/src/assets/logo.svg b/src/assets/logo.svg new file mode 100644 index 0000000..798ad7d --- /dev/null +++ b/src/assets/logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/project1.png b/src/assets/project1.png new file mode 100644 index 0000000..85ca9cd Binary files /dev/null and b/src/assets/project1.png differ diff --git a/src/assets/project2.png b/src/assets/project2.png new file mode 100644 index 0000000..f4fcced Binary files /dev/null and b/src/assets/project2.png differ diff --git a/src/assets/project3.png b/src/assets/project3.png new file mode 100644 index 0000000..c81e36d Binary files /dev/null and b/src/assets/project3.png differ diff --git a/src/assets/project4.png b/src/assets/project4.png new file mode 100644 index 0000000..cef762d Binary files /dev/null and b/src/assets/project4.png differ diff --git a/src/assets/react1.jpg b/src/assets/react1.jpg new file mode 100644 index 0000000..653f03f Binary files /dev/null and b/src/assets/react1.jpg differ diff --git a/src/assets/react2.webp b/src/assets/react2.webp new file mode 100644 index 0000000..f9f299a Binary files /dev/null and b/src/assets/react2.webp differ diff --git a/src/assets/umbreonbot.jpg b/src/assets/umbreonbot.jpg new file mode 100644 index 0000000..53e94e3 Binary files /dev/null and b/src/assets/umbreonbot.jpg differ diff --git a/src/index.css b/src/index.css index ec2585e..1729545 100644 --- a/src/index.css +++ b/src/index.css @@ -1,13 +1,43 @@ -body { +@import url('https://fonts.googleapis.com/css2?family=Outfit:wght@100;200;300;400;500;600;700;800;900&display=swap'); + +*{ margin: 0; - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', - 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', - sans-serif; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; + padding: 0; + box-sizing: border-box; + font-family: 'Outfit', sans-serif; } -code { - font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', - monospace; +body{ + background: #000; +} + +h1, h4, p, a{ + color: #fff; + text-decoration: none; +} + +ul{ + list-style: none; +} + +.btn{ + padding: 12px 32px; + font: 1rem; + background: rgb(248,217,15); + color: #222; + border: 1px solid #fff; + text-transform: uppercase; + font-weight: 600; + cursor: pointer; +} + +.btn-light{ + background: transparent; + color: #fff; +} + +.btn:hover{ + background: rgba(255, 255, 255,0.2); + color: #fff; + transition: 0.3s; } diff --git a/src/index.js b/src/index.js index d563c0f..9a5e3e3 100644 --- a/src/index.js +++ b/src/index.js @@ -1,17 +1,16 @@ -import React from 'react'; -import ReactDOM from 'react-dom/client'; -import './index.css'; -import App from './App'; -import reportWebVitals from './reportWebVitals'; +import React from "react"; +import ReactDOM from "react-dom/client"; +import "@fontsource/roboto/300.css"; +import "@fontsource/roboto/400.css"; +import "@fontsource/roboto/500.css"; +import "@fontsource/roboto/700.css"; +import "./index.css"; +import App from "./App"; +import { BrowserRouter } from "react-router-dom"; -const root = ReactDOM.createRoot(document.getElementById('root')); +const root = ReactDOM.createRoot(document.getElementById("root")); root.render( - + - + ); - -// If you want to start measuring performance in your app, pass a function -// to log results (for example: reportWebVitals(console.log)) -// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals -reportWebVitals(); diff --git a/src/routes/About.js b/src/routes/About.js new file mode 100644 index 0000000..6874f23 --- /dev/null +++ b/src/routes/About.js @@ -0,0 +1,18 @@ +import React from "react"; +import Navbar from "../Components/Navbar/Navbar"; +import Footer from "../Components/Footer/Footer"; +import HeroSec from "../Components/HeroSec/HeroSec"; +import AboutContent from "../Components/About/AboutContent"; + +const About = () => { + return ( +
+ + + +
+ ); +}; + +export default About; diff --git a/src/routes/Contact.js b/src/routes/Contact.js new file mode 100644 index 0000000..cf461f4 --- /dev/null +++ b/src/routes/Contact.js @@ -0,0 +1,18 @@ +import React from "react"; +import Navbar from "../Components/Navbar/Navbar"; +import Footer from "../Components/Footer/Footer"; +import HeroSec from "../Components/HeroSec/HeroSec"; +import ContactForm from "../Components/ContactForm/ContactForm"; + +const Contact = () => { + return ( +
+ + + +
+ ); +}; + +export default Contact; diff --git a/src/routes/Home.js b/src/routes/Home.js new file mode 100644 index 0000000..8c1dc79 --- /dev/null +++ b/src/routes/Home.js @@ -0,0 +1,22 @@ +import React from "react"; +import Navbar from "../Components/Navbar/Navbar"; +import Hero from "../Components/Hero/Hero"; +import Footer from "../Components/Footer/Footer"; +import Work from "../Components/WorkCard/Work"; + +import PersonalProjects from "../Components/WorkData/PersonalProjects"; +import AcademicProjects from "../Components/WorkData/AcademicProjects"; + +const Home = () => { + return ( +
+ + + + +
+ ); +}; + +export default Home; diff --git a/src/routes/Project.js b/src/routes/Project.js new file mode 100644 index 0000000..4ceb84d --- /dev/null +++ b/src/routes/Project.js @@ -0,0 +1,22 @@ +import React from "react"; +import Navbar from "../Components/Navbar/Navbar"; +import Footer from "../Components/Footer/Footer"; +import HeroSec from "../Components/HeroSec/HeroSec"; +import Work from "../Components/WorkCard/Work"; + +import PersonalProjects from "../Components/WorkData/PersonalProjects"; +import AcademicProjects from "../Components/WorkData/AcademicProjects"; + +const Project = () => { + return ( +
+ + + + +
+ ); +}; + +export default Project;