clearing the slate

This commit is contained in:
Amruth Pillai
2020-07-02 21:23:03 +05:30
parent 58f0cc7f30
commit d2e3227d01
912 changed files with 0 additions and 38944 deletions

View File

@ -1,79 +0,0 @@
@-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;
}
}

View File

@ -1,304 +0,0 @@
/* 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-Regular.woff2') format('woff2'),
url('../fonts/MaterialIcons/MaterialIcons-Regular.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');
}

View File

@ -1,304 +0,0 @@
{
"data": {
"profile": {
"heading": "Profile",
"photo": "https://i.imgur.com/Icr472Z.jpg",
"firstName": "Nancy",
"lastName": "Jackson",
"subtitle": "Customer Sales Representative",
"address": {
"line1": "3879 Gateway Avenue",
"line2": "Bakersfield,",
"line3": "California, USA"
},
"phone": "+1 661-808-4188",
"website": "nancyontheweb.com",
"email": "nancyjack43@gmail.com"
},
"objective": {
"enable": true,
"heading": "Professional Objective",
"body": "To obtain a job within my chosen field that will challenge me and allow me to use my education, skills and past experiences in a way that is mutually beneficial to both myself and my employer and allow for future growth and advancement."
},
"work": {
"enable": true,
"heading": "Work Experience",
"items": [
{
"id": "a208ec03-76e3-4428-ac5b-e17c3de4ac18",
"title": "On Point Electronics, NYC, NY",
"role": "Customer Service Representative",
"start": "Jan 2013",
"end": "July 2018",
"description": "- Organized customer information and account data for business planning and customer service purposes.\n- Created excel spreadsheets to track customer data and perform intense reconciliation process.\n- Received 97% positive customer survey results.\n- Speed on calls was 10% above team average. \n**Key Achievement:** Designed and executed an automatized system for following up with customers, increasing customer retention by 22%.",
"enabled": true,
"enable": true
},
{
"id": "bd8649f2-42d1-4424-acaf-a02c08c3322c",
"title": "Excelsior Communications, NYC, NY",
"role": "Customer Service Representative",
"start": "Oct 2009",
"end": "Dec 2012",
"description": "- Worked as a full time customer service rep in a high volume call center.\n- Received \"Associate of the Month\" award six times.\n- Chosen as an example for other associates in trainings. \n**Key Achievement:** Received Customer Appreciation bonus in three of four years.",
"enabled": true,
"enable": true
},
{
"id": "dde47711-a7a6-424f-9751-73483a0ef4ed",
"title": "Pizza Hut, Newark, NJ",
"role": "Waitress",
"start": "Aug 2005",
"end": "Sep 2009",
"description": "- Worked passionately in customer service in a high volume restaurant.\n- Completed the FAST customer service training class.\n- Maintained a high tip average thanks to consistent customer satisfaction.",
"enabled": true,
"enable": true
}
]
},
"education": {
"enable": true,
"heading": "Education",
"items": [
{
"id": "624f32ab-2d78-4052-86ad-1354fd41d754",
"name": "The City College of New York, NYC, NY",
"major": "MS in Computer Science",
"start": "Sep 2001",
"end": "Aug 2002",
"grade": "7.2 CGPA",
"description": "",
"enabled": true,
"enable": true
},
{
"id": "71a9852f-ed14-4281-bff2-4db9a2275978",
"name": "University of California, Berkeley, CA",
"major": "BS in Computer Science",
"start": "Sep 1997",
"end": "Aug 2001",
"grade": "8.4 CGPA",
"description": "",
"enabled": true,
"enable": true
}
]
},
"awards": {
"enable": true,
"heading": "Honors & Awards",
"items": [
{
"id": "121f0976-18cb-4e46-921d-0e156b6bf7fb",
"title": "Cast Member of a Musical - Oklahoma",
"subtitle": "Winter, 2007",
"description": "",
"enable": true
},
{
"id": "e5f27346-72ad-4d4f-bab3-726a111e4932",
"title": "Class Representative to ASB",
"subtitle": "Fall, 2008",
"description": "",
"enable": true
},
{
"id": "f71ba9bc-8c14-46b5-99dd-e1333e9aceb9",
"title": "Most Improved - Varsity Soccer",
"subtitle": "Fall, 2007",
"description": "",
"enable": true
}
]
},
"certifications": {
"enable": true,
"heading": "Certifications",
"items": [
{
"id": "e5170d99-b21d-4131-a7dc-26a4670037f5",
"title": "CCNP",
"subtitle": "Cisco Systems",
"description": "",
"enable": true
},
{
"id": "788e4042-9ecb-40c5-849d-7688b4e23888",
"title": "VCP6-DCV",
"subtitle": "VMWare",
"description": "",
"enable": true
},
{
"id": "97a1a8d9-3c03-47fb-93ab-e84f864ffe17",
"title": "DCUCI 642-999",
"subtitle": "Cisco Systems",
"description": "",
"enable": true
}
]
},
"skills": {
"enable": true,
"heading": "Skills",
"items": [
{
"id": "2562d78a-3459-4370-8604-c81b00738db1",
"skill": "Customer Service Expertise"
},
{
"id": "58c31587-9770-4522-a34c-f5ad92fe33e5",
"skill": "High-Volume Call Center"
},
{
"id": "7aa9a4b1-a2bb-4bcd-8711-b66c0d246971",
"skill": "Team Leader/Problem Solver"
},
{
"id": "e7fd33e8-5d77-462d-8115-5be57f52832e",
"skill": "Call Center Management"
},
{
"id": "7bad2af1-c24d-4e01-b68b-be01cfa784ce",
"skill": "Teambuilding & Training"
},
{
"id": "64fe1710-c2d1-4f53-922e-a5d751eee967",
"skill": "Continuous Improvement"
}
]
},
"hobbies": {
"enable": true,
"heading": "Hobbies",
"items": [
{
"id": "dd2efad7-e900-4384-bdc0-b2ab5f62bb71",
"hobby": "Poetry"
},
{
"id": "96023eb7-8c93-4b1d-b581-b8fc4107351a",
"hobby": "Travelling"
},
{
"id": "7e5a6168-9cbe-4fe6-b9b9-43a47d8bb15a",
"hobby": "Beatboxing"
},
{
"id": "dd7f4ffd-9c16-4dbf-8968-1165b9e30db8",
"hobby": "Sketching"
}
]
},
"languages": {
"enable": true,
"heading": "Languages",
"items": [
{
"id": "9d34cfcb-c9f0-4d25-ab27-cf81652dd1d0",
"key": "English (US)",
"value": 5,
"enable": true,
"level": "",
"rating": 5
},
{
"id": "3511a86b-7ea9-44ac-8144-6acc7f3bd54f",
"key": "Spanish",
"value": 4,
"enable": true,
"rating": 4
},
{
"id": "d1e17542-f7cc-473a-aa0e-978765907454",
"key": "Japanese",
"value": 4,
"enable": true,
"level": "N4",
"rating": 2
},
{
"id": "b1e8442a-7059-4c6f-8a9c-415383133b0e",
"key": "German",
"value": 3,
"enable": true,
"level": "B1",
"rating": 0
}
]
},
"references": {
"enable": true,
"heading": "References",
"items": [
{
"id": "ba3662e6-29cb-4a03-9766-b3618d1621f3",
"name": "Lorraine Beasley",
"position": "Head of HR, Carson Logistics",
"phone": "+1 661-808-4188",
"email": "l.beasley@carsonlogistics.com",
"description": "",
"enable": true
},
{
"id": "62fd3293-0e93-4242-882b-ae19b7865fef",
"name": "Mikhail Nabakov",
"position": "Assistant Manager, Bullseye",
"phone": "+1 661-808-4188",
"email": "mikhail@bullseyemart.nyc",
"description": "",
"enable": true
},
{
"id": "eaab2e32-8591-497c-8676-d122cf3a4798",
"name": "Katherine Rose",
"position": "CEO , DownToPlay",
"phone": "+1 661-808-4188",
"email": "k.rose@downtoplay.xyz",
"description": "",
"enable": true
}
]
},
"extras": {
"enable": true,
"heading": "Additional Information",
"items": [
{
"id": "3834a270-2c01-4105-b670-80863c955347",
"key": "Skype",
"value": "@NancyJack5436",
"enable": true
},
{
"id": "b0c4fd85-cfda-421e-bd31-008b9aad1dfe",
"key": "Hometown",
"value": "New Jersey, NY",
"enable": true
},
{
"id": "7f0a4971-9770-4ca7-b135-2b0ccd867879",
"key": "Hobbies",
"value": "Playing Soccer & Guitar",
"enable": true
},
{
"id": "e17552a2-e7e9-4605-8145-795e2b62c30e",
"key": "Valid Work Visas",
"value": "US, UK, EU",
"enable": true
}
]
}
},
"theme": {
"layout": "castform",
"font": { "family": "Montserrat" },
"colors": {
"background": "#ffffff",
"primary": "#212121",
"accent": "#f44336"
}
}
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

View File

@ -1,5 +0,0 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

View File

@ -1,74 +0,0 @@
/* eslint-disable jsx-a11y/media-has-caption */
import React, { useRef, useEffect, useContext, Suspense } from 'react';
import { useTranslation } from 'react-i18next';
import { PanZoom } from 'react-easy-panzoom';
import AppContext from '../../context/AppContext';
import PageContext from '../../context/PageContext';
import LeftSidebar from '../LeftSidebar/LeftSidebar';
import RightSidebar from '../RightSidebar/RightSidebar';
import templates from '../../templates';
import PageController from '../../shared/PageController';
import PrintDialog from '../../shared/PrintDialog';
import PanZoomAnimation from '../../shared/PanZoomAnimation';
const App = () => {
const pageRef = useRef(null);
const panZoomRef = useRef(null);
const { i18n } = useTranslation();
const context = useContext(AppContext);
const { state, dispatch } = context;
const { theme, settings } = state;
const pageContext = useContext(PageContext);
const { setPageRef, setPanZoomRef } = pageContext;
useEffect(() => {
setPageRef(pageRef);
setPanZoomRef(panZoomRef);
i18n.changeLanguage(settings.language);
const storedState = JSON.parse(localStorage.getItem('state'));
dispatch({ type: 'import_data', payload: storedState });
}, [dispatch, setPageRef, setPanZoomRef, i18n, settings.language]);
return (
<Suspense fallback="Loading...">
<div className="h-screen grid grid-cols-5 items-center">
<LeftSidebar />
<div className="relative z-10 h-screen overflow-hidden col-span-3 flex justify-center items-center">
<PanZoom
ref={panZoomRef}
minZoom="0.4"
autoCenter
autoCenterZoomLevel={0.7}
enableBoundingBox
boundaryRatioVertical={0.8}
boundaryRatioHorizontal={0.8}
style={{ outline: 'none' }}
>
<div id="page" ref={pageRef} className="shadow-2xl break-words">
{templates.find(x => theme.layout.toLowerCase() === x.key).component()}
</div>
</PanZoom>
<PageController />
</div>
<div id="printPage" className="break-words">
{templates.find(x => theme.layout.toLowerCase() === x.key).component()}
</div>
<RightSidebar />
<PanZoomAnimation />
<PrintDialog />
</div>
</Suspense>
);
};
export default App;

