editor-cv #26
4
dist/api/timelineData.php
vendored
4
dist/api/timelineData.php
vendored
@ -17,7 +17,7 @@ class timelineData
|
|||||||
function getEduData(): array
|
function getEduData(): array
|
||||||
{
|
{
|
||||||
$conn = dbConn();
|
$conn = dbConn();
|
||||||
$stmt = $conn->prepare("SELECT DATE_FORMAT(startPeriod, '%b, %Y') as startPeriod, DATE_FORMAT(endPeriod, '%b, %Y') as endPeriod, grade, course FROM edu ORDER BY startPeriod DESC;");
|
$stmt = $conn->prepare("SELECT startPeriod, endPeriod, grade, course FROM edu ORDER BY startPeriod DESC;");
|
||||||
$stmt->execute();
|
$stmt->execute();
|
||||||
|
|
||||||
// set the resulting array to associative
|
// set the resulting array to associative
|
||||||
@ -37,7 +37,7 @@ class timelineData
|
|||||||
function getWorkData(): array
|
function getWorkData(): array
|
||||||
{
|
{
|
||||||
$conn = dbConn();
|
$conn = dbConn();
|
||||||
$stmt = $conn->prepare("SELECT DATE_FORMAT(startPeriod, '%b, %Y') as startPeriod, DATE_FORMAT(endPeriod, '%b, %Y') as endPeriod, companyName, area, title FROM work ORDER BY work.startPeriod DESC;");
|
$stmt = $conn->prepare("SELECT startPeriod, endPeriod, companyName, area, title FROM work ORDER BY work.startPeriod DESC;");
|
||||||
$stmt->execute();
|
$stmt->execute();
|
||||||
|
|
||||||
// set the resulting array to associative
|
// set the resulting array to associative
|
||||||
|
2
dist/editor/css/main.css
vendored
2
dist/editor/css/main.css
vendored
File diff suppressed because one or more lines are too long
2
dist/editor/editor.html
vendored
2
dist/editor/editor.html
vendored
@ -1 +1 @@
|
|||||||
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>Editor</title><link rel="stylesheet" href="css/main.css"></head><body><nav class="sideNav"><a href="#" class="closeBtn" id="navClose">×</a><ul><li><a href="#" class="active"><span><</span>CV<span>></span></a></li><li><a href="#"><span><</span>Projects<span>></span></a></li><li><a href="#"><span><</span>Settings<span>></span></a></li></ul></nav><main class="editor" style="margin-left: 250px;"><div class="title"><span id="navOpen">☰</span><h1>Editor</h1></div><section id="curriculumVitae"></section><section id="projects"></section><section id="settings"></section></main><script src="js/editor.js"></script></body></html>
|
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>Editor</title><link rel="stylesheet" href="css/main.css"><script src="https://kit.fontawesome.com/ed3c25598e.js" crossorigin="anonymous"></script></head><body><nav class="sideNav"><a href="#" class="closeBtn" id="navClose">×</a><ul><li><a href="#" class="active"><span><</span>CV<span>></span></a></li><li><a href="#"><span><</span>Projects<span>></span></a></li><li><a href="#"><span><</span>Settings<span>></span></a></li></ul></nav><main class="editor" style="margin-left: 250px;"><div class="title"><span id="navOpen">☰</span><h1>Editor</h1></div><section id="curriculumVitae"><h2>curriculum vitae</h2><div class="cvGrid"><!-- https://codepen.io/keithwyland/pen/wqNqvy --><div><h3>Education</h3><div class="editorContainer"><form action="" method="POST"><div class="formControl"><label for="dateFrom">Date From</label> <input type="date" id="dateFrom" name="dateFrom"></div><div class="formControl"><label for="dateTo">Date To</label> <input type="date" id="dateTo" name="dateTo"></div><div class="formControl"><label for="grade">Grade</label> <input type="text" id="grade" name="grade"></div><div class="formControl"><label for="courseTitle">Course Title</label> <input type="text" id="courseTitle" name="courseTitle"></div><div class="error hidden" id="eduError"><button class="close" type="button">×</button><div></div></div><input type="submit" class="btn btnPrimary boxShadowIn boxShadowOut" value="Add new course"></form><div class="timeline" id="edu"></div></div></div><div><h3>Work</h3><div class="timeline" id="work"></div></div></div></section></main><script src="js/editor.js"></script></body></html>
|
2
dist/editor/js/editor.js
vendored
2
dist/editor/js/editor.js
vendored
@ -1 +1 @@
|
|||||||
document.addEventListener("DOMContentLoaded",(e=>{})),document.querySelector("#navOpen").addEventListener("click",(e=>{document.querySelector("nav.sideNav").style.removeProperty("width"),document.querySelector("main.editor").style.removeProperty("margin-left"),e.target.style.removeProperty("visibility")})),document.querySelector("#navClose").addEventListener("click",(e=>{document.querySelector("nav.sideNav").style.width="0",document.querySelector("main.editor").style.marginLeft="0",document.querySelector("#navOpen").style.visibility="visible"}));
|
let dateOptions={month:"short",year:"numeric"};function edit(e){document.querySelector("#timelineItem"+e).classList.toggle("editing"),document.querySelector("#grade"+e).removeAttribute("disabled"),document.querySelector("#course"+e).removeAttribute("disabled")}function updateItem(e,t){t.preventDefault();let n=new FormData;n.append("dateFrom",document.querySelector("#dateFrom"+e).value),n.append("dateTo",document.querySelector("#dateTo"+e).value),n.append("grade",document.querySelector("#grade"+e).value),n.append("course",document.querySelector("#course"+e).value),fetch("/api/timelineData/edu/"+e,{method:"PUT",body:n,headers:{Authorization:"Bearer "+localStorage.getItem("token")}}).then((t=>{if(t.ok)return document.querySelector("#timelineItem"+e).classList.toggle("editing"),document.querySelector("#grade"+e).setAttribute("disabled",""),void document.querySelector("#course"+e).setAttribute("disabled","");t.json().then((e=>{alert(e.message)}))}))}document.addEventListener("DOMContentLoaded",(()=>{document.querySelector("#dateFrom").max=(new Date).toISOString().split("T")[0],fetch("/api/timelineData/edu").then((e=>{e.json().then((t=>{if(e.ok)for(let e=0;e<t.length;e++){let n=document.createElement("form");n.id="timelineItem"+e,n.classList.add("timelineItem"),n.onsubmit=t=>updateItem(e,t),n.innerHTML=`\n <div class="modifyBtnContainer">\n <button class="edit" type="button" id="edit${e}" onclick="edit(${e})"><i class="fa-solid fa-pen-to-square"></i></button>\n <button class="delete" type="button" id="delete${e}"><i class="fa-solid fa-trash"></i></button>\n </div>\n <div class="dateContainer formControl">\n <input type="date" name="dateFrom${e}" id="dateFrom${e}" onload="this.max = new Date().toISOString().split('T')[0]" value="${t[e].startPeriod}">\n -\n <input type="date" name="dateTo${e}" id="dateTo${e}" value="${t[e].endPeriod}">\n </div>\n\t\t\t\t\t<h3 class="timelineHeader">${new Date(t[e].startPeriod).toLocaleString("en-gb",dateOptions)} - ${new Date(t[e].endPeriod).toLocaleString("en-gb",dateOptions)}</h3>\n <div class="gradeContainer formControl">\n <label for="grade${e}">Grade:</label>\n <input type="text" name="grade${e}" id="grade${e}" value="${t[e].grade}" disabled>\n </div>\n\t\t\t\t\t<div class="formControl">\n\t\t\t\t\t <textarea class="courseText" name="course${e}" id="course${e}" cols="10" rows="3" disabled>${t[e].course}</textarea>\n\t\t\t\t\t</div>\n\t\t\t\t\t\n <div class="error hidden" id="eduError">\n <button class="close" type="button">×</button>\n <div></div>\n </div>\n\t\t\t\t\t<input type="submit" value="Change">\n\t\t\t\t`,document.getElementById("edu").appendChild(n)}else document.querySelector("#edu").innerHTML="No education data found"}))}))})),document.querySelector("#navOpen").addEventListener("click",(e=>{document.querySelector("nav.sideNav").style.removeProperty("width"),document.querySelector("main.editor").style.removeProperty("margin-left"),e.target.style.removeProperty("visibility")})),document.querySelector("#navClose").addEventListener("click",(()=>{document.querySelector("nav.sideNav").style.width="0",document.querySelector("main.editor").style.marginLeft="0",document.querySelector("#navOpen").style.visibility="visible"}));
|
2
dist/editor/js/index.js
vendored
2
dist/editor/js/index.js
vendored
@ -1 +1 @@
|
|||||||
function showErrorMessage(e,t){document.querySelector(`#${t}Error`).classList.remove("hidden"),document.querySelector(`#${t}Error div`).innerText=e}function switchView(e,t){document.querySelector(e).classList.toggle("shown"),setTimeout((()=>document.querySelector(e).style.transform="translateX(150vw)"),500),setTimeout((()=>document.querySelector(e).style.display="none"),500),setTimeout((()=>document.querySelector(t).style.removeProperty("display")),200),setTimeout((()=>document.querySelector(t).classList.toggle("shown")),300),setTimeout((()=>document.querySelector(t).style.removeProperty("transform")),400)}document.addEventListener("DOMContentLoaded",(e=>{fetch("/api/user/isLoggedIn").then((e=>{e.ok&&(window.location.href="./editor.html")}))})),document.querySelector("#login form").addEventListener("submit",(e=>{e.preventDefault();let t=new FormData;if(e.target.username.value.length>0&&e.target.password.value.length>0)return t.append("username",e.target.username.value),t.append("password",e.target.password.value),void fetch("/api/user/login",{method:"POST",body:t}).then((e=>{e.ok?window.location.href="./editor.html":400!==e.status?showErrorMessage("Invalid username or password.","login"):showErrorMessage("Please type in a username and password.","login")}));showErrorMessage("Please type in a username and password.","login")})),document.querySelector("#loginError .close").addEventListener("click",(()=>document.querySelector("#loginError").classList.toggle("hidden"))),document.querySelector("#resetError .close").addEventListener("click",(()=>document.querySelector("#resetError").classList.toggle("hidden"))),document.querySelector("#changeError .close").addEventListener("click",(()=>document.querySelector("#changeError").classList.toggle("hidden"))),document.querySelectorAll("form i.fa-eye").forEach((e=>{e.addEventListener("click",(e=>{if("password"===e.target.previousElementSibling.type)return e.target.previousElementSibling.type="text",e.target.classList.remove("fa-eye"),void e.target.classList.add("fa-eye-slash");e.target.previousElementSibling.type="password",e.target.classList.remove("fa-eye-slash"),e.target.classList.add("fa-eye")}))})),document.querySelector("#resetPwd").addEventListener("click",(()=>{switchView("#login","#resetPassword")})),document.querySelector("#loginBtn").addEventListener("click",(()=>{switchView("#resetPassword","#login")})),document.querySelector("#resetPassword form").addEventListener("submit",(e=>{e.preventDefault();let t=new FormData;""!==e.target.email?(window.email=e.target.email.value,t.append("email",e.target.email.value),fetch(`/api/user/checkResetEmail/${e.target.email.value}`).then((e=>{e.ok&&switchView("#resetPassword","#checkResetCode"),showErrorMessage("Invalid email.","reset")}))):showErrorMessage("Please type in your email.","reset")})),document.querySelector("#checkResetCode form").addEventListener("submit",(e=>{e.preventDefault();let t=new FormData;""!==e.target.code.value?(t.append("code",e.target.code.value),fetch(`/api/user/checkResetCode/${e.target.code.value}`).then((e=>{e.ok&&switchView("#checkResetCode","#changePassword"),showErrorMessage("Invalid code.","resetCode")}))):showErrorMessage("Please type in your reset code.","check")})),document.querySelector("#changePassword form").addEventListener("submit",(e=>{e.preventDefault();let t=new FormData;""!==e.target.pass.value||""!==e.target.rePass.value?e.target.pass.value===e.target.rePass.value?(t.append("password",e.target.pass.value),fetch("/api/user/changePassword",{method:"POST",body:t}).then((e=>{e.ok&&switchView("#changePassword","#login"),showErrorMessage("Something went wrong.","change")}))):showErrorMessage("Passwords do not match.","change"):showErrorMessage("Please type in a new password.","change")}));
|
function showErrorMessage(e,t){document.querySelector(`#${t}Error`).classList.remove("hidden"),document.querySelector(`#${t}Error div`).innerText=e}function switchView(e,t){document.querySelector(e).classList.toggle("shown"),setTimeout((()=>document.querySelector(e).style.transform="translateX(150vw)"),500),setTimeout((()=>document.querySelector(e).style.display="none"),500),setTimeout((()=>document.querySelector(t).style.removeProperty("display")),200),setTimeout((()=>document.querySelector(t).classList.toggle("shown")),300),setTimeout((()=>document.querySelector(t).style.removeProperty("transform")),400)}document.addEventListener("DOMContentLoaded",(e=>{fetch("/api/user/isLoggedIn").then((e=>{e.ok&&(window.location.href="./editor.html")}))})),document.querySelector("#login form").addEventListener("submit",(e=>{e.preventDefault();let t=new FormData;if(e.target.username.value.length>0&&e.target.password.value.length>0)return t.append("username",e.target.username.value),t.append("password",e.target.password.value),void fetch("/api/user/login",{method:"POST",body:t}).then((e=>e.json())).then((e=>{if(res.ok)return localStorage.setItem("token",e.token),void(window.location.href="./editor.html");400!==res.status?showErrorMessage("Invalid username or password.","login"):showErrorMessage("Please type in a username and password.","login")}));showErrorMessage("Please type in a username and password.","login")})),document.querySelector("#loginError .close").addEventListener("click",(()=>document.querySelector("#loginError").classList.toggle("hidden"))),document.querySelector("#resetError .close").addEventListener("click",(()=>document.querySelector("#resetError").classList.toggle("hidden"))),document.querySelector("#changeError .close").addEventListener("click",(()=>document.querySelector("#changeError").classList.toggle("hidden"))),document.querySelectorAll("form i.fa-eye").forEach((e=>{e.addEventListener("click",(e=>{if("password"===e.target.previousElementSibling.type)return e.target.previousElementSibling.type="text",e.target.classList.remove("fa-eye"),void e.target.classList.add("fa-eye-slash");e.target.previousElementSibling.type="password",e.target.classList.remove("fa-eye-slash"),e.target.classList.add("fa-eye")}))})),document.querySelector("#resetPwd").addEventListener("click",(()=>{switchView("#login","#resetPassword")})),document.querySelector("#loginBtn").addEventListener("click",(()=>{switchView("#resetPassword","#login")})),document.querySelector("#resetPassword form").addEventListener("submit",(e=>{e.preventDefault();let t=new FormData;""!==e.target.email?(window.email=e.target.email.value,t.append("email",e.target.email.value),fetch(`/api/user/checkResetEmail/${e.target.email.value}`).then((e=>{e.ok&&switchView("#resetPassword","#checkResetCode"),showErrorMessage("Invalid email.","reset")}))):showErrorMessage("Please type in your email.","reset")})),document.querySelector("#checkResetCode form").addEventListener("submit",(e=>{e.preventDefault();let t=new FormData;""!==e.target.code.value?(t.append("code",e.target.code.value),fetch(`/api/user/checkResetCode/${e.target.code.value}`).then((e=>{e.ok&&switchView("#checkResetCode","#changePassword"),showErrorMessage("Invalid code.","resetCode")}))):showErrorMessage("Please type in your reset code.","check")})),document.querySelector("#changePassword form").addEventListener("submit",(e=>{e.preventDefault();let t=new FormData;""!==e.target.pass.value||""!==e.target.rePass.value?e.target.pass.value===e.target.rePass.value?(t.append("password",e.target.pass.value),fetch("/api/user/changePassword",{method:"POST",body:t}).then((e=>{e.ok&&switchView("#changePassword","#login"),showErrorMessage("Something went wrong.","change")}))):showErrorMessage("Passwords do not match.","change"):showErrorMessage("Please type in a new password.","change")}));
|
2
dist/js/main.js
vendored
2
dist/js/main.js
vendored
File diff suppressed because one or more lines are too long
@ -17,7 +17,7 @@ class timelineData
|
|||||||
function getEduData(): array
|
function getEduData(): array
|
||||||
{
|
{
|
||||||
$conn = dbConn();
|
$conn = dbConn();
|
||||||
$stmt = $conn->prepare("SELECT DATE_FORMAT(startPeriod, '%b, %Y') as startPeriod, DATE_FORMAT(endPeriod, '%b, %Y') as endPeriod, grade, course FROM edu ORDER BY startPeriod DESC;");
|
$stmt = $conn->prepare("SELECT startPeriod, endPeriod, grade, course FROM edu ORDER BY startPeriod DESC;");
|
||||||
$stmt->execute();
|
$stmt->execute();
|
||||||
|
|
||||||
// set the resulting array to associative
|
// set the resulting array to associative
|
||||||
@ -37,7 +37,7 @@ class timelineData
|
|||||||
function getWorkData(): array
|
function getWorkData(): array
|
||||||
{
|
{
|
||||||
$conn = dbConn();
|
$conn = dbConn();
|
||||||
$stmt = $conn->prepare("SELECT DATE_FORMAT(startPeriod, '%b, %Y') as startPeriod, DATE_FORMAT(endPeriod, '%b, %Y') as endPeriod, companyName, area, title FROM work ORDER BY work.startPeriod DESC;");
|
$stmt = $conn->prepare("SELECT startPeriod, endPeriod, companyName, area, title FROM work ORDER BY work.startPeriod DESC;");
|
||||||
$stmt->execute();
|
$stmt->execute();
|
||||||
|
|
||||||
// set the resulting array to associative
|
// set the resulting array to associative
|
||||||
|
129
src/editor/css/editor.css
Normal file
129
src/editor/css/editor.css
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
/*** Main editor styles ***/
|
||||||
|
|
||||||
|
section#curriculumVitae, section#projects, section#settings {
|
||||||
|
margin: 0 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="submit"] {
|
||||||
|
margin-top: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.edit, .delete{
|
||||||
|
border: none;
|
||||||
|
-webkit-border-radius: 5px;
|
||||||
|
-moz-border-radius: 5px;
|
||||||
|
border-radius: 5px;
|
||||||
|
outline: none;
|
||||||
|
background-color: var(--primaryDefault);
|
||||||
|
color: #FFFFFF;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.editorContainer {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: baseline;
|
||||||
|
gap: 2em;
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.editorContainer > * {
|
||||||
|
width: 45%;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.modifyBtnContainer {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.dateContainer {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
gap: 1em;
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
section#curriculumVitae .timeline {
|
||||||
|
position: relative;
|
||||||
|
max-width: 30em;
|
||||||
|
gap: 1em;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
section#curriculumVitae .timelineItem {
|
||||||
|
color: #FFFFFF;
|
||||||
|
border: 2px solid var(--timelineItemBrdr);
|
||||||
|
-webkit-border-radius: 10px;
|
||||||
|
-moz-border-radius: 10px;
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 0 1rem;
|
||||||
|
position: relative;
|
||||||
|
background-color: var(--primaryHover);
|
||||||
|
}
|
||||||
|
|
||||||
|
section#curriculumVitae .timelineItem.editing {
|
||||||
|
color: #000000;
|
||||||
|
border: 5px solid var(--primaryDefault);
|
||||||
|
padding: 0.5em;
|
||||||
|
background-color: #FFFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
form div.gradeContainer.formControl {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: flex-start;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
section#curriculumVitae form.timelineItem:not(.editing) .edit,
|
||||||
|
section#curriculumVitae form.timelineItem:not(.editing) .delete {
|
||||||
|
color: var(--primaryHover);
|
||||||
|
background-color: #FFFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
section#curriculumVitae form.timelineItem:not(.editing) div.dateContainer {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
section#curriculumVitae form.timelineItem.editing .timelineHeader {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
section#curriculumVitae form.timelineItem.editing div.gradeContainer.formControl {
|
||||||
|
gap: 1em;
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
section#curriculumVitae form.timelineItem:not(.editing) div.gradeContainer.formControl input,
|
||||||
|
section#curriculumVitae form.timelineItem:not(.editing) .formControl .courseText {
|
||||||
|
outline: none;
|
||||||
|
border: none;
|
||||||
|
color: #FFFFFF;
|
||||||
|
-webkit-border-radius: 0;
|
||||||
|
-moz-border-radius: 0;
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
section#curriculumVitae form.timelineItem:not(.editing) div.gradeContainer.formControl input {
|
||||||
|
padding: 0 0.25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
section#curriculumVitae form.timelineItem:not(.editing) div.formControl .courseText {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
section#curriculumVitae form.timelineItem:not(.editing) input[type=submit] {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.courseText {
|
||||||
|
resize: none;
|
||||||
|
}
|
@ -5,6 +5,7 @@
|
|||||||
@import "../../css/templateStyles.css";
|
@import "../../css/templateStyles.css";
|
||||||
@import "login.css";
|
@import "login.css";
|
||||||
@import "nav.css";
|
@import "nav.css";
|
||||||
|
@import "editor.css";
|
||||||
|
|
||||||
/*** Media Queries ***/
|
/*** Media Queries ***/
|
||||||
|
|
||||||
|
@ -71,6 +71,6 @@ main.editor {
|
|||||||
|
|
||||||
#navOpen {
|
#navOpen {
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
padding-left: 0.25em;
|
padding: 0.25em 0 0 0.25em;
|
||||||
align-self: flex-start;
|
align-self: flex-start;
|
||||||
}
|
}
|
@ -4,6 +4,7 @@
|
|||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>Editor</title>
|
<title>Editor</title>
|
||||||
<link rel="stylesheet" href="css/main.css">
|
<link rel="stylesheet" href="css/main.css">
|
||||||
|
<script src="https://kit.fontawesome.com/ed3c25598e.js" crossorigin="anonymous"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<nav class="sideNav">
|
<nav class="sideNav">
|
||||||
@ -17,8 +18,59 @@
|
|||||||
<main class="editor" style="margin-left: 250px;">
|
<main class="editor" style="margin-left: 250px;">
|
||||||
<div class="title">
|
<div class="title">
|
||||||
<span id="navOpen">☰</span>
|
<span id="navOpen">☰</span>
|
||||||
|
|
||||||
<h1>Editor</h1>
|
<h1>Editor</h1>
|
||||||
</div>
|
</div>
|
||||||
|
<section id="curriculumVitae">
|
||||||
|
<h2>curriculum vitae</h2>
|
||||||
|
<div class="cvGrid">
|
||||||
|
<!-- https://codepen.io/keithwyland/pen/wqNqvy -->
|
||||||
|
<div>
|
||||||
|
<h3>Education</h3>
|
||||||
|
|
||||||
|
<div class="editorContainer">
|
||||||
|
<form action="" method="POST">
|
||||||
|
<div class="formControl">
|
||||||
|
<label for="dateFrom">Date From</label>
|
||||||
|
<input type="date" id="dateFrom" name="dateFrom">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="formControl">
|
||||||
|
<label for="dateTo">Date To</label>
|
||||||
|
<input type="date" id="dateTo" name="dateTo">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="formControl">
|
||||||
|
<label for="grade">Grade</label>
|
||||||
|
<input type="text" id="grade" name="grade">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="formControl">
|
||||||
|
<label for="courseTitle">Course Title</label>
|
||||||
|
<input type="text" id="courseTitle" name="courseTitle">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="error hidden" id="eduError">
|
||||||
|
<button class="close" type="button">×</button>
|
||||||
|
<div></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<input type="submit" class="btn btnPrimary boxShadowIn boxShadowOut" value="Add new course">
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<div class="timeline" id="edu">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3>Work</h3>
|
||||||
|
|
||||||
|
<div class="timeline" id="work">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<script src="js/editor.js"></script>
|
<script src="js/editor.js"></script>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
|
let dateOptions = {month: 'short', year: 'numeric'};
|
||||||
document.addEventListener('DOMContentLoaded', e =>
|
document.addEventListener('DOMContentLoaded', () =>
|
||||||
{
|
{
|
||||||
// check if the user is logged in, if not redirect to log in
|
// check if the user is logged in, if not redirect to log in
|
||||||
/* fetch('/api/user/isLoggedIn').then(res =>
|
/* fetch('/api/user/isLoggedIn').then(res =>
|
||||||
@ -9,6 +9,53 @@ document.addEventListener('DOMContentLoaded', e =>
|
|||||||
window.location.href = './';
|
window.location.href = './';
|
||||||
}
|
}
|
||||||
});*/
|
});*/
|
||||||
|
document.querySelector("#dateFrom").max = new Date().toISOString().split("T")[0];
|
||||||
|
|
||||||
|
|
||||||
|
fetch("/api/timelineData/edu").then(res =>
|
||||||
|
{
|
||||||
|
res.json().then(json =>
|
||||||
|
{
|
||||||
|
if (res.ok)
|
||||||
|
{
|
||||||
|
for (let i = 0; i < json.length; i++)
|
||||||
|
{
|
||||||
|
let timelineItem = document.createElement("form")
|
||||||
|
timelineItem.id = "timelineItem" + i;
|
||||||
|
timelineItem.classList.add("timelineItem");
|
||||||
|
timelineItem.onsubmit = e => updateItem(i, e);
|
||||||
|
timelineItem.innerHTML = `
|
||||||
|
<div class="modifyBtnContainer">
|
||||||
|
<button class="edit" type="button" id="edit${i}" onclick="edit(${i})"><i class="fa-solid fa-pen-to-square"></i></button>
|
||||||
|
<button class="delete" type="button" id="delete${i}"><i class="fa-solid fa-trash"></i></button>
|
||||||
|
</div>
|
||||||
|
<div class="dateContainer formControl">
|
||||||
|
<input type="date" name="dateFrom${i}" id="dateFrom${i}" onload="this.max = new Date().toISOString().split('T')[0]" value="${json[i]['startPeriod']}">
|
||||||
|
-
|
||||||
|
<input type="date" name="dateTo${i}" id="dateTo${i}" value="${json[i]['endPeriod']}">
|
||||||
|
</div>
|
||||||
|
<h3 class="timelineHeader">${new Date(json[i]["startPeriod"]).toLocaleString('en-gb', dateOptions)} - ${new Date(json[i]["endPeriod"]).toLocaleString('en-gb', dateOptions)}</h3>
|
||||||
|
<div class="gradeContainer formControl">
|
||||||
|
<label for="grade${i}">Grade:</label>
|
||||||
|
<input type="text" name="grade${i}" id="grade${i}" value="${json[i]['grade']}" disabled>
|
||||||
|
</div>
|
||||||
|
<div class="formControl">
|
||||||
|
<textarea class="courseText" name="course${i}" id="course${i}" cols="10" rows="3" disabled>${json[i]['course']}</textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="error hidden" id="eduError">
|
||||||
|
<button class="close" type="button">×</button>
|
||||||
|
<div></div>
|
||||||
|
</div>
|
||||||
|
<input type="submit" value="Change">
|
||||||
|
`;
|
||||||
|
document.getElementById("edu").appendChild(timelineItem);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
document.querySelector("#edu").innerHTML = "No education data found";
|
||||||
|
})
|
||||||
|
});
|
||||||
})
|
})
|
||||||
|
|
||||||
document.querySelector("#navOpen").addEventListener("click", e =>
|
document.querySelector("#navOpen").addEventListener("click", e =>
|
||||||
@ -18,9 +65,49 @@ document.querySelector("#navOpen").addEventListener("click", e =>
|
|||||||
e.target.style.removeProperty("visibility");
|
e.target.style.removeProperty("visibility");
|
||||||
});
|
});
|
||||||
|
|
||||||
document.querySelector("#navClose").addEventListener("click", e =>
|
document.querySelector("#navClose").addEventListener("click", () =>
|
||||||
{
|
{
|
||||||
document.querySelector("nav.sideNav").style.width = "0";
|
document.querySelector("nav.sideNav").style.width = "0";
|
||||||
document.querySelector("main.editor").style.marginLeft = "0";
|
document.querySelector("main.editor").style.marginLeft = "0";
|
||||||
document.querySelector("#navOpen").style.visibility = "visible";
|
document.querySelector("#navOpen").style.visibility = "visible";
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function edit(i)
|
||||||
|
{
|
||||||
|
document.querySelector("#timelineItem" + i).classList.toggle("editing");
|
||||||
|
document.querySelector("#grade" + i).removeAttribute("disabled");
|
||||||
|
document.querySelector("#course" + i).removeAttribute("disabled");
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateItem(i, e)
|
||||||
|
{
|
||||||
|
e.preventDefault();
|
||||||
|
let data = new FormData();
|
||||||
|
data.append("dateFrom", document.querySelector("#dateFrom" + i).value);
|
||||||
|
data.append("dateTo", document.querySelector("#dateTo" + i).value);
|
||||||
|
data.append("grade", document.querySelector("#grade" + i).value);
|
||||||
|
data.append("course", document.querySelector("#course" + i).value);
|
||||||
|
|
||||||
|
fetch("/api/timelineData/edu/" + i, {
|
||||||
|
method: "PUT",
|
||||||
|
body: data,
|
||||||
|
headers: {
|
||||||
|
"Authorization": "Bearer " + localStorage.getItem("token")
|
||||||
|
}
|
||||||
|
}).then(res =>
|
||||||
|
{
|
||||||
|
if (res.ok)
|
||||||
|
{
|
||||||
|
document.querySelector("#timelineItem" + i).classList.toggle("editing");
|
||||||
|
document.querySelector("#grade" + i).setAttribute("disabled", "");
|
||||||
|
document.querySelector("#course" + i).setAttribute("disabled", "");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
res.json().then(json =>
|
||||||
|
{
|
||||||
|
alert(json.message);
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
@ -39,10 +39,11 @@ document.querySelector("#login form").addEventListener("submit", e =>
|
|||||||
{
|
{
|
||||||
method: "POST",
|
method: "POST",
|
||||||
body: loginData
|
body: loginData
|
||||||
}).then(res =>
|
}).then(res => res.json()).then(json =>
|
||||||
{
|
{
|
||||||
if (res.ok)
|
if (res.ok)
|
||||||
{
|
{
|
||||||
|
localStorage.setItem("token", json.token);
|
||||||
window.location.href = "./editor.html";
|
window.location.href = "./editor.html";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -107,6 +107,7 @@ function StartTextAnimation(i)
|
|||||||
*/
|
*/
|
||||||
function getTimelineData()
|
function getTimelineData()
|
||||||
{
|
{
|
||||||
|
let dateOptions = { year: "numeric", month: "short" };
|
||||||
fetch("/api/timelineData/edu").then(res =>
|
fetch("/api/timelineData/edu").then(res =>
|
||||||
{
|
{
|
||||||
res.json().then(json =>
|
res.json().then(json =>
|
||||||
@ -118,7 +119,7 @@ function getTimelineData()
|
|||||||
let timelineItem = document.createElement("div")
|
let timelineItem = document.createElement("div")
|
||||||
timelineItem.classList.add("timelineItem");
|
timelineItem.classList.add("timelineItem");
|
||||||
timelineItem.innerHTML = `
|
timelineItem.innerHTML = `
|
||||||
<h3 class="timelineHeader">${item["startPeriod"]} - ${item["endPeriod"]}</h3>
|
<h3 class="timelineHeader">${new Date(item["startPeriod"]).toLocaleString('en-gb', dateOptions)} - ${new Date(item["endPeriod"]).toLocaleString('en-gb', dateOptions)}</h3>
|
||||||
<span>Grade: ${item["grade"]}</span>
|
<span>Grade: ${item["grade"]}</span>
|
||||||
<p class="timelineText">${item["course"]}</p>
|
<p class="timelineText">${item["course"]}</p>
|
||||||
`;
|
`;
|
||||||
@ -139,7 +140,7 @@ function getTimelineData()
|
|||||||
let timelineItem = document.createElement("div")
|
let timelineItem = document.createElement("div")
|
||||||
timelineItem.classList.add("timelineItem");
|
timelineItem.classList.add("timelineItem");
|
||||||
timelineItem.innerHTML = `
|
timelineItem.innerHTML = `
|
||||||
<h3 class="timelineHeader">${item["startPeriod"]} - ${item["endPeriod"]}</h3>
|
<h3 class="timelineHeader">${new Date(item["startPeriod"]).toLocaleString('en-gb', dateOptions)} - ${new Date(item["endPeriod"]).toLocaleString('en-gb', dateOptions)}</h3>
|
||||||
<span>${item["companyName"]} - ${item["area"]}</span>
|
<span>${item["companyName"]} - ${item["area"]}</span>
|
||||||
<p class="timelineText">${item["title"]}</p>
|
<p class="timelineText">${item["title"]}</p>
|
||||||
`;
|
`;
|
||||||
|
Loading…
Reference in New Issue
Block a user