Merge branch 'develop' into l10n_develop

This commit is contained in:
Amruth Pillai
2020-05-06 23:10:46 +05:30
100 changed files with 756 additions and 100 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -8,6 +8,29 @@ All notable changes to this project will be documented in this file.
## April 2020
### April 28, 2020
- Added Feature to Reorder Skills/Hobbies
- Added Hobbies Section to Left Sidebar
- Updated Templates to Add Hobbies
### April 23, 2020
- Fix Issue with Page Controller Icon Size
- Fix Issue with Checkbox Icon Toggle
### April 23, 2020
- Transfer all external resources to local, self-host everything
- Shorten entry animation by a second
- Optimize Images through `imgbot`
### April 22, 2020
- Display Original Language Name alongside English Language Name
- Added Language: Tamil
- Added Language: Vietnamese
### April 17, 2020
- Updated Dependencies across App

Binary file not shown.

Before

Width:  |  Height:  |  Size: 377 KiB

After

Width:  |  Height:  |  Size: 374 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 335 KiB

After

Width:  |  Height:  |  Size: 331 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 220 KiB

After

Width:  |  Height:  |  Size: 218 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 535 KiB

After

Width:  |  Height:  |  Size: 491 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 225 KiB

After

Width:  |  Height:  |  Size: 117 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 163 KiB

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 94 KiB

After

Width:  |  Height:  |  Size: 47 KiB

26
package-lock.json generated
View File

@ -1704,9 +1704,9 @@
}
},
"@testing-library/user-event": {
"version": "10.0.2",
"resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-10.0.2.tgz",
"integrity": "sha512-fVeP4U37BIYdp9nBRKEITFSLPqgCSS7Og6LHvxoQ2JSOTJ1NJI4Dfesv4uNXxvNNcJgBS88V+Tc6h8vbDsa2iA=="
"version": "10.1.0",
"resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-10.1.0.tgz",
"integrity": "sha512-qutUm/2lWAD8IiKrss2Cg6Hf8AkcMeylKm09bSMtYC39Ug68aXWkcbc0H/NVD5R1zOHguTjkR/Ppuns6bWksGQ=="
},
"@types/babel__core": {
"version": "7.1.6",
@ -6844,9 +6844,9 @@
}
},
"eslint-config-prettier": {
"version": "6.10.1",
"resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-6.10.1.tgz",
"integrity": "sha512-svTy6zh1ecQojvpbJSgH3aei/Rt7C6i090l5f2WQ4aB05lYHeZIR1qL4wZyyILTbtmnbHP5Yn8MrsOJMGa8RkQ==",
"version": "6.11.0",
"resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-6.11.0.tgz",
"integrity": "sha512-oB8cpLWSAjOVFEJhhyMZh6NOEOtBVziaqdDQ86+qhDHFbZXoRTM7pNSvFRfW/W/L/LrQ38C99J5CGuRBBzBsdA==",
"dev": true,
"requires": {
"get-stdin": "^6.0.0"
@ -16082,13 +16082,13 @@
}
},
"tailwindcss": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-1.2.0.tgz",
"integrity": "sha512-CKvY0ytB3ze5qvynG7qv4XSpQtFNGPbu9pUn8qFdkqgD8Yo/vGss8mhzbqls44YCXTl4G62p3qVZBj45qrd6FQ==",
"version": "1.3.5",
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-1.3.5.tgz",
"integrity": "sha512-hHGShfHBj7tAQRobnsYckDySPpMDnPF4KejHYYRcZjZQvyRRnCSHi2S905icK24HrYadOq9pZKwENqg2axSviw==",
"requires": {
"autoprefixer": "^9.4.5",
"bytes": "^3.0.0",
"chalk": "^3.0.0",
"chalk": "^4.0.0",
"detective": "^5.2.0",
"fs-extra": "^8.0.0",
"lodash": "^4.17.15",
@ -16114,9 +16114,9 @@
}
},
"chalk": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz",
"integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==",
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.0.0.tgz",
"integrity": "sha512-N9oWFcegS0sFr9oh1oz2d7Npos6vNoWW9HvtCg5N1KRFpUhaAhvTv5Y58g880fZaEYSNm3qDz8SU1UrGvp+n7A==",
"requires": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"

View File