View File

@ -1,88 +0,0 @@
import React, { useState, useContext } from 'react';
import AppContext from '../../context/AppContext';
import TabBar from '../../shared/TabBar';
import ProfileTab from './tabs/Profile';
import ObjectiveTab from './tabs/Objective';
import WorkTab from './tabs/Work';
import EducationTab from './tabs/Education';
import AwardsTab from './tabs/Awards';
import CertificationsTab from './tabs/Certifications';
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);
const { state, dispatch } = context;
const { data } = state;
const tabs = [
{ key: 'profile', name: data.profile.heading },
{ key: 'objective', name: data.objective.heading },
{ key: 'work', name: data.work.heading },
{ key: 'education', name: data.education.heading },
{ 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 },
];
const [currentTab, setCurrentTab] = useState(tabs[0].key);
const onChange = (key, value) => {
dispatch({
type: 'on_input',
payload: {
key,
value,
},
});
dispatch({ type: 'save_data' });
};
const renderTabs = () => {
switch (currentTab) {
case 'profile':
return <ProfileTab data={data} onChange={onChange} />;
case 'objective':
return <ObjectiveTab data={data} onChange={onChange} />;
case 'work':
return <WorkTab data={data} onChange={onChange} />;
case 'education':
return <EducationTab data={data} onChange={onChange} />;
case 'awards':
return <AwardsTab data={data} onChange={onChange} />;
case 'certifications':
return <CertificationsTab data={data} onChange={onChange} />;
case 'skills':
return <SkillsTab data={data} onChange={onChange} />;
case 'hobbies':
return <HobbiesTab data={data} onChange={onChange} />;
case 'languages':
return <LanguagesTab data={data} onChange={onChange} />;
case 'references':
return <ReferencesTab data={data} onChange={onChange} />;
case 'extras':
return <ExtrasTab data={data} onChange={onChange} />;
default:
return null;
}
};
return (
<div
id="leftSidebar"
className="animated slideInLeft z-10 py-6 h-screen bg-white col-span-1 shadow-2xl overflow-y-scroll"
>
<TabBar tabs={tabs} currentTab={currentTab} setCurrentTab={setCurrentTab} />
<div className="px-6">{renderTabs()}</div>
</div>
);
};
export default LeftSidebar;

View File

@ -1,153 +0,0 @@
import React, { useState, useContext } from 'react';
import { useTranslation } from 'react-i18next';
import { v4 as uuidv4 } from 'uuid';
import set from 'lodash/set';
import TextField from '../../../shared/TextField';
import AppContext from '../../../context/AppContext';
import Checkbox from '../../../shared/Checkbox';
import TextArea from '../../../shared/TextArea';
import { addItem } from '../../../utils';
import ItemActions from '../../../shared/ItemActions';
import AddItemButton from '../../../shared/AddItemButton';
import ItemHeading from '../../../shared/ItemHeading';
const AwardsTab = ({ data, onChange }) => {
const context = useContext(AppContext);
const { dispatch } = context;
return (
<>
<div className="mb-6 grid grid-cols-6 items-center">
<div className="col-span-1">
<Checkbox
checked={data.awards.enable}
onChange={v => onChange('data.awards.enable', v)}
/>
</div>
<div className="col-span-5">
<TextField
placeholder="Heading"
value={data.awards.heading}
onChange={v => onChange('data.awards.heading', v)}
/>
</div>
</div>
<hr className="my-6" />
{data.awards.items.map((x, index) => (
<Item
item={x}
key={x.id}
index={index}
onChange={onChange}
dispatch={dispatch}
first={index === 0}
last={index === data.awards.items.length - 1}
/>
))}
<AddItem heading={data.awards.heading} dispatch={dispatch} />
</>
);
};
const Form = ({ item, onChange, identifier = '' }) => {
const { t } = useTranslation(['leftSidebar', 'app']);
return (
<div>
<TextField
className="mb-6"
label={t('awards.title.label')}
placeholder="Code For Good Hackathon"
value={item.title}
onChange={v => onChange(`${identifier}title`, v)}
/>
<TextField
className="mb-6"
label={t('awards.subtitle.label')}
placeholder="First Place, National Level"
value={item.subtitle}
onChange={v => onChange(`${identifier}subtitle`, v)}
/>
<TextArea
className="mb-6"
label={t('app:item.description.label')}
value={item.description}
onChange={v => onChange(`${identifier}description`, v)}
/>
</div>
);
};
const AddItem = ({ heading, dispatch }) => {
const [isOpen, setOpen] = useState(false);
const [item, setItem] = useState({
id: uuidv4(),
enable: true,
title: '',
subtitle: '',
description: '',
});
const onChange = (key, value) => setItem(set({ ...item }, key, value));
const onSubmit = () => {
if (item.title === '') return;
addItem(dispatch, 'awards', item);
setItem({
id: uuidv4(),
enable: true,
title: '',
subtitle: '',
description: '',
});
setOpen(false);
};
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'}`}>
<Form item={item} onChange={onChange} />
<AddItemButton onSubmit={onSubmit} />
</div>
</div>
);
};
const Item = ({ item, index, onChange, dispatch, first, last }) => {
const [isOpen, setOpen] = useState(false);
const identifier = `data.awards.items[${index}].`;
return (
<div className="my-4 border border-gray-200 rounded p-5">
<ItemHeading title={item.title} setOpen={setOpen} isOpen={isOpen} />
<div className={`mt-6 ${isOpen ? 'block' : 'hidden'}`}>
<Form item={item} onChange={onChange} identifier={identifier} />
<ItemActions
dispatch={dispatch}
first={first}
identifier={identifier}
item={item}
last={last}
onChange={onChange}
type="awards"
/>
</div>
</div>
);
};
export default AwardsTab;

View File

