Merge pull request #22 from AmruthPillai/feature/i18n

Feature: Internationalization (i18n)
This commit is contained in:
Amruth Pillai
2020-03-30 19:01:13 +05:30
committed by GitHub
772 changed files with 11831 additions and 1003 deletions
-2
View File
@@ -1,5 +1,3 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
+4
View File
@@ -0,0 +1,4 @@
{
"i18n-ally.localesPaths": "src/i18n",
"i18n-ally.keystyle": "nested"
}
+3
View File
@@ -0,0 +1,3 @@
files:
- source: /src/i18n/source/**/*.json
translation: /src/i18n/locales/%two_letters_code%/**/%original_file_name%
+1
View File
@@ -15,6 +15,7 @@ module.exports = {
'/templates/',
'/technology/',
'/contributing/',
'/translation/',
'/building-from-source/',
'/deployment/',
'/changelog/',
+1 -3
View File
@@ -30,9 +30,7 @@ Something that's missing on the app that's halting your progress from making the
## Translation
Currently, there is no translation engine in place that allows for people to easily make translations. I'm still figuring out the most elegant way to implement this feature with minimal code and maximum reach. For now, if you would like to see this feature, please vote in the GitHub Issue linked below and if you are willing to contribute, mention in the comments of the issue which language you would like to translate to.
[Vote for Translation Engine Feature ](https://github.com/AmruthPillai/Reactive-Resume/issues/18)
For information on how to translate the app into your own language, please visit the [Translation](/translation/) section of the documentation.
## Commit Code
+5
View File
@@ -0,0 +1,5 @@
---
title: Translation
---
# Translation
+30
View File
@@ -8617,6 +8617,14 @@
}
}
},
"html-parse-stringify2": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/html-parse-stringify2/-/html-parse-stringify2-2.0.1.tgz",
"integrity": "sha1-3FZwtyksoVi3vJFsmmc1rIhyg0o=",
"requires": {
"void-elements": "^2.0.1"
}
},
"html-tags": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/html-tags/-/html-tags-2.0.0.tgz",
@@ -8790,6 +8798,14 @@
"resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.0.3.tgz",
"integrity": "sha512-EcuixamT82oplpoJ2XU4pDtKGWQ7b00CD9f1ug9IaQ3p1bkHMiKCZ9ut9QDI6qsa6cpUuB+A/I+zLtdNK4n2DQ=="
},
"i18next": {
"version": "19.3.4",
"resolved": "https://registry.npmjs.org/i18next/-/i18next-19.3.4.tgz",
"integrity": "sha512-ef7AxxutzdhBsBNugE9jgqsbwesG1muJOtZ9ZrPARPs/jXegViTp4+8JCeMp8BAyTIo1Zn0giqc8+2UpqFjU0w==",
"requires": {
"@babel/runtime": "^7.3.1"
}
},
"iconv-lite": {
"version": "0.4.24",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
@@ -14234,6 +14250,15 @@
"resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.7.tgz",
"integrity": "sha512-TAv1KJFh3RhqxNvhzxj6LeT5NWklP6rDr2a0jaTfsZ5wSZWHOGeqQyejUp3xxLfPt2UpyJEcVQB/zyPcmonNFA=="
},
"react-i18next": {
"version": "11.3.4",
"resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-11.3.4.tgz",
"integrity": "sha512-IRZMD7PAM3C+fJNzRbyLNi1ZD0kc3Z3obBspJjEl+9H+ME41PhVor3BpdIqv/Rm7lUoGhMjmpu42J45ooJ61KA==",
"requires": {
"@babel/runtime": "^7.3.1",
"html-parse-stringify2": "2.0.1"
}
},
"react-is": {
"version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
@@ -17099,6 +17124,11 @@
"resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz",
"integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ=="
},
"void-elements": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz",
"integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w="
},
"vue": {
"version": "2.6.11",
"resolved": "https://registry.npmjs.org/vue/-/vue-2.6.11.tgz",
+2
View File
@@ -8,9 +8,11 @@
"@testing-library/react": "^10.0.1",
"@testing-library/user-event": "^10.0.0",
"axios": "^0.19.2",
"i18next": "^19.3.4",
"lodash": "^4.17.15",
"react": "^16.13.1",
"react-dom": "^16.13.1",
"react-i18next": "^11.3.4",
"react-markdown": "^4.3.1",
"react-scripts": "3.4.1",
"react-toastify": "^5.5.0",
+17 -35
View File
@@ -1,15 +1,10 @@
/* eslint-disable no-unused-vars */
import React, { useEffect, useContext } from 'react';
import React, { useEffect, useContext, Suspense } from 'react';
import AppContext from '../../context/AppContext';
import LeftSidebar from '../LeftSidebar/LeftSidebar';
import RightSidebar from '../RightSidebar/RightSidebar';
import AppContext from '../../context/AppContext';
// Resume Templates
import Onyx from '../../templates/onyx';
import Pikachu from '../../templates/pikachu';
import Gengar from '../../templates/gengar';
import Castform from '../../templates/castform';
import templates from '../../templates';
const App = () => {
const context = useContext(AppContext);
@@ -21,37 +16,24 @@ const App = () => {
dispatch({ type: 'import_data', payload: storedState });
}, [dispatch]);
const renderTemplate = () => {
switch (theme.layout) {
case 'Onyx':
return <Onyx />;
case 'Pikachu':
return <Pikachu />;
case 'Gengar':
return <Gengar />;
case 'Castform':
return <Castform />;
default:
return null;
}
};
return (
<div className="h-screen overflow-hidden grid grid-cols-5 items-center">
<LeftSidebar />
<Suspense fallback="Loading...">
<div className="h-screen overflow-hidden grid grid-cols-5 items-center">
<LeftSidebar />
<div className="z-0 h-screen col-span-3 flex justify-center items-center overflow-scroll">
<div
id="page"
className="animated fadeIn my-auto shadow-2xl"
style={{ animationDelay: '500ms' }}
>
{renderTemplate()}
<div className="z-0 h-screen col-span-3 flex justify-center items-center overflow-scroll">
<div
id="page"
className="animated fadeIn my-auto shadow-2xl"
style={{ animationDelay: '500ms' }}
>
{templates.find(x => theme.layout.toLowerCase() === x.key).component()}
</div>
</div>
</div>
<RightSidebar />
</div>
<RightSidebar />
</div>
</Suspense>
);
};
+12 -13
View File
@@ -13,24 +13,23 @@ import ExtrasTab from './tabs/Extras';
import LanguagesTab from './tabs/Languages';
import ReferencesTab from './tabs/References';
const tabs = [
'Profile',
'Objective',
'Work Experience',
'Education',
'Awards',
'Certifications',
'Skills',
'Languages',
'References',
'Extras',
];
const LeftSidebar = () => {
const context = useContext(AppContext);
const { state, dispatch } = context;
const { data } = state;
const tabs = [
'Profile',
'Objective',
'Work Experience',
'Education',
'Awards',
'Certifications',
'Skills',
'Languages',
'References',
'Extras',
];
const [currentTab, setCurrentTab] = useState('Profile');
const onChange = (key, value) => {
dispatch({
+50 -80
View File
@@ -1,4 +1,5 @@
import React, { useState, useContext } from 'react';
import { useTranslation } from 'react-i18next';
import { v4 as uuidv4 } from 'uuid';
import set from 'lodash/set';
@@ -6,10 +7,13 @@ import TextField from '../../../shared/TextField';
import AppContext from '../../../context/AppContext';
import Checkbox from '../../../shared/Checkbox';
import TextArea from '../../../shared/TextArea';
import { addItem, deleteItem, moveItemUp, moveItemDown } from '../../../utils';
import { addItem } from '../../../utils';
import ItemActions from '../../../shared/ItemActions';
import AddItemButton from '../../../shared/AddItemButton';
import ItemHeading from '../../../shared/ItemHeading';
const AwardsTab = ({ data, onChange }) => {
const { t } = useTranslation();
const context = useContext(AppContext);
const { dispatch } = context;
@@ -24,7 +28,7 @@ const AwardsTab = ({ data, onChange }) => {
</div>
<div className="col-span-5">
<TextField
placeholder="Heading"
placeholder={t('heading.placeholder')}
value={data.awards.heading}
onChange={v => onChange('data.awards.heading', v)}
/>
@@ -45,12 +49,44 @@ const AwardsTab = ({ data, onChange }) => {
/>
))}
<AddItem dispatch={dispatch} />
<AddItem heading={data.awards.heading} dispatch={dispatch} />
</>
);
};
const AddItem = ({ dispatch }) => {
const Form = ({ item, onChange, identifier = '' }) => {
const { t } = useTranslation(['leftSidebar', 'app']);
return (
<div>
<TextField
className="mb-6"
label={t('awards.title.label')}
placeholder={t('awards.title.placeholder')}
value={item.title}
onChange={v => onChange(`${identifier}title`, v)}
/>
<TextField
className="mb-6"
label={t('awards.subtitle.label')}
placeholder={t('awards.subtitle.placeholder')}
value={item.subtitle}
onChange={v => onChange(`${identifier}subtitle`, v)}
/>
<TextArea
className="mb-6"
label={t('app:item.description.label')}
placeholder={t('awards.description.placeholder')}
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(),
@@ -80,48 +116,12 @@ const AddItem = ({ dispatch }) => {
return (
<div className="my-4 border border-gray-200 rounded p-5">
<div
className="flex justify-between items-center cursor-pointer"
onClick={() => setOpen(!isOpen)}
>
<h6 className="text-sm font-medium">Add Award</h6>
<i className="material-icons">{isOpen ? 'expand_less' : 'expand_more'}</i>
</div>
<ItemHeading heading={heading} setOpen={setOpen} isOpen={isOpen} />
<div className={`mt-6 ${isOpen ? 'block' : 'hidden'}`}>
<TextField
label="Title"
className="mb-6"
placeholder="Math &amp; Science Olympiad"
value={item.title}
onChange={v => onChange('title', v)}
/>
<Form item={item} onChange={onChange} />
<TextField
label="Subtitle"
className="mb-6"
placeholder="First Place, International Level"
value={item.subtitle}
onChange={v => onChange('subtitle', v)}
/>
<TextArea
label="Description"
className="mb-6"
value={item.description}
onChange={v => onChange('description', v)}
/>
<button
type="button"
onClick={onSubmit}
className="bg-gray-600 hover:bg-gray-700 text-white text-sm font-medium py-2 px-5 rounded"
>
<div className="flex items-center">
<i className="material-icons mr-2 font-bold text-base">add</i>
<span className="text-sm">Add</span>
</div>
</button>
<AddItemButton onSubmit={onSubmit} />
</div>
</div>
);
@@ -129,53 +129,23 @@ const AddItem = ({ dispatch }) => {
const Item = ({ item, index, onChange, dispatch, first, last }) => {
const [isOpen, setOpen] = useState(false);
const identifier = `data.awards.items[${index}]`;
const identifier = `data.awards.items[${index}].`;
return (
<div className="my-4 border border-gray-200 rounded p-5">
<div
className="flex justify-between items-center cursor-pointer"
onClick={() => setOpen(!isOpen)}
>
<h6 className="text-sm font-medium">{item.title}</h6>
<i className="material-icons">{isOpen ? 'expand_less' : 'expand_more'}</i>
</div>
<ItemHeading title={item.title} setOpen={setOpen} isOpen={isOpen} />
<div className={`mt-6 ${isOpen ? 'block' : 'hidden'}`}>
<TextField
label="Title"
className="mb-6"
placeholder="Math &amp; Science Olympiad"
value={item.title}
onChange={v => onChange(`${identifier}.title`, v)}
/>
<TextField
label="Subtitle"
className="mb-6"
placeholder="First Place, International Level"
value={item.subtitle}
onChange={v => onChange(`${identifier}.subtitle`, v)}
/>
<TextArea
label="Description"
className="mb-6"
value={item.description}
onChange={v => onChange(`${identifier}.description`, v)}
/>
<Form item={item} onChange={onChange} identifier={identifier} />
<ItemActions
dispatch={dispatch}
first={first}
identifier={identifier}
item={item}
last={last}
onChange={onChange}
type="awards"
identifier={identifier}
dispatch={dispatch}
deleteItem={deleteItem}
first={first}
moveItemUp={moveItemUp}
last={last}
moveItemDown={moveItemDown}
/>
</div>
</div>
@@ -1,4 +1,5 @@
import React, { useState, useContext } from 'react';
import { useTranslation } from 'react-i18next';
import { v4 as uuidv4 } from 'uuid';
import set from 'lodash/set';
@@ -6,10 +7,13 @@ import TextField from '../../../shared/TextField';
import AppContext from '../../../context/AppContext';
import Checkbox from '../../../shared/Checkbox';
import TextArea from '../../../shared/TextArea';
import { addItem, deleteItem, moveItemUp, moveItemDown } from '../../../utils';
import { addItem } from '../../../utils';
import ItemActions from '../../../shared/ItemActions';
import ItemHeading from '../../../shared/ItemHeading';
import AddItemButton from '../../../shared/AddItemButton';
const CertificationsTab = ({ data, onChange }) => {
const { t } = useTranslation();
const context = useContext(AppContext);
const { dispatch } = context;
@@ -24,7 +28,7 @@ const CertificationsTab = ({ data, onChange }) => {
</div>
<div className="col-span-5">
<TextField
placeholder="Heading"
placeholder={t('heading.placeholder')}
value={data.certifications.heading}
onChange={v => onChange('data.certifications.heading', v)}
/>
@@ -45,12 +49,44 @@ const CertificationsTab = ({ data, onChange }) => {
/>
))}
<AddItem dispatch={dispatch} />
<AddItem heading={data.certifications.heading} dispatch={dispatch} />
</>
);
};
const AddItem = ({ dispatch }) => {
const Form = ({ item, onChange, identifier = '' }) => {
const { t } = useTranslation(['leftSidebar', 'app']);
return (
<div>
<TextField
className="mb-6"
label={t('certifications.title.label')}
placeholder={t('certifications.title.placeholder')}
value={item.title}
onChange={v => onChange(`${identifier}title`, v)}
/>
<TextField
className="mb-6"
label={t('certifications.subtitle.label')}
placeholder={t('certifications.subtitle.placeholder')}
value={item.subtitle}
onChange={v => onChange(`${identifier}subtitle`, v)}
/>
<TextArea
className="mb-6"
label={t('app:item.description.label')}
placeholder={t('certifications.description.placeholder')}
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(),
@@ -80,48 +116,12 @@ const AddItem = ({ dispatch }) => {
return (
<div className="my-4 border border-gray-200 rounded p-5">
<div
className="flex justify-between items-center cursor-pointer"
onClick={() => setOpen(!isOpen)}
>
<h6 className="text-sm font-medium">Add Certification</h6>
<i className="material-icons">{isOpen ? 'expand_less' : 'expand_more'}</i>
</div>
<ItemHeading heading={heading} setOpen={setOpen} isOpen={isOpen} />
<div className={`mt-6 ${isOpen ? 'block' : 'hidden'}`}>
<TextField
label="Title"
className="mb-6"
placeholder="Android Development Nanodegree"
value={item.title}
onChange={v => onChange('title', v)}
/>
<Form item={item} onChange={onChange} />
<TextField
label="Subtitle"
className="mb-6"
placeholder="Udacity"
value={item.subtitle}
onChange={v => onChange('subtitle', v)}
/>
<TextArea
label="Description"
className="mb-6"
value={item.description}
onChange={v => onChange('description', v)}
/>
<button
type="button"
onClick={onSubmit}
className="bg-gray-600 hover:bg-gray-700 text-white text-sm font-medium py-2 px-5 rounded"
>
<div className="flex items-center">
<i className="material-icons mr-2 font-bold text-base">add</i>
<span className="text-sm">Add</span>
</div>
</button>
<AddItemButton onSubmit={onSubmit} />
</div>
</div>
);
@@ -129,53 +129,23 @@ const AddItem = ({ dispatch }) => {
const Item = ({ item, index, onChange, dispatch, first, last }) => {
const [isOpen, setOpen] = useState(false);
const identifier = `data.certifications.items[${index}]`;
const identifier = `data.certifications.items[${index}].`;
return (
<div className="my-4 border border-gray-200 rounded p-5">
<div
className="flex justify-between items-center cursor-pointer"
onClick={() => setOpen(!isOpen)}
>
<h6 className="text-sm font-medium">{item.title}</h6>
<i className="material-icons">{isOpen ? 'expand_less' : 'expand_more'}</i>
</div>
<ItemHeading title={item.title} setOpen={setOpen} isOpen={isOpen} />
<div className={`mt-6 ${isOpen ? 'block' : 'hidden'}`}>
<TextField
label="Title"
className="mb-6"
placeholder="Android Development Nanodegree"
value={item.title}
onChange={v => onChange(`${identifier}.title`, v)}
/>
<TextField
label="Subtitle"
className="mb-6"
placeholder="Udacity"
value={item.subtitle}
onChange={v => onChange(`${identifier}.subtitle`, v)}
/>
<TextArea
label="Description"
className="mb-6"
value={item.description}
onChange={v => onChange(`${identifier}.description`, v)}
/>
<Form item={item} onChange={onChange} identifier={identifier} />
<ItemActions
dispatch={dispatch}
first={first}
identifier={identifier}
item={item}
last={last}
onChange={onChange}
type="certifications"
identifier={identifier}
dispatch={dispatch}
deleteItem={deleteItem}
first={first}
moveItemUp={moveItemUp}
last={last}
moveItemDown={moveItemDown}
/>
</div>
</div>
+78 -138
View File
@@ -1,4 +1,5 @@
import React, { useState, useContext } from 'react';
import { useTranslation } from 'react-i18next';
import { v4 as uuidv4 } from 'uuid';
import set from 'lodash/set';
@@ -6,10 +7,13 @@ import TextField from '../../../shared/TextField';
import TextArea from '../../../shared/TextArea';
import AppContext from '../../../context/AppContext';
import Checkbox from '../../../shared/Checkbox';
import { addItem, deleteItem, moveItemUp, moveItemDown } from '../../../utils';
import { addItem } from '../../../utils';
import ItemActions from '../../../shared/ItemActions';
import AddItemButton from '../../../shared/AddItemButton';
import ItemHeading from '../../../shared/ItemHeading';
const EducationTab = ({ data, onChange }) => {
const { t } = useTranslation();
const context = useContext(AppContext);
const { dispatch } = context;
@@ -24,7 +28,7 @@ const EducationTab = ({ data, onChange }) => {
</div>
<div className="col-span-5">
<TextField
placeholder="Heading"
placeholder={t('heading.placeholder')}
value={data.education.heading}
onChange={v => onChange('data.education.heading', v)}
/>
@@ -45,12 +49,71 @@ const EducationTab = ({ data, onChange }) => {
/>
))}
<AddItem dispatch={dispatch} />
<AddItem heading={data.education.heading} dispatch={dispatch} />
</>
);
};
const AddItem = ({ dispatch }) => {
const Form = ({ item, onChange, identifier = '' }) => {
const { t } = useTranslation(['leftSidebar', 'app']);
return (
<div>
<TextField
className="mb-6"
label={t('education.name.label')}
placeholder={t('education.name.placeholder')}
value={item.name}
onChange={v => onChange(`${identifier}name`, v)}
/>
<TextField
className="mb-6"
label={t('education.major.label')}
placeholder={t('education.major.placeholder')}
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={t('app:item.startDate.placeholder')}
value={item.start}
onChange={v => onChange(`${identifier}start`, v)}
/>
<TextField
className="mb-6"
label={t('app:item.endDate.label')}
placeholder={t('app:item.endDate.placeholder')}
value={item.end}
onChange={v => onChange(`${identifier}end`, v)}
/>
</div>
<TextArea
rows="5"
className="mb-6"
label={t('app:item.description.label')}
placeholder={t('education.description.placeholder')}
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(),
@@ -73,7 +136,7 @@ const AddItem = ({ dispatch }) => {
setItem({
id: uuidv4(),
enable: true,
title: '',
name: '',
role: '',
start: '',
end: '',
@@ -86,76 +149,11 @@ const AddItem = ({ dispatch }) => {
return (
<div className="my-4 border border-gray-200 rounded p-5">
<div
className="flex justify-between items-center cursor-pointer"
onClick={() => setOpen(!isOpen)}
>
<h6 className="text-sm font-medium">Add Education</h6>
<i className="material-icons">{isOpen ? 'expand_less' : 'expand_more'}</i>
</div>
<ItemHeading heading={heading} setOpen={setOpen} isOpen={isOpen} />
<div className={`mt-6 ${isOpen ? 'block' : 'hidden'}`}>
<TextField
label="Name"
className="mb-6"
placeholder="Harvard University"
value={item.name}
onChange={v => onChange('name', v)}
/>
<TextField
label="Major"
className="mb-6"
placeholder="Masters in Computer Science"
value={item.major}
onChange={v => onChange('major', v)}
/>
<TextField
label="Grade"
className="mb-6"
placeholder="7.2 CGPA"
value={item.grade}
onChange={v => onChange('grade', v)}
/>
<div className="grid grid-cols-2 col-gap-4">
<TextField
label="Start Date"
className="mb-6"
placeholder="March 2018"
value={item.start}
onChange={v => onChange('start', v)}
/>
<TextField
label="End Date"
className="mb-6"
placeholder="May 2020"
value={item.end}
onChange={v => onChange('end', v)}
/>
</div>
<TextArea
rows="5"
className="mb-6"
label="Description"
placeholder="You can write about projects or special credit classes that you took while studying at this school."
value={item.description}
onChange={v => onChange('description', v)}
/>
<button
type="button"
onClick={onSubmit}
className="bg-gray-600 hover:bg-gray-700 text-white text-sm font-medium py-2 px-5 rounded"
>
<div className="flex items-center">
<i className="material-icons mr-2 font-bold text-base">add</i>
<span className="text-sm">Add</span>
</div>
</button>
<Form item={item} onChange={onChange} />
<AddItemButton onSubmit={onSubmit} />
</div>
</div>
);
@@ -163,81 +161,23 @@ const AddItem = ({ dispatch }) => {
const Item = ({ item, index, onChange, dispatch, first, last }) => {
const [isOpen, setOpen] = useState(false);
const identifier = `data.education.items[${index}]`;
const identifier = `data.education.items[${index}].`;
return (
<div className="my-4 border border-gray-200 rounded p-5">
<div
className="flex justify-between items-center cursor-pointer"
onClick={() => setOpen(!isOpen)}
>
<h6 className="text-sm font-medium">{item.name}</h6>
<i className="material-icons">{isOpen ? 'expand_less' : 'expand_more'}</i>
</div>
<ItemHeading title={item.name} setOpen={setOpen} isOpen={isOpen} />
<div className={`mt-6 ${isOpen ? 'block' : 'hidden'}`}>
<TextField
label="Name"
className="mb-6"
placeholder="Harvard University"
value={item.name}
onChange={v => onChange(`${identifier}.name`, v)}
/>
<TextField
label="Major"
className="mb-6"
placeholder="Masters in Computer Science"
value={item.major}
onChange={v => onChange(`${identifier}.major`, v)}
/>
<TextField
label="Grade"
className="mb-6"
placeholder="7.2 CGPA"
value={item.grade}
onChange={v => onChange(`${identifier}.grade`, v)}
/>
<div className="grid grid-cols-2 col-gap-4">
<TextField
label="Start Date"
className="mb-6"
placeholder="March 2018"
value={item.start}
onChange={v => onChange(`${identifier}.start`, v)}
/>
<TextField
label="End Date"
className="mb-6"
placeholder="May 2020"
value={item.end}
onChange={v => onChange(`${identifier}.end`, v)}
/>
</div>
<TextArea
rows="5"
className="mb-6"
label="Description"
placeholder="You can write about projects or special credit classes that you took while studying at this school."
value={item.description}
onChange={v => onChange(`${identifier}.description`, v)}
/>
<Form item={item} onChange={onChange} identifier={identifier} />
<ItemActions
dispatch={dispatch}
first={first}
identifier={identifier}
item={item}
last={last}
onChange={onChange}
type="education"
identifier={identifier}
dispatch={dispatch}
deleteItem={deleteItem}
first={first}
moveItemUp={moveItemUp}
last={last}
moveItemDown={moveItemDown}
/>
</div>
</div>
+42 -66
View File
@@ -1,14 +1,18 @@
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, deleteItem, moveItemUp, moveItemDown } from '../../../utils';
import { addItem } from '../../../utils';
import ItemActions from '../../../shared/ItemActions';
import ItemHeading from '../../../shared/ItemHeading';
import AddItemButton from '../../../shared/AddItemButton';
const ExtrasTab = ({ data, onChange }) => {
const { t } = useTranslation();
const context = useContext(AppContext);
const { dispatch } = context;
@@ -23,7 +27,7 @@ const ExtrasTab = ({ data, onChange }) => {
</div>
<div className="col-span-5">
<TextField
placeholder="Heading"
placeholder={t('heading.placeholder')}
value={data.extras.heading}
onChange={v => onChange('data.extras.heading', v)}
/>
@@ -44,12 +48,36 @@ const ExtrasTab = ({ data, onChange }) => {
/>
))}
<AddItem dispatch={dispatch} />
<AddItem heading={data.extras.heading} dispatch={dispatch} />
</>
);
};
const AddItem = ({ dispatch }) => {
const Form = ({ item, onChange, identifier = '' }) => {
const { t } = useTranslation('leftSidebar');
return (
<div>
<TextField
className="mb-6"
label={t('extras.key.label')}
placeholder={t('extras.key.placeholder')}
value={item.key}
onChange={v => onChange(`${identifier}key`, v)}
/>
<TextField
className="mb-6"
label={t('extras.value.label')}
placeholder={t('extras.value.placeholder')}
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(),
@@ -77,41 +105,12 @@ const AddItem = ({ dispatch }) => {
return (
<div className="my-4 border border-gray-200 rounded p-5">
<div
className="flex justify-between items-center cursor-pointer"
onClick={() => setOpen(!isOpen)}
>
<h6 className="text-sm font-medium">Add Item</h6>
<i className="material-icons">{isOpen ? 'expand_less' : 'expand_more'}</i>
</div>
<ItemHeading heading={heading} setOpen={setOpen} isOpen={isOpen} />
<div className={`mt-6 ${isOpen ? 'block' : 'hidden'}`}>
<TextField
label="Key"
className="mb-6"
placeholder="Date of Birth"
value={item.key}
onChange={v => onChange('key', v)}
/>
<Form item={item} onChange={onChange} />
<TextField
label="Value"
className="mb-6"
placeholder="6th August 1995"
value={item.value}
onChange={v => onChange('value', v)}
/>
<button
type="button"
onClick={onSubmit}
className="bg-gray-600 hover:bg-gray-700 text-white text-sm font-medium py-2 px-5 rounded"
>
<div className="flex items-center">
<i className="material-icons mr-2 font-bold text-base">add</i>
<span className="text-sm">Add</span>
</div>
</button>
<AddItemButton onSubmit={onSubmit} />
</div>
</div>
);
@@ -119,46 +118,23 @@ const AddItem = ({ dispatch }) => {
const Item = ({ item, index, onChange, dispatch, first, last }) => {
const [isOpen, setOpen] = useState(false);
const identifier = `data.extras.items[${index}]`;
const identifier = `data.extras.items[${index}].`;
return (
<div className="my-4 border border-gray-200 rounded p-5">
<div
className="flex justify-between items-center cursor-pointer"
onClick={() => setOpen(!isOpen)}
>
<h6 className="text-sm font-medium">{item.key}</h6>
<i className="material-icons">{isOpen ? 'expand_less' : 'expand_more'}</i>
</div>
<ItemHeading title={item.key} setOpen={setOpen} isOpen={isOpen} />
<div className={`mt-6 ${isOpen ? 'block' : 'hidden'}`}>
<TextField
label="Key"
className="mb-6"
placeholder="Date of Birth"
value={item.key}
onChange={v => onChange(`${identifier}.key`, v)}
/>
<TextField
label="Value"
className="mb-6"
placeholder="6th August 1995"
value={item.value}
onChange={v => onChange(`${identifier}.value`, v)}
/>
<Form item={item} onChange={onChange} identifier={identifier} />
<ItemActions
dispatch={dispatch}
first={first}
identifier={identifier}
item={item}
last={last}
onChange={onChange}
type="extras"
identifier={identifier}
dispatch={dispatch}
deleteItem={deleteItem}
first={first}
moveItemUp={moveItemUp}
last={last}
moveItemDown={moveItemDown}
/>
</div>
</div>
+42 -66
View File
@@ -1,4 +1,5 @@
import React, { useState, useEffect, useContext } from 'react';
import { useTranslation } from 'react-i18next';
import { v4 as uuidv4 } from 'uuid';
import set from 'lodash/set';
@@ -6,10 +7,13 @@ import TextField from '../../../shared/TextField';
import AppContext from '../../../context/AppContext';
import Checkbox from '../../../shared/Checkbox';
import Counter from '../../../shared/Counter';
import { addItem, deleteItem, moveItemUp, moveItemDown } from '../../../utils';
import { addItem } from '../../../utils';
import ItemActions from '../../../shared/ItemActions';
import AddItemButton from '../../../shared/AddItemButton';
import ItemHeading from '../../../shared/ItemHeading';
const LanguagesTab = ({ data, onChange }) => {
const { t } = useTranslation('app');
const context = useContext(AppContext);
const { dispatch } = context;
@@ -43,7 +47,7 @@ const LanguagesTab = ({ data, onChange }) => {
</div>
<div className="col-span-5">
<TextField
placeholder="Heading"
placeholder={t('heading.placeholder')}
value={data.languages.heading}
onChange={v => onChange('data.languages.heading', v)}
/>
@@ -64,13 +68,37 @@ const LanguagesTab = ({ data, onChange }) => {
/>
))}
<AddItem dispatch={dispatch} />
<AddItem heading={data.languages.heading} dispatch={dispatch} />
</>
)
);
};
const AddItem = ({ dispatch }) => {
const Form = ({ item, onChange, identifier = '' }) => {
const { t } = useTranslation('leftSidebar');
return (
<div>
<TextField
className="mb-6"
label={t('languages.key.label')}
placeholder={t('languages.key.placeholder')}
value={item.key}
onChange={v => onChange(`${identifier}key`, v)}
/>
<Counter
className="mb-6"
label={t('languages.rating.label')}
value={item.value}
onDecrement={() => item.value > 1 && onChange(`${identifier}value`, item.value - 1)}
onIncrement={() => item.value < 5 && onChange(`${identifier}value`, item.value + 1)}
/>
</div>
);
};
const AddItem = ({ heading, dispatch }) => {
const [isOpen, setOpen] = useState(false);
const [item, setItem] = useState({
id: uuidv4(),
@@ -98,41 +126,12 @@ const AddItem = ({ dispatch }) => {
return (
<div className="my-4 border border-gray-200 rounded p-5">
<div
className="flex justify-between items-center cursor-pointer"
onClick={() => setOpen(!isOpen)}
>
<h6 className="text-sm font-medium">Add Language</h6>
<i className="material-icons">{isOpen ? 'expand_less' : 'expand_more'}</i>
</div>
<ItemHeading heading={heading} setOpen={setOpen} isOpen={isOpen} />
<div className={`mt-6 ${isOpen ? 'block' : 'hidden'}`}>
<TextField
label="Key"
className="mb-6"
placeholder="Dothraki"
value={item.key}
onChange={v => onChange('key', v)}
/>
<Form item={item} onChange={onChange} />
<Counter
label="Rating"
className="mb-6"
value={item.value}
onDecrement={() => item.value > 1 && onChange('value', item.value - 1)}
onIncrement={() => item.value < 5 && onChange('value', item.value + 1)}
/>
<button
type="button"
onClick={onSubmit}
className="bg-gray-600 hover:bg-gray-700 text-white text-sm font-medium py-2 px-5 rounded"
>
<div className="flex items-center">
<i className="material-icons mr-2 font-bold text-base">add</i>
<span className="text-sm">Add</span>
</div>
</button>
<AddItemButton onSubmit={onSubmit} />
</div>
</div>
);
@@ -140,46 +139,23 @@ const AddItem = ({ dispatch }) => {
const Item = ({ item, index, onChange, dispatch, first, last }) => {
const [isOpen, setOpen] = useState(false);
const identifier = `data.languages.items[${index}]`;
const identifier = `data.languages.items[${index}].`;
return (
<div className="my-4 border border-gray-200 rounded p-5">
<div
className="flex justify-between items-center cursor-pointer"
onClick={() => setOpen(!isOpen)}
>
<h6 className="text-sm font-medium">{item.key}</h6>
<i className="material-icons">{isOpen ? 'expand_less' : 'expand_more'}</i>
</div>
<ItemHeading title={item.key} setOpen={setOpen} isOpen={isOpen} />
<div className={`mt-6 ${isOpen ? 'block' : 'hidden'}`}>
<TextField
label="Name"
className="mb-6"
placeholder="Dothraki"
value={item.key}
onChange={v => onChange(`${identifier}.key`, v)}
/>
<Counter
label="Rating"
className="mb-6"
value={item.value}
onDecrement={() => item.value > 1 && onChange(`${identifier}.value`, item.value - 1)}
onIncrement={() => item.value < 5 && onChange(`${identifier}.value`, item.value + 1)}
/>
<Form item={item} onChange={onChange} identifier={identifier} />
<ItemActions
dispatch={dispatch}
first={first}
identifier={identifier}
item={item}
last={last}
onChange={onChange}
type="languages"
identifier={identifier}
dispatch={dispatch}
deleteItem={deleteItem}
first={first}
moveItemUp={moveItemUp}
last={last}
moveItemDown={moveItemDown}
/>
</div>
</div>
+7 -3
View File
@@ -1,9 +1,13 @@
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', 'app']);
return (
<div>
<div className="mb-6 grid grid-cols-6 items-center">
@@ -15,7 +19,7 @@ const ObjectiveTab = ({ data, onChange }) => {
</div>
<div className="col-span-5">
<TextField
placeholder="Heading"
placeholder={t('app:heading.placeholder')}
value={data.objective.heading}
onChange={v => onChange('data.objective.heading', v)}
/>
@@ -27,8 +31,8 @@ const ObjectiveTab = ({ data, onChange }) => {
<TextArea
rows="15"
className="mb-4"
label="Objective"
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."
label={t('objective.objective.label')}
placeholder={t('objective.objective.placeholder')}
value={data.objective.body}
onChange={v => onChange('data.objective.body', v)}
/>
+86 -79
View File
@@ -1,93 +1,100 @@
import React from 'react';
import { useTranslation } from 'react-i18next';
import TextField from '../../../shared/TextField';
const ProfileTab = ({ data, onChange }) => (
<div>
<TextField
className="mb-6"
label="Photo URL"
placeholder="https://i.imgur.com/..."
value={data.profile.photo}
onChange={v => onChange('data.profile.photo', v)}
/>
const ProfileTab = ({ data, onChange }) => {
const { t } = useTranslation('leftSidebar');
<div className="grid grid-cols-2 col-gap-4">
return (
<div>
<TextField
className="mb-6"
label="First Name"
placeholder="Jane"
value={data.profile.firstName}
onChange={v => onChange('data.profile.firstName', v)}
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={t('profile.firstName.placeholder')}
value={data.profile.firstName}
onChange={v => onChange('data.profile.firstName', v)}
/>
<TextField
className="mb-6"
label={t('profile.lastName.label')}
placeholder={t('profile.lastName.placeholder')}
value={data.profile.lastName}
onChange={v => onChange('data.profile.lastName', v)}
/>
</div>
<TextField
className="mb-6"
label={t('profile.subtitle.label')}
placeholder={t('profile.subtitle.placeholder')}
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={t('profile.address.line1.placeholder')}
value={data.profile.address.line1}
onChange={v => onChange('data.profile.address.line1', v)}
/>
<TextField
className="mb-6"
label="Last Name"
placeholder="Doe"
value={data.profile.lastName}
onChange={v => onChange('data.profile.lastName', v)}
label={t('profile.address.line2.label')}
placeholder={t('profile.address.line2.placeholder')}
value={data.profile.address.line2}
onChange={v => onChange('data.profile.address.line2', v)}
/>
<TextField
className="mb-6"
label={t('profile.address.line3.label')}
placeholder={t('profile.address.line3.placeholder')}
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="google.com"
value={data.profile.website}
onChange={v => onChange('data.profile.website', v)}
/>
<TextField
className="mb-6"
label={t('profile.email.label')}
placeholder="john.doe@example.com"
value={data.profile.email}
onChange={v => onChange('data.profile.email', v)}
/>
</div>
);
};
<TextField
className="mb-6"
label="Subtitle"
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="Address Line 1"
placeholder="Palladium Complex"
value={data.profile.address.line1}
onChange={v => onChange('data.profile.address.line1', v)}
/>
<TextField
className="mb-6"
label="Address Line 2"
placeholder="140 E 14th St"
value={data.profile.address.line2}
onChange={v => onChange('data.profile.address.line2', v)}
/>
<TextField
className="mb-6"
label="Address Line 3"
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="Phone Number"
placeholder="+1 541 754 3010"
value={data.profile.phone}
onChange={v => onChange('data.profile.phone', v)}
/>
<TextField
className="mb-6"
label="Website"
placeholder="google.com"
value={data.profile.website}
onChange={v => onChange('data.profile.website', v)}
/>
<TextField
className="mb-6"
label="Email Address"
placeholder="john.doe@example.com"
value={data.profile.email}
onChange={v => onChange('data.profile.email', v)}
/>
</div>
);
export default ProfileTab;
+67 -116
View File
@@ -1,4 +1,5 @@
import React, { useState, useEffect, useContext } from 'react';
import { useTranslation } from 'react-i18next';
import { v4 as uuidv4 } from 'uuid';
import set from 'lodash/set';
@@ -6,10 +7,13 @@ import TextField from '../../../shared/TextField';
import TextArea from '../../../shared/TextArea';
import AppContext from '../../../context/AppContext';
import Checkbox from '../../../shared/Checkbox';
import { addItem, deleteItem, moveItemUp, moveItemDown } from '../../../utils';
import { addItem } from '../../../utils';
import ItemActions from '../../../shared/ItemActions';
import ItemHeading from '../../../shared/ItemHeading';
import AddItemButton from '../../../shared/AddItemButton';
const ReferencesTab = ({ data, onChange }) => {
const { t } = useTranslation();
const context = useContext(AppContext);
const { dispatch } = context;
@@ -43,7 +47,7 @@ const ReferencesTab = ({ data, onChange }) => {
</div>
<div className="col-span-5">
<TextField
placeholder="Heading"
placeholder={t('heading.placeholder')}
value={data.references.heading}
onChange={v => onChange('data.references.heading', v)}
/>
@@ -64,13 +68,62 @@ const ReferencesTab = ({ data, onChange }) => {
/>
))}
<AddItem dispatch={dispatch} />
<AddItem heading={data.references.heading} dispatch={dispatch} />
</>
)
);
};
const AddItem = ({ dispatch }) => {
const Form = ({ item, onChange, identifier = '' }) => {
const { t } = useTranslation(['leftSidebar', 'app']);
return (
<div>
<TextField
className="mb-6"
label={t('references.name.label')}
placeholder={t('references.name.placeholder')}
value={item.name}
onChange={v => onChange(`${identifier}name`, v)}
/>
<TextField
className="mb-6"
label={t('references.position.label')}
placeholder={t('references.position.placeholder')}
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')}
placeholder={t('references.description.placeholder')}
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(),
@@ -104,66 +157,12 @@ const AddItem = ({ dispatch }) => {
return (
<div className="my-4 border border-gray-200 rounded p-5">
<div
className="flex justify-between items-center cursor-pointer"
onClick={() => setOpen(!isOpen)}
>
<h6 className="text-sm font-medium">Add Reference</h6>
<i className="material-icons">{isOpen ? 'expand_less' : 'expand_more'}</i>
</div>
<ItemHeading heading={heading} setOpen={setOpen} isOpen={isOpen} />
<div className={`mt-6 ${isOpen ? 'block' : 'hidden'}`}>
<TextField
label="Name"
className="mb-6"
placeholder="Steve Jobs"
value={item.name}
onChange={v => onChange('name', v)}
/>
<Form item={item} onChange={onChange} />
<TextField
label="Position"
className="mb-6"
placeholder="CEO of Apple"
value={item.position}
onChange={v => onChange('position', v)}
/>
<TextField
label="Phone Number"
className="mb-6"
placeholder="+1 123 456 7890"
value={item.phone}
onChange={v => onChange('phone', v)}
/>
<TextField
label="Email Address"
className="mb-6"
placeholder="steve@apple.com"
value={item.email}
onChange={v => onChange('email', v)}
/>
<TextArea
rows="5"
className="mb-6"
label="Description"
placeholder="You can write about how you and the reference contact worked together and which projects you were a part of."
value={item.description}
onChange={v => onChange('description', v)}
/>
<button
type="button"
onClick={onSubmit}
className="bg-gray-600 hover:bg-gray-700 text-white text-sm font-medium py-2 px-5 rounded"
>
<div className="flex items-center">
<i className="material-icons mr-2 font-bold text-base">add</i>
<span className="text-sm">Add</span>
</div>
</button>
<AddItemButton onSubmit={onSubmit} />
</div>
</div>
);
@@ -171,71 +170,23 @@ const AddItem = ({ dispatch }) => {
const Item = ({ item, index, onChange, dispatch, first, last }) => {
const [isOpen, setOpen] = useState(false);
const identifier = `data.references.items[${index}]`;
const identifier = `data.references.items[${index}].`;
return (
<div className="my-4 border border-gray-200 rounded p-5">
<div
className="flex justify-between items-center cursor-pointer"
onClick={() => setOpen(!isOpen)}
>
<h6 className="text-sm font-medium">{item.name}</h6>
<i className="material-icons">{isOpen ? 'expand_less' : 'expand_more'}</i>
</div>
<ItemHeading title={item.name} setOpen={setOpen} isOpen={isOpen} />
<div className={`mt-6 ${isOpen ? 'block' : 'hidden'}`}>
<TextField
label="Name"
className="mb-6"
placeholder="Steve Jobs"
value={item.name}
onChange={v => onChange(`${identifier}.name`, v)}
/>
<TextField
label="Position"
className="mb-6"
placeholder="CEO of Apple"
value={item.position}
onChange={v => onChange(`${identifier}.position`, v)}
/>
<TextField
label="Phone Number"
className="mb-6"
placeholder="+1 123 456 7890"
value={item.phone}
onChange={v => onChange(`${identifier}.phone`, v)}
/>
<TextField
label="Email Address"
className="mb-6"
placeholder="steve@apple.com"
value={item.email}
onChange={v => onChange(`${identifier}.email`, v)}
/>
<TextArea
rows="5"
className="mb-6"
label="Description"
placeholder="You can write about how you and the reference contact worked together and which projects you were a part of."
value={item.description}
onChange={v => onChange(`${identifier}.description`, v)}
/>
<Form item={item} onChange={onChange} identifier={identifier} />
<ItemActions
dispatch={dispatch}
first={first}
identifier={identifier}
item={item}
last={last}
onChange={onChange}
type="references"
identifier={identifier}
dispatch={dispatch}
deleteItem={deleteItem}
first={first}
moveItemUp={moveItemUp}
last={last}
moveItemDown={moveItemDown}
/>
</div>
</div>
+27 -28
View File
@@ -1,11 +1,14 @@
import React, { useState, useContext } from 'react';
import { useTranslation } from 'react-i18next';
import AppContext from '../../../context/AppContext';
import Checkbox from '../../../shared/Checkbox';
import TextField from '../../../shared/TextField';
import { addItem, deleteItem } from '../../../utils';
import ItemHeading from '../../../shared/ItemHeading';
const SkillsTab = ({ data, onChange }) => {
const { t } = useTranslation();
const context = useContext(AppContext);
const { dispatch } = context;
@@ -20,7 +23,7 @@ const SkillsTab = ({ data, onChange }) => {
</div>
<div className="col-span-5">
<TextField
placeholder="Heading"
placeholder={t('heading.placeholder')}
value={data.skills.heading}
onChange={v => onChange('data.skills.heading', v)}
/>
@@ -33,12 +36,26 @@ const SkillsTab = ({ data, onChange }) => {
<Item item={x} key={index} index={index} onChange={onChange} dispatch={dispatch} />
))}
<AddItem dispatch={dispatch} />
<AddItem heading={data.skills.heading} dispatch={dispatch} />
</>
);
};
const AddItem = ({ dispatch }) => {
const Form = ({ item, onChange }) => {
const { t } = useTranslation('leftSidebar');
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={t('skills.item.placeholder')}
value={item}
onChange={e => onChange(e.target.value)}
type="text"
/>
);
};
const AddItem = ({ heading, dispatch }) => {
const [isOpen, setOpen] = useState(false);
const [item, setItem] = useState('');
@@ -52,33 +69,21 @@ const AddItem = ({ dispatch }) => {
return (
<div className="my-4 border border-gray-200 rounded p-5">
<div
className="flex justify-between items-center cursor-pointer"
onClick={() => setOpen(!isOpen)}
>
<h6 className="text-sm font-medium">Add Skill</h6>
<i className="material-icons">{isOpen ? 'expand_less' : 'expand_more'}</i>
</div>
<ItemHeading heading={heading} setOpen={setOpen} isOpen={isOpen} />
<div className={`mt-6 ${isOpen ? 'block' : 'hidden'}`}>
<div className="grid grid-cols-4 col-gap-4">
<div className="grid grid-cols-4 gap-4">
<div className="col-span-3">
<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="Cooking"
value={item}
onChange={e => setItem(e.target.value)}
type="text"
/>
<Form item={item} onChange={setItem} />
</div>
<button
type="button"
onClick={add}
className="col-span-1 bg-gray-600 hover:bg-gray-700 text-white text-sm font-medium rounded"
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-lg">add</i>
<i className="material-icons font-bold text-white text-lg">add</i>
</div>
</button>
</div>
@@ -91,15 +96,9 @@ const Item = ({ item, index, onChange, dispatch }) => {
const identifier = `data.skills.items[${index}]`;
return (
<div className="my-4 grid grid-cols-6">
<div className="my-4 grid grid-cols-6 gap-4">
<div className="col-span-5">
<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="Cooking"
value={item}
onChange={e => onChange(`${identifier}`, e.target.value)}
type="text"
/>
<Form item={item} onChange={v => onChange(identifier, v)} />
</div>
<button
+73 -124
View File
@@ -1,4 +1,5 @@
import React, { useState, useContext } from 'react';
import { useTranslation } from 'react-i18next';
import { v4 as uuidv4 } from 'uuid';
import set from 'lodash/set';
@@ -6,10 +7,13 @@ import TextField from '../../../shared/TextField';
import TextArea from '../../../shared/TextArea';
import AppContext from '../../../context/AppContext';
import Checkbox from '../../../shared/Checkbox';
import { addItem, deleteItem, moveItemUp, moveItemDown } from '../../../utils';
import { addItem } from '../../../utils';
import ItemActions from '../../../shared/ItemActions';
import AddItemButton from '../../../shared/AddItemButton';
import ItemHeading from '../../../shared/ItemHeading';
const WorkTab = ({ data, onChange }) => {
const { t } = useTranslation();
const context = useContext(AppContext);
const { dispatch } = context;
@@ -21,7 +25,7 @@ const WorkTab = ({ data, onChange }) => {
</div>
<div className="col-span-5">
<TextField
placeholder="Heading"
placeholder={t('heading.placeholder')}
value={data.work.heading}
onChange={v => onChange('data.work.heading', v)}
/>
@@ -32,22 +36,73 @@ const WorkTab = ({ data, onChange }) => {
{data.work.items.map((x, index) => (
<Item
item={x}
key={x.id}
index={index}
onChange={onChange}
dispatch={dispatch}
first={index === 0}
index={index}
item={x}
key={x.id}
last={index === data.work.items.length - 1}
onChange={onChange}
/>
))}
<AddItem dispatch={dispatch} />
<AddItem heading={data.work.heading} dispatch={dispatch} />
</>
);
};
const AddItem = ({ dispatch }) => {
const Form = ({ item, onChange, identifier = '' }) => {
const { t } = useTranslation(['leftSidebar', 'app']);
return (
<div>
<TextField
className="mb-6"
label={t('work.name.label')}
placeholder={t('work.name.placeholder')}
value={item.title}
onChange={v => onChange(`${identifier}title`, v)}
/>
<TextField
className="mb-6"
label={t('work.role.label')}
placeholder={t('work.role.placeholder')}
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={t('app:item.startDate.placeholder')}
value={item.start}
onChange={v => onChange(`${identifier}start`, v)}
/>
<TextField
className="mb-6"
label={t('app:item.endDate.label')}
placeholder={t('app:item.endDate.placeholder')}
value={item.end}
onChange={v => onChange(`${identifier}end`, v)}
/>
</div>
<TextArea
rows="5"
className="mb-6"
label={t('app:item.description.label')}
placeholder={t('work.description.placeholder')}
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(),
@@ -81,68 +136,12 @@ const AddItem = ({ dispatch }) => {
return (
<div className="my-4 border border-gray-200 rounded p-5">
<div
className="flex justify-between items-center cursor-pointer"
onClick={() => setOpen(!isOpen)}
>
<h6 className="text-sm font-medium">Add Work Experience</h6>
<i className="material-icons">{isOpen ? 'expand_less' : 'expand_more'}</i>
</div>
<ItemHeading heading={heading} setOpen={setOpen} isOpen={isOpen} />
<div className={`mt-6 ${isOpen ? 'block' : 'hidden'}`}>
<TextField
label="Name"
className="mb-6"
placeholder="Amazon US"
value={item.title}
onChange={v => onChange('title', v)}
/>
<Form item={item} onChange={onChange} />
<TextField
label="Role"
className="mb-6"
placeholder="Frontend Web Developer"
value={item.role}
onChange={v => onChange('role', v)}
/>
<div className="grid grid-cols-2 col-gap-4">
<TextField
label="Start Date"
className="mb-6"
placeholder="March 2018"
value={item.start}
onChange={v => onChange('start', v)}
/>
<TextField
label="End Date"
className="mb-6"
placeholder="current"
value={item.end}
onChange={v => onChange('end', v)}
/>
</div>
<TextArea
rows="5"
className="mb-6"
label="Description"
placeholder="You can write about what you specialized in while working at the company and what projects you were a part of."
value={item.description}
onChange={v => onChange('description', v)}
/>
<button
type="button"
onClick={onSubmit}
className="bg-gray-600 hover:bg-gray-700 text-white text-sm font-medium py-2 px-5 rounded"
>
<div className="flex items-center">
<i className="material-icons mr-2 font-bold text-base">add</i>
<span className="text-sm">Add</span>
</div>
</button>
<AddItemButton onSubmit={onSubmit} />
</div>
</div>
);
@@ -150,73 +149,23 @@ const AddItem = ({ dispatch }) => {
const Item = ({ item, index, onChange, dispatch, first, last }) => {
const [isOpen, setOpen] = useState(false);
const identifier = `data.work.items[${index}]`;
const identifier = `data.work.items[${index}].`;
return (
<div className="my-4 border border-gray-200 rounded p-5">
<div
className="flex justify-between items-center cursor-pointer"
onClick={() => setOpen(!isOpen)}
>
<h6 className="ml-2 text-sm font-medium">{item.title}</h6>
<i className="material-icons">{isOpen ? 'expand_less' : 'expand_more'}</i>
</div>
<ItemHeading title={item.title} setOpen={setOpen} isOpen={isOpen} />
<div className={`mt-6 ${isOpen ? 'block' : 'hidden'}`}>
<TextField
label="Name"
className="mb-6"
placeholder="Amazon US"
value={item.title}
onChange={v => onChange(`${identifier}.title`, v)}
/>
<TextField
label="Role"
className="mb-6"
placeholder="Frontend Web Developer"
value={item.role}
onChange={v => onChange(`${identifier}.role`, v)}
/>
<div className="grid grid-cols-2 col-gap-4">
<TextField
label="Start Date"
className="mb-6"
placeholder="March 2018"
value={item.start}
onChange={v => onChange(`${identifier}.start`, v)}
/>
<TextField
label="End Date"
className="mb-6"
placeholder="current"
value={item.end}
onChange={v => onChange(`${identifier}.end`, v)}
/>
</div>
<TextArea
rows="5"
className="mb-6"
label="Description"
placeholder="You can write about what you specialized in while working at the company and what projects you were a part of."
value={item.description}
onChange={v => onChange(`${identifier}.description`, v)}
/>
<Form item={item} onChange={onChange} identifier={identifier} />
<ItemActions
dispatch={dispatch}
first={first}
identifier={identifier}
item={item}
last={last}
onChange={onChange}
type="work"
identifier={identifier}
dispatch={dispatch}
deleteItem={deleteItem}
first={first}
moveItemUp={moveItemUp}
last={last}
moveItemDown={moveItemDown}
/>
</div>
</div>
+22 -9
View File
@@ -1,4 +1,5 @@
import React, { useState, useContext } from 'react';
import { useTranslation } from 'react-i18next';
import AppContext from '../../context/AppContext';
import TabBar from '../../shared/TabBar';
@@ -7,15 +8,25 @@ import ColorsTab from './tabs/Colors';
import FontsTab from './tabs/Fonts';
import ActionsTab from './tabs/Actions';
import AboutTab from './tabs/About';
const tabs = ['Templates', 'Colors', 'Fonts', 'Actions', 'About'];
import SettingsTab from './tabs/Settings';
const RightSidebar = () => {
const { t } = useTranslation('rightSidebar');
const context = useContext(AppContext);
const { state, dispatch } = context;
const { data, theme } = state;
const { data, theme, settings } = state;
const tabs = [
t('templates.title'),
t('colors.title'),
t('fonts.title'),
t('actions.title'),
t('settings.title'),
t('about.title'),
];
const [currentTab, setCurrentTab] = useState(t('settings.title'));
const [currentTab, setCurrentTab] = useState('Templates');
const onChange = (key, value) => {
dispatch({
type: 'on_input',
@@ -30,15 +41,17 @@ const RightSidebar = () => {
const renderTabs = () => {
switch (currentTab) {
case 'Templates':
case t('templates.title'):
return <TemplatesTab theme={theme} onChange={onChange} />;
case 'Colors':
case t('colors.title'):
return <ColorsTab theme={theme} onChange={onChange} />;
case 'Fonts':
case t('fonts.title'):
return <FontsTab theme={theme} onChange={onChange} />;
case 'Actions':
case t('actions.title'):
return <ActionsTab data={data} theme={theme} dispatch={dispatch} />;
case 'About':
case t('settings.title'):
return <SettingsTab settings={settings} onChange={onChange} />;
case t('about.title'):
return <AboutTab />;
default:
return null;
+29 -41
View File
@@ -1,16 +1,15 @@
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">Documentation</h6>
<h6 className="font-bold text-sm mb-2">{t('about.documentation.heading')}</h6>
<div className="text-sm">
Want to know more about the app? Wouldn&apos;t it be nice if there was a guide to setting
it up on your local machine? Need information on how to contribute to the project? Look no
further, there&apos;s a comprehensive documentation made just for you.
</div>
<div className="text-sm">{t('about.documentation.body')}</div>
<a
target="_blank"
@@ -20,7 +19,7 @@ const AboutTab = () => {
>
<div className="flex justify-center items-center">
<i className="material-icons mr-2 font-bold text-base">description</i>
<span className="text-sm">Documentation</span>
<span className="text-sm">{t('about.documentation.buttons.documentation')}</span>
</div>
</a>
</div>
@@ -28,13 +27,9 @@ const AboutTab = () => {
<hr className="my-5" />
<div className="shadow text-center p-5">
<h6 className="font-bold text-sm mb-2">Bug? Feature Request?</h6>
<h6 className="font-bold text-sm mb-2">{t('about.bugOrFeatureRequest.heading')}</h6>
<div className="text-sm">
Something halting your progress from making a resume? Found a pesky bug that just
won&apos;t quit? Talk about it on the GitHub Issues section, or send me and email using
the actions below.
</div>
<div className="text-sm">{t('about.bugOrFeatureRequest.body')}</div>
<div className="grid grid-cols-1">
<a
@@ -45,7 +40,7 @@ const AboutTab = () => {
>
<div className="flex justify-center items-center">
<i className="material-icons mr-2 font-bold text-base">bug_report</i>
<span className="text-sm">Raise an Issue</span>
<span className="text-sm">{t('about.bugOrFeatureRequest.buttons.raiseIssue')}</span>
</div>
</a>
@@ -57,7 +52,7 @@ const AboutTab = () => {
>
<div className="flex justify-center items-center">
<i className="material-icons mr-2 font-bold text-base">email</i>
<span className="text-sm">Send an Email</span>
<span className="text-sm">{t('about.bugOrFeatureRequest.buttons.sendEmail')}</span>
</div>
</a>
</div>
@@ -66,12 +61,9 @@ const AboutTab = () => {
<hr className="my-5" />
<div className="shadow text-center p-5">
<h6 className="font-bold text-sm mb-2">Source Code</h6>
<h6 className="font-bold text-sm mb-2">{t('about.sourceCode.heading')}</h6>
<div className="text-sm">
Want to run the project from it&apos;s source? Are you a developer willing to contribute
to the open source development of this project? Click the button below.
</div>
<div className="text-sm">{t('about.sourceCode.body')}</div>
<a
target="_blank"
@@ -81,7 +73,7 @@ const AboutTab = () => {
>
<div className="flex justify-center items-center">
<i className="material-icons mr-2 font-bold text-base">code</i>
<span className="text-sm">GitHub Repo</span>
<span className="text-sm">{t('about.sourceCode.buttons.githubRepo')}</span>
</div>
</a>
</div>
@@ -89,13 +81,9 @@ const AboutTab = () => {
<hr className="my-5" />
<div className="shadow text-center p-5">
<h6 className="font-bold text-sm mb-2">License Information</h6>
<h6 className="font-bold text-sm mb-2">{t('about.license.heading')}</h6>
<div className="text-sm">
The project is governed under the MIT License, which you can read more about below.
Basically, you are allowed to use the project anywhere provided you give credits to the
original author.
</div>
<div className="text-sm">{t('about.license.body')}</div>
<a
target="_blank"
@@ -105,27 +93,27 @@ const AboutTab = () => {
>
<div className="flex justify-center items-center">
<i className="material-icons mr-2 font-bold text-base">policy</i>
<span className="text-sm">MIT License</span>
<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">
Reactive Resume is a project by{' '}
<a
className="hover:underline"
href="https://www.amruthpillai.com/"
rel="noopener noreferrer"
target="_blank"
>
<strong>Amruth Pillai</strong>
</a>{' '}
in hopes of allowing anyone to make beautiful resumes and get equal job opportunities.
<br />
<br />
Thank you for using Reactive Resume!
<Trans t={t} i18nKey="about.footer.credit">
Reactive Resume is a project 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>
);
+20 -29
View File
@@ -1,8 +1,10 @@
/* eslint-disable jsx-a11y/anchor-has-content */
/* eslint-disable jsx-a11y/anchor-is-valid */
import React, { useRef } from 'react';
import { useTranslation, Trans } from 'react-i18next';
const ActionsTab = ({ data, theme, dispatch }) => {
const { t } = useTranslation('rightSidebar');
const fileInputRef = useRef(null);
const importJson = event => {
@@ -36,20 +38,14 @@ const ActionsTab = ({ data, theme, dispatch }) => {
return (
<div>
<div className="shadow text-center text-sm p-5">
Changes you make to your resume are saved automatically to your browser&apos;s local
storage. No data gets out, hence your information is completely secure.
</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">Import/Export</h6>
<h6 className="font-bold text-sm mb-2">{t('actions.importExport.heading')}</h6>
<p className="text-sm">
You can import or export your data in JSON format. With this, you can edit and print your
resume from any device. Save this file for later use.
</p>
<p className="text-sm">{t('actions.importExport.body')}</p>
<input ref={fileInputRef} type="file" className="hidden" onChange={importJson} />
<a id="downloadAnchor" className="hidden" />
@@ -62,7 +58,7 @@ const ActionsTab = ({ data, theme, dispatch }) => {
>
<div className="flex justify-center items-center">
<i className="material-icons mr-2 font-bold text-base">publish</i>
<span className="text-sm">Import</span>
<span className="text-sm">{t('actions.importExport.buttons.import')}</span>
</div>
</button>
@@ -73,7 +69,7 @@ const ActionsTab = ({ data, theme, dispatch }) => {
>
<div className="flex justify-center items-center">
<i className="material-icons mr-2 font-bold text-base">get_app</i>
<span className="text-sm">Export</span>
<span className="text-sm">{t('actions.importExport.buttons.export')}</span>
</div>
</button>
</div>
@@ -82,12 +78,14 @@ const ActionsTab = ({ data, theme, dispatch }) => {
<hr className="my-6" />
<div className="shadow text-center p-5">
<h6 className="font-bold text-sm mb-2">Print Your Resume</h6>
<h6 className="font-bold text-sm mb-2">{t('actions.printResume.heading')}</h6>
<div className="text-sm">
You can simply press <pre className="inline font-bold">Cmd/Ctrl + P</pre> at any time
while you&apos;re in the app to print your resume, but here&apos;s a fancy button to do
the same thing, just &apos;cause.
<Trans t={t} i18nKey="actions.printResume.body">
You can simply press <pre className="inline font-bold">Cmd/Ctrl + P</pre> at any time
while you&apos;re in the app to print your resume, but here&apos;s a fancy button to do
the same thing, just &apos;cause.
</Trans>
</div>
<button
@@ -97,7 +95,7 @@ const ActionsTab = ({ data, theme, dispatch }) => {
>
<div className="flex justify-center items-center">
<i className="material-icons mr-2 font-bold text-base">print</i>
<span className="text-sm">Print</span>
<span className="text-sm">{t('actions.printResume.buttons.print')}</span>
</div>
</button>
</div>
@@ -105,12 +103,9 @@ const ActionsTab = ({ data, theme, dispatch }) => {
<hr className="my-6" />
<div className="shadow text-center p-5">
<h6 className="font-bold text-sm mb-2">Load Dummy Data</h6>
<h6 className="font-bold text-sm mb-2">{t('actions.loadDummyData.heading')}</h6>
<div className="text-sm">
Unclear on what to do with a fresh blank page? Load some dummy data with pre-populated
values to see how a resume should look and you can start editing from there.
</div>
<div className="text-sm">{t('actions.loadDummyData.body')}</div>
<button
type="button"
@@ -119,7 +114,7 @@ const ActionsTab = ({ data, theme, dispatch }) => {
>
<div className="flex justify-center items-center">
<i className="material-icons mr-2 font-bold text-base">flight_takeoff</i>
<span className="text-sm">Populate Data</span>
<span className="text-sm">{t('actions.loadDummyData.buttons.loadData')}</span>
</div>
</button>
</div>
@@ -127,13 +122,9 @@ const ActionsTab = ({ data, theme, dispatch }) => {
<hr className="my-6" />
<div className="shadow text-center p-5">
<h6 className="font-bold text-sm mb-2">Reset Everything!</h6>
<h6 className="font-bold text-sm mb-2">{t('actions.reset.heading')}</h6>
<div className="text-sm">
This action will reset all your data and remove backups made to your browser&apos;s local
storage as well, so please make sure you have exported your information before you reset
everything.
</div>
<div className="text-sm">{t('actions.reset.body')}</div>
<button
type="button"
@@ -142,7 +133,7 @@ const ActionsTab = ({ data, theme, dispatch }) => {
>
<div className="flex justify-center items-center">
<i className="material-icons mr-2 font-bold text-base">refresh</i>
<span className="text-sm">Reset</span>
<span className="text-sm">{t('actions.reset.buttons.reset')}</span>
</div>
</button>
</div>
+7 -20
View File
@@ -1,5 +1,6 @@
import React from 'react';
import { toast } from 'react-toastify';
import { useTranslation } from 'react-i18next';
import TextField from '../../../shared/TextField';
import { copyToClipboard } from '../../../utils';
@@ -30,9 +31,11 @@ const colorOptions = [
];
const ColorsTab = ({ theme, onChange }) => {
const { t } = useTranslation('rightSidebar');
const copyColorToClipboard = color => {
copyToClipboard(color);
toast(`Color ${color} copied to clipboard.`, {
toast(t('colors.clipboardCopyAction', { color }), {
bodyClassName: 'text-center text-gray-800 py-2',
});
onChange('theme.colors.accent', color);
@@ -41,7 +44,7 @@ const ColorsTab = ({ theme, onChange }) => {
return (
<div>
<div className="uppercase tracking-wide text-gray-600 text-xs font-semibold mb-4">
Color Options
{t('colors.colorOptions')}
</div>
<div className="mb-6 grid grid-cols-8 col-gap-2 row-gap-3">
{colorOptions.map(color => (
@@ -56,22 +59,6 @@ const ColorsTab = ({ theme, onChange }) => {
<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.background }}
/>
<div className="col-span-5">
<TextField
disabled
label="Background Color"
placeholder="#FFFFFF"
value={theme.colors.background}
onChange={v => onChange('theme.colors.background', 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"
@@ -79,7 +66,7 @@ const ColorsTab = ({ theme, onChange }) => {
/>
<div className="col-span-5">
<TextField
label="Primary Color"
label={t('colors.primaryColor')}
placeholder="#FFFFFF"
value={theme.colors.primary}
onChange={v => onChange('theme.colors.primary', v)}
@@ -94,7 +81,7 @@ const ColorsTab = ({ theme, onChange }) => {
/>
<div className="col-span-5">
<TextField
label="Accent Color"
label={t('colors.accentColor')}
placeholder="#FFFFFF"
value={theme.colors.accent}
onChange={v => onChange('theme.colors.accent', v)}
+15 -10
View File
@@ -1,4 +1,6 @@
import React from 'react';
import { useTranslation } from 'react-i18next';
import TextField from '../../../shared/TextField';
const fontOptions = [
@@ -14,6 +16,8 @@ const fontOptions = [
];
const FontsTab = ({ theme, onChange }) => {
const { t } = useTranslation('rightSidebar');
return (
<div className="grid grid-cols-1 gap-6">
{fontOptions.map(x => (
@@ -29,16 +33,17 @@ const FontsTab = ({ theme, onChange }) => {
</div>
))}
<TextField
label="Font Family"
placeholder="Avenir Next"
value={theme.font.family}
onChange={v => onChange('theme.font.family', v)}
/>
<p className="text-gray-600 text-sm">
You can use any font that is installed on your system as well. Just enter the name of the
font family here and the browser would load it up for you.
</p>
<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>
);
};
@@ -0,0 +1,47 @@
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, i18n } = useTranslation('rightSidebar');
const onChangeLanguage = code => {
i18n.changeLanguage(code);
onChange('settings.language', code);
};
return (
<div>
<Dropdown
label={t('settings.language.label')}
value={settings.language}
onChange={onChangeLanguage}
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;
+3 -28
View File
@@ -1,40 +1,15 @@
import React from 'react';
import Onyx, { Image as OnyxPreview } from '../../../templates/onyx';
import Pikachu, { Image as PikachuPreview } from '../../../templates/pikachu';
import Gengar, { Image as GengarPreview } from '../../../templates/gengar';
import Castform, { Image as CastformPreview } from '../../../templates/castform';
const templates = [
{
name: 'Onyx',
component: Onyx,
preview: OnyxPreview,
},
{
name: 'Pikachu',
component: Pikachu,
preview: PikachuPreview,
},
{
name: 'Gengar',
component: Gengar,
preview: GengarPreview,
},
{
name: 'Castform',
component: Castform,
preview: CastformPreview,
},
];
import templates from '../../../templates';
const TemplatesTab = ({ theme, onChange }) => {
return (
<div className="grid grid-cols-2 gap-6">
{templates.map(x => (
<div key={x.name} className="text-center" onClick={() => onChange('theme.layout', x.name)}>
<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 === x.name
theme.layout.toLowerCase() === x.key
? 'border-gray-600 hover:border-gray-600'
: 'border-transparent '
} hover:border-gray-500 cursor-pointer`}
+4 -2
View File
@@ -80,6 +80,9 @@ const initialState = {
accent: '#f44336',
},
},
settings: {
language: 'en',
},
};
const reducer = (state, { type, payload }) => {
@@ -120,8 +123,7 @@ const reducer = (state, { type, payload }) => {
return {
...state,
data: payload.data,
theme: payload.theme,
...payload,
};
case 'load_dummy_data':
return {
+24
View File
@@ -0,0 +1,24 @@
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import resources from './locales';
const languages = [
{
code: 'en',
name: 'English',
},
];
i18n.use(initReactI18next).init({
lng: 'en',
fallbackLng: 'en',
resources,
debug: true,
ns: ['app', 'leftSidebar', 'rightSidebar'],
defaultNS: 'app',
});
export { languages };
export default i18n;
+25
View File
@@ -0,0 +1,25 @@
{
"heading": {
"placeholder": "Heading"
},
"item": {
"add": "Add {{- heading}}",
"startDate": {
"label": "Start Date",
"placeholder": "March 2018"
},
"endDate": {
"label": "End Date",
"placeholder": "March 2022"
},
"description": {
"label": "Description"
}
},
"buttons": {
"add": {
"label": "Add"
}
},
"markdownHelpText": "You can use <1>GitHub Flavored Markdown</1> to style this section of the text."
}
+3
View File
@@ -0,0 +1,3 @@
import app from './app.json';
export default app;
+9
View File
@@ -0,0 +1,9 @@
import app from './app';
import leftSidebar from './leftSidebar';
import rightSidebar from './rightSidebar';
export default {
app,
leftSidebar,
rightSidebar,
};
@@ -0,0 +1,13 @@
{
"title": {
"label": "Title",
"placeholder": "Math & Science Olympiad"
},
"subtitle": {
"label": "Subtitle",
"placeholder": "First Place, International Level"
},
"description": {
"placeholder": "You can write about what qualities made you succeed in getting this award."
}
}
@@ -0,0 +1,13 @@
{
"title": {
"label": "Title",
"placeholder": "Android Development Nanodegree"
},
"subtitle": {
"label": "Subtitle",
"placeholder": "Udacity"
},
"description": {
"placeholder": "You can write about what you learnt from your certification program."
}
}
@@ -0,0 +1,16 @@
{
"name": {
"label": "Name",
"placeholder": "Harvard University"
},
"major": {
"label": "Major",
"placeholder": "Masters in Computer Science"
},
"grade": {
"label": "Grade"
},
"description": {
"placeholder": "You can write about projects or special credit classes that you took while studying at this school."
}
}
@@ -0,0 +1,10 @@
{
"key": {
"label": "Key",
"placeholder": "Date of Birth"
},
"value": {
"label": "Value",
"placeholder": "6th August 1995"
}
}
+23
View File
@@ -0,0 +1,23 @@
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 skills from './skills.json';
import languages from './languages.json';
import references from './references.json';
import extras from './extras.json';
export default {
profile,
objective,
work,
education,
awards,
certifications,
skills,
languages,
references,
extras,
};
@@ -0,0 +1,9 @@
{
"key": {
"label": "Key",
"placeholder": "Dothraki"
},
"rating": {
"label": "Rating"
}
}
@@ -0,0 +1,6 @@
{
"objective": {
"label": "Objective",
"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."
}
}
@@ -0,0 +1,40 @@
{
"photoUrl": {
"label": "Photo URL"
},
"firstName": {
"label": "First Name",
"placeholder": "Jane"
},
"lastName": {
"label": "Last Name",
"placeholder": "Doe"
},
"subtitle": {
"label": "Subtitle",
"placeholder": "Full Stack Web Developer"
},
"address": {
"line1": {
"label": "Address Line 1",
"placeholder": "Palladium Complex"
},
"line2": {
"label": "Address Line 2",
"placeholder": "140 E 14th St"
},
"line3": {
"label": "Address Line 3",
"placeholder": "New York, NY 10003 USA"
}
},
"phone": {
"label": "Phone Number"
},
"website": {
"label": "Website"
},
"email": {
"label": "Email Address"
}
}
@@ -0,0 +1,19 @@
{
"name": {
"label": "Name",
"placeholder": "Richard Hendricks"
},
"position": {
"label": "Position",
"placeholder": "CEO, Pied Piper"
},
"phone": {
"label": "Phone Number"
},
"email": {
"label": "Email Address"
},
"description": {
"placeholder": "You can write about how you and the reference contact worked together and which projects you were a part of."
}
}
@@ -0,0 +1,5 @@
{
"item": {
"placeholder": "Cooking"
}
}
+13
View File
@@ -0,0 +1,13 @@
{
"name": {
"label": "Name",
"placeholder": "Amazon (US)"
},
"role": {
"label": "Role",
"placeholder": "Front-end Web Developer"
},
"description": {
"placeholder": "You can write about what you specialized in while working at the company and what projects you were a part of."
}
}
@@ -0,0 +1,36 @@
{
"title": "About",
"documentation": {
"heading": "Documentation",
"body": "Want to know more about the app? Wouldn't it be nice if there was a guide to setting it up on your local machine? Need information on how to contribute to the project? Look no further, there's comprehensive documentation made just for you.",
"buttons": {
"documentation": "Documentation"
}
},
"bugOrFeatureRequest": {
"heading": "Bug? Feature Request?",
"body": "Something halting your progress from making a resume? Found a pesky bug that just won't quit? Talk about it on the GitHub Issues section, or send me and email using the actions below.",
"buttons": {
"raiseIssue": "Raise an Issue",
"sendEmail": "Send an Email"
}
},
"sourceCode": {
"heading": "Source Code",
"body": "Want to run the project from its source? Are you a developer willing to contribute to the open-source development of this project? Click the button below.",
"buttons": {
"githubRepo": "GitHub Repo"
}
},
"license": {
"heading": "License Information",
"body": "The project is governed under the MIT License, which you can read more about below. Basically, you are allowed to use the project anywhere provided you give credits to the original author.",
"buttons": {
"mitLicense": "MIT License"
}
},
"footer": {
"credit": "Reactive Resume is a project by <1>Amruth Pillai</1>.",
"thanks": "Thank you for using Reactive Resume!"
}
}
@@ -0,0 +1,33 @@
{
"title": "Actions",
"disclaimer": "Changes you make to your resume are saved automatically to your browser's local storage. No data gets out, hence your information is completely secure.",
"importExport": {
"heading": "Import/Export",
"body": "You can import or export your data in JSON format. With this, you can edit and print your resume from any device. Save this file for later use.",
"buttons": {
"import": "Import",
"export": "Export"
}
},
"printResume": {
"heading": "Print Your Resume",
"body": "You can simply press <1>Cmd/Ctrl + P</1> at any time while you're in the app to print your resume, but here's a fancy button to do the same thing, just 'cause.",
"buttons": {
"print": "Print"
}
},
"loadDummyData": {
"heading": "Load Dummy Data",
"body": "Unclear on what to do with a fresh blank page? Load some dummy data with prepopulated values to see how a resume should look and you can start editing from there.",
"buttons": {
"loadData": "Populate Data"
}
},
"reset": {
"heading": "Reset Everything!",
"body": "This action will reset all your data and remove backups made to your browser's local storage as well, so please make sure you have exported your information before you reset everything.",
"buttons": {
"reset": "Reset"
}
}
}
@@ -0,0 +1,7 @@
{
"title": "Colors",
"colorOptions": "Color Options",
"primaryColor": "Primary Color",
"accentColor": "Accent Color",
"clipboardCopyAction": "{{color}} has been copied to the clipboard."
}
@@ -0,0 +1,7 @@
{
"title": "Fonts",
"fontFamily": {
"label": "Font Family",
"helpText": "You can use any font that is installed on your system as well. Just enter the name of the font family here and the browser would load it up for you."
}
}
+15
View File
@@ -0,0 +1,15 @@
import templates from './templates.json';
import colors from './colors.json';
import fonts from './fonts.json';
import actions from './actions.json';
import settings from './settings.json';
import about from './about.json';
export default {
templates,
colors,
fonts,
actions,
settings,
about,
};
@@ -0,0 +1,7 @@
{
"title": "Settings",
"language": {
"label": "Language",
"helpText": "If you would like to help translate the app into your own language, please refer the <1>Translation Documentation</1>."
}
}
@@ -0,0 +1,3 @@
{
"title": "Templates"
}
+25
View File
@@ -0,0 +1,25 @@
{
"heading": {
"placeholder": "Heading"
},
"item": {
"add": "Add {{- heading}}",
"startDate": {
"label": "Start Date",
"placeholder": "March 2018"
},
"endDate": {
"label": "End Date",
"placeholder": "March 2022"
},
"description": {
"label": "Description"
}
},
"buttons": {
"add": {
"label": "Add"
}
},
"markdownHelpText": "You can use <1>GitHub Flavored Markdown</1> to style this section of the text."
}
+3
View File
@@ -0,0 +1,3 @@
import app from './app.json';
export default app;
+9
View File
@@ -0,0 +1,9 @@
import app from './app';
import leftSidebar from './leftSidebar';
import rightSidebar from './rightSidebar';
export default {
app,
leftSidebar,
rightSidebar,
};
@@ -0,0 +1,13 @@
{
"title": {
"label": "Title",
"placeholder": "Math & Science Olympiad"
},
"subtitle": {
"label": "Subtitle",
"placeholder": "First Place, International Level"
},
"description": {
"placeholder": "You can write about what qualities made you succeed in getting this award."
}
}
@@ -0,0 +1,13 @@
{
"title": {
"label": "Title",
"placeholder": "Android Development Nanodegree"
},
"subtitle": {
"label": "Subtitle",
"placeholder": "Udacity"
},
"description": {
"placeholder": "You can write about what you learnt from your certification program."
}
}
@@ -0,0 +1,16 @@
{
"name": {
"label": "Name",
"placeholder": "Harvard University"
},
"major": {
"label": "Major",
"placeholder": "Masters in Computer Science"
},
"grade": {
"label": "Grade"
},
"description": {
"placeholder": "You can write about projects or special credit classes that you took while studying at this school."
}
}
@@ -0,0 +1,10 @@
{
"key": {
"label": "Key",
"placeholder": "Date of Birth"
},
"value": {
"label": "Value",
"placeholder": "6th August 1995"
}
}
+23
View File
@@ -0,0 +1,23 @@
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 skills from './skills.json';
import languages from './languages.json';
import references from './references.json';
import extras from './extras.json';
export default {
profile,
objective,
work,
education,
awards,
certifications,
skills,
languages,
references,
extras,
};
@@ -0,0 +1,9 @@
{
"key": {
"label": "Key",
"placeholder": "Dothraki"
},
"rating": {
"label": "Rating"
}
}
@@ -0,0 +1,6 @@
{
"objective": {
"label": "Objective",
"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."
}
}
@@ -0,0 +1,40 @@
{
"photoUrl": {
"label": "Photo URL"
},
"firstName": {
"label": "First Name",
"placeholder": "Jane"
},
"lastName": {
"label": "Last Name",
"placeholder": "Doe"
},
"subtitle": {
"label": "Subtitle",
"placeholder": "Full Stack Web Developer"
},
"address": {
"line1": {
"label": "Address Line 1",
"placeholder": "Palladium Complex"
},
"line2": {
"label": "Address Line 2",
"placeholder": "140 E 14th St"
},
"line3": {
"label": "Address Line 3",
"placeholder": "New York, NY 10003 USA"
}
},
"phone": {
"label": "Phone Number"
},
"website": {
"label": "Website"
},
"email": {
"label": "Email Address"
}
}
@@ -0,0 +1,19 @@
{
"name": {
"label": "Name",
"placeholder": "Richard Hendricks"
},
"position": {
"label": "Position",
"placeholder": "CEO, Pied Piper"
},
"phone": {
"label": "Phone Number"
},
"email": {
"label": "Email Address"
},
"description": {
"placeholder": "You can write about how you and the reference contact worked together and which projects you were a part of."
}
}
@@ -0,0 +1,5 @@
{
"item": {
"placeholder": "Cooking"
}
}
+13
View File
@@ -0,0 +1,13 @@
{
"name": {
"label": "Name",
"placeholder": "Amazon (US)"
},
"role": {
"label": "Role",
"placeholder": "Front-end Web Developer"
},
"description": {
"placeholder": "You can write about what you specialized in while working at the company and what projects you were a part of."
}
}
@@ -0,0 +1,36 @@
{
"title": "About",
"documentation": {
"heading": "Documentation",
"body": "Want to know more about the app? Wouldn't it be nice if there was a guide to setting it up on your local machine? Need information on how to contribute to the project? Look no further, there's comprehensive documentation made just for you.",
"buttons": {
"documentation": "Documentation"
}
},
"bugOrFeatureRequest": {
"heading": "Bug? Feature Request?",
"body": "Something halting your progress from making a resume? Found a pesky bug that just won't quit? Talk about it on the GitHub Issues section, or send me and email using the actions below.",
"buttons": {
"raiseIssue": "Raise an Issue",
"sendEmail": "Send an Email"
}
},
"sourceCode": {
"heading": "Source Code",
"body": "Want to run the project from its source? Are you a developer willing to contribute to the open-source development of this project? Click the button below.",
"buttons": {
"githubRepo": "GitHub Repo"
}
},
"license": {
"heading": "License Information",
"body": "The project is governed under the MIT License, which you can read more about below. Basically, you are allowed to use the project anywhere provided you give credits to the original author.",
"buttons": {
"mitLicense": "MIT License"
}
},
"footer": {
"credit": "Reactive Resume is a project by <1>Amruth Pillai</1>.",
"thanks": "Thank you for using Reactive Resume!"
}
}
@@ -0,0 +1,33 @@
{
"title": "Actions",
"disclaimer": "Changes you make to your resume are saved automatically to your browser's local storage. No data gets out, hence your information is completely secure.",
"importExport": {
"heading": "Import/Export",
"body": "You can import or export your data in JSON format. With this, you can edit and print your resume from any device. Save this file for later use.",
"buttons": {
"import": "Import",
"export": "Export"
}
},
"printResume": {
"heading": "Print Your Resume",
"body": "You can simply press <1>Cmd/Ctrl + P</1> at any time while you're in the app to print your resume, but here's a fancy button to do the same thing, just 'cause.",
"buttons": {
"print": "Print"
}
},
"loadDummyData": {
"heading": "Load Dummy Data",
"body": "Unclear on what to do with a fresh blank page? Load some dummy data with prepopulated values to see how a resume should look and you can start editing from there.",
"buttons": {
"loadData": "Populate Data"
}
},
"reset": {
"heading": "Reset Everything!",
"body": "This action will reset all your data and remove backups made to your browser's local storage as well, so please make sure you have exported your information before you reset everything.",
"buttons": {
"reset": "Reset"
}
}
}
@@ -0,0 +1,7 @@
{
"title": "Colors",
"colorOptions": "Color Options",
"primaryColor": "Primary Color",
"accentColor": "Accent Color",
"clipboardCopyAction": "{{color}} has been copied to the clipboard."
}
@@ -0,0 +1,7 @@
{
"title": "Fonts",
"fontFamily": {
"label": "Font Family",
"helpText": "You can use any font that is installed on your system as well. Just enter the name of the font family here and the browser would load it up for you."
}
}
+15
View File
@@ -0,0 +1,15 @@
import templates from './templates.json';
import colors from './colors.json';
import fonts from './fonts.json';
import actions from './actions.json';
import settings from './settings.json';
import about from './about.json';
export default {
templates,
colors,
fonts,
actions,
settings,
about,
};
@@ -0,0 +1,7 @@
{
"title": "Settings",
"language": {
"label": "Language",
"helpText": "If you would like to help translate the app into your own language, please refer the <1>Translation Documentation</1>."
}
}
@@ -0,0 +1,3 @@
{
"title": "Templates"
}
+25
View File
@@ -0,0 +1,25 @@
{
"heading": {
"placeholder": "Heading"
},
"item": {
"add": "Add {{- heading}}",
"startDate": {
"label": "Start Date",
"placeholder": "March 2018"
},
"endDate": {
"label": "End Date",
"placeholder": "March 2022"
},
"description": {
"label": "Description"
}
},
"buttons": {
"add": {
"label": "Add"
}
},
"markdownHelpText": "You can use <1>GitHub Flavored Markdown</1> to style this section of the text."
}
+3
View File
@@ -0,0 +1,3 @@
import app from './app.json';
export default app;
+9
View File
@@ -0,0 +1,9 @@
import app from './app';
import leftSidebar from './leftSidebar';
import rightSidebar from './rightSidebar';
export default {
app,
leftSidebar,
rightSidebar,
};
@@ -0,0 +1,13 @@
{
"title": {
"label": "Title",
"placeholder": "Math & Science Olympiad"
},
"subtitle": {
"label": "Subtitle",
"placeholder": "First Place, International Level"
},
"description": {
"placeholder": "You can write about what qualities made you succeed in getting this award."
}
}
@@ -0,0 +1,13 @@
{
"title": {
"label": "Title",
"placeholder": "Android Development Nanodegree"
},
"subtitle": {
"label": "Subtitle",
"placeholder": "Udacity"
},
"description": {
"placeholder": "You can write about what you learnt from your certification program."
}
}
@@ -0,0 +1,16 @@
{
"name": {
"label": "Name",
"placeholder": "Harvard University"
},
"major": {
"label": "Major",
"placeholder": "Masters in Computer Science"
},
"grade": {
"label": "Grade"
},
"description": {
"placeholder": "You can write about projects or special credit classes that you took while studying at this school."
}
}
@@ -0,0 +1,10 @@
{
"key": {
"label": "Key",
"placeholder": "Date of Birth"
},
"value": {
"label": "Value",
"placeholder": "6th August 1995"
}
}
+23
View File
@@ -0,0 +1,23 @@
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 skills from './skills.json';
import languages from './languages.json';
import references from './references.json';
import extras from './extras.json';
export default {
profile,
objective,
work,
education,
awards,
certifications,
skills,
languages,
references,
extras,
};
@@ -0,0 +1,9 @@
{
"key": {
"label": "Key",
"placeholder": "Dothraki"
},
"rating": {
"label": "Rating"
}
}
@@ -0,0 +1,6 @@
{
"objective": {
"label": "Objective",
"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."
}
}
@@ -0,0 +1,40 @@
{
"photoUrl": {
"label": "Photo URL"
},
"firstName": {
"label": "First Name",
"placeholder": "Jane"
},
"lastName": {
"label": "Last Name",
"placeholder": "Doe"
},
"subtitle": {
"label": "Subtitle",
"placeholder": "Full Stack Web Developer"
},
"address": {
"line1": {
"label": "Address Line 1",
"placeholder": "Palladium Complex"
},
"line2": {
"label": "Address Line 2",
"placeholder": "140 E 14th St"
},
"line3": {
"label": "Address Line 3",
"placeholder": "New York, NY 10003 USA"
}
},
"phone": {
"label": "Phone Number"
},
"website": {
"label": "Website"
},
"email": {
"label": "Email Address"
}
}
@@ -0,0 +1,19 @@
{
"name": {
"label": "Name",
"placeholder": "Richard Hendricks"
},
"position": {
"label": "Position",
"placeholder": "CEO, Pied Piper"
},
"phone": {
"label": "Phone Number"
},
"email": {
"label": "Email Address"
},
"description": {
"placeholder": "You can write about how you and the reference contact worked together and which projects you were a part of."
}
}
@@ -0,0 +1,5 @@
{
"item": {
"placeholder": "Cooking"
}
}
+13
View File
@@ -0,0 +1,13 @@
{
"name": {
"label": "Name",
"placeholder": "Amazon (US)"
},
"role": {
"label": "Role",
"placeholder": "Front-end Web Developer"
},
"description": {
"placeholder": "You can write about what you specialized in while working at the company and what projects you were a part of."
}
}
@@ -0,0 +1,36 @@
{
"title": "About",
"documentation": {
"heading": "Documentation",
"body": "Want to know more about the app? Wouldn't it be nice if there was a guide to setting it up on your local machine? Need information on how to contribute to the project? Look no further, there's comprehensive documentation made just for you.",
"buttons": {
"documentation": "Documentation"
}
},
"bugOrFeatureRequest": {
"heading": "Bug? Feature Request?",
"body": "Something halting your progress from making a resume? Found a pesky bug that just won't quit? Talk about it on the GitHub Issues section, or send me and email using the actions below.",
"buttons": {
"raiseIssue": "Raise an Issue",
"sendEmail": "Send an Email"
}
},
"sourceCode": {
"heading": "Source Code",
"body": "Want to run the project from its source? Are you a developer willing to contribute to the open-source development of this project? Click the button below.",
"buttons": {
"githubRepo": "GitHub Repo"
}
},
"license": {
"heading": "License Information",
"body": "The project is governed under the MIT License, which you can read more about below. Basically, you are allowed to use the project anywhere provided you give credits to the original author.",
"buttons": {
"mitLicense": "MIT License"
}
},
"footer": {
"credit": "Reactive Resume is a project by <1>Amruth Pillai</1>.",
"thanks": "Thank you for using Reactive Resume!"
}
}
@@ -0,0 +1,33 @@
{
"title": "Actions",
"disclaimer": "Changes you make to your resume are saved automatically to your browser's local storage. No data gets out, hence your information is completely secure.",
"importExport": {
"heading": "Import/Export",
"body": "You can import or export your data in JSON format. With this, you can edit and print your resume from any device. Save this file for later use.",
"buttons": {
"import": "Import",
"export": "Export"
}
},
"printResume": {
"heading": "Print Your Resume",
"body": "You can simply press <1>Cmd/Ctrl + P</1> at any time while you're in the app to print your resume, but here's a fancy button to do the same thing, just 'cause.",
"buttons": {
"print": "Print"
}
},
"loadDummyData": {
"heading": "Load Dummy Data",
"body": "Unclear on what to do with a fresh blank page? Load some dummy data with prepopulated values to see how a resume should look and you can start editing from there.",
"buttons": {
"loadData": "Populate Data"
}
},
"reset": {
"heading": "Reset Everything!",
"body": "This action will reset all your data and remove backups made to your browser's local storage as well, so please make sure you have exported your information before you reset everything.",
"buttons": {
"reset": "Reset"
}
}
}
@@ -0,0 +1,7 @@
{
"title": "Colors",
"colorOptions": "Color Options",
"primaryColor": "Primary Color",
"accentColor": "Accent Color",
"clipboardCopyAction": "{{color}} has been copied to the clipboard."
}
@@ -0,0 +1,7 @@
{
"title": "Fonts",
"fontFamily": {
"label": "Font Family",
"helpText": "You can use any font that is installed on your system as well. Just enter the name of the font family here and the browser would load it up for you."
}
}
+15
View File
@@ -0,0 +1,15 @@
import templates from './templates.json';
import colors from './colors.json';
import fonts from './fonts.json';
import actions from './actions.json';
import settings from './settings.json';
import about from './about.json';
export default {
templates,
colors,
fonts,
actions,
settings,
about,
};
@@ -0,0 +1,7 @@
{
"title": "Settings",
"language": {
"label": "Language",
"helpText": "If you would like to help translate the app into your own language, please refer the <1>Translation Documentation</1>."
}
}
@@ -0,0 +1,3 @@
{
"title": "Templates"
}
+25
View File
@@ -0,0 +1,25 @@
{
"heading": {
"placeholder": "Heading"
},
"item": {
"add": "Add {{- heading}}",
"startDate": {
"label": "Start Date",
"placeholder": "March 2018"
},
"endDate": {
"label": "End Date",
"placeholder": "March 2022"
},
"description": {
"label": "Description"
}
},
"buttons": {
"add": {
"label": "Add"
}
},
"markdownHelpText": "You can use <1>GitHub Flavored Markdown</1> to style this section of the text."
}
+3
View File
@@ -0,0 +1,3 @@
import app from './app.json';
export default app;
+9
View File
@@ -0,0 +1,9 @@
import app from './app';
import leftSidebar from './leftSidebar';
import rightSidebar from './rightSidebar';
export default {
app,
leftSidebar,
rightSidebar,
};
@@ -0,0 +1,13 @@
{
"title": {
"label": "Title",
"placeholder": "Math & Science Olympiad"
},
"subtitle": {
"label": "Subtitle",
"placeholder": "First Place, International Level"
},
"description": {
"placeholder": "You can write about what qualities made you succeed in getting this award."
}
}
@@ -0,0 +1,13 @@
{
"title": {
"label": "Title",
"placeholder": "Android Development Nanodegree"
},
"subtitle": {
"label": "Subtitle",
"placeholder": "Udacity"
},
"description": {
"placeholder": "You can write about what you learnt from your certification program."
}
}
@@ -0,0 +1,16 @@
{
"name": {
"label": "Name",
"placeholder": "Harvard University"
},
"major": {
"label": "Major",
"placeholder": "Masters in Computer Science"
},
"grade": {
"label": "Grade"
},
"description": {
"placeholder": "You can write about projects or special credit classes that you took while studying at this school."
}
}
@@ -0,0 +1,10 @@
{
"key": {
"label": "Key",
"placeholder": "Date of Birth"
},
"value": {
"label": "Value",
"placeholder": "6th August 1995"
}
}
+23
View File
@@ -0,0 +1,23 @@
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 skills from './skills.json';
import languages from './languages.json';
import references from './references.json';
import extras from './extras.json';
export default {
profile,
objective,
work,
education,
awards,
certifications,
skills,
languages,
references,
extras,
};

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