- implement work experience

- implement education
- show dynamic names in layout
This commit is contained in:
Amruth Pillai
2020-07-08 16:49:26 +05:30
parent bee6a40e9f
commit 922db70107
33 changed files with 822 additions and 169 deletions

View File

@ -12,9 +12,9 @@ const LeftSidebar = () => {
<LeftNavbar />
<div className={styles.container}>
{sections.map(({ id, component: Component }) => (
{sections.map(({ id, name, event, component: Component }) => (
<Fragment key={id}>
<Component state={state} />
<Component id={id} name={name} event={event} state={state} />
<hr />
</Fragment>
))}

View File

@ -1,6 +1,12 @@
.container {
z-index: 10;
box-shadow: var(--left-shadow);
-ms-overflow-style: none;
scrollbar-width: none;
@apply w-full h-screen overflow-scroll p-8;
@apply grid gap-6;
}
.container::-webkit-scrollbar {
display: none;
}

View File

@ -1,9 +1,7 @@
import React from "react";
const EmptyList = () => (
<div className="rounded border border-secondary py-6 text-center">
This list is empty.
</div>
<div className="py-6 opacity-75 text-center">This list is empty.</div>
);
export default EmptyList;

View File

@ -1,22 +1,67 @@
import { isEmpty } from "lodash";
import React from "react";
import { get, isEmpty } from "lodash";
import moment from "moment";
import React, { useContext } from "react";
import { MdAdd } from "react-icons/md";
import ModalContext from "../../../contexts/ModalContext";
import Button from "../../shared/Button";
import EmptyList from "./EmptyList";
import styles from "./List.module.css";
const List = ({ items, onAdd, children }) => {
const List = ({
path,
items,
title,
titlePath,
subtitle,
subtitlePath,
text,
textPath,
event,
listItemComponent: ListItemComponent,
}) => {
const { emitter } = useContext(ModalContext);
const handleAdd = () => emitter.emit(event);
const handleEdit = (data) => emitter.emit(event, data);
const formatDateRange = (x) =>
`${moment(x.startDate).format("MMMM Y")}${
moment(x.endDate).isValid()
? moment(x.endDate).format("MMMM Y")
: "Present"
}`;
return (
<div className="flex flex-col">
<div className={styles.container}>
{isEmpty(items) ? <EmptyList /> : children}
<div className={styles.list}>
{isEmpty(items) ? (
<EmptyList />
) : (
items.map((x, i) => (
<ListItemComponent
key={x.id}
data={x}
path={path}
title={title || get(x, titlePath, "")}
subtitle={
subtitle || get(x, subtitlePath, "") || formatDateRange(x)
}
text={text || get(x, textPath, "")}
className={styles.listItem}
onEdit={() => handleEdit(x)}
isFirst={i === 0}
isLast={i === items.length - 1}
/>
))
)}
</div>
<Button
outline
icon={MdAdd}
title="Add New"
onClick={onAdd}
onClick={handleAdd}
className="mt-8 ml-auto"
/>
</div>

View File

@ -1,3 +1,21 @@
.container {
.list {
@apply flex flex-col border border-secondary rounded;
}
}
.list-item {
@apply flex items-center justify-between border-t border-secondary px-8 py-5;
}
.list-item:first-child {
@apply border-t-0;
}
.menu {
@apply opacity-0;
@apply transition-opacity duration-200 ease-in-out;
}
.list-item:hover .menu {
@apply opacity-100;
@apply transition-opacity duration-200 ease-in-out;
}

View File

@ -3,9 +3,9 @@ import React, { useContext, useState } from "react";
import { IoIosArrowDown, IoIosArrowUp } from "react-icons/io";
import { MdMoreVert } from "react-icons/md";
import ResumeContext from "../../../../contexts/ResumeContext";
import styles from "./SmallListItem.module.css";
import styles from "./DoubleFieldListItem.module.css";
const SmallListItem = ({
const DoubleFieldListItem = ({
title,
subtitle,
path,
@ -100,4 +100,4 @@ const SmallListItem = ({
);
};
export default SmallListItem;
export default DoubleFieldListItem;

View File

@ -0,0 +1,106 @@
import { Menu, MenuItem } from "@material-ui/core";
import React, { useContext, useState } from "react";
import { IoIosArrowDown, IoIosArrowUp } from "react-icons/io";
import { MdMoreVert } from "react-icons/md";
import ResumeContext from "../../../../contexts/ResumeContext";
import styles from "./TripleFieldListItem.module.css";
const TripleFieldListItem = ({
title,
subtitle,
text,
path,
data,
isFirst,
isLast,
onEdit,
}) => {
const [anchorEl, setAnchorEl] = useState(null);
const { dispatch } = useContext(ResumeContext);
const handleClick = (event) => setAnchorEl(event.currentTarget);
const handleClose = () => setAnchorEl(null);
const handleEdit = () => {
onEdit();
handleClose();
};
const handleMoveUp = () => {
dispatch({
type: "on_move_item_up",
payload: {
path,
value: data,
},
});
handleClose();
};
const handleMoveDown = () => {
dispatch({
type: "on_move_item_down",
payload: {
path,
value: data,
},
});
handleClose();
};
const handleDelete = () => {
dispatch({
type: "on_delete_item",
payload: {
path,
value: data,
},
});
handleClose();
};
return (
<div className={styles.container}>
<div className="grid">
<span className="font-medium">{title}</span>
<span className="mt-1 text-sm opacity-75">{subtitle}</span>
<span className="w-4/5 mt-6 text-sm opacity-75 truncate">{text}</span>
</div>
<div className={styles.menu}>
<MdMoreVert
size="18px"
aria-haspopup="true"
onClick={handleClick}
className="cursor-pointer"
/>
<Menu
keepMounted
anchorEl={anchorEl}
onClose={handleClose}
open={Boolean(anchorEl)}
>
<div className="flex items-center space-around">
<MenuItem disabled={isFirst} onClick={handleMoveUp}>
<IoIosArrowUp size="18px" />
</MenuItem>
<MenuItem disabled={isLast} onClick={handleMoveDown}>
<IoIosArrowDown size="18px" />
</MenuItem>
</div>
<MenuItem onClick={handleEdit}>Edit</MenuItem>
<MenuItem onClick={handleDelete}>
<span className="text-red-600 font-medium">Delete</span>
</MenuItem>
</Menu>
</div>
</div>
);
};
export default TripleFieldListItem;

View File

@ -0,0 +1,17 @@
.container {
@apply flex items-center justify-between border-t border-secondary px-8 py-5;
}
.container:first-child {
@apply border-t-0;
}
.menu {
@apply opacity-0;
@apply transition-opacity duration-200 ease-in-out;
}
.container:hover .menu {
@apply opacity-100;
@apply transition-opacity duration-200 ease-in-out;
}

View File

@ -8,6 +8,7 @@ const RightSidebar = () => {
<div className="flex">
<div className={styles.container}>
<Layout />
<hr />
</div>
<RightNavbar />

View File

@ -1,5 +1,12 @@
.container {
z-index: 10;
box-shadow: var(--right-shadow);
@apply w-full h-screen p-8;
-ms-overflow-style: none;
scrollbar-width: none;
@apply w-full h-screen overflow-scroll p-8;
@apply grid gap-6;
}
.container::-webkit-scrollbar {
display: none;
}

View File

@ -0,0 +1,27 @@
import { get } from "lodash";
import React from "react";
import Heading from "../../shared/Heading";
import List from "../lists/List";
import TripleFieldListItem from "../lists/triple/TripleFieldListItem";
const Education = ({ id, name, event, state }) => {
const path = `${id}.items`;
const items = get(state, path, []);
return (
<section>
<Heading>{name}</Heading>
<List
path={path}
items={items}
event={event}
titlePath="institution"
textPath="field"
listItemComponent={TripleFieldListItem}
/>
</section>
);
};
export default Education;

View File

@ -31,7 +31,11 @@ const Layout = () => {
Block {ind + 1}
</span>
{el.map((item, index) => (
<Draggable key={item} draggableId={item} index={index}>
<Draggable
key={item.id}
draggableId={item.id}
index={index}
>
{(provided) => (
<div
ref={provided.innerRef}
@ -39,7 +43,7 @@ const Layout = () => {
{...provided.draggableProps}
{...provided.dragHandleProps}
>
{item}
{item.name}
</div>
)}
</Draggable>

View File

@ -0,0 +1,15 @@
import React from "react";
import Heading from "../../shared/Heading";
import Input from "../../shared/Input";
const Objective = () => {
return (
<section>
<Heading>Objective</Heading>
<Input type="textarea" label="Objective" path="objective" />
</section>
);
};
export default Objective;

View File

@ -1,38 +1,25 @@
import { get } from "lodash";
import React, { useContext } from "react";
import ModalContext from "../../../contexts/ModalContext";
import React from "react";
import Heading from "../../shared/Heading";
import DoubleFieldListItem from "../lists/double/DoubleFieldListItem";
import List from "../lists/List";
import SmallListItem from "../lists/small/SmallListItem";
const Social = ({ state }) => {
const { emitter, events } = useContext(ModalContext);
const path = "social.items";
const Social = ({ id, name, event, state }) => {
const path = `${id}.items`;
const items = get(state, path, []);
const handleAdd = () => emitter.emit(events.SOCIAL_MODAL);
const handleEdit = (data) => emitter.emit(events.SOCIAL_MODAL, data);
return (
<section>
<Heading>Social Network</Heading>
<Heading>{name}</Heading>
<List items={items} onAdd={handleAdd}>
{items.map((x, i) => (
<SmallListItem
key={x.id}
data={x}
path={path}
title={x.network}
isFirst={i === 0}
subtitle={x.username}
onEdit={() => handleEdit(x)}
isLast={i === items.length - 1}
/>
))}
</List>
<List
path={path}
items={items}
event={event}
titlePath="network"
subtitlePath="username"
listItemComponent={DoubleFieldListItem}
/>
</section>
);
};

View File

@ -0,0 +1,27 @@
import { get } from "lodash";
import React from "react";
import Heading from "../../shared/Heading";
import List from "../lists/List";
import TripleFieldListItem from "../lists/triple/TripleFieldListItem";
const Work = ({ id, name, event, state }) => {
const path = `${id}.items`;
const items = get(state, path, []);
return (
<section>
<Heading>{name}</Heading>
<List
path={path}
items={items}
event={event}
titlePath="company"
textPath="summary"
listItemComponent={TripleFieldListItem}
/>
</section>
);
};
export default Work;

View File

@ -7,10 +7,6 @@
@apply bg-primary-dark;
}
.container:focus {
@apply outline-none;
}
.container.outline {
@apply border border-primary bg-inverse text-primary;
}

View File

@ -1,8 +1,10 @@
import cx from "classnames";
import { get } from "lodash";
import { get, isFunction } from "lodash";
import React, { useContext } from "react";
import { MdClose } from "react-icons/md";
import { v4 as uuidv4 } from "uuid";
import ResumeContext from "../../contexts/ResumeContext";
import { handleKeyDown } from "../../utils";
import styles from "./Input.module.css";
const Input = ({
@ -17,6 +19,8 @@ const Input = ({
onChange,
className,
placeholder,
onDeleteItem,
showDeleteItemButton,
type = "text",
}) => {
const uuid = uuidv4();
@ -39,18 +43,59 @@ const Input = ({
<div className={cx(styles.container, className)}>
<label htmlFor={uuid}>
<span>{label}</span>
<input
id={uuid}
name={name}
type={type}
value={value}
onBlur={onBlur}
checked={checked}
onChange={onChange}
placeholder={placeholder}
{...(path && inputProps(path))}
/>
{touched && <p>{error}</p>}
{type === "textarea" ? (
<div className="flex flex-col">
<textarea
id={uuid}
rows="4"
name={name}
type={type}
value={value}
onBlur={onBlur}
checked={checked}
onChange={onChange}
placeholder={placeholder}
{...(path && inputProps(path))}
/>
<p className="mt-2 text-sm opacity-75">
This text block supports{" "}
<a
href="https://www.markdownguide.org/basic-syntax/"
className="text-blue-600"
target="blank"
>
markdown
</a>
.
</p>
</div>
) : (
<div className="relative grid items-center">
<input
id={uuid}
name={name}
type={type}
value={value}
onBlur={onBlur}
checked={checked}
onChange={onChange}
placeholder={placeholder}
{...(path && inputProps(path))}
/>
{showDeleteItemButton && isFunction(onDeleteItem) && (
<MdClose
size="16px"
tabIndex="0"
onClick={onDeleteItem}
onKeyDown={(e) => handleKeyDown(e, onDeleteItem)}
className="absolute right-0 cursor-pointer opacity-50 hover:opacity-75 mx-4"
/>
)}
</div>
)}
{error && touched && <p>{error}</p>}
</label>
</div>
);

View File

@ -2,26 +2,21 @@
@apply w-full;
}
.container > label {
@apply flex flex-col;
}
.container > label > span {
@apply mb-1 text-secondary-dark font-semibold tracking-wide text-xs uppercase;
}
.container > label > input {
.container label input,
.container label textarea {
@apply py-3 px-4 rounded bg-secondary text-primary border border-secondary;
}
.container > label > input::placeholder {
.container label input::placeholder,
.container label textarea::placeholder {
@apply text-primary opacity-50;
}
.container > label > input:focus {
.container label input:focus,
.container label textarea:focus {
@apply outline-none border-gray-500;
}
.container > label > p {
.container label > p {
@apply mt-1 text-red-600 text-xs;
}