@ -1,153 +0,0 @@
import React, { useState, useContext } from 'react';
import { useTranslation } from 'react-i18next';
import { v4 as uuidv4 } from 'uuid';
import set from 'lodash/set';
import TextField from '../../../shared/TextField';
import AppContext from '../../../context/AppContext';
import Checkbox from '../../../shared/Checkbox';
import TextArea from '../../../shared/TextArea';
import { addItem } from '../../../utils';
import ItemActions from '../../../shared/ItemActions';
import ItemHeading from '../../../shared/ItemHeading';
import AddItemButton from '../../../shared/AddItemButton';
const CertificationsTab = ({ 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.certifications.enable}
onChange={v => onChange('data.certifications.enable', v)}
/>
</div>
<div className="col-span-5">
<TextField
placeholder="Heading"
value={data.certifications.heading}
onChange={v => onChange('data.certifications.heading', v)}
/>
</div>
</div>
<hr className="my-6" />
{data.certifications.items.map((x, index) => (
<Item
item={x}
key={x.id}
index={index}
onChange={onChange}
dispatch={dispatch}
first={index === 0}
last={index === data.certifications.items.length - 1}
/>
))}
<AddItem heading={data.certifications.heading} dispatch={dispatch} />
</>
);
};
const Form = ({ item, onChange, identifier = '' }) => {
const { t } = useTranslation(['leftSidebar', 'app']);
return (
<div>
<TextField
className="mb-6"
label={t('certifications.title.label')}
placeholder="CS50: Intro to Computer Science"
value={item.title}
onChange={v => onChange(`${identifier}title`, v)}
/>
<TextField
className="mb-6"
label={t('certifications.subtitle.label')}
placeholder="Harvard University"
value={item.subtitle}
onChange={v => onChange(`${identifier}subtitle`, v)}
/>
<TextArea
className="mb-6"
label={t('app:item.description.label')}
value={item.description}
onChange={v => onChange(`${identifier}description`, v)}
/>
</div>
);
};
const AddItem = ({ heading, dispatch }) => {
const [isOpen, setOpen] = useState(false);
const [item, setItem] = useState({
id: uuidv4(),
enable: true,
title: '',
subtitle: '',
description: '',
});
const onChange = (key, value) => setItem(set({ ...item }, key, value));
const onSubmit = () => {
if (item.title === '') return;
addItem(dispatch, 'certifications', item);
setItem({
id: uuidv4(),
enable: true,
title: '',
subtitle: '',
description: '',
});
setOpen(false);
};
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'}`}>
<Form item={item} onChange={onChange} />
<AddItemButton onSubmit={onSubmit} />
</div>
</div>
);
};
const Item = ({ item, index, onChange, dispatch, first, last }) => {
const [isOpen, setOpen] = useState(false);
const identifier = `data.certifications.items[${index}].`;
return (
<div className="my-4 border border-gray-200 rounded p-5">
<ItemHeading title={item.title} setOpen={setOpen} isOpen={isOpen} />
<div className={`mt-6 ${isOpen ? 'block' : 'hidden'}`}>
<Form item={item} onChange={onChange} identifier={identifier} />
<ItemActions
dispatch={dispatch}
first={first}
identifier={identifier}
item={item}
last={last}
onChange={onChange}
type="certifications"
/>
</div>
</div>
);
};
export default CertificationsTab;

View File

@ -1,185 +0,0 @@
import React, { useState, useContext } from 'react';
import { useTranslation } from 'react-i18next';
import { v4 as uuidv4 } from 'uuid';
import set from 'lodash/set';
import TextField from '../../../shared/TextField';
import TextArea from '../../../shared/TextArea';
import AppContext from '../../../context/AppContext';
import Checkbox from '../../../shared/Checkbox';
import { addItem } from '../../../utils';
import ItemActions from '../../../shared/ItemActions';
import AddItemButton from '../../../shared/AddItemButton';
import ItemHeading from '../../../shared/ItemHeading';
const EducationTab = ({ data, onChange }) => {
const context = useContext(AppContext);
const { dispatch } = context;
return (
<>
<div className="mb-6 grid grid-cols-6 items-center">
<div className="col-span-1">
<Checkbox
checked={data.education.enable}
onChange={v => onChange('data.education.enable', v)}
/>
</div>
<div className="col-span-5">
<TextField
placeholder="Heading"
value={data.education.heading}
onChange={v => onChange('data.education.heading', v)}
/>
</div>
</div>
<hr className="my-6" />
{data.education.items.map((x, index) => (
<Item
item={x}
key={x.id}
index={index}
onChange={onChange}
dispatch={dispatch}
first={index === 0}
last={index === data.education.items.length - 1}
/>
))}
<AddItem heading={data.education.heading} dispatch={dispatch} />
</>
);
};
const Form = ({ item, onChange, identifier = '' }) => {
const { t } = useTranslation(['leftSidebar', 'app']);
return (
<div>
<TextField
className="mb-6"
label={t('education.name.label')}
placeholder="Harvard University"
value={item.name}
onChange={v => onChange(`${identifier}name`, v)}
/>
<TextField
className="mb-6"
label={t('education.major.label')}
placeholder="Masters in Computer Science"
value={item.major}
onChange={v => onChange(`${identifier}major`, v)}
/>
<TextField
className="mb-6"
label={t('education.grade.label')}
placeholder="7.2 CGPA"
value={item.grade}
onChange={v => onChange(`${identifier}grade`, v)}
/>
<div className="grid grid-cols-2 col-gap-4">
<TextField
className="mb-6"
label={t('app:item.startDate.label')}
placeholder="March 2018"
value={item.start}
onChange={v => onChange(`${identifier}start`, v)}
/>
<TextField
className="mb-6"
label={t('app:item.endDate.label')}
placeholder="June 2022"
value={item.end}
onChange={v => onChange(`${identifier}end`, v)}
/>
</div>
<TextArea
rows="5"
className="mb-6"
label={t('app:item.description.label')}
value={item.description}
onChange={v => onChange(`${identifier}description`, v)}
/>
</div>
);
};
const AddItem = ({ heading, dispatch }) => {
const [isOpen, setOpen] = useState(false);
const [item, setItem] = useState({
id: uuidv4(),
enable: true,
name: '',
major: '',
start: '',
end: '',
grade: '',
description: '',
});
const onChange = (key, value) => setItem(set({ ...item }, key, value));
const onSubmit = () => {
if (item.name === '' || item.major === '') return;
addItem(dispatch, 'education', item);
setItem({
id: uuidv4(),
enable: true,
name: '',
role: '',
start: '',
end: '',
grade: '',
description: '',
});
setOpen(false);
};
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'}`}>
<Form item={item} onChange={onChange} />
<AddItemButton onSubmit={onSubmit} />
</div>
</div>
);
};
const Item = ({ item, index, onChange, dispatch, first, last }) => {
const [isOpen, setOpen] = useState(false);
const identifier = `data.education.items[${index}].`;
return (
<div className="my-4 border border-gray-200 rounded p-5">
<ItemHeading title={item.name} setOpen={setOpen} isOpen={isOpen} />
<div className={`mt-6 ${isOpen ? 'block' : 'hidden'}`}>
<Form item={item} onChange={onChange} identifier={identifier} />
<ItemActions
dispatch={dispatch}
first={first}
identifier={identifier}
item={item}
last={last}
onChange={onChange}
type="education"
/>
</div>
</div>
);
};
export default EducationTab;

View File

@ -1,143 +0,0 @@
import React, { useState, useContext } from 'react';
import { useTranslation } from 'react-i18next';
import { v4 as uuidv4 } from 'uuid';
import set from 'lodash/set';
import TextField from '../../../shared/TextField';
import AppContext from '../../../context/AppContext';
import Checkbox from '../../../shared/Checkbox';
import { addItem } from '../../../utils';
import ItemActions from '../../../shared/ItemActions';
import ItemHeading from '../../../shared/ItemHeading';
import AddItemButton from '../../../shared/AddItemButton';
const ExtrasTab = ({ data, onChange }) => {
const context = useContext(AppContext);
const { dispatch } = context;
return (
<>
<div className="mb-6 grid grid-cols-6 items-center">
<div className="col-span-1">
<Checkbox
checked={data.extras.enable}
onChange={v => onChange('data.extras.enable', v)}
/>
</div>
<div className="col-span-5">
<TextField
placeholder="Heading"
value={data.extras.heading}
onChange={v => onChange('data.extras.heading', v)}
/>
</div>
</div>
<hr className="my-6" />
{data.extras.items.map((x, index) => (
<Item
item={x}
key={x.id}
index={index}
onChange={onChange}
dispatch={dispatch}
first={index === 0}
last={index === data.extras.items.length - 1}
/>
))}
<AddItem heading={data.extras.heading} dispatch={dispatch} />
</>
);
};
const Form = ({ item, onChange, identifier = '' }) => {
const { t } = useTranslation('leftSidebar');
return (
<div>
<TextField
className="mb-6"
label={t('extras.key.label')}
placeholder="Date of Birth"
value={item.key}
onChange={v => onChange(`${identifier}key`, v)}
/>
<TextField
className="mb-6"
label={t('extras.value.label')}
placeholder="6th August 1995"
value={item.value}
onChange={v => onChange(`${identifier}value`, v)}
/>
</div>
);
};
const AddItem = ({ heading, dispatch }) => {
const [isOpen, setOpen] = useState(false);
const [item, setItem] = useState({
id: uuidv4(),
enable: true,
key: '',
value: '',
});
const onChange = (key, value) => setItem(items => set({ ...items }, key, value));
const onSubmit = () => {
if (item.key === '' || item.value === '') return;
addItem(dispatch, 'extras', item);
setItem({
id: uuidv4(),
enable: true,
key: '',
value: '',
});
setOpen(false);
};
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'}`}>
<Form item={item} onChange={onChange} />
<AddItemButton onSubmit={onSubmit} />
</div>
</div>
);
};
const Item = ({ item, index, onChange, dispatch, first, last }) => {
const [isOpen, setOpen] = useState(false);
const identifier = `data.extras.items[${index}].`;
return (
<div className="my-4 border border-gray-200 rounded p-5">
<ItemHeading title={item.key} setOpen={setOpen} isOpen={isOpen} />
<div className={`mt-6 ${isOpen ? 'block' : 'hidden'}`}>
<Form item={item} onChange={onChange} identifier={identifier} />
<ItemActions
dispatch={dispatch}
first={first}
identifier={identifier}
item={item}
last={last}
onChange={onChange}
type="extras"
/>
</div>
</div>
);
};
export default ExtrasTab;