@ -10,7 +10,7 @@
"@fullhuman/postcss-purgecss": "^2.1.2",
"@testing-library/jest-dom": "^5.5.0",
"@testing-library/react": "^10.0.3",
"@testing-library/user-event": "^10.0.2",
"@testing-library/user-event": "^10.1.0",
"@vuepress/plugin-google-analytics": "^1.4.1",
"autoprefixer": "^9.7.6",
"axios": "^0.19.2",
@ -28,7 +28,7 @@
"react-markdown": "^4.3.1",
"react-scripts": "3.4.1",
"react-toastify": "^5.5.0",
"tailwindcss": "^1.2.0",
"tailwindcss": "^1.3.5",
"uuid": "^7.0.3",
"vuepress": "^1.4.1"
},
@ -69,7 +69,7 @@
},
"devDependencies": {
"eslint-config-airbnb": "^18.1.0",
"eslint-config-prettier": "^6.10.1",
"eslint-config-prettier": "^6.11.0",
"eslint-plugin-import": "^2.20.2",
"eslint-plugin-jsx-a11y": "^6.2.3",
"eslint-plugin-prettier": "^3.1.3",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 226 KiB

After

Width:  |  Height:  |  Size: 133 KiB

View File

@ -25,15 +25,6 @@
<meta name="twitter:site" content="@amruthpillai">
<title>Reactive Resume</title>
<!-- Animate.css -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.7.2/animate.min.css" />
<!-- Google Fonts -->
<link href="https://fonts.googleapis.com/css2?family=Montserrat:wght@400;500;600;700&display=swap" rel="stylesheet">
<!-- Material Icons -->
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" />
</head>
<body>

79
src/assets/css/animate.css vendored Normal file
View File

@ -0,0 +1,79 @@
@-webkit-keyframes slideInLeft {
from {
-webkit-transform: translate3d(-100%, 0, 0);
transform: translate3d(-100%, 0, 0);
visibility: visible;
}
to {
-webkit-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
}
@keyframes slideInLeft {
from {
-webkit-transform: translate3d(-100%, 0, 0);
transform: translate3d(-100%, 0, 0);
visibility: visible;
}
to {
-webkit-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
}
.slideInLeft {
-webkit-animation-name: slideInLeft;
animation-name: slideInLeft;
}
@-webkit-keyframes slideInRight {
from {
-webkit-transform: translate3d(100%, 0, 0);
transform: translate3d(100%, 0, 0);
visibility: visible;
}
to {
-webkit-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
}
@keyframes slideInRight {
from {
-webkit-transform: translate3d(100%, 0, 0);
transform: translate3d(100%, 0, 0);
visibility: visible;
}
to {
-webkit-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
}
.slideInRight {
-webkit-animation-name: slideInRight;
animation-name: slideInRight;
}
.animated {
-webkit-animation-duration: 1s;
animation-duration: 1s;
-webkit-animation-fill-mode: both;
animation-fill-mode: both;
}
@media (print), (prefers-reduced-motion: reduce) {
.animated {
-webkit-animation-duration: 1ms !important;
animation-duration: 1ms !important;
-webkit-transition-duration: 1ms !important;
transition-duration: 1ms !important;
-webkit-animation-iteration-count: 1 !important;
animation-iteration-count: 1 !important;
}
}

304
src/assets/css/fonts.css Normal file
View File

@ -0,0 +1,304 @@
/* Material Icons */
@font-face {
font-family: 'Material Icons';
font-style: normal;
font-weight: 400;
src: local('Material Icons'), local('MaterialIcons-Regular'),
url('../fonts/MaterialIcons/MaterialIcons-400.woff2') format('woff2'),
url('../fonts/MaterialIcons/MaterialIcons-400.woff') format('woff');
}
.material-icons {
font-family: 'Material Icons';
font-weight: normal;
font-style: normal;
display: inline-block;
line-height: 1;
text-transform: none;
letter-spacing: normal;
word-wrap: normal;
white-space: nowrap;
direction: ltr;
-webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility;
-moz-osx-font-smoothing: grayscale;
font-feature-settings: 'liga';
}
/* Montserrat 400 */
@font-face {
font-family: 'Montserrat';
font-style: normal;
font-weight: 400;
src: local('Montserrat Regular'), local('Montserrat-Regular'),
url('../fonts/Montserrat/Montserrat-400.woff2') format('woff2'),
url('../fonts/Montserrat/Montserrat-400.woff') format('woff');
}
/* Montserrat 500 */
@font-face {
font-family: 'Montserrat';
font-style: normal;
font-weight: 500;
src: local('Montserrat Medium'), local('Montserrat-Medium'),
url('../fonts/Montserrat/Montserrat-500.woff2') format('woff2'),
url('../fonts/Montserrat/Montserrat-500.woff') format('woff');
}
/* Montserrat 600 */
@font-face {
font-family: 'Montserrat';
font-style: normal;
font-weight: 600;
src: local('Montserrat SemiBold'), local('Montserrat-SemiBold'),
url('../fonts/Montserrat/Montserrat-600.woff2') format('woff2'),
url('../fonts/Montserrat/Montserrat-600.woff') format('woff');
}
/* Montserrat 700 */
@font-face {
font-family: 'Montserrat';
font-style: normal;
font-weight: 700;
src: local('Montserrat Bold'), local('Montserrat-Bold'),
url('../fonts/Montserrat/Montserrat-700.woff2') format('woff2'),
url('../fonts/Montserrat/Montserrat-700.woff') format('woff');
}
/* Lato 400 */
@font-face {
font-family: 'Lato';
font-style: normal;
font-weight: 400;
src: local('Lato Regular'), local('Lato-Regular'),
url('../fonts/Lato/Lato-400.woff2') format('woff2'),
url('../fonts/Lato/Lato-400.woff') format('woff');
}
/* Lato 700 */
@font-face {
font-family: 'Lato';
font-style: normal;
font-weight: 700;
src: local('Lato Bold'), local('Lato-Bold'), url('../fonts/Lato/Lato-700.woff2') format('woff2'),
url('../fonts/Lato/Lato-700.woff') format('woff');
}
/* Nunito 400 */
@font-face {
font-family: 'Nunito';
font-style: normal;
font-weight: 400;
src: local('Nunito Regular'), local('Nunito-Regular'),
url('../fonts/Nunito/Nunito-400.woff') format('woff2'),
url('../fonts/Nunito/Nunito-400.woff2') format('woff');
}
/* Nunito 600 */
@font-face {
font-family: 'Nunito';
font-style: normal;
font-weight: 600;
src: local('Nunito SemiBold'), local('Nunito-SemiBold'),
url('../fonts/Nunito/Nunito-600.woff') format('woff2'),
url('../fonts/Nunito/Nunito-600.woff2') format('woff');
}
/* Nunito 700 */
@font-face {
font-family: 'Nunito';
font-style: normal;
font-weight: 700;
src: local('Nunito Bold'), local('Nunito-Bold'),
url('../fonts/Nunito/Nunito-700.woff') format('woff2'),
url('../fonts/Nunito/Nunito-700.woff2') format('woff');
}
/* Open Sans 400 */
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 400;
src: local('Open Sans Regular'), local('OpenSans-Regular'),
url('../fonts/OpenSans/OpenSans-400.woff2') format('woff2'),
url('../fonts/OpenSans/OpenSans-400.woff') format('woff');
}
/* Open Sans 600 */
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 600;
src: local('Open Sans SemiBold'), local('OpenSans-SemiBold'),
url('../fonts/OpenSans/OpenSans-600.woff2') format('woff2'),
url('../fonts/OpenSans/OpenSans-600.woff') format('woff');
}
/* Open Sans 700 */
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 700;
src: local('Open Sans Bold'), local('OpenSans-Bold'),
url('../fonts/OpenSans/OpenSans-700.woff2') format('woff2'),
url('../fonts/OpenSans/OpenSans-700.woff') format('woff');
}
/* Raleway 400 */
@font-face {
font-family: 'Raleway';
font-style: normal;
font-weight: 400;
src: local('Raleway'), local('Raleway-Regular'),
url('../fonts/Raleway/Raleway-400.woff2') format('woff2'),
url('../fonts/Raleway/Raleway-400.woff') format('woff');
}
/* Raleway 500 */
@font-face {
font-family: 'Raleway';
font-style: normal;
font-weight: 500;
src: local('Raleway Medium'), local('Raleway-Medium'),
url('../fonts/Raleway/Raleway-500.woff2') format('woff2'),
url('../fonts/Raleway/Raleway-500.woff') format('woff');
}
/* Raleway 600 */
@font-face {
font-family: 'Raleway';
font-style: normal;
font-weight: 600;
src: local('Raleway SemiBold'), local('Raleway-SemiBold'),
url('../fonts/Raleway/Raleway-600.woff2') format('woff2'),
url('../fonts/Raleway/Raleway-600.woff') format('woff');
}
/* Raleway 700 */
@font-face {
font-family: 'Raleway';
font-style: normal;
font-weight: 700;
src: local('Raleway Bold'), local('Raleway-Bold'),
url('../fonts/Raleway/Raleway-700.woff2') format('woff2'),
url('../fonts/Raleway/Raleway-700.woff') format('woff');
}
/* Rubik 400 */
@font-face {
font-family: 'Rubik';
font-style: normal;
font-weight: 400;
src: local('Rubik'), local('Rubik-Regular'), url('../fonts/Rubik/Rubik-400.woff2') format('woff2'),
url('../fonts/Rubik/Rubik-400.woff') format('woff');
}
/* Rubik 500 */
@font-face {
font-family: 'Rubik';
font-style: normal;
font-weight: 500;
src: local('Rubik Medium'), local('Rubik-Medium'),
url('../fonts/Rubik/Rubik-500.woff2') format('woff2'),
url('../fonts/Rubik/Rubik-500.woff') format('woff');
}
/* Rubik 700 */
@font-face {
font-family: 'Rubik';
font-style: normal;
font-weight: 700;
src: local('Rubik Bold'), local('Rubik-Bold'),
url('../fonts/Rubik/Rubik-700.woff2') format('woff2'),
url('../fonts/Rubik/Rubik-700.woff') format('woff');
}
/* Source Sans Pro 400 */
@font-face {
font-family: 'Source Sans Pro';
font-style: normal;
font-weight: 400;
src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'),
url('../fonts/SourceSansPro/SourceSansPro-400.woff2') format('woff2'),
url('../fonts/SourceSansPro/SourceSansPro-400.woff') format('woff');
}
/* Source Sans Pro 600 */
@font-face {
font-family: 'Source Sans Pro';
font-style: normal;
font-weight: 600;
src: local('Source Sans Pro SemiBold'), local('SourceSansPro-SemiBold'),
url('../fonts/SourceSansPro/SourceSansPro-600.woff2') format('woff2'),
url('../fonts/SourceSansPro/SourceSansPro-600.woff') format('woff');
}
/* Source Sans Pro 700 */
@font-face {
font-family: 'Source Sans Pro';
font-style: normal;
font-weight: 700;
src: local('Source Sans Pro Bold'), local('SourceSansPro-Bold'),
url('../fonts/SourceSansPro/SourceSansPro-700.woff2') format('woff2'),
url('../fonts/SourceSansPro/SourceSansPro-700.woff') format('woff');
}
/* Titillium Web 400 */
@font-face {
font-family: 'Titillium Web';
font-style: normal;
font-weight: 400;
src: local('Titillium Web Regular'), local('TitilliumWeb-Regular'),
url('../fonts/TitilliumWeb/TitilliumWeb-400.woff2') format('woff2'),
url('../fonts/TitilliumWeb/TitilliumWeb-400.woff') format('woff');
}
/* Titillium Web 600 */
@font-face {
font-family: 'Titillium Web';
font-style: normal;
font-weight: 600;
src: local('Titillium Web SemiBold'), local('TitilliumWeb-SemiBold'),
url('../fonts/TitilliumWeb/TitilliumWeb-600.woff2') format('woff2'),
url('../fonts/TitilliumWeb/TitilliumWeb-600.woff') format('woff');
}
/* Titillium Web 700 */
@font-face {
font-family: 'Titillium Web';
font-style: normal;
font-weight: 700;
src: local('Titillium Web Bold'), local('TitilliumWeb-Bold'),
url('../fonts/TitilliumWeb/TitilliumWeb-700.woff2') format('woff2'),
url('../fonts/TitilliumWeb/TitilliumWeb-700.woff') format('woff');
}
/* Ubuntu 400 */
@font-face {
font-family: 'Ubuntu';
font-style: normal;
font-weight: 400;
src: local('Ubuntu Regular'), local('Ubuntu-Regular'),
url('../fonts/Ubuntu/Ubuntu-400.woff2') format('woff2'),
url('../fonts/Ubuntu/Ubuntu-400.woff') format('woff');
}
/* Ubuntu 500 */
@font-face {
font-family: 'Ubuntu';
font-style: normal;
font-weight: 500;
src: local('Ubuntu Medium'), local('Ubuntu-Medium'),
url('../fonts/Ubuntu/Ubuntu-500.woff2') format('woff2'),
url('../fonts/Ubuntu/Ubuntu-500.woff') format('woff');
}
/* Ubuntu 700 */
@font-face {
font-family: 'Ubuntu';
font-style: normal;
font-weight: 700;
src: local('Ubuntu Bold'), local('Ubuntu-Bold'),
url('../fonts/Ubuntu/Ubuntu-700.woff2') format('woff2'),
url('../fonts/Ubuntu/Ubuntu-700.woff') format('woff');
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -12,6 +12,7 @@ import SkillsTab from './tabs/Skills';
import ExtrasTab from './tabs/Extras';
import LanguagesTab from './tabs/Languages';
import ReferencesTab from './tabs/References';
import HobbiesTab from './tabs/Hobbies';
const LeftSidebar = () => {
const context = useContext(AppContext);
@ -26,6 +27,7 @@ const LeftSidebar = () => {
{ key: 'awards', name: data.awards.heading },
{ key: 'certifications', name: data.certifications.heading },
{ key: 'skills', name: data.skills.heading },
{ key: 'hobbies', name: data.hobbies.heading },
{ key: 'languages', name: data.languages.heading },
{ key: 'references', name: data.references.heading },
{ key: 'extras', name: data.extras.heading },
@ -45,25 +47,27 @@ const LeftSidebar = () => {
const renderTabs = () => {
switch (currentTab) {
case tabs[0].key:
case 'profile':
return <ProfileTab data={data} onChange={onChange} />;
case tabs[1].key:
case 'objective':
return <ObjectiveTab data={data} onChange={onChange} />;
case tabs[2].key:
case 'work':
return <WorkTab data={data} onChange={onChange} />;
case tabs[3].key:
case 'education':
return <EducationTab data={data} onChange={onChange} />;
case tabs[4].key:
case 'awards':
return <AwardsTab data={data} onChange={onChange} />;
case tabs[5].key:
case 'certifications':
return <CertificationsTab data={data} onChange={onChange} />;
case tabs[6].key:
case 'skills':
return <SkillsTab data={data} onChange={onChange} />;
case tabs[7].key:
case 'hobbies':
return <HobbiesTab data={data} onChange={onChange} />;
case 'languages':
return <LanguagesTab data={data} onChange={onChange} />;
case tabs[8].key:
case 'references':
return <ReferencesTab data={data} onChange={onChange} />;
case tabs[9].key:
case 'extras':
return <ExtrasTab data={data} onChange={onChange} />;
default:
return null;

View File

@ -0,0 +1,133 @@
import React, { useState, useContext } from 'react';
import AppContext from '../../../context/AppContext';
import Checkbox from '../../../shared/Checkbox';
import TextField from '../../../shared/TextField';
import { addItem, deleteItem, moveItemUp, moveItemDown } from '../../../utils';
import ItemHeading from '../../../shared/ItemHeading';
const HobbiesTab = ({ data, onChange }) => {
const context = useContext(AppContext);
const { dispatch } = context;
return (
<>
<div className="my-6 grid grid-cols-6 items-center">
<div className="col-span-1">
<Checkbox
checked={data.hobbies.enable}
onChange={v => onChange('data.hobbies.enable', v)}
/>
</div>
<div className="col-span-5">
<TextField
placeholder="Heading"
value={data.hobbies.heading}
onChange={v => onChange('data.hobbies.heading', v)}
/>
</div>
</div>
<hr className="my-6" />
{data.hobbies.items.map((x, index) => (
<Item item={x} key={index} index={index} onChange={onChange} dispatch={dispatch} />
))}
<AddItem heading={data.hobbies.heading} dispatch={dispatch} />
</>
);
};
const Form = ({ item, onChange }) => {
return (
<input
className="appearance-none block w-full bg-gray-200 text-gray-700 border border-gray-200 rounded py-3 px-4 leading-tight focus:outline-none focus:bg-white focus:border-gray-500"
placeholder="Beatboxing"
value={item}
onChange={e => onChange(e.target.value)}
type="text"
/>
);
};
const AddItem = ({ heading, dispatch }) => {
const [isOpen, setOpen] = useState(false);
const [item, setItem] = useState('');
const add = () => {
if (item === '') return;
addItem(dispatch, 'hobbies', item);
setItem('');
};
return (
<div className="my-4 border border-gray-200 rounded p-5">
<ItemHeading heading={heading} setOpen={setOpen} isOpen={isOpen} />
<div className={`mt-6 ${isOpen ? 'block' : 'hidden'}`}>
<div className="grid grid-cols-4 gap-4">
<div className="col-span-3">
<Form item={item} onChange={setItem} />
</div>
<button
type="button"
onClick={add}
className="col-span-1 bg-gray-600 hover:bg-gray-700 text-sm font-medium rounded"
>
<div className="flex justify-center items-center">
<i className="material-icons font-bold text-white text-lg">add</i>
</div>
</button>
</div>
</div>
</div>
);
};
const Item = ({ item, index, onChange, dispatch }) => {
const identifier = `data.hobbies.items[${index}]`;
return (
<div className="my-4 grid grid-cols-12">
<div className="col-span-9">
<Form item={item} onChange={v => onChange(identifier, v)} />
</div>
<button
type="button"
onClick={() => moveItemUp(dispatch, 'hobbies', item)}
className="col-span-1 text-gray-600 hover:text-red-600 text-sm font-medium"
>
<div className="flex justify-end items-center">
<i className="material-icons font-bold text-lg">arrow_upward</i>
</div>
</button>
<button
type="button"
onClick={() => moveItemDown(dispatch, 'hobbies', item)}
className="col-span-1 text-gray-600 hover:text-red-600 text-sm font-medium"
>
<div className="flex justify-end items-center">
<i className="material-icons font-bold text-lg">arrow_downward</i>
</div>
</button>
<button
type="button"
onClick={() => deleteItem(dispatch, 'hobbies', item)}
className="col-span-1 text-gray-600 hover:text-red-600 text-sm font-medium"
>
<div className="flex justify-end items-center">
<i className="material-icons font-bold text-lg">close</i>
</div>
</button>
</div>
);
};
export default HobbiesTab;

View File

@ -3,7 +3,7 @@ import React, { useState, useContext } from 'react';
import AppContext from '../../../context/AppContext';
import Checkbox from '../../../shared/Checkbox';
import TextField from '../../../shared/TextField';
import { addItem, deleteItem } from '../../../utils';
import { addItem, deleteItem, moveItemUp, moveItemDown } from '../../../utils';
import ItemHeading from '../../../shared/ItemHeading';
const SkillsTab = ({ data, onChange }) => {
@ -92,18 +92,38 @@ const Item = ({ item, index, onChange, dispatch }) => {
const identifier = `data.skills.items[${index}]`;
return (
<div className="my-4 grid grid-cols-6 gap-4">
<div className="col-span-5">
<div className="my-4 grid grid-cols-12">
<div className="col-span-9">
<Form item={item} onChange={v => onChange(identifier, v)} />
</div>
<button
type="button"
onClick={() => moveItemUp(dispatch, 'skills', item)}
className="col-span-1 text-gray-600 hover:text-red-600 text-sm font-medium"
>
<div className="flex justify-end items-center">
<i className="material-icons font-bold text-lg">arrow_upward</i>
</div>
</button>
<button
type="button"
onClick={() => moveItemDown(dispatch, 'skills', item)}
className="col-span-1 text-gray-600 hover:text-red-600 text-sm font-medium"
>
<div className="flex justify-end items-center">
<i className="material-icons font-bold text-lg">arrow_downward</i>
</div>
</button>
<button
type="button"
onClick={() => deleteItem(dispatch, 'skills', item)}
className="col-span-1 text-gray-600 hover:text-red-600 text-sm font-medium"
>
<div className="flex justify-end items-center">
<i className="material-icons font-bold text-lg pr-4">close</i>
<i className="material-icons font-bold text-lg">close</i>
</div>
</button>
</div>

View File

@ -24,47 +24,52 @@ const initialState = {
email: '',
},
objective: {
enable: false,
enable: true,
heading: 'Objective',
body: '',
},
work: {
enable: false,
enable: true,
heading: 'Work Experience',
items: [],
},
education: {
enable: false,
enable: true,
heading: 'Education',
items: [],
},
awards: {
enable: false,
enable: true,
heading: 'Honors & Awards',
items: [],
},
certifications: {
enable: false,
enable: true,
heading: 'Certifications',
items: [],
},
skills: {
enable: false,
heading: 'Skills & Hobbies',
enable: true,
heading: 'Skills',
items: [],
},
hobbies: {
enable: true,
heading: 'Hobbies',
items: [],
},
languages: {
enable: false,
enable: true,
heading: 'Languages',
items: [],
},
references: {
enable: false,
enable: true,
heading: 'References',
items: [],
},
extras: {
enable: false,
enable: true,
heading: 'Personal Information',
items: [],
},
@ -97,7 +102,7 @@ const reducer = (state, { type, payload }) => {
return set({ ...state }, `data.${payload.key}.items`, items);
case 'delete_item':
items = get({ ...state }, `data.${payload.key}.items`, []);
remove(items, (x) => x === payload.value);
remove(items, x => x === payload.value);
return set({ ...state }, `data.${payload.key}.items`, items);
case 'move_item_up':
items = get({ ...state }, `data.${payload.key}.items`, []);

View File

@ -24,7 +24,7 @@
},
"license": {
"heading": "Thông tin Giấy phép",
"body": "Dự án này được điều chỉnh bởi Giấy phép MIT, bạn có thể đọc thêm về nó dưới đây. Về cơ bản, bạn được sử dụng dự án này ở bất kì đâu, chỉ cần bạn công nhận tác giả gốc.",
"body": "Dự án này được điều chỉnh bởi Giấy phép MIT, bạn có thể đọc thêm về nó dưới đây. Về cơ bản, bạn được xử dụng dự án này ở bất kì đâu, chỉ cần bạn công nhận tác giả gốc.",
"buttons": {
"mitLicense": "Giấy phép MIT"
}

View File

@ -1,12 +1,5 @@
/* Google Fonts */
@import url('https://fonts.googleapis.com/css2?family=Lato:wght@400;700&display=swap');
@import url('https://fonts.googleapis.com/css2?family=Nunito:wght@400;600;700&display=swap');
@import url('https://fonts.googleapis.com/css2?family=Open+Sans:wght@400;600;700&display=swap');
@import url('https://fonts.googleapis.com/css2?family=Raleway:wght@400;500;600;700&display=swap');
@import url('https://fonts.googleapis.com/css2?family=Rubik:wght@400;500&display=swap');
@import url('https://fonts.googleapis.com/css2?family=Source+Sans+Pro:wght@400;600;700&display=swap');
@import url('https://fonts.googleapis.com/css2?family=Titillium+Web:wght@400;600;700&display=swap');
@import url('https://fonts.googleapis.com/css2?family=Ubuntu:wght@400;500;700&display=swap');
@import './assets/css/animate.css';
@import './assets/css/fonts.css';
* {
-ms-overflow-style: none;

View File

@ -3,17 +3,21 @@ import React from 'react';
const Checkbox = ({ checked, onChange, icon = 'check', size = '2rem' }) => {
return (
<div
className="bg-white border-2 rounded border-gray-400 hover:border-gray-500 flex flex-shrink-0 justify-center items-center mr-2 focus-within:border-blue-500 cursor-pointer"
className="relative bg-white border-2 rounded border-gray-400 hover:border-gray-500 flex flex-shrink-0 justify-center items-center mr-2 focus-within:border-blue-500 cursor-pointer"
style={{ width: size, height: size }}
>
<input
type="checkbox"
style={{ width: size, height: size }}
className="opacity-0 absolute cursor-pointer"
className="opacity-0 absolute cursor-pointer z-20"
checked={checked}
onChange={e => onChange(e.target.checked)}
/>
<i className="material-icons fill-current hidden text-sm font-bold text-gray-800 cursor-pointer">
<i
className={`absolute material-icons ${
checked ? 'opacity-100' : 'opacity-0'
} text-sm text-gray-800`}
>
{icon}
</i>
</div>

View File

@ -18,7 +18,7 @@ const PageController = () => {
id="pageController"
className="absolute z-20 opacity-75 hover:opacity-100 transition-all duration-150"
>
<div className="px-8 border border-gray-200 rounded-full bg-white flex justify-center items-center select-none">
<div className="text-2xl px-8 border border-gray-200 rounded-full bg-white flex justify-center items-center leading-none select-none">
<div className="p-3 hover:bg-gray-200 cursor-pointer flex" onClick={zoomIn}>
<i className="material-icons">zoom_in</i>
</div>

View File

@ -9,7 +9,7 @@ const PanZoomAnimation = () => {
useEffect(() => {
setTimeout(() => setAnimationVisible(true), 500);
setTimeout(() => setAnimationVisible(false), 4500);
setTimeout(() => setAnimationVisible(false), 3000);
}, []);
return (

View File

@ -93,6 +93,21 @@ const Castform = () => {
</div>
);
const HobbyItem = x => (
<li key={x} className="text-sm my-2">
{x}
</li>
);
const Hobbies = () =>
data.hobbies &&
data.hobbies.enable && (
<div>
<Heading title={data.hobbies.heading} />
<ul className="list-none px-5">{data.hobbies.items.map(HobbyItem)}</ul>
</div>
);
const Objective = () =>
data.objective && data.objective.enable && <p className="m-5 text-sm">{data.objective.body}</p>;
@ -251,7 +266,7 @@ const Castform = () => {
data.extras &&
data.extras.enable && (
<div>
<Heading title={data.extras.heading} />
<Heading light title={data.extras.heading} />
{data.extras.items.filter(x => x.enable).map(ExtraItem)}
</div>
);
@ -276,9 +291,9 @@ const Castform = () => {
<PersonalInformation />
<ContactInformation />
<Skills />
<Hobbies />
<Languages />
<Certifications />
<Extras />
</div>
<div className="col-span-8">
<Objective />
@ -286,6 +301,7 @@ const Castform = () => {
<Education />
<Awards />
<References />
<Extras />
</div>
</div>
</div>

View File

@ -144,7 +144,21 @@ const Celebi = () => {
<Heading title="Skills" className="w-3/4 mx-auto" />
<ul className="list-none text-sm">
{data.skills.items.map(x => (
<li key="x" className="my-2">
<li key={x} className="my-2">
{x}
</li>
))}
</ul>
</div>
);
const Hobbies = () =>
data.hobbies.enable && (
<div className="mb-6">
<Heading title="Hobbies" className="w-3/4 mx-auto" />
<ul className="list-none text-sm">
{data.hobbies.items.map(x => (
<li key={x} className="my-2">
{x}
</li>
))}
@ -266,6 +280,7 @@ const Celebi = () => {
<Photo />
<Contact />
<Skills />
<Hobbies />
<Languages />
<Certifications />
<Extras />

View File

@ -79,6 +79,21 @@ const Gengar = () => {
</div>
);
const HobbyItem = x => (
<li key={x} className="text-sm py-1">
{x}
</li>
);
const Hobbies = () =>
data.hobbies &&
data.hobbies.enable && (
<div className="mb-6">
<Heading title={data.hobbies.heading} />
<ul>{data.hobbies.items.map(HobbyItem)}</ul>
</div>
);
const EducationItem = x => (
<div key={x.id} className="mb-3">
<div className="flex justify-between items-center">
@ -260,7 +275,7 @@ const Gengar = () => {
<ContactItem icon="phone" value={data.profile.phone} link={`tel:${data.profile.phone}`} />
<ContactItem
icon="alternate_email"
icon="email"
value={data.profile.email}
link={`mailto:${data.profile.email}`}
/>
@ -285,6 +300,7 @@ const Gengar = () => {
style={{ backgroundColor: `rgba(${r}, ${g}, ${b}, 0.1)` }}
>
<Skills />
<Hobbies />
<Languages />
<Education />
<Certifications />

View File

@ -31,10 +31,6 @@ const Glalie = () => {
<div className="tracking-wide text-xs uppercase font-medium">{data.profile.subtitle}</div>
);
const Divider = () => (
<div className="w-1/2 mx-auto my-2 border-b-2" style={{ borderColor: theme.colors.accent }} />
);
const ContactItem = ({ title, value }) =>
value && (
<div className="flex flex-col">
@ -47,14 +43,14 @@ const Glalie = () => {
const ContactInformation = () => (
<div
className="w-full border-2 pl-4 pr-4 pb-6"
className="w-full border-2 pl-4 pr-4 mb-6"
style={{
borderColor: theme.colors.accent,
}}
>
<div
className="inline-block relative px-4"
style={{ top: '-.9em', color: theme.colors.accent }}
style={{ top: '-.75em', color: theme.colors.accent }}
>
<h2 className="flex">
<i className="material-icons">flare</i>
@ -191,6 +187,23 @@ const Glalie = () => {
</div>
);
const HobbyItem = x => (
<li key={x} className="text-xs font-medium">
{x}
</li>
);
const Hobbies = () =>
data.hobbies &&
data.hobbies.enable && (
<div>
<Heading title={data.hobbies.heading} />
<ul className="pt-2 grid grid-cols-2 row-gap-3 text-left">
{data.hobbies.items.map(HobbyItem)}
</ul>
</div>
);
const LanguageItem = x => (
<div key={x.id} className="grid grid-cols-2 items-center py-2">
<h6 className="text-xs font-medium text-left">{x.key}</h6>
@ -267,33 +280,28 @@ const Glalie = () => {
>
<div className="grid grid-cols-12">
<div
className="h-full col-span-4 p-8 grid grid-cols-1 row-gap-8 text-center"
className="h-full col-span-4 p-8 grid grid-cols-1 row-gap-4 text-center"
style={{ backgroundColor: `rgba(${r}, ${g}, ${b}, 0.1)` }}
>
<div className="grid grid-cols-1 row-gap-4">
<div className="grid grid-cols-1 gap-2">
<Photo />
<FullName />
<Subtitle />
</div>
<Divider />
<ContactInformation />
<Divider />
<Objective />
<Hobbies />
<Languages />
<Certifications />
</div>
<div className="col-span-8 p-8">
<div className="grid grid-cols-1 row-gap-6">
<Work />
<Education />
<Skills />
<Awards />
<References />
<Extras />
</div>
<div className="col-span-8 p-8 grid grid-cols-1 row-gap-4">
<Work />
<Education />
<Skills />
<Awards />
<References />
<Extras />
</div>
</div>
</div>

View File

@ -145,6 +145,28 @@ const Onyx = () => {
</div>
);
const HobbyItem = x => (
<span
key={x}
className="text-xs rounded-full px-3 py-1 font-medium my-2 mr-2"
style={{
backgroundColor: theme.colors.primary,
color: theme.colors.background,
}}
>
{x}
</span>
);
const Hobbies = () =>
data.hobbies &&
data.hobbies.enable && (
<div>
<Heading title={data.hobbies.heading} />
<div className="mt-1 flex flex-wrap">{data.hobbies.items.map(HobbyItem)}</div>
</div>
);
const SkillItem = x => (
<span
key={x}
@ -227,7 +249,7 @@ const Onyx = () => {
data.extras.enable && (
<div>
<Heading title={data.extras.heading} />
<table className="w-2/3 table-auto">
<table className="table-auto">
<tbody>{data.extras.items.filter(x => x.enable).map(ExtraItem)}</tbody>
</table>
</div>
@ -256,7 +278,7 @@ const Onyx = () => {
link={`http://${data.profile.website}`}
/>
<ContactItem
icon="alternate_email"
icon="email"
value={data.profile.email}
link={`mailto:${data.profile.email}`}
/>
@ -277,11 +299,15 @@ const Onyx = () => {
<div className="grid grid-cols-2 gap-6">
<Skills />
<Languages />
<Hobbies />
</div>
<References />
<Extras />
<div className="grid grid-cols-2 gap-6">
<Extras />
<Languages />
</div>
</div>
);
};

View File

@ -76,6 +76,24 @@ const Pikachu = () => {
</div>
);
const HobbyItem = x => (
<span
key={x}
className="leading-none rounded-lg text-sm font-medium bg-gray-300 py-3 my-1 px-4"
>
{x}
</span>
);
const Hobbies = () =>
data.hobbies &&
data.hobbies.enable && (
<div>
<Heading title={data.hobbies.heading} />
<div className="flex flex-col mb-6">{data.hobbies.items.map(HobbyItem)}</div>
</div>
);
const ReferenceItem = x => (
<div key={x.id} className="flex flex-col">
<h6 className="text-sm font-medium">{x.name}</h6>
@ -91,7 +109,7 @@ const Pikachu = () => {
data.references.enable && (
<div>
<Heading title={data.references.heading} />
<div className="grid grid-cols-2 gap-6">
<div className="grid grid-cols-2 gap-2 mb-6">
{data.references.items.filter(x => x.enable).map(ReferenceItem)}
</div>
</div>
@ -136,7 +154,7 @@ const Pikachu = () => {
data.extras.enable && (
<div>
<Heading title={data.extras.heading} />
<div className="flex flex-col mb-6">
<div className="grid grid-cols-2">
{data.extras.items.filter(x => x.enable).map(ExtraItem)}
</div>
</div>
@ -169,7 +187,7 @@ const Pikachu = () => {
);
const EducationItem = x => (
<div key={x.id} className="mb-3">
<div key={x.id} className="mb-2">
<div className="flex justify-between items-center">
<div>
<h6 className="font-semibold">{x.name}</h6>
@ -200,7 +218,7 @@ const Pikachu = () => {
);
const AwardItem = x => (
<div key={x.id} className="mb-3">
<div key={x.id} className="mb-2">
<h6 className="font-semibold">{x.title}</h6>
<p className="text-xs">{x.subtitle}</p>
<ReactMarkdown className="mt-2 text-sm" source={x.description} />
@ -266,7 +284,7 @@ const Pikachu = () => {
link={`http://${data.profile.website}`}
/>
<ContactItem
icon="alternate_email"
icon="email"
value={data.profile.email}
link={`mailto:${data.profile.email}`}
/>
@ -274,9 +292,9 @@ const Pikachu = () => {
</div>
<Skills />
<Hobbies />
<Languages />
<Certifications />
<Extras />
</div>
<div className="col-span-8">
@ -284,6 +302,7 @@ const Pikachu = () => {
<Education />
<Awards />
<References />
<Extras />
</div>
</div>
</div>