View File

@ -1,140 +0,0 @@
import React, { useState, useContext } from 'react';
import { v4 as uuidv4 } from 'uuid';
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.hobby}
onChange={e => onChange(e.target.value)}
type="text"
/>
);
};
const AddItem = ({ heading, dispatch }) => {
const [isOpen, setOpen] = useState(false);
const [item, setItem] = useState({
id: uuidv4(),
hobby: ''
});
const add = () => {
if (item.hobby === '') return;
addItem(dispatch, 'hobbies', item);
setItem({
id: uuidv4(),
hobby: ''
});
};
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={v => setItem({...item, hobby: v})} />
</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

@ -1,182 +0,0 @@
import set from 'lodash/set';
import React, { useContext, useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { v4 as uuidv4 } from 'uuid';
import AppContext from '../../../context/AppContext';
import AddItemButton from '../../../shared/AddItemButton';
import Checkbox from '../../../shared/Checkbox';
import Counter from '../../../shared/Counter';
import ItemActions from '../../../shared/ItemActions';
import ItemHeading from '../../../shared/ItemHeading';
import TextField from '../../../shared/TextField';
import { addItem } from '../../../utils';
const LanguagesTab = ({ data, onChange }) => {
const context = useContext(AppContext);
const { dispatch } = context;
useEffect(() => {
if (!('languages' in data)) {
dispatch({
type: 'migrate_section',
payload: {
key: 'languages',
value: {
enable: false,
heading: 'Languages',
items: [],
},
},
});
dispatch({ type: 'save_data' });
}
}, [data, dispatch]);
return (
'languages' in data && (
<>
<div className="mb-6 grid grid-cols-6 items-center">
<div className="col-span-1">
<Checkbox
checked={data.languages.enable}
onChange={v => onChange('data.languages.enable', v)}
/>
</div>
<div className="col-span-5">
<TextField
placeholder="Heading"
value={data.languages.heading}
onChange={v => onChange('data.languages.heading', v)}
/>
</div>
</div>
<hr className="my-6" />
{data.languages.items.map((x, index) => (
<Item
item={x}
key={x.id}
index={index}
onChange={onChange}
dispatch={dispatch}
first={index === 0}
last={index === data.languages.items.length - 1}
/>
))}
<AddItem heading={data.languages.heading} dispatch={dispatch} />
</>
)
);
};
const Form = ({ item, onChange, identifier = '' }) => {
const { t } = useTranslation('leftSidebar');
return (
<div>
<TextField
className="mb-6"
label={t('languages.key.label')}
placeholder="English"
value={item.key}
onChange={v => onChange(`${identifier}key`, v)}
/>
<TextField
className="mb-6"
label={t('languages.level.label')}
placeholder="B1"
value={item.level}
onChange={v => onChange(`${identifier}level`, v)}
/>
<Counter
className="mb-6"
label={t('languages.rating.label')}
value={item.rating}
onDecrement={() =>
item.rating > 1
? onChange(`${identifier}rating`, item.rating - 1)
: onChange(`${identifier}rating`, 0)
}
onIncrement={() =>
item.rating < 5
? onChange(`${identifier}rating`, item.rating + 1)
: onChange(`${identifier}rating`, 0)
}
/>
</div>
);
};
const AddItem = ({ heading, dispatch }) => {
const [isOpen, setOpen] = useState(false);
const [item, setItem] = useState({
id: uuidv4(),
enable: true,
key: '',
value: '',
rating: 1,
});
const onChange = (key, value) => setItem(items => set({ ...items }, key, value));
const onSubmit = () => {
if (item.key === '') return;
addItem(dispatch, 'languages', item);
setItem({
id: uuidv4(),
enable: true,
key: '',
value: '',
rating: 1,
});
setOpen(false);
};
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'}`}>
<Form item={item} onChange={onChange} />
<AddItemButton onSubmit={onSubmit} />
</div>
</div>
);
};
const Item = ({ item, index, onChange, dispatch, first, last }) => {
const [isOpen, setOpen] = useState(false);
const identifier = `data.languages.items[${index}].`;
return (
<div className="my-4 border border-gray-200 rounded p-5">
<ItemHeading title={item.key} setOpen={setOpen} isOpen={isOpen} />
<div className={`mt-6 ${isOpen ? 'block' : 'hidden'}`}>
<Form item={item} onChange={onChange} identifier={identifier} />
<ItemActions
dispatch={dispatch}
first={first}
identifier={identifier}
item={item}
last={last}
onChange={onChange}
type="languages"
/>
</div>
</div>
);
};
export default LanguagesTab;

View File

@ -1,43 +0,0 @@
import React from 'react';
import { useTranslation } from 'react-i18next';
import TextArea from '../../../shared/TextArea';
import TextField from '../../../shared/TextField';
import Checkbox from '../../../shared/Checkbox';
const ObjectiveTab = ({ data, onChange }) => {
const { t } = useTranslation('leftSidebar');
return (
<div>
<div className="mb-6 grid grid-cols-6 items-center">
<div className="col-span-1">
<Checkbox
checked={data.objective.enable}
onChange={v => onChange('data.objective.enable', v)}
/>
</div>
<div className="col-span-5">
<TextField
placeholder="Heading"
value={data.objective.heading}
onChange={v => onChange('data.objective.heading', v)}
/>
</div>
</div>
<hr className="my-6" />
<TextArea
rows="15"
className="mb-4"
label={t('objective.objective.label')}
value={data.objective.body}
placeholder="Looking for a challenging role in a reputable organization to utilize my technical, database, and management skills for the growth of the organization as well as to enhance my knowledge about new and emerging trends in the IT sector."
onChange={v => onChange('data.objective.body', v)}
/>
</div>
);
};
export default ObjectiveTab;

View File

@ -1,109 +0,0 @@
import React from 'react';
import { useTranslation } from 'react-i18next';
import TextField from '../../../shared/TextField';
const ProfileTab = ({ data, onChange }) => {
const { t } = useTranslation('leftSidebar');
return (
<div>
<TextField
className="mb-6"
placeholder="Heading"
value={data.profile.heading}
onChange={v => onChange('data.profile.heading', v)}
/>
<hr className="my-6" />
<TextField
className="mb-6"
label={t('profile.photoUrl.label')}
placeholder="https://i.imgur.com/..."
value={data.profile.photo}
onChange={v => onChange('data.profile.photo', v)}
/>
<div className="grid grid-cols-2 col-gap-4">
<TextField
className="mb-6"
label={t('profile.firstName.label')}
placeholder="Jane"
value={data.profile.firstName}
onChange={v => onChange('data.profile.firstName', v)}
/>
<TextField
className="mb-6"
label={t('profile.lastName.label')}
placeholder="Doe"
value={data.profile.lastName}
onChange={v => onChange('data.profile.lastName', v)}
/>
</div>
<TextField
className="mb-6"
label={t('profile.subtitle.label')}
placeholder="Full-Stack Web Developer"
value={data.profile.subtitle}
onChange={v => onChange('data.profile.subtitle', v)}
/>
<hr className="my-6" />
<TextField
className="mb-6"
label={t('profile.address.line1.label')}
placeholder="Palladium Complex"
value={data.profile.address.line1}
onChange={v => onChange('data.profile.address.line1', v)}
/>
<TextField
className="mb-6"
label={t('profile.address.line2.label')}
placeholder="140 E 14th St"
value={data.profile.address.line2}
onChange={v => onChange('data.profile.address.line2', v)}
/>
<TextField
className="mb-6"
label={t('profile.address.line3.label')}
placeholder="New York, NY 10003 USA"
value={data.profile.address.line3}
onChange={v => onChange('data.profile.address.line3', v)}
/>
<hr className="my-6" />
<TextField
className="mb-6"
label={t('profile.phone.label')}
placeholder="+1 541 754 3010"
value={data.profile.phone}
onChange={v => onChange('data.profile.phone', v)}
/>
<TextField
className="mb-6"
label={t('profile.website.label')}
placeholder="janedoe.me"
value={data.profile.website}
onChange={v => onChange('data.profile.website', v)}
/>
<TextField
className="mb-6"
label={t('profile.email.label')}
placeholder="jane.doe@example.com"
value={data.profile.email}
onChange={v => onChange('data.profile.email', v)}
/>
</div>
);
};
export default ProfileTab;

View File

@ -1,194 +0,0 @@
import React, { useState, useEffect, useContext } from 'react';
import { useTranslation } from 'react-i18next';
import { v4 as uuidv4 } from 'uuid';
import set from 'lodash/set';
import TextField from '../../../shared/TextField';
import TextArea from '../../../shared/TextArea';
import AppContext from '../../../context/AppContext';
import Checkbox from '../../../shared/Checkbox';
import { addItem } from '../../../utils';
import ItemActions from '../../../shared/ItemActions';
import ItemHeading from '../../../shared/ItemHeading';
import AddItemButton from '../../../shared/AddItemButton';
const ReferencesTab = ({ data, onChange }) => {
const context = useContext(AppContext);
const { dispatch } = context;
useEffect(() => {
if (!('references' in data)) {
dispatch({
type: 'migrate_section',
payload: {
key: 'references',
value: {
enable: false,
heading: 'References',
items: [],
},
},
});
dispatch({ type: 'save_data' });
}
}, [data, dispatch]);
return (
'references' in data && (
<>
<div className="mb-6 grid grid-cols-6 items-center">
<div className="col-span-1">
<Checkbox
checked={data.references.enable}
onChange={v => onChange('data.references.enable', v)}
/>
</div>
<div className="col-span-5">
<TextField
placeholder="Heading"
value={data.references.heading}
onChange={v => onChange('data.references.heading', v)}
/>
</div>
</div>
<hr className="my-6" />
{data.references.items.map((x, index) => (
<Item
item={x}
key={x.id}
index={index}
onChange={onChange}
dispatch={dispatch}
first={index === 0}
last={index === data.references.items.length - 1}
/>
))}
<AddItem heading={data.references.heading} dispatch={dispatch} />
</>
)
);
};
const Form = ({ item, onChange, identifier = '' }) => {
const { t } = useTranslation(['leftSidebar', 'app']);
return (
<div>
<TextField
className="mb-6"
label={t('references.name.label')}
placeholder="Richard Hendricks"
value={item.name}
onChange={v => onChange(`${identifier}name`, v)}
/>
<TextField
className="mb-6"
label={t('references.position.label')}
placeholder="CEO, Pied Piper"
value={item.position}
onChange={v => onChange(`${identifier}position`, v)}
/>
<TextField
className="mb-6"
label={t('references.phone.label')}
placeholder="+1 541 754 3010"
value={item.phone}
onChange={v => onChange(`${identifier}phone`, v)}
/>
<TextField
className="mb-6"
label={t('references.email.label')}
placeholder="richard@piedpiper.com"
value={item.email}
onChange={v => onChange(`${identifier}email`, v)}
/>
<TextArea
rows="5"
className="mb-6"
label={t('app:item.description.label')}
value={item.description}
onChange={v => onChange(`${identifier}description`, v)}
/>
</div>
);
};
const AddItem = ({ heading, dispatch }) => {
const [isOpen, setOpen] = useState(false);
const [item, setItem] = useState({
id: uuidv4(),
enable: true,
name: '',
position: '',
phone: '',
email: '',
description: '',
});
const onChange = (key, value) => setItem(set({ ...item }, key, value));
const onSubmit = () => {
if (item.name === '' || item.position === '') return;
addItem(dispatch, 'references', item);
setItem({
id: uuidv4(),
enable: true,
name: '',
position: '',
phone: '',
email: '',
description: '',
});
setOpen(false);
};
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'}`}>
<Form item={item} onChange={onChange} />
<AddItemButton onSubmit={onSubmit} />
</div>
</div>
);
};
const Item = ({ item, index, onChange, dispatch, first, last }) => {
const [isOpen, setOpen] = useState(false);
const identifier = `data.references.items[${index}].`;
return (
<div className="my-4 border border-gray-200 rounded p-5">
<ItemHeading title={item.name} setOpen={setOpen} isOpen={isOpen} />
<div className={`mt-6 ${isOpen ? 'block' : 'hidden'}`}>
<Form item={item} onChange={onChange} identifier={identifier} />
<ItemActions
dispatch={dispatch}
first={first}
identifier={identifier}
item={item}
last={last}
onChange={onChange}
type="references"
/>
</div>
</div>
);
};
export default ReferencesTab;

View File

@ -1,140 +0,0 @@
import React, { useState, useContext } from 'react';
import { v4 as uuidv4 } from 'uuid';
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 SkillsTab = ({ 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.skills.enable}
onChange={v => onChange('data.skills.enable', v)}
/>
</div>
<div className="col-span-5">
<TextField
placeholder="Heading"
value={data.skills.heading}
onChange={v => onChange('data.skills.heading', v)}
/>
</div>
</div>
<hr className="my-6" />
{data.skills.items.map((x, index) => (
<Item item={x} key={x.id} index={index} onChange={onChange} dispatch={dispatch} />
))}
<AddItem heading={data.skills.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="Team Building &amp; Training"
value={item.skill}
onChange={e => onChange(e.target.value)}
type="text"
/>
);
};
const AddItem = ({ heading, dispatch }) => {
const [isOpen, setOpen] = useState(false);
const [item, setItem] = useState({
id: uuidv4(),
skill: ''
});
const add = () => {
if (item.skill === '') return;
addItem(dispatch, 'skills', item);
setItem({
id: uuidv4(),
skill: ''
});
};
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={v => setItem({...item, skill: v})} />
</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.skills.items[${index}]`;
return (
<div className="my-4 grid grid-cols-12">
<div className="col-span-9">
<Form item={item} onChange={v => onChange(identifier, {...item, skill: 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">close</i>
</div>
</button>
</div>
);
};
export default SkillsTab;

View File

@ -1,173 +0,0 @@
import React, { useState, useContext } from 'react';
import { useTranslation } from 'react-i18next';
import { v4 as uuidv4 } from 'uuid';
import set from 'lodash/set';
import TextField from '../../../shared/TextField';
import TextArea from '../../../shared/TextArea';
import AppContext from '../../../context/AppContext';
import Checkbox from '../../../shared/Checkbox';
import { addItem } from '../../../utils';
import ItemActions from '../../../shared/ItemActions';
import AddItemButton from '../../../shared/AddItemButton';
import ItemHeading from '../../../shared/ItemHeading';
const WorkTab = ({ data, onChange }) => {
const context = useContext(AppContext);
const { dispatch } = context;
return (
<>
<div className="mb-6 grid grid-cols-6 items-center">
<div className="col-span-1">
<Checkbox checked={data.work.enable} onChange={v => onChange('data.work.enable', v)} />
</div>
<div className="col-span-5">
<TextField
placeholder="Heading"
value={data.work.heading}
onChange={v => onChange('data.work.heading', v)}
/>
</div>
</div>
<hr className="my-6" />
{data.work.items.map((x, index) => (
<Item
dispatch={dispatch}
first={index === 0}
index={index}
item={x}
key={x.id}
last={index === data.work.items.length - 1}
onChange={onChange}
/>
))}
<AddItem heading={data.work.heading} dispatch={dispatch} />
</>
);
};
const Form = ({ item, onChange, identifier = '' }) => {
const { t } = useTranslation(['leftSidebar', 'app']);
return (
<div>
<TextField
className="mb-6"
label={t('work.name.label')}
placeholder="Amazon"
value={item.title}
onChange={v => onChange(`${identifier}title`, v)}
/>
<TextField
className="mb-6"
label={t('work.role.label')}
placeholder="Full-Stack Web Developer"
value={item.role}
onChange={v => onChange(`${identifier}role`, v)}
/>
<div className="grid grid-cols-2 col-gap-4">
<TextField
className="mb-6"
label={t('app:item.startDate.label')}
placeholder="March 2018"
value={item.start}
onChange={v => onChange(`${identifier}start`, v)}
/>
<TextField
className="mb-6"
label={t('app:item.endDate.label')}
placeholder="June 2022"
value={item.end}
onChange={v => onChange(`${identifier}end`, v)}
/>
</div>
<TextArea
rows="5"
className="mb-6"
label={t('app:item.description.label')}
value={item.description}
onChange={v => onChange(`${identifier}description`, v)}
/>
</div>
);
};
const AddItem = ({ heading, dispatch }) => {
const [isOpen, setOpen] = useState(false);
const [item, setItem] = useState({
id: uuidv4(),
enable: true,
title: '',
role: '',
start: '',
end: '',
description: '',
});
const onChange = (key, value) => setItem(set({ ...item }, key, value));
const onSubmit = () => {
if (item.title === '' || item.role === '') return;
addItem(dispatch, 'work', item);
setItem({
id: uuidv4(),
enable: true,
title: '',
role: '',
start: '',
end: '',
description: '',
});
setOpen(false);
};
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'}`}>
<Form item={item} onChange={onChange} />
<AddItemButton onSubmit={onSubmit} />
</div>
</div>
);
};
const Item = ({ item, index, onChange, dispatch, first, last }) => {
const [isOpen, setOpen] = useState(false);
const identifier = `data.work.items[${index}].`;
return (
<div className="my-4 border border-gray-200 rounded p-5">
<ItemHeading title={item.title} setOpen={setOpen} isOpen={isOpen} />
<div className={`mt-6 ${isOpen ? 'block' : 'hidden'}`}>
<Form item={item} onChange={onChange} identifier={identifier} />
<ItemActions
dispatch={dispatch}
first={first}
identifier={identifier}
item={item}
last={last}
onChange={onChange}
type="work"
/>
</div>
</div>
);
};
export default WorkTab;

View File

@ -1,90 +0,0 @@
import React, { useState, useContext } from 'react';
import { useTranslation } from 'react-i18next';
import AppContext from '../../context/AppContext';
import TabBar from '../../shared/TabBar';
import TemplatesTab from './tabs/Templates';
import ColorsTab from './tabs/Colors';
import FontsTab from './tabs/Fonts';
import ActionsTab from './tabs/Actions';
import AboutTab from './tabs/About';
import SettingsTab from './tabs/Settings';
const RightSidebar = () => {
const { t } = useTranslation('rightSidebar');
const context = useContext(AppContext);
const { state, dispatch } = context;
const { data, theme, settings } = state;
const tabs = [
{
key: 'templates',
name: t('templates.title'),
},
{
key: 'colors',
name: t('colors.title'),
},
{
key: 'fonts',
name: t('fonts.title'),
},
{
key: 'actions',
name: t('actions.title'),
},
{
key: 'settings',
name: t('settings.title'),
},
{
key: 'about',
name: t('about.title'),
},
];
const [currentTab, setCurrentTab] = useState(tabs[0].key);
const onChange = (key, value) => {
dispatch({
type: 'on_input',
payload: {
key,
value,
},
});
dispatch({ type: 'save_data' });
};
const renderTabs = () => {
switch (currentTab) {
case tabs[0].key:
return <TemplatesTab theme={theme} onChange={onChange} />;
case tabs[1].key:
return <ColorsTab theme={theme} onChange={onChange} />;
case tabs[2].key:
return <FontsTab theme={theme} onChange={onChange} />;
case tabs[3].key:
return <ActionsTab data={data} theme={theme} dispatch={dispatch} />;
case tabs[4].key:
return <SettingsTab settings={settings} onChange={onChange} />;
case tabs[5].key:
return <AboutTab />;
default:
return null;
}
};
return (
<div
id="rightSidebar"
className="animated slideInRight z-10 py-6 h-screen bg-white col-span-1 shadow-2xl overflow-y-scroll"
>
<TabBar tabs={tabs} currentTab={currentTab} setCurrentTab={setCurrentTab} />
<div className="px-6">{renderTabs()}</div>
</div>
);
};
export default RightSidebar;

View File

@ -1,121 +0,0 @@
import React from 'react';
import { Trans, useTranslation } from 'react-i18next';
const AboutTab = () => {
const { t } = useTranslation('rightSidebar');
return (
<div>
<div className="shadow text-center p-5">
<h6 className="font-bold text-sm mb-2">{t('about.documentation.heading')}</h6>
<div className="text-sm">{t('about.documentation.body')}</div>
<a
target="_blank"
rel="noopener noreferrer"
href="https://docs.rxresu.me/"
className="flex justify-center items-center mt-4 bg-gray-600 hover:bg-gray-700 text-white text-sm font-medium py-2 px-5 rounded"
>
<div className="flex justify-center items-center">
<i className="material-icons mr-2 font-bold text-base">description</i>
<span className="text-sm">{t('about.documentation.buttons.documentation')}</span>
</div>
</a>
</div>
<hr className="my-5" />
<div className="shadow text-center p-5">
<h6 className="font-bold text-sm mb-2">{t('about.bugOrFeatureRequest.heading')}</h6>
<div className="text-sm">{t('about.bugOrFeatureRequest.body')}</div>
<div className="grid grid-cols-1">
<a
target="_blank"
rel="noopener noreferrer"
href="https://github.com/AmruthPillai/Reactive-Resume/issues/new"
className="mt-4 bg-red-600 hover:bg-red-700 text-white text-sm font-medium py-2 px-5 rounded"
>
<div className="flex justify-center items-center">
<i className="material-icons mr-2 font-bold text-base">bug_report</i>
<span className="text-sm">{t('about.bugOrFeatureRequest.buttons.raiseIssue')}</span>
</div>
</a>
<a
target="_blank"
rel="noopener noreferrer"
href="mailto:im.amruth@gmail.com?subject=Feature Request/Reporting a Bug in Reactive Resume: "
className="mt-4 bg-blue-600 hover:bg-blue-700 text-white text-sm font-medium py-2 px-5 rounded"
>
<div className="flex justify-center items-center">
<i className="material-icons mr-2 font-bold text-base">email</i>
<span className="text-sm">{t('about.bugOrFeatureRequest.buttons.sendEmail')}</span>
</div>
</a>
</div>
</div>
<hr className="my-5" />
<div className="shadow text-center p-5">
<h6 className="font-bold text-sm mb-2">{t('about.sourceCode.heading')}</h6>
<div className="text-sm">{t('about.sourceCode.body')}</div>
<a
target="_blank"
rel="noopener noreferrer"
href="https://github.com/AmruthPillai/Reactive-Resume"
className="flex justify-center items-center mt-4 bg-green-600 hover:bg-green-700 text-white text-sm font-medium py-2 px-5 rounded"
>
<div className="flex justify-center items-center">
<i className="material-icons mr-2 font-bold text-base">code</i>
<span className="text-sm">{t('about.sourceCode.buttons.githubRepo')}</span>
</div>
</a>
</div>
<hr className="my-5" />
<div className="shadow text-center p-5">
<h6 className="font-bold text-sm mb-2">{t('about.license.heading')}</h6>
<div className="text-sm">{t('about.license.body')}</div>
<a
target="_blank"
rel="noopener noreferrer"
href="https://github.com/AmruthPillai/Reactive-Resume/blob/master/LICENSE"
className="flex justify-center items-center mt-4 bg-gray-600 hover:bg-gray-700 text-white text-sm font-medium py-2 px-5 rounded"
>
<div className="flex justify-center items-center">
<i className="material-icons mr-2 font-bold text-base">gavel</i>
<span className="text-sm">{t('about.license.buttons.mitLicense')}</span>
</div>
</a>
</div>
<div className="mt-5">
<p className="text-xs font-gray-600 text-center">
<Trans t={t} i18nKey="about.footer.credit">
Made with Love by
<a
className="font-bold hover:underline"
href="https://www.amruthpillai.com/"
rel="noopener noreferrer"
target="_blank"
>
Amruth Pillai
</a>
</Trans>
</p>
<p className="text-xs font-gray-600 text-center">{t('about.footer.thanks')}</p>
</div>
</div>
);
};
export default AboutTab;

View File

@ -1,139 +0,0 @@
/* eslint-disable new-cap */
/* eslint-disable jsx-a11y/anchor-has-content */
/* eslint-disable jsx-a11y/anchor-is-valid */
import React, { useRef, useContext } from 'react';
import { useTranslation } from 'react-i18next';
import PageContext from '../../../context/PageContext';
import { importJson } from '../../../utils';
const ActionsTab = ({ data, theme, dispatch }) => {
const pageContext = useContext(PageContext);
const { setPrintDialogOpen } = pageContext;
const { t } = useTranslation('rightSidebar');
const fileInputRef = useRef(null);
const exportToJson = () => {
const backupObj = { data, theme };
const dataStr = `data:text/json;charset=utf-8,${encodeURIComponent(JSON.stringify(backupObj))}`;
const dlAnchor = document.getElementById('downloadAnchor');
dlAnchor.setAttribute('href', dataStr);
dlAnchor.setAttribute('download', `RxResumeBackup_${Date.now()}.json`);
dlAnchor.click();
};
const loadDemoData = () => {
dispatch({ type: 'load_demo_data' });
dispatch({ type: 'save_data' });
};
const resetEverything = () => {
dispatch({ type: 'reset' });
dispatch({ type: 'save_data' });
};
return (
<div>
<div className="shadow text-center text-sm p-5">{t('actions.disclaimer')}</div>
<hr className="my-6" />
<div className="shadow text-center p-5">
<h6 className="font-bold text-sm mb-2">{t('actions.importExport.heading')}</h6>
<p className="text-sm">{t('actions.importExport.body')}</p>
<input
ref={fileInputRef}
type="file"
className="hidden"
onChange={(e) => importJson(e, dispatch)}
/>
<a id="downloadAnchor" className="hidden" />
<div className="mt-4 grid grid-cols-2 col-gap-6">
<button
type="button"
onClick={() => fileInputRef.current.click()}
className="bg-gray-600 hover:bg-gray-700 text-white text-sm font-medium py-2 px-5 rounded"
>
<div className="flex justify-center items-center">
<i className="material-icons mr-2 font-bold text-base">publish</i>
<span className="text-sm">{t('actions.importExport.buttons.import')}</span>
</div>
</button>
<button
type="button"
onClick={exportToJson}
className="bg-gray-600 hover:bg-gray-700 text-white text-sm font-medium py-2 px-5 rounded"
>
<div className="flex justify-center items-center">
<i className="material-icons mr-2 font-bold text-base">get_app</i>
<span className="text-sm">{t('actions.importExport.buttons.export')}</span>
</div>
</button>
</div>
</div>
<hr className="my-6" />
<div className="shadow text-center p-5">
<h6 className="font-bold text-sm mb-2">{t('actions.downloadResume.heading')}</h6>
<div className="text-sm">{t('actions.downloadResume.body')}</div>
<button
type="button"
onClick={() => setPrintDialogOpen(true)}
className="mt-4 bg-blue-600 hover:bg-blue-700 text-white text-sm font-medium py-2 px-5 rounded"
>
<div className="flex justify-center items-center">
<i className="material-icons mr-2 font-bold text-base">save</i>
<span className="text-sm">{t('actions.downloadResume.buttons.saveAsPdf')}</span>
</div>
</button>
</div>
<hr className="my-6" />
<div className="shadow text-center p-5">
<h6 className="font-bold text-sm mb-2">{t('actions.loadDemoData.heading')}</h6>
<div className="text-sm">{t('actions.loadDemoData.body')}</div>
<button
type="button"
onClick={loadDemoData}
className="mt-4 bg-green-600 hover:bg-green-700 text-white text-sm font-medium py-2 px-5 rounded"
>
<div className="flex justify-center items-center">
<i className="material-icons mr-2 font-bold text-base">flight_takeoff</i>
<span className="text-sm">{t('actions.loadDemoData.buttons.loadData')}</span>
</div>
</button>
</div>
<hr className="my-6" />
<div className="shadow text-center p-5">
<h6 className="font-bold text-sm mb-2">{t('actions.reset.heading')}</h6>
<div className="text-sm">{t('actions.reset.body')}</div>
<button
type="button"
onClick={resetEverything}
className="mt-4 bg-red-600 hover:bg-red-700 text-white text-sm font-medium py-2 px-5 rounded"
>
<div className="flex justify-center items-center">
<i className="material-icons mr-2 font-bold text-base">refresh</i>
<span className="text-sm">{t('actions.reset.buttons.reset')}</span>
</div>
</button>
</div>
</div>
);
};
export default ActionsTab;

View File

@ -1,95 +0,0 @@
import React from 'react';
import { toast } from 'react-toastify';
import { useTranslation } from 'react-i18next';
import TextField from '../../../shared/TextField';
import { copyToClipboard } from '../../../utils';
const colorOptions = [
'#f44336',
'#E91E63',
'#9C27B0',
'#673AB7',
'#3F51B5',
'#2196F3',
'#03A9F4',
'#00BCD4',
'#009688',
'#4CAF50',
'#8BC34A',
'#CDDC39',
'#FFEB3B',
'#FFC107',
'#FF9800',
'#FF5722',
'#795548',
'#9E9E9E',
'#607D8B',
'#FAFAFA',
'#212121',
'#263238',
];
const ColorsTab = ({ theme, onChange }) => {
const { t } = useTranslation('rightSidebar');
const copyColorToClipboard = color => {
copyToClipboard(color);
toast(t('colors.clipboardCopyAction', { color }), {
bodyClassName: 'text-center text-gray-800 py-2',
});
onChange('theme.colors.accent', color);
};
return (
<div>
<div className="uppercase tracking-wide text-gray-600 text-xs font-semibold mb-4">
{t('colors.colorOptions')}
</div>
<div className="mb-6 grid grid-cols-8 col-gap-2 row-gap-3">
{colorOptions.map(color => (
<div
key={color}
className="cursor-pointer rounded-full border border-gray-200 h-6 w-6 hover:opacity-75"
style={{ backgroundColor: color }}
onClick={() => copyColorToClipboard(color)}
/>
))}
</div>
<hr className="my-6" />
<div className="my-6 grid grid-cols-6 items-end">
<div
className="rounded-full w-8 h-8 mb-2 border-2"
style={{ backgroundColor: theme.colors.primary }}
/>
<div className="col-span-5">
<TextField
label={t('colors.primaryColor')}
placeholder="#FFFFFF"
value={theme.colors.primary}
onChange={v => onChange('theme.colors.primary', v)}
/>
</div>
</div>
<div className="my-6 grid grid-cols-6 items-end">
<div
className="rounded-full w-8 h-8 mb-2 border-2"
style={{ backgroundColor: theme.colors.accent }}
/>
<div className="col-span-5">
<TextField
label={t('colors.accentColor')}
placeholder="#FFFFFF"
value={theme.colors.accent}
onChange={v => onChange('theme.colors.accent', v)}
/>
</div>
</div>
</div>
);
};
export default ColorsTab;

View File

@ -1,51 +0,0 @@
import React from 'react';
import { useTranslation } from 'react-i18next';
import TextField from '../../../shared/TextField';
const fontOptions = [
'Lato',
'Montserrat',
'Nunito',
'Open Sans',
'Raleway',
'Rubik',
'Source Sans Pro',
'Titillium Web',
'Ubuntu',
];
const FontsTab = ({ theme, onChange }) => {
const { t } = useTranslation('rightSidebar');
return (
<div className="grid grid-cols-1 gap-6">
{fontOptions.map(x => (
<div
key={x}
style={{ fontFamily: x }}
onClick={() => onChange('theme.font.family', x)}
className={`w-full rounded border py-4 shadow text-xl text-center ${
theme.font.family === x ? 'border-gray-500' : 'border-transparent'
} hover:border-gray-400 cursor-pointer`}
>
{x}
</div>
))}
<div>
<TextField
className="mb-3"
label={t('fonts.fontFamily.label')}
placeholder="Avenir Next"
value={theme.font.family}
onChange={v => onChange('theme.font.family', v)}
/>
<p className="text-gray-800 text-xs">{t('fonts.fontFamily.helpText')}</p>
</div>
</div>
);
};
export default FontsTab;

View File

@ -1,42 +0,0 @@
import React from 'react';
import { useTranslation, Trans } from 'react-i18next';
import { languages } from '../../../i18n';
import Dropdown from '../../../shared/Dropdown';
const SettingsTab = ({ settings, onChange }) => {
const { t } = useTranslation('rightSidebar');
return (
<div>
<Dropdown
label={t('settings.language.label')}
value={settings.language}
onChange={x => onChange('settings.language', x)}
options={languages}
optionItem={x => (
<option key={x.code} value={x.code}>
{x.name}
</option>
)}
/>
<p className="text-gray-800 text-xs">
<Trans t={t} i18nKey="settings.language.helpText">
If you would like to help translate the app into your own language, please refer the
<a
className="text-blue-600 hover:underline"
target="_blank"
rel="noopener noreferrer"
href="https://docs.rxresu.me/translation/"
>
Translation Documentation
</a>
.
</Trans>
</p>
</div>
);
};
export default SettingsTab;

View File

@ -1,26 +0,0 @@
import React from 'react';
import templates from '../../../templates';
const TemplatesTab = ({ theme, onChange }) => {
return (
<div className="grid grid-cols-2 gap-6">
{templates.map(x => (
<div key={x.key} className="text-center" onClick={() => onChange('theme.layout', x.key)}>
<img
className={`rounded cursor-pointer object-cover border shadow hover:shadow-md ${
theme.layout.toLowerCase() === x.key
? 'border-gray-600 hover:border-gray-600'
: 'border-transparent '
} hover:border-gray-500 cursor-pointer`}
src={x.preview}
alt={x.name}
/>
<p className="mt-1 text-sm font-medium">{x.name}</p>
</div>
))}
</div>
);
};
export default TemplatesTab;

View File

@ -1,157 +0,0 @@
import React, { createContext, useReducer } from 'react';
import get from 'lodash/get';
import set from 'lodash/set';
import remove from 'lodash/remove';
import demoData from '../assets/demo/data.json';
import { move } from '../utils';
const initialState = {
data: {
profile: {
heading: 'Profile',
photo: '',
firstName: '',
lastName: '',
subtitle: '',
address: {
line1: '',
line2: '',
line3: '',
},
phone: '',
website: '',
email: '',
},
objective: {
enable: true,
heading: 'Objective',
body: '',
},
work: {
enable: true,
heading: 'Work Experience',
items: [],
},
education: {
enable: true,
heading: 'Education',
items: [],
},
awards: {
enable: true,
heading: 'Honors & Awards',
items: [],
},
certifications: {
enable: true,
heading: 'Certifications',
items: [],
},
skills: {
enable: true,
heading: 'Skills',
items: [],
},
hobbies: {
enable: true,
heading: 'Hobbies',
items: [],
},
languages: {
enable: true,
heading: 'Languages',
items: [],
},
references: {
enable: true,
heading: 'References',
items: [],
},
extras: {
enable: true,
heading: 'Personal Information',
items: [],
},
},
theme: {
layout: 'Onyx',
font: {
family: '',
},
colors: {
background: '#ffffff',
primary: '#212121',
accent: '#f44336',
},
},
settings: {
language: 'en',
},
};
const reducer = (state, { type, payload }) => {
let items;
const newState = JSON.parse(JSON.stringify(state));
switch (type) {
case 'migrate_section':
return set({ ...newState }, `data.${payload.key}`, payload.value);
case 'add_item':
items = get({ ...newState }, `data.${payload.key}.items`, []);
items.push(payload.value);
return set({ ...newState }, `data.${payload.key}.items`, items);
case 'delete_item':
items = get({ ...newState }, `data.${payload.key}.items`, []);
remove(items, x => x.id === payload.value.id);
return set({ ...newState }, `data.${payload.key}.items`, items);
case 'move_item_up':
items = get({ ...newState }, `data.${payload.key}.items`, []);
move(items, payload.value, -1);
return set({ ...newState }, `data.${payload.key}.items`, items);
case 'move_item_down':
items = get({ ...newState }, `data.${payload.key}.items`, []);
move(items, payload.value, 1);
return set({ ...newState }, `data.${payload.key}.items`, items);
case 'on_input':
return set({ ...newState }, payload.key, payload.value);
case 'save_data':
localStorage.setItem('state', JSON.stringify(newState));
return newState;
case 'import_data':
if (payload === null) return initialState;
for (const section of Object.keys(initialState.data)) {
if (!(section in payload.data)) {
payload.data[section] = initialState.data[section];
}
}
return {
...newState,
...payload,
};
case 'load_demo_data':
return {
...newState,
...demoData,
};
case 'reset':
return initialState;
default:
return newState;
}
};
const AppContext = createContext(initialState);
const { Provider } = AppContext;
const StateProvider = ({ children }) => {
const [state, dispatch] = useReducer(reducer, initialState);
return <Provider value={{ state, dispatch }}>{children}</Provider>;
};
export const AppProvider = StateProvider;
export const AppConsumer = AppContext.Consumer;
export default AppContext;

View File

@ -1,30 +0,0 @@
import React, { useState } from 'react';
const PageContext = React.createContext(null);
const { Provider } = PageContext;
const StateProvider = ({ children }) => {
const [pageRef, setPageRef] = useState(null);
const [panZoomRef, setPanZoomRef] = useState(null);
const [isPrintDialogOpen, setPrintDialogOpen] = useState(false);
return (
<Provider
value={{
pageRef,
setPageRef,
panZoomRef,
setPanZoomRef,
isPrintDialogOpen,
setPrintDialogOpen,
}}
>
{children}
</Provider>
);
};
export const PageProvider = StateProvider;
export const PageConsumer = PageContext.Consumer;
export default PageContext;

View File

@ -1,93 +0,0 @@
import i18n from 'i18next';
import backend from 'i18next-http-backend';
import { initReactI18next } from 'react-i18next';
import detector from 'i18next-browser-languagedetector';
import resources from './locales';
const languages = [
{
code: 'ar',
name: 'Arabic (عربى)',
},
{
code: 'zh',
name: 'Chinese (中文)',
},
{
code: 'da',
name: 'Danish (Dansk)',
},
{
code: 'nl',
name: 'Dutch (Nederlands)',
},
{
code: 'en',
name: 'English (US)',
},
{
code: 'fr',
name: 'French (Français)',
},
{
code: 'de',
name: 'German (Deutsche)',
},
{
code: 'he',
name: 'Hebrew (עברית)',
},
{
code: 'hi',
name: 'Hindi (हिन्दी)',
},
{
code: 'it',
name: 'Italian (Italiano)',
},
{
code: 'kn',
name: 'Kannada (ಕನ್ನಡ)',
},
{
code: 'pl',
name: 'Polish (Polskie)',
},
{
code: 'pt',
name: 'Portuguese (Português)',
},
{
code: 'ru',
name: 'Russian (русский)',
},
{
code: 'es',
name: 'Spanish (Español)',
},
{
code: 'ta',
name: 'Tamil (தமிழ்)',
},
{
code: 'vi',
name: 'Vietnamese (Tiếng Việt)',
},
];
i18n
.use(detector)
.use(backend)
.use(initReactI18next)
.init({
resources,
lng: 'en',
fallbackLng: 'en',
ns: ['app', 'leftSidebar', 'rightSidebar'],
defaultNS: 'app',
});
export { languages };
export default i18n;

View File

@ -1,48 +0,0 @@
{
"item": {
"add": "Add {{- heading}}",
"startDate": {
"label": "Start Date"
},
"endDate": {
"label": "End Date"
},
"description": {
"label": "Description"
}
},
"buttons": {
"add": {
"label": "Add"
},
"delete": {
"label": "Delete"
}
},
"printDialog": {
"heading": "Download Your Resume",
"quality": {
"label": "Quality"
},
"printType": {
"label": "Type",
"types": {
"unconstrained": "Unconstrained",
"fitInA4": "Fit in A4",
"multiPageA4": "Multi-Page A4"
}
},
"helpText": [
"This export method makes use of HTML canvas to convert the resume to an image and print it on a PDF, which means it will lose all selecting/parsing capabilities.",
"If that is important to you, please try printing the resume instead, using Cmd/Ctrl + P or the print button below. The result may vary as the output is browser dependent, but it is known to work best on the latest version of Google Chrome."
],
"buttons": {
"cancel": "Cancel",
"saveAsPdf": "Save as PDF"
}
},
"panZoomAnimation": {
"helpText": "You can pan and zoom around the artboard at any time to get a closer look at your resume."
},
"markdownHelpText": "You can use <1>GitHub Flavored Markdown</1> to style this section of the text."
}

View File

@ -1,3 +0,0 @@
import app from './app.json';
export default app;

View File

@ -1,9 +0,0 @@
import app from './app';
import leftSidebar from './leftSidebar';
import rightSidebar from './rightSidebar';
export default {
app,
leftSidebar,
rightSidebar,
};

View File

@ -1,8 +0,0 @@
{
"title": {
"label": "Title"
},
"subtitle": {
"label": "Subtitle"
}
}

View File

@ -1,8 +0,0 @@
{
"title": {
"label": "Name"
},
"subtitle": {
"label": "Authority"
}
}

View File

@ -1,11 +0,0 @@
{
"name": {
"label": "Name"
},
"major": {
"label": "Major"
},
"grade": {
"label": "Grade"
}
}

View File

@ -1,8 +0,0 @@
{
"key": {
"label": "Key"
},
"value": {
"label": "Value"
}
}

View File

@ -1,21 +0,0 @@
import profile from './profile.json';
import objective from './objective.json';
import work from './work.json';
import education from './education.json';
import awards from './awards.json';
import certifications from './certifications.json';
import languages from './languages.json';
import references from './references.json';
import extras from './extras.json';
export default {
profile,
objective,
work,
education,
awards,
certifications,
languages,
references,
extras,
};

View File

@ -1,11 +0,0 @@
{
"key": {
"label": "Name"
},
"level": {
"label": "Level"
},
"rating": {
"label": "Rating"
}
}

View File

@ -1,5 +0,0 @@
{
"objective": {
"label": "Objective"
}
}

View File

@ -1,35 +0,0 @@
{
"photoUrl": {
"label": "Photo URL"
},
"firstName": {
"label": "First Name"
},
"lastName": {
"label": "Last Name"
},
"subtitle": {
"label": "Subtitle"
},
"address": {
"label": "Address",
"line1": {
"label": "Address Line 1"
},
"line2": {
"label": "Address Line 2"
},
"line3": {
"label": "Address Line 3"
}
},
"phone": {
"label": "Phone Number"
},
"website": {
"label": "Website"
},
"email": {
"label": "Email Address"
}
}

View File

@ -1,14 +0,0 @@
{
"name": {
"label": "Name"
},
"position": {
"label": "Position"
},
"phone": {
"label": "Phone Number"
},
"email": {
"label": "Email Address"
}
}

View File

@ -1,8 +0,0 @@
{
"name": {
"label": "Name"
},
"role": {
"label": "Role"
}
}

Some files were not shown because too many files have changed in this diff Show More